private void ExportCollada_Mesh(XmlWriter xml, string name, IReadOnlyList<Kn5Node> unsorted) {
xml.WriteStartElement("geometry");
xml.WriteAttributeStringSafe("id", $"{name}-mesh");
xml.WriteAttributeStringSafe("name", name);
xml.WriteStartElement("mesh");
var nodes = unsorted.Count == 1 ? unsorted :
unsorted.OrderBy(x => int.Parse(x.Name.Split(new[] { "_SUB" }, StringSplitOptions.None).Last())).ToList();
/* coordinates */
var vertexCount = nodes.Sum(x => x.Vertices.Length);
xml.WriteStartElement("source");
xml.WriteAttributeStringSafe("id", $"{name}-mesh-positions");
xml.WriteStartElement("float_array");
xml.WriteAttributeStringSafe("id", $"{name}-mesh-positions-array");
xml.WriteAttributeString("count", vertexCount * 3);
xml.WriteString(nodes.SelectMany(x => x.Vertices).SelectMany(x => x.Co).JoinToString(" "));
xml.WriteEndElement(); // float_array
xml.WriteStartElement("technique_common");
xml.WriteStartElement("accessor");
xml.WriteAttributeStringSafe("source", $"#{name}-mesh-positions-array");
xml.WriteAttributeString("count", vertexCount);
xml.WriteAttributeString("stride", 3);
xml.WriteElement("param",
"name", "X",
"type", "float");
xml.WriteElement("param",
"name", "Y",
"type", "float");
xml.WriteElement("param",
"name", "Z",
"type", "float");
xml.WriteEndElement(); // accessor
xml.WriteEndElement(); // technique_common
xml.WriteEndElement(); // source
/* normals */
xml.WriteStartElement("source");
xml.WriteAttributeStringSafe("id", $"{name}-mesh-normals");
xml.WriteStartElement("float_array");
xml.WriteAttributeStringSafe("id", $"{name}-mesh-normals-array");
xml.WriteAttributeString("count", vertexCount * 3);
xml.WriteString(nodes.SelectMany(x => x.Vertices).SelectMany(x => x.Normal).JoinToString(" "));
xml.WriteEndElement(); // float_array
xml.WriteStartElement("technique_common");
xml.WriteStartElement("accessor");
xml.WriteAttributeStringSafe("source", $"#{name}-mesh-normals-array");
xml.WriteAttributeString("count", vertexCount);
xml.WriteAttributeString("stride", "3");
xml.WriteElement("param",
"name", "X",
"type", "float");
xml.WriteElement("param",
"name", "Y",
"type", "float");
xml.WriteElement("param",
"name", "Z",
"type", "float");
xml.WriteEndElement(); // accessor
xml.WriteEndElement(); // technique_common
xml.WriteEndElement(); // source
/* uv */
xml.WriteStartElement("source");
xml.WriteAttributeStringSafe("id", $"{name}-mesh-map-0");
xml.WriteStartElement("float_array");
xml.WriteAttributeStringSafe("id", $"{name}-mesh-map-0-array");
xml.WriteAttributeString("count", vertexCount * 2);
xml.WriteString(nodes.SelectMany(x => x.Vertices).SelectMany(x => new[] { x.Uv[0], -x.Uv[1] }).JoinToString(" "));
xml.WriteEndElement(); // float_array
xml.WriteStartElement("technique_common");
xml.WriteStartElement("accessor");
xml.WriteAttributeStringSafe("source", $"#{name}-mesh-map-0-array");
xml.WriteAttributeString("count", vertexCount);
xml.WriteAttributeString("stride", 2);
xml.WriteElement("param",
"name", "S",
"type", "float");
xml.WriteElement("param",
"name", "T",
"type", "float");
xml.WriteEndElement(); // accessor
xml.WriteEndElement(); // technique_common
xml.WriteEndElement(); // source
/* vertices */
xml.WriteStartElement("vertices");
xml.WriteAttributeStringSafe("id", $"{name}-mesh-vertices");
xml.WriteElement("input",
"semantic", "POSITION",
"source", $"#{name}-mesh-positions");
xml.WriteEndElement();
/* triangles */
var offset = 0;
foreach (var node in nodes) {
xml.WriteStartElement("triangles");
xml.WriteAttributeStringSafe("original_node", $"{node.Name}");
xml.WriteAttributeStringSafe("material", $"{Materials.Values.ElementAt((int)node.MaterialId).Name}-material");
xml.WriteAttributeString("count", node.Indices.Length / 3);
xml.WriteElement("input",
"semantic", "VERTEX",
"source", $"#{name}-mesh-vertices",
"offset", 0);
xml.WriteElement("input",
"semantic", "NORMAL",
"source", $"#{name}-mesh-normals",
"offset", 1);
xml.WriteElement("input",
"semantic", "TEXCOORD",
"source", $"#{name}-mesh-map-0",
"offset", 2,
"set", 0);
var inner = offset;
xml.WriteElementString("p", node.Indices.SelectMany(x => new[] { x + inner, x + inner, x + inner }).JoinToString(" "));
xml.WriteEndElement(); // triangles
offset += node.Vertices.Length;
}
xml.WriteEndElement(); // mesh
xml.WriteEndElement(); // geometry
}