2011-09-05 21:01:50 +00:00
|
|
|
/*
|
|
|
|
* This program is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU General Public License
|
|
|
|
* as published by the Free Software Foundation; either version 2
|
2018-06-01 18:19:39 +02:00
|
|
|
* of the License, or (at your option) any later version.
|
2011-09-05 21:01:50 +00:00
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program; if not, write to the Free Software Foundation,
|
|
|
|
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
|
|
*
|
|
|
|
* The Original Code is Copyright (C) 2005 Blender Foundation.
|
|
|
|
* All rights reserved.
|
|
|
|
*/
|
|
|
|
|
2019-02-18 08:08:12 +11:00
|
|
|
/** \file
|
|
|
|
* \ingroup nodes
|
2011-09-05 21:01:50 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
#include "DNA_node_types.h"
|
|
|
|
|
|
|
|
#include "node_shader_util.h"
|
|
|
|
|
|
|
|
#include "node_exec.h"
|
|
|
|
|
2013-03-18 16:34:57 +00:00
|
|
|
|
2018-07-02 11:47:00 +02:00
|
|
|
bool sh_node_poll_default(bNodeType *UNUSED(ntype), bNodeTree *ntree)
|
2013-03-18 16:34:57 +00:00
|
|
|
{
|
2013-05-27 07:57:17 +00:00
|
|
|
return STREQ(ntree->idname, "ShaderNodeTree");
|
2013-03-18 16:34:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void sh_node_type_base(struct bNodeType *ntype, int type, const char *name, short nclass, short flag)
|
|
|
|
{
|
|
|
|
node_type_base(ntype, type, name, nclass, flag);
|
2018-06-08 08:07:48 +02:00
|
|
|
|
2013-03-18 16:34:57 +00:00
|
|
|
ntype->poll = sh_node_poll_default;
|
Node callback for handling link insertion and swapping of occupied inputs.
Nodes have a feature for moving existing links to unoccupied sockets when connecting
to an already used input. This is based on the standard legacy socket types (value/float,
vector, color/rgba) and works reasonably well for shader, compositor and texture nodes.
For new pynode systems, however, the hardcoded nature of that feature has major drawbacks:
* It does not take different type systems into account, leading to meaningless connections
when sockets are swapped and making the feature useless or outright debilitating.
* Advanced socket behaviors would be possible with a registerable callback, e.g. creating
extensible input lists that move existing connections down to make room for a new link.
Now any handling of new links is done via the 'insert_links' callback, which can also be
registered through the RNA API. For the legacy shader/compo/tex nodes the behavior is the
same, using a C callback.
Note on the 'use_swap' flag: this has been removed because it was meaningless anyway:
It was disabled only for the insert-node-on-link feature, which works only for
completely unconnected nodes anyway, so there would be nothing to swap in the first place.
2015-12-03 12:51:29 +01:00
|
|
|
ntype->insert_link = node_insert_link_default;
|
2013-03-18 16:34:57 +00:00
|
|
|
ntype->update_internal_links = node_update_internal_links_default;
|
|
|
|
}
|
|
|
|
|
2011-09-05 21:01:50 +00:00
|
|
|
/* ****** */
|
|
|
|
|
|
|
|
void nodestack_get_vec(float *in, short type_in, bNodeStack *ns)
|
|
|
|
{
|
2014-04-27 00:24:11 +10:00
|
|
|
const float *from = ns->vec;
|
2018-06-08 08:07:48 +02:00
|
|
|
|
2013-05-27 07:57:17 +00:00
|
|
|
if (type_in == SOCK_FLOAT) {
|
|
|
|
if (ns->sockettype == SOCK_FLOAT)
|
|
|
|
*in = *from;
|
2018-06-08 08:07:48 +02:00
|
|
|
else
|
2013-05-27 07:57:17 +00:00
|
|
|
*in = (from[0] + from[1] + from[2]) / 3.0f;
|
2011-09-05 21:01:50 +00:00
|
|
|
}
|
2013-05-27 07:57:17 +00:00
|
|
|
else if (type_in == SOCK_VECTOR) {
|
|
|
|
if (ns->sockettype == SOCK_FLOAT) {
|
2012-10-22 08:15:51 +00:00
|
|
|
in[0] = from[0];
|
|
|
|
in[1] = from[0];
|
|
|
|
in[2] = from[0];
|
2011-09-05 21:01:50 +00:00
|
|
|
}
|
|
|
|
else {
|
2011-11-06 16:23:28 +00:00
|
|
|
copy_v3_v3(in, from);
|
2011-09-05 21:01:50 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else { /* type_in==SOCK_RGBA */
|
2013-05-27 07:57:17 +00:00
|
|
|
if (ns->sockettype == SOCK_RGBA) {
|
2011-11-06 16:23:28 +00:00
|
|
|
copy_v4_v4(in, from);
|
2011-09-05 21:01:50 +00:00
|
|
|
}
|
2013-05-27 07:57:17 +00:00
|
|
|
else if (ns->sockettype == SOCK_FLOAT) {
|
2012-10-22 08:15:51 +00:00
|
|
|
in[0] = from[0];
|
|
|
|
in[1] = from[0];
|
|
|
|
in[2] = from[0];
|
|
|
|
in[3] = 1.0f;
|
2011-09-05 21:01:50 +00:00
|
|
|
}
|
|
|
|
else {
|
2011-11-06 16:23:28 +00:00
|
|
|
copy_v3_v3(in, from);
|
2012-10-22 08:15:51 +00:00
|
|
|
in[3] = 1.0f;
|
2011-09-05 21:01:50 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void node_gpu_stack_from_data(struct GPUNodeStack *gs, int type, bNodeStack *ns)
|
|
|
|
{
|
|
|
|
memset(gs, 0, sizeof(*gs));
|
2018-06-08 08:07:48 +02:00
|
|
|
|
2017-06-01 12:18:57 +02:00
|
|
|
if (ns == NULL) {
|
2018-09-03 16:49:08 +02:00
|
|
|
/* node_get_stack() will generate NULL bNodeStack pointers for unknown/unsupported types of sockets... */
|
2017-06-01 12:18:57 +02:00
|
|
|
zero_v4(gs->vec);
|
|
|
|
gs->link = NULL;
|
2013-05-27 07:57:17 +00:00
|
|
|
gs->type = GPU_NONE;
|
2017-06-01 12:18:57 +02:00
|
|
|
gs->hasinput = false;
|
|
|
|
gs->hasoutput = false;
|
|
|
|
gs->sockettype = type;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
nodestack_get_vec(gs->vec, type, ns);
|
|
|
|
gs->link = ns->data;
|
2018-06-08 08:07:48 +02:00
|
|
|
|
2017-06-01 12:18:57 +02:00
|
|
|
if (type == SOCK_FLOAT)
|
|
|
|
gs->type = GPU_FLOAT;
|
2019-03-13 01:20:44 +01:00
|
|
|
else if (type == SOCK_INT)
|
|
|
|
gs->type = GPU_FLOAT; /* HACK: Support as float. */
|
2017-06-01 12:18:57 +02:00
|
|
|
else if (type == SOCK_VECTOR)
|
|
|
|
gs->type = GPU_VEC3;
|
|
|
|
else if (type == SOCK_RGBA)
|
|
|
|
gs->type = GPU_VEC4;
|
|
|
|
else if (type == SOCK_SHADER)
|
2017-07-03 21:39:52 +02:00
|
|
|
gs->type = GPU_CLOSURE;
|
2017-06-01 12:18:57 +02:00
|
|
|
else
|
|
|
|
gs->type = GPU_NONE;
|
|
|
|
|
|
|
|
gs->hasinput = ns->hasinput && ns->data;
|
|
|
|
/* XXX Commented out the ns->data check here, as it seems it's not always set,
|
|
|
|
* even though there *is* a valid connection/output... But that might need
|
|
|
|
* further investigation.
|
|
|
|
*/
|
|
|
|
gs->hasoutput = ns->hasoutput /*&& ns->data*/;
|
|
|
|
gs->sockettype = ns->sockettype;
|
|
|
|
}
|
2011-09-05 21:01:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void node_data_from_gpu_stack(bNodeStack *ns, GPUNodeStack *gs)
|
|
|
|
{
|
2013-01-15 12:16:27 +00:00
|
|
|
copy_v4_v4(ns->vec, gs->vec);
|
2013-05-27 07:57:17 +00:00
|
|
|
ns->data = gs->link;
|
|
|
|
ns->sockettype = gs->sockettype;
|
2011-09-05 21:01:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void gpu_stack_from_data_list(GPUNodeStack *gs, ListBase *sockets, bNodeStack **ns)
|
|
|
|
{
|
|
|
|
bNodeSocket *sock;
|
|
|
|
int i;
|
2018-06-08 08:07:48 +02:00
|
|
|
|
2013-05-27 07:57:17 +00:00
|
|
|
for (sock = sockets->first, i = 0; sock; sock = sock->next, i++)
|
2011-09-05 21:01:50 +00:00
|
|
|
node_gpu_stack_from_data(&gs[i], sock->type, ns[i]);
|
2018-06-08 08:07:48 +02:00
|
|
|
|
2018-02-22 20:52:08 +01:00
|
|
|
gs[i].end = true;
|
2011-09-05 21:01:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void data_from_gpu_stack_list(ListBase *sockets, bNodeStack **ns, GPUNodeStack *gs)
|
|
|
|
{
|
|
|
|
bNodeSocket *sock;
|
|
|
|
int i;
|
|
|
|
|
2013-05-27 07:57:17 +00:00
|
|
|
for (sock = sockets->first, i = 0; sock; sock = sock->next, i++)
|
2011-09-05 21:01:50 +00:00
|
|
|
node_data_from_gpu_stack(ns[i], &gs[i]);
|
|
|
|
}
|
|
|
|
|
2011-11-08 13:07:16 +00:00
|
|
|
bNode *nodeGetActiveTexture(bNodeTree *ntree)
|
|
|
|
{
|
|
|
|
/* this is the node we texture paint and draw in textured draw */
|
2014-06-18 20:40:27 +03:00
|
|
|
bNode *node, *tnode, *inactivenode = NULL, *activetexnode = NULL, *activegroup = NULL;
|
|
|
|
bool hasgroup = false;
|
2011-11-08 13:07:16 +00:00
|
|
|
|
2012-03-24 06:38:07 +00:00
|
|
|
if (!ntree)
|
2011-11-08 13:07:16 +00:00
|
|
|
return NULL;
|
|
|
|
|
2013-09-02 16:05:51 +00:00
|
|
|
for (node = ntree->nodes.first; node; node = node->next) {
|
2014-06-18 20:40:27 +03:00
|
|
|
if (node->flag & NODE_ACTIVE_TEXTURE) {
|
|
|
|
activetexnode = node;
|
|
|
|
/* if active we can return immediately */
|
|
|
|
if (node->flag & NODE_ACTIVE)
|
|
|
|
return node;
|
|
|
|
}
|
2013-09-02 16:05:51 +00:00
|
|
|
else if (!inactivenode && node->typeinfo->nclass == NODE_CLASS_TEXTURE)
|
|
|
|
inactivenode = node;
|
2014-06-18 20:40:27 +03:00
|
|
|
else if (node->type == NODE_GROUP) {
|
|
|
|
if (node->flag & NODE_ACTIVE)
|
|
|
|
activegroup = node;
|
|
|
|
else
|
|
|
|
hasgroup = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* first, check active group for textures */
|
|
|
|
if (activegroup) {
|
|
|
|
tnode = nodeGetActiveTexture((bNodeTree *)activegroup->id);
|
|
|
|
/* active node takes priority, so ignore any other possible nodes here */
|
|
|
|
if (tnode)
|
|
|
|
return tnode;
|
2013-09-02 16:05:51 +00:00
|
|
|
}
|
2014-06-18 20:40:27 +03:00
|
|
|
|
|
|
|
if (activetexnode)
|
|
|
|
return activetexnode;
|
2018-06-08 08:07:48 +02:00
|
|
|
|
2014-06-18 20:40:27 +03:00
|
|
|
if (hasgroup) {
|
|
|
|
/* node active texture node in this tree, look inside groups */
|
|
|
|
for (node = ntree->nodes.first; node; node = node->next) {
|
|
|
|
if (node->type == NODE_GROUP) {
|
|
|
|
tnode = nodeGetActiveTexture((bNodeTree *)node->id);
|
|
|
|
if (tnode && ((tnode->flag & NODE_ACTIVE_TEXTURE) || !inactivenode))
|
|
|
|
return tnode;
|
|
|
|
}
|
2013-03-18 16:34:57 +00:00
|
|
|
}
|
|
|
|
}
|
2018-06-08 08:07:48 +02:00
|
|
|
|
2013-09-02 16:05:51 +00:00
|
|
|
return inactivenode;
|
2011-11-08 13:07:16 +00:00
|
|
|
}
|
|
|
|
|
2019-04-02 16:37:54 +02:00
|
|
|
void ntreeExecGPUNodes(bNodeTreeExec *exec, GPUMaterial *mat, bNode *output_node)
|
2011-09-05 21:01:50 +00:00
|
|
|
{
|
|
|
|
bNodeExec *nodeexec;
|
|
|
|
bNode *node;
|
|
|
|
int n;
|
|
|
|
bNodeStack *stack;
|
2013-05-27 07:57:17 +00:00
|
|
|
bNodeStack *nsin[MAX_SOCKET]; /* arbitrary... watch this */
|
|
|
|
bNodeStack *nsout[MAX_SOCKET]; /* arbitrary... watch this */
|
2013-02-02 04:58:03 +00:00
|
|
|
GPUNodeStack gpuin[MAX_SOCKET + 1], gpuout[MAX_SOCKET + 1];
|
2014-04-01 11:34:00 +11:00
|
|
|
bool do_it;
|
2011-09-05 21:01:50 +00:00
|
|
|
|
2013-05-27 07:57:17 +00:00
|
|
|
stack = exec->stack;
|
2011-09-05 21:01:50 +00:00
|
|
|
|
2013-05-27 07:57:17 +00:00
|
|
|
for (n = 0, nodeexec = exec->nodeexec; n < exec->totnodes; ++n, ++nodeexec) {
|
2011-09-05 21:01:50 +00:00
|
|
|
node = nodeexec->node;
|
2018-06-08 08:07:48 +02:00
|
|
|
|
2014-04-01 11:34:00 +11:00
|
|
|
do_it = false;
|
2011-09-05 21:01:50 +00:00
|
|
|
/* for groups, only execute outputs for edited group */
|
2013-05-27 07:57:17 +00:00
|
|
|
if (node->typeinfo->nclass == NODE_CLASS_OUTPUT) {
|
2019-04-02 16:37:54 +02:00
|
|
|
if ((output_node != NULL) && (node == output_node))
|
2018-07-05 19:18:43 +02:00
|
|
|
do_it = true;
|
2014-04-01 11:34:00 +11:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
do_it = true;
|
2011-09-05 21:01:50 +00:00
|
|
|
}
|
|
|
|
|
2012-05-19 13:28:19 +00:00
|
|
|
if (do_it) {
|
2012-03-24 06:38:07 +00:00
|
|
|
if (node->typeinfo->gpufunc) {
|
2011-09-05 21:01:50 +00:00
|
|
|
node_get_stack(node, stack, nsin, nsout);
|
|
|
|
gpu_stack_from_data_list(gpuin, &node->inputs, nsin);
|
|
|
|
gpu_stack_from_data_list(gpuout, &node->outputs, nsout);
|
2013-03-18 16:34:57 +00:00
|
|
|
if (node->typeinfo->gpufunc(mat, node, &nodeexec->data, gpuin, gpuout))
|
2011-09-05 21:01:50 +00:00
|
|
|
data_from_gpu_stack_list(&node->outputs, nsout, gpuout);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2011-11-08 11:38:16 +00:00
|
|
|
|
|
|
|
void node_shader_gpu_tex_mapping(GPUMaterial *mat, bNode *node, GPUNodeStack *in, GPUNodeStack *UNUSED(out))
|
|
|
|
{
|
2013-05-27 07:57:17 +00:00
|
|
|
NodeTexBase *base = node->storage;
|
|
|
|
TexMapping *texmap = &base->tex_mapping;
|
|
|
|
float domin = (texmap->flag & TEXMAP_CLIP_MIN) != 0;
|
|
|
|
float domax = (texmap->flag & TEXMAP_CLIP_MAX) != 0;
|
2011-11-08 11:38:16 +00:00
|
|
|
|
2012-03-24 06:38:07 +00:00
|
|
|
if (domin || domax || !(texmap->flag & TEXMAP_UNIT_MATRIX)) {
|
2018-08-01 19:37:18 +02:00
|
|
|
static float max[3] = { FLT_MAX, FLT_MAX, FLT_MAX};
|
|
|
|
static float min[3] = {-FLT_MAX, -FLT_MAX, -FLT_MAX};
|
|
|
|
GPUNodeLink *tmin, *tmax, *tmat0, *tmat1, *tmat2, *tmat3;
|
|
|
|
|
2018-08-13 15:30:29 +02:00
|
|
|
tmin = GPU_uniform((domin) ? texmap->min : min);
|
|
|
|
tmax = GPU_uniform((domax) ? texmap->max : max);
|
|
|
|
tmat0 = GPU_uniform((float *)texmap->mat[0]);
|
|
|
|
tmat1 = GPU_uniform((float *)texmap->mat[1]);
|
|
|
|
tmat2 = GPU_uniform((float *)texmap->mat[2]);
|
|
|
|
tmat3 = GPU_uniform((float *)texmap->mat[3]);
|
2018-08-01 19:37:18 +02:00
|
|
|
|
|
|
|
GPU_link(mat, "mapping", in[0].link, tmat0, tmat1, tmat2, tmat3, tmin, tmax, &in[0].link);
|
2013-09-25 20:28:49 +00:00
|
|
|
|
|
|
|
if (texmap->type == TEXMAP_TYPE_NORMAL)
|
|
|
|
GPU_link(mat, "texco_norm", in[0].link, &in[0].link);
|
2011-11-08 11:38:16 +00:00
|
|
|
}
|
|
|
|
}
|