The goal is to solve confusion of the "All rights reserved" for licensing
code under an open-source license.
The phrase "All rights reserved" comes from a historical convention that
required this phrase for the copyright protection to apply. This convention
is no longer relevant.
However, even though the phrase has no meaning in establishing the copyright
it has not lost meaning in terms of licensing.
This change makes it so code under the Blender Foundation copyright does
not use "all rights reserved". This is also how the GPL license itself
states how to apply it to the source code:
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software ...
This change does not change copyright notice in cases when the copyright
is dual (BF and an author), or just an author of the code. It also does
mot change copyright which is inherited from NaN Holding BV as it needs
some further investigation about what is the proper way to handle it.
263 lines
7.4 KiB
C++
263 lines
7.4 KiB
C++
/* SPDX-License-Identifier: GPL-2.0-or-later
|
|
* Copyright 2007 Blender Foundation */
|
|
|
|
/** \file
|
|
* \ingroup nodes
|
|
*/
|
|
|
|
#include "DNA_node_types.h"
|
|
|
|
#include "BLI_listbase.h"
|
|
#include "BLI_utildefines.h"
|
|
|
|
#include "BKE_global.h"
|
|
#include "BKE_node.h"
|
|
#include "BKE_node_runtime.hh"
|
|
#include "BKE_node_tree_update.h"
|
|
|
|
#include "MEM_guardedalloc.h"
|
|
|
|
#include "node_exec.h"
|
|
#include "node_util.h"
|
|
|
|
static int node_exec_socket_use_stack(bNodeSocket *sock)
|
|
{
|
|
/* NOTE: INT supported as FLOAT. Only for EEVEE. */
|
|
return ELEM(sock->type, SOCK_INT, SOCK_FLOAT, SOCK_VECTOR, SOCK_RGBA, SOCK_SHADER);
|
|
}
|
|
|
|
bNodeStack *node_get_socket_stack(bNodeStack *stack, bNodeSocket *sock)
|
|
{
|
|
if (stack && sock && sock->stack_index >= 0) {
|
|
return stack + sock->stack_index;
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
void node_get_stack(bNode *node, bNodeStack *stack, bNodeStack **in, bNodeStack **out)
|
|
{
|
|
bNodeSocket *sock;
|
|
|
|
/* build pointer stack */
|
|
if (in) {
|
|
for (sock = (bNodeSocket *)node->inputs.first; sock; sock = sock->next) {
|
|
*(in++) = node_get_socket_stack(stack, sock);
|
|
}
|
|
}
|
|
|
|
if (out) {
|
|
for (sock = (bNodeSocket *)node->outputs.first; sock; sock = sock->next) {
|
|
*(out++) = node_get_socket_stack(stack, sock);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void node_init_input_index(bNodeSocket *sock, int *index)
|
|
{
|
|
/* Only consider existing link if from socket is valid! */
|
|
if (sock->link && !(sock->link->flag & NODE_LINK_MUTED) && sock->link->fromsock &&
|
|
sock->link->fromsock->stack_index >= 0) {
|
|
sock->stack_index = sock->link->fromsock->stack_index;
|
|
}
|
|
else {
|
|
if (node_exec_socket_use_stack(sock)) {
|
|
sock->stack_index = (*index)++;
|
|
}
|
|
else {
|
|
sock->stack_index = -1;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void node_init_output_index_muted(bNodeSocket *sock,
|
|
int *index,
|
|
const blender::MutableSpan<bNodeLink> internal_links)
|
|
{
|
|
const bNodeLink *link;
|
|
/* copy the stack index from internally connected input to skip the node */
|
|
for (bNodeLink &iter_link : internal_links) {
|
|
if (iter_link.tosock == sock) {
|
|
sock->stack_index = iter_link.fromsock->stack_index;
|
|
/* set the link pointer to indicate that this socket
|
|
* should not overwrite the stack value!
|
|
*/
|
|
sock->link = &iter_link;
|
|
link = &iter_link;
|
|
break;
|
|
}
|
|
}
|
|
/* if not internally connected, assign a new stack index anyway to avoid bad stack access */
|
|
if (!link) {
|
|
if (node_exec_socket_use_stack(sock)) {
|
|
sock->stack_index = (*index)++;
|
|
}
|
|
else {
|
|
sock->stack_index = -1;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void node_init_output_index(bNodeSocket *sock, int *index)
|
|
{
|
|
if (node_exec_socket_use_stack(sock)) {
|
|
sock->stack_index = (*index)++;
|
|
}
|
|
else {
|
|
sock->stack_index = -1;
|
|
}
|
|
}
|
|
|
|
/* basic preparation of socket stacks */
|
|
static struct bNodeStack *setup_stack(bNodeStack *stack,
|
|
bNodeTree *ntree,
|
|
bNode *node,
|
|
bNodeSocket *sock)
|
|
{
|
|
bNodeStack *ns = node_get_socket_stack(stack, sock);
|
|
if (!ns) {
|
|
return nullptr;
|
|
}
|
|
|
|
/* don't mess with remote socket stacks, these are initialized by other nodes! */
|
|
if (sock->link && !(sock->link->flag & NODE_LINK_MUTED)) {
|
|
return ns;
|
|
}
|
|
|
|
ns->sockettype = sock->type;
|
|
|
|
switch (sock->type) {
|
|
case SOCK_FLOAT:
|
|
ns->vec[0] = node_socket_get_float(ntree, node, sock);
|
|
break;
|
|
case SOCK_VECTOR:
|
|
node_socket_get_vector(ntree, node, sock, ns->vec);
|
|
break;
|
|
case SOCK_RGBA:
|
|
node_socket_get_color(ntree, node, sock, ns->vec);
|
|
break;
|
|
}
|
|
|
|
return ns;
|
|
}
|
|
|
|
bNodeTreeExec *ntree_exec_begin(bNodeExecContext *context,
|
|
bNodeTree *ntree,
|
|
bNodeInstanceKey parent_key)
|
|
{
|
|
using namespace blender;
|
|
bNodeTreeExec *exec;
|
|
bNode *node;
|
|
bNodeExec *nodeexec;
|
|
bNodeInstanceKey nodekey;
|
|
bNodeSocket *sock;
|
|
bNodeStack *ns;
|
|
int index;
|
|
/* XXX: texture-nodes have threading issues with muting, have to disable it there. */
|
|
|
|
/* ensure all sock->link pointers and node levels are correct */
|
|
/* Using global main here is likely totally wrong, not sure what to do about that one though...
|
|
* We cannot even check ntree is in global main,
|
|
* since most of the time it won't be (thanks to ntree design)!!! */
|
|
BKE_ntree_update_main_tree(G.main, ntree, nullptr);
|
|
|
|
ntree->ensure_topology_cache();
|
|
const Span<bNode *> nodelist = ntree->toposort_left_to_right();
|
|
|
|
/* XXX could let callbacks do this for specialized data */
|
|
exec = MEM_cnew<bNodeTreeExec>("node tree execution data");
|
|
/* Back-pointer to node tree. */
|
|
exec->nodetree = ntree;
|
|
|
|
/* set stack indices */
|
|
index = 0;
|
|
for (const int n : nodelist.index_range()) {
|
|
node = nodelist[n];
|
|
|
|
/* init node socket stack indexes */
|
|
for (sock = (bNodeSocket *)node->inputs.first; sock; sock = sock->next) {
|
|
node_init_input_index(sock, &index);
|
|
}
|
|
|
|
if (node->flag & NODE_MUTED || node->type == NODE_REROUTE) {
|
|
for (sock = (bNodeSocket *)node->outputs.first; sock; sock = sock->next) {
|
|
node_init_output_index_muted(sock, &index, node->runtime->internal_links);
|
|
}
|
|
}
|
|
else {
|
|
for (sock = (bNodeSocket *)node->outputs.first; sock; sock = sock->next) {
|
|
node_init_output_index(sock, &index);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* allocated exec data pointers for nodes */
|
|
exec->totnodes = nodelist.size();
|
|
exec->nodeexec = (bNodeExec *)MEM_callocN(exec->totnodes * sizeof(bNodeExec),
|
|
"node execution data");
|
|
/* allocate data pointer for node stack */
|
|
exec->stacksize = index;
|
|
exec->stack = (bNodeStack *)MEM_callocN(exec->stacksize * sizeof(bNodeStack), "bNodeStack");
|
|
|
|
/* all non-const results are considered inputs */
|
|
int n;
|
|
for (n = 0; n < exec->stacksize; n++) {
|
|
exec->stack[n].hasinput = 1;
|
|
}
|
|
|
|
/* prepare all nodes for execution */
|
|
for (n = 0, nodeexec = exec->nodeexec; n < nodelist.size(); n++, nodeexec++) {
|
|
node = nodeexec->node = nodelist[n];
|
|
nodeexec->free_exec_fn = node->typeinfo->free_exec_fn;
|
|
|
|
/* tag inputs */
|
|
for (sock = (bNodeSocket *)node->inputs.first; sock; sock = sock->next) {
|
|
/* disable the node if an input link is invalid */
|
|
if (sock->link && !(sock->link->flag & NODE_LINK_VALID)) {
|
|
node->runtime->need_exec = 0;
|
|
}
|
|
|
|
ns = setup_stack(exec->stack, ntree, node, sock);
|
|
if (ns) {
|
|
ns->hasoutput = 1;
|
|
}
|
|
}
|
|
|
|
/* tag all outputs */
|
|
for (sock = (bNodeSocket *)node->outputs.first; sock; sock = sock->next) {
|
|
/* ns = */ setup_stack(exec->stack, ntree, node, sock);
|
|
}
|
|
|
|
nodekey = BKE_node_instance_key(parent_key, ntree, node);
|
|
nodeexec->data.preview = context->previews ? (bNodePreview *)BKE_node_instance_hash_lookup(
|
|
context->previews, nodekey) :
|
|
nullptr;
|
|
if (node->typeinfo->init_exec_fn) {
|
|
nodeexec->data.data = node->typeinfo->init_exec_fn(context, node, nodekey);
|
|
}
|
|
}
|
|
|
|
return exec;
|
|
}
|
|
|
|
void ntree_exec_end(bNodeTreeExec *exec)
|
|
{
|
|
bNodeExec *nodeexec;
|
|
int n;
|
|
|
|
if (exec->stack) {
|
|
MEM_freeN(exec->stack);
|
|
}
|
|
|
|
for (n = 0, nodeexec = exec->nodeexec; n < exec->totnodes; n++, nodeexec++) {
|
|
if (nodeexec->free_exec_fn) {
|
|
nodeexec->free_exec_fn(nodeexec->data.data);
|
|
}
|
|
}
|
|
|
|
if (exec->nodeexec) {
|
|
MEM_freeN(exec->nodeexec);
|
|
}
|
|
|
|
MEM_freeN(exec);
|
|
}
|