Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/nodes/shader/node_shader_util.cc')
-rw-r--r--source/blender/nodes/shader/node_shader_util.cc347
1 files changed, 347 insertions, 0 deletions
diff --git a/source/blender/nodes/shader/node_shader_util.cc b/source/blender/nodes/shader/node_shader_util.cc
new file mode 100644
index 00000000000..f2464d4c1b4
--- /dev/null
+++ b/source/blender/nodes/shader/node_shader_util.cc
@@ -0,0 +1,347 @@
+/*
+ * 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
+ * of the License, or (at your option) any later version.
+ *
+ * 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.
+ */
+
+/** \file
+ * \ingroup nodes
+ */
+
+#include "DNA_node_types.h"
+
+#include "node_shader_util.h"
+
+#include "NOD_socket_search_link.hh"
+
+#include "node_exec.h"
+
+bool sh_node_poll_default(bNodeType *UNUSED(ntype), bNodeTree *ntree, const char **r_disabled_hint)
+{
+ if (!STREQ(ntree->idname, "ShaderNodeTree")) {
+ *r_disabled_hint = TIP_("Not a shader node tree");
+ return false;
+ }
+ return true;
+}
+
+static bool sh_fn_poll_default(bNodeType *UNUSED(ntype),
+ bNodeTree *ntree,
+ const char **r_disabled_hint)
+{
+ if (!STR_ELEM(ntree->idname, "ShaderNodeTree", "GeometryNodeTree")) {
+ *r_disabled_hint = TIP_("Not a shader or geometry node tree");
+ return false;
+ }
+ return true;
+}
+
+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);
+
+ ntype->poll = sh_node_poll_default;
+ ntype->insert_link = node_insert_link_default;
+ ntype->gather_link_search_ops = blender::nodes::search_link_ops_for_basic_node;
+}
+
+void sh_fn_node_type_base(bNodeType *ntype, int type, const char *name, short nclass, short flag)
+{
+ sh_node_type_base(ntype, type, name, nclass, flag);
+ ntype->poll = sh_fn_poll_default;
+ ntype->gather_link_search_ops = blender::nodes::search_link_ops_for_basic_node;
+}
+
+/* ****** */
+
+void nodestack_get_vec(float *in, short type_in, bNodeStack *ns)
+{
+ const float *from = ns->vec;
+
+ if (type_in == SOCK_FLOAT) {
+ if (ns->sockettype == SOCK_FLOAT) {
+ *in = *from;
+ }
+ else {
+ *in = (from[0] + from[1] + from[2]) / 3.0f;
+ }
+ }
+ else if (type_in == SOCK_VECTOR) {
+ if (ns->sockettype == SOCK_FLOAT) {
+ in[0] = from[0];
+ in[1] = from[0];
+ in[2] = from[0];
+ }
+ else {
+ copy_v3_v3(in, from);
+ }
+ }
+ else { /* type_in==SOCK_RGBA */
+ if (ns->sockettype == SOCK_RGBA) {
+ copy_v4_v4(in, from);
+ }
+ else if (ns->sockettype == SOCK_FLOAT) {
+ in[0] = from[0];
+ in[1] = from[0];
+ in[2] = from[0];
+ in[3] = 1.0f;
+ }
+ else {
+ copy_v3_v3(in, from);
+ in[3] = 1.0f;
+ }
+ }
+}
+
+void node_gpu_stack_from_data(struct GPUNodeStack *gs, int type, bNodeStack *ns)
+{
+ memset(gs, 0, sizeof(*gs));
+
+ if (ns == nullptr) {
+ /* node_get_stack() will generate nullptr bNodeStack pointers
+ * for unknown/unsupported types of sockets. */
+ zero_v4(gs->vec);
+ gs->link = nullptr;
+ gs->type = GPU_NONE;
+ gs->hasinput = false;
+ gs->hasoutput = false;
+ gs->sockettype = type;
+ }
+ else {
+ nodestack_get_vec(gs->vec, type, ns);
+ gs->link = (GPUNodeLink *)ns->data;
+
+ if (type == SOCK_FLOAT) {
+ gs->type = GPU_FLOAT;
+ }
+ else if (type == SOCK_INT) {
+ gs->type = GPU_FLOAT; /* HACK: Support as float. */
+ }
+ else if (type == SOCK_VECTOR) {
+ gs->type = GPU_VEC3;
+ }
+ else if (type == SOCK_RGBA) {
+ gs->type = GPU_VEC4;
+ }
+ else if (type == SOCK_SHADER) {
+ gs->type = GPU_CLOSURE;
+ }
+ 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;
+ }
+}
+
+void node_data_from_gpu_stack(bNodeStack *ns, GPUNodeStack *gs)
+{
+ copy_v4_v4(ns->vec, gs->vec);
+ ns->data = gs->link;
+ ns->sockettype = gs->sockettype;
+}
+
+static void gpu_stack_from_data_list(GPUNodeStack *gs, ListBase *sockets, bNodeStack **ns)
+{
+ int i;
+ LISTBASE_FOREACH_INDEX (bNodeSocket *, socket, sockets, i) {
+ node_gpu_stack_from_data(&gs[i], socket->type, ns[i]);
+ }
+
+ gs[i].end = true;
+}
+
+static void data_from_gpu_stack_list(ListBase *sockets, bNodeStack **ns, GPUNodeStack *gs)
+{
+ int i;
+ LISTBASE_FOREACH_INDEX (bNodeSocket *, socket, sockets, i) {
+ node_data_from_gpu_stack(ns[i], &gs[i]);
+ }
+}
+
+bNode *nodeGetActiveTexture(bNodeTree *ntree)
+{
+ /* this is the node we texture paint and draw in textured draw */
+ bNode *inactivenode = nullptr, *activetexnode = nullptr, *activegroup = nullptr;
+ bool hasgroup = false;
+
+ if (!ntree) {
+ return nullptr;
+ }
+
+ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
+ if (node->flag & NODE_ACTIVE_TEXTURE) {
+ activetexnode = node;
+ /* if active we can return immediately */
+ if (node->flag & NODE_ACTIVE) {
+ return node;
+ }
+ }
+ else if (!inactivenode && node->typeinfo->nclass == NODE_CLASS_TEXTURE) {
+ inactivenode = node;
+ }
+ else if (node->type == NODE_GROUP) {
+ if (node->flag & NODE_ACTIVE) {
+ activegroup = node;
+ }
+ else {
+ hasgroup = true;
+ }
+ }
+ }
+
+ /* first, check active group for textures */
+ if (activegroup) {
+ bNode *tnode = nodeGetActiveTexture((bNodeTree *)activegroup->id);
+ /* active node takes priority, so ignore any other possible nodes here */
+ if (tnode) {
+ return tnode;
+ }
+ }
+
+ if (activetexnode) {
+ return activetexnode;
+ }
+
+ if (hasgroup) {
+ /* node active texture node in this tree, look inside groups */
+ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
+ if (node->type == NODE_GROUP) {
+ bNode *tnode = nodeGetActiveTexture((bNodeTree *)node->id);
+ if (tnode && ((tnode->flag & NODE_ACTIVE_TEXTURE) || !inactivenode)) {
+ return tnode;
+ }
+ }
+ }
+ }
+
+ return inactivenode;
+}
+
+void ntreeExecGPUNodes(bNodeTreeExec *exec, GPUMaterial *mat, bNode *output_node)
+{
+ bNodeExec *nodeexec;
+ bNode *node;
+ int n;
+ bNodeStack *stack;
+ bNodeStack *nsin[MAX_SOCKET]; /* arbitrary... watch this */
+ bNodeStack *nsout[MAX_SOCKET]; /* arbitrary... watch this */
+ GPUNodeStack gpuin[MAX_SOCKET + 1], gpuout[MAX_SOCKET + 1];
+ bool do_it;
+
+ stack = exec->stack;
+
+ for (n = 0, nodeexec = exec->nodeexec; n < exec->totnodes; n++, nodeexec++) {
+ node = nodeexec->node;
+
+ do_it = false;
+ /* for groups, only execute outputs for edited group */
+ if (node->typeinfo->nclass == NODE_CLASS_OUTPUT) {
+ if ((output_node != nullptr) && (node == output_node)) {
+ do_it = true;
+ }
+ }
+ else {
+ do_it = true;
+ }
+
+ if (do_it) {
+ if (node->typeinfo->gpu_fn) {
+ 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);
+ if (node->typeinfo->gpu_fn(mat, node, &nodeexec->data, gpuin, gpuout)) {
+ data_from_gpu_stack_list(&node->outputs, nsout, gpuout);
+ }
+ }
+ }
+ }
+}
+
+void node_shader_gpu_bump_tex_coord(GPUMaterial *mat, bNode *node, GPUNodeLink **link)
+{
+ if (node->branch_tag == 1) {
+ /* Add one time the value for derivative to the input vector. */
+ GPU_link(mat, "dfdx_v3", *link, link);
+ }
+ else if (node->branch_tag == 2) {
+ /* Add one time the value for derivative to the input vector. */
+ GPU_link(mat, "dfdy_v3", *link, link);
+ }
+ else {
+ /* nothing to do, reference center value. */
+ }
+}
+
+void node_shader_gpu_default_tex_coord(GPUMaterial *mat, bNode *node, GPUNodeLink **link)
+{
+ if (!*link) {
+ *link = GPU_attribute(mat, CD_ORCO, "");
+ GPU_link(mat, "generated_texco", GPU_builtin(GPU_VIEW_POSITION), *link, link);
+ node_shader_gpu_bump_tex_coord(mat, node, link);
+ }
+}
+
+void node_shader_gpu_tex_mapping(GPUMaterial *mat,
+ bNode *node,
+ GPUNodeStack *in,
+ GPUNodeStack *UNUSED(out))
+{
+ NodeTexBase *base = (NodeTexBase *)node->storage;
+ TexMapping *texmap = &base->tex_mapping;
+ float domin = (texmap->flag & TEXMAP_CLIP_MIN) != 0;
+ float domax = (texmap->flag & TEXMAP_CLIP_MAX) != 0;
+
+ if (domin || domax || !(texmap->flag & TEXMAP_UNIT_MATRIX)) {
+ 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;
+
+ 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]);
+
+ GPU_link(mat, "mapping_mat4", in[0].link, tmat0, tmat1, tmat2, tmat3, tmin, tmax, &in[0].link);
+
+ if (texmap->type == TEXMAP_TYPE_NORMAL) {
+ GPU_link(mat, "vector_normalize", in[0].link, &in[0].link);
+ }
+ }
+}
+
+void get_XYZ_to_RGB_for_gpu(XYZ_to_RGB *data)
+{
+ const float *xyz_to_rgb = IMB_colormanagement_get_xyz_to_rgb();
+ data->r[0] = xyz_to_rgb[0];
+ data->r[1] = xyz_to_rgb[3];
+ data->r[2] = xyz_to_rgb[6];
+ data->g[0] = xyz_to_rgb[1];
+ data->g[1] = xyz_to_rgb[4];
+ data->g[2] = xyz_to_rgb[7];
+ data->b[0] = xyz_to_rgb[2];
+ data->b[1] = xyz_to_rgb[5];
+ data->b[2] = xyz_to_rgb[8];
+}