Refactor: move bNodeTree .blend I/O to IDTypeInfo callbacks

This commit is contained in:
Jacques Lucke 2020-09-10 13:33:29 +02:00
parent e347b6b86b
commit d11651fff9
4 changed files with 537 additions and 529 deletions

View File

@ -72,6 +72,10 @@ struct bNodeTree;
struct bNodeTreeExec;
struct bNodeTreeType;
struct uiLayout;
struct BlendWriter;
struct BlendDataReader;
struct BlendLibReader;
struct BlendExpander;
/* -------------------------------------------------------------------- */
/** \name Node Type Definitions
@ -453,6 +457,11 @@ struct bNodeTree *ntreeLocalize(struct bNodeTree *ntree);
void ntreeLocalSync(struct bNodeTree *localtree, struct bNodeTree *ntree);
void ntreeLocalMerge(struct Main *bmain, struct bNodeTree *localtree, struct bNodeTree *ntree);
void ntreeBlendWrite(struct BlendWriter *writer, struct bNodeTree *ntree);
void ntreeBlendReadData(struct BlendDataReader *reader, struct bNodeTree *ntree);
void ntreeBlendReadLib(struct BlendLibReader *reader, struct bNodeTree *ntree);
void ntreeBlendReadExpand(struct BlendExpander *expander, struct bNodeTree *ntree);
/** \} */
/* -------------------------------------------------------------------- */

View File

@ -30,6 +30,9 @@
#include <stdlib.h>
#include <string.h>
/* Allow using deprecated functionality for .blend file I/O. */
#define DNA_DEPRECATED_ALLOW
#include "DNA_action_types.h"
#include "DNA_anim_types.h"
#include "DNA_gpencil_types.h"
@ -54,6 +57,7 @@
#include "BKE_anim_data.h"
#include "BKE_animsys.h"
#include "BKE_colortools.h"
#include "BKE_global.h"
#include "BKE_idprop.h"
#include "BKE_idtype.h"
@ -79,6 +83,8 @@
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_build.h"
#include "BLO_read_write.h"
#define NODE_DEFAULT_MAX_WIDTH 700
/* Fallback types for undefined tree, nodes, sockets */
@ -337,6 +343,511 @@ static void node_foreach_cache(ID *id,
}
}
static void write_node_socket_default_value(BlendWriter *writer, bNodeSocket *sock)
{
if (sock->default_value == NULL) {
return;
}
switch ((eNodeSocketDatatype)sock->type) {
case SOCK_FLOAT:
BLO_write_struct(writer, bNodeSocketValueFloat, sock->default_value);
break;
case SOCK_VECTOR:
BLO_write_struct(writer, bNodeSocketValueVector, sock->default_value);
break;
case SOCK_RGBA:
BLO_write_struct(writer, bNodeSocketValueRGBA, sock->default_value);
break;
case SOCK_BOOLEAN:
BLO_write_struct(writer, bNodeSocketValueBoolean, sock->default_value);
break;
case SOCK_INT:
BLO_write_struct(writer, bNodeSocketValueInt, sock->default_value);
break;
case SOCK_STRING:
BLO_write_struct(writer, bNodeSocketValueString, sock->default_value);
break;
case SOCK_OBJECT:
BLO_write_struct(writer, bNodeSocketValueObject, sock->default_value);
break;
case SOCK_IMAGE:
BLO_write_struct(writer, bNodeSocketValueImage, sock->default_value);
break;
case __SOCK_MESH:
case SOCK_CUSTOM:
case SOCK_SHADER:
case SOCK_EMITTERS:
case SOCK_EVENTS:
case SOCK_FORCES:
case SOCK_CONTROL_FLOW:
BLI_assert(false);
break;
}
}
static void write_node_socket(BlendWriter *writer, bNodeSocket *sock)
{
/* actual socket writing */
BLO_write_struct(writer, bNodeSocket, sock);
if (sock->prop) {
IDP_BlendWrite(writer, sock->prop);
}
write_node_socket_default_value(writer, sock);
}
static void write_node_socket_interface(BlendWriter *writer, bNodeSocket *sock)
{
/* actual socket writing */
BLO_write_struct(writer, bNodeSocket, sock);
if (sock->prop) {
IDP_BlendWrite(writer, sock->prop);
}
write_node_socket_default_value(writer, sock);
}
/* this is only direct data, tree itself should have been written */
void ntreeBlendWrite(BlendWriter *writer, bNodeTree *ntree)
{
/* for link_list() speed, we write per list */
if (ntree->adt) {
BKE_animdata_blend_write(writer, ntree->adt);
}
LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
BLO_write_struct(writer, bNode, node);
if (node->prop) {
IDP_BlendWrite(writer, node->prop);
}
LISTBASE_FOREACH (bNodeSocket *, sock, &node->inputs) {
write_node_socket(writer, sock);
}
LISTBASE_FOREACH (bNodeSocket *, sock, &node->outputs) {
write_node_socket(writer, sock);
}
LISTBASE_FOREACH (bNodeLink *, link, &node->internal_links) {
BLO_write_struct(writer, bNodeLink, link);
}
if (node->storage) {
/* could be handlerized at some point, now only 1 exception still */
if ((ntree->type == NTREE_SHADER) &&
ELEM(node->type, SH_NODE_CURVE_VEC, SH_NODE_CURVE_RGB)) {
BKE_curvemapping_blend_write(writer, node->storage);
}
else if (ntree->type == NTREE_SHADER && (node->type == SH_NODE_SCRIPT)) {
NodeShaderScript *nss = (NodeShaderScript *)node->storage;
if (nss->bytecode) {
BLO_write_string(writer, nss->bytecode);
}
BLO_write_struct_by_name(writer, node->typeinfo->storagename, node->storage);
}
else if ((ntree->type == NTREE_COMPOSIT) && ELEM(node->type,
CMP_NODE_TIME,
CMP_NODE_CURVE_VEC,
CMP_NODE_CURVE_RGB,
CMP_NODE_HUECORRECT)) {
BKE_curvemapping_blend_write(writer, node->storage);
}
else if ((ntree->type == NTREE_TEXTURE) &&
(node->type == TEX_NODE_CURVE_RGB || node->type == TEX_NODE_CURVE_TIME)) {
BKE_curvemapping_blend_write(writer, node->storage);
}
else if ((ntree->type == NTREE_COMPOSIT) && (node->type == CMP_NODE_MOVIEDISTORTION)) {
/* pass */
}
else if ((ntree->type == NTREE_COMPOSIT) && (node->type == CMP_NODE_GLARE)) {
/* Simple forward compatibility for fix for T50736.
* Not ideal (there is no ideal solution here), but should do for now. */
NodeGlare *ndg = node->storage;
/* Not in undo case. */
if (!BLO_write_is_undo(writer)) {
switch (ndg->type) {
case 2: /* Grrrr! magic numbers :( */
ndg->angle = ndg->streaks;
break;
case 0:
ndg->angle = ndg->star_45;
break;
default:
break;
}
}
BLO_write_struct_by_name(writer, node->typeinfo->storagename, node->storage);
}
else if ((ntree->type == NTREE_COMPOSIT) && (node->type == CMP_NODE_CRYPTOMATTE)) {
NodeCryptomatte *nc = (NodeCryptomatte *)node->storage;
if (nc->matte_id) {
BLO_write_string(writer, nc->matte_id);
}
BLO_write_struct_by_name(writer, node->typeinfo->storagename, node->storage);
}
else if (node->typeinfo != &NodeTypeUndefined) {
BLO_write_struct_by_name(writer, node->typeinfo->storagename, node->storage);
}
}
if (node->type == CMP_NODE_OUTPUT_FILE) {
/* inputs have own storage data */
LISTBASE_FOREACH (bNodeSocket *, sock, &node->inputs) {
BLO_write_struct(writer, NodeImageMultiFileSocket, sock->storage);
}
}
if (ELEM(node->type, CMP_NODE_IMAGE, CMP_NODE_R_LAYERS)) {
/* write extra socket info */
LISTBASE_FOREACH (bNodeSocket *, sock, &node->outputs) {
BLO_write_struct(writer, NodeImageLayer, sock->storage);
}
}
}
LISTBASE_FOREACH (bNodeLink *, link, &ntree->links) {
BLO_write_struct(writer, bNodeLink, link);
}
LISTBASE_FOREACH (bNodeSocket *, sock, &ntree->inputs) {
write_node_socket_interface(writer, sock);
}
LISTBASE_FOREACH (bNodeSocket *, sock, &ntree->outputs) {
write_node_socket_interface(writer, sock);
}
}
static void ntree_blend_write(BlendWriter *writer, ID *id, const void *id_address)
{
bNodeTree *ntree = (bNodeTree *)id;
if (ntree->id.us > 0 || BLO_write_is_undo(writer)) {
/* Clean up, important in undo case to reduce false detection of changed datablocks. */
ntree->init = 0; /* to set callbacks and force setting types */
ntree->is_updating = false;
ntree->typeinfo = NULL;
ntree->interface_type = NULL;
ntree->progress = NULL;
ntree->execdata = NULL;
BLO_write_id_struct(writer, bNodeTree, id_address, &ntree->id);
/* Note that trees directly used by other IDs (materials etc.) are not 'real' ID, they cannot
* be linked, etc., so we write actual id data here only, for 'real' ID trees. */
BKE_id_blend_write(writer, &ntree->id);
ntreeBlendWrite(writer, ntree);
}
}
static void direct_link_node_socket(BlendDataReader *reader, bNodeSocket *sock)
{
BLO_read_data_address(reader, &sock->prop);
IDP_BlendDataRead(reader, &sock->prop);
BLO_read_data_address(reader, &sock->link);
sock->typeinfo = NULL;
BLO_read_data_address(reader, &sock->storage);
BLO_read_data_address(reader, &sock->default_value);
sock->cache = NULL;
}
/* ntree itself has been read! */
void ntreeBlendReadData(BlendDataReader *reader, bNodeTree *ntree)
{
/* note: writing and reading goes in sync, for speed */
ntree->init = 0; /* to set callbacks and force setting types */
ntree->is_updating = false;
ntree->typeinfo = NULL;
ntree->interface_type = NULL;
ntree->progress = NULL;
ntree->execdata = NULL;
BLO_read_data_address(reader, &ntree->adt);
BKE_animdata_blend_read_data(reader, ntree->adt);
BLO_read_list(reader, &ntree->nodes);
LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
node->typeinfo = NULL;
BLO_read_list(reader, &node->inputs);
BLO_read_list(reader, &node->outputs);
BLO_read_data_address(reader, &node->prop);
IDP_BlendDataRead(reader, &node->prop);
BLO_read_list(reader, &node->internal_links);
LISTBASE_FOREACH (bNodeLink *, link, &node->internal_links) {
BLO_read_data_address(reader, &link->fromnode);
BLO_read_data_address(reader, &link->fromsock);
BLO_read_data_address(reader, &link->tonode);
BLO_read_data_address(reader, &link->tosock);
}
if (node->type == CMP_NODE_MOVIEDISTORTION) {
/* Do nothing, this is runtime cache and hence handled by generic code using
* `IDTypeInfo.foreach_cache` callback. */
}
else {
BLO_read_data_address(reader, &node->storage);
}
if (node->storage) {
/* could be handlerized at some point */
switch (node->type) {
case SH_NODE_CURVE_VEC:
case SH_NODE_CURVE_RGB:
case CMP_NODE_TIME:
case CMP_NODE_CURVE_VEC:
case CMP_NODE_CURVE_RGB:
case CMP_NODE_HUECORRECT:
case TEX_NODE_CURVE_RGB:
case TEX_NODE_CURVE_TIME: {
BKE_curvemapping_blend_read(reader, node->storage);
break;
}
case SH_NODE_SCRIPT: {
NodeShaderScript *nss = (NodeShaderScript *)node->storage;
BLO_read_data_address(reader, &nss->bytecode);
break;
}
case SH_NODE_TEX_POINTDENSITY: {
NodeShaderTexPointDensity *npd = (NodeShaderTexPointDensity *)node->storage;
memset(&npd->pd, 0, sizeof(npd->pd));
break;
}
case SH_NODE_TEX_IMAGE: {
NodeTexImage *tex = (NodeTexImage *)node->storage;
tex->iuser.ok = 1;
tex->iuser.scene = NULL;
break;
}
case SH_NODE_TEX_ENVIRONMENT: {
NodeTexEnvironment *tex = (NodeTexEnvironment *)node->storage;
tex->iuser.ok = 1;
tex->iuser.scene = NULL;
break;
}
case CMP_NODE_IMAGE:
case CMP_NODE_R_LAYERS:
case CMP_NODE_VIEWER:
case CMP_NODE_SPLITVIEWER: {
ImageUser *iuser = node->storage;
iuser->ok = 1;
iuser->scene = NULL;
break;
}
case CMP_NODE_CRYPTOMATTE: {
NodeCryptomatte *nc = (NodeCryptomatte *)node->storage;
BLO_read_data_address(reader, &nc->matte_id);
break;
}
case TEX_NODE_IMAGE: {
ImageUser *iuser = node->storage;
iuser->ok = 1;
iuser->scene = NULL;
break;
}
default:
break;
}
}
}
BLO_read_list(reader, &ntree->links);
/* and we connect the rest */
LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
BLO_read_data_address(reader, &node->parent);
node->lasty = 0;
LISTBASE_FOREACH (bNodeSocket *, sock, &node->inputs) {
direct_link_node_socket(reader, sock);
}
LISTBASE_FOREACH (bNodeSocket *, sock, &node->outputs) {
direct_link_node_socket(reader, sock);
}
}
/* interface socket lists */
BLO_read_list(reader, &ntree->inputs);
BLO_read_list(reader, &ntree->outputs);
LISTBASE_FOREACH (bNodeSocket *, sock, &ntree->inputs) {
direct_link_node_socket(reader, sock);
}
LISTBASE_FOREACH (bNodeSocket *, sock, &ntree->outputs) {
direct_link_node_socket(reader, sock);
}
LISTBASE_FOREACH (bNodeLink *, link, &ntree->links) {
BLO_read_data_address(reader, &link->fromnode);
BLO_read_data_address(reader, &link->tonode);
BLO_read_data_address(reader, &link->fromsock);
BLO_read_data_address(reader, &link->tosock);
}
/* TODO, should be dealt by new generic cache handling of IDs... */
ntree->previews = NULL;
/* type verification is in lib-link */
}
static void ntree_blend_read_data(BlendDataReader *reader, ID *id)
{
bNodeTree *ntree = (bNodeTree *)id;
ntreeBlendReadData(reader, ntree);
}
static void lib_link_node_socket(BlendLibReader *reader, Library *lib, bNodeSocket *sock)
{
IDP_BlendReadLib(reader, sock->prop);
switch ((eNodeSocketDatatype)sock->type) {
case SOCK_OBJECT: {
bNodeSocketValueObject *default_value = sock->default_value;
BLO_read_id_address(reader, lib, &default_value->value);
break;
}
case SOCK_IMAGE: {
bNodeSocketValueImage *default_value = sock->default_value;
BLO_read_id_address(reader, 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:
case SOCK_EMITTERS:
case SOCK_EVENTS:
case SOCK_FORCES:
case SOCK_CONTROL_FLOW:
break;
}
}
static void lib_link_node_sockets(BlendLibReader *reader, Library *lib, ListBase *sockets)
{
LISTBASE_FOREACH (bNodeSocket *, sock, sockets) {
lib_link_node_socket(reader, lib, sock);
}
}
void ntreeBlendReadLib(struct BlendLibReader *reader, struct bNodeTree *ntree)
{
Library *lib = ntree->id.lib;
BLO_read_id_address(reader, lib, &ntree->gpd);
LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
/* Link ID Properties -- and copy this comment EXACTLY for easy finding
* of library blocks that implement this.*/
IDP_BlendReadLib(reader, node->prop);
BLO_read_id_address(reader, lib, &node->id);
lib_link_node_sockets(reader, lib, &node->inputs);
lib_link_node_sockets(reader, lib, &node->outputs);
}
lib_link_node_sockets(reader, lib, &ntree->inputs);
lib_link_node_sockets(reader, 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
* update the typeinfo pointers. Versioning after lib linking needs
* these top be valid. */
ntreeSetTypes(NULL, ntree);
/* For nodes with static socket layout, add/remove sockets as needed
* to match the static layout. */
if (!BLO_read_lib_is_undo(reader)) {
LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
node_verify_socket_templates(ntree, node);
}
}
}
static void ntree_blend_read_lib(BlendLibReader *reader, ID *id)
{
bNodeTree *ntree = (bNodeTree *)id;
ntreeBlendReadLib(reader, ntree);
}
static void expand_node_socket(BlendExpander *expander, bNodeSocket *sock)
{
IDP_BlendReadExpand(expander, sock->prop);
if (sock->default_value != NULL) {
switch ((eNodeSocketDatatype)sock->type) {
case SOCK_OBJECT: {
bNodeSocketValueObject *default_value = sock->default_value;
BLO_expand(expander, default_value->value);
break;
}
case SOCK_IMAGE: {
bNodeSocketValueImage *default_value = sock->default_value;
BLO_expand(expander, 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:
case SOCK_EMITTERS:
case SOCK_EVENTS:
case SOCK_FORCES:
case SOCK_CONTROL_FLOW:
break;
}
}
}
static void expand_node_sockets(BlendExpander *expander, ListBase *sockets)
{
LISTBASE_FOREACH (bNodeSocket *, sock, sockets) {
expand_node_socket(expander, sock);
}
}
void ntreeBlendReadExpand(BlendExpander *expander, bNodeTree *ntree)
{
if (ntree->gpd) {
BLO_expand(expander, ntree->gpd);
}
LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
if (node->id && node->type != CMP_NODE_R_LAYERS) {
BLO_expand(expander, node->id);
}
IDP_BlendReadExpand(expander, node->prop);
expand_node_sockets(expander, &node->inputs);
expand_node_sockets(expander, &node->outputs);
}
expand_node_sockets(expander, &ntree->inputs);
expand_node_sockets(expander, &ntree->outputs);
}
static void ntree_blend_read_expand(BlendExpander *expander, ID *id)
{
bNodeTree *ntree = (bNodeTree *)id;
ntreeBlendReadExpand(expander, ntree);
}
IDTypeInfo IDType_ID_NT = {
.id_code = ID_NT,
.id_filter = FILTER_ID_NT,
@ -354,10 +865,10 @@ IDTypeInfo IDType_ID_NT = {
.foreach_id = node_foreach_id,
.foreach_cache = node_foreach_cache,
.blend_write = NULL,
.blend_read_data = NULL,
.blend_read_lib = NULL,
.blend_read_expand = NULL,
.blend_write = ntree_blend_write,
.blend_read_data = ntree_blend_read_data,
.blend_read_lib = ntree_blend_read_lib,
.blend_read_expand = ntree_blend_read_expand,
};
static void node_add_sockets_from_type(bNodeTree *ntree, bNode *node, bNodeType *ntype)

View File

@ -2252,7 +2252,6 @@ static void link_glob_list(FileData *fd, ListBase *lb) /* for glob data */
* \{ */
static void lib_link_id(BlendLibReader *reader, ID *id);
static void lib_link_nodetree(BlendLibReader *reader, bNodeTree *ntree);
static void lib_link_collection(BlendLibReader *reader, Collection *collection);
static void lib_link_id_embedded_id(BlendLibReader *reader, ID *id)
@ -2262,7 +2261,7 @@ static void lib_link_id_embedded_id(BlendLibReader *reader, ID *id)
bNodeTree *nodetree = ntreeFromID(id);
if (nodetree != NULL) {
lib_link_id(reader, &nodetree->id);
lib_link_nodetree(reader, nodetree);
ntreeBlendReadLib(reader, nodetree);
}
if (GS(id->name) == ID_SCE) {
@ -2316,7 +2315,6 @@ static void direct_link_id_override_property_cb(BlendDataReader *reader, void *d
static void direct_link_id_common(
BlendDataReader *reader, Library *current_library, ID *id, ID *id_old, const int tag);
static void direct_link_nodetree(BlendDataReader *reader, bNodeTree *ntree);
static void direct_link_collection(BlendDataReader *reader, Collection *collection);
static void direct_link_id_embedded_id(BlendDataReader *reader,
@ -2333,7 +2331,7 @@ static void direct_link_id_embedded_id(BlendDataReader *reader,
(ID *)*nodetree,
id_old != NULL ? (ID *)ntreeFromID(id_old) : NULL,
0);
direct_link_nodetree(reader, *nodetree);
ntreeBlendReadData(reader, *nodetree);
}
if (GS(id->name) == ID_SCE) {
@ -2781,246 +2779,6 @@ static void lib_link_workspace_instance_hook(BlendLibReader *reader,
/** \} */
/* -------------------------------------------------------------------- */
/** \name Read ID: Node Tree
* \{ */
static void lib_link_node_socket(BlendLibReader *reader, Library *lib, bNodeSocket *sock)
{
IDP_BlendReadLib(reader, sock->prop);
switch ((eNodeSocketDatatype)sock->type) {
case SOCK_OBJECT: {
bNodeSocketValueObject *default_value = sock->default_value;
BLO_read_id_address(reader, lib, &default_value->value);
break;
}
case SOCK_IMAGE: {
bNodeSocketValueImage *default_value = sock->default_value;
BLO_read_id_address(reader, 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:
case SOCK_EMITTERS:
case SOCK_EVENTS:
case SOCK_FORCES:
case SOCK_CONTROL_FLOW:
break;
}
}
static void lib_link_node_sockets(BlendLibReader *reader, Library *lib, ListBase *sockets)
{
LISTBASE_FOREACH (bNodeSocket *, sock, sockets) {
lib_link_node_socket(reader, lib, sock);
}
}
/* Single node tree (also used for material/scene trees), ntree is not NULL */
static void lib_link_ntree(BlendLibReader *reader, Library *lib, bNodeTree *ntree)
{
ntree->id.lib = lib;
BLO_read_id_address(reader, lib, &ntree->gpd);
LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
/* Link ID Properties -- and copy this comment EXACTLY for easy finding
* of library blocks that implement this.*/
IDP_BlendReadLib(reader, node->prop);
BLO_read_id_address(reader, lib, &node->id);
lib_link_node_sockets(reader, lib, &node->inputs);
lib_link_node_sockets(reader, lib, &node->outputs);
}
lib_link_node_sockets(reader, lib, &ntree->inputs);
lib_link_node_sockets(reader, 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
* update the typeinfo pointers. Versioning after lib linking needs
* these top be valid. */
ntreeSetTypes(NULL, ntree);
/* For nodes with static socket layout, add/remove sockets as needed
* to match the static layout. */
if (!BLO_read_lib_is_undo(reader)) {
LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
node_verify_socket_templates(ntree, node);
}
}
}
/* library ntree linking after fileread */
static void lib_link_nodetree(BlendLibReader *reader, bNodeTree *ntree)
{
lib_link_ntree(reader, ntree->id.lib, ntree);
}
static void direct_link_node_socket(BlendDataReader *reader, bNodeSocket *sock)
{
BLO_read_data_address(reader, &sock->prop);
IDP_BlendDataRead(reader, &sock->prop);
BLO_read_data_address(reader, &sock->link);
sock->typeinfo = NULL;
BLO_read_data_address(reader, &sock->storage);
BLO_read_data_address(reader, &sock->default_value);
sock->cache = NULL;
}
/* ntree itself has been read! */
static void direct_link_nodetree(BlendDataReader *reader, bNodeTree *ntree)
{
/* note: writing and reading goes in sync, for speed */
ntree->init = 0; /* to set callbacks and force setting types */
ntree->is_updating = false;
ntree->typeinfo = NULL;
ntree->interface_type = NULL;
ntree->progress = NULL;
ntree->execdata = NULL;
BLO_read_data_address(reader, &ntree->adt);
BKE_animdata_blend_read_data(reader, ntree->adt);
BLO_read_list(reader, &ntree->nodes);
LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
node->typeinfo = NULL;
BLO_read_list(reader, &node->inputs);
BLO_read_list(reader, &node->outputs);
BLO_read_data_address(reader, &node->prop);
IDP_BlendDataRead(reader, &node->prop);
BLO_read_list(reader, &node->internal_links);
LISTBASE_FOREACH (bNodeLink *, link, &node->internal_links) {
BLO_read_data_address(reader, &link->fromnode);
BLO_read_data_address(reader, &link->fromsock);
BLO_read_data_address(reader, &link->tonode);
BLO_read_data_address(reader, &link->tosock);
}
if (node->type == CMP_NODE_MOVIEDISTORTION) {
/* Do nothing, this is runtime cache and hence handled by generic code using
* `IDTypeInfo.foreach_cache` callback. */
}
else {
BLO_read_data_address(reader, &node->storage);
}
if (node->storage) {
/* could be handlerized at some point */
switch (node->type) {
case SH_NODE_CURVE_VEC:
case SH_NODE_CURVE_RGB:
case CMP_NODE_TIME:
case CMP_NODE_CURVE_VEC:
case CMP_NODE_CURVE_RGB:
case CMP_NODE_HUECORRECT:
case TEX_NODE_CURVE_RGB:
case TEX_NODE_CURVE_TIME: {
BKE_curvemapping_blend_read(reader, node->storage);
break;
}
case SH_NODE_SCRIPT: {
NodeShaderScript *nss = (NodeShaderScript *)node->storage;
BLO_read_data_address(reader, &nss->bytecode);
break;
}
case SH_NODE_TEX_POINTDENSITY: {
NodeShaderTexPointDensity *npd = (NodeShaderTexPointDensity *)node->storage;
memset(&npd->pd, 0, sizeof(npd->pd));
break;
}
case SH_NODE_TEX_IMAGE: {
NodeTexImage *tex = (NodeTexImage *)node->storage;
tex->iuser.ok = 1;
tex->iuser.scene = NULL;
break;
}
case SH_NODE_TEX_ENVIRONMENT: {
NodeTexEnvironment *tex = (NodeTexEnvironment *)node->storage;
tex->iuser.ok = 1;
tex->iuser.scene = NULL;
break;
}
case CMP_NODE_IMAGE:
case CMP_NODE_R_LAYERS:
case CMP_NODE_VIEWER:
case CMP_NODE_SPLITVIEWER: {
ImageUser *iuser = node->storage;
iuser->ok = 1;
iuser->scene = NULL;
break;
}
case CMP_NODE_CRYPTOMATTE: {
NodeCryptomatte *nc = (NodeCryptomatte *)node->storage;
BLO_read_data_address(reader, &nc->matte_id);
break;
}
case TEX_NODE_IMAGE: {
ImageUser *iuser = node->storage;
iuser->ok = 1;
iuser->scene = NULL;
break;
}
default:
break;
}
}
}
BLO_read_list(reader, &ntree->links);
/* and we connect the rest */
LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
BLO_read_data_address(reader, &node->parent);
node->lasty = 0;
LISTBASE_FOREACH (bNodeSocket *, sock, &node->inputs) {
direct_link_node_socket(reader, sock);
}
LISTBASE_FOREACH (bNodeSocket *, sock, &node->outputs) {
direct_link_node_socket(reader, sock);
}
}
/* interface socket lists */
BLO_read_list(reader, &ntree->inputs);
BLO_read_list(reader, &ntree->outputs);
LISTBASE_FOREACH (bNodeSocket *, sock, &ntree->inputs) {
direct_link_node_socket(reader, sock);
}
LISTBASE_FOREACH (bNodeSocket *, sock, &ntree->outputs) {
direct_link_node_socket(reader, sock);
}
LISTBASE_FOREACH (bNodeLink *, link, &ntree->links) {
BLO_read_data_address(reader, &link->fromnode);
BLO_read_data_address(reader, &link->tonode);
BLO_read_data_address(reader, &link->fromsock);
BLO_read_data_address(reader, &link->tosock);
}
/* TODO, should be dealt by new generic cache handling of IDs... */
ntree->previews = NULL;
/* type verification is in lib-link */
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name Read ID: Armature
* \{ */
@ -7993,9 +7751,6 @@ static bool direct_link_id(FileData *fd, Main *main, const int tag, ID *id, ID *
case ID_AR:
direct_link_armature(&reader, (bArmature *)id);
break;
case ID_NT:
direct_link_nodetree(&reader, (bNodeTree *)id);
break;
case ID_BR:
direct_link_brush(&reader, (Brush *)id);
break;
@ -8041,6 +7796,7 @@ static bool direct_link_id(FileData *fd, Main *main, const int tag, ID *id, ID *
case ID_ME:
case ID_LT:
case ID_AC:
case ID_NT:
/* Do nothing. Handled by IDTypeInfo callback. */
break;
}
@ -8739,10 +8495,6 @@ static void lib_link_all(FileData *fd, Main *bmain)
case ID_IM:
lib_link_image(&reader, (Image *)id);
break;
case ID_NT:
/* Has to be done after node users (scene/materials/...), this will verify group nodes. */
lib_link_nodetree(&reader, (bNodeTree *)id);
break;
case ID_GD:
lib_link_gpencil(&reader, (bGPdata *)id);
break;
@ -8765,6 +8517,7 @@ static void lib_link_all(FileData *fd, Main *bmain)
case ID_ME:
case ID_LT:
case ID_AC:
case ID_NT:
/* Do nothing. Handled by IDTypeInfo callback. */
break;
}
@ -9348,7 +9101,6 @@ static void expand_constraint_channels(BlendExpander *expander, ListBase *chanba
}
static void expand_id(BlendExpander *expander, ID *id);
static void expand_nodetree(BlendExpander *expander, bNodeTree *ntree);
static void expand_collection(BlendExpander *expander, Collection *collection);
static void expand_id_embedded_id(BlendExpander *expander, ID *id)
@ -9357,7 +9109,7 @@ static void expand_id_embedded_id(BlendExpander *expander, ID *id)
bNodeTree *nodetree = ntreeFromID(id);
if (nodetree != NULL) {
expand_id(expander, &nodetree->id);
expand_nodetree(expander, nodetree);
ntreeBlendReadExpand(expander, nodetree);
}
if (GS(id->name) == ID_SCE) {
@ -9456,69 +9208,6 @@ static void expand_key(BlendExpander *expander, Key *key)
BLO_expand(expander, key->ipo); // XXX deprecated - old animation system
}
static void expand_node_socket(BlendExpander *expander, bNodeSocket *sock)
{
IDP_BlendReadExpand(expander, sock->prop);
if (sock->default_value != NULL) {
switch ((eNodeSocketDatatype)sock->type) {
case SOCK_OBJECT: {
bNodeSocketValueObject *default_value = sock->default_value;
BLO_expand(expander, default_value->value);
break;
}
case SOCK_IMAGE: {
bNodeSocketValueImage *default_value = sock->default_value;
BLO_expand(expander, 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:
case SOCK_EMITTERS:
case SOCK_EVENTS:
case SOCK_FORCES:
case SOCK_CONTROL_FLOW:
break;
}
}
}
static void expand_node_sockets(BlendExpander *expander, ListBase *sockets)
{
LISTBASE_FOREACH (bNodeSocket *, sock, sockets) {
expand_node_socket(expander, sock);
}
}
static void expand_nodetree(BlendExpander *expander, bNodeTree *ntree)
{
if (ntree->gpd) {
BLO_expand(expander, ntree->gpd);
}
LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
if (node->id && node->type != CMP_NODE_R_LAYERS) {
BLO_expand(expander, node->id);
}
IDP_BlendReadExpand(expander, node->prop);
expand_node_sockets(expander, &node->inputs);
expand_node_sockets(expander, &node->outputs);
}
expand_node_sockets(expander, &ntree->inputs);
expand_node_sockets(expander, &ntree->outputs);
}
static void expand_texture(BlendExpander *expander, Tex *tex)
{
BLO_expand(expander, tex->ima);
@ -10056,9 +9745,6 @@ void BLO_expand_main(void *fdhandle, Main *mainvar)
case ID_GR:
expand_collection(&expander, (Collection *)id);
break;
case ID_NT:
expand_nodetree(&expander, (bNodeTree *)id);
break;
case ID_BR:
expand_brush(&expander, (Brush *)id);
break;

View File

@ -661,182 +661,6 @@ static void writelist_id(WriteData *wd, int filecode, const char *structname, co
* These functions are used by blender's .blend system for file saving/loading.
* \{ */
static void write_node_socket_default_value(BlendWriter *writer, bNodeSocket *sock)
{
if (sock->default_value == NULL) {
return;
}
switch ((eNodeSocketDatatype)sock->type) {
case SOCK_FLOAT:
BLO_write_struct(writer, bNodeSocketValueFloat, sock->default_value);
break;
case SOCK_VECTOR:
BLO_write_struct(writer, bNodeSocketValueVector, sock->default_value);
break;
case SOCK_RGBA:
BLO_write_struct(writer, bNodeSocketValueRGBA, sock->default_value);
break;
case SOCK_BOOLEAN:
BLO_write_struct(writer, bNodeSocketValueBoolean, sock->default_value);
break;
case SOCK_INT:
BLO_write_struct(writer, bNodeSocketValueInt, sock->default_value);
break;
case SOCK_STRING:
BLO_write_struct(writer, bNodeSocketValueString, sock->default_value);
break;
case SOCK_OBJECT:
BLO_write_struct(writer, bNodeSocketValueObject, sock->default_value);
break;
case SOCK_IMAGE:
BLO_write_struct(writer, bNodeSocketValueImage, sock->default_value);
break;
case __SOCK_MESH:
case SOCK_CUSTOM:
case SOCK_SHADER:
case SOCK_EMITTERS:
case SOCK_EVENTS:
case SOCK_FORCES:
case SOCK_CONTROL_FLOW:
BLI_assert(false);
break;
}
}
static void write_node_socket(BlendWriter *writer, bNodeSocket *sock)
{
/* actual socket writing */
BLO_write_struct(writer, bNodeSocket, sock);
if (sock->prop) {
IDP_BlendWrite(writer, sock->prop);
}
write_node_socket_default_value(writer, sock);
}
static void write_node_socket_interface(BlendWriter *writer, bNodeSocket *sock)
{
/* actual socket writing */
BLO_write_struct(writer, bNodeSocket, sock);
if (sock->prop) {
IDP_BlendWrite(writer, sock->prop);
}
write_node_socket_default_value(writer, sock);
}
/* this is only direct data, tree itself should have been written */
static void write_nodetree_nolib(BlendWriter *writer, bNodeTree *ntree)
{
/* for link_list() speed, we write per list */
if (ntree->adt) {
BKE_animdata_blend_write(writer, ntree->adt);
}
LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
BLO_write_struct(writer, bNode, node);
if (node->prop) {
IDP_BlendWrite(writer, node->prop);
}
LISTBASE_FOREACH (bNodeSocket *, sock, &node->inputs) {
write_node_socket(writer, sock);
}
LISTBASE_FOREACH (bNodeSocket *, sock, &node->outputs) {
write_node_socket(writer, sock);
}
LISTBASE_FOREACH (bNodeLink *, link, &node->internal_links) {
BLO_write_struct(writer, bNodeLink, link);
}
if (node->storage) {
/* could be handlerized at some point, now only 1 exception still */
if ((ntree->type == NTREE_SHADER) &&
ELEM(node->type, SH_NODE_CURVE_VEC, SH_NODE_CURVE_RGB)) {
BKE_curvemapping_blend_write(writer, node->storage);
}
else if (ntree->type == NTREE_SHADER && (node->type == SH_NODE_SCRIPT)) {
NodeShaderScript *nss = (NodeShaderScript *)node->storage;
if (nss->bytecode) {
BLO_write_string(writer, nss->bytecode);
}
BLO_write_struct_by_name(writer, node->typeinfo->storagename, node->storage);
}
else if ((ntree->type == NTREE_COMPOSIT) && ELEM(node->type,
CMP_NODE_TIME,
CMP_NODE_CURVE_VEC,
CMP_NODE_CURVE_RGB,
CMP_NODE_HUECORRECT)) {
BKE_curvemapping_blend_write(writer, node->storage);
}
else if ((ntree->type == NTREE_TEXTURE) &&
(node->type == TEX_NODE_CURVE_RGB || node->type == TEX_NODE_CURVE_TIME)) {
BKE_curvemapping_blend_write(writer, node->storage);
}
else if ((ntree->type == NTREE_COMPOSIT) && (node->type == CMP_NODE_MOVIEDISTORTION)) {
/* pass */
}
else if ((ntree->type == NTREE_COMPOSIT) && (node->type == CMP_NODE_GLARE)) {
/* Simple forward compatibility for fix for T50736.
* Not ideal (there is no ideal solution here), but should do for now. */
NodeGlare *ndg = node->storage;
/* Not in undo case. */
if (!BLO_write_is_undo(writer)) {
switch (ndg->type) {
case 2: /* Grrrr! magic numbers :( */
ndg->angle = ndg->streaks;
break;
case 0:
ndg->angle = ndg->star_45;
break;
default:
break;
}
}
BLO_write_struct_by_name(writer, node->typeinfo->storagename, node->storage);
}
else if ((ntree->type == NTREE_COMPOSIT) && (node->type == CMP_NODE_CRYPTOMATTE)) {
NodeCryptomatte *nc = (NodeCryptomatte *)node->storage;
if (nc->matte_id) {
BLO_write_string(writer, nc->matte_id);
}
BLO_write_struct_by_name(writer, node->typeinfo->storagename, node->storage);
}
else if (node->typeinfo != &NodeTypeUndefined) {
BLO_write_struct_by_name(writer, node->typeinfo->storagename, node->storage);
}
}
if (node->type == CMP_NODE_OUTPUT_FILE) {
/* inputs have own storage data */
LISTBASE_FOREACH (bNodeSocket *, sock, &node->inputs) {
BLO_write_struct(writer, NodeImageMultiFileSocket, sock->storage);
}
}
if (ELEM(node->type, CMP_NODE_IMAGE, CMP_NODE_R_LAYERS)) {
/* write extra socket info */
LISTBASE_FOREACH (bNodeSocket *, sock, &node->outputs) {
BLO_write_struct(writer, NodeImageLayer, sock->storage);
}
}
}
LISTBASE_FOREACH (bNodeLink *, link, &ntree->links) {
BLO_write_struct(writer, bNodeLink, link);
}
LISTBASE_FOREACH (bNodeSocket *, sock, &ntree->inputs) {
write_node_socket_interface(writer, sock);
}
LISTBASE_FOREACH (bNodeSocket *, sock, &ntree->outputs) {
write_node_socket_interface(writer, sock);
}
}
/**
* Take care using 'use_active_win', since we wont want the currently active window
* to change which scene renders (currently only used for undo).
@ -1759,7 +1583,7 @@ static void write_texture(BlendWriter *writer, Tex *tex, const void *id_address)
/* nodetree is integral part of texture, no libdata */
if (tex->nodetree) {
BLO_write_struct(writer, bNodeTree, tex->nodetree);
write_nodetree_nolib(writer, tex->nodetree);
ntreeBlendWrite(writer, tex->nodetree);
}
BKE_previewimg_blend_write(writer, tex->preview);
@ -1784,7 +1608,7 @@ static void write_material(BlendWriter *writer, Material *ma, const void *id_add
/* nodetree is integral part of material, no libdata */
if (ma->nodetree) {
BLO_write_struct(writer, bNodeTree, ma->nodetree);
write_nodetree_nolib(writer, ma->nodetree);
ntreeBlendWrite(writer, ma->nodetree);
}
BKE_previewimg_blend_write(writer, ma->preview);
@ -1813,7 +1637,7 @@ static void write_world(BlendWriter *writer, World *wrld, const void *id_address
/* nodetree is integral part of world, no libdata */
if (wrld->nodetree) {
BLO_write_struct(writer, bNodeTree, wrld->nodetree);
write_nodetree_nolib(writer, wrld->nodetree);
ntreeBlendWrite(writer, wrld->nodetree);
}
BKE_previewimg_blend_write(writer, wrld->preview);
@ -1838,7 +1662,7 @@ static void write_light(BlendWriter *writer, Light *la, const void *id_address)
/* Node-tree is integral part of lights, no libdata. */
if (la->nodetree) {
BLO_write_struct(writer, bNodeTree, la->nodetree);
write_nodetree_nolib(writer, la->nodetree);
ntreeBlendWrite(writer, la->nodetree);
}
BKE_previewimg_blend_write(writer, la->preview);
@ -2176,7 +2000,7 @@ static void write_scene(BlendWriter *writer, Scene *sce, const void *id_address)
if (sce->nodetree) {
BLO_write_struct(writer, bNodeTree, sce->nodetree);
write_nodetree_nolib(writer, sce->nodetree);
ntreeBlendWrite(writer, sce->nodetree);
}
write_view_settings(writer, &sce->view_settings);
@ -2669,26 +2493,6 @@ static void write_probe(BlendWriter *writer, LightProbe *prb, const void *id_add
}
}
static void write_nodetree(BlendWriter *writer, bNodeTree *ntree, const void *id_address)
{
if (ntree->id.us > 0 || BLO_write_is_undo(writer)) {
/* Clean up, important in undo case to reduce false detection of changed datablocks. */
ntree->init = 0; /* to set callbacks and force setting types */
ntree->is_updating = false;
ntree->typeinfo = NULL;
ntree->interface_type = NULL;
ntree->progress = NULL;
ntree->execdata = NULL;
BLO_write_id_struct(writer, bNodeTree, id_address, &ntree->id);
/* Note that trees directly used by other IDs (materials etc.) are not 'real' ID, they cannot
* be linked, etc., so we write actual id data here only, for 'real' ID trees. */
BKE_id_blend_write(writer, &ntree->id);
write_nodetree_nolib(writer, ntree);
}
}
static void write_brush(BlendWriter *writer, Brush *brush, const void *id_address)
{
if (brush->id.us > 0 || BLO_write_is_undo(writer)) {
@ -3165,7 +2969,7 @@ static void write_linestyle(BlendWriter *writer,
}
if (linestyle->nodetree) {
BLO_write_struct(writer, bNodeTree, linestyle->nodetree);
write_nodetree_nolib(writer, linestyle->nodetree);
ntreeBlendWrite(writer, linestyle->nodetree);
}
}
}
@ -3297,7 +3101,7 @@ static void write_simulation(BlendWriter *writer, Simulation *simulation, const
/* nodetree is integral part of simulation, no libdata */
if (simulation->nodetree) {
BLO_write_struct(writer, bNodeTree, simulation->nodetree);
write_nodetree_nolib(writer, simulation->nodetree);
ntreeBlendWrite(writer, simulation->nodetree);
}
LISTBASE_FOREACH (SimulationState *, state, &simulation->states) {
@ -3668,9 +3472,6 @@ static bool write_file_handle(Main *mainvar,
case ID_PA:
write_particlesettings(&writer, (ParticleSettings *)id_buffer, id);
break;
case ID_NT:
write_nodetree(&writer, (bNodeTree *)id_buffer, id);
break;
case ID_BR:
write_brush(&writer, (Brush *)id_buffer, id);
break;
@ -3704,6 +3505,7 @@ static bool write_file_handle(Main *mainvar,
case ID_ME:
case ID_LT:
case ID_AC:
case ID_NT:
/* Do nothing, handled in IDTypeInfo callback. */
break;
case ID_LI: