Fix: Crash versioning transfer node with animation data

This versioning needs to be done after linking in order to affect
animation  data which might not be loaded in the regular "do_versions"
loop. Animation data is removed in `nodeRemoveNode`.

Fixes T101439
This commit is contained in:
Hans Goudey 2022-10-04 13:27:11 -05:00
parent ea95d04245
commit d981418c8c
Notes: blender-bot 2023-02-14 08:59:10 +01:00
Referenced by issue #101439, Regression: Crash when opening file
1 changed files with 151 additions and 149 deletions

View File

@ -670,6 +670,147 @@ static bool seq_speed_factor_set(Sequence *seq, void *user_data)
return true;
}
static void version_geometry_nodes_replace_transfer_attribute_node(bNodeTree *ntree)
{
using namespace blender;
/* Otherwise `ntree->typeInfo` is null. */
ntreeSetTypes(NULL, ntree);
LISTBASE_FOREACH_MUTABLE (bNode *, node, &ntree->nodes) {
if (node->type != GEO_NODE_TRANSFER_ATTRIBUTE_DEPRECATED) {
continue;
}
bNodeSocket *old_geometry_socket = nodeFindSocket(node, SOCK_IN, "Source");
const NodeGeometryTransferAttribute *storage = (const NodeGeometryTransferAttribute *)
node->storage;
switch (storage->mode) {
case GEO_NODE_ATTRIBUTE_TRANSFER_NEAREST_FACE_INTERPOLATED: {
bNode *sample_nearest_surface = nodeAddStaticNode(
NULL, ntree, GEO_NODE_SAMPLE_NEAREST_SURFACE);
sample_nearest_surface->parent = node->parent;
sample_nearest_surface->custom1 = storage->data_type;
sample_nearest_surface->locx = node->locx;
sample_nearest_surface->locy = node->locy;
static auto socket_remap = []() {
Map<std::string, std::string> map;
map.add_new("Attribute", "Value_Vector");
map.add_new("Attribute_001", "Value_Float");
map.add_new("Attribute_002", "Value_Color");
map.add_new("Attribute_003", "Value_Bool");
map.add_new("Attribute_004", "Value_Int");
map.add_new("Source", "Mesh");
map.add_new("Source Position", "Sample Position");
return map;
}();
node_tree_relink_with_socket_id_map(*ntree, *node, *sample_nearest_surface, socket_remap);
break;
}
case GEO_NODE_ATTRIBUTE_TRANSFER_NEAREST: {
/* These domains weren't supported by the index transfer mode, but were selectable. */
const eAttrDomain domain = ELEM(storage->domain, ATTR_DOMAIN_INSTANCE, ATTR_DOMAIN_CURVE) ?
ATTR_DOMAIN_POINT :
eAttrDomain(storage->domain);
/* Use a sample index node to retrieve the data with this node's index output. */
bNode *sample_index = nodeAddStaticNode(NULL, ntree, GEO_NODE_SAMPLE_INDEX);
NodeGeometrySampleIndex *sample_storage = static_cast<NodeGeometrySampleIndex *>(
sample_index->storage);
sample_storage->data_type = storage->data_type;
sample_storage->domain = domain;
sample_index->parent = node->parent;
sample_index->locx = node->locx + 25.0f;
sample_index->locy = node->locy;
if (old_geometry_socket->link) {
nodeAddLink(ntree,
old_geometry_socket->link->fromnode,
old_geometry_socket->link->fromsock,
sample_index,
nodeFindSocket(sample_index, SOCK_IN, "Geometry"));
}
bNode *sample_nearest = nodeAddStaticNode(NULL, ntree, GEO_NODE_SAMPLE_NEAREST);
sample_nearest->parent = node->parent;
sample_nearest->custom1 = storage->data_type;
sample_nearest->custom2 = domain;
sample_nearest->locx = node->locx - 25.0f;
sample_nearest->locy = node->locy;
if (old_geometry_socket->link) {
nodeAddLink(ntree,
old_geometry_socket->link->fromnode,
old_geometry_socket->link->fromsock,
sample_nearest,
nodeFindSocket(sample_nearest, SOCK_IN, "Geometry"));
}
static auto sample_nearest_remap = []() {
Map<std::string, std::string> map;
map.add_new("Source Position", "Sample Position");
return map;
}();
node_tree_relink_with_socket_id_map(*ntree, *node, *sample_nearest, sample_nearest_remap);
static auto sample_index_remap = []() {
Map<std::string, std::string> map;
map.add_new("Attribute", "Value_Vector");
map.add_new("Attribute_001", "Value_Float");
map.add_new("Attribute_002", "Value_Color");
map.add_new("Attribute_003", "Value_Bool");
map.add_new("Attribute_004", "Value_Int");
map.add_new("Source Position", "Sample Position");
return map;
}();
node_tree_relink_with_socket_id_map(*ntree, *node, *sample_index, sample_index_remap);
nodeAddLink(ntree,
sample_nearest,
nodeFindSocket(sample_nearest, SOCK_OUT, "Index"),
sample_index,
nodeFindSocket(sample_index, SOCK_IN, "Index"));
break;
}
case GEO_NODE_ATTRIBUTE_TRANSFER_INDEX: {
bNode *sample_index = nodeAddStaticNode(NULL, ntree, GEO_NODE_SAMPLE_INDEX);
NodeGeometrySampleIndex *sample_storage = static_cast<NodeGeometrySampleIndex *>(
sample_index->storage);
sample_storage->data_type = storage->data_type;
sample_storage->domain = storage->domain;
sample_storage->clamp = 1;
sample_index->parent = node->parent;
sample_index->locx = node->locx;
sample_index->locy = node->locy;
const bool index_was_linked = nodeFindSocket(node, SOCK_IN, "Index")->link != nullptr;
static auto socket_remap = []() {
Map<std::string, std::string> map;
map.add_new("Attribute", "Value_Vector");
map.add_new("Attribute_001", "Value_Float");
map.add_new("Attribute_002", "Value_Color");
map.add_new("Attribute_003", "Value_Bool");
map.add_new("Attribute_004", "Value_Int");
map.add_new("Source", "Geometry");
map.add_new("Index", "Index");
return map;
}();
node_tree_relink_with_socket_id_map(*ntree, *node, *sample_index, socket_remap);
if (!index_was_linked) {
/* Add an index input node, since the new node doesn't use an implicit input. */
bNode *index = nodeAddStaticNode(NULL, ntree, GEO_NODE_INPUT_INDEX);
index->parent = node->parent;
index->locx = node->locx - 25.0f;
index->locy = node->locy - 25.0f;
nodeAddLink(ntree,
index,
nodeFindSocket(index, SOCK_OUT, "Index"),
sample_index,
nodeFindSocket(sample_index, SOCK_IN, "Index"));
}
break;
}
}
/* The storage must be freed manually because the node type isn't defined anymore. */
MEM_freeN(node->storage);
nodeRemoveNode(NULL, ntree, node, false);
}
}
void do_versions_after_linking_300(Main *bmain, ReportList * /*reports*/)
{
if (MAIN_VERSION_ATLEAST(bmain, 300, 0) && !MAIN_VERSION_ATLEAST(bmain, 300, 1)) {
@ -933,6 +1074,16 @@ void do_versions_after_linking_300(Main *bmain, ReportList * /*reports*/)
}
}
if (!MAIN_VERSION_ATLEAST(bmain, 304, 1)) {
/* Split the transfer attribute node into multiple smaller nodes. */
FOREACH_NODETREE_BEGIN (bmain, ntree, id) {
if (ntree->type == NTREE_GEOMETRY) {
version_geometry_nodes_replace_transfer_attribute_node(ntree);
}
}
FOREACH_NODETREE_END;
}
/**
* Versioning code until next subversion bump goes here.
*
@ -1791,147 +1942,6 @@ static void version_fix_image_format_copy(Main *bmain, ImageFormatData *format)
}
}
static void version_geometry_nodes_replace_transfer_attribute_node(bNodeTree *ntree)
{
using namespace blender;
/* Otherwise `ntree->typeInfo` is null. */
ntreeSetTypes(NULL, ntree);
LISTBASE_FOREACH_MUTABLE (bNode *, node, &ntree->nodes) {
if (node->type != GEO_NODE_TRANSFER_ATTRIBUTE_DEPRECATED) {
continue;
}
bNodeSocket *old_geometry_socket = nodeFindSocket(node, SOCK_IN, "Source");
const NodeGeometryTransferAttribute *storage = (const NodeGeometryTransferAttribute *)
node->storage;
switch (storage->mode) {
case GEO_NODE_ATTRIBUTE_TRANSFER_NEAREST_FACE_INTERPOLATED: {
bNode *sample_nearest_surface = nodeAddStaticNode(
NULL, ntree, GEO_NODE_SAMPLE_NEAREST_SURFACE);
sample_nearest_surface->parent = node->parent;
sample_nearest_surface->custom1 = storage->data_type;
sample_nearest_surface->locx = node->locx;
sample_nearest_surface->locy = node->locy;
static auto socket_remap = []() {
Map<std::string, std::string> map;
map.add_new("Attribute", "Value_Vector");
map.add_new("Attribute_001", "Value_Float");
map.add_new("Attribute_002", "Value_Color");
map.add_new("Attribute_003", "Value_Bool");
map.add_new("Attribute_004", "Value_Int");
map.add_new("Source", "Mesh");
map.add_new("Source Position", "Sample Position");
return map;
}();
node_tree_relink_with_socket_id_map(*ntree, *node, *sample_nearest_surface, socket_remap);
break;
}
case GEO_NODE_ATTRIBUTE_TRANSFER_NEAREST: {
/* These domains weren't supported by the index transfer mode, but were selectable. */
const eAttrDomain domain = ELEM(storage->domain, ATTR_DOMAIN_INSTANCE, ATTR_DOMAIN_CURVE) ?
ATTR_DOMAIN_POINT :
eAttrDomain(storage->domain);
/* Use a sample index node to retrieve the data with this node's index output. */
bNode *sample_index = nodeAddStaticNode(NULL, ntree, GEO_NODE_SAMPLE_INDEX);
NodeGeometrySampleIndex *sample_storage = static_cast<NodeGeometrySampleIndex *>(
sample_index->storage);
sample_storage->data_type = storage->data_type;
sample_storage->domain = domain;
sample_index->parent = node->parent;
sample_index->locx = node->locx + 25.0f;
sample_index->locy = node->locy;
if (old_geometry_socket->link) {
nodeAddLink(ntree,
old_geometry_socket->link->fromnode,
old_geometry_socket->link->fromsock,
sample_index,
nodeFindSocket(sample_index, SOCK_IN, "Geometry"));
}
bNode *sample_nearest = nodeAddStaticNode(NULL, ntree, GEO_NODE_SAMPLE_NEAREST);
sample_nearest->parent = node->parent;
sample_nearest->custom1 = storage->data_type;
sample_nearest->custom2 = domain;
sample_nearest->locx = node->locx - 25.0f;
sample_nearest->locy = node->locy;
if (old_geometry_socket->link) {
nodeAddLink(ntree,
old_geometry_socket->link->fromnode,
old_geometry_socket->link->fromsock,
sample_nearest,
nodeFindSocket(sample_nearest, SOCK_IN, "Geometry"));
}
static auto sample_nearest_remap = []() {
Map<std::string, std::string> map;
map.add_new("Source Position", "Sample Position");
return map;
}();
node_tree_relink_with_socket_id_map(*ntree, *node, *sample_nearest, sample_nearest_remap);
static auto sample_index_remap = []() {
Map<std::string, std::string> map;
map.add_new("Attribute", "Value_Vector");
map.add_new("Attribute_001", "Value_Float");
map.add_new("Attribute_002", "Value_Color");
map.add_new("Attribute_003", "Value_Bool");
map.add_new("Attribute_004", "Value_Int");
map.add_new("Source Position", "Sample Position");
return map;
}();
node_tree_relink_with_socket_id_map(*ntree, *node, *sample_index, sample_index_remap);
nodeAddLink(ntree,
sample_nearest,
nodeFindSocket(sample_nearest, SOCK_OUT, "Index"),
sample_index,
nodeFindSocket(sample_index, SOCK_IN, "Index"));
break;
}
case GEO_NODE_ATTRIBUTE_TRANSFER_INDEX: {
bNode *sample_index = nodeAddStaticNode(NULL, ntree, GEO_NODE_SAMPLE_INDEX);
NodeGeometrySampleIndex *sample_storage = static_cast<NodeGeometrySampleIndex *>(
sample_index->storage);
sample_storage->data_type = storage->data_type;
sample_storage->domain = storage->domain;
sample_storage->clamp = 1;
sample_index->parent = node->parent;
sample_index->locx = node->locx;
sample_index->locy = node->locy;
const bool index_was_linked = nodeFindSocket(node, SOCK_IN, "Index")->link != nullptr;
static auto socket_remap = []() {
Map<std::string, std::string> map;
map.add_new("Attribute", "Value_Vector");
map.add_new("Attribute_001", "Value_Float");
map.add_new("Attribute_002", "Value_Color");
map.add_new("Attribute_003", "Value_Bool");
map.add_new("Attribute_004", "Value_Int");
map.add_new("Source", "Geometry");
map.add_new("Index", "Index");
return map;
}();
node_tree_relink_with_socket_id_map(*ntree, *node, *sample_index, socket_remap);
if (!index_was_linked) {
/* Add an index input node, since the new node doesn't use an implicit input. */
bNode *index = nodeAddStaticNode(NULL, ntree, GEO_NODE_INPUT_INDEX);
index->parent = node->parent;
index->locx = node->locx - 25.0f;
index->locy = node->locy - 25.0f;
nodeAddLink(ntree,
index,
nodeFindSocket(index, SOCK_OUT, "Index"),
sample_index,
nodeFindSocket(sample_index, SOCK_IN, "Index"));
}
break;
}
}
/* The storage must be freed manually because the node type isn't defined anymore. */
MEM_freeN(node->storage);
nodeRemoveNode(NULL, ntree, node, false);
}
}
/* NOLINTNEXTLINE: readability-function-size */
void blo_do_versions_300(FileData *fd, Library * /*lib*/, Main *bmain)
{
@ -3574,14 +3584,6 @@ void blo_do_versions_300(FileData *fd, Library * /*lib*/, Main *bmain)
}
}
}
/* Split the transfer attribute node into multiple smaller nodes. */
FOREACH_NODETREE_BEGIN (bmain, ntree, id) {
if (ntree->type == NTREE_GEOMETRY) {
version_geometry_nodes_replace_transfer_attribute_node(ntree);
}
}
FOREACH_NODETREE_END;
}
if (!MAIN_VERSION_ATLEAST(bmain, 304, 2)) {