/* SPDX-License-Identifier: Apache-2.0 * Copyright 2011-2022 Blender Foundation */ #include "graph/node_xml.h" #include "util/foreach.h" #include "util/string.h" #include "util/transform.h" CCL_NAMESPACE_BEGIN static bool xml_read_boolean(const char *value) { return string_iequals(value, "true") || (atoi(value) != 0); } static const char *xml_write_boolean(bool value) { return (value) ? "true" : "false"; } template static void xml_read_float_array(T &value, xml_attribute attr) { vector tokens; string_split(tokens, attr.value()); if (tokens.size() % VECTOR_SIZE != 0) { return; } value.resize(tokens.size() / VECTOR_SIZE); for (size_t i = 0; i < value.size(); i++) { float *value_float = (float *)&value[i]; for (size_t j = 0; j < VECTOR_SIZE; j++) value_float[j] = (float)atof(tokens[i * VECTOR_SIZE + j].c_str()); } } void xml_read_node(XMLReader &reader, Node *node, xml_node xml_node) { xml_attribute name_attr = xml_node.attribute("name"); if (name_attr) { node->name = ustring(name_attr.value()); } foreach (const SocketType &socket, node->type->inputs) { if (socket.type == SocketType::CLOSURE || socket.type == SocketType::UNDEFINED) { continue; } if (socket.flags & SocketType::INTERNAL) { continue; } xml_attribute attr = xml_node.attribute(socket.name.c_str()); if (!attr) { continue; } switch (socket.type) { case SocketType::BOOLEAN: { node->set(socket, xml_read_boolean(attr.value())); break; } case SocketType::BOOLEAN_ARRAY: { vector tokens; string_split(tokens, attr.value()); array value; value.resize(tokens.size()); for (size_t i = 0; i < value.size(); i++) value[i] = xml_read_boolean(tokens[i].c_str()); node->set(socket, value); break; } case SocketType::FLOAT: { node->set(socket, (float)atof(attr.value())); break; } case SocketType::FLOAT_ARRAY: { array value; xml_read_float_array<1>(value, attr); node->set(socket, value); break; } case SocketType::INT: { node->set(socket, (int)atoi(attr.value())); break; } case SocketType::UINT: { node->set(socket, (uint)atoi(attr.value())); break; } case SocketType::INT_ARRAY: { vector tokens; string_split(tokens, attr.value()); array value; value.resize(tokens.size()); for (size_t i = 0; i < value.size(); i++) { value[i] = (int)atoi(attr.value()); } node->set(socket, value); break; } case SocketType::COLOR: case SocketType::VECTOR: case SocketType::POINT: case SocketType::NORMAL: { array value; xml_read_float_array<3>(value, attr); if (value.size() == 1) { node->set(socket, value[0]); } break; } case SocketType::COLOR_ARRAY: case SocketType::VECTOR_ARRAY: case SocketType::POINT_ARRAY: case SocketType::NORMAL_ARRAY: { array value; xml_read_float_array<3>(value, attr); node->set(socket, value); break; } case SocketType::POINT2: { array value; xml_read_float_array<2>(value, attr); if (value.size() == 1) { node->set(socket, value[0]); } break; } case SocketType::POINT2_ARRAY: { array value; xml_read_float_array<2>(value, attr); node->set(socket, value); break; } case SocketType::STRING: { node->set(socket, attr.value()); break; } case SocketType::ENUM: { ustring value(attr.value()); if (socket.enum_values->exists(value)) { node->set(socket, value); } else { fprintf(stderr, "Unknown value \"%s\" for attribute \"%s\".\n", value.c_str(), socket.name.c_str()); } break; } case SocketType::STRING_ARRAY: { vector tokens; string_split(tokens, attr.value()); array value; value.resize(tokens.size()); for (size_t i = 0; i < value.size(); i++) { value[i] = ustring(tokens[i]); } node->set(socket, value); break; } case SocketType::TRANSFORM: { array value; xml_read_float_array<12>(value, attr); if (value.size() == 1) { node->set(socket, value[0]); } break; } case SocketType::TRANSFORM_ARRAY: { array value; xml_read_float_array<12>(value, attr); node->set(socket, value); break; } case SocketType::NODE: { ustring value(attr.value()); map::iterator it = reader.node_map.find(value); if (it != reader.node_map.end()) { Node *value_node = it->second; if (value_node->is_a(socket.node_type)) node->set(socket, it->second); } break; } case SocketType::NODE_ARRAY: { vector tokens; string_split(tokens, attr.value()); array value; value.resize(tokens.size()); for (size_t i = 0; i < value.size(); i++) { map::iterator it = reader.node_map.find(ustring(tokens[i])); if (it != reader.node_map.end()) { Node *value_node = it->second; value[i] = (value_node->is_a(socket.node_type)) ? value_node : NULL; } else { value[i] = NULL; } } node->set(socket, value); break; } case SocketType::CLOSURE: case SocketType::UNDEFINED: break; } } if (!node->name.empty()) reader.node_map[node->name] = node; } xml_node xml_write_node(Node *node, xml_node xml_root) { xml_node xml_node = xml_root.append_child(node->type->name.c_str()); xml_node.append_attribute("name") = node->name.c_str(); foreach (const SocketType &socket, node->type->inputs) { if (socket.type == SocketType::CLOSURE || socket.type == SocketType::UNDEFINED) { continue; } if (socket.flags & SocketType::INTERNAL) { continue; } if (node->has_default_value(socket)) { continue; } xml_attribute attr = xml_node.append_attribute(socket.name.c_str()); switch (socket.type) { case SocketType::BOOLEAN: { attr = xml_write_boolean(node->get_bool(socket)); break; } case SocketType::BOOLEAN_ARRAY: { std::stringstream ss; const array &value = node->get_bool_array(socket); for (size_t i = 0; i < value.size(); i++) { ss << xml_write_boolean(value[i]); if (i != value.size() - 1) ss << " "; } attr = ss.str().c_str(); break; } case SocketType::FLOAT: { attr = (double)node->get_float(socket); break; } case SocketType::FLOAT_ARRAY: { std::stringstream ss; const array &value = node->get_float_array(socket); for (size_t i = 0; i < value.size(); i++) { ss << value[i]; if (i != value.size() - 1) { ss << " "; } } attr = ss.str().c_str(); break; } case SocketType::INT: { attr = node->get_int(socket); break; } case SocketType::UINT: { attr = node->get_uint(socket); break; } case SocketType::INT_ARRAY: { std::stringstream ss; const array &value = node->get_int_array(socket); for (size_t i = 0; i < value.size(); i++) { ss << value[i]; if (i != value.size() - 1) { ss << " "; } } attr = ss.str().c_str(); break; } case SocketType::COLOR: case SocketType::VECTOR: case SocketType::POINT: case SocketType::NORMAL: { float3 value = node->get_float3(socket); attr = string_printf("%g %g %g", (double)value.x, (double)value.y, (double)value.z).c_str(); break; } case SocketType::COLOR_ARRAY: case SocketType::VECTOR_ARRAY: case SocketType::POINT_ARRAY: case SocketType::NORMAL_ARRAY: { std::stringstream ss; const array &value = node->get_float3_array(socket); for (size_t i = 0; i < value.size(); i++) { ss << string_printf( "%g %g %g", (double)value[i].x, (double)value[i].y, (double)value[i].z); if (i != value.size() - 1) { ss << " "; } } attr = ss.str().c_str(); break; } case SocketType::POINT2: { float2 value = node->get_float2(socket); attr = string_printf("%g %g", (double)value.x, (double)value.y).c_str(); break; } case SocketType::POINT2_ARRAY: { std::stringstream ss; const array &value = node->get_float2_array(socket); for (size_t i = 0; i < value.size(); i++) { ss << string_printf("%g %g", (double)value[i].x, (double)value[i].y); if (i != value.size() - 1) { ss << " "; } } attr = ss.str().c_str(); break; } case SocketType::STRING: case SocketType::ENUM: { attr = node->get_string(socket).c_str(); break; } case SocketType::STRING_ARRAY: { std::stringstream ss; const array &value = node->get_string_array(socket); for (size_t i = 0; i < value.size(); i++) { ss << value[i]; if (i != value.size() - 1) { ss << " "; } } attr = ss.str().c_str(); break; } case SocketType::TRANSFORM: { Transform tfm = node->get_transform(socket); std::stringstream ss; for (int i = 0; i < 3; i++) { ss << string_printf("%g %g %g %g ", (double)tfm[i][0], (double)tfm[i][1], (double)tfm[i][2], (double)tfm[i][3]); } ss << string_printf("%g %g %g %g", 0.0, 0.0, 0.0, 1.0); attr = ss.str().c_str(); break; } case SocketType::TRANSFORM_ARRAY: { std::stringstream ss; const array &value = node->get_transform_array(socket); for (size_t j = 0; j < value.size(); j++) { const Transform &tfm = value[j]; for (int i = 0; i < 3; i++) { ss << string_printf("%g %g %g %g ", (double)tfm[i][0], (double)tfm[i][1], (double)tfm[i][2], (double)tfm[i][3]); } ss << string_printf("%g %g %g %g", 0.0, 0.0, 0.0, 1.0); if (j != value.size() - 1) { ss << " "; } } attr = ss.str().c_str(); break; } case SocketType::NODE: { Node *value = node->get_node(socket); if (value) { attr = value->name.c_str(); } break; } case SocketType::NODE_ARRAY: { std::stringstream ss; const array &value = node->get_node_array(socket); for (size_t i = 0; i < value.size(); i++) { if (value[i]) { ss << value[i]->name.c_str(); } if (i != value.size() - 1) { ss << " "; } } attr = ss.str().c_str(); break; } case SocketType::CLOSURE: case SocketType::UNDEFINED: break; } } return xml_node; } CCL_NAMESPACE_END