tornavis/source/blender/nodes/intern/node_socket.cc

1186 lines
41 KiB
C++

/* SPDX-FileCopyrightText: 2007 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup nodes
*/
#include <climits>
#include "DNA_node_types.h"
#include "BLI_color.hh"
#include "BLI_listbase.h"
#include "BLI_math_euler.hh"
#include "BLI_math_matrix.h"
#include "BLI_math_matrix.hh"
#include "BLI_math_quaternion_types.hh"
#include "BLI_math_vector.h"
#include "BLI_math_vector_types.hh"
#include "BLI_string.h"
#include "BLI_utildefines.h"
#include "BKE_geometry_set.hh"
#include "BKE_lib_id.hh"
#include "BKE_node.hh"
#include "BKE_node_runtime.hh"
#include "BKE_node_socket_value.hh"
#include "BKE_node_tree_update.hh"
#include "DNA_collection_types.h"
#include "DNA_material_types.h"
#include "RNA_access.hh"
#include "MEM_guardedalloc.h"
#include "NOD_node_declaration.hh"
#include "NOD_socket.hh"
#include "NOD_socket_declarations.hh"
#include "NOD_socket_declarations_geometry.hh"
using namespace blender;
using blender::bke::SocketValueVariant;
using blender::nodes::SocketDeclarationPtr;
bNodeSocket *node_add_socket_from_template(bNodeTree *ntree,
bNode *node,
bNodeSocketTemplate *stemp,
eNodeSocketInOut in_out)
{
bNodeSocket *sock = nodeAddStaticSocket(
ntree, node, in_out, stemp->type, stemp->subtype, stemp->identifier, stemp->name);
sock->flag |= stemp->flag;
/* initialize default_value */
switch (stemp->type) {
case SOCK_FLOAT: {
bNodeSocketValueFloat *dval = (bNodeSocketValueFloat *)sock->default_value;
dval->value = stemp->val1;
dval->min = stemp->min;
dval->max = stemp->max;
break;
}
case SOCK_INT: {
bNodeSocketValueInt *dval = (bNodeSocketValueInt *)sock->default_value;
dval->value = int(stemp->val1);
dval->min = int(stemp->min);
dval->max = int(stemp->max);
break;
}
case SOCK_BOOLEAN: {
bNodeSocketValueBoolean *dval = (bNodeSocketValueBoolean *)sock->default_value;
dval->value = int(stemp->val1);
break;
}
case SOCK_VECTOR: {
bNodeSocketValueVector *dval = (bNodeSocketValueVector *)sock->default_value;
dval->value[0] = stemp->val1;
dval->value[1] = stemp->val2;
dval->value[2] = stemp->val3;
dval->min = stemp->min;
dval->max = stemp->max;
break;
}
case SOCK_RGBA: {
bNodeSocketValueRGBA *dval = (bNodeSocketValueRGBA *)sock->default_value;
dval->value[0] = stemp->val1;
dval->value[1] = stemp->val2;
dval->value[2] = stemp->val3;
dval->value[3] = stemp->val4;
break;
}
}
return sock;
}
static bNodeSocket *verify_socket_template(bNodeTree *ntree,
bNode *node,
eNodeSocketInOut in_out,
ListBase *socklist,
bNodeSocketTemplate *stemp)
{
bNodeSocket *sock;
for (sock = (bNodeSocket *)socklist->first; sock; sock = sock->next) {
if (STREQLEN(sock->name, stemp->name, NODE_MAXSTR)) {
break;
}
}
if (sock) {
if (sock->type != stemp->type) {
nodeModifySocketTypeStatic(ntree, node, sock, stemp->type, stemp->subtype);
}
sock->flag |= stemp->flag;
}
else {
/* no socket for this template found, make a new one */
sock = node_add_socket_from_template(ntree, node, stemp, in_out);
}
/* remove the new socket from the node socket list first,
* will be added back after verification. */
BLI_remlink(socklist, sock);
return sock;
}
static void verify_socket_template_list(bNodeTree *ntree,
bNode *node,
eNodeSocketInOut in_out,
ListBase *socklist,
bNodeSocketTemplate *stemp_first)
{
bNodeSocket *sock, *nextsock;
bNodeSocketTemplate *stemp;
/* no inputs anymore? */
if (stemp_first == nullptr) {
for (sock = (bNodeSocket *)socklist->first; sock; sock = nextsock) {
nextsock = sock->next;
nodeRemoveSocket(ntree, node, sock);
}
}
else {
/* step by step compare */
stemp = stemp_first;
while (stemp->type != -1) {
stemp->sock = verify_socket_template(ntree, node, in_out, socklist, stemp);
stemp++;
}
/* leftovers are removed */
for (sock = (bNodeSocket *)socklist->first; sock; sock = nextsock) {
nextsock = sock->next;
nodeRemoveSocket(ntree, node, sock);
}
/* and we put back the verified sockets */
stemp = stemp_first;
if (socklist->first) {
/* Some dynamic sockets left, store the list start
* so we can add static sockets in front of it. */
sock = (bNodeSocket *)socklist->first;
while (stemp->type != -1) {
/* Put static sockets in front of dynamic. */
BLI_insertlinkbefore(socklist, sock, stemp->sock);
stemp++;
}
}
else {
while (stemp->type != -1) {
BLI_addtail(socklist, stemp->sock);
stemp++;
}
}
}
}
namespace blender::nodes {
static void refresh_node_socket(bNodeTree &ntree,
bNode &node,
const SocketDeclaration &socket_decl,
Vector<bNodeSocket *> &old_sockets,
VectorSet<bNodeSocket *> &new_sockets)
{
/* Try to find a socket that corresponds to the declaration. */
bNodeSocket *old_socket_with_same_identifier = nullptr;
for (const int i : old_sockets.index_range()) {
bNodeSocket &old_socket = *old_sockets[i];
if (old_socket.identifier == socket_decl.identifier) {
old_sockets.remove_and_reorder(i);
old_socket_with_same_identifier = &old_socket;
break;
}
}
bNodeSocket *new_socket = nullptr;
if (old_socket_with_same_identifier == nullptr) {
/* Create a completely new socket. */
new_socket = &socket_decl.build(ntree, node);
}
else {
STRNCPY(old_socket_with_same_identifier->name, socket_decl.name.c_str());
if (socket_decl.matches(*old_socket_with_same_identifier)) {
/* The existing socket matches exactly, just use it. */
new_socket = old_socket_with_same_identifier;
}
else {
/* Clear out identifier to avoid name collisions when a new socket is created. */
old_socket_with_same_identifier->identifier[0] = '\0';
new_socket = &socket_decl.update_or_build(ntree, node, *old_socket_with_same_identifier);
if (new_socket == old_socket_with_same_identifier) {
/* The existing socket has been updated, set the correct identifier again. */
STRNCPY(new_socket->identifier, socket_decl.identifier.c_str());
}
else {
/* Move links to new socket with same identifier. */
LISTBASE_FOREACH (bNodeLink *, link, &ntree.links) {
if (link->fromsock == old_socket_with_same_identifier) {
link->fromsock = new_socket;
}
else if (link->tosock == old_socket_with_same_identifier) {
link->tosock = new_socket;
}
}
for (bNodeLink &internal_link : node.runtime->internal_links) {
if (internal_link.fromsock == old_socket_with_same_identifier) {
internal_link.fromsock = new_socket;
}
else if (internal_link.tosock == old_socket_with_same_identifier) {
internal_link.tosock = new_socket;
}
}
}
}
}
new_sockets.add_new(new_socket);
BKE_ntree_update_tag_socket_new(&ntree, new_socket);
}
static void refresh_node_panel(const PanelDeclaration &panel_decl,
Vector<bNodePanelState> &old_panels,
bNodePanelState &new_panel)
{
/* Try to find a panel that corresponds to the declaration. */
bNodePanelState *old_panel_with_same_identifier = nullptr;
for (const int i : old_panels.index_range()) {
bNodePanelState &old_panel = old_panels[i];
if (old_panel.identifier == panel_decl.identifier) {
/* Panel is removed after copying to #new_panel. */
old_panel_with_same_identifier = &old_panel;
break;
}
}
if (old_panel_with_same_identifier == nullptr) {
/* Create a completely new panel. */
panel_decl.build(new_panel);
}
else {
if (panel_decl.matches(*old_panel_with_same_identifier)) {
/* The existing socket matches exactly, just use it. */
new_panel = *old_panel_with_same_identifier;
}
else {
/* Clear out identifier to avoid name collisions when a new panel is created. */
old_panel_with_same_identifier->identifier = -1;
panel_decl.update_or_build(*old_panel_with_same_identifier, new_panel);
}
/* Remove from old panels. */
const int64_t old_panel_index = old_panel_with_same_identifier - old_panels.begin();
old_panels.remove_and_reorder(old_panel_index);
}
}
static const char *get_identifier_from_decl(const char *identifier_prefix,
const bNodeSocket &socket,
const Span<const SocketDeclaration *> socket_decls)
{
if (!BLI_str_startswith(socket.identifier, identifier_prefix)) {
return nullptr;
}
for (const SocketDeclaration *socket_decl : socket_decls) {
if (BLI_str_startswith(socket_decl->identifier.c_str(), identifier_prefix)) {
if (socket.type == socket_decl->socket_type) {
return socket_decl->identifier.c_str();
}
}
}
return nullptr;
}
static const char *get_identifier_from_decl(const Span<const char *> identifier_prefixes,
const bNodeSocket &socket,
const Span<const SocketDeclaration *> socket_decls)
{
for (const char *identifier_prefix : identifier_prefixes) {
if (const char *identifier = get_identifier_from_decl(identifier_prefix, socket, socket_decls))
{
return identifier;
}
}
return nullptr;
}
/**
* Currently, nodes that support different socket types have sockets for all supported types with
* different identifiers (e.g. `Attribute`, `Attribute_001`, `Attribute_002`, ...). In the future,
* we will hopefully have a better way to handle this that does not require all the sockets of
* different types to exist at the same time. Instead we want that there is only a single socket
* that can change its type while the identifier stays the same.
*
* This function prepares us for that future. It returns the identifier that we use for a socket
* now based on the "base socket name" (e.g. `Attribute`) and its socket type. It allows us to
* change the socket identifiers in the future without breaking forward compatibility for the nodes
* handled here.
*/
static const char *get_current_socket_identifier_for_future_socket(
const bNode &node,
const bNodeSocket &socket,
const Span<const SocketDeclaration *> socket_decls)
{
switch (node.type) {
case FN_NODE_RANDOM_VALUE: {
return get_identifier_from_decl({"Min", "Max", "Value"}, socket, socket_decls);
}
case SH_NODE_MIX: {
return get_identifier_from_decl({"A", "B", "Result"}, socket, socket_decls);
}
case FN_NODE_COMPARE: {
if (STREQ(socket.identifier, "Angle")) {
return nullptr;
}
return get_identifier_from_decl({"A", "B"}, socket, socket_decls);
}
case SH_NODE_MAP_RANGE: {
if (socket.type == SOCK_VECTOR) {
if (STREQ(socket.identifier, "Value")) {
return "Vector";
}
if (STREQ(socket.identifier, "From Min")) {
return "From_Min_FLOAT3";
}
if (STREQ(socket.identifier, "From Max")) {
return "From_Max_FLOAT3";
}
if (STREQ(socket.identifier, "To Min")) {
return "To_Min_FLOAT3";
}
if (STREQ(socket.identifier, "To Max")) {
return "To_Max_FLOAT3";
}
if (STREQ(socket.identifier, "Steps")) {
return "Steps_FLOAT3";
}
if (STREQ(socket.identifier, "Result")) {
return "Vector";
}
}
return nullptr;
}
}
return nullptr;
}
/**
* Try to update identifiers of sockets created in the future to match identifiers that exist now.
*/
static void do_forward_compat_versioning(bNode &node, const NodeDeclaration &node_decl)
{
LISTBASE_FOREACH (bNodeSocket *, socket, &node.inputs) {
if (socket->is_available()) {
if (const char *new_identifier = get_current_socket_identifier_for_future_socket(
node, *socket, node_decl.inputs))
{
STRNCPY(socket->identifier, new_identifier);
}
}
}
LISTBASE_FOREACH (bNodeSocket *, socket, &node.outputs) {
if (socket->is_available()) {
if (const char *new_identifier = get_current_socket_identifier_for_future_socket(
node, *socket, node_decl.outputs))
{
STRNCPY(socket->identifier, new_identifier);
}
}
}
}
static void refresh_node_sockets_and_panels(bNodeTree &ntree,
bNode &node,
const NodeDeclaration &node_decl,
const bool do_id_user)
{
if (!node.runtime->forward_compatible_versioning_done) {
do_forward_compat_versioning(node, node_decl);
node.runtime->forward_compatible_versioning_done = true;
}
/* Count panels */
int new_num_panels = 0;
for (const ItemDeclarationPtr &item_decl : node_decl.items) {
if (dynamic_cast<const PanelDeclaration *>(item_decl.get())) {
++new_num_panels;
}
}
Vector<bNodeSocket *> old_inputs;
LISTBASE_FOREACH (bNodeSocket *, socket, &node.inputs) {
old_inputs.append(socket);
}
Vector<bNodeSocket *> old_outputs;
LISTBASE_FOREACH (bNodeSocket *, socket, &node.outputs) {
old_outputs.append(socket);
}
Vector<bNodePanelState> old_panels = Vector<bNodePanelState>(node.panel_states());
/* New panel states buffer. */
MEM_SAFE_FREE(node.panel_states_array);
node.num_panel_states = new_num_panels;
node.panel_states_array = MEM_cnew_array<bNodePanelState>(new_num_panels, __func__);
/* Find list of sockets to add, mixture of old and new sockets. */
VectorSet<bNodeSocket *> new_inputs;
VectorSet<bNodeSocket *> new_outputs;
bNodePanelState *new_panel = node.panel_states_array;
for (const ItemDeclarationPtr &item_decl : node_decl.items) {
if (const SocketDeclaration *socket_decl = dynamic_cast<const SocketDeclaration *>(
item_decl.get()))
{
if (socket_decl->in_out == SOCK_IN) {
refresh_node_socket(ntree, node, *socket_decl, old_inputs, new_inputs);
}
else {
refresh_node_socket(ntree, node, *socket_decl, old_outputs, new_outputs);
}
}
else if (const PanelDeclaration *panel_decl = dynamic_cast<const PanelDeclaration *>(
item_decl.get()))
{
refresh_node_panel(*panel_decl, old_panels, *new_panel);
++new_panel;
}
}
/* Destroy any remaining sockets that are no longer in the declaration. */
LISTBASE_FOREACH_MUTABLE (bNodeSocket *, old_socket, &node.inputs) {
if (!new_inputs.contains(old_socket)) {
blender::bke::nodeRemoveSocketEx(&ntree, &node, old_socket, do_id_user);
}
}
LISTBASE_FOREACH_MUTABLE (bNodeSocket *, old_socket, &node.outputs) {
if (!new_outputs.contains(old_socket)) {
blender::bke::nodeRemoveSocketEx(&ntree, &node, old_socket, do_id_user);
}
}
/* Clear and reinsert sockets in the new order. */
BLI_listbase_clear(&node.inputs);
BLI_listbase_clear(&node.outputs);
for (bNodeSocket *socket : new_inputs) {
BLI_addtail(&node.inputs, socket);
}
for (bNodeSocket *socket : new_outputs) {
BLI_addtail(&node.outputs, socket);
}
}
static void refresh_node(bNodeTree &ntree,
bNode &node,
blender::nodes::NodeDeclaration &node_decl,
bool do_id_user)
{
if (node_decl.skip_updating_sockets) {
return;
}
if (!node_decl.matches(node)) {
refresh_node_sockets_and_panels(ntree, node, node_decl, do_id_user);
}
blender::bke::nodeSocketDeclarationsUpdate(&node);
}
void update_node_declaration_and_sockets(bNodeTree &ntree, bNode &node)
{
if (node.typeinfo->declare) {
if (node.typeinfo->static_declaration->is_context_dependent) {
if (!node.runtime->declaration) {
node.runtime->declaration = new NodeDeclaration();
}
build_node_declaration(*node.typeinfo, *node.runtime->declaration, &ntree, &node);
}
}
refresh_node(ntree, node, *node.runtime->declaration, true);
}
bool socket_type_supports_fields(const eNodeSocketDatatype socket_type)
{
return ELEM(socket_type,
SOCK_FLOAT,
SOCK_VECTOR,
SOCK_RGBA,
SOCK_BOOLEAN,
SOCK_INT,
SOCK_ROTATION,
SOCK_MENU,
SOCK_MATRIX);
}
bool socket_type_supports_grids(const eNodeSocketDatatype socket_type)
{
return ELEM(socket_type, SOCK_FLOAT, SOCK_VECTOR);
}
} // namespace blender::nodes
void node_verify_sockets(bNodeTree *ntree, bNode *node, bool do_id_user)
{
bNodeType *ntype = node->typeinfo;
if (ntype == nullptr) {
return;
}
if (ntype->declare) {
blender::bke::nodeDeclarationEnsureOnOutdatedNode(ntree, node);
refresh_node(*ntree, *node, *node->runtime->declaration, do_id_user);
return;
}
/* Don't try to match socket lists when there are no templates.
* This prevents dynamically generated sockets to be removed, like for
* group, image or render layer nodes. We have an explicit check for the
* render layer node since it still has fixed sockets too.
*/
if (ntype) {
if (ntype->inputs && ntype->inputs[0].type >= 0) {
verify_socket_template_list(ntree, node, SOCK_IN, &node->inputs, ntype->inputs);
}
if (ntype->outputs && ntype->outputs[0].type >= 0 && node->type != CMP_NODE_R_LAYERS) {
verify_socket_template_list(ntree, node, SOCK_OUT, &node->outputs, ntype->outputs);
}
}
}
void node_socket_init_default_value_data(eNodeSocketDatatype datatype, int subtype, void **data)
{
if (!data) {
return;
}
switch (datatype) {
case SOCK_FLOAT: {
bNodeSocketValueFloat *dval = MEM_cnew<bNodeSocketValueFloat>("node socket value float");
dval->subtype = subtype;
dval->value = 0.0f;
dval->min = -FLT_MAX;
dval->max = FLT_MAX;
*data = dval;
break;
}
case SOCK_INT: {
bNodeSocketValueInt *dval = MEM_cnew<bNodeSocketValueInt>("node socket value int");
dval->subtype = subtype;
dval->value = 0;
dval->min = INT_MIN;
dval->max = INT_MAX;
*data = dval;
break;
}
case SOCK_BOOLEAN: {
bNodeSocketValueBoolean *dval = MEM_cnew<bNodeSocketValueBoolean>("node socket value bool");
dval->value = false;
*data = dval;
break;
}
case SOCK_ROTATION: {
bNodeSocketValueRotation *dval = MEM_cnew<bNodeSocketValueRotation>(__func__);
*data = dval;
break;
}
case SOCK_VECTOR: {
static float default_value[] = {0.0f, 0.0f, 0.0f};
bNodeSocketValueVector *dval = MEM_cnew<bNodeSocketValueVector>("node socket value vector");
dval->subtype = subtype;
copy_v3_v3(dval->value, default_value);
dval->min = -FLT_MAX;
dval->max = FLT_MAX;
*data = dval;
break;
}
case SOCK_RGBA: {
static float default_value[] = {0.0f, 0.0f, 0.0f, 1.0f};
bNodeSocketValueRGBA *dval = MEM_cnew<bNodeSocketValueRGBA>("node socket value color");
copy_v4_v4(dval->value, default_value);
*data = dval;
break;
}
case SOCK_STRING: {
bNodeSocketValueString *dval = MEM_cnew<bNodeSocketValueString>("node socket value string");
dval->subtype = subtype;
dval->value[0] = '\0';
*data = dval;
break;
}
case SOCK_MENU: {
bNodeSocketValueMenu *dval = MEM_cnew<bNodeSocketValueMenu>("node socket value menu");
dval->value = -1;
*data = dval;
break;
}
case SOCK_OBJECT: {
bNodeSocketValueObject *dval = MEM_cnew<bNodeSocketValueObject>("node socket value object");
dval->value = nullptr;
*data = dval;
break;
}
case SOCK_IMAGE: {
bNodeSocketValueImage *dval = MEM_cnew<bNodeSocketValueImage>("node socket value image");
dval->value = nullptr;
*data = dval;
break;
}
case SOCK_COLLECTION: {
bNodeSocketValueCollection *dval = MEM_cnew<bNodeSocketValueCollection>(
"node socket value object");
dval->value = nullptr;
*data = dval;
break;
}
case SOCK_TEXTURE: {
bNodeSocketValueTexture *dval = MEM_cnew<bNodeSocketValueTexture>(
"node socket value texture");
dval->value = nullptr;
*data = dval;
break;
}
case SOCK_MATERIAL: {
bNodeSocketValueMaterial *dval = MEM_cnew<bNodeSocketValueMaterial>(
"node socket value material");
dval->value = nullptr;
*data = dval;
break;
}
case SOCK_CUSTOM:
case SOCK_GEOMETRY:
case SOCK_MATRIX:
case SOCK_SHADER:
break;
}
}
void node_socket_copy_default_value_data(eNodeSocketDatatype datatype, void *to, const void *from)
{
if (!to || !from) {
return;
}
switch (datatype) {
case SOCK_FLOAT: {
bNodeSocketValueFloat *toval = (bNodeSocketValueFloat *)to;
bNodeSocketValueFloat *fromval = (bNodeSocketValueFloat *)from;
*toval = *fromval;
break;
}
case SOCK_INT: {
bNodeSocketValueInt *toval = (bNodeSocketValueInt *)to;
bNodeSocketValueInt *fromval = (bNodeSocketValueInt *)from;
*toval = *fromval;
break;
}
case SOCK_BOOLEAN: {
bNodeSocketValueBoolean *toval = (bNodeSocketValueBoolean *)to;
bNodeSocketValueBoolean *fromval = (bNodeSocketValueBoolean *)from;
*toval = *fromval;
break;
}
case SOCK_VECTOR: {
bNodeSocketValueVector *toval = (bNodeSocketValueVector *)to;
bNodeSocketValueVector *fromval = (bNodeSocketValueVector *)from;
*toval = *fromval;
break;
}
case SOCK_RGBA: {
bNodeSocketValueRGBA *toval = (bNodeSocketValueRGBA *)to;
bNodeSocketValueRGBA *fromval = (bNodeSocketValueRGBA *)from;
*toval = *fromval;
break;
}
case SOCK_ROTATION: {
bNodeSocketValueRotation *toval = (bNodeSocketValueRotation *)to;
bNodeSocketValueRotation *fromval = (bNodeSocketValueRotation *)from;
*toval = *fromval;
break;
}
case SOCK_STRING: {
bNodeSocketValueString *toval = (bNodeSocketValueString *)to;
bNodeSocketValueString *fromval = (bNodeSocketValueString *)from;
*toval = *fromval;
break;
}
case SOCK_MENU: {
bNodeSocketValueMenu *toval = (bNodeSocketValueMenu *)to;
bNodeSocketValueMenu *fromval = (bNodeSocketValueMenu *)from;
*toval = *fromval;
break;
}
case SOCK_OBJECT: {
bNodeSocketValueObject *toval = (bNodeSocketValueObject *)to;
bNodeSocketValueObject *fromval = (bNodeSocketValueObject *)from;
*toval = *fromval;
id_us_plus(&toval->value->id);
break;
}
case SOCK_IMAGE: {
bNodeSocketValueImage *toval = (bNodeSocketValueImage *)to;
bNodeSocketValueImage *fromval = (bNodeSocketValueImage *)from;
*toval = *fromval;
id_us_plus(&toval->value->id);
break;
}
case SOCK_COLLECTION: {
bNodeSocketValueCollection *toval = (bNodeSocketValueCollection *)to;
bNodeSocketValueCollection *fromval = (bNodeSocketValueCollection *)from;
*toval = *fromval;
id_us_plus(&toval->value->id);
break;
}
case SOCK_TEXTURE: {
bNodeSocketValueTexture *toval = (bNodeSocketValueTexture *)to;
bNodeSocketValueTexture *fromval = (bNodeSocketValueTexture *)from;
*toval = *fromval;
id_us_plus(&toval->value->id);
break;
}
case SOCK_MATERIAL: {
bNodeSocketValueMaterial *toval = (bNodeSocketValueMaterial *)to;
bNodeSocketValueMaterial *fromval = (bNodeSocketValueMaterial *)from;
*toval = *fromval;
id_us_plus(&toval->value->id);
break;
}
case SOCK_CUSTOM:
case SOCK_GEOMETRY:
case SOCK_MATRIX:
case SOCK_SHADER:
break;
}
}
void node_socket_init_default_value(bNodeSocket *sock)
{
if (sock->default_value) {
return; /* already initialized */
}
node_socket_init_default_value_data(eNodeSocketDatatype(sock->typeinfo->type),
PropertySubType(sock->typeinfo->subtype),
&sock->default_value);
}
void node_socket_copy_default_value(bNodeSocket *to, const bNodeSocket *from)
{
/* sanity check */
if (to->type != from->type) {
return;
}
/* make sure both exist */
if (!from->default_value) {
return;
}
node_socket_init_default_value(to);
/* use label instead of name if it has been set */
if (from->label[0] != '\0') {
STRNCPY(to->name, from->label);
}
node_socket_copy_default_value_data(
eNodeSocketDatatype(to->typeinfo->type), to->default_value, from->default_value);
to->flag |= (from->flag & SOCK_HIDE_VALUE);
}
static void standard_node_socket_interface_init_socket(
ID * /*id*/,
const bNodeTreeInterfaceSocket *interface_socket,
bNode * /*node*/,
bNodeSocket *sock,
const char * /*data_path*/)
{
/* initialize the type value */
sock->type = sock->typeinfo->type;
node_socket_init_default_value_data(
eNodeSocketDatatype(sock->type), sock->typeinfo->subtype, &sock->default_value);
node_socket_copy_default_value_data(
eNodeSocketDatatype(sock->type), sock->default_value, interface_socket->socket_data);
}
static void standard_node_socket_interface_from_socket(ID * /*id*/,
bNodeTreeInterfaceSocket *iosock,
const bNode * /*node*/,
const bNodeSocket *sock)
{
/* initialize settings */
iosock->init_from_socket_instance(sock);
}
void ED_init_standard_node_socket_type(bNodeSocketType *);
static bNodeSocketType *make_standard_socket_type(int type, int subtype)
{
const char *socket_idname = nodeStaticSocketType(type, subtype);
const char *interface_idname = nodeStaticSocketInterfaceTypeNew(type, subtype);
const char *socket_label = nodeStaticSocketLabel(type, subtype);
const char *socket_subtype_label = blender::bke::nodeSocketSubTypeLabel(subtype);
bNodeSocketType *stype;
StructRNA *srna;
stype = MEM_cnew<bNodeSocketType>("node socket C type");
stype->free_self = (void (*)(bNodeSocketType *stype))MEM_freeN;
STRNCPY(stype->idname, socket_idname);
STRNCPY(stype->label, socket_label);
STRNCPY(stype->subtype_label, socket_subtype_label);
/* set the RNA type
* uses the exact same identifier as the socket type idname */
srna = stype->ext_socket.srna = RNA_struct_find(socket_idname);
BLI_assert(srna != nullptr);
/* associate the RNA type with the socket type */
RNA_struct_blender_type_set(srna, stype);
/* set the interface RNA type */
srna = stype->ext_interface.srna = RNA_struct_find(interface_idname);
BLI_assert(srna != nullptr);
/* associate the RNA type with the socket type */
RNA_struct_blender_type_set(srna, stype);
/* extra type info for standard socket types */
stype->type = type;
stype->subtype = subtype;
/* XXX bad-level call! needed for setting draw callbacks */
ED_init_standard_node_socket_type(stype);
stype->interface_init_socket = standard_node_socket_interface_init_socket;
stype->interface_from_socket = standard_node_socket_interface_from_socket;
stype->use_link_limits_of_type = true;
stype->input_link_limit = 1;
stype->output_link_limit = 0xFFF;
return stype;
}
void ED_init_node_socket_type_virtual(bNodeSocketType *);
static bNodeSocketType *make_socket_type_virtual()
{
const char *socket_idname = "NodeSocketVirtual";
bNodeSocketType *stype;
StructRNA *srna;
stype = MEM_cnew<bNodeSocketType>("node socket C type");
stype->free_self = (void (*)(bNodeSocketType *stype))MEM_freeN;
STRNCPY(stype->idname, socket_idname);
/* set the RNA type
* uses the exact same identifier as the socket type idname */
srna = stype->ext_socket.srna = RNA_struct_find(socket_idname);
BLI_assert(srna != nullptr);
/* associate the RNA type with the socket type */
RNA_struct_blender_type_set(srna, stype);
/* extra type info for standard socket types */
stype->type = SOCK_CUSTOM;
ED_init_node_socket_type_virtual(stype);
stype->use_link_limits_of_type = true;
stype->input_link_limit = 0xFFF;
stype->output_link_limit = 0xFFF;
return stype;
}
static bNodeSocketType *make_socket_type_bool()
{
bNodeSocketType *socktype = make_standard_socket_type(SOCK_BOOLEAN, PROP_NONE);
socktype->base_cpp_type = &blender::CPPType::get<bool>();
socktype->get_base_cpp_value = [](const void *socket_value, void *r_value) {
*(bool *)r_value = ((bNodeSocketValueBoolean *)socket_value)->value;
};
socktype->geometry_nodes_cpp_type = &blender::CPPType::get<SocketValueVariant>();
socktype->get_geometry_nodes_cpp_value = [](const void *socket_value, void *r_value) {
const bool value = ((bNodeSocketValueBoolean *)socket_value)->value;
new (r_value) SocketValueVariant(value);
};
static SocketValueVariant default_value{false};
socktype->geometry_nodes_default_cpp_value = &default_value;
return socktype;
}
static bNodeSocketType *make_socket_type_rotation()
{
bNodeSocketType *socktype = make_standard_socket_type(SOCK_ROTATION, PROP_NONE);
socktype->base_cpp_type = &blender::CPPType::get<math::Quaternion>();
socktype->get_base_cpp_value = [](const void *socket_value, void *r_value) {
const auto &typed_value = *(bNodeSocketValueRotation *)socket_value;
const math::EulerXYZ euler(float3(typed_value.value_euler));
*static_cast<math::Quaternion *>(r_value) = math::to_quaternion(euler);
};
socktype->geometry_nodes_cpp_type = &blender::CPPType::get<SocketValueVariant>();
socktype->get_geometry_nodes_cpp_value = [](const void *socket_value, void *r_value) {
const auto &typed_value = *(bNodeSocketValueRotation *)socket_value;
const math::EulerXYZ euler(float3(typed_value.value_euler));
const math::Quaternion value = math::to_quaternion(euler);
new (r_value) SocketValueVariant(value);
};
static SocketValueVariant default_value{math::Quaternion::identity()};
socktype->geometry_nodes_default_cpp_value = &default_value;
return socktype;
}
static bNodeSocketType *make_socket_type_matrix()
{
bNodeSocketType *socktype = make_standard_socket_type(SOCK_MATRIX, PROP_NONE);
socktype->base_cpp_type = &blender::CPPType::get<float4x4>();
socktype->get_base_cpp_value = [](const void * /*socket_value*/, void *r_value) {
*static_cast<float4x4 *>(r_value) = float4x4::identity();
};
socktype->geometry_nodes_cpp_type = &blender::CPPType::get<SocketValueVariant>();
socktype->get_geometry_nodes_cpp_value = [](const void * /*socket_value*/, void *r_value) {
new (r_value) SocketValueVariant(float4x4::identity());
};
static SocketValueVariant default_value{float4x4::identity()};
socktype->geometry_nodes_default_cpp_value = &default_value;
return socktype;
}
static bNodeSocketType *make_socket_type_float(PropertySubType subtype)
{
bNodeSocketType *socktype = make_standard_socket_type(SOCK_FLOAT, subtype);
socktype->base_cpp_type = &blender::CPPType::get<float>();
socktype->get_base_cpp_value = [](const void *socket_value, void *r_value) {
*(float *)r_value = ((bNodeSocketValueFloat *)socket_value)->value;
};
socktype->geometry_nodes_cpp_type = &blender::CPPType::get<SocketValueVariant>();
socktype->get_geometry_nodes_cpp_value = [](const void *socket_value, void *r_value) {
const float value = ((bNodeSocketValueFloat *)socket_value)->value;
new (r_value) SocketValueVariant(value);
};
static SocketValueVariant default_value{0.0f};
socktype->geometry_nodes_default_cpp_value = &default_value;
return socktype;
}
static bNodeSocketType *make_socket_type_int(PropertySubType subtype)
{
bNodeSocketType *socktype = make_standard_socket_type(SOCK_INT, subtype);
socktype->base_cpp_type = &blender::CPPType::get<int>();
socktype->get_base_cpp_value = [](const void *socket_value, void *r_value) {
*(int *)r_value = ((bNodeSocketValueInt *)socket_value)->value;
};
socktype->geometry_nodes_cpp_type = &blender::CPPType::get<SocketValueVariant>();
socktype->get_geometry_nodes_cpp_value = [](const void *socket_value, void *r_value) {
const int value = ((bNodeSocketValueInt *)socket_value)->value;
new (r_value) SocketValueVariant(value);
};
static SocketValueVariant default_value{0};
socktype->geometry_nodes_default_cpp_value = &default_value;
return socktype;
}
static bNodeSocketType *make_socket_type_vector(PropertySubType subtype)
{
bNodeSocketType *socktype = make_standard_socket_type(SOCK_VECTOR, subtype);
socktype->base_cpp_type = &blender::CPPType::get<blender::float3>();
socktype->get_base_cpp_value = [](const void *socket_value, void *r_value) {
*(blender::float3 *)r_value = ((bNodeSocketValueVector *)socket_value)->value;
};
socktype->geometry_nodes_cpp_type = &blender::CPPType::get<SocketValueVariant>();
socktype->get_geometry_nodes_cpp_value = [](const void *socket_value, void *r_value) {
const blender::float3 value = ((bNodeSocketValueVector *)socket_value)->value;
new (r_value) SocketValueVariant(value);
};
static SocketValueVariant default_value{blender::float3(0, 0, 0)};
socktype->geometry_nodes_default_cpp_value = &default_value;
return socktype;
}
static bNodeSocketType *make_socket_type_rgba()
{
bNodeSocketType *socktype = make_standard_socket_type(SOCK_RGBA, PROP_NONE);
socktype->base_cpp_type = &blender::CPPType::get<blender::ColorGeometry4f>();
socktype->get_base_cpp_value = [](const void *socket_value, void *r_value) {
*(blender::ColorGeometry4f *)r_value = ((bNodeSocketValueRGBA *)socket_value)->value;
};
socktype->geometry_nodes_cpp_type = &blender::CPPType::get<SocketValueVariant>();
socktype->get_geometry_nodes_cpp_value = [](const void *socket_value, void *r_value) {
const blender::ColorGeometry4f value = ((bNodeSocketValueRGBA *)socket_value)->value;
new (r_value) SocketValueVariant(value);
};
static SocketValueVariant default_value{blender::ColorGeometry4f(0, 0, 0, 0)};
socktype->geometry_nodes_default_cpp_value = &default_value;
return socktype;
}
static bNodeSocketType *make_socket_type_string()
{
bNodeSocketType *socktype = make_standard_socket_type(SOCK_STRING, PROP_NONE);
socktype->base_cpp_type = &blender::CPPType::get<std::string>();
socktype->get_base_cpp_value = [](const void *socket_value, void *r_value) {
new (r_value) std::string(((bNodeSocketValueString *)socket_value)->value);
};
socktype->geometry_nodes_cpp_type = &blender::CPPType::get<SocketValueVariant>();
socktype->get_geometry_nodes_cpp_value = [](const void *socket_value, void *r_value) {
std::string value = ((bNodeSocketValueString *)socket_value)->value;
new (r_value) SocketValueVariant(value);
};
static SocketValueVariant default_value{std::string()};
socktype->geometry_nodes_default_cpp_value = &default_value;
return socktype;
}
static bNodeSocketType *make_socket_type_menu()
{
bNodeSocketType *socktype = make_standard_socket_type(SOCK_MENU, PROP_NONE);
socktype->base_cpp_type = &blender::CPPType::get<int>();
socktype->get_base_cpp_value = [](const void *socket_value, void *r_value) {
*(int *)r_value = ((bNodeSocketValueMenu *)socket_value)->value;
};
socktype->geometry_nodes_cpp_type = &blender::CPPType::get<SocketValueVariant>();
socktype->get_geometry_nodes_cpp_value = [](const void *socket_value, void *r_value) {
const int value = ((bNodeSocketValueMenu *)socket_value)->value;
new (r_value) SocketValueVariant(value);
};
static SocketValueVariant default_value{0};
socktype->geometry_nodes_default_cpp_value = &default_value;
return socktype;
}
static bNodeSocketType *make_socket_type_object()
{
bNodeSocketType *socktype = make_standard_socket_type(SOCK_OBJECT, PROP_NONE);
socktype->base_cpp_type = &blender::CPPType::get<Object *>();
socktype->get_base_cpp_value = [](const void *socket_value, void *r_value) {
*(Object **)r_value = ((bNodeSocketValueObject *)socket_value)->value;
};
socktype->geometry_nodes_cpp_type = socktype->base_cpp_type;
socktype->get_geometry_nodes_cpp_value = socktype->get_base_cpp_value;
return socktype;
}
static bNodeSocketType *make_socket_type_geometry()
{
bNodeSocketType *socktype = make_standard_socket_type(SOCK_GEOMETRY, PROP_NONE);
socktype->base_cpp_type = &blender::CPPType::get<blender::bke::GeometrySet>();
socktype->get_base_cpp_value = [](const void * /*socket_value*/, void *r_value) {
new (r_value) blender::bke::GeometrySet();
};
socktype->geometry_nodes_cpp_type = socktype->base_cpp_type;
socktype->get_geometry_nodes_cpp_value = socktype->get_base_cpp_value;
return socktype;
}
static bNodeSocketType *make_socket_type_collection()
{
bNodeSocketType *socktype = make_standard_socket_type(SOCK_COLLECTION, PROP_NONE);
socktype->base_cpp_type = &blender::CPPType::get<Collection *>();
socktype->get_base_cpp_value = [](const void *socket_value, void *r_value) {
*(Collection **)r_value = ((bNodeSocketValueCollection *)socket_value)->value;
};
socktype->geometry_nodes_cpp_type = socktype->base_cpp_type;
socktype->get_geometry_nodes_cpp_value = socktype->get_base_cpp_value;
return socktype;
}
static bNodeSocketType *make_socket_type_texture()
{
bNodeSocketType *socktype = make_standard_socket_type(SOCK_TEXTURE, PROP_NONE);
socktype->base_cpp_type = &blender::CPPType::get<Tex *>();
socktype->get_base_cpp_value = [](const void *socket_value, void *r_value) {
*(Tex **)r_value = ((bNodeSocketValueTexture *)socket_value)->value;
};
socktype->geometry_nodes_cpp_type = socktype->base_cpp_type;
socktype->get_geometry_nodes_cpp_value = socktype->get_base_cpp_value;
return socktype;
}
static bNodeSocketType *make_socket_type_image()
{
bNodeSocketType *socktype = make_standard_socket_type(SOCK_IMAGE, PROP_NONE);
socktype->base_cpp_type = &blender::CPPType::get<Image *>();
socktype->get_base_cpp_value = [](const void *socket_value, void *r_value) {
*(Image **)r_value = ((bNodeSocketValueImage *)socket_value)->value;
};
socktype->geometry_nodes_cpp_type = socktype->base_cpp_type;
socktype->get_geometry_nodes_cpp_value = socktype->get_base_cpp_value;
return socktype;
}
static bNodeSocketType *make_socket_type_material()
{
bNodeSocketType *socktype = make_standard_socket_type(SOCK_MATERIAL, PROP_NONE);
socktype->base_cpp_type = &blender::CPPType::get<Material *>();
socktype->get_base_cpp_value = [](const void *socket_value, void *r_value) {
*(Material **)r_value = ((bNodeSocketValueMaterial *)socket_value)->value;
};
socktype->geometry_nodes_cpp_type = socktype->base_cpp_type;
socktype->get_geometry_nodes_cpp_value = socktype->get_base_cpp_value;
return socktype;
}
void register_standard_node_socket_types()
{
/* Draw callbacks are set in `drawnode.cc` to avoid bad-level calls. */
nodeRegisterSocketType(make_socket_type_float(PROP_NONE));
nodeRegisterSocketType(make_socket_type_float(PROP_UNSIGNED));
nodeRegisterSocketType(make_socket_type_float(PROP_PERCENTAGE));
nodeRegisterSocketType(make_socket_type_float(PROP_FACTOR));
nodeRegisterSocketType(make_socket_type_float(PROP_ANGLE));
nodeRegisterSocketType(make_socket_type_float(PROP_TIME));
nodeRegisterSocketType(make_socket_type_float(PROP_TIME_ABSOLUTE));
nodeRegisterSocketType(make_socket_type_float(PROP_DISTANCE));
nodeRegisterSocketType(make_socket_type_int(PROP_NONE));
nodeRegisterSocketType(make_socket_type_int(PROP_UNSIGNED));
nodeRegisterSocketType(make_socket_type_int(PROP_PERCENTAGE));
nodeRegisterSocketType(make_socket_type_int(PROP_FACTOR));
nodeRegisterSocketType(make_socket_type_bool());
nodeRegisterSocketType(make_socket_type_rotation());
nodeRegisterSocketType(make_socket_type_matrix());
nodeRegisterSocketType(make_socket_type_vector(PROP_NONE));
nodeRegisterSocketType(make_socket_type_vector(PROP_TRANSLATION));
nodeRegisterSocketType(make_socket_type_vector(PROP_DIRECTION));
nodeRegisterSocketType(make_socket_type_vector(PROP_VELOCITY));
nodeRegisterSocketType(make_socket_type_vector(PROP_ACCELERATION));
nodeRegisterSocketType(make_socket_type_vector(PROP_EULER));
nodeRegisterSocketType(make_socket_type_vector(PROP_XYZ));
nodeRegisterSocketType(make_socket_type_rgba());
nodeRegisterSocketType(make_socket_type_string());
nodeRegisterSocketType(make_socket_type_menu());
nodeRegisterSocketType(make_standard_socket_type(SOCK_SHADER, PROP_NONE));
nodeRegisterSocketType(make_socket_type_object());
nodeRegisterSocketType(make_socket_type_geometry());
nodeRegisterSocketType(make_socket_type_collection());
nodeRegisterSocketType(make_socket_type_texture());
nodeRegisterSocketType(make_socket_type_image());
nodeRegisterSocketType(make_socket_type_material());
nodeRegisterSocketType(make_socket_type_virtual());
}