|
|
|
@ -10,6 +10,11 @@ namespace blender::nodes::materialx {
|
|
|
|
|
|
|
|
|
|
NodeItem::NodeItem(MaterialX::GraphElement *graph) : graph_(graph) {}
|
|
|
|
|
|
|
|
|
|
NodeItem NodeItem::empty() const
|
|
|
|
|
{
|
|
|
|
|
return NodeItem(graph_);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void NodeItem::set_input(const std::string &name, const NodeItem &item)
|
|
|
|
|
{
|
|
|
|
|
if (item.value) {
|
|
|
|
@ -59,121 +64,141 @@ NodeItem::operator bool() const
|
|
|
|
|
return value || node;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NodeItem NodeItem::operator+(const NodeItem &other)
|
|
|
|
|
NodeItem NodeItem::operator+(const NodeItem &other) const
|
|
|
|
|
{
|
|
|
|
|
return arithmetic(other, "add", [](float a, float b) { return a + b; });
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NodeItem NodeItem::operator-(const NodeItem &other)
|
|
|
|
|
NodeItem NodeItem::operator-(const NodeItem &other) const
|
|
|
|
|
{
|
|
|
|
|
return arithmetic(other, "subtract", [](float a, float b) { return a - b; });
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NodeItem NodeItem::operator*(const NodeItem &other)
|
|
|
|
|
NodeItem NodeItem::operator*(const NodeItem &other) const
|
|
|
|
|
{
|
|
|
|
|
return arithmetic(other, "multiply", [](float a, float b) { return a * b; });
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NodeItem NodeItem::operator/(const NodeItem &other)
|
|
|
|
|
NodeItem NodeItem::operator/(const NodeItem &other) const
|
|
|
|
|
{
|
|
|
|
|
return arithmetic(other, "divide", [](float a, float b) { return b == 0.0f ? 0.0f : a / b; });
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NodeItem NodeItem::min(const NodeItem &other)
|
|
|
|
|
bool NodeItem::operator==(const NodeItem &other) const
|
|
|
|
|
{
|
|
|
|
|
if (node && node == other.node) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
/* TODO: implement */
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NodeItem NodeItem::min(const NodeItem &other) const
|
|
|
|
|
{
|
|
|
|
|
return arithmetic(other, "min", [](float a, float b) { return std::min(a, b); });
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NodeItem NodeItem::max(const NodeItem &other)
|
|
|
|
|
NodeItem NodeItem::max(const NodeItem &other) const
|
|
|
|
|
{
|
|
|
|
|
return arithmetic(other, "max", [](float a, float b) { return std::max(a, b); });
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NodeItem NodeItem::blend(const NodeItem &a, const NodeItem &b)
|
|
|
|
|
NodeItem NodeItem::blend(const NodeItem &a, const NodeItem &b) const
|
|
|
|
|
{
|
|
|
|
|
return *this * a + (one() - *this) * b;
|
|
|
|
|
return (val(1.0f) - *this) * a + *this * b;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NodeItem NodeItem::to_color3() const
|
|
|
|
|
{
|
|
|
|
|
NodeItem res(graph_);
|
|
|
|
|
std::string t = type();
|
|
|
|
|
NodeItem res = empty();
|
|
|
|
|
if (value) {
|
|
|
|
|
MaterialX::Color3 c;
|
|
|
|
|
if (value->isA<float>()) {
|
|
|
|
|
if (t == "float") {
|
|
|
|
|
float v = value->asA<float>();
|
|
|
|
|
c = {v, v, v};
|
|
|
|
|
}
|
|
|
|
|
else if (value->isA<MaterialX::Color3>()) {
|
|
|
|
|
else if (t == "color3") {
|
|
|
|
|
auto v = value->asA<MaterialX::Color3>();
|
|
|
|
|
c = {v[0], v[1], v[2]};
|
|
|
|
|
}
|
|
|
|
|
else if (value->isA<MaterialX::Color4>()) {
|
|
|
|
|
else if (t == "color4") {
|
|
|
|
|
auto v = value->asA<MaterialX::Color4>();
|
|
|
|
|
c = {v[0], v[1], v[2]};
|
|
|
|
|
}
|
|
|
|
|
else if (value->isA<MaterialX::Vector3>()) {
|
|
|
|
|
else if (t == "vector3") {
|
|
|
|
|
auto v = value->asA<MaterialX::Vector3>();
|
|
|
|
|
c = {v[0], v[1], v[2]};
|
|
|
|
|
}
|
|
|
|
|
else if (value->isA<MaterialX::Vector4>()) {
|
|
|
|
|
else if (t == "vector4") {
|
|
|
|
|
auto v = value->asA<MaterialX::Vector4>();
|
|
|
|
|
c = {v[0], v[1], v[2]};
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
/* Default color */
|
|
|
|
|
c = {0.0f, 0.0f, 0.0f};
|
|
|
|
|
return res;
|
|
|
|
|
}
|
|
|
|
|
res.value = MaterialX::Value::createValue<MaterialX::Color3>(c);
|
|
|
|
|
}
|
|
|
|
|
else if (node) {
|
|
|
|
|
if (t != "color3") {
|
|
|
|
|
return res;
|
|
|
|
|
}
|
|
|
|
|
res.node = node;
|
|
|
|
|
}
|
|
|
|
|
return res;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NodeItem NodeItem::one() const
|
|
|
|
|
bool NodeItem::is_numeric() const
|
|
|
|
|
{
|
|
|
|
|
NodeItem res(graph_);
|
|
|
|
|
res = 1.0f;
|
|
|
|
|
return res;
|
|
|
|
|
std::string t = type();
|
|
|
|
|
return ELEM(t, "float", "color3", "color4", "vector2", "vector3", "vector4");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NodeItem NodeItem::arithmetic(const std::string &mx_category, std::function<float(float)> func)
|
|
|
|
|
std::string NodeItem::type() const
|
|
|
|
|
{
|
|
|
|
|
return value ? value->getTypeString() : node->getType();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NodeItem NodeItem::arithmetic(const std::string &mx_category,
|
|
|
|
|
std::function<float(float)> func) const
|
|
|
|
|
{
|
|
|
|
|
if (!is_numeric()) {
|
|
|
|
|
return empty();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::string t = value ? value->getTypeString() : node->getType();
|
|
|
|
|
NodeItem res(graph_);
|
|
|
|
|
if (value) {
|
|
|
|
|
if (value->isA<float>()) {
|
|
|
|
|
if (t == "float") {
|
|
|
|
|
float v = value->asA<float>();
|
|
|
|
|
res.value = MaterialX::Value::createValue<float>(func(v));
|
|
|
|
|
}
|
|
|
|
|
else if (value->isA<MaterialX::Color3>()) {
|
|
|
|
|
else if (t == "color3") {
|
|
|
|
|
auto v = value->asA<MaterialX::Color3>();
|
|
|
|
|
res.value = MaterialX::Value::createValue<MaterialX::Color3>(
|
|
|
|
|
{func(v[0]), func(v[1]), func(v[2])});
|
|
|
|
|
}
|
|
|
|
|
else if (value->isA<MaterialX::Color4>()) {
|
|
|
|
|
else if (t == "color4") {
|
|
|
|
|
auto v = value->asA<MaterialX::Color4>();
|
|
|
|
|
res.value = MaterialX::Value::createValue<MaterialX::Color4>(
|
|
|
|
|
{func(v[0]), func(v[1]), func(v[2]), func(v[3])});
|
|
|
|
|
}
|
|
|
|
|
else if (value->isA<MaterialX::Vector2>()) {
|
|
|
|
|
else if (t == "vector2") {
|
|
|
|
|
auto v = value->asA<MaterialX::Vector2>();
|
|
|
|
|
res.value = MaterialX::Value::createValue<MaterialX::Vector2>({func(v[0]), func(v[1])});
|
|
|
|
|
}
|
|
|
|
|
else if (value->isA<MaterialX::Vector3>()) {
|
|
|
|
|
else if (t == "vector3") {
|
|
|
|
|
auto v = value->asA<MaterialX::Vector3>();
|
|
|
|
|
res.value = MaterialX::Value::createValue<MaterialX::Vector3>(
|
|
|
|
|
{func(v[0]), func(v[1]), func(v[2])});
|
|
|
|
|
}
|
|
|
|
|
else if (value->isA<MaterialX::Vector4>()) {
|
|
|
|
|
else if (t == "vector4") {
|
|
|
|
|
auto v = value->asA<MaterialX::Vector4>();
|
|
|
|
|
res.value = MaterialX::Value::createValue<MaterialX::Vector4>(
|
|
|
|
|
{func(v[0]), func(v[1]), func(v[2]), func(v[3])});
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
/* Nothing change */
|
|
|
|
|
res.value = value;
|
|
|
|
|
BLI_assert_unreachable();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
@ -185,64 +210,121 @@ NodeItem NodeItem::arithmetic(const std::string &mx_category, std::function<floa
|
|
|
|
|
|
|
|
|
|
NodeItem NodeItem::arithmetic(const NodeItem &other,
|
|
|
|
|
const std::string &mx_category,
|
|
|
|
|
std::function<float(float, float)> func)
|
|
|
|
|
std::function<float(float, float)> func) const
|
|
|
|
|
{
|
|
|
|
|
std::string t1 = value ? value->getTypeString() : node->getType();
|
|
|
|
|
std::string t2 = other.value ? other.value->getTypeString() : other.node->getType();
|
|
|
|
|
if (t1 != t2) {
|
|
|
|
|
return *this;
|
|
|
|
|
NodeItem res = empty();
|
|
|
|
|
if (!is_numeric() || !other.is_numeric()) {
|
|
|
|
|
return res;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NodeItem res(graph_);
|
|
|
|
|
std::string t1 = type();
|
|
|
|
|
std::string t2 = other.type();
|
|
|
|
|
|
|
|
|
|
if (value && other.value) {
|
|
|
|
|
if (value->isA<float>()) {
|
|
|
|
|
float v1 = value->asA<float>();
|
|
|
|
|
float v2 = other.value->asA<float>();
|
|
|
|
|
std::string t = t1;
|
|
|
|
|
auto val1 = value;
|
|
|
|
|
auto val2 = other.value;
|
|
|
|
|
if (t1 != t2) {
|
|
|
|
|
if (t1 == "float") {
|
|
|
|
|
val1 = float_to_type(val1->asA<float>(), t2);
|
|
|
|
|
t = t2;
|
|
|
|
|
}
|
|
|
|
|
else if (t2 == "float") {
|
|
|
|
|
val2 = float_to_type(val2->asA<float>(), t1);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
return res;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (t == "float") {
|
|
|
|
|
float v1 = val1->asA<float>();
|
|
|
|
|
float v2 = val2->asA<float>();
|
|
|
|
|
res.value = MaterialX::Value::createValue<float>(func(v1, v2));
|
|
|
|
|
}
|
|
|
|
|
else if (value->isA<MaterialX::Color3>()) {
|
|
|
|
|
auto v1 = value->asA<MaterialX::Color3>();
|
|
|
|
|
auto v2 = other.value->asA<MaterialX::Color3>();
|
|
|
|
|
else if (t == "color3") {
|
|
|
|
|
auto v1 = val1->asA<MaterialX::Color3>();
|
|
|
|
|
auto v2 = val2->asA<MaterialX::Color3>();
|
|
|
|
|
res.value = MaterialX::Value::createValue<MaterialX::Color3>(
|
|
|
|
|
{func(v1[0], v2[0]), func(v1[1], v2[1]), func(v1[2], v2[2])});
|
|
|
|
|
}
|
|
|
|
|
else if (value->isA<MaterialX::Color4>()) {
|
|
|
|
|
auto v1 = value->asA<MaterialX::Color4>();
|
|
|
|
|
auto v2 = other.value->asA<MaterialX::Color4>();
|
|
|
|
|
else if (t == "color4") {
|
|
|
|
|
auto v1 = val1->asA<MaterialX::Color4>();
|
|
|
|
|
auto v2 = val2->asA<MaterialX::Color4>();
|
|
|
|
|
res.value = MaterialX::Value::createValue<MaterialX::Color4>(
|
|
|
|
|
{func(v1[0], v2[0]), func(v1[1], v2[1]), func(v1[2], v2[2]), func(v1[3], v2[3])});
|
|
|
|
|
}
|
|
|
|
|
else if (value->isA<MaterialX::Vector2>()) {
|
|
|
|
|
auto v1 = value->asA<MaterialX::Vector2>();
|
|
|
|
|
auto v2 = other.value->asA<MaterialX::Vector2>();
|
|
|
|
|
else if (t == "vector2") {
|
|
|
|
|
auto v1 = val1->asA<MaterialX::Vector2>();
|
|
|
|
|
auto v2 = val2->asA<MaterialX::Vector2>();
|
|
|
|
|
res.value = MaterialX::Value::createValue<MaterialX::Vector2>(
|
|
|
|
|
{func(v1[0], v2[0]), func(v1[1], v2[1])});
|
|
|
|
|
}
|
|
|
|
|
else if (value->isA<MaterialX::Vector3>()) {
|
|
|
|
|
auto v1 = value->asA<MaterialX::Vector3>();
|
|
|
|
|
auto v2 = other.value->asA<MaterialX::Vector3>();
|
|
|
|
|
else if (t == "vector3") {
|
|
|
|
|
auto v1 = val1->asA<MaterialX::Vector3>();
|
|
|
|
|
auto v2 = val2->asA<MaterialX::Vector3>();
|
|
|
|
|
res.value = MaterialX::Value::createValue<MaterialX::Vector3>(
|
|
|
|
|
{func(v1[0], v2[0]), func(v1[1], v2[1]), func(v1[2], v2[2])});
|
|
|
|
|
}
|
|
|
|
|
else if (value->isA<MaterialX::Vector4>()) {
|
|
|
|
|
auto v1 = value->asA<MaterialX::Vector4>();
|
|
|
|
|
auto v2 = other.value->asA<MaterialX::Vector4>();
|
|
|
|
|
else if (t == "vector4") {
|
|
|
|
|
auto v1 = val1->asA<MaterialX::Vector4>();
|
|
|
|
|
auto v2 = val2->asA<MaterialX::Vector4>();
|
|
|
|
|
res.value = MaterialX::Value::createValue<MaterialX::Vector4>(
|
|
|
|
|
{func(v1[0], v2[0]), func(v1[1], v2[1]), func(v1[2], v2[2]), func(v1[3], v2[3])});
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
/* default color */
|
|
|
|
|
res.value = value;
|
|
|
|
|
BLI_assert_unreachable();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
res.node = graph_->addNode(mx_category, MaterialX::EMPTY_STRING, t1);
|
|
|
|
|
res.set_input("in1", *this);
|
|
|
|
|
res.set_input("in2", other);
|
|
|
|
|
std::string t = t1;
|
|
|
|
|
auto val1 = *this;
|
|
|
|
|
auto val2 = other;
|
|
|
|
|
if (t1 != t2) {
|
|
|
|
|
if (val1.value && t1 == "float") {
|
|
|
|
|
val1.value = float_to_type(val1.value->asA<float>(), t2);
|
|
|
|
|
t = t2;
|
|
|
|
|
}
|
|
|
|
|
else if (val2.value && t2 == "float") {
|
|
|
|
|
val2.value = float_to_type(val2.value->asA<float>(), t1);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
return res;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
res.node = graph_->addNode(mx_category, MaterialX::EMPTY_STRING, t);
|
|
|
|
|
res.set_input("in1", val1);
|
|
|
|
|
res.set_input("in2", val2);
|
|
|
|
|
}
|
|
|
|
|
return res;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
MaterialX::ValuePtr NodeItem::float_to_type(float v, std::string t) const
|
|
|
|
|
{
|
|
|
|
|
if (t == "float") {
|
|
|
|
|
return MaterialX::Value::createValue<float>(v);
|
|
|
|
|
}
|
|
|
|
|
if (t == "color3") {
|
|
|
|
|
return MaterialX::Value::createValue<MaterialX::Color3>({v, v, v});
|
|
|
|
|
}
|
|
|
|
|
if (t == "color4") {
|
|
|
|
|
return MaterialX::Value::createValue<MaterialX::Color4>({v, v, v, 1.0f});
|
|
|
|
|
}
|
|
|
|
|
if (t == "vector2") {
|
|
|
|
|
return MaterialX::Value::createValue<MaterialX::Vector2>({v, v});
|
|
|
|
|
}
|
|
|
|
|
if (t == "vector3") {
|
|
|
|
|
return MaterialX::Value::createValue<MaterialX::Vector3>({v, v, v});
|
|
|
|
|
}
|
|
|
|
|
if (t == "vector4") {
|
|
|
|
|
return MaterialX::Value::createValue<MaterialX::Vector4>({v, v, v, 1.0f});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
BLI_assert_unreachable();
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NodeParser::NodeParser(MaterialX::GraphElement *graph,
|
|
|
|
|
const Depsgraph *depsgraph,
|
|
|
|
|
const Material *material,
|
|
|
|
|