This makes specifying a legacy type for new node types optional (e.g. `GEO_NODE_MESH_TO_CURVE`). Instead, only the `idname` is used as a stable identifier for node types. So there is less redundancy for now. This change helps with the decentralized definition of nodes and reduces the number minimum number of files that need to be changed for a new node from 5 to 4. It especially helps when multiple nodes are worked on at the same time, because the legacy type definition was very prone to have merge conflicts. For compatibility reasons and because it's still used by existing code, the `legacy_type` is not removed. All existing nodes keep their current `legacy_type`. New nodes will receive an auto-incremented legacy type. It's still necessary to give nodes unique legacy types, because some code checks if two nodes have the same type by comparing their `legacy_type`. These types only have to be unique at run-time though. Some randomness is used to avoid depending on stable generated legacy types accidentally. Pull Request: https://projects.blender.org/blender/blender/pulls/133044
169 lines
4.1 KiB
C++
169 lines
4.1 KiB
C++
/* SPDX-FileCopyrightText: 2005 Blender Authors
|
|
*
|
|
* SPDX-License-Identifier: GPL-2.0-or-later */
|
|
|
|
/** \file
|
|
* \ingroup nodes
|
|
*/
|
|
|
|
/*
|
|
* HOW TEXTURE NODES WORK
|
|
*
|
|
* In contrast to Shader nodes, which place a color into the output
|
|
* stack when executed, Texture nodes place a TexDelegate* there. To
|
|
* obtain a color value from this, a node further up the chain reads
|
|
* the TexDelegate* from its input stack, and uses tex_call_delegate to
|
|
* retrieve the color from the delegate.
|
|
*
|
|
* comments: (ton)
|
|
*
|
|
* This system needs recode, a node system should rely on the stack, and
|
|
* callbacks for nodes only should evaluate their own node, not recursively go
|
|
* over other previous ones.
|
|
*/
|
|
|
|
#include "BKE_node_runtime.hh"
|
|
|
|
#include "NOD_texture.h"
|
|
|
|
#include "node_texture_util.hh"
|
|
#include "node_util.hh"
|
|
#include <optional>
|
|
|
|
bool tex_node_poll_default(const blender::bke::bNodeType * /*ntype*/,
|
|
const bNodeTree *ntree,
|
|
const char **r_disabled_hint)
|
|
{
|
|
if (!STREQ(ntree->idname, "TextureNodeTree")) {
|
|
*r_disabled_hint = RPT_("Not a texture node tree");
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
void tex_node_type_base(blender::bke::bNodeType *ntype,
|
|
std::string idname,
|
|
const std::optional<int16_t> legacy_type)
|
|
{
|
|
blender::bke::node_type_base(ntype, idname, legacy_type);
|
|
|
|
ntype->poll = tex_node_poll_default;
|
|
ntype->insert_link = node_insert_link_default;
|
|
}
|
|
|
|
static void tex_call_delegate(TexDelegate *dg, float *out, TexParams *params, short thread)
|
|
{
|
|
if (dg->node->runtime->need_exec) {
|
|
dg->fn(out, params, dg->node, dg->in, thread);
|
|
}
|
|
}
|
|
|
|
static void tex_input(float *out, int num, bNodeStack *in, TexParams *params, short thread)
|
|
{
|
|
TexDelegate *dg = static_cast<TexDelegate *>(in->data);
|
|
if (dg) {
|
|
tex_call_delegate(dg, in->vec, params, thread);
|
|
|
|
if (in->hasoutput && in->sockettype == SOCK_FLOAT) {
|
|
in->vec[1] = in->vec[2] = in->vec[0];
|
|
}
|
|
}
|
|
memcpy(out, in->vec, num * sizeof(float));
|
|
}
|
|
|
|
void tex_input_vec(float *out, bNodeStack *in, TexParams *params, short thread)
|
|
{
|
|
tex_input(out, 3, in, params, thread);
|
|
}
|
|
|
|
void tex_input_rgba(float *out, bNodeStack *in, TexParams *params, short thread)
|
|
{
|
|
tex_input(out, 4, in, params, thread);
|
|
|
|
if (in->hasoutput && in->sockettype == SOCK_FLOAT) {
|
|
out[1] = out[2] = out[0];
|
|
out[3] = 1;
|
|
}
|
|
|
|
if (in->hasoutput && in->sockettype == SOCK_VECTOR) {
|
|
out[0] = out[0] * 0.5f + 0.5f;
|
|
out[1] = out[1] * 0.5f + 0.5f;
|
|
out[2] = out[2] * 0.5f + 0.5f;
|
|
out[3] = 1;
|
|
}
|
|
}
|
|
|
|
float tex_input_value(bNodeStack *in, TexParams *params, short thread)
|
|
{
|
|
float out[4];
|
|
tex_input_vec(out, in, params, thread);
|
|
return out[0];
|
|
}
|
|
|
|
void params_from_cdata(TexParams *out, TexCallData *in)
|
|
{
|
|
out->co = in->co;
|
|
out->dxt = in->dxt;
|
|
out->dyt = in->dyt;
|
|
out->previewco = in->co;
|
|
out->osatex = in->osatex;
|
|
out->cfra = in->cfra;
|
|
out->mtex = in->mtex;
|
|
}
|
|
|
|
void tex_output(bNode *node,
|
|
bNodeExecData *execdata,
|
|
bNodeStack **in,
|
|
bNodeStack *out,
|
|
TexFn texfn,
|
|
TexCallData *cdata)
|
|
{
|
|
TexDelegate *dg;
|
|
|
|
if (node->flag & NODE_MUTED) {
|
|
/* do not add a delegate if the node is muted */
|
|
return;
|
|
}
|
|
|
|
if (!out->data) {
|
|
/* Freed in tex_end_exec (node.cc) */
|
|
dg = MEM_cnew<TexDelegate>("tex delegate");
|
|
out->data = dg;
|
|
}
|
|
else {
|
|
dg = static_cast<TexDelegate *>(out->data);
|
|
}
|
|
|
|
dg->cdata = cdata;
|
|
dg->fn = texfn;
|
|
dg->node = node;
|
|
dg->preview = execdata->preview;
|
|
memcpy(dg->in, in, MAX_SOCKET * sizeof(bNodeStack *));
|
|
dg->type = out->sockettype;
|
|
}
|
|
|
|
void ntreeTexCheckCyclics(bNodeTree *ntree)
|
|
{
|
|
LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
|
|
|
|
if (node->type_legacy == TEX_NODE_TEXTURE && node->id) {
|
|
/* custom2 stops the node from rendering */
|
|
if (node->custom1) {
|
|
node->custom2 = 1;
|
|
node->custom1 = 0;
|
|
}
|
|
else {
|
|
Tex *tex = (Tex *)node->id;
|
|
|
|
node->custom2 = 0;
|
|
|
|
node->custom1 = 1;
|
|
if (tex->use_nodes && tex->nodetree) {
|
|
ntreeTexCheckCyclics(tex->nodetree);
|
|
}
|
|
node->custom1 = 0;
|
|
}
|
|
}
|
|
}
|
|
}
|