Blender V5.0
node_item.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2011-2022 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
5#include "node_item.h"
6#include "node_graph.h"
7#include "node_parser.h"
8
9#include "BLI_assert.h"
10#include "BLI_utildefines.h"
11
13
14NodeItem::NodeItem(MaterialX::GraphElement *graph) : graph_(graph) {}
15
16NodeItem::Type NodeItem::type(const std::string &type_str)
17{
18 /* Converting only MaterialX supported types */
19 if (type_str == "multioutput") {
20 return Type::Multioutput;
21 }
22 if (type_str == "string") {
23 return Type::String;
24 }
25 if (type_str == "filename") {
26 return Type::Filename;
27 }
28 if (type_str == "boolean") {
29 return Type::Boolean;
30 }
31 if (type_str == "integer") {
32 return Type::Integer;
33 }
34 if (type_str == "float") {
35 return Type::Float;
36 }
37 if (type_str == "vector2") {
38 return Type::Vector2;
39 }
40 if (type_str == "vector3") {
41 return Type::Vector3;
42 }
43 if (type_str == "vector4") {
44 return Type::Vector4;
45 }
46 if (type_str == "color3") {
47 return Type::Color3;
48 }
49 if (type_str == "color4") {
50 return Type::Color4;
51 }
52 if (type_str == "BSDF") {
53 return Type::BSDF;
54 }
55 if (type_str == "EDF") {
56 return Type::EDF;
57 }
58 if (type_str == "displacementshader") {
60 }
61 if (type_str == "surfaceshader") {
63 }
64 if (type_str == "material") {
65 return Type::Material;
66 }
68 return Type::Empty;
69}
70
72{
73 switch (type) {
74 case Type::Any:
75 return "any";
77 return "multioutput";
78 case Type::String:
79 return "string";
80 case Type::Filename:
81 return "filename";
82 case Type::Boolean:
83 return "boolean";
84 case Type::Integer:
85 return "integer";
86 case Type::Float:
87 return "float";
88 case Type::Vector2:
89 return "vector2";
90 case Type::Vector3:
91 return "vector3";
92 case Type::Vector4:
93 return "vector4";
94 case Type::Color3:
95 return "color3";
96 case Type::Color4:
97 return "color4";
98 case Type::BSDF:
99 return "BSDF";
100 case Type::EDF:
101 return "EDF";
103 return "displacementshader";
105 return "surfaceshader";
106 case Type::Material:
107 return "material";
109 return "opacity";
110 default:
112 }
113 return "";
114}
115
117{
118 return type >= Type::Float && type <= Type::Color4;
119}
120
121NodeItem::operator bool() const
122{
123 return value || node || input || output;
124}
125
127{
128 Type type = this->type();
129 if (ELEM(type, Type::BSDF, Type::EDF)) {
130 /* Special case: add BSDF/EDF shaders */
131 NodeItem res = empty();
132 if (other.type() == type) {
133 res = create_node("add", type, {{"in1", *this}, {"in2", other}});
134 }
135 else {
137 }
138 return res;
139 }
140
141 return arithmetic(other, "add", [](float a, float b) { return a + b; });
142}
143
145{
146 return arithmetic(other, "subtract", [](float a, float b) { return a - b; });
147}
148
150{
151 return val(0.0f) - *this;
152}
153
155{
156 Type type = this->type();
157 if (ELEM(type, Type::BSDF, Type::EDF)) {
158 /* Special case: multiple BSDF/EDF shader by Float or Color3 */
159 NodeItem res = empty();
160 Type other_type = other.type();
161 if (ELEM(other_type, Type::Float, Type::Color3)) {
162 res = create_node("multiply", type, {{"in1", *this}, {"in2", other}});
163 }
164 else {
166 }
167 return res;
168 }
169
170 return arithmetic(other, "multiply", [](float a, float b) { return a * b; });
171}
172
174{
175 return arithmetic(other, "divide", [](float a, float b) { return b == 0.0f ? 0.0f : a / b; });
176}
177
179{
180 return arithmetic(
181 other, "modulo", [](float a, float b) { return b == 0.0f ? 0.0f : std::fmod(a, b); });
182}
183
185{
186 return arithmetic(other, "power", [](float a, float b) { return std::pow(a, b); });
187}
188
190{
192
193 if (value) {
194 float v = 0.0f;
195 switch (type()) {
196 case Type::Float:
197 v = value->asA<float>();
198 break;
199 case Type::Vector2:
200 v = value->asA<MaterialX::Vector2>()[index];
201 break;
202 case Type::Vector3:
203 v = value->asA<MaterialX::Vector3>()[index];
204 break;
205 case Type::Vector4:
206 v = value->asA<MaterialX::Vector4>()[index];
207 break;
208 case Type::Color3:
209 v = value->asA<MaterialX::Color3>()[index];
210 break;
211 case Type::Color4:
212 v = value->asA<MaterialX::Color4>()[index];
213 break;
214 default:
216 }
217 return val(v);
218 }
219 return create_node("extract", Type::Float, {{"in", *this}, {"index", val(index)}});
220}
221
222bool NodeItem::operator==(const NodeItem &other) const
223{
224 if (!*this) {
225 return !other;
226 }
227 if (!other) {
228 return !*this;
229 }
230 if (node && node == other.node) {
231 return true;
232 }
233 if ((node && other.value) || (value && other.node)) {
234 return false;
235 }
236
237 NodeItem item1 = *this;
238 NodeItem item2 = other;
239 Type to_type = cast_types(item1, item2);
240 if (to_type == Type::Empty) {
241 return false;
242 }
243 return item1.value->getValueString() == item2.value->getValueString();
244}
245
246bool NodeItem::operator!=(const NodeItem &other) const
247{
248 return !(*this == other);
249}
250
252{
253 return arithmetic("absval", [](float a) { return std::abs(a); });
254}
255
257{
258 return arithmetic("floor", [](float a) { return std::floor(a); });
259}
260
262{
263 return arithmetic("ceil", [](float a) { return std::ceil(a); });
264}
265
267{
268 if (value) {
269 return dotproduct(*this).sqrt();
270 }
271 return create_node("magnitude", Type::Float, {{"in", to_vector()}});
272}
273
275{
276 if (value) {
277 return *this / length();
278 }
279 return create_node("normalize", Type::Vector3, {{"in", to_vector()}});
280}
281
282NodeItem NodeItem::min(const NodeItem &other) const
283{
284 return arithmetic(other, "min", [](float a, float b) { return std::min(a, b); });
285}
286
287NodeItem NodeItem::max(const NodeItem &other) const
288{
289 return arithmetic(other, "max", [](float a, float b) { return std::max(a, b); });
290}
291
293{
294 if (value && other.value) {
295 NodeItem d = *this * other;
296 float f = 0.0f;
297 switch (d.type()) {
298 case Type::Float: {
299 f = d.value->asA<float>();
300 break;
301 }
302 case Type::Vector2: {
303 auto v = d.value->asA<MaterialX::Vector2>();
304 f = v[0] + v[1];
305 break;
306 }
307 case Type::Vector3: {
308 auto v = d.value->asA<MaterialX::Vector3>();
309 f = v[0] + v[1] + v[2];
310 break;
311 }
312 case Type::Vector4: {
313 auto v = d.value->asA<MaterialX::Vector4>();
314 f = v[0] + v[1] + v[2] + v[3];
315 break;
316 }
317 case Type::Color3: {
318 auto v = d.value->asA<MaterialX::Color3>();
319 f = v[0] + v[1] + v[2];
320 break;
321 }
322 case Type::Color4: {
323 auto v = d.value->asA<MaterialX::Color4>();
324 f = v[0] + v[1] + v[2] + v[3];
325 break;
326 }
327 default:
329 }
330 return val(f);
331 }
332
333 NodeItem item1 = to_vector();
334 NodeItem item2 = other.to_vector();
335 cast_types(item1, item2);
336 return create_node("dotproduct", Type::Float, {{"in1", item1}, {"in2", item2}});
337}
338
339NodeItem NodeItem::mix(const NodeItem &val1, const NodeItem &val2) const
340{
341 if ((value && val1.value && val2.value) || type() != Type::Float) {
342 return (val(1.0f) - *this) * val1 + *this * val2;
343 }
344
345 Type type1 = val1.type();
346 if (ELEM(type1, Type::BSDF, Type::EDF)) {
347 BLI_assert(val2.type() == type1);
348
349 /* Special case: mix BSDF/EDF shaders */
350 return create_node("mix", type1, {{"bg", val1}, {"fg", val2}, {"mix", *this}});
351 };
352
353 NodeItem item1 = val1;
354 NodeItem item2 = val2;
355 Type to_type = cast_types(item1, item2);
356 return create_node("mix", to_type, {{"bg", item1}, {"fg", item2}, {"mix", *this}});
357}
358
359NodeItem NodeItem::clamp(const NodeItem &min_val, const NodeItem &max_val) const
360{
361 if (value && min_val.value && max_val.value) {
362 return min(max_val).max(min_val);
363 }
364
365 if (min_val.type() == Type::Float && max_val.type() == Type::Float) {
366 return create_node("clamp", type(), {{"in", *this}, {"low", min_val}, {"high", max_val}});
367 }
368
369 Type type = this->type();
370 return create_node(
371 "clamp",
372 type,
373 {{"in", *this}, {"low", min_val.convert(type)}, {"high", max_val.convert(type)}});
374}
375
376NodeItem NodeItem::clamp(float min_val, float max_val) const
377{
378 return clamp(val(min_val), val(max_val));
379}
380
382{
384 BLI_assert(angle.type() == Type::Float);
385 BLI_assert(axis.type() == Type::Vector3);
386
387 return create_node(
388 "rotate3d", NodeItem::Type::Vector3, {{"in", *this}, {"amount", angle}, {"axis", axis}});
389}
390
392{
393 NodeItem x = angle_xyz[0];
394 NodeItem y = angle_xyz[1];
395 NodeItem z = angle_xyz[2];
396
397 NodeItem x_axis = val(MaterialX::Vector3(1.0f, 0.0f, 0.0f));
398 NodeItem y_axis = val(MaterialX::Vector3(0.0f, 1.0f, 0.0f));
399 NodeItem z_axis = val(MaterialX::Vector3(0.0f, 0.0f, 1.0f));
400
401 if (invert) {
402 return rotate(z, z_axis).rotate(y, y_axis).rotate(x, x_axis);
403 }
404 return rotate(x, x_axis).rotate(y, y_axis).rotate(z, z_axis);
405}
406
408{
409 return to_vector().arithmetic("sin", [](float a) { return std::sin(a); });
410}
411
413{
414 return to_vector().arithmetic("cos", [](float a) { return std::cos(a); });
415}
416
418{
419 return to_vector().arithmetic("tan", [](float a) { return std::tan(a); });
420}
421
423{
424 return to_vector().arithmetic("asin", [](float a) { return std::asin(a); });
425}
426
428{
429 return to_vector().arithmetic("acos", [](float a) { return std::acos(a); });
430}
431
433{
434 return to_vector().arithmetic("atan", [](float a) { return std::atan(a); });
435}
436
438{
439 return to_vector().arithmetic(other, "atan2", [](float a, float b) { return std::atan2(a, b); });
440}
441
443{
444 NodeItem v = to_vector();
445 return (v.exp() - (-v).exp()) / val(2.0f);
446}
447
449{
450 NodeItem v = to_vector();
451 return (v.exp() + (-v).exp()) / val(2.0f);
452}
453
455{
456 NodeItem v = to_vector();
457 NodeItem a = v.exp();
458 NodeItem b = (-v).exp();
459 return (a - b) / (a + b);
460}
461
463{
464 return to_vector().arithmetic("ln", [](float a) { return std::log(a); });
465}
466
468{
469 return to_vector().arithmetic("sqrt", [](float a) { return std::sqrt(a); });
470}
471
473{
474 return arithmetic("sign", [](float a) { return a < 0.0f ? -1.0f : (a == 0.0f ? 0.0f : 1.0f); });
475}
476
478{
479 return to_vector().arithmetic("exp", [](float a) { return std::exp(a); });
480}
481
483{
484 switch (to_type) {
485 case Type::Any:
486 return true;
487 case Type::Empty:
489 return false;
490 case Type::String:
491 case Type::Filename:
492 return from_type == SOCK_STRING;
493 case Type::Boolean:
494 return from_type == SOCK_BOOLEAN;
495 case Type::Integer:
496 return from_type == SOCK_INT;
497 case Type::Float:
498 case Type::Vector2:
499 case Type::Vector3:
500 case Type::Color3:
501 case Type::Vector4:
502 case Type::Color4:
504 return ELEM(from_type, SOCK_FLOAT, SOCK_VECTOR, SOCK_RGBA);
505 case Type::EDF:
506 return ELEM(from_type, SOCK_FLOAT, SOCK_VECTOR, SOCK_RGBA, SOCK_SHADER);
507 case Type::BSDF:
509 case Type::Material:
511 return from_type == SOCK_SHADER;
512 }
513
514 return false;
515}
516
518{
519 Type from_type = type();
520 if (from_type == Type::Empty || from_type == to_type || to_type == Type::Any) {
521 return *this;
522 }
523
524 switch (to_type) {
525 /* Link arithmetic types to shader as EDF. */
526 case Type::EDF:
527 if (is_arithmetic(from_type)) {
528 return create_node("uniform_edf", NodeItem::Type::EDF, {{"color", convert(Type::Color3)}});
529 }
530 return empty();
531 /* Displacement shader from arithmetic types, when not using (Vector) Displacement node. */
533 if (is_arithmetic(from_type)) {
534 return create_node("displacement",
536 {{"displacement", convert(Type::Vector3)}});
537 }
538 return empty();
539 /* Surface opacity is just a float. */
542 if (from_type == to_type || to_type == Type::Any) {
543 return *this;
544 }
545 break;
546 /* Material output will evaluate graph multiple times for different components,
547 * when linking arithmetic types we want to leave those empty. */
548 case Type::BSDF:
550 case Type::Material:
551 return empty();
552 default:
553 break;
554 }
555
556 if (!is_arithmetic(from_type) || !is_arithmetic(to_type)) {
558 "Cannot convert: %s -> %s",
559 type(from_type).c_str(),
560 type(to_type).c_str());
561 return empty();
562 }
563
564 if (to_type == Type::Float) {
565 return (*this)[0];
566 }
567
568 /* Converting types which requires > 1 iteration */
569 switch (from_type) {
570 case Type::Vector2:
571 switch (to_type) {
572 case Type::Vector4:
574 case Type::Color3:
576 case Type::Color4:
578 default:
579 break;
580 }
581 break;
582 case Type::Vector3:
583 switch (to_type) {
584 case Type::Color4:
586 default:
587 break;
588 }
589 break;
590 case Type::Vector4:
591 switch (to_type) {
592 case Type::Vector2:
594 case Type::Color3:
596 default:
597 break;
598 }
599 break;
600 case Type::Color3:
601 switch (to_type) {
602 case Type::Vector2:
604 case Type::Vector4:
606 default:
607 break;
608 }
609 break;
610 case Type::Color4:
611 switch (to_type) {
612 case Type::Vector2:
614 case Type::Vector3:
616 default:
617 break;
618 }
619 break;
620 default:
621 break;
622 }
623
624 /* Converting 1 iteration types */
625 NodeItem res = empty();
626 if (value) {
627 switch (from_type) {
628 case Type::Float: {
629 float v = value->asA<float>();
630 switch (to_type) {
631 case Type::Vector2:
632 res.value = MaterialX::Value::createValue<MaterialX::Vector2>({v, v});
633 break;
634 case Type::Vector3:
635 res.value = MaterialX::Value::createValue<MaterialX::Vector3>({v, v, v});
636 break;
637 case Type::Vector4:
638 res.value = MaterialX::Value::createValue<MaterialX::Vector4>({v, v, v, 1.0f});
639 break;
640 case Type::Color3:
641 res.value = MaterialX::Value::createValue<MaterialX::Color3>({v, v, v});
642 break;
643 case Type::Color4:
644 res.value = MaterialX::Value::createValue<MaterialX::Color4>({v, v, v, 1.0f});
645 break;
646 default:
648 }
649 break;
650 }
651 case Type::Vector2: {
652 auto v = value->asA<MaterialX::Vector2>();
653 switch (to_type) {
654 case Type::Vector3:
655 res.value = MaterialX::Value::createValue<MaterialX::Vector3>({v[0], v[1], 0.0f});
656 break;
657 default:
659 }
660 break;
661 }
662 case Type::Vector3: {
663 auto v = value->asA<MaterialX::Vector3>();
664 switch (to_type) {
665 case Type::Vector2:
666 res.value = MaterialX::Value::createValue<MaterialX::Vector2>({v[0], v[1]});
667 break;
668 case Type::Vector4:
669 res.value = MaterialX::Value::createValue<MaterialX::Vector4>(
670 {v[0], v[1], v[2], 0.0f});
671 break;
672 case Type::Color3:
673 res.value = MaterialX::Value::createValue<MaterialX::Color3>({v[0], v[1], v[2]});
674 break;
675 default:
677 }
678 break;
679 }
680 case Type::Vector4: {
681 auto v = value->asA<MaterialX::Vector4>();
682 switch (to_type) {
683 case Type::Vector3:
684 res.value = MaterialX::Value::createValue<MaterialX::Vector3>({v[0], v[1], v[2]});
685 break;
686 case Type::Color4:
687 res.value = MaterialX::Value::createValue<MaterialX::Color4>({v[0], v[1], v[2], v[3]});
688 break;
689 default:
691 }
692 break;
693 }
694 case Type::Color3: {
695 auto v = value->asA<MaterialX::Color3>();
696 switch (to_type) {
697 case Type::Vector3:
698 res.value = MaterialX::Value::createValue<MaterialX::Vector3>({v[0], v[1], v[2]});
699 break;
700 case Type::Color4:
701 res.value = MaterialX::Value::createValue<MaterialX::Color4>({v[0], v[1], v[2], 1.0f});
702 break;
703 default:
705 }
706 break;
707 }
708 case Type::Color4: {
709 auto v = value->asA<MaterialX::Color4>();
710 switch (to_type) {
711 case Type::Vector4:
712 res.value = MaterialX::Value::createValue<MaterialX::Vector4>(
713 {v[0], v[1], v[2], v[3]});
714 break;
715 case Type::Color3:
716 res.value = MaterialX::Value::createValue<MaterialX::Color3>({v[0], v[1], v[2]});
717 break;
718 default:
720 }
721 break;
722 }
723 default:
725 }
726 }
727 else {
728 res = create_node("convert", to_type, {{"in", *this}});
729 }
730 return res;
731}
732
734{
735 switch (type()) {
736 case Type::Float:
737 case Type::Vector2:
738 case Type::Vector3:
739 case Type::Vector4:
740 return *this;
741
742 case Type::Color3:
743 return convert(Type::Vector3);
744
745 case Type::Color4:
746 return convert(Type::Vector4);
747
748 default:
750 }
751 return empty();
752}
753
755 const NodeItem &other,
756 const NodeItem &if_val,
757 const NodeItem &else_val) const
758{
759 switch (op) {
760 case CompareOp::Less:
761 return if_else(CompareOp::GreaterEq, other, else_val, if_val);
763 return if_else(CompareOp::Greater, other, else_val, if_val);
764 case CompareOp::NotEq:
765 return if_else(CompareOp::Eq, other, else_val, if_val);
766 default:
767 break;
768 }
769
770 NodeItem res = empty();
771 if (type() != Type::Float || other.type() != Type::Float) {
772 return res;
773 }
774
775 auto item1 = if_val;
776 auto item2 = else_val;
777 Type to_type = cast_types(item1, item2);
778 if (to_type == Type::Empty) {
779 return res;
780 }
781
782 std::function<bool(float, float)> func = nullptr;
783 std::string category;
784 switch (op) {
786 category = "ifgreater";
787 func = [](float a, float b) { return a > b; };
788 break;
790 category = "ifgreatereq";
791 func = [](float a, float b) { return a >= b; };
792 break;
793 case CompareOp::Eq:
794 category = "ifequal";
795 func = [](float a, float b) { return a == b; };
796 break;
797 default:
799 }
800
801 if (value && other.value) {
802 res = func(value->asA<float>(), other.value->asA<float>()) ? item1 : item2;
803 }
804 else {
805 res = create_node(
806 category, to_type, {{"value1", *this}, {"value2", other}, {"in1", item1}, {"in2", item2}});
807 }
808
809 return res;
810}
811
813{
814 return NodeItem(graph_);
815}
816
818{
819 if (value) {
820 return type(value->getTypeString());
821 }
822 if (node) {
823 return type(node->getType());
824 }
825 if (output) {
826 return type(output->getType());
827 }
828 return Type::Empty;
829}
830
831NodeItem NodeItem::create_node(const std::string &category, Type type) const
832{
833 const std::string name = NodeGraph::unique_anonymous_node_name(graph_);
834 const std::string type_str = NodeItem::type(type);
835 CLOG_DEBUG(LOG_IO_MATERIALX, "<%s type=%s>", category.c_str(), type_str.c_str());
836 NodeItem res = empty();
837 /* Surface-shader nodes and materials are added directly to the document,
838 * otherwise to the node-graph. */
840 res.node = graph_->getDocument()->addNode(category, name, type_str);
841 }
842 else {
843 res.node = graph_->addNode(category, name, type_str);
844 }
845 return res;
846}
847
848NodeItem NodeItem::create_node(const std::string &category, Type type, const Inputs &inputs) const
849{
850 NodeItem res = create_node(category, type);
851 for (const auto &it : inputs) {
852 if (it.second) {
853 res.set_input(it.first, it.second);
854 }
855 }
856 return res;
857}
858
859void NodeItem::set_input(const std::string &in_name, const NodeItem &item)
860{
861 if (item.value) {
862 Type item_type = item.type();
863 switch (item_type) {
864 case Type::String:
865 set_input(in_name, item.value->asA<std::string>(), item_type);
866 break;
867 case Type::Boolean:
868 set_input(in_name, item.value->asA<bool>(), item_type);
869 break;
870 case Type::Integer:
871 set_input(in_name, item.value->asA<int>(), item_type);
872 break;
873 case Type::Float:
874 set_input(in_name, item.value->asA<float>(), item_type);
875 break;
876 case Type::Vector2:
877 set_input(in_name, item.value->asA<MaterialX::Vector2>(), item_type);
878 break;
879 case Type::Vector3:
880 set_input(in_name, item.value->asA<MaterialX::Vector3>(), item_type);
881 break;
882 case Type::Vector4:
883 set_input(in_name, item.value->asA<MaterialX::Vector4>(), item_type);
884 break;
885 case Type::Color3:
886 set_input(in_name, item.value->asA<MaterialX::Color3>(), item_type);
887 break;
888 case Type::Color4:
889 set_input(in_name, item.value->asA<MaterialX::Color4>(), item_type);
890 break;
891 default:
893 }
894 }
895 else if (item.node) {
896 if (type() == Type::SurfaceShader) {
897 auto output_name = item.node->getName() + "_out";
898
899 auto output = graph_->getOutput(output_name);
900 if (!output) {
901 output = graph_->addOutput(output_name, item.node->getType());
902 }
903
904 output->setConnectedNode(item.node);
905 node->setConnectedOutput(in_name, output);
906 }
907 else {
908 node->setConnectedNode(in_name, item.node);
909 }
910 }
911 else if (item.input) {
912 node->setAttribute("interfacename", item.input->getName());
913 }
914 else if (item.output) {
915 node->setConnectedOutput(in_name, item.output);
916 }
917 else {
918 CLOG_WARN(LOG_IO_MATERIALX, "Empty item to input: %s", in_name.c_str());
919 }
920}
921
922NodeItem NodeItem::add_output(const std::string &out_name, Type out_type)
923{
924 NodeItem res = empty();
925 res.output = node->addOutput(out_name, type(out_type));
926 return res;
927}
928
929NodeItem NodeItem::create_input(const std::string &name, const NodeItem &item) const
930{
931 NodeItem res = empty();
932 res.input = graph_->addInput(name);
933
934 Type item_type = item.type();
935 if (item.node) {
936 res.input->setConnectedNode(item.node);
937 }
938 else {
940 }
941 res.input->setType(type(item_type));
942
943 return res;
944}
945
946NodeItem NodeItem::create_output(const std::string &name, const NodeItem &item) const
947{
948 NodeItem res = empty();
949 res.output = graph_->addOutput(name);
950
951 Type item_type = item.type();
952 if (item.node) {
953 res.output->setConnectedNode(item.node);
954 }
955 else if (item.input) {
956 res.output->setInterfaceName(item.input->getName());
957 }
958 else {
960 }
961 res.output->setType(type(item_type));
962
963 return res;
964}
965
966NodeItem::Type NodeItem::cast_types(NodeItem &item1, NodeItem &item2)
967{
968 Type t1 = item1.type();
969 Type t2 = item2.type();
970 if (t1 == t2) {
971 return t1;
972 }
973 if (!is_arithmetic(t1) || !is_arithmetic(t2)) {
974 CLOG_WARN(
975 LOG_IO_MATERIALX, "Can't adjust types: %s <-> %s", type(t1).c_str(), type(t2).c_str());
976 return Type::Empty;
977 }
978 if (t1 < t2) {
979 item1 = item1.convert(t2);
980 return t2;
981 }
982 item2 = item2.convert(t1);
983 return t1;
984}
985
986bool NodeItem::is_arithmetic() const
987{
988 return is_arithmetic(type());
989}
990
991NodeItem NodeItem::arithmetic(const std::string &category, std::function<float(float)> func) const
992{
993 NodeItem res = empty();
994 Type type = this->type();
996
997 if (value) {
998 switch (type) {
999 case Type::Float: {
1000 float v = value->asA<float>();
1001 res.value = MaterialX::Value::createValue<float>(func(v));
1002 break;
1003 }
1004 case Type::Color3: {
1005 auto v = value->asA<MaterialX::Color3>();
1006 res.value = MaterialX::Value::createValue<MaterialX::Color3>(
1007 {func(v[0]), func(v[1]), func(v[2])});
1008 break;
1009 }
1010 case Type::Color4: {
1011 auto v = value->asA<MaterialX::Color4>();
1012 res.value = MaterialX::Value::createValue<MaterialX::Color4>(
1013 {func(v[0]), func(v[1]), func(v[2]), func(v[3])});
1014 break;
1015 }
1016 case Type::Vector2: {
1017 auto v = value->asA<MaterialX::Vector2>();
1018 res.value = MaterialX::Value::createValue<MaterialX::Vector2>({func(v[0]), func(v[1])});
1019 break;
1020 }
1021 case Type::Vector3: {
1022 auto v = value->asA<MaterialX::Vector3>();
1023 res.value = MaterialX::Value::createValue<MaterialX::Vector3>(
1024 {func(v[0]), func(v[1]), func(v[2])});
1025 break;
1026 }
1027 case Type::Vector4: {
1028 auto v = value->asA<MaterialX::Vector4>();
1029 res.value = MaterialX::Value::createValue<MaterialX::Vector4>(
1030 {func(v[0]), func(v[1]), func(v[2]), func(v[3])});
1031 break;
1032 }
1033 default:
1035 }
1036 }
1037 else {
1038 res = create_node(category, type, {{"in", *this}});
1039 }
1040 return res;
1041}
1042
1043NodeItem NodeItem::arithmetic(const NodeItem &other,
1044 const std::string &category,
1045 std::function<float(float, float)> func,
1046 Type to_type) const
1047{
1048 NodeItem res = empty();
1049 NodeItem item1 = *this;
1050 NodeItem item2 = other;
1051 to_type = (to_type == Type::Any) ? cast_types(item1, item2) : to_type;
1052 if (to_type == Type::Empty) {
1053 return res;
1054 }
1055
1056 if (value && other.value) {
1057 switch (to_type) {
1058 case Type::Float: {
1059 float v1 = item1.value->asA<float>();
1060 float v2 = item2.value->asA<float>();
1061 res.value = MaterialX::Value::createValue<float>(func(v1, v2));
1062 break;
1063 }
1064 case Type::Color3: {
1065 auto v1 = item1.value->asA<MaterialX::Color3>();
1066 auto v2 = item2.value->asA<MaterialX::Color3>();
1067 res.value = MaterialX::Value::createValue<MaterialX::Color3>(
1068 {func(v1[0], v2[0]), func(v1[1], v2[1]), func(v1[2], v2[2])});
1069 break;
1070 }
1071 case Type::Color4: {
1072 auto v1 = item1.value->asA<MaterialX::Color4>();
1073 auto v2 = item2.value->asA<MaterialX::Color4>();
1074 res.value = MaterialX::Value::createValue<MaterialX::Color4>(
1075 {func(v1[0], v2[0]), func(v1[1], v2[1]), func(v1[2], v2[2]), func(v1[3], v2[3])});
1076 break;
1077 }
1078 case Type::Vector2: {
1079 auto v1 = item1.value->asA<MaterialX::Vector2>();
1080 auto v2 = item2.value->asA<MaterialX::Vector2>();
1081 res.value = MaterialX::Value::createValue<MaterialX::Vector2>(
1082 {func(v1[0], v2[0]), func(v1[1], v2[1])});
1083 break;
1084 }
1085 case Type::Vector3: {
1086 auto v1 = item1.value->asA<MaterialX::Vector3>();
1087 auto v2 = item2.value->asA<MaterialX::Vector3>();
1088 res.value = MaterialX::Value::createValue<MaterialX::Vector3>(
1089 {func(v1[0], v2[0]), func(v1[1], v2[1]), func(v1[2], v2[2])});
1090 break;
1091 }
1092 case Type::Vector4: {
1093 auto v1 = item1.value->asA<MaterialX::Vector4>();
1094 auto v2 = item2.value->asA<MaterialX::Vector4>();
1095 res.value = MaterialX::Value::createValue<MaterialX::Vector4>(
1096 {func(v1[0], v2[0]), func(v1[1], v2[1]), func(v1[2], v2[2]), func(v1[3], v2[3])});
1097 break;
1098 }
1099 default:
1101 }
1102 }
1103 else {
1104#if !(MATERIALX_MAJOR_VERSION <= 1 && MATERIALX_MINOR_VERSION <= 38)
1105 if (category == "atan2") {
1106 res = create_node(category, to_type, {{"iny", item1}, {"inx", item2}});
1107 }
1108 else
1109#endif
1110 {
1111 res = create_node(category, to_type, {{"in1", item1}, {"in2", item2}});
1112 }
1113 }
1114 return res;
1115}
1116
1117} // namespace blender::nodes::materialx
#define BLI_assert_unreachable()
Definition BLI_assert.h:93
#define BLI_assert(a)
Definition BLI_assert.h:46
#define ELEM(...)
#define CLOG_DEBUG(clg_ref,...)
Definition CLG_log.h:191
#define CLOG_WARN(clg_ref,...)
Definition CLG_log.h:189
eNodeSocketDatatype
@ SOCK_INT
@ SOCK_VECTOR
@ SOCK_BOOLEAN
@ SOCK_SHADER
@ SOCK_FLOAT
@ SOCK_STRING
@ SOCK_RGBA
static double angle(const Eigen::Vector3d &v1, const Eigen::Vector3d &v2)
Definition IK_Math.h:117
ATTR_WARN_UNUSED_RESULT const BMVert * v2
ATTR_WARN_UNUSED_RESULT const BMVert * v
SIMD_FORCE_INLINE const btScalar & z() const
Return the z value.
Definition btQuadWord.h:117
NodeItem operator*(const NodeItem &other) const
Definition node_item.cc:154
NodeItem operator[](int index) const
Definition node_item.cc:189
NodeItem add_output(const std::string &out_name, Type out_type)
Definition node_item.cc:922
NodeItem clamp(const NodeItem &min_val, const NodeItem &max_val) const
Definition node_item.cc:359
NodeItem dotproduct(const NodeItem &other) const
Definition node_item.cc:292
NodeItem max(const NodeItem &other) const
Definition node_item.cc:287
NodeItem val(const T &data) const
Definition node_item.h:148
void set_input(const std::string &in_name, const T &value, Type in_type)
Definition node_item.h:156
bool operator!=(const NodeItem &other) const
Definition node_item.cc:246
NodeItem min(const NodeItem &other) const
Definition node_item.cc:282
bool operator==(const NodeItem &other) const
Definition node_item.cc:222
NodeItem atan2(const NodeItem &other) const
Definition node_item.cc:437
NodeItem create_input(const std::string &name, const NodeItem &item) const
Definition node_item.cc:929
MaterialX::OutputPtr output
Definition node_item.h:56
NodeItem operator+(const NodeItem &other) const
Definition node_item.cc:126
static bool is_arithmetic(Type type)
Definition node_item.cc:116
NodeItem if_else(CompareOp op, const NodeItem &other, const NodeItem &if_val, const NodeItem &else_val) const
Definition node_item.cc:754
NodeItem rotate(const NodeItem &angle, const NodeItem &axis)
Definition node_item.cc:381
NodeItem convert(Type to_type) const
Definition node_item.cc:517
NodeItem create_output(const std::string &name, const NodeItem &item) const
Definition node_item.cc:946
NodeItem operator^(const NodeItem &other) const
Definition node_item.cc:184
static bool is_convertible(eNodeSocketDatatype from_type, Type to_type)
Definition node_item.cc:482
NodeItem mix(const NodeItem &val1, const NodeItem &val2) const
Definition node_item.cc:339
static Type type(const std::string &type_str)
Definition node_item.cc:16
NodeItem operator/(const NodeItem &other) const
Definition node_item.cc:173
std::vector< std::pair< std::string, NodeItem > > Inputs
Definition node_item.h:20
NodeItem operator%(const NodeItem &other) const
Definition node_item.cc:178
NodeItem create_node(const std::string &category, Type type) const
Definition node_item.cc:831
CCL_NAMESPACE_BEGIN ccl_device float invert(const float color, const float factor)
Definition invert.h:11
static Type to_type(const GPUType type)
struct CLG_LogRef * LOG_IO_MATERIALX
static blender::bke::bNodeSocketTemplate inputs[]
const char * name
#define min(a, b)
Definition sort.cc:36
static std::string unique_anonymous_node_name(MaterialX::GraphElement *graph_element)