Nodes: New Object and Image socket types

Those new socket types will be necessary for particle nodes.

The main difficulty with adding these socket types is that they
are the first that reference ID data in their `value`.
Therefore, user counting code had to be added in a couple new places.

Reviewers: brecht, mont29

Differential Revision: https://developer.blender.org/D7347
This commit is contained in:
Jacques Lucke 2020-04-20 13:22:20 +02:00
parent 2b2d3c14fe
commit 8759813abd
Notes: blender-bot 2023-02-13 22:41:05 +01:00
Referenced by issue #76277, Enabling Viewer Border in Compositor Crashes Blender
8 changed files with 342 additions and 40 deletions

View File

@ -205,6 +205,36 @@ static void library_foreach_idproperty_ID_link(LibraryForeachIDData *data,
FOREACH_FINALIZE_VOID;
}
static void library_foreach_node_socket(LibraryForeachIDData *data, bNodeSocket *sock)
{
library_foreach_idproperty_ID_link(data, sock->prop, IDWALK_CB_USER);
switch ((eNodeSocketDatatype)sock->type) {
case SOCK_OBJECT: {
bNodeSocketValueObject *default_value = sock->default_value;
FOREACH_CALLBACK_INVOKE_ID_PP(data, (ID **)&default_value->value, IDWALK_CB_USER);
break;
}
case SOCK_IMAGE: {
bNodeSocketValueImage *default_value = sock->default_value;
FOREACH_CALLBACK_INVOKE_ID_PP(data, (ID **)&default_value->value, IDWALK_CB_USER);
break;
}
case SOCK_FLOAT:
case SOCK_VECTOR:
case SOCK_RGBA:
case SOCK_BOOLEAN:
case SOCK_INT:
case SOCK_STRING:
case __SOCK_MESH:
case SOCK_CUSTOM:
case SOCK_SHADER:
break;
}
FOREACH_FINALIZE_VOID;
}
static void library_foreach_rigidbodyworldSceneLooper(struct RigidBodyWorld *UNUSED(rbw),
ID **id_pointer,
void *user_data,
@ -1018,7 +1048,6 @@ static void library_foreach_ID_link(Main *bmain,
case ID_NT: {
bNodeTree *ntree = (bNodeTree *)id;
bNode *node;
bNodeSocket *sock;
CALLBACK_INVOKE(ntree->gpd, IDWALK_CB_USER);
@ -1026,19 +1055,19 @@ static void library_foreach_ID_link(Main *bmain,
CALLBACK_INVOKE_ID(node->id, IDWALK_CB_USER);
library_foreach_idproperty_ID_link(&data, node->prop, IDWALK_CB_USER);
for (sock = node->inputs.first; sock; sock = sock->next) {
library_foreach_idproperty_ID_link(&data, sock->prop, IDWALK_CB_USER);
LISTBASE_FOREACH (bNodeSocket *, sock, &node->inputs) {
library_foreach_node_socket(&data, sock);
}
for (sock = node->outputs.first; sock; sock = sock->next) {
library_foreach_idproperty_ID_link(&data, sock->prop, IDWALK_CB_USER);
LISTBASE_FOREACH (bNodeSocket *, sock, &node->outputs) {
library_foreach_node_socket(&data, sock);
}
}
for (sock = ntree->inputs.first; sock; sock = sock->next) {
library_foreach_idproperty_ID_link(&data, sock->prop, IDWALK_CB_USER);
LISTBASE_FOREACH (bNodeSocket *, sock, &ntree->inputs) {
library_foreach_node_socket(&data, sock);
}
for (sock = ntree->outputs.first; sock; sock = sock->next) {
library_foreach_idproperty_ID_link(&data, sock->prop, IDWALK_CB_USER);
LISTBASE_FOREACH (bNodeSocket *, sock, &ntree->outputs) {
library_foreach_node_socket(&data, sock);
}
break;
}

View File

@ -88,7 +88,9 @@ static void ntree_set_typeinfo(bNodeTree *ntree, bNodeTreeType *typeinfo);
static void node_socket_copy(bNodeSocket *sock_dst, const bNodeSocket *sock_src, const int flag);
static void free_localized_node_groups(bNodeTree *ntree);
static void node_free_node(bNodeTree *ntree, bNode *node);
static void node_socket_interface_free(bNodeTree *UNUSED(ntree), bNodeSocket *sock);
static void node_socket_interface_free(bNodeTree *UNUSED(ntree),
bNodeSocket *sock,
const bool do_id_user);
static void ntree_init_data(ID *id)
{
@ -231,12 +233,12 @@ static void ntree_free_data(ID *id)
/* free interface sockets */
for (sock = ntree->inputs.first; sock; sock = nextsock) {
nextsock = sock->next;
node_socket_interface_free(ntree, sock);
node_socket_interface_free(ntree, sock, false);
MEM_freeN(sock);
}
for (sock = ntree->outputs.first; sock; sock = nextsock) {
nextsock = sock->next;
node_socket_interface_free(ntree, sock);
node_socket_interface_free(ntree, sock, false);
MEM_freeN(sock);
}
@ -746,6 +748,58 @@ static bNodeSocket *make_socket(bNodeTree *ntree,
return sock;
}
static void socket_id_user_increment(bNodeSocket *sock)
{
switch ((eNodeSocketDatatype)sock->type) {
case SOCK_OBJECT: {
bNodeSocketValueObject *default_value = sock->default_value;
id_us_plus(&default_value->value->id);
break;
}
case SOCK_IMAGE: {
bNodeSocketValueImage *default_value = sock->default_value;
id_us_plus(&default_value->value->id);
break;
}
case SOCK_FLOAT:
case SOCK_VECTOR:
case SOCK_RGBA:
case SOCK_BOOLEAN:
case SOCK_INT:
case SOCK_STRING:
case __SOCK_MESH:
case SOCK_CUSTOM:
case SOCK_SHADER:
break;
}
}
static void socket_id_user_decrement(bNodeSocket *sock)
{
switch ((eNodeSocketDatatype)sock->type) {
case SOCK_OBJECT: {
bNodeSocketValueObject *default_value = sock->default_value;
id_us_min(&default_value->value->id);
break;
}
case SOCK_IMAGE: {
bNodeSocketValueImage *default_value = sock->default_value;
id_us_min(&default_value->value->id);
break;
}
case SOCK_FLOAT:
case SOCK_VECTOR:
case SOCK_RGBA:
case SOCK_BOOLEAN:
case SOCK_INT:
case SOCK_STRING:
case __SOCK_MESH:
case SOCK_CUSTOM:
case SOCK_SHADER:
break;
}
}
void nodeModifySocketType(
bNodeTree *ntree, bNode *UNUSED(node), bNodeSocket *sock, int type, int subtype)
{
@ -757,6 +811,7 @@ void nodeModifySocketType(
}
if (sock->default_value) {
socket_id_user_decrement(sock);
MEM_freeN(sock->default_value);
sock->default_value = NULL;
}
@ -860,6 +915,10 @@ const char *nodeStaticSocketType(int type, int subtype)
return "NodeSocketString";
case SOCK_SHADER:
return "NodeSocketShader";
case SOCK_OBJECT:
return "NodeSocketObject";
case SOCK_IMAGE:
return "NodeSocketImage";
}
return NULL;
}
@ -921,6 +980,10 @@ const char *nodeStaticSocketInterfaceType(int type, int subtype)
return "NodeSocketInterfaceString";
case SOCK_SHADER:
return "NodeSocketInterfaceShader";
case SOCK_OBJECT:
return "NodeSocketInterfaceObject";
case SOCK_IMAGE:
return "NodeSocketInterfaceImage";
}
return NULL;
}
@ -979,6 +1042,9 @@ static void node_socket_free(bNodeTree *UNUSED(ntree),
}
if (sock->default_value) {
if (do_id_user) {
socket_id_user_decrement(sock);
}
MEM_freeN(sock->default_value);
}
}
@ -1265,6 +1331,10 @@ static void node_socket_copy(bNodeSocket *sock_dst, const bNodeSocket *sock_src,
if (sock_src->default_value) {
sock_dst->default_value = MEM_dupallocN(sock_src->default_value);
if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) {
socket_id_user_increment(sock_dst);
}
}
sock_dst->stack_index = 0;
@ -2085,6 +2155,13 @@ void nodeRemoveNode(Main *bmain, bNodeTree *ntree, bNode *node, bool do_id_user)
if (node->id) {
id_us_min(node->id);
}
LISTBASE_FOREACH (bNodeSocket *, sock, &node->inputs) {
socket_id_user_decrement(sock);
}
LISTBASE_FOREACH (bNodeSocket *, sock, &node->outputs) {
socket_id_user_decrement(sock);
}
}
/* Remove animation data. */
@ -2104,13 +2181,18 @@ void nodeRemoveNode(Main *bmain, bNodeTree *ntree, bNode *node, bool do_id_user)
node_free_node(ntree, node);
}
static void node_socket_interface_free(bNodeTree *UNUSED(ntree), bNodeSocket *sock)
static void node_socket_interface_free(bNodeTree *UNUSED(ntree),
bNodeSocket *sock,
const bool do_id_user)
{
if (sock->prop) {
IDP_FreeProperty(sock->prop);
IDP_FreeProperty_ex(sock->prop, do_id_user);
}
if (sock->default_value) {
if (do_id_user) {
socket_id_user_decrement(sock);
}
MEM_freeN(sock->default_value);
}
}
@ -2533,7 +2615,7 @@ void ntreeRemoveSocketInterface(bNodeTree *ntree, bNodeSocket *sock)
BLI_remlink(&ntree->inputs, sock);
BLI_remlink(&ntree->outputs, sock);
node_socket_interface_free(ntree, sock);
node_socket_interface_free(ntree, sock, true);
MEM_freeN(sock);
ntree->update |= NTREE_UPDATE_GROUP;

View File

@ -3602,6 +3602,41 @@ static void lib_link_workspace_instance_hook(FileData *fd, WorkSpaceInstanceHook
/** \name Read ID: Node Tree
* \{ */
static void lib_link_node_socket(FileData *fd, Library *lib, bNodeSocket *sock)
{
IDP_LibLinkProperty(sock->prop, fd);
switch ((eNodeSocketDatatype)sock->type) {
case SOCK_OBJECT: {
bNodeSocketValueObject *default_value = sock->default_value;
default_value->value = newlibadr(fd, lib, default_value->value);
break;
}
case SOCK_IMAGE: {
bNodeSocketValueImage *default_value = sock->default_value;
default_value->value = newlibadr(fd, lib, default_value->value);
break;
}
case SOCK_FLOAT:
case SOCK_VECTOR:
case SOCK_RGBA:
case SOCK_BOOLEAN:
case SOCK_INT:
case SOCK_STRING:
case __SOCK_MESH:
case SOCK_CUSTOM:
case SOCK_SHADER:
break;
}
}
static void lib_link_node_sockets(FileData *fd, Library *lib, ListBase *sockets)
{
LISTBASE_FOREACH (bNodeSocket *, sock, sockets) {
lib_link_node_socket(fd, lib, sock);
}
}
/* Single node tree (also used for material/scene trees), ntree is not NULL */
static void lib_link_ntree(FileData *fd, Library *lib, bNodeTree *ntree)
{
@ -3616,20 +3651,12 @@ static void lib_link_ntree(FileData *fd, Library *lib, bNodeTree *ntree)
node->id = newlibadr(fd, lib, node->id);
LISTBASE_FOREACH (bNodeSocket *, sock, &node->inputs) {
IDP_LibLinkProperty(sock->prop, fd);
}
LISTBASE_FOREACH (bNodeSocket *, sock, &node->outputs) {
IDP_LibLinkProperty(sock->prop, fd);
}
lib_link_node_sockets(fd, lib, &node->inputs);
lib_link_node_sockets(fd, lib, &node->outputs);
}
LISTBASE_FOREACH (bNodeSocket *, sock, &ntree->inputs) {
IDP_LibLinkProperty(sock->prop, fd);
}
LISTBASE_FOREACH (bNodeSocket *, sock, &ntree->outputs) {
IDP_LibLinkProperty(sock->prop, fd);
}
lib_link_node_sockets(fd, lib, &ntree->inputs);
lib_link_node_sockets(fd, lib, &ntree->outputs);
/* Set node->typeinfo pointers. This is done in lib linking, after the
* first versioning that can change types still without functions that
@ -10959,10 +10986,47 @@ static void expand_key(FileData *fd, Main *mainvar, Key *key)
expand_doit(fd, mainvar, key->ipo); // XXX deprecated - old animation system
}
static void expand_node_socket(FileData *fd, Main *mainvar, bNodeSocket *sock)
{
expand_idprops(fd, mainvar, sock->prop);
if (sock->default_value != NULL) {
switch ((eNodeSocketDatatype)sock->type) {
case SOCK_OBJECT: {
bNodeSocketValueObject *default_value = sock->default_value;
expand_doit(fd, mainvar, default_value->value);
break;
}
case SOCK_IMAGE: {
bNodeSocketValueImage *default_value = sock->default_value;
expand_doit(fd, mainvar, default_value->value);
break;
}
case SOCK_FLOAT:
case SOCK_VECTOR:
case SOCK_RGBA:
case SOCK_BOOLEAN:
case SOCK_INT:
case SOCK_STRING:
case __SOCK_MESH:
case SOCK_CUSTOM:
case SOCK_SHADER:
break;
}
}
}
static void expand_node_sockets(FileData *fd, Main *mainvar, ListBase *sockets)
{
LISTBASE_FOREACH (bNodeSocket *, sock, sockets) {
expand_node_socket(fd, mainvar, sock);
}
}
static void expand_nodetree(FileData *fd, Main *mainvar, bNodeTree *ntree)
{
bNode *node;
bNodeSocket *sock;
if (ntree->gpd) {
expand_doit(fd, mainvar, ntree->gpd);
@ -10975,20 +11039,12 @@ static void expand_nodetree(FileData *fd, Main *mainvar, bNodeTree *ntree)
expand_idprops(fd, mainvar, node->prop);
for (sock = node->inputs.first; sock; sock = sock->next) {
expand_idprops(fd, mainvar, sock->prop);
}
for (sock = node->outputs.first; sock; sock = sock->next) {
expand_idprops(fd, mainvar, sock->prop);
}
expand_node_sockets(fd, mainvar, &node->inputs);
expand_node_sockets(fd, mainvar, &node->outputs);
}
for (sock = ntree->inputs.first; sock; sock = sock->next) {
expand_idprops(fd, mainvar, sock->prop);
}
for (sock = ntree->outputs.first; sock; sock = sock->next) {
expand_idprops(fd, mainvar, sock->prop);
}
expand_node_sockets(fd, mainvar, &ntree->inputs);
expand_node_sockets(fd, mainvar, &ntree->outputs);
}
static void expand_texture(FileData *fd, Main *mainvar, Tex *tex)

View File

@ -991,6 +991,12 @@ static void write_node_socket_default_value(WriteData *wd, bNodeSocket *sock)
case SOCK_STRING:
writestruct(wd, DATA, bNodeSocketValueString, 1, sock->default_value);
break;
case SOCK_OBJECT:
writestruct(wd, DATA, bNodeSocketValueObject, 1, sock->default_value);
break;
case SOCK_IMAGE:
writestruct(wd, DATA, bNodeSocketValueImage, 1, sock->default_value);
break;
case __SOCK_MESH:
case SOCK_CUSTOM:
case SOCK_SHADER:

View File

@ -3277,6 +3277,8 @@ static const float std_node_socket_colors[][4] = {
{0.0, 0.0, 0.0, 1.0}, /*__SOCK_MESH (deprecated) */
{0.06, 0.52, 0.15, 1.0}, /* SOCK_INT */
{0.39, 0.39, 0.39, 1.0}, /* SOCK_STRING */
{0.40, 0.10, 0.10, 1.0}, /* SOCK_OBJECT */
{0.10, 0.40, 0.10, 1.0}, /* SOCK_IMAGE */
};
/* common color callbacks for standard types */
@ -3394,6 +3396,14 @@ static void std_node_socket_draw(
uiItemR(row, ptr, "default_value", 0, "", 0);
break;
}
case SOCK_OBJECT: {
uiItemR(layout, ptr, "default_value", 0, text, 0);
break;
}
case SOCK_IMAGE: {
uiItemR(layout, ptr, "default_value", 0, text, 0);
break;
}
default:
node_socket_button_label(C, layout, ptr, node_ptr, text);
break;

View File

@ -154,6 +154,8 @@ typedef enum eNodeSocketDatatype {
__SOCK_MESH = 5, /* deprecated */
SOCK_INT = 6,
SOCK_STRING = 7,
SOCK_OBJECT = 8,
SOCK_IMAGE = 9,
} eNodeSocketDatatype;
/* socket shape */
@ -566,6 +568,14 @@ typedef struct bNodeSocketValueString {
char value[1024];
} bNodeSocketValueString;
typedef struct bNodeSocketValueObject {
struct Object *value;
} bNodeSocketValueObject;
typedef struct bNodeSocketValueImage {
struct Image *value;
} bNodeSocketValueImage;
/* data structs, for node->storage */
enum {
CMP_NODE_MASKTYPE_ADD = 0,

View File

@ -81,6 +81,8 @@ static const EnumPropertyItem node_socket_type_items[] = {
{SOCK_STRING, "STRING", 0, "String", ""},
{SOCK_RGBA, "RGBA", 0, "RGBA", ""},
{SOCK_SHADER, "SHADER", 0, "Shader", ""},
{SOCK_OBJECT, "OBJECT", 0, "Object", ""},
{SOCK_IMAGE, "IMAGE", 0, "Image", ""},
{0, NULL, 0, NULL, NULL},
};
@ -8538,6 +8540,74 @@ static void rna_def_node_socket_virtual(BlenderRNA *brna, const char *identifier
RNA_def_struct_sdna(srna, "bNodeSocket");
}
static void rna_def_node_socket_object(BlenderRNA *brna,
const char *identifier,
const char *interface_idname)
{
StructRNA *srna;
PropertyRNA *prop;
srna = RNA_def_struct(brna, identifier, "NodeSocketStandard");
RNA_def_struct_ui_text(srna, "Object Node Socket", "Object socket of a node");
RNA_def_struct_sdna(srna, "bNodeSocket");
RNA_def_struct_sdna_from(srna, "bNodeSocketValueObject", "default_value");
prop = RNA_def_property(srna, "default_value", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "value");
RNA_def_property_struct_type(prop, "Object");
RNA_def_property_ui_text(prop, "Default Value", "Input value used for unconnected socket");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_NodeSocketStandard_value_update");
RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_REFCOUNT | PROP_CONTEXT_UPDATE);
/* socket interface */
srna = RNA_def_struct(brna, interface_idname, "NodeSocketInterfaceStandard");
RNA_def_struct_ui_text(srna, "Object Node Socket Interface", "Object socket of a node");
RNA_def_struct_sdna(srna, "bNodeSocket");
RNA_def_struct_sdna_from(srna, "bNodeSocketValueObject", "default_value");
prop = RNA_def_property(srna, "default_value", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "value");
RNA_def_property_struct_type(prop, "Object");
RNA_def_property_ui_text(prop, "Default Value", "Input value used for unconnected socket");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_NodeSocketInterface_update");
}
static void rna_def_node_socket_image(BlenderRNA *brna,
const char *identifier,
const char *interface_idname)
{
StructRNA *srna;
PropertyRNA *prop;
srna = RNA_def_struct(brna, identifier, "NodeSocketStandard");
RNA_def_struct_ui_text(srna, "Image Node Socket", "Image socket of a node");
RNA_def_struct_sdna(srna, "bNodeSocket");
RNA_def_struct_sdna_from(srna, "bNodeSocketValueImage", "default_value");
prop = RNA_def_property(srna, "default_value", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "value");
RNA_def_property_struct_type(prop, "Image");
RNA_def_property_ui_text(prop, "Default Value", "Input value used for unconnected socket");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_NodeSocketStandard_value_update");
RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_REFCOUNT | PROP_CONTEXT_UPDATE);
/* socket interface */
srna = RNA_def_struct(brna, interface_idname, "NodeSocketInterfaceStandard");
RNA_def_struct_ui_text(srna, "Image Node Socket Interface", "Image socket of a node");
RNA_def_struct_sdna(srna, "bNodeSocket");
RNA_def_struct_sdna_from(srna, "bNodeSocketValueImage", "default_value");
prop = RNA_def_property(srna, "default_value", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "value");
RNA_def_property_struct_type(prop, "Image");
RNA_def_property_ui_text(prop, "Default Value", "Input value used for unconnected socket");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_NodeSocketInterface_update");
}
static void rna_def_node_socket_standard_types(BlenderRNA *brna)
{
/* XXX Workaround: Registered functions are not exposed in python by bpy,
@ -8672,6 +8742,10 @@ static void rna_def_node_socket_standard_types(BlenderRNA *brna)
rna_def_node_socket_shader(brna, "NodeSocketShader", "NodeSocketInterfaceShader");
rna_def_node_socket_virtual(brna, "NodeSocketVirtual");
rna_def_node_socket_object(brna, "NodeSocketObject", "NodeSocketInterfaceObject");
rna_def_node_socket_image(brna, "NodeSocketImage", "NodeSocketInterfaceImage");
}
static void rna_def_internal_node(BlenderRNA *brna)

View File

@ -30,6 +30,7 @@
#include "BLI_string.h"
#include "BLI_utildefines.h"
#include "BKE_lib_id.h"
#include "BKE_node.h"
#include "RNA_access.h"
@ -256,6 +257,22 @@ void node_socket_init_default_value(bNodeSocket *sock)
dval->subtype = subtype;
dval->value[0] = '\0';
sock->default_value = dval;
break;
}
case SOCK_OBJECT: {
bNodeSocketValueObject *dval = MEM_callocN(sizeof(bNodeSocketValueObject),
"node socket value object");
dval->value = NULL;
sock->default_value = dval;
break;
}
case SOCK_IMAGE: {
bNodeSocketValueImage *dval = MEM_callocN(sizeof(bNodeSocketValueImage),
"node socket value image");
dval->value = NULL;
sock->default_value = dval;
break;
}
@ -317,6 +334,20 @@ void node_socket_copy_default_value(bNodeSocket *to, const bNodeSocket *from)
*toval = *fromval;
break;
}
case SOCK_OBJECT: {
bNodeSocketValueObject *toval = to->default_value;
bNodeSocketValueObject *fromval = from->default_value;
*toval = *fromval;
id_us_plus(&toval->value->id);
break;
}
case SOCK_IMAGE: {
bNodeSocketValueImage *toval = to->default_value;
bNodeSocketValueImage *fromval = from->default_value;
*toval = *fromval;
id_us_plus(&toval->value->id);
break;
}
}
to->flag |= (from->flag & SOCK_HIDE_VALUE);
@ -499,5 +530,9 @@ void register_standard_node_socket_types(void)
nodeRegisterSocketType(make_standard_socket_type(SOCK_SHADER, PROP_NONE));
nodeRegisterSocketType(make_standard_socket_type(SOCK_OBJECT, PROP_NONE));
nodeRegisterSocketType(make_standard_socket_type(SOCK_IMAGE, PROP_NONE));
nodeRegisterSocketType(make_socket_type_virtual());
}