Changeset View
Standalone View
intern/cycles/render/nodes.cpp
| Show All 23 Lines | |||||
| #include "osl.h" | #include "osl.h" | ||||
| #include "util_sky_model.h" | #include "util_sky_model.h" | ||||
| #include "util_foreach.h" | #include "util_foreach.h" | ||||
| #include "util_transform.h" | #include "util_transform.h" | ||||
| CCL_NAMESPACE_BEGIN | CCL_NAMESPACE_BEGIN | ||||
| /* Constant Folding Helpers */ | |||||
| inline bool fold_as_value(ShaderInput *optimized, float value) | |||||
sergey: Arguably, should it actually be a function or a method of `Graph` / `ShaderNode` /… | |||||
angavrilovUnsubmitted Not Done Inline Actions
Actually, links are removed by the main constant folding function if constant_fold returned true, so at this point there definitely are links. The main function also copies the value to other sibling users from this one ShaderInput that was directly set here. This does feel a bit weird so maybe now there's fold_as_value, it should do all that stuff instead?.. angavrilov: > We might add extra sanity checks there like `assert… | |||||
| { | |||||
| optimized->set(value); | |||||
| return true; | |||||
| } | |||||
| inline bool fold_as_value(ShaderInput *optimized, float3 value) | |||||
| { | |||||
| optimized->set(value); | |||||
| return true; | |||||
| } | |||||
| inline bool fold_as_value_clamp(ShaderInput *optimized, bool use_clamp, float result) | |||||
| { | |||||
| optimized->set(use_clamp ? saturate(result) : result); | |||||
| return true; | |||||
| } | |||||
| inline bool fold_as_value_clamp(ShaderInput *optimized, bool use_clamp, float3 result) | |||||
| { | |||||
| optimized->set(use_clamp ? svm_mix_clamp(result) : result); | |||||
| return true; | |||||
| } | |||||
| inline bool fold_as_noop(ShaderGraph *graph, ShaderNode *node, ShaderInput *input, ShaderOutput *output) | |||||
| { | |||||
| graph->relink(node, output, input->link); | |||||
| return true; | |||||
| } | |||||
| /* Texture Mapping */ | /* Texture Mapping */ | ||||
| #define TEXTURE_MAPPING_DEFINE(TextureNode) \ | #define TEXTURE_MAPPING_DEFINE(TextureNode) \ | ||||
| SOCKET_POINT(tex_mapping.translation, "Translation", make_float3(0.0f, 0.0f, 0.0f)); \ | SOCKET_POINT(tex_mapping.translation, "Translation", make_float3(0.0f, 0.0f, 0.0f)); \ | ||||
| SOCKET_VECTOR(tex_mapping.rotation, "Rotation", make_float3(0.0f, 0.0f, 0.0f)); \ | SOCKET_VECTOR(tex_mapping.rotation, "Rotation", make_float3(0.0f, 0.0f, 0.0f)); \ | ||||
| SOCKET_VECTOR(tex_mapping.scale, "Scale", make_float3(1.0f, 1.0f, 1.0f)); \ | SOCKET_VECTOR(tex_mapping.scale, "Scale", make_float3(1.0f, 1.0f, 1.0f)); \ | ||||
| \ | \ | ||||
| SOCKET_VECTOR(tex_mapping.min, "Min", make_float3(-FLT_MAX, -FLT_MAX, -FLT_MAX)); \ | SOCKET_VECTOR(tex_mapping.min, "Min", make_float3(-FLT_MAX, -FLT_MAX, -FLT_MAX)); \ | ||||
| ▲ Show 20 Lines • Show All 1,534 Lines • ▼ Show 20 Lines | |||||
| RGBToBWNode::RGBToBWNode() | RGBToBWNode::RGBToBWNode() | ||||
| : ShaderNode(node_type) | : ShaderNode(node_type) | ||||
| { | { | ||||
| } | } | ||||
| bool RGBToBWNode::constant_fold(ShaderGraph *, ShaderOutput *, ShaderInput *optimized) | bool RGBToBWNode::constant_fold(ShaderGraph *, ShaderOutput *, ShaderInput *optimized) | ||||
| { | { | ||||
| if(all_inputs_constant()) { | if(all_inputs_constant()) { | ||||
| optimized->set(linear_rgb_to_gray(color)); | return fold_as_value(optimized, linear_rgb_to_gray(color)); | ||||
| return true; | |||||
| } | } | ||||
Not Done Inline ActionsIs it a nifty way to save one line of code with a searate return? Feel weird about reutning a void value. And either having memory glitch, or some compilers might generate warning? sergey: Is it a nifty way to save one line of code with a searate return?
Feel weird about reutning a… | |||||
Not Done Inline ActionsIt's valid C++, but since it's causing confusion I'll change it. brecht: It's valid C++, but since it's causing confusion I'll change it. | |||||
Not Done Inline ActionsInteresting. Coz i remember having issues with such (or similar but more tricky?) case. If it's valid, i'm not fussed at all. But code after changes i like more, since it leaves no room to confusion. sergey: Interesting. Coz i remember having issues with such (or similar but more tricky?) case.
If… | |||||
| return false; | return false; | ||||
| } | } | ||||
| void RGBToBWNode::compile(SVMCompiler& compiler) | void RGBToBWNode::compile(SVMCompiler& compiler) | ||||
| { | { | ||||
| compiler.add_node(NODE_CONVERT, | compiler.add_node(NODE_CONVERT, | ||||
| NODE_CONVERT_CF, | NODE_CONVERT_CF, | ||||
| ▲ Show 20 Lines • Show All 73 Lines • ▼ Show 20 Lines | bool ConvertNode::constant_fold(ShaderGraph *, ShaderOutput *, ShaderInput *optimized) | ||||
| /* proxy nodes should have been removed at this point */ | /* proxy nodes should have been removed at this point */ | ||||
| assert(special_type != SHADER_SPECIAL_TYPE_PROXY); | assert(special_type != SHADER_SPECIAL_TYPE_PROXY); | ||||
| /* TODO(DingTo): conversion from/to int is not supported yet, don't fold in that case */ | /* TODO(DingTo): conversion from/to int is not supported yet, don't fold in that case */ | ||||
| if(all_inputs_constant()) { | if(all_inputs_constant()) { | ||||
| if(from == SocketType::FLOAT) { | if(from == SocketType::FLOAT) { | ||||
| if(SocketType::is_float3(to)) { | if(SocketType::is_float3(to)) { | ||||
| optimized->set(make_float3(value_float, value_float, value_float)); | return fold_as_value(optimized, make_float3(value_float, value_float, value_float)); | ||||
| return true; | |||||
| } | } | ||||
| } | } | ||||
| else if(SocketType::is_float3(from)) { | else if(SocketType::is_float3(from)) { | ||||
| if(to == SocketType::FLOAT) { | if(to == SocketType::FLOAT) { | ||||
| if(from == SocketType::COLOR) | if(from == SocketType::COLOR) { | ||||
| /* color to float */ | /* color to float */ | ||||
| optimized->set(linear_rgb_to_gray(value_color)); | return fold_as_value(optimized, linear_rgb_to_gray(value_color)); | ||||
| else | } | ||||
| else { | |||||
| /* vector/point/normal to float */ | /* vector/point/normal to float */ | ||||
| optimized->set(average(value_vector)); | return fold_as_value(optimized, average(value_vector)); | ||||
| return true; | } | ||||
| } | } | ||||
| else if(SocketType::is_float3(to)) { | else if(SocketType::is_float3(to)) { | ||||
| optimized->set(value_color); | return fold_as_value(optimized, value_color); | ||||
| return true; | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| return false; | return false; | ||||
| } | } | ||||
| void ConvertNode::compile(SVMCompiler& compiler) | void ConvertNode::compile(SVMCompiler& compiler) | ||||
| ▲ Show 20 Lines • Show All 1,803 Lines • ▼ Show 20 Lines | |||||
| bool MixClosureNode::constant_fold(ShaderGraph *graph, ShaderOutput *, ShaderInput *) | bool MixClosureNode::constant_fold(ShaderGraph *graph, ShaderOutput *, ShaderInput *) | ||||
| { | { | ||||
| ShaderInput *fac_in = input("Fac"); | ShaderInput *fac_in = input("Fac"); | ||||
| ShaderInput *closure1_in = input("Closure1"); | ShaderInput *closure1_in = input("Closure1"); | ||||
| ShaderInput *closure2_in = input("Closure2"); | ShaderInput *closure2_in = input("Closure2"); | ||||
| ShaderOutput *closure_out = output("Closure"); | ShaderOutput *closure_out = output("Closure"); | ||||
| /* remove useless mix closures nodes */ | /* remove useless mix closures nodes */ | ||||
| if(closure1_in->link == closure2_in->link) { | if(closure1_in->link && closure1_in->link == closure2_in->link) { | ||||
| graph->relink(this, closure_out, closure1_in->link); | return fold_as_noop(graph, this, closure1_in, closure_out); | ||||
| return true; | |||||
| } | } | ||||
| /* remove unused mix closure input when factor is 0.0 or 1.0 */ | /* remove unused mix closure input when factor is 0.0 or 1.0 */ | ||||
| /* check for closure links and make sure factor link is disconnected */ | /* check for closure links and make sure factor link is disconnected */ | ||||
| if(closure1_in->link && closure2_in->link && !fac_in->link) { | if(closure1_in->link && closure2_in->link && !fac_in->link) { | ||||
| /* factor 0.0 */ | /* factor 0.0 */ | ||||
| if(fac == 0.0f) { | if(fac <= 0.0f) { | ||||
| graph->relink(this, closure_out, closure1_in->link); | return fold_as_noop(graph, this, closure1_in, closure_out); | ||||
| return true; | |||||
| } | } | ||||
| /* factor 1.0 */ | /* factor 1.0 */ | ||||
| else if(fac == 1.0f) { | else if(fac >= 1.0f) { | ||||
| graph->relink(this, closure_out, closure2_in->link); | return fold_as_noop(graph, this, closure2_in, closure_out); | ||||
| return true; | |||||
| } | } | ||||
| } | } | ||||
| return false; | return false; | ||||
| } | } | ||||
| /* Mix Closure */ | /* Mix Closure */ | ||||
| ▲ Show 20 Lines • Show All 58 Lines • ▼ Show 20 Lines | |||||
| { | { | ||||
| ShaderInput *fac_in = input("Fac"); | ShaderInput *fac_in = input("Fac"); | ||||
| ShaderInput *color_in = input("Color"); | ShaderInput *color_in = input("Color"); | ||||
| ShaderOutput *color_out = output("Color"); | ShaderOutput *color_out = output("Color"); | ||||
| if(!fac_in->link) { | if(!fac_in->link) { | ||||
| /* evaluate fully constant node */ | /* evaluate fully constant node */ | ||||
| if(!color_in->link) { | if(!color_in->link) { | ||||
| optimized->set(interp(color, make_float3(1.0f, 1.0f, 1.0f) - color, fac)); | float3 result = interp(color, make_float3(1.0f, 1.0f, 1.0f) - color, fac); | ||||
| return true; | return fold_as_value(optimized, result); | ||||
| } | } | ||||
| /* remove no-op node */ | /* remove no-op node */ | ||||
| else if(fac == 0.0f) { | else if(fac == 0.0f) { | ||||
| graph->relink(this, color_out, color_in->link); | return fold_as_noop(graph, this, color_in, color_out); | ||||
| return true; | |||||
| } | } | ||||
| } | } | ||||
| return false; | return false; | ||||
| } | } | ||||
| void InvertNode::compile(SVMCompiler& compiler) | void InvertNode::compile(SVMCompiler& compiler) | ||||
| { | { | ||||
| ▲ Show 20 Lines • Show All 76 Lines • ▼ Show 20 Lines | |||||
| void MixNode::compile(OSLCompiler& compiler) | void MixNode::compile(OSLCompiler& compiler) | ||||
| { | { | ||||
| compiler.parameter(this, "type"); | compiler.parameter(this, "type"); | ||||
| compiler.parameter(this, "use_clamp"); | compiler.parameter(this, "use_clamp"); | ||||
| compiler.add(this, "node_mix"); | compiler.add(this, "node_mix"); | ||||
| } | } | ||||
| bool MixNode::try_fold_as_noop(ShaderGraph *graph, ShaderInput *input, float3 input_value, ShaderInput *optimized) | |||||
| { | |||||
| if(!input->link) { | |||||
| return fold_as_value_clamp(optimized, use_clamp, input_value); | |||||
| } | |||||
| else if(!use_clamp) { | |||||
| return fold_as_noop(graph, this, input, output("Color")); | |||||
| } | |||||
| return false; | |||||
| } | |||||
| bool MixNode::constant_fold(ShaderGraph *graph, ShaderOutput *, ShaderInput *optimized) | bool MixNode::constant_fold(ShaderGraph *graph, ShaderOutput *, ShaderInput *optimized) | ||||
| { | { | ||||
| ShaderInput *fac_in = input("Fac"); | ShaderInput *fac_in = input("Fac"); | ||||
| ShaderInput *color1_in = input("Color1"); | ShaderInput *color1_in = input("Color1"); | ||||
| ShaderInput *color2_in = input("Color2"); | ShaderInput *color2_in = input("Color2"); | ||||
| ShaderOutput *color_out = output("Color"); | |||||
| /* evaluate fully constant node */ | /* evaluate fully constant node */ | ||||
| if(all_inputs_constant()) { | if(all_inputs_constant()) { | ||||
| float3 result = svm_mix(type, fac, color1, color2); | return fold_as_value_clamp(optimized, use_clamp, svm_mix(type, fac, color1, color2)); | ||||
| optimized->set(use_clamp ? svm_mix_clamp(result) : result); | |||||
| return true; | |||||
| } | } | ||||
| /* remove no-op node when factor is 0.0 */ | /* remove no-op node when factor is 0.0 */ | ||||
| if(!fac_in->link && fac <= 0.0f) { | if(!fac_in->link && fac <= 0.0f) { | ||||
| /* note that some of the modes will clamp out of bounds values even without use_clamp */ | /* note that some of the modes will clamp out of bounds values even without use_clamp */ | ||||
| if(type == NODE_MIX_LIGHT || type == NODE_MIX_DODGE || type == NODE_MIX_BURN) { | |||||
| if(!color1_in->link) { | if(!color1_in->link) { | ||||
| float3 result = svm_mix(type, 0.0f, color1, color1); | return fold_as_value_clamp(optimized, use_clamp, svm_mix(type, 0.0f, color1, color1)); | ||||
| optimized->set(use_clamp ? svm_mix_clamp(result) : result); | |||||
| return true; | |||||
| } | |||||
| else if(!use_clamp && type != NODE_MIX_LIGHT && type != NODE_MIX_DODGE && type != NODE_MIX_BURN) { | |||||
| graph->relink(this, color_out, color1_in->link); | |||||
| return true; | |||||
| } | } | ||||
| } | } | ||||
| else if(try_fold_as_noop(graph, color1_in, color1, optimized)) | |||||
| if(type != NODE_MIX_BLEND) { | return true; | ||||
| return false; | |||||
| } | } | ||||
| if(type == NODE_MIX_BLEND) { | |||||
| /* remove useless mix colors nodes */ | /* remove useless mix colors nodes */ | ||||
| if(color1_in->link && color1_in->link == color2_in->link && !use_clamp) { | if(color1_in->link ? (color1_in->link == color2_in->link) : (!color2_in->link && color1 == color2)) { | ||||
| graph->relink(this, color_out, color1_in->link); | if(try_fold_as_noop(graph, color1_in, color1, optimized)) | ||||
| return true; | |||||
| } | |||||
| if(!color1_in->link && !color2_in->link && color1 == color2) { | |||||
| optimized->set(use_clamp ? svm_mix_clamp(color1) : color1); | |||||
| return true; | return true; | ||||
| } | } | ||||
| /* remove no-op mix color node when factor is 1.0 */ | /* remove no-op mix color node when factor is 1.0 */ | ||||
| if(!fac_in->link && fac >= 1.0f) { | if(!fac_in->link && fac >= 1.0f) { | ||||
| if(!color2_in->link) { | if(try_fold_as_noop(graph, color2_in, color2, optimized)) | ||||
| optimized->set(use_clamp ? svm_mix_clamp(color2) : color2); | |||||
| return true; | |||||
| } | |||||
| else if(!use_clamp) { | |||||
| graph->relink(this, color_out, color2_in->link); | |||||
| return true; | return true; | ||||
| } | } | ||||
| } | } | ||||
| return false; | return false; | ||||
| } | } | ||||
| /* Combine RGB */ | /* Combine RGB */ | ||||
| Show All 13 Lines | |||||
| CombineRGBNode::CombineRGBNode() | CombineRGBNode::CombineRGBNode() | ||||
| : ShaderNode(node_type) | : ShaderNode(node_type) | ||||
| { | { | ||||
| } | } | ||||
| bool CombineRGBNode::constant_fold(ShaderGraph *, ShaderOutput *, ShaderInput *optimized) | bool CombineRGBNode::constant_fold(ShaderGraph *, ShaderOutput *, ShaderInput *optimized) | ||||
| { | { | ||||
| if(all_inputs_constant()) { | if(all_inputs_constant()) { | ||||
| optimized->set(make_float3(r, g, b)); | return fold_as_value(optimized, make_float3(r, g, b)); | ||||
| return true; | |||||
| } | } | ||||
| return false; | return false; | ||||
| } | } | ||||
| void CombineRGBNode::compile(SVMCompiler& compiler) | void CombineRGBNode::compile(SVMCompiler& compiler) | ||||
| { | { | ||||
| ShaderInput *red_in = input("R"); | ShaderInput *red_in = input("R"); | ||||
| Show All 37 Lines | |||||
| CombineXYZNode::CombineXYZNode() | CombineXYZNode::CombineXYZNode() | ||||
| : ShaderNode(node_type) | : ShaderNode(node_type) | ||||
| { | { | ||||
| } | } | ||||
| bool CombineXYZNode::constant_fold(ShaderGraph *, ShaderOutput *, ShaderInput *optimized) | bool CombineXYZNode::constant_fold(ShaderGraph *, ShaderOutput *, ShaderInput *optimized) | ||||
| { | { | ||||
| if(all_inputs_constant()) { | if(all_inputs_constant()) { | ||||
| optimized->set(make_float3(x, y, z)); | return fold_as_value(optimized, make_float3(x, y, z)); | ||||
| return true; | |||||
| } | } | ||||
| return false; | return false; | ||||
| } | } | ||||
| void CombineXYZNode::compile(SVMCompiler& compiler) | void CombineXYZNode::compile(SVMCompiler& compiler) | ||||
| { | { | ||||
| ShaderInput *x_in = input("X"); | ShaderInput *x_in = input("X"); | ||||
| Show All 37 Lines | |||||
| CombineHSVNode::CombineHSVNode() | CombineHSVNode::CombineHSVNode() | ||||
| : ShaderNode(node_type) | : ShaderNode(node_type) | ||||
| { | { | ||||
| } | } | ||||
| bool CombineHSVNode::constant_fold(ShaderGraph *, ShaderOutput *, ShaderInput *optimized) | bool CombineHSVNode::constant_fold(ShaderGraph *, ShaderOutput *, ShaderInput *optimized) | ||||
| { | { | ||||
| if(all_inputs_constant()) { | if(all_inputs_constant()) { | ||||
| optimized->set(hsv_to_rgb(make_float3(h, s, v))); | return fold_as_value(optimized, hsv_to_rgb(make_float3(h, s, v))); | ||||
| return true; | |||||
| } | } | ||||
| return false; | return false; | ||||
| } | } | ||||
| void CombineHSVNode::compile(SVMCompiler& compiler) | void CombineHSVNode::compile(SVMCompiler& compiler) | ||||
| { | { | ||||
| ShaderInput *hue_in = input("H"); | ShaderInput *hue_in = input("H"); | ||||
| Show All 30 Lines | |||||
| GammaNode::GammaNode() | GammaNode::GammaNode() | ||||
| : ShaderNode(node_type) | : ShaderNode(node_type) | ||||
| { | { | ||||
| } | } | ||||
| bool GammaNode::constant_fold(ShaderGraph *, ShaderOutput *, ShaderInput *optimized) | bool GammaNode::constant_fold(ShaderGraph *, ShaderOutput *, ShaderInput *optimized) | ||||
| { | { | ||||
| if(all_inputs_constant()) { | if(all_inputs_constant()) { | ||||
| optimized->set(svm_math_gamma_color(color, gamma)); | return fold_as_value(optimized, svm_math_gamma_color(color, gamma)); | ||||
| return true; | |||||
| } | } | ||||
| return false; | return false; | ||||
| } | } | ||||
| void GammaNode::compile(SVMCompiler& compiler) | void GammaNode::compile(SVMCompiler& compiler) | ||||
| { | { | ||||
| ShaderInput *color_in = input("Color"); | ShaderInput *color_in = input("Color"); | ||||
| Show All 29 Lines | |||||
| BrightContrastNode::BrightContrastNode() | BrightContrastNode::BrightContrastNode() | ||||
| : ShaderNode(node_type) | : ShaderNode(node_type) | ||||
| { | { | ||||
| } | } | ||||
| bool BrightContrastNode::constant_fold(ShaderGraph *, ShaderOutput *, ShaderInput *optimized) | bool BrightContrastNode::constant_fold(ShaderGraph *, ShaderOutput *, ShaderInput *optimized) | ||||
| { | { | ||||
| if(all_inputs_constant()) { | if(all_inputs_constant()) { | ||||
| optimized->set(svm_brightness_contrast(color, bright, contrast)); | return fold_as_value(optimized, svm_brightness_contrast(color, bright, contrast)); | ||||
| return true; | |||||
| } | } | ||||
| return false; | return false; | ||||
| } | } | ||||
| void BrightContrastNode::compile(SVMCompiler& compiler) | void BrightContrastNode::compile(SVMCompiler& compiler) | ||||
| { | { | ||||
| ShaderInput *color_in = input("Color"); | ShaderInput *color_in = input("Color"); | ||||
| Show All 34 Lines | |||||
| { | { | ||||
| } | } | ||||
| bool SeparateRGBNode::constant_fold(ShaderGraph *, ShaderOutput *socket, ShaderInput *optimized) | bool SeparateRGBNode::constant_fold(ShaderGraph *, ShaderOutput *socket, ShaderInput *optimized) | ||||
| { | { | ||||
| if(all_inputs_constant()) { | if(all_inputs_constant()) { | ||||
| for(int channel = 0; channel < 3; channel++) { | for(int channel = 0; channel < 3; channel++) { | ||||
| if(outputs[channel] == socket) { | if(outputs[channel] == socket) { | ||||
| optimized->set(color[channel]); | return fold_as_value(optimized, color[channel]); | ||||
| return true; | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| return false; | return false; | ||||
| } | } | ||||
| void SeparateRGBNode::compile(SVMCompiler& compiler) | void SeparateRGBNode::compile(SVMCompiler& compiler) | ||||
| ▲ Show 20 Lines • Show All 41 Lines • ▼ Show 20 Lines | |||||
| { | { | ||||
| } | } | ||||
| bool SeparateXYZNode::constant_fold(ShaderGraph *, ShaderOutput *socket, ShaderInput *optimized) | bool SeparateXYZNode::constant_fold(ShaderGraph *, ShaderOutput *socket, ShaderInput *optimized) | ||||
| { | { | ||||
| if(all_inputs_constant()) { | if(all_inputs_constant()) { | ||||
| for(int channel = 0; channel < 3; channel++) { | for(int channel = 0; channel < 3; channel++) { | ||||
| if(outputs[channel] == socket) { | if(outputs[channel] == socket) { | ||||
| optimized->set(vector[channel]); | return fold_as_value(optimized, vector[channel]); | ||||
| return true; | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| return false; | return false; | ||||
| } | } | ||||
| void SeparateXYZNode::compile(SVMCompiler& compiler) | void SeparateXYZNode::compile(SVMCompiler& compiler) | ||||
| ▲ Show 20 Lines • Show All 43 Lines • ▼ Show 20 Lines | |||||
| bool SeparateHSVNode::constant_fold(ShaderGraph *, ShaderOutput *socket, ShaderInput *optimized) | bool SeparateHSVNode::constant_fold(ShaderGraph *, ShaderOutput *socket, ShaderInput *optimized) | ||||
| { | { | ||||
| if(all_inputs_constant()) { | if(all_inputs_constant()) { | ||||
| float3 hsv = rgb_to_hsv(color); | float3 hsv = rgb_to_hsv(color); | ||||
| for(int channel = 0; channel < 3; channel++) { | for(int channel = 0; channel < 3; channel++) { | ||||
| if(outputs[channel] == socket) { | if(outputs[channel] == socket) { | ||||
| optimized->set(hsv[channel]); | return fold_as_value(optimized, hsv[channel]); | ||||
| return true; | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| return false; | return false; | ||||
| } | } | ||||
| void SeparateHSVNode::compile(SVMCompiler& compiler) | void SeparateHSVNode::compile(SVMCompiler& compiler) | ||||
| ▲ Show 20 Lines • Show All 377 Lines • ▼ Show 20 Lines | |||||
| BlackbodyNode::BlackbodyNode() | BlackbodyNode::BlackbodyNode() | ||||
| : ShaderNode(node_type) | : ShaderNode(node_type) | ||||
| { | { | ||||
| } | } | ||||
| bool BlackbodyNode::constant_fold(ShaderGraph *, ShaderOutput *, ShaderInput *optimized) | bool BlackbodyNode::constant_fold(ShaderGraph *, ShaderOutput *, ShaderInput *optimized) | ||||
| { | { | ||||
| if(all_inputs_constant()) { | if(all_inputs_constant()) { | ||||
| optimized->set(svm_math_blackbody_color(temperature)); | return fold_as_value(optimized, svm_math_blackbody_color(temperature)); | ||||
| return true; | |||||
| } | } | ||||
| return false; | return false; | ||||
| } | } | ||||
| void BlackbodyNode::compile(SVMCompiler& compiler) | void BlackbodyNode::compile(SVMCompiler& compiler) | ||||
| { | { | ||||
| ShaderInput *temperature_in = input("Temperature"); | ShaderInput *temperature_in = input("Temperature"); | ||||
| ▲ Show 20 Lines • Show All 91 Lines • ▼ Show 20 Lines | |||||
| MathNode::MathNode() | MathNode::MathNode() | ||||
| : ShaderNode(node_type) | : ShaderNode(node_type) | ||||
| { | { | ||||
| } | } | ||||
| bool MathNode::constant_fold(ShaderGraph *, ShaderOutput *, ShaderInput *optimized) | bool MathNode::constant_fold(ShaderGraph *, ShaderOutput *, ShaderInput *optimized) | ||||
| { | { | ||||
| if(all_inputs_constant()) { | if(all_inputs_constant()) { | ||||
| float value = svm_math(type, value1, value2); | return fold_as_value_clamp(optimized, use_clamp, svm_math(type, value1, value2)); | ||||
| optimized->set(use_clamp ? saturate(value) : value); | |||||
| return true; | |||||
| } | } | ||||
| return false; | return false; | ||||
| } | } | ||||
| void MathNode::compile(SVMCompiler& compiler) | void MathNode::compile(SVMCompiler& compiler) | ||||
| { | { | ||||
| ShaderInput *value1_in = input("Value1"); | ShaderInput *value1_in = input("Value1"); | ||||
| ▲ Show 20 Lines • Show All 53 Lines • ▼ Show 20 Lines | bool VectorMathNode::constant_fold(ShaderGraph *, ShaderOutput *socket, ShaderInput *optimized) | ||||
| if(all_inputs_constant()) { | if(all_inputs_constant()) { | ||||
| svm_vector_math(&value, | svm_vector_math(&value, | ||||
| &vector, | &vector, | ||||
| type, | type, | ||||
| vector1, | vector1, | ||||
| vector2); | vector2); | ||||
| if(socket == output("Value")) { | if(socket == output("Value")) { | ||||
| optimized->set(value); | return fold_as_value(optimized, value); | ||||
| return true; | |||||
| } | } | ||||
| else if(socket == output("Vector")) { | else if(socket == output("Vector")) { | ||||
| optimized->set(vector); | return fold_as_value(optimized, vector); | ||||
| return true; | |||||
| } | } | ||||
| } | } | ||||
| return false; | return false; | ||||
| } | } | ||||
| void VectorMathNode::compile(SVMCompiler& compiler) | void VectorMathNode::compile(SVMCompiler& compiler) | ||||
| { | { | ||||
| ▲ Show 20 Lines • Show All 131 Lines • ▼ Show 20 Lines | bool BumpNode::constant_fold(ShaderGraph *graph, ShaderOutput *, ShaderInput *) | ||||
| ShaderInput *height_in = input("Height"); | ShaderInput *height_in = input("Height"); | ||||
| ShaderInput *normal_in = input("Normal"); | ShaderInput *normal_in = input("Normal"); | ||||
| if(height_in->link == NULL) { | if(height_in->link == NULL) { | ||||
| if(normal_in->link == NULL) { | if(normal_in->link == NULL) { | ||||
| GeometryNode *geom = new GeometryNode(); | GeometryNode *geom = new GeometryNode(); | ||||
| graph->add(geom); | graph->add(geom); | ||||
| graph->relink(this, outputs[0], geom->output("Normal")); | graph->relink(this, outputs[0], geom->output("Normal")); | ||||
| return true; | |||||
| } | } | ||||
| else { | else { | ||||
| graph->relink(this, outputs[0], normal_in->link); | return fold_as_noop(graph, this, normal_in, outputs[0]); | ||||
| } | } | ||||
| return true; | |||||
| } | } | ||||
| /* TODO(sergey): Ignore bump with zero strength. */ | /* TODO(sergey): Ignore bump with zero strength. */ | ||||
| return false; | return false; | ||||
| } | } | ||||
| ▲ Show 20 Lines • Show All 441 Lines • Show Last 20 Lines | |||||
Arguably, should it actually be a function or a method of Graph / ShaderNode / ShaderInput?
For now functions will work fine, but making it a method can save us passing some arguments perhaps. Just thinking we can have:
And things like that. We might add extra sanity checks there like assert(there_is_no_connected_links_to_this_input);.
Just an idea which we can do later if this new approach is accepted by everyone.