Blender V4.3
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_parser.h"
7
8#include "BLI_assert.h"
9#include "BLI_utildefines.h"
10
12
13NodeItem::NodeItem(MaterialX::GraphElement *graph) : graph_(graph) {}
14
15NodeItem::Type NodeItem::type(const std::string &type_str)
16{
17 /* Converting only MaterialX supported types */
18 if (type_str == "multioutput") {
19 return Type::Multioutput;
20 }
21 if (type_str == "string") {
22 return Type::String;
23 }
24 if (type_str == "filename") {
25 return Type::Filename;
26 }
27 if (type_str == "boolean") {
28 return Type::Boolean;
29 }
30 if (type_str == "integer") {
31 return Type::Integer;
32 }
33 if (type_str == "float") {
34 return Type::Float;
35 }
36 if (type_str == "vector2") {
37 return Type::Vector2;
38 }
39 if (type_str == "vector3") {
40 return Type::Vector3;
41 }
42 if (type_str == "vector4") {
43 return Type::Vector4;
44 }
45 if (type_str == "color3") {
46 return Type::Color3;
47 }
48 if (type_str == "color4") {
49 return Type::Color4;
50 }
51 if (type_str == "BSDF") {
52 return Type::BSDF;
53 }
54 if (type_str == "EDF") {
55 return Type::EDF;
56 }
57 if (type_str == "displacementshader") {
59 }
60 if (type_str == "surfaceshader") {
62 }
63 if (type_str == "material") {
64 return Type::Material;
65 }
67 return Type::Empty;
68}
69
70std::string NodeItem::type(Type type)
71{
72 switch (type) {
73 case Type::Any:
74 return "any";
76 return "multioutput";
77 case Type::String:
78 return "string";
79 case Type::Filename:
80 return "filename";
81 case Type::Boolean:
82 return "boolean";
83 case Type::Integer:
84 return "integer";
85 case Type::Float:
86 return "float";
87 case Type::Vector2:
88 return "vector2";
89 case Type::Vector3:
90 return "vector3";
91 case Type::Vector4:
92 return "vector4";
93 case Type::Color3:
94 return "color3";
95 case Type::Color4:
96 return "color4";
97 case Type::BSDF:
98 return "BSDF";
99 case Type::EDF:
100 return "EDF";
102 return "displacementshader";
104 return "surfaceshader";
105 case Type::Material:
106 return "material";
108 return "opacity";
109 default:
111 }
112 return "";
113}
114
115bool NodeItem::is_arithmetic(Type type)
116{
117 return type >= Type::Float && type <= Type::Color4;
118}
119
120NodeItem::operator bool() const
121{
122 return value || node || input || output;
123}
124
126{
127 Type type = this->type();
128 if (ELEM(type, Type::BSDF, Type::EDF)) {
129 /* Special case: add BSDF/EDF shaders */
130 NodeItem res = empty();
131 if (other.type() == type) {
132 res = create_node("add", type, {{"in1", *this}, {"in2", other}});
133 }
134 else {
136 }
137 return res;
138 }
139
140 return arithmetic(other, "add", [](float a, float b) { return a + b; });
141}
142
144{
145 return arithmetic(other, "subtract", [](float a, float b) { return a - b; });
146}
147
149{
150 return val(0.0f) - *this;
151}
152
154{
155 Type type = this->type();
156 if (ELEM(type, Type::BSDF, Type::EDF)) {
157 /* Special case: multiple BSDF/EDF shader by Float or Color3 */
158 NodeItem res = empty();
159 Type other_type = other.type();
160 if (ELEM(other_type, Type::Float, Type::Color3)) {
161 res = create_node("multiply", type, {{"in1", *this}, {"in2", other}});
162 }
163 else {
165 }
166 return res;
167 }
168
169 return arithmetic(other, "multiply", [](float a, float b) { return a * b; });
170}
171
173{
174 return arithmetic(other, "divide", [](float a, float b) { return b == 0.0f ? 0.0f : a / b; });
175}
176
178{
179 return arithmetic(
180 other, "modulo", [](float a, float b) { return b == 0.0f ? 0.0f : std::fmod(a, b); });
181}
182
184{
185 return arithmetic(other, "power", [](float a, float b) { return std::pow(a, b); });
186}
187
189{
191
192 if (value) {
193 float v = 0.0f;
194 switch (type()) {
195 case Type::Float:
196 v = value->asA<float>();
197 break;
198 case Type::Vector2:
199 v = value->asA<MaterialX::Vector2>()[index];
200 break;
201 case Type::Vector3:
202 v = value->asA<MaterialX::Vector3>()[index];
203 break;
204 case Type::Vector4:
205 v = value->asA<MaterialX::Vector4>()[index];
206 break;
207 case Type::Color3:
208 v = value->asA<MaterialX::Color3>()[index];
209 break;
210 case Type::Color4:
211 v = value->asA<MaterialX::Color4>()[index];
212 break;
213 default:
215 }
216 return val(v);
217 }
218 return create_node("extract", Type::Float, {{"in", *this}, {"index", val(index)}});
219}
220
221bool NodeItem::operator==(const NodeItem &other) const
222{
223 if (!*this) {
224 return !other;
225 }
226 if (!other) {
227 return !*this;
228 }
229 if (node && node == other.node) {
230 return true;
231 }
232 if ((node && other.value) || (value && other.node)) {
233 return false;
234 }
235
236 NodeItem item1 = *this;
237 NodeItem item2 = other;
238 Type to_type = cast_types(item1, item2);
239 if (to_type == Type::Empty) {
240 return false;
241 }
242 return item1.value->getValueString() == item2.value->getValueString();
243}
244
245bool NodeItem::operator!=(const NodeItem &other) const
246{
247 return !(*this == other);
248}
249
251{
252 return arithmetic("absval", [](float a) { return std::abs(a); });
253}
254
256{
257 return arithmetic("floor", [](float a) { return std::floor(a); });
258}
259
261{
262 return arithmetic("ceil", [](float a) { return std::ceil(a); });
263}
264
266{
267 if (value) {
268 return dotproduct(*this).sqrt();
269 }
270 return create_node("magnitude", Type::Float, {{"in", to_vector()}});
271}
272
274{
275 if (value) {
276 return *this / length();
277 }
278 return create_node("normalize", Type::Vector3, {{"in", to_vector()}});
279}
280
281NodeItem NodeItem::min(const NodeItem &other) const
282{
283 return arithmetic(other, "min", [](float a, float b) { return std::min(a, b); });
284}
285
286NodeItem NodeItem::max(const NodeItem &other) const
287{
288 return arithmetic(other, "max", [](float a, float b) { return std::max(a, b); });
289}
290
292{
293 if (value && other.value) {
294 NodeItem d = *this * other;
295 float f = 0.0f;
296 switch (d.type()) {
297 case Type::Float: {
298 f = d.value->asA<float>();
299 break;
300 }
301 case Type::Vector2: {
302 auto v = d.value->asA<MaterialX::Vector2>();
303 f = v[0] + v[1];
304 break;
305 }
306 case Type::Vector3: {
307 auto v = d.value->asA<MaterialX::Vector3>();
308 f = v[0] + v[1] + v[2];
309 break;
310 }
311 case Type::Vector4: {
312 auto v = d.value->asA<MaterialX::Vector4>();
313 f = v[0] + v[1] + v[2] + v[3];
314 break;
315 }
316 case Type::Color3: {
317 auto v = d.value->asA<MaterialX::Color3>();
318 f = v[0] + v[1] + v[2];
319 break;
320 }
321 case Type::Color4: {
322 auto v = d.value->asA<MaterialX::Color4>();
323 f = v[0] + v[1] + v[2] + v[3];
324 break;
325 }
326 default:
328 }
329 return val(f);
330 }
331
332 NodeItem item1 = to_vector();
333 NodeItem item2 = other.to_vector();
334 cast_types(item1, item2);
335 return create_node("dotproduct", Type::Float, {{"in1", item1}, {"in2", item2}});
336}
337
338NodeItem NodeItem::mix(const NodeItem &val1, const NodeItem &val2) const
339{
340 if ((value && val1.value && val2.value) || type() != Type::Float) {
341 return (val(1.0f) - *this) * val1 + *this * val2;
342 }
343
344 Type type1 = val1.type();
345 if (ELEM(type1, Type::BSDF, Type::EDF)) {
346 BLI_assert(val2.type() == type1);
347
348 /* Special case: mix BSDF/EDF shaders */
349 return create_node("mix", type1, {{"bg", val1}, {"fg", val2}, {"mix", *this}});
350 };
351
352 NodeItem item1 = val1;
353 NodeItem item2 = val2;
354 Type to_type = cast_types(item1, item2);
355 return create_node("mix", to_type, {{"bg", item1}, {"fg", item2}, {"mix", *this}});
356}
357
358NodeItem NodeItem::clamp(const NodeItem &min_val, const NodeItem &max_val) const
359{
360 if (value && min_val.value && max_val.value) {
361 return min(max_val).max(min_val);
362 }
363
364 if (min_val.type() == Type::Float && max_val.type() == Type::Float) {
365 return create_node("clamp", type(), {{"in", *this}, {"low", min_val}, {"high", max_val}});
366 }
367
368 Type type = this->type();
369 return create_node(
370 "clamp",
371 type,
372 {{"in", *this}, {"low", min_val.convert(type)}, {"high", max_val.convert(type)}});
373}
374
375NodeItem NodeItem::clamp(float min_val, float max_val) const
376{
377 return clamp(val(min_val), val(max_val));
378}
379
380NodeItem NodeItem::rotate(const NodeItem &angle, const NodeItem &axis)
381{
383 BLI_assert(angle.type() == Type::Float);
384 BLI_assert(axis.type() == Type::Vector3);
385
386 return create_node(
387 "rotate3d", NodeItem::Type::Vector3, {{"in", *this}, {"amount", angle}, {"axis", axis}});
388}
389
391{
392 NodeItem x = angle_xyz[0];
393 NodeItem y = angle_xyz[1];
394 NodeItem z = angle_xyz[2];
395
396 NodeItem x_axis = val(MaterialX::Vector3(1.0f, 0.0f, 0.0f));
397 NodeItem y_axis = val(MaterialX::Vector3(0.0f, 1.0f, 0.0f));
398 NodeItem z_axis = val(MaterialX::Vector3(0.0f, 0.0f, 1.0f));
399
400 if (invert) {
401 return rotate(z, z_axis).rotate(y, y_axis).rotate(x, x_axis);
402 }
403 return rotate(x, x_axis).rotate(y, y_axis).rotate(z, z_axis);
404}
405
407{
408 return to_vector().arithmetic("sin", [](float a) { return std::sin(a); });
409}
410
412{
413 return to_vector().arithmetic("cos", [](float a) { return std::cos(a); });
414}
415
417{
418 return to_vector().arithmetic("tan", [](float a) { return std::tan(a); });
419}
420
422{
423 return to_vector().arithmetic("asin", [](float a) { return std::asin(a); });
424}
425
427{
428 return to_vector().arithmetic("acos", [](float a) { return std::acos(a); });
429}
430
432{
433 return to_vector().arithmetic("atan", [](float a) { return std::atan(a); });
434}
435
437{
438 return to_vector().arithmetic(other, "atan2", [](float a, float b) { return std::atan2(a, b); });
439}
440
442{
443 NodeItem v = to_vector();
444 return (v.exp() - (-v).exp()) / val(2.0f);
445}
446
448{
449 NodeItem v = to_vector();
450 return (v.exp() + (-v).exp()) / val(2.0f);
451}
452
454{
455 NodeItem v = to_vector();
456 NodeItem a = v.exp();
457 NodeItem b = (-v).exp();
458 return (a - b) / (a + b);
459}
460
462{
463 return to_vector().arithmetic("ln", [](float a) { return std::log(a); });
464}
465
467{
468 return to_vector().arithmetic("sqrt", [](float a) { return std::sqrt(a); });
469}
470
472{
473 return arithmetic("sign", [](float a) { return a < 0.0f ? -1.0f : (a == 0.0f ? 0.0f : 1.0f); });
474}
475
477{
478 return to_vector().arithmetic("exp", [](float a) { return std::exp(a); });
479}
480
482{
483 Type from_type = type();
484 if (from_type == Type::Empty || from_type == to_type || to_type == Type::Any) {
485 return *this;
486 }
487 if (!is_arithmetic(from_type) || !is_arithmetic(to_type)) {
489 "Cannot convert: %s -> %s",
490 type(from_type).c_str(),
491 type(to_type).c_str());
492 return empty();
493 }
494
495 if (to_type == Type::Float) {
496 return (*this)[0];
497 }
498
499 /* Converting types which requires > 1 iteration */
500 switch (from_type) {
501 case Type::Vector2:
502 switch (to_type) {
503 case Type::Vector4:
505 case Type::Color3:
507 case Type::Color4:
509 default:
510 break;
511 }
512 break;
513 case Type::Vector3:
514 switch (to_type) {
515 case Type::Color4:
517 default:
518 break;
519 }
520 break;
521 case Type::Vector4:
522 switch (to_type) {
523 case Type::Vector2:
525 case Type::Color3:
527 default:
528 break;
529 }
530 break;
531 case Type::Color3:
532 switch (to_type) {
533 case Type::Vector2:
535 case Type::Vector4:
537 default:
538 break;
539 }
540 break;
541 case Type::Color4:
542 switch (to_type) {
543 case Type::Vector2:
545 case Type::Vector3:
547 default:
548 break;
549 }
550 break;
551 default:
552 break;
553 }
554
555 /* Converting 1 iteration types */
556 NodeItem res = empty();
557 if (value) {
558 switch (from_type) {
559 case Type::Float: {
560 float v = value->asA<float>();
561 switch (to_type) {
562 case Type::Vector2:
563 res.value = MaterialX::Value::createValue<MaterialX::Vector2>({v, v});
564 break;
565 case Type::Vector3:
566 res.value = MaterialX::Value::createValue<MaterialX::Vector3>({v, v, v});
567 break;
568 case Type::Vector4:
569 res.value = MaterialX::Value::createValue<MaterialX::Vector4>({v, v, v, 1.0f});
570 break;
571 case Type::Color3:
572 res.value = MaterialX::Value::createValue<MaterialX::Color3>({v, v, v});
573 break;
574 case Type::Color4:
575 res.value = MaterialX::Value::createValue<MaterialX::Color4>({v, v, v, 1.0f});
576 break;
577 default:
579 }
580 break;
581 }
582 case Type::Vector2: {
583 auto v = value->asA<MaterialX::Vector2>();
584 switch (to_type) {
585 case Type::Vector3:
586 res.value = MaterialX::Value::createValue<MaterialX::Vector3>({v[0], v[1], 0.0f});
587 break;
588 default:
590 }
591 break;
592 }
593 case Type::Vector3: {
594 auto v = value->asA<MaterialX::Vector3>();
595 switch (to_type) {
596 case Type::Vector2:
597 res.value = MaterialX::Value::createValue<MaterialX::Vector2>({v[0], v[1]});
598 break;
599 case Type::Vector4:
600 res.value = MaterialX::Value::createValue<MaterialX::Vector4>(
601 {v[0], v[1], v[2], 0.0f});
602 break;
603 case Type::Color3:
604 res.value = MaterialX::Value::createValue<MaterialX::Color3>({v[0], v[1], v[2]});
605 break;
606 default:
608 }
609 break;
610 }
611 case Type::Vector4: {
612 auto v = value->asA<MaterialX::Vector4>();
613 switch (to_type) {
614 case Type::Vector3:
615 res.value = MaterialX::Value::createValue<MaterialX::Vector3>({v[0], v[1], v[2]});
616 break;
617 case Type::Color4:
618 res.value = MaterialX::Value::createValue<MaterialX::Color4>({v[0], v[1], v[2], v[3]});
619 break;
620 default:
622 }
623 break;
624 }
625 case Type::Color3: {
626 auto v = value->asA<MaterialX::Color3>();
627 switch (to_type) {
628 case Type::Vector3:
629 res.value = MaterialX::Value::createValue<MaterialX::Vector3>({v[0], v[1], v[2]});
630 break;
631 case Type::Color4:
632 res.value = MaterialX::Value::createValue<MaterialX::Color4>({v[0], v[1], v[2], 1.0f});
633 break;
634 default:
636 }
637 break;
638 }
639 case Type::Color4: {
640 auto v = value->asA<MaterialX::Color4>();
641 switch (to_type) {
642 case Type::Vector4:
643 res.value = MaterialX::Value::createValue<MaterialX::Vector4>(
644 {v[0], v[1], v[2], v[3]});
645 break;
646 case Type::Color3:
647 res.value = MaterialX::Value::createValue<MaterialX::Color3>({v[0], v[1], v[2]});
648 break;
649 default:
651 }
652 break;
653 }
654 default:
656 }
657 }
658 else {
659 res = create_node("convert", to_type, {{"in", *this}});
660 }
661 return res;
662}
663
665{
666 switch (type()) {
667 case Type::Float:
668 case Type::Vector2:
669 case Type::Vector3:
670 case Type::Vector4:
671 return *this;
672
673 case Type::Color3:
674 return convert(Type::Vector3);
675
676 case Type::Color4:
677 return convert(Type::Vector4);
678
679 default:
681 }
682 return empty();
683}
684
686 const NodeItem &other,
687 const NodeItem &if_val,
688 const NodeItem &else_val) const
689{
690 switch (op) {
691 case CompareOp::Less:
692 return if_else(CompareOp::GreaterEq, other, else_val, if_val);
694 return if_else(CompareOp::Greater, other, else_val, if_val);
695 case CompareOp::NotEq:
696 return if_else(CompareOp::Eq, other, else_val, if_val);
697 default:
698 break;
699 }
700
701 NodeItem res = empty();
702 if (type() != Type::Float || other.type() != Type::Float) {
703 return res;
704 }
705
706 auto item1 = if_val;
707 auto item2 = else_val;
708 Type to_type = cast_types(item1, item2);
709 if (to_type == Type::Empty) {
710 return res;
711 }
712
713 std::function<bool(float, float)> func = nullptr;
714 std::string category;
715 switch (op) {
717 category = "ifgreater";
718 func = [](float a, float b) { return a > b; };
719 break;
721 category = "ifgreatereq";
722 func = [](float a, float b) { return a >= b; };
723 break;
724 case CompareOp::Eq:
725 category = "ifequal";
726 func = [](float a, float b) { return a == b; };
727 break;
728 default:
730 }
731
732 if (value && other.value) {
733 res = func(value->asA<float>(), other.value->asA<float>()) ? item1 : item2;
734 }
735 else {
736 res = create_node(
737 category, to_type, {{"value1", *this}, {"value2", other}, {"in1", item1}, {"in2", item2}});
738 }
739
740 return res;
741}
742
744{
745 return NodeItem(graph_);
746}
747
749{
750 if (value) {
751 return type(value->getTypeString());
752 }
753 if (node) {
754 return type(node->getType());
755 }
756 if (output) {
757 return type(output->getType());
758 }
759 return Type::Empty;
760}
761
762NodeItem NodeItem::create_node(const std::string &category, Type type) const
763{
764 std::string type_str = this->type(type);
765 CLOG_INFO(LOG_MATERIALX_SHADER, 2, "<%s type=%s>", category.c_str(), type_str.c_str());
766 NodeItem res = empty();
767 /* Surface-shader nodes and materials are added directly to the document,
768 * otherwise to the node-graph. */
770 res.node = graph_->getDocument()->addNode(category, MaterialX::EMPTY_STRING, type_str);
771 }
772 else {
773 res.node = graph_->addNode(category, MaterialX::EMPTY_STRING, type_str);
774 }
775 return res;
776}
777
778NodeItem NodeItem::create_node(const std::string &category, Type type, const Inputs &inputs) const
779{
780 NodeItem res = create_node(category, type);
781 for (auto &it : inputs) {
782 if (it.second) {
783 res.set_input(it.first, it.second);
784 }
785 }
786 return res;
787}
788
789void NodeItem::set_input(const std::string &in_name, const NodeItem &item)
790{
791 if (item.value) {
792 Type item_type = item.type();
793 switch (item_type) {
794 case Type::String:
795 set_input(in_name, item.value->asA<std::string>(), item_type);
796 break;
797 case Type::Boolean:
798 set_input(in_name, item.value->asA<bool>(), item_type);
799 break;
800 case Type::Integer:
801 set_input(in_name, item.value->asA<int>(), item_type);
802 break;
803 case Type::Float:
804 set_input(in_name, item.value->asA<float>(), item_type);
805 break;
806 case Type::Vector2:
807 set_input(in_name, item.value->asA<MaterialX::Vector2>(), item_type);
808 break;
809 case Type::Vector3:
810 set_input(in_name, item.value->asA<MaterialX::Vector3>(), item_type);
811 break;
812 case Type::Vector4:
813 set_input(in_name, item.value->asA<MaterialX::Vector4>(), item_type);
814 break;
815 case Type::Color3:
816 set_input(in_name, item.value->asA<MaterialX::Color3>(), item_type);
817 break;
818 case Type::Color4:
819 set_input(in_name, item.value->asA<MaterialX::Color4>(), item_type);
820 break;
821 default:
823 }
824 }
825 else if (item.node) {
826 if (type() == Type::SurfaceShader) {
827 auto output_name = item.node->getName() + "_out";
828
829 auto output = graph_->getOutput(output_name);
830 if (!output) {
831 auto output_type = MaterialX::DEFAULT_TYPE_STRING;
832 if (item.node->getType() == "BSDF") {
833 output_type = "BSDF";
834 }
835 output = graph_->addOutput(output_name, output_type);
836 }
837
838 output->setConnectedNode(item.node);
839 node->setConnectedOutput(in_name, output);
840 }
841 else {
842 node->setConnectedNode(in_name, item.node);
843 }
844 }
845 else if (item.input) {
846 node->setAttribute("interfacename", item.input->getName());
847 }
848 else if (item.output) {
849 node->setConnectedOutput(in_name, item.output);
850 }
851 else {
852 CLOG_WARN(LOG_MATERIALX_SHADER, "Empty item to input: %s", in_name.c_str());
853 }
854}
855
856NodeItem NodeItem::add_output(const std::string &out_name, Type out_type)
857{
858 NodeItem res = empty();
859 res.output = node->addOutput(out_name, type(out_type));
860 return res;
861}
862
863NodeItem NodeItem::create_input(const std::string &name, const NodeItem &item) const
864{
865 NodeItem res = empty();
866 res.input = graph_->addInput(name);
867
868 Type item_type = item.type();
869 if (item.node) {
870 res.input->setConnectedNode(item.node);
871 }
872 else {
874 }
875 res.input->setType(type(item_type));
876
877 return res;
878}
879
880NodeItem NodeItem::create_output(const std::string &name, const NodeItem &item) const
881{
882 NodeItem res = empty();
883 res.output = graph_->addOutput(name);
884
885 Type item_type = item.type();
886 if (item.node) {
887 res.output->setConnectedNode(item.node);
888 }
889 else if (item.input) {
890 res.output->setInterfaceName(item.input->getName());
891 }
892 else {
894 }
895 res.output->setType(type(item_type));
896
897 return res;
898}
899
900NodeItem::Type NodeItem::cast_types(NodeItem &item1, NodeItem &item2)
901{
902 Type t1 = item1.type();
903 Type t2 = item2.type();
904 if (t1 == t2) {
905 return t1;
906 }
907 if (!is_arithmetic(t1) || !is_arithmetic(t2)) {
908 CLOG_WARN(
909 LOG_MATERIALX_SHADER, "Can't adjust types: %s <-> %s", type(t1).c_str(), type(t2).c_str());
910 return Type::Empty;
911 }
912 if (t1 < t2) {
913 item1 = item1.convert(t2);
914 return t2;
915 }
916 else {
917 item2 = item2.convert(t1);
918 return t1;
919 }
920}
921
922bool NodeItem::is_arithmetic() const
923{
924 return is_arithmetic(type());
925}
926
927NodeItem NodeItem::arithmetic(const std::string &category, std::function<float(float)> func) const
928{
929 NodeItem res = empty();
930 Type type = this->type();
932
933 if (value) {
934 switch (type) {
935 case Type::Float: {
936 float v = value->asA<float>();
937 res.value = MaterialX::Value::createValue<float>(func(v));
938 break;
939 }
940 case Type::Color3: {
941 auto v = value->asA<MaterialX::Color3>();
942 res.value = MaterialX::Value::createValue<MaterialX::Color3>(
943 {func(v[0]), func(v[1]), func(v[2])});
944 break;
945 }
946 case Type::Color4: {
947 auto v = value->asA<MaterialX::Color4>();
948 res.value = MaterialX::Value::createValue<MaterialX::Color4>(
949 {func(v[0]), func(v[1]), func(v[2]), func(v[3])});
950 break;
951 }
952 case Type::Vector2: {
953 auto v = value->asA<MaterialX::Vector2>();
954 res.value = MaterialX::Value::createValue<MaterialX::Vector2>({func(v[0]), func(v[1])});
955 break;
956 }
957 case Type::Vector3: {
958 auto v = value->asA<MaterialX::Vector3>();
959 res.value = MaterialX::Value::createValue<MaterialX::Vector3>(
960 {func(v[0]), func(v[1]), func(v[2])});
961 break;
962 }
963 case Type::Vector4: {
964 auto v = value->asA<MaterialX::Vector4>();
965 res.value = MaterialX::Value::createValue<MaterialX::Vector4>(
966 {func(v[0]), func(v[1]), func(v[2]), func(v[3])});
967 break;
968 }
969 default:
971 }
972 }
973 else {
974 res = create_node(category, type, {{"in", *this}});
975 }
976 return res;
977}
978
979NodeItem NodeItem::arithmetic(const NodeItem &other,
980 const std::string &category,
981 std::function<float(float, float)> func,
982 Type to_type) const
983{
984 NodeItem res = empty();
985 NodeItem item1 = *this;
986 NodeItem item2 = other;
987 to_type = (to_type == Type::Any) ? cast_types(item1, item2) : to_type;
988 if (to_type == Type::Empty) {
989 return res;
990 }
991
992 if (value && other.value) {
993 switch (to_type) {
994 case Type::Float: {
995 float v1 = item1.value->asA<float>();
996 float v2 = item2.value->asA<float>();
997 res.value = MaterialX::Value::createValue<float>(func(v1, v2));
998 break;
999 }
1000 case Type::Color3: {
1001 auto v1 = item1.value->asA<MaterialX::Color3>();
1002 auto v2 = item2.value->asA<MaterialX::Color3>();
1003 res.value = MaterialX::Value::createValue<MaterialX::Color3>(
1004 {func(v1[0], v2[0]), func(v1[1], v2[1]), func(v1[2], v2[2])});
1005 break;
1006 }
1007 case Type::Color4: {
1008 auto v1 = item1.value->asA<MaterialX::Color4>();
1009 auto v2 = item2.value->asA<MaterialX::Color4>();
1010 res.value = MaterialX::Value::createValue<MaterialX::Color4>(
1011 {func(v1[0], v2[0]), func(v1[1], v2[1]), func(v1[2], v2[2]), func(v1[3], v2[3])});
1012 break;
1013 }
1014 case Type::Vector2: {
1015 auto v1 = item1.value->asA<MaterialX::Vector2>();
1016 auto v2 = item2.value->asA<MaterialX::Vector2>();
1017 res.value = MaterialX::Value::createValue<MaterialX::Vector2>(
1018 {func(v1[0], v2[0]), func(v1[1], v2[1])});
1019 break;
1020 }
1021 case Type::Vector3: {
1022 auto v1 = item1.value->asA<MaterialX::Vector3>();
1023 auto v2 = item2.value->asA<MaterialX::Vector3>();
1024 res.value = MaterialX::Value::createValue<MaterialX::Vector3>(
1025 {func(v1[0], v2[0]), func(v1[1], v2[1]), func(v1[2], v2[2])});
1026 break;
1027 }
1028 case Type::Vector4: {
1029 auto v1 = item1.value->asA<MaterialX::Vector4>();
1030 auto v2 = item2.value->asA<MaterialX::Vector4>();
1031 res.value = MaterialX::Value::createValue<MaterialX::Vector4>(
1032 {func(v1[0], v2[0]), func(v1[1], v2[1]), func(v1[2], v2[2]), func(v1[3], v2[3])});
1033 break;
1034 }
1035 default:
1037 }
1038 }
1039 else {
1040 res = create_node(category, to_type, {{"in1", item1}, {"in2", item2}});
1041 }
1042 return res;
1043}
1044
1045} // namespace blender::nodes::materialx
#define BLI_assert_unreachable()
Definition BLI_assert.h:97
#define BLI_assert(a)
Definition BLI_assert.h:50
#define ELEM(...)
#define CLOG_WARN(clg_ref,...)
Definition CLG_log.h:181
#define CLOG_INFO(clg_ref, level,...)
Definition CLG_log.h:179
ATTR_WARN_UNUSED_RESULT const BMVert * v2
ATTR_WARN_UNUSED_RESULT const BMVert * v
#define output
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:153
NodeItem operator[](int index) const
Definition node_item.cc:188
NodeItem add_output(const std::string &out_name, Type out_type)
Definition node_item.cc:856
NodeItem clamp(const NodeItem &min_val, const NodeItem &max_val) const
Definition node_item.cc:358
NodeItem dotproduct(const NodeItem &other) const
Definition node_item.cc:291
NodeItem max(const NodeItem &other) const
Definition node_item.cc:286
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:245
NodeItem min(const NodeItem &other) const
Definition node_item.cc:281
bool operator==(const NodeItem &other) const
Definition node_item.cc:221
NodeItem atan2(const NodeItem &other) const
Definition node_item.cc:436
NodeItem create_input(const std::string &name, const NodeItem &item) const
Definition node_item.cc:863
MaterialX::OutputPtr output
Definition node_item.h:57
NodeItem operator+(const NodeItem &other) const
Definition node_item.cc:125
static bool is_arithmetic(Type type)
Definition node_item.cc:115
NodeItem if_else(CompareOp op, const NodeItem &other, const NodeItem &if_val, const NodeItem &else_val) const
Definition node_item.cc:685
NodeItem rotate(const NodeItem &angle, const NodeItem &axis)
Definition node_item.cc:380
NodeItem convert(Type to_type) const
Definition node_item.cc:481
NodeItem create_output(const std::string &name, const NodeItem &item) const
Definition node_item.cc:880
NodeItem operator^(const NodeItem &other) const
Definition node_item.cc:183
NodeItem mix(const NodeItem &val1, const NodeItem &val2) const
Definition node_item.cc:338
static Type type(const std::string &type_str)
Definition node_item.cc:15
NodeItem operator/(const NodeItem &other) const
Definition node_item.cc:172
std::vector< std::pair< std::string, NodeItem > > Inputs
Definition node_item.h:20
NodeItem operator%(const NodeItem &other) const
Definition node_item.cc:177
NodeItem create_node(const std::string &category, Type type) const
Definition node_item.cc:762
local_group_size(16, 16) .push_constant(Type b
CCL_NAMESPACE_BEGIN ccl_device float invert(float color, float factor)
Definition invert.h:9
static Type to_type(const eGPUType type)
struct CLG_LogRef * LOG_MATERIALX_SHADER
static blender::bke::bNodeSocketTemplate inputs[]
#define min(a, b)
Definition sort.c:32