Code refactor: reduce special node types, use generic constant folding.
authorBrecht Van Lommel <brechtvanlommel@gmail.com>
Sun, 1 May 2016 22:05:16 +0000 (00:05 +0200)
committerBrecht Van Lommel <brechtvanlommel@gmail.com>
Thu, 5 May 2016 19:43:46 +0000 (21:43 +0200)
intern/cycles/blender/blender_shader.cpp
intern/cycles/render/graph.cpp
intern/cycles/render/graph.h
intern/cycles/render/mesh.cpp
intern/cycles/render/nodes.cpp
intern/cycles/render/nodes.h
intern/cycles/render/osl.cpp
intern/cycles/render/shader.cpp
intern/cycles/render/svm.cpp

index 3f919bcad887953817b3ca68a3701d3b918fdcb0..6e4ca6627a16bac2106cb9c9c6b3bb82b2dd8315 100644 (file)
@@ -32,7 +32,7 @@ CCL_NAMESPACE_BEGIN
 
 typedef map<void*, ShaderInput*> PtrInputMap;
 typedef map<void*, ShaderOutput*> PtrOutputMap;
-typedef map<std::string, ProxyNode*> ProxyMap;
+typedef map<std::string, ConvertNode*> ProxyMap;
 
 /* Find */
 
@@ -321,10 +321,6 @@ static ShaderNode *add_node(Scene *scene,
                BL::ShaderNodeMixRGB b_mix_node(b_node);
                MixNode *mix = new MixNode();
                mix->type = MixNode::type_enum[b_mix_node.blend_type()];
-               /* Tag if it's Mix */
-               if(b_mix_node.blend_type() == 0) 
-                       mix->special_type = SHADER_SPECIAL_TYPE_MIX_RGB;
-
                mix->use_clamp = b_mix_node.use_clamp();
                node = mix;
        }
@@ -1029,7 +1025,8 @@ static void add_nodes(Scene *scene,
                        BL::Node::internal_links_iterator b_link;
                        for(b_node->internal_links.begin(b_link); b_link != b_node->internal_links.end(); ++b_link) {
                                BL::NodeSocket to_socket(b_link->to_socket());
-                               ProxyNode *proxy = new ProxyNode(convert_socket_type(to_socket));
+                               ShaderSocketType to_socket_type = convert_socket_type(to_socket);
+                               ConvertNode *proxy = new ConvertNode(to_socket_type, to_socket_type, true);
 
                                input_map[b_link->from_socket().ptr.data] = proxy->inputs[0];
                                output_map[b_link->to_socket().ptr.data] = proxy->outputs[0];
@@ -1051,7 +1048,8 @@ static void add_nodes(Scene *scene,
                         * so that links have something to connect to and assert won't fail.
                         */
                        for(b_node->inputs.begin(b_input); b_input != b_node->inputs.end(); ++b_input) {
-                               ProxyNode *proxy = new ProxyNode(convert_socket_type(*b_input));
+                               ShaderSocketType input_type = convert_socket_type(*b_input);
+                               ConvertNode *proxy = new ConvertNode(input_type, input_type, true);
                                graph->add(proxy);
 
                                /* register the proxy node for internal binding */
@@ -1062,7 +1060,8 @@ static void add_nodes(Scene *scene,
                                set_default_value(proxy->inputs[0], *b_input, b_data, b_ntree);
                        }
                        for(b_node->outputs.begin(b_output); b_output != b_node->outputs.end(); ++b_output) {
-                               ProxyNode *proxy = new ProxyNode(convert_socket_type(*b_output));
+                               ShaderSocketType output_type = convert_socket_type(*b_output);
+                               ConvertNode *proxy = new ConvertNode(output_type, output_type, true);
                                graph->add(proxy);
 
                                /* register the proxy node for internal binding */
@@ -1088,7 +1087,7 @@ static void add_nodes(Scene *scene,
                        for(b_node->outputs.begin(b_output); b_output != b_node->outputs.end(); ++b_output) {
                                ProxyMap::const_iterator proxy_it = proxy_input_map.find(b_output->identifier());
                                if(proxy_it != proxy_input_map.end()) {
-                                       ProxyNode *proxy = proxy_it->second;
+                                       ConvertNode *proxy = proxy_it->second;
 
                                        output_map[b_output->ptr.data] = proxy->outputs[0];
                                }
@@ -1102,7 +1101,7 @@ static void add_nodes(Scene *scene,
                                for(b_node->inputs.begin(b_input); b_input != b_node->inputs.end(); ++b_input) {
                                        ProxyMap::const_iterator proxy_it = proxy_output_map.find(b_input->identifier());
                                        if(proxy_it != proxy_output_map.end()) {
-                                               ProxyNode *proxy = proxy_it->second;
+                                               ConvertNode *proxy = proxy_it->second;
 
                                                input_map[b_input->ptr.data] = proxy->inputs[0];
 
index 4a9b2f1103cacb6e6214e4133fd34928694d274e..b23fd2a7a8bfc17a9b6e880dc1bbfa4e13e0da5f 100644 (file)
@@ -290,18 +290,21 @@ void ShaderGraph::disconnect(ShaderInput *to)
        from->links.erase(remove(from->links.begin(), from->links.end(), to), from->links.end());
 }
 
-void ShaderGraph::relink(vector<ShaderInput*> inputs, vector<ShaderInput*> outputs, ShaderOutput *output)
+void ShaderGraph::relink(ShaderNode *node, ShaderOutput *from, ShaderOutput *to)
 {
-       /* Remove nodes and re-link if output isn't NULL. */
-       foreach(ShaderInput *sock, inputs) {
+       /* Copy because disconnect modifies this list */
+       vector<ShaderInput*> outputs = from->links;
+
+       /* Bypass node by moving all links from "from" to "to" */
+       foreach(ShaderInput *sock, node->inputs) {
                if(sock->link)
                        disconnect(sock);
        }
 
        foreach(ShaderInput *sock, outputs) {
                disconnect(sock);
-               if(output)
-                       connect(output, sock);
+               if(to)
+                       connect(to, sock);
        }
 }
 
@@ -411,39 +414,29 @@ void ShaderGraph::copy_nodes(ShaderNodeSet& nodes, ShaderNodeMap& nnodemap)
 /* Graph simplification */
 /* ******************** */
 
-/* Step 1: Remove unused nodes.
- * Remove nodes which are not needed in the graph, such as proxies,
- * mix nodes with a factor of 0 or 1, emission shaders without contribution...
+/* Step 1: Remove proxy nodes.
+ * These only exists temporarily when exporting groups, and we must remove them
+ * early so that node->attributes() and default links do not see them.
  */
-void ShaderGraph::remove_unneeded_nodes()
+void ShaderGraph::remove_proxy_nodes()
 {
        vector<bool> removed(num_node_ids, false);
        bool any_node_removed = false;
 
-       ShaderNode *geom = NULL;
-
-       /* find and unlink proxy nodes */
        foreach(ShaderNode *node, nodes) {
                if(node->special_type == SHADER_SPECIAL_TYPE_PROXY) {
-                       ProxyNode *proxy = static_cast<ProxyNode*>(node);
+                       ConvertNode *proxy = static_cast<ConvertNode*>(node);
                        ShaderInput *input = proxy->inputs[0];
                        ShaderOutput *output = proxy->outputs[0];
 
-                       /* temp. copy of the output links list.
-                        * output->links is modified when we disconnect!
-                        */
-                       vector<ShaderInput*> links(output->links);
-                       ShaderOutput *from = input->link;
-
                        /* bypass the proxy node */
-                       if(from) {
-                               disconnect(input);
-                               foreach(ShaderInput *to, links) {
-                                       disconnect(to);
-                                       connect(from, to);
-                               }
+                       if(input->link) {
+                               relink(proxy, output, input->link);
                        }
                        else {
+                               /* Copy because disconnect modifies this list */
+                               vector<ShaderInput*> links(output->links);
+
                                foreach(ShaderInput *to, links) {
                                        /* remove any autoconvert nodes too if they lead to
                                         * sockets with an automatically set default value */
@@ -465,132 +458,16 @@ void ShaderGraph::remove_unneeded_nodes()
                                        }
 
                                        disconnect(to);
-                                       
+
                                        /* transfer the default input value to the target socket */
                                        to->set(input->value);
                                        to->set(input->value_string);
                                }
                        }
-                       
+
                        removed[proxy->id] = true;
                        any_node_removed = true;
                }
-               else if(node->special_type == SHADER_SPECIAL_TYPE_BACKGROUND) {
-                       BackgroundNode *bg = static_cast<BackgroundNode*>(node);
-
-                       if(bg->outputs[0]->links.size()) {
-                               /* Black color or zero strength, remove node */
-                               if((!bg->inputs[0]->link && bg->inputs[0]->value == make_float3(0.0f, 0.0f, 0.0f)) ||
-                                  (!bg->inputs[1]->link && bg->inputs[1]->value.x == 0.0f))
-                               {
-                                       vector<ShaderInput*> inputs = bg->outputs[0]->links;
-
-                                       relink(bg->inputs, inputs, NULL);
-                                       removed[bg->id] = true;
-                                       any_node_removed = true;
-                               }
-                       }
-               }
-               else if(node->special_type == SHADER_SPECIAL_TYPE_EMISSION) {
-                       EmissionNode *em = static_cast<EmissionNode*>(node);
-
-                       if(em->outputs[0]->links.size()) {
-                               /* Black color or zero strength, remove node */
-                               if((!em->inputs[0]->link && em->inputs[0]->value == make_float3(0.0f, 0.0f, 0.0f)) ||
-                                  (!em->inputs[1]->link && em->inputs[1]->value.x == 0.0f))
-                               {
-                                       vector<ShaderInput*> inputs = em->outputs[0]->links;
-
-                                       relink(em->inputs, inputs, NULL);
-                                       removed[em->id] = true;
-                                       any_node_removed = true;
-                               }
-                       }
-               }
-               else if(node->special_type == SHADER_SPECIAL_TYPE_BUMP) {
-                       BumpNode *bump = static_cast<BumpNode*>(node);
-
-                       if(bump->outputs[0]->links.size()) {
-                               /* Height inputs is not connected. */
-                               /* TODO(sergey): Ignore bump with zero strength. */
-                               if(bump->inputs[0]->link == NULL) {
-                                       vector<ShaderInput*> inputs = bump->outputs[0]->links;
-                                       if(bump->inputs[4]->link == NULL) {
-                                               if(geom == NULL) {
-                                                       geom = new GeometryNode();
-                                               }
-                                               relink(bump->inputs, inputs, geom->output("Normal"));
-                                       }
-                                       else {
-                                               relink(bump->inputs, inputs, bump->input("Normal")->link);
-                                       }
-                                       removed[bump->id] = true;
-                                       any_node_removed = true;
-                               }
-                       }
-               }
-               else if(node->special_type == SHADER_SPECIAL_TYPE_MIX_CLOSURE) {
-                       MixClosureNode *mix = static_cast<MixClosureNode*>(node);
-
-                       /* remove useless mix closures nodes */
-                       if(mix->outputs[0]->links.size() && mix->inputs[1]->link == mix->inputs[2]->link) {
-                               ShaderOutput *output = mix->inputs[1]->link;
-                               vector<ShaderInput*> inputs = mix->outputs[0]->links;
-
-                               relink(mix->inputs, inputs, output);
-                               removed[mix->id] = true;
-                               any_node_removed = true;
-                       }
-               
-                       /* remove unused mix closure input when factor is 0.0 or 1.0 */
-                       /* check for closure links and make sure factor link is disconnected */
-                       if(mix->outputs[0]->links.size() && mix->inputs[1]->link && mix->inputs[2]->link && !mix->inputs[0]->link) {
-                               /* factor 0.0 */
-                               if(mix->inputs[0]->value.x == 0.0f) {
-                                       ShaderOutput *output = mix->inputs[1]->link;
-                                       vector<ShaderInput*> inputs = mix->outputs[0]->links;
-
-                                       relink(mix->inputs, inputs, output);
-                                       removed[mix->id] = true;
-                                       any_node_removed = true;
-                               }
-                               /* factor 1.0 */
-                               else if(mix->inputs[0]->value.x == 1.0f) {
-                                       ShaderOutput *output = mix->inputs[2]->link;
-                                       vector<ShaderInput*> inputs = mix->outputs[0]->links;
-
-                                       relink(mix->inputs, inputs, output);
-                                       removed[mix->id] = true;
-                                       any_node_removed = true;
-                               }
-                       }
-               }
-               else if(node->special_type == SHADER_SPECIAL_TYPE_MIX_RGB) {
-                       MixNode *mix = static_cast<MixNode*>(node);
-
-                       /* remove unused Mix RGB inputs when factor is 0.0 or 1.0 */
-                       /* check for color links and make sure factor link is disconnected */
-                       if(mix->outputs[0]->links.size() && mix->inputs[1]->link && mix->inputs[2]->link && !mix->inputs[0]->link) {
-                               /* factor 0.0 */
-                               if(mix->inputs[0]->value.x == 0.0f) {
-                                       ShaderOutput *output = mix->inputs[1]->link;
-                                       vector<ShaderInput*> inputs = mix->outputs[0]->links;
-
-                                       relink(mix->inputs, inputs, output);
-                                       removed[mix->id] = true;
-                                       any_node_removed = true;
-                               }
-                               /* factor 1.0 */
-                               else if(mix->inputs[0]->value.x == 1.0f) {
-                                       ShaderOutput *output = mix->inputs[2]->link;
-                                       vector<ShaderInput*> inputs = mix->outputs[0]->links;
-
-                                       relink(mix->inputs, inputs, output);
-                                       removed[mix->id] = true;
-                                       any_node_removed = true;
-                               }
-                       }
-               }
        }
 
        /* remove nodes */
@@ -606,10 +483,6 @@ void ShaderGraph::remove_unneeded_nodes()
 
                nodes = newnodes;
        }
-
-       if(geom != NULL) {
-               add(geom);
-       }
 }
 
 /* Step 2: Constant folding.
@@ -634,6 +507,9 @@ void ShaderGraph::constant_fold()
                traverse_queue.pop();
                done.insert(node);
                foreach(ShaderOutput *output, node->outputs) {
+                       if (output->links.size() == 0) {
+                               continue;
+                       }
                        /* Schedule node which was depending on the value,
                         * when possible. Do it before disconnect.
                         */
@@ -652,7 +528,7 @@ void ShaderGraph::constant_fold()
                        }
                        /* Optimize current node. */
                        float3 optimized_value = make_float3(0.0f, 0.0f, 0.0f);
-                       if(node->constant_fold(output, &optimized_value)) {
+                       if(node->constant_fold(this, output, &optimized_value)) {
                                /* Apply optimized value to connected sockets. */
                                vector<ShaderInput*> links(output->links);
                                foreach(ShaderInput *input, links) {
@@ -737,8 +613,7 @@ void ShaderGraph::deduplicate_nodes()
                        }
                        /* TODO(sergey): Consider making it an utility function. */
                        for(int i = 0; i < node->outputs.size(); ++i) {
-                               vector<ShaderInput*> inputs = node->outputs[i]->links;
-                               relink(node->inputs, inputs, other_node->outputs[i]);
+                               relink(node, node->outputs[i], other_node->outputs[i]);
                        }
                        break;
                }
@@ -771,15 +646,9 @@ void ShaderGraph::break_cycles(ShaderNode *node, vector<bool>& visited, vector<b
 
 void ShaderGraph::clean(Scene *scene)
 {
-       /* Graph simplification:
-        *  1: Remove unnecessary nodes
-        *  2: Constant folding
-        *  3: Simplification
-        *  4: De-duplication
-        */
+       /* Graph simplification */
 
-       /* 1: Remove proxy and unnecessary nodes. */
-       remove_unneeded_nodes();
+       /* 1: Remove proxy nodes was already done. */
 
        /* 2: Constant folding. */
        constant_fold();
@@ -892,7 +761,7 @@ void ShaderGraph::refine_bump_nodes()
         * to "center" input. */
 
        foreach(ShaderNode *node, nodes) {
-               if(node->name == ustring("bump") && node->input("Height")->link) {
+               if(node->special_type == SHADER_SPECIAL_TYPE_BUMP && node->input("Height")->link) {
                        ShaderInput *bump_input = node->input("Height");
                        ShaderNodeSet nodes_bump;
 
index 214199a1c52e4d70e27c71bc025fdb99dc336d16..2236f51957c8b58d85926a307722c150449f98a8 100644 (file)
@@ -76,15 +76,11 @@ enum ShaderBump {
 enum ShaderNodeSpecialType {
        SHADER_SPECIAL_TYPE_NONE,
        SHADER_SPECIAL_TYPE_PROXY,
-       SHADER_SPECIAL_TYPE_MIX_CLOSURE,
-       SHADER_SPECIAL_TYPE_MIX_RGB, /* Only Mix subtype */
        SHADER_SPECIAL_TYPE_AUTOCONVERT,
        SHADER_SPECIAL_TYPE_GEOMETRY,
        SHADER_SPECIAL_TYPE_SCRIPT,
-       SHADER_SPECIAL_TYPE_BACKGROUND,
        SHADER_SPECIAL_TYPE_IMAGE_SLOT,
        SHADER_SPECIAL_TYPE_CLOSURE,
-       SHADER_SPECIAL_TYPE_EMISSION,
        SHADER_SPECIAL_TYPE_BUMP,
 };
 
@@ -197,7 +193,7 @@ public:
 
        /* ** Node optimization ** */
        /* Check whether the node can be replaced with single constant. */
-       virtual bool constant_fold(ShaderOutput * /*socket*/, float3 * /*optimized_value*/) { return false; }
+       virtual bool constant_fold(ShaderGraph * /*graph*/, ShaderOutput * /*socket*/, float3 * /*optimized_value*/) { return false; }
 
        /* Simplify settings used by artists to the ones which are simpler to
         * evaluate in the kernel but keep the final result unchanged.
@@ -307,9 +303,9 @@ public:
 
        void connect(ShaderOutput *from, ShaderInput *to);
        void disconnect(ShaderInput *to);
-       void relink(vector<ShaderInput*> inputs, vector<ShaderInput*> outputs, ShaderOutput *output);
+       void relink(ShaderNode *node, ShaderOutput *from, ShaderOutput *to);
 
-       void remove_unneeded_nodes();
+       void remove_proxy_nodes();
        void finalize(Scene *scene,
                      bool do_bump = false,
                      bool do_osl = false,
index cc8519219edd2b46c0cd3b0d4a749c5715668072..f8273107e1b4cb55c9a7d6b84db8a191dfd00db6 100644 (file)
@@ -1210,7 +1210,7 @@ void MeshManager::device_update_displacement_images(Device *device,
                                                                             progress);
                                                return;
                                        }
-                                       ImageSlotNode *image_node = static_cast<ImageSlotNode*>(node);
+                                       ImageSlotTextureNode *image_node = static_cast<ImageSlotTextureNode*>(node);
                                        int slot = image_node->slot;
                                        if(slot != -1) {
                                                bump_images.insert(slot);
index 57fb1a78f5bedda81aebacc5dc7cfbb38815087c..8e8b99ec5e74548b3e87045ef746b884f3a0f0e1 100644 (file)
@@ -1595,10 +1595,12 @@ ConvertNode::ConvertNode(ShaderSocketType from_, ShaderSocketType to_, bool auto
        from = from_;
        to = to_;
 
-       if(autoconvert)
-               special_type = SHADER_SPECIAL_TYPE_AUTOCONVERT;
-
-       assert(from != to);
+       if(autoconvert) {
+               if(from == to)
+                       special_type = SHADER_SPECIAL_TYPE_PROXY;
+               else
+                       special_type = SHADER_SPECIAL_TYPE_AUTOCONVERT;
+       }
 
        if(from == SHADER_SOCKET_FLOAT)
                add_input("Val", SHADER_SOCKET_FLOAT);
@@ -1614,6 +1616,8 @@ ConvertNode::ConvertNode(ShaderSocketType from_, ShaderSocketType to_, bool auto
                add_input("Normal", SHADER_SOCKET_NORMAL);
        else if(from == SHADER_SOCKET_STRING)
                add_input("String", SHADER_SOCKET_STRING);
+       else if(from == SHADER_SOCKET_CLOSURE)
+               add_input("Closure", SHADER_SOCKET_CLOSURE);
        else
                assert(0);
 
@@ -1631,48 +1635,50 @@ ConvertNode::ConvertNode(ShaderSocketType from_, ShaderSocketType to_, bool auto
                add_output("Normal", SHADER_SOCKET_NORMAL);
        else if(to == SHADER_SOCKET_STRING)
                add_output("String", SHADER_SOCKET_STRING);
+       else if(to == SHADER_SOCKET_CLOSURE)
+               add_output("Closure", SHADER_SOCKET_CLOSURE);
        else
                assert(0);
 }
 
-bool ConvertNode::constant_fold(ShaderOutput *socket, float3 *optimized_value)
+bool ConvertNode::constant_fold(ShaderGraph *graph, ShaderOutput *socket, float3 *optimized_value)
 {
        ShaderInput *in = inputs[0];
        float3 value = in->value;
 
        /* TODO(DingTo): conversion from/to int is not supported yet, don't fold in that case */
 
-       if(socket == outputs[0] && in->link == NULL) {
+       if(in->link == NULL) {
                if(from == SHADER_SOCKET_FLOAT) {
                        if(to == SHADER_SOCKET_INT)
-                       /* float to int */
+                               /* float to int */
                                return false;
                        else
-                       /* float to float3 */
+                               /* float to float3 */
                                *optimized_value = make_float3(value.x, value.x, value.x);
                }
                else if(from == SHADER_SOCKET_INT) {
                        if(to == SHADER_SOCKET_FLOAT)
-                       /* int to float */
+                               /* int to float */
                                return false;
                        else
-                       /* int to vector/point/normal */
+                               /* int to vector/point/normal */
                                return false;
                }
                else if(to == SHADER_SOCKET_FLOAT) {
                        if(from == SHADER_SOCKET_COLOR)
-                       /* color to float */
+                               /* color to float */
                                optimized_value->x = linear_rgb_to_gray(value);
                        else
-                       /* vector/point/normal to float */
+                               /* vector/point/normal to float */
                                optimized_value->x = average(value);
                }
                else if(to == SHADER_SOCKET_INT) {
                        if(from == SHADER_SOCKET_COLOR)
-                       /* color to int */
+                               /* color to int */
                                return false;
                        else
-                       /* vector/point/normal to int */
+                               /* vector/point/normal to int */
                                return false;
                }
                else {
@@ -1687,6 +1693,9 @@ bool ConvertNode::constant_fold(ShaderOutput *socket, float3 *optimized_value)
 
 void ConvertNode::compile(SVMCompiler& compiler)
 {
+       /* constant folding should eliminate proxy nodes */
+       assert(from != to);
+
        ShaderInput *in = inputs[0];
        ShaderOutput *out = outputs[0];
 
@@ -1753,6 +1762,9 @@ void ConvertNode::compile(SVMCompiler& compiler)
 
 void ConvertNode::compile(OSLCompiler& compiler)
 {
+       /* constant folding should eliminate proxy nodes */
+       assert(from != to);
+
        if(from == SHADER_SOCKET_FLOAT)
                compiler.add(this, "node_convert_from_float");
        else if(from == SHADER_SOCKET_INT)
@@ -1769,26 +1781,6 @@ void ConvertNode::compile(OSLCompiler& compiler)
                assert(0);
 }
 
-/* Proxy */
-
-ProxyNode::ProxyNode(ShaderSocketType type_)
-: ShaderNode("proxy")
-{
-       type = type_;
-       special_type = SHADER_SPECIAL_TYPE_PROXY;
-
-       add_input("Input", type);
-       add_output("Output", type);
-}
-
-void ProxyNode::compile(SVMCompiler& /*compiler*/)
-{
-}
-
-void ProxyNode::compile(OSLCompiler& /*compiler*/)
-{
-}
-
 /* BSDF Closure */
 
 BsdfNode::BsdfNode(bool scattering_)
@@ -2285,8 +2277,6 @@ bool SubsurfaceScatteringNode::has_bssrdf_bump()
 EmissionNode::EmissionNode()
 : ShaderNode("emission")
 {
-       special_type = SHADER_SPECIAL_TYPE_EMISSION;
-
        add_input("Color", SHADER_SOCKET_COLOR, make_float3(0.8f, 0.8f, 0.8f));
        add_input("Strength", SHADER_SOCKET_FLOAT, 10.0f);
        add_input("SurfaceMixWeight", SHADER_SOCKET_FLOAT, 0.0f, ShaderInput::USE_SVM);
@@ -2315,13 +2305,20 @@ void EmissionNode::compile(OSLCompiler& compiler)
        compiler.add(this, "node_emission");
 }
 
+bool EmissionNode::constant_fold(ShaderGraph * /*graph*/, ShaderOutput * /*socket*/, float3 * /*optimized_value*/)
+{
+       ShaderInput *color_in = input("Color");
+       ShaderInput *strength_in = input("Strength");
+
+       return ((!color_in->link && color_in->value == make_float3(0.0f, 0.0f, 0.0f)) ||
+               (!strength_in->link && strength_in->value.x == 0.0f));
+}
+
 /* Background Closure */
 
 BackgroundNode::BackgroundNode()
 : ShaderNode("background")
 {
-       special_type = SHADER_SPECIAL_TYPE_BACKGROUND;
-
        add_input("Color", SHADER_SOCKET_COLOR, make_float3(0.8f, 0.8f, 0.8f));
        add_input("Strength", SHADER_SOCKET_FLOAT, 1.0f);
        add_input("SurfaceMixWeight", SHADER_SOCKET_FLOAT, 0.0f, ShaderInput::USE_SVM);
@@ -2350,6 +2347,15 @@ void BackgroundNode::compile(OSLCompiler& compiler)
        compiler.add(this, "node_background");
 }
 
+bool BackgroundNode::constant_fold(ShaderGraph * /*graph*/, ShaderOutput * /*socket*/, float3 * /*optimized_value*/)
+{
+       ShaderInput *color_in = input("Color");
+       ShaderInput *strength_in = input("Strength");
+
+       return ((!color_in->link && color_in->value == make_float3(0.0f, 0.0f, 0.0f)) ||
+               (!strength_in->link && strength_in->value.x == 0.0f));
+}
+
 /* Holdout Closure */
 
 HoldoutNode::HoldoutNode()
@@ -3249,7 +3255,7 @@ ValueNode::ValueNode()
        add_output("Value", SHADER_SOCKET_FLOAT);
 }
 
-bool ValueNode::constant_fold(ShaderOutput * /*socket*/,
+bool ValueNode::constant_fold(ShaderGraph * /*graph*/, ShaderOutput * /*socket*/,
                               float3 *optimized_value)
 {
        *optimized_value = make_float3(value, value, value);
@@ -3280,7 +3286,7 @@ ColorNode::ColorNode()
        add_output("Color", SHADER_SOCKET_COLOR);
 }
 
-bool ColorNode::constant_fold(ShaderOutput * /*socket*/,
+bool ColorNode::constant_fold(ShaderGraph * /*graph*/, ShaderOutput * /*socket*/,
                               float3 *optimized_value)
 {
        *optimized_value = value;
@@ -3330,8 +3336,6 @@ void AddClosureNode::compile(OSLCompiler& compiler)
 MixClosureNode::MixClosureNode()
 : ShaderNode("mix_closure")
 {
-       special_type = SHADER_SPECIAL_TYPE_MIX_CLOSURE;
-       
        add_input("Fac", SHADER_SOCKET_FLOAT, 0.5f);
        add_input("Closure1", SHADER_SOCKET_CLOSURE);
        add_input("Closure2", SHADER_SOCKET_CLOSURE);
@@ -3348,6 +3352,37 @@ void MixClosureNode::compile(OSLCompiler& compiler)
        compiler.add(this, "node_mix_closure");
 }
 
+bool MixClosureNode::constant_fold(ShaderGraph *graph, ShaderOutput * /*socket*/, float3 * /*optimized_value*/)
+{
+       ShaderInput *fac_in = input("Fac");
+       ShaderInput *closure1_in = input("Closure1");
+       ShaderInput *closure2_in = input("Closure2");
+       ShaderOutput *closure_out = output("Closure");
+
+       /* remove useless mix closures nodes */
+       if(closure1_in->link == closure2_in->link) {
+               graph->relink(this, closure_out, closure1_in->link);
+               return true;
+       }
+
+       /* remove unused mix closure input when factor is 0.0 or 1.0 */
+       /* check for closure links and make sure factor link is disconnected */
+       if(closure1_in->link && closure2_in->link && !fac_in->link) {
+               /* factor 0.0 */
+               if(fac_in->value.x == 0.0f) {
+                       graph->relink(this, closure_out, closure1_in->link);
+                       return true;
+               }
+               /* factor 1.0 */
+               else if(fac_in->value.x == 1.0f) {
+                       graph->relink(this, closure_out, closure2_in->link);
+                       return true;
+               }
+       }
+
+       return false;
+}
+
 /* Mix Closure */
 
 MixClosureWeightNode::MixClosureWeightNode()
@@ -3480,6 +3515,41 @@ void MixNode::compile(OSLCompiler& compiler)
        compiler.add(this, "node_mix");
 }
 
+bool MixNode::constant_fold(ShaderGraph *graph, ShaderOutput * /*socket*/, float3 * /*optimized_value*/)
+{
+       if(type != ustring("Mix")) {
+               return false;
+       }
+
+       ShaderInput *fac_in = input("Fac");
+       ShaderInput *color1_in = input("Color1");
+       ShaderInput *color2_in = input("Color2");
+       ShaderOutput *color_out = output("Color");
+
+       /* remove useless mix colors nodes */
+       if(color1_in->link == color2_in->link) {
+               graph->relink(this, color_out, color1_in->link);
+               return true;
+       }
+
+       /* remove unused mix color input when factor is 0.0 or 1.0 */
+       /* check for color links and make sure factor link is disconnected */
+       if(color1_in->link && color2_in->link && !fac_in->link) {
+               /* factor 0.0 */
+               if(fac_in->value.x == 0.0f) {
+                       graph->relink(this, color_out, color1_in->link);
+                       return true;
+               }
+               /* factor 1.0 */
+               else if(fac_in->value.x == 1.0f) {
+                       graph->relink(this, color_out, color2_in->link);
+                       return true;
+               }
+       }
+
+       return false;
+}
+
 /* Combine RGB */
 CombineRGBNode::CombineRGBNode()
 : ShaderNode("combine_rgb")
@@ -3588,7 +3658,7 @@ GammaNode::GammaNode()
        add_output("Color", SHADER_SOCKET_COLOR);
 }
 
-bool GammaNode::constant_fold(ShaderOutput *socket, float3 *optimized_value)
+bool GammaNode::constant_fold(ShaderGraph * /*graph*/, ShaderOutput *socket, float3 *optimized_value)
 {
        ShaderInput *color_in = input("Color");
        ShaderInput *gamma_in = input("Gamma");
@@ -3597,7 +3667,6 @@ bool GammaNode::constant_fold(ShaderOutput *socket, float3 *optimized_value)
                if(color_in->link == NULL && gamma_in->link == NULL) {
                        *optimized_value = svm_math_gamma_color(color_in->value,
                                                                gamma_in->value.x);
-
                        return true;
                }
        }
@@ -4058,14 +4127,13 @@ BlackbodyNode::BlackbodyNode()
        add_output("Color", SHADER_SOCKET_COLOR);
 }
 
-bool BlackbodyNode::constant_fold(ShaderOutput *socket, float3 *optimized_value)
+bool BlackbodyNode::constant_fold(ShaderGraph * /*graph*/, ShaderOutput *socket, float3 *optimized_value)
 {
        ShaderInput *temperature_in = input("Temperature");
 
        if(socket == output("Color")) {
                if(temperature_in->link == NULL) {
                        *optimized_value = svm_math_blackbody_color(temperature_in->value.x);
-
                        return true;
                }
        }
@@ -4165,7 +4233,7 @@ static ShaderEnum math_type_init()
 
 ShaderEnum MathNode::type_enum = math_type_init();
 
-bool MathNode::constant_fold(ShaderOutput *socket, float3 *optimized_value)
+bool MathNode::constant_fold(ShaderGraph * /*graph*/, ShaderOutput *socket, float3 *optimized_value)
 {
        ShaderInput *value1_in = input("Value1");
        ShaderInput *value2_in = input("Value2");
@@ -4242,7 +4310,7 @@ static ShaderEnum vector_math_type_init()
 
 ShaderEnum VectorMathNode::type_enum = vector_math_type_init();
 
-bool VectorMathNode::constant_fold(ShaderOutput *socket, float3 *optimized_value)
+bool VectorMathNode::constant_fold(ShaderGraph * /*graph*/, ShaderOutput *socket, float3 *optimized_value)
 {
        ShaderInput *vector1_in = input("Vector1");
        ShaderInput *vector2_in = input("Vector2");
@@ -4409,6 +4477,28 @@ void BumpNode::compile(OSLCompiler& compiler)
        compiler.add(this, "node_bump");
 }
 
+bool BumpNode::constant_fold(ShaderGraph *graph, ShaderOutput *socket, float3 *optimized_value)
+{
+       ShaderInput *height_in = input("Height");
+       ShaderInput *normal_in = input("Normal");
+
+       if(height_in->link == NULL) {
+               if(normal_in->link == NULL) {
+                       GeometryNode *geom = new GeometryNode();
+                       graph->add(geom);
+                       graph->relink(this, outputs[0], geom->output("Normal"));
+               }
+               else {
+                       graph->relink(this, outputs[0], normal_in->link);
+               }
+               return true;
+       }
+
+       /* TODO(sergey): Ignore bump with zero strength. */
+
+       return false;
+}
+
 /* RGBCurvesNode */
 
 RGBCurvesNode::RGBCurvesNode()
index a5495ff3671cb39ea5ed46f9754277c1cee171b7..9e93f30e75e1034383977a2ee6b89d530d67db5c 100644 (file)
@@ -70,15 +70,6 @@ public:
 
 /* Nodes */
 
-/* Any node which uses image manager's slot should be a subclass of this one. */
-class ImageSlotNode : public ShaderNode {
-public:
-       ImageSlotNode(const char *name_) : ShaderNode(name_) {
-               special_type = SHADER_SPECIAL_TYPE_IMAGE_SLOT;
-       }
-       int slot;
-};
-
 class TextureNode : public ShaderNode {
 public:
        TextureNode(const char *name_) : ShaderNode(name_) {}
@@ -90,15 +81,13 @@ public:
        }
 };
 
-class ImageSlotTextureNode : public ImageSlotNode {
+/* Any node which uses image manager's slot should be a subclass of this one. */
+class ImageSlotTextureNode : public TextureNode {
 public:
-       ImageSlotTextureNode(const char *name_) : ImageSlotNode(name_) {}
-       TextureMapping tex_mapping;
-
-       virtual bool equals(const ShaderNode *other) {
-               return ShaderNode::equals(other) &&
-                      tex_mapping.equals(((const ImageSlotTextureNode*)other)->tex_mapping);
+       ImageSlotTextureNode(const char *name_) : TextureNode(name_) {
+               special_type = SHADER_SPECIAL_TYPE_IMAGE_SLOT;
        }
+       int slot;
 };
 
 class ImageTextureNode : public ImageSlotTextureNode {
@@ -372,7 +361,7 @@ public:
        ConvertNode(ShaderSocketType from, ShaderSocketType to, bool autoconvert = false);
        SHADER_NODE_BASE_CLASS(ConvertNode)
 
-       bool constant_fold(ShaderOutput *socket, float3 *optimized_value);
+       bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, float3 *optimized_value);
 
        ShaderSocketType from, to;
 
@@ -385,23 +374,6 @@ public:
        }
 };
 
-class ProxyNode : public ShaderNode {
-public:
-       ProxyNode(ShaderSocketType type);
-       SHADER_NODE_BASE_CLASS(ProxyNode)
-
-       ShaderSocketType type;
-
-       virtual bool equals(const ShaderNode * /*other*/)
-       {
-               /* Proxy nodes are created for node groups and can't be duplicated
-                * actually. So in order to make code a bit more robust in obscure cases
-                * lets explicitly forbid de-duplication of proxy nodes for now.
-                */
-               return false;
-       }
-};
-
 class BsdfNode : public ShaderNode {
 public:
        BsdfNode(bool scattering = false);
@@ -505,6 +477,7 @@ public:
 class EmissionNode : public ShaderNode {
 public:
        SHADER_NODE_CLASS(EmissionNode)
+       bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, float3 *optimized_value);
 
        bool has_surface_emission() { return true; }
 };
@@ -512,6 +485,7 @@ public:
 class BackgroundNode : public ShaderNode {
 public:
        SHADER_NODE_CLASS(BackgroundNode)
+       bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, float3 *optimized_value);
 };
 
 class HoldoutNode : public ShaderNode {
@@ -650,7 +624,7 @@ class ValueNode : public ShaderNode {
 public:
        SHADER_NODE_CLASS(ValueNode)
 
-       bool constant_fold(ShaderOutput *socket, float3 *optimized_value);
+       bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, float3 *optimized_value);
 
        float value;
 
@@ -665,7 +639,7 @@ class ColorNode : public ShaderNode {
 public:
        SHADER_NODE_CLASS(ColorNode)
 
-       bool constant_fold(ShaderOutput *socket, float3 *optimized_value);
+       bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, float3 *optimized_value);
 
        float3 value;
 
@@ -684,6 +658,7 @@ public:
 class MixClosureNode : public ShaderNode {
 public:
        SHADER_NODE_CLASS(MixClosureNode)
+       bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, float3 *optimized_value);
 };
 
 class MixClosureWeightNode : public ShaderNode {
@@ -701,6 +676,7 @@ public:
 class MixNode : public ShaderNode {
 public:
        SHADER_NODE_CLASS(MixNode)
+       bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, float3 *optimized_value);
 
        virtual int get_group() { return NODE_GROUP_LEVEL_3; }
 
@@ -743,7 +719,7 @@ class GammaNode : public ShaderNode {
 public:
        SHADER_NODE_CLASS(GammaNode)
 
-       bool constant_fold(ShaderOutput *socket, float3 *optimized_value);
+       bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, float3 *optimized_value);
 
        virtual int get_group() { return NODE_GROUP_LEVEL_1; }
 };
@@ -834,7 +810,7 @@ public:
 class BlackbodyNode : public ShaderNode {
 public:
        SHADER_NODE_CLASS(BlackbodyNode)
-       bool constant_fold(ShaderOutput *socket, float3 *optimized_value);
+       bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, float3 *optimized_value);
 
        virtual int get_group() { return NODE_GROUP_LEVEL_3; }
 };
@@ -843,7 +819,7 @@ class MathNode : public ShaderNode {
 public:
        SHADER_NODE_CLASS(MathNode)
        virtual int get_group() { return NODE_GROUP_LEVEL_1; }
-       bool constant_fold(ShaderOutput *socket, float3 *optimized_value);
+       bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, float3 *optimized_value);
 
        bool use_clamp;
 
@@ -878,7 +854,7 @@ class VectorMathNode : public ShaderNode {
 public:
        SHADER_NODE_CLASS(VectorMathNode)
        virtual int get_group() { return NODE_GROUP_LEVEL_1; }
-       bool constant_fold(ShaderOutput *socket, float3 *optimized_value);
+       bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, float3 *optimized_value);
 
        ustring type;
        static ShaderEnum type_enum;
@@ -916,6 +892,7 @@ public:
 class BumpNode : public ShaderNode {
 public:
        SHADER_NODE_CLASS(BumpNode)
+       bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, float3 *optimized_value);
        bool has_spatial_varying() { return true; }
        virtual int get_feature() {
                return NODE_FEATURE_BUMP;
index cb3cb8b9b1b49cf7ff2ae0c13c9974d2ab56f885..964ed8db3f77b71158ebc1aed58ae23b1c34c634 100644 (file)
@@ -483,11 +483,11 @@ bool OSLCompiler::node_skip_input(ShaderNode *node, ShaderInput *input)
                if(strcmp(input->name, "Normal") == 0)
                        return true;
        }
-       else if(node->name == ustring("bump")) {
+       else if(node->special_type == SHADER_SPECIAL_TYPE_BUMP) {
                if(strcmp(input->name, "Height") == 0)
                        return true;
        }
-       else if(current_type == SHADER_TYPE_DISPLACEMENT && input->link && input->link->parent->name == ustring("bump"))
+       else if(current_type == SHADER_TYPE_DISPLACEMENT && input->link && input->link->parent->special_type == SHADER_SPECIAL_TYPE_BUMP)
                return true;
 
        return false;
index 09a6061abea8561b4f784835deef3fb3f54fff5b..797f31ce92db345666e8654b258b810935ed8e1c 100644 (file)
@@ -175,7 +175,7 @@ void Shader::set_graph(ShaderGraph *graph_)
         * are needed, since the node attribute callbacks check if their sockets
         * are connected but proxy nodes should not count */
        if(graph_)
-               graph_->remove_unneeded_nodes();
+               graph_->remove_proxy_nodes();
 
        /* assign graph */
        delete graph;
index 56fb57e96672430bdb30db6d58216c81a3f7f773..350ef921bc19dc66ac3f2a0c38c6ef2c409bc112 100644 (file)
@@ -365,7 +365,7 @@ uint SVMCompiler::attribute(AttributeStandard std)
 bool SVMCompiler::node_skip_input(ShaderNode * /*node*/, ShaderInput *input)
 {
        /* nasty exception .. */
-       if(current_type == SHADER_TYPE_DISPLACEMENT && input->link && input->link->parent->name == ustring("bump"))
+       if(current_type == SHADER_TYPE_DISPLACEMENT && input->link && input->link->parent->special_type == SHADER_SPECIAL_TYPE_BUMP)
                return true;
        
        return false;