Merge branch 'master' into blender2.8
[blender.git] / source / blender / nodes / shader / node_shader_tree.c
index b4cdb1585264f2e45852f5cfefd4e7efb2f13e56..bd22a2be647b06b5bf5ce1f26ce2630bf6c34de9 100644 (file)
@@ -39,6 +39,7 @@
 #include "DNA_space_types.h"
 #include "DNA_world_types.h"
 #include "DNA_linestyle_types.h"
+#include "DNA_workspace_types.h"
 
 #include "BLI_listbase.h"
 #include "BLI_threads.h"
 static int shader_tree_poll(const bContext *C, bNodeTreeType *UNUSED(treetype))
 {
        Scene *scene = CTX_data_scene(C);
+       WorkSpace *workspace = CTX_wm_workspace(C);
+       ViewRender *view_render = BKE_viewrender_get(scene, workspace);
+       const char *engine_id = view_render->engine_id;
+
        /* allow empty engine string too, this is from older versions that didn't have registerable engines yet */
-       return (scene->r.engine[0] == '\0' ||
-               STREQ(scene->r.engine, RE_engine_id_BLENDER_RENDER) ||
-               STREQ(scene->r.engine, RE_engine_id_BLENDER_GAME) ||
-               STREQ(scene->r.engine, RE_engine_id_CYCLES) ||
-               !BKE_scene_use_shading_nodes_custom(scene));
+       return (engine_id[0] == '\0' ||
+               STREQ(engine_id, RE_engine_id_BLENDER_RENDER) ||
+               STREQ(engine_id, RE_engine_id_BLENDER_GAME) ||
+               STREQ(engine_id, RE_engine_id_CYCLES) ||
+               !BKE_viewrender_use_shading_nodes_custom(view_render));
 }
 
 static void shader_get_from_context(const bContext *C, bNodeTreeType *UNUSED(treetype), bNodeTree **r_ntree, ID **r_id, ID **r_from)
 {
        SpaceNode *snode = CTX_wm_space_node(C);
        Scene *scene = CTX_data_scene(C);
-       Object *ob = OBACT;
+       WorkSpace *workspace = CTX_wm_workspace(C);
+       ViewLayer *view_layer = CTX_data_view_layer(C);
+       Object *ob = OBACT(view_layer);
+       ViewRender *view_render = BKE_viewrender_get(scene, workspace);
        
        if ((snode->shaderfrom == SNODE_SHADER_OBJECT) ||
-           (BKE_scene_use_new_shading_nodes(scene) == false))
+           (BKE_viewrender_use_new_shading_nodes(view_render) == false))
        {
                if (ob) {
                        *r_from = &ob->id;
@@ -118,12 +126,12 @@ static void shader_get_from_context(const bContext *C, bNodeTreeType *UNUSED(tre
        }
 }
 
-static void foreach_nodeclass(Scene *scene, void *calldata, bNodeClassCallback func)
+static void foreach_nodeclass(ViewRender *view_render, void *calldata, bNodeClassCallback func)
 {
        func(calldata, NODE_CLASS_INPUT, N_("Input"));
        func(calldata, NODE_CLASS_OUTPUT, N_("Output"));
 
-       if (BKE_scene_use_new_shading_nodes(scene)) {
+       if (BKE_viewrender_use_new_shading_nodes(view_render)) {
                func(calldata, NODE_CLASS_SHADER, N_("Shader"));
                func(calldata, NODE_CLASS_TEXTURE, N_("Texture"));
        }
@@ -213,6 +221,9 @@ static void ntree_shader_link_builtin_normal(bNodeTree *ntree,
  * render engines works but it's how the GPU shader compilation works. This we
  * can change in the future and make it a generic function, but for now it stays
  * private here.
+ *
+ * It also does not yet take into account render engine specific output nodes,
+ * it should give priority to e.g. the Eevee material output node for Eevee.
  */
 static bNode *ntree_shader_output_node(bNodeTree *ntree)
 {
@@ -430,7 +441,7 @@ static void ntree_shader_link_builtin_normal(bNodeTree *ntree,
 static void ntree_shader_relink_displacement(bNodeTree *ntree,
                                              short compatibility)
 {
-       if (compatibility != NODE_NEW_SHADING) {
+       if ((compatibility & NODE_NEW_SHADING) == 0) {
                /* We can only deal with new shading system here. */
                return;
        }
@@ -476,6 +487,112 @@ static void ntree_shader_relink_displacement(bNodeTree *ntree,
        ntreeUpdateTree(G.main, ntree);
 }
 
+static bool ntree_tag_ssr_bsdf_cb(bNode *fromnode, bNode *UNUSED(tonode), void *userdata, const bool UNUSED(reversed))
+{
+       switch (fromnode->type) {
+               case SH_NODE_BSDF_ANISOTROPIC:
+               case SH_NODE_EEVEE_SPECULAR:
+               case SH_NODE_BSDF_PRINCIPLED:
+               case SH_NODE_BSDF_GLOSSY:
+               case SH_NODE_BSDF_GLASS:
+                       fromnode->ssr_id = (*(float *)userdata);
+                       (*(float *)userdata) += 1;
+                       break;
+               default:
+                       /* We could return false here but since we (will)
+                        * allow the use of Closure as RGBA, we can have
+                        * Bsdf nodes linked to other Bsdf nodes. */
+                       break;
+       }
+
+       return true;
+}
+
+/* EEVEE: Scan the ntree to set the Screen Space Reflection
+ * layer id of every specular node.
+ */
+static void ntree_shader_tag_ssr_node(bNodeTree *ntree, short compatibility)
+{
+       if ((compatibility & NODE_NEWER_SHADING) == 0) {
+               /* We can only deal with new shading system here. */
+               return;
+       }
+
+       bNode *output_node = ntree_shader_output_node(ntree);
+       if (output_node == NULL) {
+               return;
+       }
+       /* Make sure sockets links pointers are correct. */
+       ntreeUpdateTree(G.main, ntree);
+
+       float lobe_id = 1;
+       nodeChainIter(ntree, output_node, ntree_tag_ssr_bsdf_cb, &lobe_id, true);
+}
+
+static bool ntree_tag_sss_bsdf_cb(bNode *fromnode, bNode *UNUSED(tonode), void *userdata, const bool UNUSED(reversed))
+{
+       switch (fromnode->type) {
+               case SH_NODE_BSDF_PRINCIPLED:
+               case SH_NODE_SUBSURFACE_SCATTERING:
+                       fromnode->sss_id = (*(float *)userdata);
+                       (*(float *)userdata) += 1;
+                       break;
+               default:
+                       break;
+       }
+
+       return true;
+}
+
+/* EEVEE: Scan the ntree to set the Subsurface Scattering id of every SSS node.
+ */
+static void ntree_shader_tag_sss_node(bNodeTree *ntree, short compatibility)
+{
+       if ((compatibility & NODE_NEWER_SHADING) == 0) {
+               /* We can only deal with new shading system here. */
+               return;
+       }
+
+       bNode *output_node = ntree_shader_output_node(ntree);
+       if (output_node == NULL) {
+               return;
+       }
+       /* Make sure sockets links pointers are correct. */
+       ntreeUpdateTree(G.main, ntree);
+
+       float sss_id = 1;
+       nodeChainIter(ntree, output_node, ntree_tag_sss_bsdf_cb, &sss_id, true);
+}
+
+/* EEVEE: Find which material domain are used (volume, surface ...).
+ */
+void ntreeGPUMaterialDomain(bNodeTree *ntree, bool *has_surface_output, bool *has_volume_output)
+{
+       /* localize tree to create links for reroute and mute */
+       bNodeTree *localtree = ntreeLocalize(ntree);
+
+       struct bNode *output = ntree_shader_output_node(localtree);
+
+       *has_surface_output = false;
+       *has_volume_output = false;
+
+       if (output != NULL) {
+               bNodeSocket *surface_sock = ntree_shader_node_find_input(output, "Surface");
+               bNodeSocket *volume_sock = ntree_shader_node_find_input(output, "Volume");
+
+               if (surface_sock != NULL) {
+                       *has_surface_output = (nodeCountSocketLinks(localtree, surface_sock) > 0);
+               }
+
+               if (volume_sock != NULL) {
+                       *has_volume_output = (nodeCountSocketLinks(localtree, volume_sock) > 0);
+               }
+       }
+
+       ntreeFreeTree(localtree);
+       MEM_freeN(localtree);
+}
+
 void ntreeGPUMaterialNodes(bNodeTree *ntree, GPUMaterial *mat, short compatibility)
 {
        /* localize tree to create links for reroute and mute */
@@ -487,6 +604,9 @@ void ntreeGPUMaterialNodes(bNodeTree *ntree, GPUMaterial *mat, short compatibili
         */
        ntree_shader_relink_displacement(localtree, compatibility);
 
+       ntree_shader_tag_ssr_node(localtree, compatibility);
+       ntree_shader_tag_sss_node(localtree, compatibility);
+
        exec = ntreeShaderBeginExecTree(localtree);
        ntreeExecGPUNodes(exec, mat, 1, compatibility);
        ntreeShaderEndExecTree(exec);