diff --git a/intern/cycles/graph/node_xml.cpp b/intern/cycles/graph/node_xml.cpp
index 85f8e35e86f56ca379750635fd6f530963858d7a..7ff994b0c6a6852bf8f58080b65759b9d6f2994c 100644
--- a/intern/cycles/graph/node_xml.cpp
+++ b/intern/cycles/graph/node_xml.cpp
@@ -7,429 +7,552 @@
 #include "util/foreach.h"
 #include "util/string.h"
 #include "util/transform.h"
+#include "util/path.h"
 
-CCL_NAMESPACE_BEGIN
-
-static bool xml_read_boolean(const char *value)
-{
-  return string_iequals(value, "true") || (atoi(value) != 0);
-}
+#include "scene/object.h"
 
-static const char *xml_write_boolean(bool value)
-{
-  return (value) ? "true" : "false";
-}
+CCL_NAMESPACE_BEGIN
 
-template<int VECTOR_SIZE, typename T>
-static void xml_read_float_array(T &value, xml_attribute attr)
+// Function to write an array to a binary file
+template<typename T>
+string write_array_to_binary_file(XMLWriter& writer, const array<T>& data)
 {
-  vector<string> tokens;
-  string_split(tokens, attr.value());
+    std::stringstream ss;
+    ss << writer.offset;
 
-  if (tokens.size() % VECTOR_SIZE != 0) {
-    return;
-  }
+    // Write the size of the vector first
+    size_t data_size = data.size();
+    writer.file.write(reinterpret_cast<const char*>(&data_size), sizeof(size_t));
+    writer.offset += sizeof(size_t);
 
-  value.resize(tokens.size() / VECTOR_SIZE);
-  for (size_t i = 0; i < value.size(); i++) {
-    float *value_float = (float *)&value[i];
+    // Write the actual data to the file
+    writer.file.write(reinterpret_cast<const char*>(data.data()), data_size * sizeof(T));
+    writer.offset += data_size * sizeof(T);
 
-    for (size_t j = 0; j < VECTOR_SIZE; j++) {
-      value_float[j] = (float)atof(tokens[i * VECTOR_SIZE + j].c_str());
-    }
-  }
+    return ss.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());
-  }
+bool xml_pointer_to_name_check(Node* node) {
+    if (node->name == "default_background" ||
+        node->name == "default_empty" ||
+        node->name == "default_light" ||
+        node->name == "default_surface" ||
+        node->name == "default_volume") {
 
-  foreach (const SocketType &socket, node->type->inputs) {
-    if (socket.type == SocketType::CLOSURE || socket.type == SocketType::UNDEFINED) {
-      continue;
+        return false;
     }
-    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<string> tokens;
-        string_split(tokens, attr.value());
 
-        array<bool> 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<float> 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::UINT64: {
-        node->set(socket, (uint64_t)strtoull(attr.value(), nullptr, 10));
-        break;
-      }
-      case SocketType::INT_ARRAY: {
-        vector<string> tokens;
-        string_split(tokens, attr.value());
+    return true;
+}
+string xml_pointer_to_name(void *ptr) 
+{
+    // Convert void* to name
+    size_t ptrAsSizeT = reinterpret_cast<size_t>(ptr);
+    std::string ptrAsString = std::to_string(ptrAsSizeT);
+    return ptrAsString;
+}
 
-        array<int> 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<float3> 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<float3> value;
-        xml_read_float_array<3>(value, attr);
-        node->set(socket, value);
-        break;
-      }
-      case SocketType::POINT2: {
-        array<float2> value;
-        xml_read_float_array<2>(value, attr);
-        if (value.size() == 1) {
-          node->set(socket, value[0]);
-        }
-        break;
-      }
-      case SocketType::POINT2_ARRAY: {
-        array<float2> 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<string> tokens;
-        string_split(tokens, attr.value());
+string xml_fix_tag(ustring tag)
+{
+    string str = tag.string();
+    std::replace(str.begin(), str.end(), ' ', '_');
 
-        array<ustring> 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<Transform> value;
-        xml_read_float_array<12>(value, attr);
-        if (value.size() == 1) {
-          node->set(socket, value[0]);
-        }
-        break;
-      }
-      case SocketType::TRANSFORM_ARRAY: {
-        array<Transform> value;
-        xml_read_float_array<12>(value, attr);
-        node->set(socket, value);
-        break;
-      }
-      case SocketType::NODE: {
-        ustring value(attr.value());
-        map<ustring, Node *>::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<string> tokens;
-        string_split(tokens, attr.value());
+    return str;
+}
 
-        array<Node *> value;
-        value.resize(tokens.size());
-        for (size_t i = 0; i < value.size(); i++) {
-          map<ustring, Node *>::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:
-      case SocketType::NUM_TYPES:
-        break;
-    }
-  }
+//static bool xml_read_boolean(const char *value)
+//{
+//  return string_iequals(value, "true") || (atoi(value) != 0);
+//}
 
-  if (!node->name.empty()) {
-    reader.node_map[node->name] = node;
-  }
+static const char *xml_write_boolean(bool value)
+{
+  return (value) ? "true" : "false";
 }
 
-xml_node xml_write_node(Node *node, xml_node xml_root)
-{
-  xml_node xml_node = xml_root.append_child(node->type->name.c_str());
+//template<int VECTOR_SIZE, typename T>
+//static void xml_read_float_array(T &value, xml_attribute attr)
+//{
+//  vector<string> 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());
+//    }
+//  }
+//}
 
-  xml_node.append_attribute("name") = node->name.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.ui_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<string> tokens;
+//        string_split(tokens, attr.value());
+//
+//        array<bool> 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<float> 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::UINT64: {
+//        node->set(socket, (uint64_t)strtoull(attr.value(), nullptr, 10));
+//        break;
+//      }
+//      case SocketType::INT_ARRAY: {
+//        vector<string> tokens;
+//        string_split(tokens, attr.value());
+//
+//        array<int> 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<float3> 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<float3> value;
+//        xml_read_float_array<3>(value, attr);
+//        node->set(socket, value);
+//        break;
+//      }
+//      case SocketType::POINT2: {
+//        array<float2> value;
+//        xml_read_float_array<2>(value, attr);
+//        if (value.size() == 1) {
+//          node->set(socket, value[0]);
+//        }
+//        break;
+//      }
+//      case SocketType::POINT2_ARRAY: {
+//        array<float2> 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.ui_name.c_str());
+//        }
+//        break;
+//      }
+//      case SocketType::STRING_ARRAY: {
+//        vector<string> tokens;
+//        string_split(tokens, attr.value());
+//
+//        array<ustring> 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<Transform> value;
+//        xml_read_float_array<12>(value, attr);
+//        if (value.size() == 1) {
+//          node->set(socket, value[0]);
+//        }
+//        break;
+//      }
+//      case SocketType::TRANSFORM_ARRAY: {
+//        array<Transform> value;
+//        xml_read_float_array<12>(value, attr);
+//        node->set(socket, value);
+//        break;
+//      }
+//      case SocketType::NODE: {
+//        ustring value(attr.value());
+//        map<ustring, Node *>::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<string> tokens;
+//        string_split(tokens, attr.value());
+//
+//        array<Node *> value;
+//        value.resize(tokens.size());
+//        for (size_t i = 0; i < value.size(); i++) {
+//          map<ustring, Node *>::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:
+//      case SocketType::NUM_TYPES:
+//        break;
+//    }
+//  }
+//
+//  if (!node->name.empty()) {
+//    reader.node_map[node->name] = node;
+//  }
+//}
 
-  foreach (const SocketType &socket, node->type->inputs) {
+void xml_write_node_socket(XMLWriter& writer, Node* node, xml_node xml_root, const SocketType& socket, xml_node xml_node_main, string xml_node_name)
+{
     if (socket.type == SocketType::CLOSURE || socket.type == SocketType::UNDEFINED) {
-      continue;
+        return;
     }
     if (socket.flags & SocketType::INTERNAL) {
-      continue;
+        return;
     }
-    if (node->has_default_value(socket)) {
-      continue;
+    if (socket.default_value && node->has_default_value(socket)) {
+        return;
     }
 
-    xml_attribute attr = xml_node.append_attribute(socket.name.c_str());
+    string attr;
 
     switch (socket.type) {
-      case SocketType::BOOLEAN: {
+    case SocketType::BOOLEAN: {
         attr = xml_write_boolean(node->get_bool(socket));
         break;
-      }
-      case SocketType::BOOLEAN_ARRAY: {
+    }
+    case SocketType::BOOLEAN_ARRAY: {
         std::stringstream ss;
-        const array<bool> &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();
+        const array<bool>& value = node->get_bool_array(socket);
+        ss << write_array_to_binary_file(writer, value);
+        attr = ss.str();
         break;
-      }
-      case SocketType::FLOAT: {
-        attr = (double)node->get_float(socket);
+    }
+    case SocketType::FLOAT: {
+        std::stringstream ss;
+        ss << (double)node->get_float(socket);
+        attr = ss.str();
         break;
-      }
-      case SocketType::FLOAT_ARRAY: {
+    }
+    case SocketType::FLOAT_ARRAY: {
         std::stringstream ss;
-        const array<float> &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();
+        const array<float>& value = node->get_float_array(socket);
+        //for (size_t i = 0; i < value.size(); i++) {
+        //  ss << value[i];
+        //  if (i != value.size() - 1) {
+        //    ss << " ";
+        //  }
+        //}
+        ss << write_array_to_binary_file(writer, value);
+        attr = ss.str();
         break;
-      }
-      case SocketType::INT: {
-        attr = node->get_int(socket);
+    }
+    case SocketType::INT: {
+        std::stringstream ss;
+        ss << node->get_int(socket);
+        attr = ss.str();
         break;
-      }
-      case SocketType::UINT: {
-        attr = node->get_uint(socket);
+    }
+    case SocketType::UINT: {
+        std::stringstream ss;
+        ss << node->get_uint(socket);
+        attr = ss.str();
         break;
-      }
-      case SocketType::UINT64: {
-        attr = node->get_uint64(socket);
+    }
+    case SocketType::UINT64: {
+        std::stringstream ss;
+        ss << node->get_uint64(socket);
+        attr = ss.str();
         break;
-      }
-      case SocketType::INT_ARRAY: {
+    }
+    case SocketType::INT_ARRAY: {
         std::stringstream ss;
-        const array<int> &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();
+        const array<int>& value = node->get_int_array(socket);
+        //for (size_t i = 0; i < value.size(); i++) {
+        //  ss << value[i];
+        //  if (i != value.size() - 1) {
+        //    ss << " ";
+        //  }
+        //}
+        ss << write_array_to_binary_file(writer, value);
+        attr = ss.str();
         break;
-      }
-      case SocketType::COLOR:
-      case SocketType::VECTOR:
-      case SocketType::POINT:
-      case SocketType::NORMAL: {
+    }
+    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();
+            string_printf("%g %g %g %g", (double)value.x, (double)value.y, (double)value.z, (double)value.w);
         break;
-      }
-      case SocketType::COLOR_ARRAY:
-      case SocketType::VECTOR_ARRAY:
-      case SocketType::POINT_ARRAY:
-      case SocketType::NORMAL_ARRAY: {
+    }
+    case SocketType::COLOR_ARRAY:
+    case SocketType::VECTOR_ARRAY:
+    case SocketType::POINT_ARRAY:
+    case SocketType::NORMAL_ARRAY: {
         std::stringstream ss;
-        const array<float3> &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();
+        const array<float3>& value = node->get_float3_array(socket);
+        //for (size_t i = 0; i < value.size(); i++) {
+        //  ss << string_printf(
+        //      "%g %g %g %g", (double)value[i].x, (double)value[i].y, (double)value[i].z, (double)value[i].w);
+        //  if (i != value.size() - 1) {
+        //    ss << " ";
+        //  }
+        //}
+        ss << write_array_to_binary_file(writer, value);
+        attr = ss.str();
         break;
-      }
-      case SocketType::POINT2: {
+    }
+    case SocketType::POINT2: {
         float2 value = node->get_float2(socket);
-        attr = string_printf("%g %g", (double)value.x, (double)value.y).c_str();
+        attr = string_printf("%g %g", (double)value.x, (double)value.y);
         break;
-      }
-      case SocketType::POINT2_ARRAY: {
+    }
+    case SocketType::POINT2_ARRAY: {
         std::stringstream ss;
-        const array<float2> &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();
+        const array<float2>& 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 << " ";
+        //  }
+        //}
+        ss << write_array_to_binary_file(writer, value);
+        attr = ss.str();
         break;
-      }
-      case SocketType::STRING:
-      case SocketType::ENUM: {
-        attr = node->get_string(socket).c_str();
+    }
+    case SocketType::ENUM:
+    case SocketType::STRING: {
+        std::stringstream ss;
+        ss << node->get_string(socket);
+        attr = ss.str();
         break;
-      }
-      case SocketType::STRING_ARRAY: {
+    }
+    //case SocketType::ENUM: {
+    //    std::stringstream ss;
+    //    ss << node->get_int(socket);
+    //    attr = ss.str();
+    //    break;
+    //}
+    case SocketType::STRING_ARRAY: {
         std::stringstream ss;
-        const array<ustring> &value = node->get_string_array(socket);
+        const array<ustring>& value = node->get_string_array(socket);
         for (size_t i = 0; i < value.size(); i++) {
-          ss << value[i];
-          if (i != value.size() - 1) {
-            ss << " ";
-          }
+            ss << value[i];
+            if (i != value.size() - 1) {
+                ss << " ";
+            }
         }
-        attr = ss.str().c_str();
+        attr = ss.str();
         break;
-      }
-      case SocketType::TRANSFORM: {
+    }
+    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]);
+        
+        Object* ob = dynamic_cast<Object*>(node);
+        if (!ob || ob->get_geometry() && (ob->get_geometry()->geometry_type == Geometry::Type::VOLUME || !ob->get_geometry()->transform_applied)) {
+            std::stringstream ss;
+            for (int i = 0; i < 3; i++) {
+                if (i == 2)
+                    ss << string_printf("%g %g %g %g",
+                        (double)tfm[i][0],
+                        (double)tfm[i][1],
+                        (double)tfm[i][2],
+                        (double)tfm[i][3]);
+                else
+                    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();
         }
-        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: {
+    }
+    case SocketType::TRANSFORM_ARRAY: {
         std::stringstream ss;
-        const array<Transform> &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();
+        const array<Transform>& 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++) {
+        //    if (i == 2)
+        //      ss << string_printf("%g %g %g %g",
+        //          (double)tfm[i][0],
+        //          (double)tfm[i][1],
+        //          (double)tfm[i][2],
+        //          (double)tfm[i][3]);
+        //    else
+        //      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 << " ";
+        //  }
+        //}
+        ss << write_array_to_binary_file(writer, value);
+        attr = ss.str();
         break;
-      }
-      case SocketType::NODE: {
-        Node *value = node->get_node(socket);
+    }
+    case SocketType::NODE: {
+        Node* value = node->get_node(socket);
         if (value) {
-          attr = value->name.c_str();
+            if (xml_pointer_to_name_check(value))
+                attr = xml_pointer_to_name(value);
+            else
+                attr = value->name.string();
         }
         break;
-      }
-      case SocketType::NODE_ARRAY: {
+    }
+    case SocketType::NODE_ARRAY: {
         std::stringstream ss;
-        const array<Node *> &value = node->get_node_array(socket);
+        const array<Node*>& 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 << " ";
-          }
+            if (value[i]) {
+                if (xml_pointer_to_name_check(value[i]))
+                    ss << xml_pointer_to_name(value[i]);
+                else
+                    ss << value[i]->name;
+            }
+            if (i != value.size() - 1) {
+                ss << " ";
+            }
         }
-        attr = ss.str().c_str();
+        attr = ss.str();
         break;
-      }
-      case SocketType::CLOSURE:
-      case SocketType::UNDEFINED:
-      case SocketType::NUM_TYPES:
+    }
+    case SocketType::CLOSURE:
+    case SocketType::UNDEFINED:
+    case SocketType::NUM_TYPES:
         break;
     }
+
+    if (attr.empty())
+        return;
+
+    string socket_file = xml_node_name + "_" + socket.name.string();
+
+    xml_node xml_node_socket = xml_node_main.append_child("socket");
+
+    xml_attribute attr_name = xml_node_socket.append_attribute("name");
+    attr_name = socket.name.c_str();
+
+    xml_attribute attr_ui_name = xml_node_socket.append_attribute("ui_name");
+    attr_ui_name = socket.ui_name.c_str();
+
+    xml_attribute attr_value = xml_node_socket.append_attribute("value");
+    attr_value = attr.c_str();
+
+    xml_attribute attr_type_name = xml_node_socket.append_attribute("type_name");
+    attr_type_name = SocketType::type_name(socket.type).c_str();
+}
+
+xml_node xml_write_node(XMLWriter& writer, Node* node, xml_node xml_root)
+{
+  xml_node xml_node_main = xml_root.append_child(node->type->name.c_str());
+
+  string xml_node_name = node->name.string();
+  if (xml_pointer_to_name_check(node))
+      xml_node_name = xml_pointer_to_name(node);
+
+  xml_node_main.append_attribute("name") = xml_node_name.c_str();
+  xml_node_main.append_attribute("ui_name") = node->name.string().c_str();
+
+  foreach (const SocketType &socket, node->type->inputs) {
+      xml_write_node_socket(writer, node, xml_root, socket, xml_node_main, xml_node_name);
   }
 
-  return xml_node;
+  //foreach(const SocketType& socket, node->type->outputs) {
+  //    xml_write_node_socket(writer, node, xml_root, socket, xml_node_main, xml_node_name);
+  //}
+
+  return xml_node_main;
 }
 
 CCL_NAMESPACE_END
diff --git a/intern/cycles/graph/node_xml.h b/intern/cycles/graph/node_xml.h
index 56dd200dfcaa419ed37f39ec9d066cdd55b1dbfe..761dc0a60154cb11472ecc1e1148568f86c6e703 100644
--- a/intern/cycles/graph/node_xml.h
+++ b/intern/cycles/graph/node_xml.h
@@ -12,11 +12,19 @@
 
 CCL_NAMESPACE_BEGIN
 
-struct XMLReader {
-  map<ustring, Node *> node_map;
+//struct XMLReader {
+//  map<ustring, Node *> node_map;
+//};
+
+struct XMLWriter {
+  //std::string base;       /* Base path to current file. */
+  size_t offset = 0;
+  std::ofstream file;
 };
 
-void xml_read_node(XMLReader &reader, Node *node, xml_node xml_node);
-xml_node xml_write_node(Node *node, xml_node xml_root);
+//void xml_read_node(XMLReader &reader, Node *node, xml_node xml_node);
+xml_node xml_write_node(XMLWriter &writer, Node *node, xml_node xml_root);
+string xml_pointer_to_name(void* ptr);
+bool xml_pointer_to_name_check(Node* node);
 
 CCL_NAMESPACE_END
diff --git a/intern/cycles/scene/CMakeLists.txt b/intern/cycles/scene/CMakeLists.txt
index 874b38525ed2b20115cd43e22150e010725a70db..a17af79891f14d7399525d28f0c1e42722064329 100644
--- a/intern/cycles/scene/CMakeLists.txt
+++ b/intern/cycles/scene/CMakeLists.txt
@@ -41,6 +41,8 @@ set(SRC
   pass.cpp
   curves.cpp
   scene.cpp
+  scene_read_xml.cpp
+  scene_write_xml.cpp
   shader.cpp
   shader_graph.cpp
   shader_nodes.cpp
@@ -80,6 +82,8 @@ set(SRC_HEADERS
   pointcloud.h
   curves.h
   scene.h
+  scene_read_xml.h
+  scene_write_xml.h
   shader.h
   shader_graph.h
   shader_nodes.h
diff --git a/intern/cycles/scene/image.cpp b/intern/cycles/scene/image.cpp
index 1f4d129950d142a9867e830df291a48a8890250d..5b53901c6371f198a571e572a23d887ee0537f1e 100644
--- a/intern/cycles/scene/image.cpp
+++ b/intern/cycles/scene/image.cpp
@@ -809,7 +809,10 @@ void ImageManager::device_load_image(Device *device, Scene *scene, size_t slot,
   }
 
   /* Cleanup memory in image loader. */
-  img->loader->cleanup();
+  const char* filepath_xml = getenv("CYCLES_XML_PATH");
+  if (filepath_xml == nullptr) {
+      img->loader->cleanup();
+  }
   img->need_load = false;
 }
 
diff --git a/intern/cycles/scene/scene.cpp b/intern/cycles/scene/scene.cpp
index 341e6ec37a74ba4efbb6eae357f93e4d51819d72..8e931f140971ccb2d9631a322e0d7d09a5aa5d07 100644
--- a/intern/cycles/scene/scene.cpp
+++ b/intern/cycles/scene/scene.cpp
@@ -28,6 +28,8 @@
 #include "scene/volume.h"
 #include "session/session.h"
 
+#include "scene/scene_write_xml.h"
+
 #include "util/foreach.h"
 #include "util/guarded_allocator.h"
 #include "util/log.h"
@@ -357,6 +359,12 @@ void Scene::device_update(Device *device_, Progress &progress)
               << "  Peak: " << string_human_readable_number(mem_peak) << " ("
               << string_human_readable_size(mem_peak) << ")";
   }
+
+  //////////////////////////////EXPORT/////////////////////////////////////
+  //static void xml_read_scene(XMLReadState & state, xml_node scene_node)
+  const char* filepath_xml = getenv("CYCLES_XML_PATH");
+  scene_write_xml_file(this, filepath_xml);
+  /////////////////////////////////////////////////////////////////////////
 }
 
 Scene::MotionType Scene::need_motion() const
diff --git a/intern/cycles/scene/scene_read_xml.cpp b/intern/cycles/scene/scene_read_xml.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..cf6ca83a11dd5ad4a1eedc915f5f21b0b2ce6692
--- /dev/null
+++ b/intern/cycles/scene/scene_read_xml.cpp
@@ -0,0 +1,855 @@
+/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
+ *
+ * SPDX-License-Identifier: Apache-2.0 */
+
+#include "scene_read_xml.h"
+
+#include <stdio.h>
+
+#include <algorithm>
+#include <iterator>
+#include <sstream>
+
+#include "graph/node_xml.h"
+
+#include "scene/alembic.h"
+#include "scene/background.h"
+#include "scene/camera.h"
+#include "scene/film.h"
+#include "scene/integrator.h"
+#include "scene/light.h"
+#include "scene/mesh.h"
+#include "scene/object.h"
+#include "scene/osl.h"
+#include "scene/scene.h"
+#include "scene/shader.h"
+#include "scene/shader_graph.h"
+#include "scene/shader_nodes.h"
+
+#include "subd/patch.h"
+#include "subd/split.h"
+
+#include "util/foreach.h"
+#include "util/path.h"
+#include "util/projection.h"
+#include "util/transform.h"
+#include "util/xml.h"
+
+ /* macros for importing */
+#define RAD2DEGF(_rad) ((_rad) * (float)(180.0 / M_PI))
+#define DEG2RADF(_deg) ((_deg) * (float)(M_PI / 180.0))
+
+CCL_NAMESPACE_BEGIN
+
+/* Attribute Reading */
+
+//bool scene_read_xml_int(int* value, xml_node node, const char* name)
+//{
+//    xml_attribute attr = node.attribute(name);
+//
+//    if (attr) {
+//        *value = atoi(attr.value());
+//        return true;
+//    }
+//
+//    return false;
+//}
+//
+//bool scene_read_xml_int_array(vector<int>& value, xml_node node, const char* name)
+//{
+//    xml_attribute attr = node.attribute(name);
+//
+//    if (attr) {
+//        vector<string> tokens;
+//        string_split(tokens, attr.value());
+//
+//        foreach(const string & token, tokens)
+//            value.push_back(atoi(token.c_str()));
+//
+//        return true;
+//    }
+//
+//    return false;
+//}
+//
+//bool scene_read_xml_float(float* value, xml_node node, const char* name)
+//{
+//    xml_attribute attr = node.attribute(name);
+//
+//    if (attr) {
+//        *value = (float)atof(attr.value());
+//        return true;
+//    }
+//
+//    return false;
+//}
+//
+//bool scene_read_xml_float_array(vector<float>& value, xml_node node, const char* name)
+//{
+//    xml_attribute attr = node.attribute(name);
+//
+//    if (attr) {
+//        vector<string> tokens;
+//        string_split(tokens, attr.value());
+//
+//        foreach(const string & token, tokens)
+//            value.push_back((float)atof(token.c_str()));
+//
+//        return true;
+//    }
+//
+//    return false;
+//}
+//
+//bool scene_read_xml_float3(float3* value, xml_node node, const char* name)
+//{
+//    vector<float> array;
+//
+//    if (scene_read_xml_float_array(array, node, name) && array.size() == 3) {
+//        *value = make_float3(array[0], array[1], array[2]);
+//        return true;
+//    }
+//
+//    return false;
+//}
+//
+//bool scene_read_xml_float3_array(vector<float3>& value, xml_node node, const char* name)
+//{
+//    vector<float> array;
+//
+//    if (scene_read_xml_float_array(array, node, name)) {
+//        for (size_t i = 0; i < array.size(); i += 3) {
+//            value.push_back(make_float3(array[i + 0], array[i + 1], array[i + 2]));
+//        }
+//
+//        return true;
+//    }
+//
+//    return false;
+//}
+//
+//bool scene_read_xml_float4(float4* value, xml_node node, const char* name)
+//{
+//    vector<float> array;
+//
+//    if (scene_read_xml_float_array(array, node, name) && array.size() == 4) {
+//        *value = make_float4(array[0], array[1], array[2], array[3]);
+//        return true;
+//    }
+//
+//    return false;
+//}
+//
+//bool scene_read_xml_string(string* str, xml_node node, const char* name)
+//{
+//    xml_attribute attr = node.attribute(name);
+//
+//    if (attr) {
+//        *str = attr.value();
+//        return true;
+//    }
+//
+//    return false;
+//}
+//
+//bool scene_read_xml_equal_string(xml_node node, const char* name, const char* value)
+//{
+//    xml_attribute attr = node.attribute(name);
+//
+//    if (attr) {
+//        return string_iequals(attr.value(), value);
+//    }
+//
+//    return false;
+//}
+//
+///* Camera */
+//
+//void scene_read_xml_camera(XMLReadState& state, xml_node node)
+//{
+//    Camera* cam = state.scene->camera;
+//
+//    int width = -1, height = -1;
+//    scene_read_xml_int(&width, node, "width");
+//    scene_read_xml_int(&height, node, "height");
+//
+//    cam->set_full_width(width);
+//    cam->set_full_height(height);
+//
+//    xml_read_node(state, cam, node);
+//
+//    cam->set_matrix(state.tfm);
+//
+//    cam->need_flags_update = true;
+//    cam->update(state.scene);
+//}
+//
+///* Alembic */
+//
+//#ifdef WITH_ALEMBIC
+//void scene_read_xml_alembic(XMLReadState& state, xml_node graph_node)
+//{
+//    AlembicProcedural* proc = state.scene->create_node<AlembicProcedural>();
+//    xml_read_node(state, proc, graph_node);
+//
+//    for (xml_node node = graph_node.first_child(); node; node = node.next_sibling()) {
+//        if (string_iequals(node.name(), "object")) {
+//            string path;
+//            if (scene_read_xml_string(&path, node, "path")) {
+//                ustring object_path(path, 0);
+//                AlembicObject* object = static_cast<AlembicObject*>(
+//                    proc->get_or_create_object(object_path));
+//
+//                array<Node*> used_shaders = object->get_used_shaders();
+//                used_shaders.push_back_slow(state.shader);
+//                object->set_used_shaders(used_shaders);
+//            }
+//        }
+//    }
+//}
+//#endif
+//
+///* Shader */
+//
+//void scene_read_xml_shader_graph(XMLReadState& state, Shader* shader, xml_node graph_node)
+//{
+//    xml_read_node(state, shader, graph_node);
+//
+//    ShaderGraph* graph = new ShaderGraph();
+//
+//    /* local state, shader nodes can't link to nodes outside the shader graph */
+//    XMLReader graph_reader;
+//    graph_reader.node_map[ustring("output")] = graph->output();
+//
+//    for (xml_node node = graph_node.first_child(); node; node = node.next_sibling()) {
+//        ustring node_name(node.name());
+//
+//        if (node_name == "connect") {
+//            /* connect nodes */
+//            vector<string> from_tokens, to_tokens;
+//
+//            string_split(from_tokens, node.attribute("from").value());
+//            string_split(to_tokens, node.attribute("to").value());
+//
+//            if (from_tokens.size() == 2 && to_tokens.size() == 2) {
+//                ustring from_node_name(from_tokens[0]);
+//                ustring from_socket_name(from_tokens[1]);
+//                ustring to_node_name(to_tokens[0]);
+//                ustring to_socket_name(to_tokens[1]);
+//
+//                /* find nodes and sockets */
+//                ShaderOutput* output = NULL;
+//                ShaderInput* input = NULL;
+//
+//                if (graph_reader.node_map.find(from_node_name) != graph_reader.node_map.end()) {
+//                    ShaderNode* fromnode = (ShaderNode*)graph_reader.node_map[from_node_name];
+//
+//                    foreach(ShaderOutput * out, fromnode->outputs)
+//                        if (string_iequals(out->socket_type.name.string(), from_socket_name.string())) {
+//                            output = out;
+//                        }
+//
+//                    if (!output) {
+//                        fprintf(stderr,
+//                            "Unknown output socket name \"%s\" on \"%s\".\n",
+//                            from_node_name.c_str(),
+//                            from_socket_name.c_str());
+//                    }
+//                }
+//                else {
+//                    fprintf(stderr, "Unknown shader node name \"%s\".\n", from_node_name.c_str());
+//                }
+//
+//                if (graph_reader.node_map.find(to_node_name) != graph_reader.node_map.end()) {
+//                    ShaderNode* tonode = (ShaderNode*)graph_reader.node_map[to_node_name];
+//
+//                    foreach(ShaderInput * in, tonode->inputs)
+//                        if (string_iequals(in->socket_type.name.string(), to_socket_name.string())) {
+//                            input = in;
+//                        }
+//
+//                    if (!input) {
+//                        fprintf(stderr,
+//                            "Unknown input socket name \"%s\" on \"%s\".\n",
+//                            to_socket_name.c_str(),
+//                            to_node_name.c_str());
+//                    }
+//                }
+//                else {
+//                    fprintf(stderr, "Unknown shader node name \"%s\".\n", to_node_name.c_str());
+//                }
+//
+//                /* connect */
+//                if (output && input) {
+//                    graph->connect(output, input);
+//                }
+//            }
+//            else {
+//                fprintf(stderr, "Invalid from or to value for connect node.\n");
+//            }
+//
+//            continue;
+//        }
+//
+//        ShaderNode* snode = NULL;
+//
+//#ifdef WITH_OSL
+//        if (node_name == "osl_shader") {
+//            ShaderManager* manager = state.scene->shader_manager;
+//
+//            if (manager->use_osl()) {
+//                std::string filepath;
+//
+//                if (scene_read_xml_string(&filepath, node, "src")) {
+//                    if (path_is_relative(filepath)) {
+//                        filepath = path_join(state.base, filepath);
+//                    }
+//
+//                    snode = OSLShaderManager::osl_node(graph, manager, filepath, "");
+//
+//                    if (!snode) {
+//                        fprintf(stderr, "Failed to create OSL node from \"%s\".\n", filepath.c_str());
+//                        continue;
+//                    }
+//                }
+//                else {
+//                    fprintf(stderr, "OSL node missing \"src\" attribute.\n");
+//                    continue;
+//                }
+//            }
+//            else {
+//                fprintf(stderr, "OSL node without using --shadingsys osl.\n");
+//                continue;
+//            }
+//        }
+//        else
+//#endif
+//        {
+//            /* exception for name collision */
+//            if (node_name == "background") {
+//                node_name = "background_shader";
+//            }
+//
+//            const NodeType* node_type = NodeType::find(node_name);
+//
+//            if (!node_type) {
+//                fprintf(stderr, "Unknown shader node \"%s\".\n", node.name());
+//                continue;
+//            }
+//            else if (node_type->type != NodeType::SHADER) {
+//                fprintf(stderr, "Node type \"%s\" is not a shader node.\n", node_type->name.c_str());
+//                continue;
+//            }
+//            else if (node_type->create == NULL) {
+//                fprintf(stderr, "Can't create abstract node type \"%s\".\n", node_type->name.c_str());
+//                continue;
+//            }
+//
+//            snode = (ShaderNode*)node_type->create(node_type);
+//            snode->set_owner(graph);
+//        }
+//
+//        xml_read_node(graph_reader, snode, node);
+//
+//        if (node_name == "image_texture") {
+//            ImageTextureNode* img = (ImageTextureNode*)snode;
+//            ustring filename(path_join(state.base, img->get_filename().string()));
+//            img->set_filename(filename);
+//        }
+//        else if (node_name == "environment_texture") {
+//            EnvironmentTextureNode* env = (EnvironmentTextureNode*)snode;
+//            ustring filename(path_join(state.base, env->get_filename().string()));
+//            env->set_filename(filename);
+//        }
+//
+//        if (snode) {
+//            /* add to graph */
+//            graph->add(snode);
+//        }
+//    }
+//
+//    shader->set_graph(graph);
+//    shader->tag_update(state.scene);
+//}
+//
+//void scene_read_xml_shader(XMLReadState& state, xml_node node)
+//{
+//    Shader* shader = new Shader();
+//    scene_read_xml_shader_graph(state, shader, node);
+//    state.scene->shaders.push_back(shader);
+//}
+//
+///* Background */
+//
+//void scene_read_xml_background(XMLReadState& state, xml_node node)
+//{
+//    /* Background Settings */
+//    xml_read_node(state, state.scene->background, node);
+//
+//    /* Background Shader */
+//    Shader* shader = state.scene->default_background;
+//    scene_read_xml_shader_graph(state, shader, node);
+//}
+//
+///* Mesh */
+//
+//Mesh* xml_add_mesh(Scene* scene, const Transform& tfm, Object* object)
+//{
+//    if (object && object->get_geometry()->is_mesh()) {
+//        /* Use existing object and mesh */
+//        object->set_tfm(tfm);
+//        Geometry* geometry = object->get_geometry();
+//        return static_cast<Mesh*>(geometry);
+//    }
+//    else {
+//        /* Create mesh */
+//        Mesh* mesh = new Mesh();
+//        scene->geometry.push_back(mesh);
+//
+//        /* Create object. */
+//        Object* object = new Object();
+//        object->set_geometry(mesh);
+//        object->set_tfm(tfm);
+//        scene->objects.push_back(object);
+//
+//        return mesh;
+//    }
+//}
+//
+//void scene_read_xml_mesh(const XMLReadState& state, xml_node node)
+//{
+//    /* add mesh */
+//    Mesh* mesh = xml_add_mesh(state.scene, state.tfm, state.object);
+//    array<Node*> used_shaders = mesh->get_used_shaders();
+//    used_shaders.push_back_slow(state.shader);
+//    mesh->set_used_shaders(used_shaders);
+//
+//    /* read state */
+//    int shader = 0;
+//    bool smooth = state.smooth;
+//
+//    /* read vertices and polygons */
+//    vector<float3> P;
+//    vector<float3> VN; /* Vertex normals */
+//    vector<float> UV;
+//    vector<float> T;  /* UV tangents */
+//    vector<float> TS; /* UV tangent signs */
+//    vector<int> verts, nverts;
+//
+//    scene_read_xml_float3_array(P, node, "P");
+//    scene_read_xml_int_array(verts, node, "verts");
+//    scene_read_xml_int_array(nverts, node, "nverts");
+//
+//    if (scene_read_xml_equal_string(node, "subdivision", "catmull-clark")) {
+//        mesh->set_subdivision_type(Mesh::SUBDIVISION_CATMULL_CLARK);
+//    }
+//    else if (scene_read_xml_equal_string(node, "subdivision", "linear")) {
+//        mesh->set_subdivision_type(Mesh::SUBDIVISION_LINEAR);
+//    }
+//
+//    array<float3> P_array;
+//    P_array = P;
+//
+//    if (mesh->get_subdivision_type() == Mesh::SUBDIVISION_NONE) {
+//        /* create vertices */
+//
+//        mesh->set_verts(P_array);
+//
+//        size_t num_triangles = 0;
+//        for (size_t i = 0; i < nverts.size(); i++) {
+//            num_triangles += nverts[i] - 2;
+//        }
+//        mesh->reserve_mesh(mesh->get_verts().size(), num_triangles);
+//
+//        /* create triangles */
+//        int index_offset = 0;
+//
+//        for (size_t i = 0; i < nverts.size(); i++) {
+//            for (int j = 0; j < nverts[i] - 2; j++) {
+//                int v0 = verts[index_offset];
+//                int v1 = verts[index_offset + j + 1];
+//                int v2 = verts[index_offset + j + 2];
+//
+//                assert(v0 < (int)P.size());
+//                assert(v1 < (int)P.size());
+//                assert(v2 < (int)P.size());
+//
+//                mesh->add_triangle(v0, v1, v2, shader, smooth);
+//            }
+//
+//            index_offset += nverts[i];
+//        }
+//
+//        /* Vertex normals */
+//        if (scene_read_xml_float3_array(VN, node, Attribute::standard_name(ATTR_STD_VERTEX_NORMAL))) {
+//            Attribute* attr = mesh->attributes.add(ATTR_STD_VERTEX_NORMAL);
+//            float3* fdata = attr->data_float3();
+//
+//            /* Loop over the normals */
+//            for (auto n : VN) {
+//                fdata[0] = n;
+//                fdata++;
+//            }
+//        }
+//
+//        /* UV map */
+//        if (scene_read_xml_float_array(UV, node, "UV") ||
+//            scene_read_xml_float_array(UV, node, Attribute::standard_name(ATTR_STD_UV)))
+//        {
+//            Attribute* attr = mesh->attributes.add(ATTR_STD_UV);
+//            float2* fdata = attr->data_float2();
+//
+//            /* Loop over the triangles */
+//            index_offset = 0;
+//            for (size_t i = 0; i < nverts.size(); i++) {
+//                for (int j = 0; j < nverts[i] - 2; j++) {
+//                    int v0 = index_offset;
+//                    int v1 = index_offset + j + 1;
+//                    int v2 = index_offset + j + 2;
+//
+//                    assert(v0 * 2 + 1 < (int)UV.size());
+//                    assert(v1 * 2 + 1 < (int)UV.size());
+//                    assert(v2 * 2 + 1 < (int)UV.size());
+//
+//                    fdata[0] = make_float2(UV[v0 * 2], UV[v0 * 2 + 1]);
+//                    fdata[1] = make_float2(UV[v1 * 2], UV[v1 * 2 + 1]);
+//                    fdata[2] = make_float2(UV[v2 * 2], UV[v2 * 2 + 1]);
+//                    fdata += 3;
+//                }
+//
+//                index_offset += nverts[i];
+//            }
+//        }
+//
+//        /* Tangents */
+//        if (scene_read_xml_float_array(T, node, Attribute::standard_name(ATTR_STD_UV_TANGENT))) {
+//            Attribute* attr = mesh->attributes.add(ATTR_STD_UV_TANGENT);
+//            float3* fdata = attr->data_float3();
+//
+//            /* Loop over the triangles */
+//            index_offset = 0;
+//            for (size_t i = 0; i < nverts.size(); i++) {
+//                for (int j = 0; j < nverts[i] - 2; j++) {
+//                    int v0 = index_offset;
+//                    int v1 = index_offset + j + 1;
+//                    int v2 = index_offset + j + 2;
+//
+//                    assert(v0 * 3 + 2 < (int)T.size());
+//                    assert(v1 * 3 + 2 < (int)T.size());
+//                    assert(v2 * 3 + 2 < (int)T.size());
+//
+//                    fdata[0] = make_float3(T[v0 * 3], T[v0 * 3 + 1], T[v0 * 3 + 2]);
+//                    fdata[1] = make_float3(T[v1 * 3], T[v1 * 3 + 1], T[v1 * 3 + 2]);
+//                    fdata[2] = make_float3(T[v2 * 3], T[v2 * 3 + 1], T[v2 * 3 + 2]);
+//                    fdata += 3;
+//                }
+//                index_offset += nverts[i];
+//            }
+//        }
+//
+//        /* Tangent signs */
+//        if (scene_read_xml_float_array(TS, node, Attribute::standard_name(ATTR_STD_UV_TANGENT_SIGN))) {
+//            Attribute* attr = mesh->attributes.add(ATTR_STD_UV_TANGENT_SIGN);
+//            float* fdata = attr->data_float();
+//
+//            /* Loop over the triangles */
+//            index_offset = 0;
+//            for (size_t i = 0; i < nverts.size(); i++) {
+//                for (int j = 0; j < nverts[i] - 2; j++) {
+//                    int v0 = index_offset;
+//                    int v1 = index_offset + j + 1;
+//                    int v2 = index_offset + j + 2;
+//
+//                    assert(v0 < (int)TS.size());
+//                    assert(v1 < (int)TS.size());
+//                    assert(v2 < (int)TS.size());
+//
+//                    fdata[0] = TS[v0];
+//                    fdata[1] = TS[v1];
+//                    fdata[2] = TS[v2];
+//                    fdata += 3;
+//                }
+//                index_offset += nverts[i];
+//            }
+//        }
+//    }
+//    else {
+//        /* create vertices */
+//        mesh->set_verts(P_array);
+//
+//        size_t num_ngons = 0;
+//        size_t num_corners = 0;
+//        for (size_t i = 0; i < nverts.size(); i++) {
+//            num_ngons += (nverts[i] == 4) ? 0 : 1;
+//            num_corners += nverts[i];
+//        }
+//        mesh->reserve_subd_faces(nverts.size(), num_ngons, num_corners);
+//
+//        /* create subd_faces */
+//        int index_offset = 0;
+//
+//        for (size_t i = 0; i < nverts.size(); i++) {
+//            mesh->add_subd_face(&verts[index_offset], nverts[i], shader, smooth);
+//            index_offset += nverts[i];
+//        }
+//
+//        /* UV map */
+//        if (scene_read_xml_float_array(UV, node, "UV") ||
+//            scene_read_xml_float_array(UV, node, Attribute::standard_name(ATTR_STD_UV)))
+//        {
+//            Attribute* attr = mesh->subd_attributes.add(ATTR_STD_UV);
+//            float3* fdata = attr->data_float3();
+//
+//#if 0
+//            if (subdivide_uvs) {
+//                attr->flags |= ATTR_SUBDIVIDED;
+//            }
+//#endif
+//
+//            index_offset = 0;
+//            for (size_t i = 0; i < nverts.size(); i++) {
+//                for (int j = 0; j < nverts[i]; j++) {
+//                    *(fdata++) = make_float3(UV[index_offset++]);
+//                }
+//            }
+//        }
+//
+//        /* setup subd params */
+//        float dicing_rate = state.dicing_rate;
+//        scene_read_xml_float(&dicing_rate, node, "dicing_rate");
+//        dicing_rate = std::max(0.1f, dicing_rate);
+//
+//        mesh->set_subd_dicing_rate(dicing_rate);
+//        mesh->set_subd_objecttoworld(state.tfm);
+//    }
+//
+//    /* we don't yet support arbitrary attributes, for now add vertex
+//     * coordinates as generated coordinates if requested */
+//    if (mesh->need_attribute(state.scene, ATTR_STD_GENERATED)) {
+//        Attribute* attr = mesh->attributes.add(ATTR_STD_GENERATED);
+//        memcpy(
+//            attr->data_float3(), mesh->get_verts().data(), sizeof(float3) * mesh->get_verts().size());
+//    }
+//}
+//
+///* Light */
+//
+//void scene_read_xml_light(XMLReadState& state, xml_node node)
+//{
+//    Light* light = new Light();
+//
+//    light->set_shader(state.shader);
+//    xml_read_node(state, light, node);
+//
+//    state.scene->lights.push_back(light);
+//}
+//
+///* Transform */
+//
+//void scene_read_xml_transform(xml_node node, Transform& tfm)
+//{
+//    if (node.attribute("matrix")) {
+//        vector<float> matrix;
+//        if (scene_read_xml_float_array(matrix, node, "matrix") && matrix.size() == 16) {
+//            ProjectionTransform projection = *(ProjectionTransform*)&matrix[0];
+//            tfm = tfm * projection_to_transform(projection_transpose(projection));
+//        }
+//    }
+//
+//    if (node.attribute("translate")) {
+//        float3 translate = zero_float3();
+//        scene_read_xml_float3(&translate, node, "translate");
+//        tfm = tfm * transform_translate(translate);
+//    }
+//
+//    if (node.attribute("rotate")) {
+//        float4 rotate = zero_float4();
+//        scene_read_xml_float4(&rotate, node, "rotate");
+//        tfm = tfm * transform_rotate(DEG2RADF(rotate.x), make_float3(rotate.y, rotate.z, rotate.w));
+//    }
+//
+//    if (node.attribute("scale")) {
+//        float3 scale = zero_float3();
+//        scene_read_xml_float3(&scale, node, "scale");
+//        tfm = tfm * transform_scale(scale);
+//    }
+//}
+//
+///* State */
+//
+//void scene_read_xml_state(XMLReadState& state, xml_node node)
+//{
+//    /* Read shader */
+//    string shadername;
+//
+//    if (scene_read_xml_string(&shadername, node, "shader")) {
+//        bool found = false;
+//
+//        foreach(Shader * shader, state.scene->shaders) {
+//            if (shader->name == shadername) {
+//                state.shader = shader;
+//                found = true;
+//                break;
+//            }
+//        }
+//
+//        if (!found) {
+//            fprintf(stderr, "Unknown shader \"%s\".\n", shadername.c_str());
+//        }
+//    }
+//
+//    /* Read object */
+//    string objectname;
+//
+//    if (scene_read_xml_string(&objectname, node, "object")) {
+//        bool found = false;
+//
+//        foreach(Object * object, state.scene->objects) {
+//            if (object->name == objectname) {
+//                state.object = object;
+//                found = true;
+//                break;
+//            }
+//        }
+//
+//        if (!found) {
+//            fprintf(stderr, "Unknown object \"%s\".\n", objectname.c_str());
+//        }
+//    }
+//
+//    scene_read_xml_float(&state.dicing_rate, node, "dicing_rate");
+//
+//    /* read smooth/flat */
+//    if (scene_read_xml_equal_string(node, "interpolation", "smooth")) {
+//        state.smooth = true;
+//    }
+//    else if (scene_read_xml_equal_string(node, "interpolation", "flat")) {
+//        state.smooth = false;
+//    }
+//}
+//
+///* Object */
+//
+//void scene_read_xml_object(XMLReadState& state, xml_node node)
+//{
+//    Scene* scene = state.scene;
+//
+//    /* create mesh */
+//    Mesh* mesh = new Mesh();
+//    scene->geometry.push_back(mesh);
+//
+//    /* create object */
+//    Object* object = new Object();
+//    object->set_geometry(mesh);
+//    object->set_tfm(state.tfm);
+//
+//    xml_read_node(state, object, node);
+//
+//    scene->objects.push_back(object);
+//}
+//
+///* Scene */
+//
+//void scene_read_xml_scene(XMLReadState& state, xml_node scene_node)
+//{
+//    for (xml_node node = scene_node.first_child(); node; node = node.next_sibling()) {
+//        if (string_iequals(node.name(), "film")) {
+//            xml_read_node(state, state.scene->film, node);
+//        }
+//        else if (string_iequals(node.name(), "integrator")) {
+//            xml_read_node(state, state.scene->integrator, node);
+//        }
+//        else if (string_iequals(node.name(), "camera")) {
+//            scene_read_xml_camera(state, node);
+//        }
+//        else if (string_iequals(node.name(), "shader")) {
+//            scene_read_xml_shader(state, node);
+//        }
+//        else if (string_iequals(node.name(), "background")) {
+//            scene_read_xml_background(state, node);
+//        }
+//        else if (string_iequals(node.name(), "mesh")) {
+//            scene_read_xml_mesh(state, node);
+//        }
+//        else if (string_iequals(node.name(), "light")) {
+//            scene_read_xml_light(state, node);
+//        }
+//        else if (string_iequals(node.name(), "transform")) {
+//            XMLReadState substate = state;
+//
+//            scene_read_xml_transform(node, substate.tfm);
+//            scene_read_xml_scene(substate, node);
+//        }
+//        else if (string_iequals(node.name(), "state")) {
+//            XMLReadState substate = state;
+//
+//            scene_read_xml_state(substate, node);
+//            scene_read_xml_scene(substate, node);
+//        }
+//        else if (string_iequals(node.name(), "include")) {
+//            string src;
+//
+//            if (scene_read_xml_string(&src, node, "src")) {
+//                scene_read_xml_include(state, src);
+//            }
+//        }
+//        else if (string_iequals(node.name(), "object")) {
+//            XMLReadState substate = state;
+//
+//            scene_read_xml_object(substate, node);
+//            scene_read_xml_scene(substate, node);
+//        }
+//#ifdef WITH_ALEMBIC
+//        else if (string_iequals(node.name(), "alembic")) {
+//            scene_read_xml_alembic(state, node);
+//        }
+//#endif
+//        else {
+//            fprintf(stderr, "Unknown node \"%s\".\n", node.name());
+//        }
+//    }
+//}
+//
+///* Include */
+//
+//void scene_read_xml_include(XMLReadState& state, const string& src)
+//{
+//    /* open XML document */
+//    xml_document doc;
+//    xml_parse_result parse_result;
+//
+//    string path = path_join(state.base, src);
+//    parse_result = doc.load_file(path.c_str());
+//
+//    if (parse_result) {
+//        XMLReadState substate = state;
+//        substate.base = path_dirname(path);
+//
+//        xml_node cycles = doc.child("cycles");
+//        scene_read_xml_scene(substate, cycles);
+//    }
+//    else {
+//        fprintf(stderr, "%s read error: %s\n", src.c_str(), parse_result.description());
+//        exit(EXIT_FAILURE);
+//    }
+//}
+//
+///* File */
+//
+//void scene_read_xml_file(Scene* scene, const char* filepath)
+//{
+//    XMLReadState state;
+//
+//    state.scene = scene;
+//    state.tfm = transform_identity();
+//    state.shader = scene->default_surface;
+//    state.smooth = false;
+//    state.dicing_rate = 1.0f;
+//    state.base = path_dirname(filepath);
+//
+//    scene_read_xml_include(state, path_filename(filepath));
+//
+//    scene->params.bvh_type = BVH_TYPE_STATIC;
+//}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/scene/scene_read_xml.h b/intern/cycles/scene/scene_read_xml.h
new file mode 100644
index 0000000000000000000000000000000000000000..bcb3d00311e7cf3e72d662a9713ddcf411a7f3cc
--- /dev/null
+++ b/intern/cycles/scene/scene_read_xml.h
@@ -0,0 +1,53 @@
+/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
+ *
+ * SPDX-License-Identifier: Apache-2.0 */
+
+#pragma once
+
+#include "graph/node_xml.h"
+
+#include "scene/scene.h"
+
+CCL_NAMESPACE_BEGIN
+
+/* XML reading state */
+
+//struct XMLReadState : public XMLReader {
+//  Scene* scene;      /* Scene pointer. */
+//  Transform tfm;     /* Current transform state. */
+//  bool smooth;       /* Smooth normal state. */
+//  Shader* shader;    /* Current shader. */
+//  string base;       /* Base path to current file. */
+//  float dicing_rate; /* Current dicing rate. */
+//  Object* object;    /* Current object. */
+//
+//  XMLReadState() : scene(NULL), smooth(false), shader(NULL), dicing_rate(1.0f), object(NULL)
+//  {
+//    tfm = transform_identity();
+//  }
+//};
+//
+//bool scene_read_xml_int(int* value, xml_node node, const char* name);
+//bool scene_read_xml_int_array(vector<int>& value, xml_node node, const char* name);
+//bool scene_read_xml_float(float* value, xml_node node, const char* name);
+//bool scene_read_xml_float_array(vector<float>& value, xml_node node, const char* name);
+//bool scene_read_xml_float3(float3* value, xml_node node, const char* name);
+//bool scene_read_xml_float3_array(vector<float3>& value, xml_node node, const char* name);
+//bool scene_read_xml_float4(float4* value, xml_node node, const char* name);
+//bool scene_read_xml_string(string* str, xml_node node, const char* name);
+//void scene_read_xml_camera(XMLReadState& state, xml_node node);
+//void scene_read_xml_alembic(XMLReadState& state, xml_node graph_node);
+//void scene_read_xml_shader_graph(XMLReadState& state, Shader* shader, xml_node graph_node);
+//void scene_read_xml_shader(XMLReadState& state, xml_node node);
+//void scene_read_xml_background(XMLReadState& state, xml_node node);
+//void scene_read_xml_mesh(const XMLReadState& state, xml_node node);
+//void scene_read_xml_light(XMLReadState& state, xml_node node);
+//void scene_read_xml_transform(xml_node node, Transform& tfm);
+//void scene_read_xml_state(XMLReadState& state, xml_node node);
+//void scene_read_xml_object(XMLReadState& state, xml_node node);
+//void scene_read_xml_include(XMLReadState& state, const string& src);
+//void scene_read_xml_scene(XMLReadState& state, xml_node scene_node);
+//void scene_read_xml_include(XMLReadState& state, const string& src);
+//void scene_read_xml_file(Scene* scene, const char* filepath);
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/scene/scene_write_xml.cpp b/intern/cycles/scene/scene_write_xml.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..bb036fe8e2e5a8da76e55191f8bba46ed9b839b9
--- /dev/null
+++ b/intern/cycles/scene/scene_write_xml.cpp
@@ -0,0 +1,1404 @@
+/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
+ *
+ * SPDX-License-Identifier: Apache-2.0 */
+
+#include "scene_write_xml.h"
+
+#include <stdio.h>
+
+#include <algorithm>
+#include <iterator>
+#include <sstream>
+
+#include "graph/node_xml.h"
+
+#include "scene/alembic.h"
+#include "scene/background.h"
+#include "scene/camera.h"
+#include "scene/film.h"
+#include "scene/integrator.h"
+#include "scene/light.h"
+#include "scene/mesh.h"
+#include "scene/object.h"
+#include "scene/osl.h"
+#include "scene/scene.h"
+#include "scene/shader.h"
+#include "scene/shader_graph.h"
+#include "scene/shader_nodes.h"
+#include "scene/image_vdb.h"
+
+#include "subd/patch.h"
+#include "subd/split.h"
+
+#include "util/foreach.h"
+#include "util/path.h"
+#include "util/projection.h"
+#include "util/transform.h"
+#include "util/xml.h"
+#include "util/string.h"
+
+#include <OpenImageIO/imageio.h>
+#include <OpenImageIO/imagebuf.h>
+#include <OpenImageIO/imagebufalgo.h>
+#include <OpenImageIO/filesystem.h>
+
+#include <openvdb/io/Stream.h>
+
+#define ADD_ATTR(name) \
+			xml_attribute attr_##name = node_attribute.append_attribute(#name); \
+			attr_##name = attr.##name;
+
+#define ADD_ATTR_STR(name) \
+			xml_attribute attr_##name = node_attribute.append_attribute(#name); \
+			attr_##name = attr.##name.c_str();
+
+#define ADD_ATTR_DTYPE(type, name) \
+			xml_attribute attr_##name = node_attribute.append_attribute(#name); \
+			attr_##name = type.##name;
+
+CCL_NAMESPACE_BEGIN
+
+/* XML writing state */
+
+struct XMLWriteState : public XMLWriter {
+	Scene* scene;      /* Scene pointer. */	
+
+	XMLWriteState() :
+		scene(NULL)
+	{
+	}
+};
+
+template<typename T>
+string write_vector_to_binary_file(XMLWriter& writer, const vector<T>& data)
+{
+	std::stringstream ss;
+	ss << writer.offset;
+
+	// Write the size of the vector first
+	size_t data_size = data.size();
+	writer.file.write(reinterpret_cast<const char*>(&data_size), sizeof(size_t));
+	writer.offset += sizeof(size_t);
+
+	// Write the actual data to the file
+	writer.file.write(reinterpret_cast<const char*>(data.data()), data_size * sizeof(T));
+	writer.offset += data_size * sizeof(T);
+
+	return ss.str();
+}
+
+void save_image_to_memory(device_texture* dt, vector<char>& output_buffer) {
+#if 0
+	TypeDesc image_type;
+	switch (dt->data_type) {
+	case ImageDataType::IMAGE_DATA_TYPE_FLOAT4:
+	case ImageDataType::IMAGE_DATA_TYPE_FLOAT:
+		image_type = TypeDesc::FLOAT;
+		break;
+	case ImageDataType::IMAGE_DATA_TYPE_BYTE4:
+	case ImageDataType::IMAGE_DATA_TYPE_BYTE:
+		image_type = TypeDesc::UCHAR;
+		break;
+	case ImageDataType::IMAGE_DATA_TYPE_HALF4:
+	case ImageDataType::IMAGE_DATA_TYPE_HALF:
+		image_type = TypeDesc::HALF;
+		break;
+	case ImageDataType::IMAGE_DATA_TYPE_USHORT4:
+	case ImageDataType::IMAGE_DATA_TYPE_USHORT:
+		image_type = TypeDesc::USHORT;
+		break;
+	default:
+		std::cerr << "Wrong image type" << std::endl;
+		return;
+	}
+
+	int width = dt->data_width;
+	int height = dt->data_height;
+	int channels = dt->data_elements;
+	ImageSpec spec(width, height, channels, image_type);
+
+	// Use OpenImageIO's ImageBuf for flipping
+	ImageBuf img_buf(spec, dt->host_pointer);
+	ImageBuf flipped_buf;
+	if (!ImageBufAlgo::flip(flipped_buf, img_buf)) {
+		std::cerr << "Error flipping the image" << std::endl;
+		return;
+	}
+
+	// Create an in-memory image writer using IOVecOutput
+	std::unique_ptr<ImageOutput> image_output = ImageOutput::create("image.exr");
+	if (!image_output) {
+		std::cerr << "Failed to create image output for memory buffer" << std::endl;
+		return;
+	}
+
+	std::vector<unsigned char> io_buffer;
+	Filesystem::IOVecOutput io_vec_output(io_buffer);
+	//void* ptr = &io_vec_output;
+	//spec.attribute("oiio:ioproxy", TypeDesc::PTR, &ptr);
+	image_output->set_ioproxy(&io_vec_output);
+	image_output->open("image.exr", spec);
+
+	if (!image_output->write_image(image_type, flipped_buf.localpixels())) { //flipped_buf
+		std::cerr << "Error writing image" << std::endl;
+		return;
+	}
+	image_output->close();
+#endif
+
+#if 0
+	struct TempMetaData {
+		int width;
+		int height;
+		int channels;
+		TypeDesc image_type;
+	};
+	TempMetaData temp_meta_data;
+	temp_meta_data.width = width;
+	temp_meta_data.height = height;
+	temp_meta_data.channels = channels;
+	temp_meta_data.image_type = image_type;	
+
+	// Get the buffer as a vector<char>
+	output_buffer.resize(sizeof(TempMetaData));
+	memcpy(output_buffer.data(), &temp_meta_data, sizeof(TempMetaData));
+
+	output_buffer.insert(output_buffer.end(), io_buffer.begin(), io_buffer.end());
+	//output_buffer.assign(io_buffer.begin(), io_buffer.end());
+#endif
+
+	output_buffer.resize(dt->memory_size());
+	memcpy(output_buffer.data(), dt->host_pointer, dt->memory_size());
+}
+
+/* Attribute Reading */
+
+void scene_write_xml_int(int value, xml_node node, const char* name)
+{
+	xml_attribute attr = node.append_attribute(name);
+
+	attr.set_value(value);
+}
+
+void scene_write_xml_int_array(vector<int>& value, xml_node node, const char* name)
+{
+	xml_attribute attr = node.append_attribute(name);
+
+	std::ostringstream oss;
+
+	for (size_t i = 0; i < value.size(); ++i) {
+		if (i != 0 && i != value.size() - 1) {
+			oss << ";"; // Add separator before each number except the first and the last
+		}
+		oss << value[i];
+	}
+
+	attr.set_value(oss.str().c_str());
+}
+
+void scene_write_xml_float(float value, xml_node node, const char* name)
+{
+	xml_attribute attr = node.append_attribute(name);
+
+	attr.set_value(value);
+}
+
+void scene_write_xml_float_array(vector<float>& value, xml_node node, const char* name)
+{
+	xml_attribute attr = node.append_attribute(name);
+
+	std::ostringstream oss;
+
+	for (size_t i = 0; i < value.size(); ++i) {
+		if (i != 0 && i != value.size() - 1) {
+			oss << ";"; // Add separator before each number except the first and the last
+		}
+		oss << value[i];
+	}
+
+	attr.set_value(oss.str().c_str());
+}
+
+void scene_write_xml_float3(float3 value, xml_node node, const char* name)
+{
+	vector<float> array;
+	array.push_back(value[0]);
+	array.push_back(value[1]);
+	array.push_back(value[2]);
+
+	scene_write_xml_float_array(array, node, name);
+}
+
+void scene_write_xml_float3_array(vector<float3>& value, xml_node node, const char* name)
+{
+	vector<float> array;
+
+	foreach(float3 v, value) {
+		array.push_back(v[0]);
+		array.push_back(v[1]);
+		array.push_back(v[2]);
+	}
+
+	scene_write_xml_float_array(array, node, name);
+}
+
+void scene_write_xml_float4(float4 value, xml_node node, const char* name)
+{
+	vector<float> array;
+	array.push_back(value[0]);
+	array.push_back(value[1]);
+	array.push_back(value[2]);
+	array.push_back(value[3]);
+
+	scene_write_xml_float_array(array, node, name);
+}
+
+void scene_write_xml_string(string str, xml_node node, const char* name)
+{
+	xml_attribute attr = node.append_attribute(name);
+	attr.set_value(str.c_str());
+}
+
+//bool scene_write_xml_equal_string(xml_node node, const char* name, const char* value)
+//{
+//	xml_attribute attr = node.append_attribute(name);
+//
+//	if (attr) {
+//		return string_iequals(attr.value(), value);
+//	}
+//
+//	return false;
+//}
+
+/* Camera */
+
+//void scene_write_xml_camera(Scene* scene, xml_node node)
+//{
+//	Camera* cam = scene->camera;
+//
+//	int width = cam->get_full_width(), height = cam->get_full_height();
+//	scene_write_xml_int(width, node, "width");
+//	scene_write_xml_int(height, node, "height");
+//
+//	//cam->set_full_width(width);
+//	//cam->set_full_height(height);
+//
+//	xml_write_node(cam, node);
+//
+//	//cam->set_matrix(state.tfm);
+//
+//	//cam->need_flags_update = true;
+//	//cam->update(state.scene);
+//}
+
+/* Alembic */
+
+//#ifdef WITH_ALEMBIC
+//void scene_write_xml_alembic(XMLReadState& state, xml_node graph_node)
+//{
+//    AlembicProcedural* proc = state.scene->create_node<AlembicProcedural>();
+//    xml_write_node(state, proc, graph_node);
+//
+//    for (xml_node node = graph_node.first_child(); node; node = node.next_sibling()) {
+//        if (string_iequals(node.name(), "object")) {
+//            string path;
+//            if (scene_write_xml_string(&path, node, "path")) {
+//                ustring object_path(path, 0);
+//                AlembicObject* object = static_cast<AlembicObject*>(
+//                    proc->get_or_create_object(object_path));
+//
+//                array<Node*> used_shaders = object->get_used_shaders();
+//                used_shaders.push_back_slow(state.shader);
+//                object->set_used_shaders(used_shaders);
+//            }
+//        }
+//    }
+//}
+//#endif
+
+/* Shader */
+
+void scene_write_xml_shader_graph(XMLWriteState& state, Shader* shader, xml_node xml_root)
+{
+	//xml_node graph_node = xml_root;// .append_child(shader->type->name.c_str());
+	//xml_write_node(shader, graph_node);
+
+	foreach(ShaderNode * node, shader->graph->nodes) {
+		if (node->name == "output")
+			continue; // skip
+
+		//xml_node xml_node = xml_root.append_child(node->type->name.c_str());
+		xml_node xnode = xml_write_node(state, node, xml_root);
+		if (node->type->name == "image_texture" || node->type->name == "environment_texture") {
+
+			bool socket_found = false;
+
+			xml_node xml_node_socket_found;
+			xml_attribute attr_name_found;
+			xml_attribute attr_name_ui_found;
+			xml_attribute attr_value_found;
+
+			for (xml_node xml_node_socket : xnode.children("socket")) {
+
+				xml_attribute attr_name = xml_node_socket.attribute("name");
+				xml_attribute attr_name_ui = xml_node_socket.attribute("ui_name");
+				xml_attribute attr_value = xml_node_socket.attribute("value");
+
+				//ustring xml_socket_name(attr_name.value());
+
+				if (attr_name && ustring(attr_name.value()) == "filename" || 
+					attr_name_ui && ustring(attr_name_ui.value()) == "Filename") {
+					//std::string str_filename(attr.value());
+					//if (!str_filename.empty()) {
+
+					xml_node_socket_found = xml_node_socket;
+					attr_name_found = attr_name;
+					attr_name_ui_found = attr_name_ui;
+					attr_value_found = attr_value;
+
+					socket_found = true;
+					break;
+					//}
+				}
+			}
+
+			//if (socket_found)
+			//	continue;
+
+			//xml_attribute attr_filename = xnode.attribute("filename");
+			//if (attr_filename) {
+			//	std::string str_filename(attr_filename.value());
+			//	if (!str_filename.empty())
+			//		continue;
+			//}
+			//else {
+			//	attr_filename = xnode.append_attribute("filename");
+			//}
+
+			//xml_node xml_node_socket_found;
+			//xml_attribute attr_name_found;
+			//xml_attribute attr_name_ui_found;
+			//xml_attribute attr_value_found;
+
+			if (!socket_found) {
+				xml_node_socket_found = xnode.append_child("socket");
+				attr_name_found = xml_node_socket_found.append_attribute("name");
+				attr_name_found = "filename";
+
+				attr_name_ui_found = xml_node_socket_found.append_attribute("ui_name");
+				attr_name_ui_found = "Filename";
+
+				attr_value_found = xml_node_socket_found.append_attribute("value");
+			}
+
+			ImageSlotTextureNode* img = (ImageSlotTextureNode*)node;
+			//ImageMetaData metadata = img->handle.metadata();
+
+			device_texture* dt = img->handle.image_memory(0);
+			if (dt && dt->host_pointer) {
+#if 0
+				std::stringstream ss;
+
+				ss << xml_pointer_to_name(dt->host_pointer) << ".exr";
+				std::string str = ss.str();
+				std::replace(str.begin(), str.end(), ' ', '_');
+				string filename(path_join(state.base, str));
+
+				unique_ptr<ImageOutput> image_output(ImageOutput::create(filename));
+				if (!image_output) {
+					fprintf(stderr, "Failed to create image output for %s\n", filename.c_str());
+					return;
+				}
+
+				TypeDesc image_type;
+				switch (metadata.type) {
+				case ImageDataType::IMAGE_DATA_TYPE_FLOAT4:
+				case ImageDataType::IMAGE_DATA_TYPE_FLOAT:
+					image_type = TypeDesc::FLOAT;
+					break;
+				case ImageDataType::IMAGE_DATA_TYPE_BYTE4:
+				case ImageDataType::IMAGE_DATA_TYPE_BYTE:
+					image_type = TypeDesc::UCHAR;
+					break;
+				case ImageDataType::IMAGE_DATA_TYPE_HALF4:
+				case ImageDataType::IMAGE_DATA_TYPE_HALF:
+					image_type = TypeDesc::HALF;
+					break;
+				case ImageDataType::IMAGE_DATA_TYPE_USHORT4:
+				case ImageDataType::IMAGE_DATA_TYPE_USHORT:
+					image_type = TypeDesc::USHORT;
+					break;
+					//case ImageDataType::IMAGE_DATA_TYPE_NANOVDB_FLOAT:
+					//case ImageDataType::IMAGE_DATA_TYPE_NANOVDB_FLOAT3:
+					//case ImageDataType::IMAGE_DATA_TYPE_NANOVDB_FPN:
+					//case ImageDataType::IMAGE_DATA_TYPE_NANOVDB_FP16:
+				default:
+					fprintf(stderr, "Wrong image type");
+					return;
+				}
+
+				// Setup image specification
+				int width = metadata.width;
+				int height = metadata.height;
+				ImageSpec spec(width, height, metadata.channels, image_type);
+
+				// Use OpenImageIO's ImageBuf for flipping
+				ImageBuf img_buf(spec, dt->host_pointer);
+				ImageBuf flipped_buf;
+
+				if (!ImageBufAlgo::flip(flipped_buf, img_buf)) {
+					fprintf(stderr, "Error flipping the image");
+					return;
+				}
+
+				if (!image_output->open(filename, spec)) {
+					fprintf(stderr, "Failed to open image file for %s\n", filename.c_str());
+					return;
+				}
+
+				if (!image_output->write_image(image_type, flipped_buf.localpixels())) {
+					fprintf(stderr, "Error writing image");
+					return;
+				}
+
+				// Close the file
+				if (!image_output->close()) {
+					fprintf(stderr, "Error closing file");
+					return;
+				}
+				attr_filename = filename.c_str();
+#endif
+				vector<char> output_buffer;
+				save_image_to_memory(dt, output_buffer);
+				std::string soffset = write_vector_to_binary_file(state, output_buffer);
+				attr_value_found = soffset.c_str();
+
+				// MetaData
+				xml_node node_attribute = xnode;
+				ImageMetaData attr = img->handle.metadata();
+
+				bool is_rgba = (attr.type == IMAGE_DATA_TYPE_FLOAT4 ||
+					attr.type == IMAGE_DATA_TYPE_HALF4 ||
+					attr.type == IMAGE_DATA_TYPE_BYTE4 ||
+					attr.type == IMAGE_DATA_TYPE_USHORT4);
+
+				if (is_rgba)
+					attr.channels = 4; //ImageManager::file_load_image
+
+				//int channels;			
+				ADD_ATTR(channels);
+
+				//size_t width, height, depth;
+				ADD_ATTR(width);
+				ADD_ATTR(height);
+				ADD_ATTR(depth);
+				//size_t byte_size;
+				//ADD_ATTR(byte_size);
+				//ImageDataType type;
+				//int itype = attr.type;
+				ADD_ATTR(type);
+
+				///* Optional color space, defaults to raw. */
+				//ustring colorspace;
+				ADD_ATTR_STR(colorspace);
+				//string colorspace_file_hint;
+				ADD_ATTR_STR(colorspace_file_hint);
+				//const char* colorspace_file_format;
+				ADD_ATTR(colorspace_file_format);
+
+				///* Optional transform for 3D images. */
+				//bool use_transform_3d;
+				//Transform transform_3d;
+
+				///* Automatically set. */
+				//bool compress_as_srgb;
+			}
+		}
+	}
+
+	foreach(ShaderNode * node, shader->graph->nodes) {
+		foreach(ShaderOutput * output, node->outputs) {
+			foreach(ShaderInput * input, output->links) {
+				xml_node connect_node = xml_root.append_child("connect");
+
+				xml_attribute attr_from_node = connect_node.append_attribute("from_node");
+				attr_from_node = xml_pointer_to_name(output->parent).c_str();
+
+				xml_attribute attr_from_socket = connect_node.append_attribute("from_socket");
+				attr_from_socket = output->socket_type.name.c_str();
+
+				xml_attribute attr_from_socket_ui = connect_node.append_attribute("from_socket_ui");
+				attr_from_socket_ui = output->socket_type.ui_name.c_str();
+
+				xml_attribute attr_to_node = connect_node.append_attribute("to_node");
+				string to_name = xml_pointer_to_name(input->parent);
+				if (dynamic_cast<OutputNode*>(input->parent))
+					to_name = input->parent->name.string(); // output
+				attr_to_node = to_name.c_str();
+					
+				xml_attribute attr_to_socket = connect_node.append_attribute("to_socket");
+				attr_to_socket = input->socket_type.name.c_str();
+
+				xml_attribute attr_to_socket_ui = connect_node.append_attribute("to_socket_ui");
+				attr_to_socket_ui = input->socket_type.ui_name.c_str();
+			}
+		}
+	}
+	//
+	//
+	//	xml_write_node(state, shader, graph_node);
+	//
+	//	ShaderGraph* graph = new ShaderGraph();
+	//
+	//	/* local state, shader nodes can't link to nodes outside the shader graph */
+	//	XMLReader graph_reader;
+	//	graph_reader.node_map[ustring("output")] = graph->output();
+	//
+	//	for (xml_node node = graph_node.first_child(); node; node = node.next_sibling()) {
+	//		ustring node_name(node.name());
+	//
+	//		if (node_name == "connect") {
+	//			/* connect nodes */
+	//			vector<string> from_tokens, to_tokens;
+	//
+	//			string_split(from_tokens, node.append_attribute("from").value());
+	//			string_split(to_tokens, node.append_attribute("to").value());
+	//
+	//			if (from_tokens.size() == 2 && to_tokens.size() == 2) {
+	//				ustring from_node_name(from_tokens[0]);
+	//				ustring from_socket_name(from_tokens[1]);
+	//				ustring to_node_name(to_tokens[0]);
+	//				ustring to_socket_name(to_tokens[1]);
+	//
+	//				/* find nodes and sockets */
+	//				ShaderOutput* output = NULL;
+	//				ShaderInput* input = NULL;
+	//
+	//				if (graph_reader.node_map.find(from_node_name) != graph_reader.node_map.end()) {
+	//					ShaderNode* fromnode = (ShaderNode*)graph_reader.node_map[from_node_name];
+	//
+	//					foreach(ShaderOutput * out, fromnode->outputs)
+	//						if (string_iequals(out->socket_type.name.string(), from_socket_name.string())) {
+	//							output = out;
+	//						}
+	//
+	//					if (!output) {
+	//						fprintf(stderr,
+	//							"Unknown output socket name \"%s\" on \"%s\".\n",
+	//							from_node_name.c_str(),
+	//							from_socket_name.c_str());
+	//					}
+	//				}
+	//				else {
+	//					fprintf(stderr, "Unknown shader node name \"%s\".\n", from_node_name.c_str());
+	//				}
+	//
+	//				if (graph_reader.node_map.find(to_node_name) != graph_reader.node_map.end()) {
+	//					ShaderNode* tonode = (ShaderNode*)graph_reader.node_map[to_node_name];
+	//
+	//					foreach(ShaderInput * in, tonode->inputs)
+	//						if (string_iequals(in->socket_type.name.string(), to_socket_name.string())) {
+	//							input = in;
+	//						}
+	//
+	//					if (!input) {
+	//						fprintf(stderr,
+	//							"Unknown input socket name \"%s\" on \"%s\".\n",
+	//							to_socket_name.c_str(),
+	//							to_node_name.c_str());
+	//					}
+	//				}
+	//				else {
+	//					fprintf(stderr, "Unknown shader node name \"%s\".\n", to_node_name.c_str());
+	//				}
+	//
+	//				/* connect */
+	//				if (output && input) {
+	//					graph->connect(output, input);
+	//				}
+	//			}
+	//			else {
+	//				fprintf(stderr, "Invalid from or to value for connect node.\n");
+	//			}
+	//
+	//			continue;
+	//		}
+	//
+	//		ShaderNode* snode = NULL;
+	//
+	//#ifdef WITH_OSL
+	//		if (node_name == "osl_shader") {
+	//			ShaderManager* manager = state.scene->shader_manager;
+	//
+	//			if (manager->use_osl()) {
+	//				std::string filepath;
+	//
+	//				if (scene_write_xml_string(&filepath, node, "src")) {
+	//					if (path_is_relative(filepath)) {
+	//						filepath = path_join(state.base, filepath);
+	//					}
+	//
+	//					snode = OSLShaderManager::osl_node(graph, manager, filepath, "");
+	//
+	//					if (!snode) {
+	//						fprintf(stderr, "Failed to create OSL node from \"%s\".\n", filepath.c_str());
+	//						continue;
+	//					}
+	//				}
+	//				else {
+	//					fprintf(stderr, "OSL node missing \"src\" attribute.\n");
+	//					continue;
+	//				}
+	//			}
+	//			else {
+	//				fprintf(stderr, "OSL node without using --shadingsys osl.\n");
+	//				continue;
+	//			}
+	//		}
+	//		else
+	//#endif
+	//		{
+	//			/* exception for name collision */
+	//			if (node_name == "background") {
+	//				node_name = "background_shader";
+	//			}
+	//
+	//			const NodeType* node_type = NodeType::find(node_name);
+	//
+	//			if (!node_type) {
+	//				fprintf(stderr, "Unknown shader node \"%s\".\n", node.name());
+	//				continue;
+	//			}
+	//			else if (node_type->type != NodeType::SHADER) {
+	//				fprintf(stderr, "Node type \"%s\" is not a shader node.\n", node_type->name.c_str());
+	//				continue;
+	//			}
+	//			else if (node_type->create == NULL) {
+	//				fprintf(stderr, "Can't create abstract node type \"%s\".\n", node_type->name.c_str());
+	//				continue;
+	//			}
+	//
+	//			snode = (ShaderNode*)node_type->create(node_type);
+	//			snode->set_owner(graph);
+	//		}
+	//
+	//		xml_write_node(graph_reader, snode, node);
+	//
+	//		if (node_name == "image_texture") {
+	//			ImageTextureNode* img = (ImageTextureNode*)snode;
+	//			ustring filename(path_join(state.base, img->get_filename().string()));
+	//			img->set_filename(filename);
+	//		}
+	//		else if (node_name == "environment_texture") {
+	//			EnvironmentTextureNode* env = (EnvironmentTextureNode*)snode;
+	//			ustring filename(path_join(state.base, env->get_filename().string()));
+	//			env->set_filename(filename);
+	//		}
+	//
+	//		if (snode) {
+	//			/* add to graph */
+	//			graph->add(snode);
+	//		}
+	//	}
+	//
+	//	shader->set_graph(graph);
+	//	shader->tag_update(state.scene);
+}
+
+void scene_write_xml_shader(XMLWriteState& state, xml_node node)
+{
+	//Shader* shader = new Shader();
+	foreach(Shader * shader, state.scene->shaders) {
+
+		//if (shader->name == "default_background" ||
+		//	shader->name == "default_empty" ||
+		//	shader->name == "default_light" ||
+		//	shader->name == "default_surface" ||
+		//	shader->name == "default_volume")
+		//	continue;
+
+		//xml_node xml_shader = node.append_child(shader->type->name.c_str());
+		xml_node xml_shader = xml_write_node(state, shader, node);
+
+		//if (shader->name == "default_background" ||
+		//	shader->name == "default_empty" ||
+		//	shader->name == "default_light" ||
+		//	shader->name == "default_surface" ||
+		//	shader->name == "default_volume") {
+
+		//	xml_attribute name_attr = xml_shader.attribute("name");
+		//	name_attr = shader->name.c_str();
+		//}
+
+		scene_write_xml_shader_graph(state, shader, xml_shader);
+	}
+	//state.scene->shaders.push_back(shader);
+}
+
+/* Background */
+
+//void scene_write_xml_background(Scene* scene, xml_node node)
+//{
+//	/* Background Settings */
+//	xml_write_node(scene->background, node);
+//
+//	/* Background Shader */
+//	Shader* shader = scene->default_background;
+//	xml_node xml_shader = node.append_child(shader->type->name.c_str());
+//	xml_write_node(shader, xml_shader);
+//
+//	scene_write_xml_shader_graph(shader, node);
+//}
+
+/* Mesh */
+
+//Mesh* xml_add_mesh(Scene* scene, const Transform& tfm, Object* object)
+//{
+//    if (object && object->get_geometry()->is_mesh()) {
+//        /* Use existing object and mesh */
+//        object->set_tfm(tfm);
+//        Geometry* geometry = object->get_geometry();
+//        return static_cast<Mesh*>(geometry);
+//    }
+//    else {
+//        /* Create mesh */
+//        Mesh* mesh = new Mesh();
+//        scene->geometry.push_back(mesh);
+//
+//        /* Create object. */
+//        Object* object = new Object();
+//        object->set_geometry(mesh);
+//        object->set_tfm(tfm);
+//        scene->objects.push_back(object);
+//
+//        return mesh;
+//    }
+//}
+//
+
+void scene_write_xml_geom(XMLWriteState& state, xml_node node)
+{
+	foreach(Geometry * geom, state.scene->geometry) {
+		//xml_node xml_node = node.append_child(mesh->type->name.c_str());
+		xml_node xml_node_geom = xml_write_node(state, geom, node);
+
+		//Type geometry_type;
+		xml_attribute attr_gt = xml_node_geom.append_attribute("geometry_type");
+		attr_gt = geom->geometry_type;
+
+		if (geom->attributes.attributes.size() > 0) {
+			//AttributeSet attributes;
+			//xml_node node_attributes = xml_node_geom.append_child("attributes");
+			foreach(Attribute & attr, geom->attributes.attributes) {
+				xml_node node_attribute = xml_node_geom.append_child("attribute");
+
+				//ustring name;
+				//ADD_ATTR_STR(name);
+				xml_attribute attr_name = node_attribute.append_attribute("name");
+				attr_name = attr.name.string().c_str();//(xml_pointer_to_name(&attr) + "_" + attr.name.string()).c_str();
+
+				//AttributeStandard std;
+				ADD_ATTR(std);				
+
+				//TypeDesc type;
+				//ADD_ATTR(type);
+				ADD_ATTR_DTYPE(attr.type, basetype);      ///< C data type at the heart of our type
+				ADD_ATTR_DTYPE(attr.type, aggregate);     ///< What kind of AGGREGATE is it?
+				ADD_ATTR_DTYPE(attr.type, vecsemantics);  ///< Hint: What does the aggregate represent?
+				ADD_ATTR_DTYPE(attr.type, reserved);      ///< Reserved for future expansion
+				ADD_ATTR_DTYPE(attr.type, arraylen);      ///< Array length, 0 = not array, -1 = unsized
+
+				//AttributeElement element;
+				ADD_ATTR(element);
+
+				//uint flags;
+				ADD_ATTR(flags);
+
+				//vector<char> buffer;
+				xml_attribute attr_buffer = node_attribute.append_attribute("buffer");
+
+				std::string str_buffer = xml_pointer_to_name(&attr) + "_" + attr.name.string();
+
+				std::stringstream ss;								
+
+				if (attr.element == AttributeElement::ATTR_ELEMENT_VOXEL) {
+					ImageHandle handle = attr.data_voxel();
+					VDBImageLoader *vdb_loader = handle.vdb_loader();
+
+					//vector<char> buffer;
+					//// Convert the stringstream to a vector<char>			
+					//std::ostringstream stream(std::ios_base::binary);
+					//openvdb::io::Stream(stream).write({ vdb_loader->get_grid() });
+					//stream.flush();
+					//const std::string& str = stream.str();
+					//buffer.assign(str.begin(), str.end());
+
+					//ss << write_vector_to_binary_file(state, geom, string("buffer"), buffer);
+
+					//std::stringstream ss;
+					//ss << geom->type->name << "_" << geom->name << "_" << attr.name.string() + string("_") + string("buffer") << ".vdb";					
+					//ss << attr_name.value() << ".vdb";					
+					//std::replace(str.begin(), str.end(), ' ', '_');
+					//ss << str_buffer << ".vdb";
+					//string filename(path_join(state.base, ss.str()));
+					//openvdb::io::File(filename).write({ vdb_loader->get_grid() });
+					
+					// Convert the stringstream to a vector<char>
+					vector<char> file_content;
+					std::ostringstream stream(std::ios_base::binary);
+					openvdb::io::Stream(stream).write({ vdb_loader->get_grid() });
+					stream.flush();
+					const std::string& str = stream.str();
+					file_content.assign(str.begin(), str.end());
+					ss << write_vector_to_binary_file(state, file_content);
+
+					xml_attribute attr_volume_type = node_attribute.append_attribute("volume_type");
+					attr_volume_type = "openvdb";					
+				}
+				else {
+					ss << write_vector_to_binary_file(state, attr.buffer);
+				}
+
+				attr_buffer = ss.str().c_str();
+			}
+		}
+
+		//BoundBox bounds;
+		//Transform transform_normal;
+	}
+
+//    /* add mesh */
+//    Mesh* mesh = xml_add_mesh(state.scene, state.tfm, state.object);
+//    array<Node*> used_shaders = mesh->get_used_shaders();
+//    used_shaders.push_back_slow(state.shader);
+//    mesh->set_used_shaders(used_shaders);
+//
+//    /* read state */
+//    int shader = 0;
+//    bool smooth = state.smooth;
+//
+//    /* read vertices and polygons */
+//    vector<float3> P;
+//    vector<float3> VN; /* Vertex normals */
+//    vector<float> UV;
+//    vector<float> T;  /* UV tangents */
+//    vector<float> TS; /* UV tangent signs */
+//    vector<int> verts, nverts;
+//
+//    scene_write_xml_float3_array(P, node, "P");
+//    scene_write_xml_int_array(verts, node, "verts");
+//    scene_write_xml_int_array(nverts, node, "nverts");
+//
+//    if (scene_write_xml_equal_string(node, "subdivision", "catmull-clark")) {
+//        mesh->set_subdivision_type(Mesh::SUBDIVISION_CATMULL_CLARK);
+//    }
+//    else if (scene_write_xml_equal_string(node, "subdivision", "linear")) {
+//        mesh->set_subdivision_type(Mesh::SUBDIVISION_LINEAR);
+//    }
+//
+//    array<float3> P_array;
+//    P_array = P;
+//
+//    if (mesh->get_subdivision_type() == Mesh::SUBDIVISION_NONE) {
+//        /* create vertices */
+//
+//        mesh->set_verts(P_array);
+//
+//        size_t num_triangles = 0;
+//        for (size_t i = 0; i < nverts.size(); i++) {
+//            num_triangles += nverts[i] - 2;
+//        }
+//        mesh->reserve_mesh(mesh->get_verts().size(), num_triangles);
+//
+//        /* create triangles */
+//        int index_offset = 0;
+//
+//        for (size_t i = 0; i < nverts.size(); i++) {
+//            for (int j = 0; j < nverts[i] - 2; j++) {
+//                int v0 = verts[index_offset];
+//                int v1 = verts[index_offset + j + 1];
+//                int v2 = verts[index_offset + j + 2];
+//
+//                assert(v0 < (int)P.size());
+//                assert(v1 < (int)P.size());
+//                assert(v2 < (int)P.size());
+//
+//                mesh->add_triangle(v0, v1, v2, shader, smooth);
+//            }
+//
+//            index_offset += nverts[i];
+//        }
+//
+//        /* Vertex normals */
+//        if (scene_write_xml_float3_array(VN, node, Attribute::standard_name(ATTR_STD_VERTEX_NORMAL))) {
+//            Attribute* attr = mesh->attributes.add(ATTR_STD_VERTEX_NORMAL);
+//            float3* fdata = attr->data_float3();
+//
+//            /* Loop over the normals */
+//            for (auto n : VN) {
+//                fdata[0] = n;
+//                fdata++;
+//            }
+//        }
+//
+//        /* UV map */
+//        if (scene_write_xml_float_array(UV, node, "UV") ||
+//            scene_write_xml_float_array(UV, node, Attribute::standard_name(ATTR_STD_UV)))
+//        {
+//            Attribute* attr = mesh->attributes.add(ATTR_STD_UV);
+//            float2* fdata = attr->data_float2();
+//
+//            /* Loop over the triangles */
+//            index_offset = 0;
+//            for (size_t i = 0; i < nverts.size(); i++) {
+//                for (int j = 0; j < nverts[i] - 2; j++) {
+//                    int v0 = index_offset;
+//                    int v1 = index_offset + j + 1;
+//                    int v2 = index_offset + j + 2;
+//
+//                    assert(v0 * 2 + 1 < (int)UV.size());
+//                    assert(v1 * 2 + 1 < (int)UV.size());
+//                    assert(v2 * 2 + 1 < (int)UV.size());
+//
+//                    fdata[0] = make_float2(UV[v0 * 2], UV[v0 * 2 + 1]);
+//                    fdata[1] = make_float2(UV[v1 * 2], UV[v1 * 2 + 1]);
+//                    fdata[2] = make_float2(UV[v2 * 2], UV[v2 * 2 + 1]);
+//                    fdata += 3;
+//                }
+//
+//                index_offset += nverts[i];
+//            }
+//        }
+//
+//        /* Tangents */
+//        if (scene_write_xml_float_array(T, node, Attribute::standard_name(ATTR_STD_UV_TANGENT))) {
+//            Attribute* attr = mesh->attributes.add(ATTR_STD_UV_TANGENT);
+//            float3* fdata = attr->data_float3();
+//
+//            /* Loop over the triangles */
+//            index_offset = 0;
+//            for (size_t i = 0; i < nverts.size(); i++) {
+//                for (int j = 0; j < nverts[i] - 2; j++) {
+//                    int v0 = index_offset;
+//                    int v1 = index_offset + j + 1;
+//                    int v2 = index_offset + j + 2;
+//
+//                    assert(v0 * 3 + 2 < (int)T.size());
+//                    assert(v1 * 3 + 2 < (int)T.size());
+//                    assert(v2 * 3 + 2 < (int)T.size());
+//
+//                    fdata[0] = make_float3(T[v0 * 3], T[v0 * 3 + 1], T[v0 * 3 + 2]);
+//                    fdata[1] = make_float3(T[v1 * 3], T[v1 * 3 + 1], T[v1 * 3 + 2]);
+//                    fdata[2] = make_float3(T[v2 * 3], T[v2 * 3 + 1], T[v2 * 3 + 2]);
+//                    fdata += 3;
+//                }
+//                index_offset += nverts[i];
+//            }
+//        }
+//
+//        /* Tangent signs */
+//        if (scene_write_xml_float_array(TS, node, Attribute::standard_name(ATTR_STD_UV_TANGENT_SIGN))) {
+//            Attribute* attr = mesh->attributes.add(ATTR_STD_UV_TANGENT_SIGN);
+//            float* fdata = attr->data_float();
+//
+//            /* Loop over the triangles */
+//            index_offset = 0;
+//            for (size_t i = 0; i < nverts.size(); i++) {
+//                for (int j = 0; j < nverts[i] - 2; j++) {
+//                    int v0 = index_offset;
+//                    int v1 = index_offset + j + 1;
+//                    int v2 = index_offset + j + 2;
+//
+//                    assert(v0 < (int)TS.size());
+//                    assert(v1 < (int)TS.size());
+//                    assert(v2 < (int)TS.size());
+//
+//                    fdata[0] = TS[v0];
+//                    fdata[1] = TS[v1];
+//                    fdata[2] = TS[v2];
+//                    fdata += 3;
+//                }
+//                index_offset += nverts[i];
+//            }
+//        }
+//    }
+//    else {
+//        /* create vertices */
+//        mesh->set_verts(P_array);
+//
+//        size_t num_ngons = 0;
+//        size_t num_corners = 0;
+//        for (size_t i = 0; i < nverts.size(); i++) {
+//            num_ngons += (nverts[i] == 4) ? 0 : 1;
+//            num_corners += nverts[i];
+//        }
+//        mesh->reserve_subd_faces(nverts.size(), num_ngons, num_corners);
+//
+//        /* create subd_faces */
+//        int index_offset = 0;
+//
+//        for (size_t i = 0; i < nverts.size(); i++) {
+//            mesh->add_subd_face(&verts[index_offset], nverts[i], shader, smooth);
+//            index_offset += nverts[i];
+//        }
+//
+//        /* UV map */
+//        if (scene_write_xml_float_array(UV, node, "UV") ||
+//            scene_write_xml_float_array(UV, node, Attribute::standard_name(ATTR_STD_UV)))
+//        {
+//            Attribute* attr = mesh->subd_attributes.add(ATTR_STD_UV);
+//            float3* fdata = attr->data_float3();
+//
+//#if 0
+//            if (subdivide_uvs) {
+//                attr->flags |= ATTR_SUBDIVIDED;
+//            }
+//#endif
+//
+//            index_offset = 0;
+//            for (size_t i = 0; i < nverts.size(); i++) {
+//                for (int j = 0; j < nverts[i]; j++) {
+//                    *(fdata++) = make_float3(UV[index_offset++]);
+//                }
+//            }
+//        }
+//
+//        /* setup subd params */
+//        float dicing_rate = state.dicing_rate;
+//        scene_write_xml_float(&dicing_rate, node, "dicing_rate");
+//        dicing_rate = std::max(0.1f, dicing_rate);
+//
+//        mesh->set_subd_dicing_rate(dicing_rate);
+//        mesh->set_subd_objecttoworld(state.tfm);
+//    }
+//
+//    /* we don't yet support arbitrary attributes, for now add vertex
+//     * coordinates as generated coordinates if requested */
+//    if (mesh->need_attribute(state.scene, ATTR_STD_GENERATED)) {
+//        Attribute* attr = mesh->attributes.add(ATTR_STD_GENERATED);
+//        memcpy(
+//            attr->data_float3(), mesh->get_verts().data(), sizeof(float3) * mesh->get_verts().size());
+//    }
+}
+
+/* Light */
+
+void scene_write_xml_light(XMLWriteState& state, xml_node node)
+{
+	//Light* light = new Light();
+
+	//light->set_shader(state.shader);
+	foreach(Light * light, state.scene->lights) {
+		//xml_node xml_node = node.append_child(light->type->name.c_str());
+		//if (light->get_light_type() != LIGHT_BACKGROUND)
+		xml_write_node(state, light, node);
+	}
+
+	//state.scene->lights.push_back(light);
+}
+
+void scene_write_xml_particle_systems(XMLWriteState& state, xml_node node)
+{
+	foreach(ParticleSystem * ps, state.scene->particle_systems) {
+		xml_write_node(state, ps, node);
+	}
+}
+
+//void scene_write_xml_passes(XMLWriteState& state, xml_node node)
+//{
+//	foreach(Pass * pass, scene->passes) {
+//		xml_write_node(pass, node);
+//	}
+//}
+//
+//void scene_write_xml_procedurals(XMLWriteState& state, xml_node node)
+//{
+//	foreach(Procedural * p, scene->procedurals) {
+//		xml_write_node(p, node);
+//	}
+//}
+
+/* Transform */
+
+//void scene_write_xml_transform(xml_node node, Transform& tfm)
+//{
+//    if (node.append_attribute("matrix")) {
+//        vector<float> matrix;
+//        if (scene_write_xml_float_array(matrix, node, "matrix") && matrix.size() == 16) {
+//            ProjectionTransform projection = *(ProjectionTransform*)&matrix[0];
+//            tfm = tfm * projection_to_transform(projection_transpose(projection));
+//        }
+//    }
+//
+//    if (node.append_attribute("translate")) {
+//        float3 translate = zero_float3();
+//        scene_write_xml_float3(&translate, node, "translate");
+//        tfm = tfm * transform_translate(translate);
+//    }
+//
+//    if (node.append_attribute("rotate")) {
+//        float4 rotate = zero_float4();
+//        scene_write_xml_float4(&rotate, node, "rotate");
+//        tfm = tfm * transform_rotate(DEG2RADF(rotate.x), make_float3(rotate.y, rotate.z, rotate.w));
+//    }
+//
+//    if (node.append_attribute("scale")) {
+//        float3 scale = zero_float3();
+//        scene_write_xml_float3(&scale, node, "scale");
+//        tfm = tfm * transform_scale(scale);
+//    }
+//}
+
+/* State */
+
+//void scene_write_xml_state(XMLReadState& state, xml_node node)
+//{
+//	/* Read shader */
+//	string shadername;
+//
+//	if (scene_write_xml_string(&shadername, node, "shader")) {
+//		bool found = false;
+//
+//		foreach(Shader * shader, state.scene->shaders) {
+//			if (shader->name == shadername) {
+//				state.shader = shader;
+//				found = true;
+//				break;
+//			}
+//		}
+//
+//		if (!found) {
+//			fprintf(stderr, "Unknown shader \"%s\".\n", shadername.c_str());
+//		}
+//	}
+//
+//	/* Read object */
+//	string objectname;
+//
+//	if (scene_write_xml_string(&objectname, node, "object")) {
+//		bool found = false;
+//
+//		foreach(Object * object, state.scene->objects) {
+//			if (object->name == objectname) {
+//				state.object = object;
+//				found = true;
+//				break;
+//			}
+//		}
+//
+//		if (!found) {
+//			fprintf(stderr, "Unknown object \"%s\".\n", objectname.c_str());
+//		}
+//	}
+//
+//	scene_write_xml_float(&state.dicing_rate, node, "dicing_rate");
+//
+//	/* read smooth/flat */
+//	if (scene_write_xml_equal_string(node, "interpolation", "smooth")) {
+//		state.smooth = true;
+//	}
+//	else if (scene_write_xml_equal_string(node, "interpolation", "flat")) {
+//		state.smooth = false;
+//	}
+//}
+
+/* Object */
+
+void scene_write_xml_object(XMLWriteState& state, xml_node node)
+{
+//    Scene* scene = state.scene;
+//
+//    /* create mesh */
+//    Mesh* mesh = new Mesh();
+//    scene->geometry.push_back(mesh);
+//
+//    /* create object */
+//    Object* object = new Object();
+//    object->set_geometry(mesh);
+//    object->set_tfm(state.tfm);
+//
+//    xml_write_node(state, object, node);
+//
+//    scene->objects.push_back(object);
+
+	foreach(Object * object, state.scene->objects) {
+		xml_node xml_node_obj = xml_write_node(state, object, node);
+
+		if (object->attributes.size() > 0) {
+			//AttributeSet attributes;
+			//xml_node node_attributes = xml_node_obj.append_child("attributes");
+			foreach(ParamValue & param_value, object->attributes) {
+				xml_node node_attribute = xml_node_obj.append_child("attribute");
+
+				//ustring m_name;   ///< data name
+				xml_attribute attr_name = node_attribute.append_attribute("name");
+				attr_name = (xml_pointer_to_name(&param_value) + "_" + param_value.name().string()).c_str();
+
+				//TypeDesc m_type;  ///< data type, which may itself be an array
+				//xml_attribute attr_type = node_attribute.append_attribute("type");
+				//attr_type = (int)param_value.type();// .c_str();
+
+				//ADD_ATTR(type);
+				ADD_ATTR_DTYPE(param_value.type(), basetype);      ///< C data type at the heart of our type
+				ADD_ATTR_DTYPE(param_value.type(), aggregate);     ///< What kind of AGGREGATE is it?
+				ADD_ATTR_DTYPE(param_value.type(), vecsemantics);  ///< Hint: What does the aggregate represent?
+				ADD_ATTR_DTYPE(param_value.type(), reserved);      ///< Reserved for future expansion
+				ADD_ATTR_DTYPE(param_value.type(), arraylen);      ///< Array length, 0 = not array, -1 = unsized
+
+				//union {
+				//	char localval[16];
+				//	const void* ptr;
+				//} m_data;  ///< Our data, either a pointer or small local value
+
+				vector<char> data(param_value.datasize());
+				memcpy(data.data(), param_value.data(), param_value.datasize());
+				xml_attribute attr_data = node_attribute.append_attribute("data");
+				std::stringstream ss;
+				ss << write_vector_to_binary_file(state, data);
+				attr_data = ss.str().c_str();
+
+				//int m_nvalues = 0;  ///< number of values of the given type
+				//unsigned char m_interp = INTERP_CONSTANT;  ///< Interpolation type
+				xml_attribute attr_interp = node_attribute.append_attribute("interp");
+				attr_interp = param_value.interp();
+				//bool m_copy = false;
+				//bool m_nonlocal = false;
+				//xml_attribute attr_nonlocal = node_attribute.append_attribute("nonlocal");
+				//attr_nonlocal = param_value.is_nonlocal();
+			}
+		}
+	}
+}
+
+/* Scene */
+
+void scene_write_xml_scene(XMLWriteState& state, xml_node scene_node)
+{
+	//for (xml_node node = scene_node.first_child(); node; node = node.next_sibling()) {
+		//if (string_iequals(node.name(), "film")) {
+	//xml_node film = scene_node.append_child(scene->film->type->name.c_str());
+	xml_write_node(state, state.scene->film, scene_node).attribute("name") = "film";
+	//}
+//	else if (string_iequals(node.name(), "integrator")) {
+	//xml_node integrator = scene_node.append_child("integrator");
+	xml_write_node(state, state.scene->integrator, scene_node).attribute("name") = "integrator";
+	//}
+	//else if (string_iequals(node.name(), "camera")) {
+	//xml_node camera = scene_node.append_child("camera");
+	xml_write_node(state, state.scene->camera, scene_node).attribute("name") = "camera";
+	//}
+	//		else if (string_iequals(node.name(), "background")) {
+	//xml_node background = scene_node.append_child("background");
+	//scene_write_xml_background(scene, background);
+	xml_write_node(state, state.scene->background, scene_node).attribute("name") = "background";
+	//		}
+	//		else if (string_iequals(node.name(), "shader")) {
+	//xml_node shader = scene_node.append_child("shader");
+	scene_write_xml_shader(state, scene_node);
+	//		}
+	//		else if (string_iequals(node.name(), "light")) {	
+	scene_write_xml_light(state, scene_node);
+	//		}
+	//		else if (string_iequals(node.name(), "mesh")) {
+	//xml_node mesh = scene_node.append_child("mesh");
+	scene_write_xml_geom(state, scene_node);
+
+	scene_write_xml_particle_systems(state, scene_node);
+	//scene_write_xml_passes(scene, scene_node);
+	//scene_write_xml_procedurals(scene, scene_node);
+
+	//		}
+	//		else if (string_iequals(node.name(), "transform")) {
+	//			XMLReadState substate = state;
+	//
+	   //         xml_node transform = scene_node.append_child("transform");
+				//scene_write_xml_transform(transform, scene/*substate.tfm*/);
+				//scene_write_xml_scene(scene, transform);
+	//		}
+	//		else if (string_iequals(node.name(), "state")) {
+	//			XMLReadState substate = state;
+	//
+	   //         xml_node state = scene_node.append_child("state");
+				//scene_write_xml_state(scene, state);
+				//scene_write_xml_scene(scene, state);
+	//		}
+	//		else if (string_iequals(node.name(), "include")) {
+	//			string src;
+				//xml_node node_include = scene_node.append_child("include");
+
+	//			if (scene_write_xml_string(&src, node, "src")) {
+	//				scene_write_xml_include(state, src);
+	//			}
+	//		}
+	//		else if (string_iequals(node.name(), "object")) {
+	//			XMLReadState substate = state;
+	//
+	   //         xml_node object = scene_node.append_child("object");
+	scene_write_xml_object(state, scene_node);
+				//scene_write_xml_scene(scene, object);
+	//		}
+	//#ifdef WITH_ALEMBIC
+	//		else if (string_iequals(node.name(), "alembic")) {
+	//			scene_write_xml_alembic(state, node);
+	//		}
+	//#endif
+	//		else {
+	//			fprintf(stderr, "Unknown node \"%s\".\n", node.name());
+	//		}
+		//}
+}
+
+/* Include */
+
+void scene_write_xml_include(XMLWriteState &state, const string& filename_xml)
+{
+	/* open XML document */
+	xml_document doc;
+	//xml_parse_result parse_result;
+
+	//string path = path_join(state.base, src);
+	//parse_result = doc.load_file(path.c_str());
+
+	//if (parse_result) {
+		//XMLReadState substate = state;
+		//substate.base = path_dirname(path);
+
+	string filename_bin = string(filename_xml) + string(".bin");
+
+	// Open the file in binary write mode
+	state.file.open(filename_bin, std::ios::binary);
+	if (!state.file.is_open()) {
+		std::cerr << "Error: Could not open file for writing: " << filename_bin << "\n";
+		return;
+	}
+
+	xml_node cycles = doc.append_child("cycles");
+	scene_write_xml_scene(state, cycles);
+	//}
+	//else {
+	//    fprintf(stderr, "%s read error: %s\n", src.c_str(), parse_result.description());
+	//    exit(EXIT_FAILURE);
+	//}
+
+	// Save the XML to a file
+	doc.save_file(filename_xml.c_str());
+
+	state.file.close();
+}
+
+/* File */
+
+void scene_write_xml_file(Scene* scene, const char* filepath)
+{
+	if (scene == nullptr || filepath == nullptr)
+		return;
+
+	XMLWriteState state;
+
+	state.scene = scene;
+	//std::string base = path_dirname(filepath);
+
+	scene_write_xml_include(state, filepath);	
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/scene/scene_write_xml.h b/intern/cycles/scene/scene_write_xml.h
new file mode 100644
index 0000000000000000000000000000000000000000..164c82a0920caf67ad482089a4d79a63cb9cb5e0
--- /dev/null
+++ b/intern/cycles/scene/scene_write_xml.h
@@ -0,0 +1,38 @@
+/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
+ *
+ * SPDX-License-Identifier: Apache-2.0 */
+
+#pragma once
+
+#include "graph/node_xml.h"
+#include "scene/scene.h"
+
+CCL_NAMESPACE_BEGIN
+
+#if 0
+void scene_write_xml_int(int value, xml_node node, const char* name);
+void scene_write_xml_int_array(vector<int>& value, xml_node node, const char* name);
+void scene_write_xml_float(float value, xml_node node, const char* name);
+void scene_write_xml_float_array(vector<float>& value, xml_node node, const char* name);
+void scene_write_xml_float3(float3 value, xml_node node, const char* name);
+void scene_write_xml_float3_array(vector<float3>& value, xml_node node, const char* name);
+void scene_write_xml_float4(float4 value, xml_node node, const char* name);
+void scene_write_xml_string(string str, xml_node node, const char* name);
+void scene_write_xml_camera(Scene *scene, xml_node node);
+//void scene_write_xml_alembic(Scene *scene, xml_node graph_node);
+void scene_write_xml_shader_graph(Scene *scene, Shader* shader, xml_node graph_node);
+void scene_write_xml_shader(Scene *scene, xml_node node);
+void scene_write_xml_background(Scene *scene, xml_node node);
+//void scene_write_xml_mesh(const Scene *scene, xml_node node);
+void scene_write_xml_light(Scene *scene, xml_node node);
+void scene_write_xml_transform(xml_node node, Transform& tfm);
+void scene_write_xml_state(Scene *scene, xml_node node);
+void scene_write_xml_object(Scene *scene, xml_node node);
+void scene_write_xml_include(Scene *scene, const string& src);
+void scene_write_xml_scene(Scene *scene, xml_node scene_node);
+void scene_write_xml_include(Scene *scene, const string& src);
+#endif
+
+void scene_write_xml_file(Scene* scene, const char* filepath);
+
+CCL_NAMESPACE_END