Geometry Nodes: Add default attribute name to field inputs/outputs
Geometry node group inputs and outputs get a new property that controls the attribute name used for that field input/output when assigning the node group to a modifier for the first time. If the default name is assigned to an input, the default "Use attribute name" is true . In order to properly detect when a node group is first assigned, the modifier now clears its properties when clearing the node group. Ref T96707 Differential Revision: https://developer.blender.org/D14761
This commit is contained in:
@@ -797,8 +797,10 @@ class NodeTreeInterfacePanel:
|
|||||||
active_socket.bl_socket_idname.startswith(prefix)
|
active_socket.bl_socket_idname.startswith(prefix)
|
||||||
for prefix in field_socket_prefixes
|
for prefix in field_socket_prefixes
|
||||||
)
|
)
|
||||||
if in_out == 'OUT' and is_field_type:
|
if is_field_type:
|
||||||
layout.prop(active_socket, "attribute_domain")
|
if in_out == 'OUT':
|
||||||
|
layout.prop(active_socket, "attribute_domain")
|
||||||
|
layout.prop(active_socket, "default_attribute_name")
|
||||||
active_socket.draw(context, layout)
|
active_socket.draw(context, layout)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -487,6 +487,9 @@ static void write_node_socket(BlendWriter *writer, bNodeSocket *sock)
|
|||||||
IDP_BlendWrite(writer, sock->prop);
|
IDP_BlendWrite(writer, sock->prop);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* This property should only be used for group node "interface" sockets. */
|
||||||
|
BLI_assert(sock->default_attribute_name == nullptr);
|
||||||
|
|
||||||
write_node_socket_default_value(writer, sock);
|
write_node_socket_default_value(writer, sock);
|
||||||
}
|
}
|
||||||
static void write_node_socket_interface(BlendWriter *writer, bNodeSocket *sock)
|
static void write_node_socket_interface(BlendWriter *writer, bNodeSocket *sock)
|
||||||
@@ -497,6 +500,8 @@ static void write_node_socket_interface(BlendWriter *writer, bNodeSocket *sock)
|
|||||||
IDP_BlendWrite(writer, sock->prop);
|
IDP_BlendWrite(writer, sock->prop);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BLO_write_string(writer, sock->default_attribute_name);
|
||||||
|
|
||||||
write_node_socket_default_value(writer, sock);
|
write_node_socket_default_value(writer, sock);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -650,6 +655,7 @@ static void direct_link_node_socket(BlendDataReader *reader, bNodeSocket *sock)
|
|||||||
sock->typeinfo = nullptr;
|
sock->typeinfo = nullptr;
|
||||||
BLO_read_data_address(reader, &sock->storage);
|
BLO_read_data_address(reader, &sock->storage);
|
||||||
BLO_read_data_address(reader, &sock->default_value);
|
BLO_read_data_address(reader, &sock->default_value);
|
||||||
|
BLO_read_data_address(reader, &sock->default_attribute_name);
|
||||||
sock->total_inputs = 0; /* Clear runtime data set before drawing. */
|
sock->total_inputs = 0; /* Clear runtime data set before drawing. */
|
||||||
sock->cache = nullptr;
|
sock->cache = nullptr;
|
||||||
sock->declaration = nullptr;
|
sock->declaration = nullptr;
|
||||||
@@ -2161,6 +2167,9 @@ static void node_socket_copy(bNodeSocket *sock_dst, const bNodeSocket *sock_src,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sock_dst->default_attribute_name = static_cast<char *>(
|
||||||
|
MEM_dupallocN(sock_src->default_attribute_name));
|
||||||
|
|
||||||
sock_dst->stack_index = 0;
|
sock_dst->stack_index = 0;
|
||||||
/* XXX some compositor nodes (e.g. image, render layers) still store
|
/* XXX some compositor nodes (e.g. image, render layers) still store
|
||||||
* some persistent buffer data here, need to clear this to avoid dangling pointers. */
|
* some persistent buffer data here, need to clear this to avoid dangling pointers. */
|
||||||
|
|||||||
@@ -139,6 +139,14 @@ typedef struct bNodeSocket {
|
|||||||
char label[64];
|
char label[64];
|
||||||
char description[64];
|
char description[64];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The default attribute name to use for geometry nodes modifier output attribute sockets.
|
||||||
|
* \note Storing this pointer in every single socket exposes the bad design of using sockets
|
||||||
|
* to describe group inputs and outputs. In the future, it should be stored in socket
|
||||||
|
* declarations.
|
||||||
|
*/
|
||||||
|
char *default_attribute_name;
|
||||||
|
|
||||||
/** Cached data from execution. */
|
/** Cached data from execution. */
|
||||||
void *cache;
|
void *cache;
|
||||||
|
|
||||||
|
|||||||
@@ -10890,6 +10890,14 @@ static void rna_def_node_socket_interface(BlenderRNA *brna)
|
|||||||
"Attribute domain used by the geometry nodes modifier to create an attribute output");
|
"Attribute domain used by the geometry nodes modifier to create an attribute output");
|
||||||
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_NodeSocketInterface_update");
|
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_NodeSocketInterface_update");
|
||||||
|
|
||||||
|
prop = RNA_def_property(srna, "default_attribute_name", PROP_STRING, PROP_NONE);
|
||||||
|
RNA_def_property_string_sdna(prop, NULL, "default_attribute_name");
|
||||||
|
RNA_def_property_ui_text(prop,
|
||||||
|
"Default Attribute",
|
||||||
|
"The attribute name used by default when the node group is used by a "
|
||||||
|
"geometry nodes modifier");
|
||||||
|
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_NodeSocketInterface_update");
|
||||||
|
|
||||||
/* registration */
|
/* registration */
|
||||||
prop = RNA_def_property(srna, "bl_socket_idname", PROP_STRING, PROP_NONE);
|
prop = RNA_def_property(srna, "bl_socket_idname", PROP_STRING, PROP_NONE);
|
||||||
RNA_def_property_string_sdna(prop, NULL, "typeinfo->idname");
|
RNA_def_property_string_sdna(prop, NULL, "typeinfo->idname");
|
||||||
|
|||||||
@@ -628,6 +628,10 @@ static void init_socket_cpp_value_from_property(const IDProperty &property,
|
|||||||
void MOD_nodes_update_interface(Object *object, NodesModifierData *nmd)
|
void MOD_nodes_update_interface(Object *object, NodesModifierData *nmd)
|
||||||
{
|
{
|
||||||
if (nmd->node_group == nullptr) {
|
if (nmd->node_group == nullptr) {
|
||||||
|
if (nmd->settings.properties) {
|
||||||
|
IDP_FreeProperty(nmd->settings.properties);
|
||||||
|
nmd->settings.properties = nullptr;
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -680,7 +684,13 @@ void MOD_nodes_update_interface(Object *object, NodesModifierData *nmd)
|
|||||||
IDProperty *attribute_prop = IDP_New(IDP_STRING, &idprop, attribute_name_id.c_str());
|
IDProperty *attribute_prop = IDP_New(IDP_STRING, &idprop, attribute_name_id.c_str());
|
||||||
IDP_AddToGroup(nmd->settings.properties, attribute_prop);
|
IDP_AddToGroup(nmd->settings.properties, attribute_prop);
|
||||||
|
|
||||||
if (old_properties != nullptr) {
|
if (old_properties == nullptr) {
|
||||||
|
if (socket->default_attribute_name && socket->default_attribute_name[0] != '\0') {
|
||||||
|
IDP_AssignString(attribute_prop, socket->default_attribute_name, MAX_NAME);
|
||||||
|
IDP_Int(use_attribute_prop) = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
IDProperty *old_prop_use_attribute = IDP_GetPropertyFromGroup(old_properties,
|
IDProperty *old_prop_use_attribute = IDP_GetPropertyFromGroup(old_properties,
|
||||||
use_attribute_id.c_str());
|
use_attribute_id.c_str());
|
||||||
if (old_prop_use_attribute != nullptr) {
|
if (old_prop_use_attribute != nullptr) {
|
||||||
@@ -709,7 +719,12 @@ void MOD_nodes_update_interface(Object *object, NodesModifierData *nmd)
|
|||||||
}
|
}
|
||||||
IDP_AddToGroup(nmd->settings.properties, new_prop);
|
IDP_AddToGroup(nmd->settings.properties, new_prop);
|
||||||
|
|
||||||
if (old_properties != nullptr) {
|
if (old_properties == nullptr) {
|
||||||
|
if (socket->default_attribute_name && socket->default_attribute_name[0] != '\0') {
|
||||||
|
IDP_AssignString(new_prop, socket->default_attribute_name, MAX_NAME);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
IDProperty *old_prop = IDP_GetPropertyFromGroup(old_properties, idprop_name.c_str());
|
IDProperty *old_prop = IDP_GetPropertyFromGroup(old_properties, idprop_name.c_str());
|
||||||
if (old_prop != nullptr) {
|
if (old_prop != nullptr) {
|
||||||
/* #IDP_CopyPropertyContent replaces the UI data as well, which we don't (we only
|
/* #IDP_CopyPropertyContent replaces the UI data as well, which we don't (we only
|
||||||
@@ -1728,8 +1743,13 @@ static void blendWrite(BlendWriter *writer, const ModifierData *md)
|
|||||||
static void blendRead(BlendDataReader *reader, ModifierData *md)
|
static void blendRead(BlendDataReader *reader, ModifierData *md)
|
||||||
{
|
{
|
||||||
NodesModifierData *nmd = reinterpret_cast<NodesModifierData *>(md);
|
NodesModifierData *nmd = reinterpret_cast<NodesModifierData *>(md);
|
||||||
BLO_read_data_address(reader, &nmd->settings.properties);
|
if (nmd->node_group == nullptr) {
|
||||||
IDP_BlendDataRead(reader, &nmd->settings.properties);
|
nmd->settings.properties = nullptr;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
BLO_read_data_address(reader, &nmd->settings.properties);
|
||||||
|
IDP_BlendDataRead(reader, &nmd->settings.properties);
|
||||||
|
}
|
||||||
nmd->runtime_eval_log = nullptr;
|
nmd->runtime_eval_log = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user