Nodes: remove writing legacy node group interface
When panels in node groups were introduced, the interface data of a tree was moved from `tree.inputs_legacy/outputs_legacy` to `tree.tree_interface`. For forward compatibility, the old interface was still written. Since Blender 4.5 can read the new format and older versions are not able to open files created in 5.0 directly anymore, it's fine to remove this forward-compatibility code now. Also fixes #145278. Pull Request: https://projects.blender.org/blender/blender/pulls/145489
This commit is contained in:
@@ -484,213 +484,6 @@ static ID **node_owner_pointer_get(ID *id, const bool debug_relationship_assert)
|
||||
|
||||
namespace forward_compat {
|
||||
|
||||
static void write_node_socket_interface(BlendWriter *writer, const bNodeSocket *sock)
|
||||
{
|
||||
BLO_write_struct(writer, bNodeSocket, sock);
|
||||
|
||||
if (sock->prop) {
|
||||
IDP_BlendWrite(writer, sock->prop);
|
||||
}
|
||||
|
||||
BLO_write_string(writer, sock->default_attribute_name);
|
||||
|
||||
write_node_socket_default_value(writer, sock);
|
||||
}
|
||||
|
||||
/* Construct a bNodeSocket that represents a node group socket the old way. */
|
||||
static bNodeSocket *make_socket(bNodeTree *ntree,
|
||||
const eNodeSocketInOut in_out,
|
||||
const StringRef idname,
|
||||
const StringRef name,
|
||||
const StringRef identifier)
|
||||
{
|
||||
bNodeSocketType *stype = node_socket_type_find(idname);
|
||||
if (stype == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bNodeSocket *sock = MEM_callocN<bNodeSocket>(__func__);
|
||||
sock->runtime = MEM_new<bNodeSocketRuntime>(__func__);
|
||||
StringRef(stype->idname).copy_utf8_truncated(sock->idname);
|
||||
sock->in_out = int(in_out);
|
||||
sock->type = int(SOCK_CUSTOM); /* int type undefined by default */
|
||||
node_socket_set_typeinfo(ntree, sock, stype);
|
||||
|
||||
sock->limit = (in_out == SOCK_IN ? 1 : 0xFFF);
|
||||
|
||||
identifier.copy_utf8_truncated(sock->identifier);
|
||||
name.copy_utf8_truncated(sock->name);
|
||||
sock->storage = nullptr;
|
||||
sock->flag |= SOCK_COLLAPSED;
|
||||
|
||||
return sock;
|
||||
}
|
||||
|
||||
/* Include the subtype suffix for old socket idnames. */
|
||||
static StringRef get_legacy_socket_subtype_idname(StringRef idname, const void *socket_data)
|
||||
{
|
||||
if (idname == "NodeSocketFloat") {
|
||||
const bNodeSocketValueFloat &float_data = *static_cast<const bNodeSocketValueFloat *>(
|
||||
socket_data);
|
||||
switch (float_data.subtype) {
|
||||
case PROP_UNSIGNED:
|
||||
return "NodeSocketFloatUnsigned";
|
||||
case PROP_PERCENTAGE:
|
||||
return "NodeSocketFloatPercentage";
|
||||
case PROP_FACTOR:
|
||||
return "NodeSocketFloatFactor";
|
||||
case PROP_ANGLE:
|
||||
return "NodeSocketFloatAngle";
|
||||
case PROP_TIME:
|
||||
return "NodeSocketFloatTime";
|
||||
case PROP_TIME_ABSOLUTE:
|
||||
return "NodeSocketFloatTimeAbsolute";
|
||||
case PROP_DISTANCE:
|
||||
return "NodeSocketFloatDistance";
|
||||
case PROP_WAVELENGTH:
|
||||
return "NodeSocketFloatWavelength";
|
||||
case PROP_COLOR_TEMPERATURE:
|
||||
return "NodeSocketFloatColorTemperature";
|
||||
case PROP_FREQUENCY:
|
||||
return "NodeSocketFloatFrequency";
|
||||
}
|
||||
}
|
||||
if (idname == "NodeSocketInt") {
|
||||
const bNodeSocketValueInt &int_data = *static_cast<const bNodeSocketValueInt *>(socket_data);
|
||||
switch (int_data.subtype) {
|
||||
case PROP_UNSIGNED:
|
||||
return "NodeSocketIntUnsigned";
|
||||
case PROP_PERCENTAGE:
|
||||
return "NodeSocketIntPercentage";
|
||||
case PROP_FACTOR:
|
||||
return "NodeSocketIntFactor";
|
||||
}
|
||||
}
|
||||
if (idname == "NodeSocketVector") {
|
||||
const bNodeSocketValueVector &vector_data = *static_cast<const bNodeSocketValueVector *>(
|
||||
socket_data);
|
||||
switch (vector_data.subtype) {
|
||||
case PROP_FACTOR:
|
||||
return "NodeSocketVectorFactor";
|
||||
case PROP_PERCENTAGE:
|
||||
return "NodeSocketVectorPercentage";
|
||||
case PROP_TRANSLATION:
|
||||
return "NodeSocketVectorTranslation";
|
||||
case PROP_DIRECTION:
|
||||
return "NodeSocketVectorDirection";
|
||||
case PROP_VELOCITY:
|
||||
return "NodeSocketVectorVelocity";
|
||||
case PROP_ACCELERATION:
|
||||
return "NodeSocketVectorAcceleration";
|
||||
case PROP_EULER:
|
||||
return "NodeSocketVectorEuler";
|
||||
}
|
||||
}
|
||||
return idname;
|
||||
}
|
||||
|
||||
/**
|
||||
* Socket interface reconstruction for forward compatibility.
|
||||
* To enable previous Blender versions to read the new interface DNA data,
|
||||
* construct the bNodeSocket inputs/outputs lists.
|
||||
* This discards any information about panels and alternating input/output order,
|
||||
* but all functional information is preserved for executing node trees.
|
||||
*/
|
||||
static void construct_interface_as_legacy_sockets(bNodeTree *ntree)
|
||||
{
|
||||
BLI_assert(BLI_listbase_is_empty(&ntree->inputs_legacy));
|
||||
BLI_assert(BLI_listbase_is_empty(&ntree->outputs_legacy));
|
||||
|
||||
auto make_legacy_socket = [&](const bNodeTreeInterfaceSocket &socket,
|
||||
eNodeSocketInOut in_out) -> bNodeSocket * {
|
||||
bNodeSocket *iosock = make_socket(
|
||||
ntree,
|
||||
in_out,
|
||||
get_legacy_socket_subtype_idname(socket.socket_type, socket.socket_data),
|
||||
socket.name ? socket.name : "",
|
||||
socket.identifier);
|
||||
if (!iosock) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (socket.description) {
|
||||
STRNCPY(iosock->description, socket.description);
|
||||
}
|
||||
node_socket_copy_default_value_data(
|
||||
iosock->typeinfo->type, iosock->default_value, socket.socket_data);
|
||||
if (socket.properties) {
|
||||
iosock->prop = IDP_CopyProperty(socket.properties);
|
||||
}
|
||||
SET_FLAG_FROM_TEST(
|
||||
iosock->flag, socket.flag & NODE_INTERFACE_SOCKET_HIDE_VALUE, SOCK_HIDE_VALUE);
|
||||
SET_FLAG_FROM_TEST(
|
||||
iosock->flag, socket.flag & NODE_INTERFACE_SOCKET_HIDE_IN_MODIFIER, SOCK_HIDE_IN_MODIFIER);
|
||||
iosock->attribute_domain = socket.attribute_domain;
|
||||
iosock->default_attribute_name = BLI_strdup_null(socket.default_attribute_name);
|
||||
return iosock;
|
||||
};
|
||||
|
||||
/* Construct inputs/outputs socket lists in the node tree. */
|
||||
ntree->tree_interface.foreach_item([&](const bNodeTreeInterfaceItem &item) {
|
||||
if (const bNodeTreeInterfaceSocket *socket =
|
||||
node_interface::get_item_as<bNodeTreeInterfaceSocket>(&item))
|
||||
{
|
||||
if (socket->flag & NODE_INTERFACE_SOCKET_INPUT) {
|
||||
if (bNodeSocket *legacy_socket = make_legacy_socket(*socket, SOCK_IN)) {
|
||||
BLI_addtail(&ntree->inputs_legacy, legacy_socket);
|
||||
}
|
||||
}
|
||||
if (socket->flag & NODE_INTERFACE_SOCKET_OUTPUT) {
|
||||
if (bNodeSocket *legacy_socket = make_legacy_socket(*socket, SOCK_OUT)) {
|
||||
BLI_addtail(&ntree->outputs_legacy, legacy_socket);
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
static void write_legacy_sockets(BlendWriter *writer, bNodeTree *ntree)
|
||||
{
|
||||
/* Write inputs/outputs */
|
||||
LISTBASE_FOREACH (bNodeSocket *, sock, &ntree->inputs_legacy) {
|
||||
write_node_socket_interface(writer, sock);
|
||||
}
|
||||
LISTBASE_FOREACH (bNodeSocket *, sock, &ntree->outputs_legacy) {
|
||||
write_node_socket_interface(writer, sock);
|
||||
}
|
||||
}
|
||||
|
||||
static void legacy_socket_interface_free(bNodeSocket *sock)
|
||||
{
|
||||
if (sock->prop) {
|
||||
IDP_FreeProperty_ex(sock->prop, false);
|
||||
}
|
||||
|
||||
if (sock->default_value) {
|
||||
MEM_freeN(sock->default_value);
|
||||
}
|
||||
if (sock->default_attribute_name) {
|
||||
MEM_freeN(sock->default_attribute_name);
|
||||
}
|
||||
MEM_delete(sock->runtime);
|
||||
}
|
||||
|
||||
static void cleanup_legacy_sockets(bNodeTree *ntree)
|
||||
{
|
||||
/* Clean up temporary inputs/outputs. */
|
||||
LISTBASE_FOREACH_MUTABLE (bNodeSocket *, socket, &ntree->inputs_legacy) {
|
||||
legacy_socket_interface_free(socket);
|
||||
MEM_freeN(socket);
|
||||
}
|
||||
LISTBASE_FOREACH_MUTABLE (bNodeSocket *, socket, &ntree->outputs_legacy) {
|
||||
legacy_socket_interface_free(socket);
|
||||
MEM_freeN(socket);
|
||||
}
|
||||
BLI_listbase_clear(&ntree->inputs_legacy);
|
||||
BLI_listbase_clear(&ntree->outputs_legacy);
|
||||
}
|
||||
|
||||
static void update_node_location_legacy(bNodeTree &ntree)
|
||||
{
|
||||
for (bNode *node : ntree.all_nodes()) {
|
||||
@@ -1198,9 +991,6 @@ void node_tree_blend_write(BlendWriter *writer, bNodeTree *ntree)
|
||||
}
|
||||
|
||||
ntree->tree_interface.write(writer);
|
||||
if (!BLO_write_is_undo(writer)) {
|
||||
forward_compat::write_legacy_sockets(writer, ntree);
|
||||
}
|
||||
|
||||
BLO_write_struct(writer, GeometryNodeAssetTraits, ntree->geometry_node_asset_traits);
|
||||
|
||||
@@ -1218,20 +1008,9 @@ static void ntree_blend_write(BlendWriter *writer, ID *id, const void *id_addres
|
||||
ntree->typeinfo = nullptr;
|
||||
ntree->runtime->execdata = nullptr;
|
||||
|
||||
if (!BLO_write_is_undo(writer)) {
|
||||
/* Generate legacy inputs/outputs socket ListBase for forward compatibility.
|
||||
* NOTE: this has to happen before writing the ntree struct itself so that the ListBase
|
||||
* first/last pointers are valid. */
|
||||
forward_compat::construct_interface_as_legacy_sockets(ntree);
|
||||
}
|
||||
|
||||
BLO_write_id_struct(writer, bNodeTree, id_address, &ntree->id);
|
||||
|
||||
node_tree_blend_write(writer, ntree);
|
||||
|
||||
if (!BLO_write_is_undo(writer)) {
|
||||
forward_compat::cleanup_legacy_sockets(ntree);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user