Implement type conversion for NodeItem #9

Merged
Bogdan Nagirniak merged 12 commits from BogdanNagirniak/blender:matx-nodeitem-type into matx-export-material 2023-09-05 12:03:24 +02:00
2 changed files with 228 additions and 227 deletions
Showing only changes of commit 53c4638b53 - Show all commits

View File

@ -12,125 +12,6 @@ namespace blender::nodes::materialx {
NodeItem::NodeItem(MaterialX::GraphElement *graph) : graph_(graph) {} NodeItem::NodeItem(MaterialX::GraphElement *graph) : graph_(graph) {}
NodeItem::Type NodeItem::type(const std::string &type_str)
{
if (type_str == "string") {
return Type::String;
}
if (type_str == "integer") {
return Type::Integer;
}
if (type_str == "float") {
return Type::Float;
}
if (type_str == "vector2") {
return Type::Vector2;
}
if (type_str == "vector3") {
return Type::Vector3;
}
if (type_str == "vector4") {
return Type::Vector4;
}
if (type_str == "color3") {
return Type::Color3;
}
if (type_str == "color4") {
return Type::Color4;
}
return Type::Other;
}
std::string NodeItem::type(Type tp)
{
switch (tp) {
case Type::String:
return "string";
case Type::Integer:
return "integer";
case Type::Float:
return "float";
case Type::Vector2:
return "vector2";
case Type::Vector3:
return "vector3";
case Type::Vector4:
return "vector4";
case Type::Color3:
return "color3";
case Type::Color4:
return "color4";
default:
break;
}
return "";
}
NodeItem NodeItem::empty() const
{
return NodeItem(graph_);
}
void NodeItem::set_input(const std::string &name,
const NodeItem &item,
const std::string &output_name)
{
if (item.value) {
Type t = item.type();
std::string mx_type = type(t);
switch (t) {
case Type::String:
set_input(name, item.value->asA<std::string>(), mx_type);
break;
case Type::Integer:
set_input(name, item.value->asA<int>(), mx_type);
break;
case Type::Float:
set_input(name, item.value->asA<float>(), mx_type);
break;
case Type::Vector2:
set_input(name, item.value->asA<MaterialX::Vector2>(), mx_type);
break;
case Type::Vector3:
set_input(name, item.value->asA<MaterialX::Vector3>(), mx_type);
break;
case Type::Vector4:
set_input(name, item.value->asA<MaterialX::Vector4>(), mx_type);
break;
case Type::Color3:
set_input(name, item.value->asA<MaterialX::Color3>(), mx_type);
break;
case Type::Color4:
set_input(name, item.value->asA<MaterialX::Color4>(), mx_type);
break;
default:
BLI_assert_unreachable();
}
}
else if (item.node) {
node->setConnectedNode(name, item.node);
if (output_name != "") {
node->setConnectedOutput(name, item.node->getOutput(output_name));
}
}
else {
CLOG_WARN(LOG_MATERIALX_SHADER, "Empty item to input: %s", name.c_str());
}
}
void NodeItem::set_input(const std::string &name,
const NodeItem &item,
Type in_type,
const std::string &output_name)
{
set_input(name, item.convert(in_type), output_name);
}
void NodeItem::add_output(const std::string &name, Type out_type)
{
node->addOutput(name, type(out_type));
}
NodeItem::operator bool() const NodeItem::operator bool() const
{ {
return value || node; return value || node;
@ -270,67 +151,6 @@ NodeItem NodeItem::dotproduct(const NodeItem &other) const
return d; return d;
} }
NodeItem NodeItem::if_else(IfType condition,
const NodeItem &other,
const NodeItem &if_val,
const NodeItem &else_val) const
{
switch (condition) {
case IfType::Less:
return other.if_else(IfType::Greater, *this, else_val, if_val);
case IfType::LessEq:
return other.if_else(IfType::GreaterEq, *this, else_val, if_val);
case IfType::NotEq:
return if_else(IfType::Eq, other, else_val, if_val);
default:
break;
}
NodeItem res = empty();
if (type() != Type::Float || other.type() != Type::Float) {
return res;
}
auto item1 = if_val;
auto item2 = else_val;
Type tp = adjust_types(item1, item2);
if (tp == Type::Empty) {
return res;
}
std::function<bool(float, float)> func = nullptr;
std::string mx_category;
switch (condition) {
case IfType::Greater:
mx_category = "ifgreater";
func = [](float a, float b) { return a > b; };
break;
case IfType::GreaterEq:
mx_category = "ifgreatereq";
func = [](float a, float b) { return a >= b; };
break;
case IfType::Eq:
mx_category = "ifequal";
func = [](float a, float b) { return a == b; };
break;
default:
BLI_assert_unreachable();
}
if (value && other.value) {
res = func(value->asA<float>(), other.value->asA<float>()) ? item1 : item2;
}
else {
res.node = graph_->addNode(mx_category, MaterialX::EMPTY_STRING, type(tp));
res.set_input("value1", *this);
res.set_input("value2", other);
res.set_input("in1", item1);
res.set_input("in2", item2);
}
return res;
}
NodeItem NodeItem::blend(const NodeItem &a, const NodeItem &b) const NodeItem NodeItem::blend(const NodeItem &a, const NodeItem &b) const
{ {
return (val(1.0f) - *this) * a + *this * b; return (val(1.0f) - *this) * a + *this * b;
@ -590,6 +410,72 @@ NodeItem NodeItem::convert(Type to_type) const
return res; return res;
} }
NodeItem NodeItem::if_else(IfType condition,
const NodeItem &other,
const NodeItem &if_val,
const NodeItem &else_val) const
{
switch (condition) {
case IfType::Less:
return other.if_else(IfType::Greater, *this, else_val, if_val);
case IfType::LessEq:
return other.if_else(IfType::GreaterEq, *this, else_val, if_val);
case IfType::NotEq:
return if_else(IfType::Eq, other, else_val, if_val);
default:
break;
}
NodeItem res = empty();
if (type() != Type::Float || other.type() != Type::Float) {
return res;
}
auto item1 = if_val;
auto item2 = else_val;
Type tp = adjust_types(item1, item2);
BogdanNagirniak marked this conversation as resolved
Review

Should Integer be here?

Should `Integer` be here?
Review

Discussed: let it be here

Discussed: let it be here
if (tp == Type::Empty) {
return res;
}
std::function<bool(float, float)> func = nullptr;
std::string mx_category;
switch (condition) {
case IfType::Greater:
mx_category = "ifgreater";
func = [](float a, float b) { return a > b; };
break;
case IfType::GreaterEq:
mx_category = "ifgreatereq";
func = [](float a, float b) { return a >= b; };
break;
case IfType::Eq:
mx_category = "ifequal";
func = [](float a, float b) { return a == b; };
break;
default:
BLI_assert_unreachable();
}
if (value && other.value) {
res = func(value->asA<float>(), other.value->asA<float>()) ? item1 : item2;
}
else {
res.node = graph_->addNode(mx_category, MaterialX::EMPTY_STRING, type(tp));
res.set_input("value1", *this);
res.set_input("value2", other);
res.set_input("in1", item1);
res.set_input("in2", item2);
}
return res;
}
NodeItem NodeItem::empty() const
{
return NodeItem(graph_);
}
NodeItem::Type NodeItem::type() const NodeItem::Type NodeItem::type() const
{ {
if (value) { if (value) {
@ -601,9 +487,143 @@ NodeItem::Type NodeItem::type() const
return Type::Empty; return Type::Empty;
} }
bool NodeItem::is_arithmetic(Type t) void NodeItem::set_input(const std::string &name,
const NodeItem &item,
const std::string &output_name)
{ {
return t >= Type::Float; if (item.value) {
Type t = item.type();
std::string mx_type = type(t);
switch (t) {
case Type::String:
set_input(name, item.value->asA<std::string>(), mx_type);
break;
case Type::Integer:
set_input(name, item.value->asA<int>(), mx_type);
break;
case Type::Float:
set_input(name, item.value->asA<float>(), mx_type);
break;
case Type::Vector2:
set_input(name, item.value->asA<MaterialX::Vector2>(), mx_type);
break;
case Type::Vector3:
set_input(name, item.value->asA<MaterialX::Vector3>(), mx_type);
break;
case Type::Vector4:
set_input(name, item.value->asA<MaterialX::Vector4>(), mx_type);
break;
case Type::Color3:
set_input(name, item.value->asA<MaterialX::Color3>(), mx_type);
break;
case Type::Color4:
set_input(name, item.value->asA<MaterialX::Color4>(), mx_type);
break;
default:
BLI_assert_unreachable();
}
}
else if (item.node) {
node->setConnectedNode(name, item.node);
if (output_name != "") {
node->setConnectedOutput(name, item.node->getOutput(output_name));
}
}
else {
CLOG_WARN(LOG_MATERIALX_SHADER, "Empty item to input: %s", name.c_str());
}
}
void NodeItem::set_input(const std::string &name,
const NodeItem &item,
Type in_type,
const std::string &output_name)
{
set_input(name, item.convert(in_type), output_name);
}
void NodeItem::add_output(const std::string &name, Type out_type)
{
node->addOutput(name, type(out_type));
}
NodeItem::Type NodeItem::type(const std::string &tp)
{
if (tp == "string") {
return Type::String;
}
if (tp == "integer") {
return Type::Integer;
}
if (tp == "float") {
return Type::Float;
}
if (tp == "vector2") {
return Type::Vector2;
}
if (tp == "vector3") {
return Type::Vector3;
}
if (tp == "vector4") {
return Type::Vector4;
}
if (tp == "color3") {
return Type::Color3;
}
if (tp == "color4") {
return Type::Color4;
}
return Type::Other;
}
std::string NodeItem::type(Type tp)
{
switch (tp) {
case Type::String:
return "string";
case Type::Integer:
return "integer";
case Type::Float:
return "float";
case Type::Vector2:
return "vector2";
case Type::Vector3:
return "vector3";
case Type::Vector4:
return "vector4";
case Type::Color3:
return "color3";
case Type::Color4:
return "color4";
default:
break;
}
return "";
}
bool NodeItem::is_arithmetic(Type tp)
{
return tp >= Type::Float;
}
NodeItem::Type NodeItem::adjust_types(NodeItem &item1, NodeItem &item2)
{
Type t1 = item1.type();
Type t2 = item2.type();
BogdanNagirniak marked this conversation as resolved Outdated

Type::Float -> Type::Integer

Type::Float -> Type::Integer

Integer isn't used in arithmetic operations

Integer isn't used in arithmetic operations
if (t1 == t2) {
return t1;
}
if (!is_arithmetic(t1) || !is_arithmetic(t2)) {
return Type::Empty;
}
if (t1 < t2) {
item1 = item1.convert(t2);
return t2;
}
else {
item2 = item2.convert(t1);
return t1;
}
} }
bool NodeItem::is_arithmetic() const bool NodeItem::is_arithmetic() const
@ -732,24 +752,4 @@ NodeItem NodeItem::arithmetic(const NodeItem &other,
return res; return res;
} }
NodeItem::Type NodeItem::adjust_types(NodeItem &item1, NodeItem &item2)
{
Type t1 = item1.type();
Type t2 = item2.type();
if (t1 == t2) {
return t1;
}
if (!is_arithmetic(t1) || !is_arithmetic(t2)) {
return Type::Empty;
}
if (t1 < t2) {
item1 = item1.convert(t2);
return t2;
}
else {
item2 = item2.convert(t1);
return t1;
}
}
} // namespace blender::nodes::materialx } // namespace blender::nodes::materialx

View File

@ -35,23 +35,7 @@ class NodeItem {
NodeItem(MaterialX::GraphElement *graph); NodeItem(MaterialX::GraphElement *graph);
~NodeItem() = default; ~NodeItem() = default;
static Type type(const std::string &type_str); /* Operators */
BogdanNagirniak marked this conversation as resolved
Review

Suggest add #pragma region for such places

Suggest add `#pragma region` for such places
Review

It is not commonly used in Blender code

It is not commonly used in Blender code
static std::string type(Type tp);
NodeItem empty() const;
template<class T> NodeItem val(const T &data) const;
template<class T>
void set_input(const std::string &in_name, const T &value, const std::string &in_type);
void set_input(const std::string &in_name,
const NodeItem &item,
const std::string &out_name = "");
void set_input(const std::string &in_name,
const NodeItem &item,
Type in_type,
const std::string &out_name = "");
void add_output(const std::string &in_name, Type out_type);
operator bool() const; operator bool() const;
NodeItem operator+(const NodeItem &other) const; NodeItem operator+(const NodeItem &other) const;
NodeItem operator-(const NodeItem &other) const; NodeItem operator-(const NodeItem &other) const;
@ -63,16 +47,13 @@ class NodeItem {
bool operator==(const NodeItem &other) const; bool operator==(const NodeItem &other) const;
bool operator!=(const NodeItem &other) const; bool operator!=(const NodeItem &other) const;
/* Math functions */
NodeItem abs() const; NodeItem abs() const;
NodeItem floor() const; NodeItem floor() const;
NodeItem ceil() const; NodeItem ceil() const;
NodeItem min(const NodeItem &other) const; NodeItem min(const NodeItem &other) const;
NodeItem max(const NodeItem &other) const; NodeItem max(const NodeItem &other) const;
NodeItem dotproduct(const NodeItem &other) const; NodeItem dotproduct(const NodeItem &other) const;
NodeItem if_else(IfType condition,
const NodeItem &other,
const NodeItem &if_val,
const NodeItem &else_val) const;
NodeItem blend(const NodeItem &a, const NodeItem &b) const; NodeItem blend(const NodeItem &a, const NodeItem &b) const;
NodeItem clamp(const NodeItem &min_val, const NodeItem &max_val) const; NodeItem clamp(const NodeItem &min_val, const NodeItem &max_val) const;
NodeItem clamp(float min_val = 0.0f, float max_val = 1.0f) const; NodeItem clamp(float min_val = 0.0f, float max_val = 1.0f) const;
@ -90,20 +71,40 @@ class NodeItem {
NodeItem sqrt() const; NodeItem sqrt() const;
NodeItem sign() const; NodeItem sign() const;
NodeItem exp() const; NodeItem exp() const;
NodeItem convert(Type to_type) const; NodeItem convert(Type to_type) const;
NodeItem if_else(IfType condition,
const NodeItem &other,
const NodeItem &if_val,
const NodeItem &else_val) const;
/* Useful functions */
NodeItem empty() const;
template<class T> NodeItem val(const T &data) const;
Type type() const; Type type() const;
/* Functions to set input and output */
template<class T>
void set_input(const std::string &in_name, const T &value, const std::string &in_type);
void set_input(const std::string &in_name,
const NodeItem &item,
const std::string &out_name = "");
void set_input(const std::string &in_name,
const NodeItem &item,
Type in_type,
const std::string &out_name = "");
void add_output(const std::string &in_name, Type out_type);
private: private:
static bool is_arithmetic(Type t); static Type type(const std::string &tp);
static std::string type(Type tp);
static bool is_arithmetic(Type tp);
static Type adjust_types(NodeItem &item1, NodeItem &item2);
bool is_arithmetic() const; bool is_arithmetic() const;
NodeItem arithmetic(const std::string &category, std::function<float(float)> func) const; NodeItem arithmetic(const std::string &category, std::function<float(float)> func) const;
NodeItem arithmetic(const NodeItem &other, NodeItem arithmetic(const NodeItem &other,
const std::string &category, const std::string &category,
std::function<float(float, float)> func) const; std::function<float(float, float)> func) const;
static Type adjust_types(NodeItem &item1, NodeItem &item2);
}; };
template<class T> NodeItem NodeItem::val(const T &data) const template<class T> NodeItem NodeItem::val(const T &data) const