using System.Collections.Generic; using System.Globalization; using System.IO; using System.Xml; namespace Oni.Level { using Akira; using Metadata; using Motoko; using Physics; using Xml; partial class LevelImporter { private void ReadPhysics(XmlReader xml, string basePath) { if (xml.SkipEmpty()) return; xml.ReadStartElement("Physics"); while (xml.IsStartElement()) ReadObjectSetup(xml, basePath); xml.ReadEndElement(); } private void ReadObjectSetup(XmlReader xml, string basePath) { var scriptId = -1; var name = xml.GetAttribute("Name"); var position = Vector3.Zero; var rotation = Quaternion.Identity; var scale = 1.0f; var flags = ObjectSetupFlags.None; var physicsType = ObjectPhysicsType.None; var particles = new List(); var nodes = new List(); string geometryName = null; string animationName = null; xml.ReadStartElement("Object"); while (xml.IsStartElement()) { switch (xml.LocalName) { case "Name": name = xml.ReadElementContentAsString(); break; case "ScriptId": scriptId = xml.ReadElementContentAsInt(); break; case "Flags": flags = xml.ReadElementContentAsEnum() & ~ObjectSetupFlags.InUse; break; case "Position": position = xml.ReadElementContentAsVector3(); break; case "Rotation": rotation = xml.ReadElementContentAsEulerXYZ(); break; case "Scale": scale = xml.ReadElementContentAsFloat(); break; case "Physics": physicsType = xml.ReadElementContentAsEnum(); break; case "Particles": particles.AddRange(ReadParticles(xml, basePath)); break; case "Geometry": geometryName = xml.ReadElementContentAsString(); if (nodes.Count > 0) { error.WriteLine("Geometry cannot be used together with Import, ignoring"); break; } break; case "Animation": animationName = xml.ReadElementContentAsString(); if (nodes.Count > 0) { error.WriteLine("Animation cannot be used together with Import, ignoring"); break; } break; case "Import": if (geometryName != null || animationName != null) { error.WriteLine("Import cannot be used together with Geometry and Animation, ignoring"); break; } nodes.AddRange(ImportObjectGeometry(xml, basePath)); break; default: error.WriteLine("Unknown physics object element {0}", xml.LocalName); xml.Skip(); break; } } xml.ReadEndElement(); if (geometryName != null) { var m3gm = FindSharedInstance(TemplateTag.M3GM, geometryName, objectLoadContext); var geometry = GeometryDatReader.Read(m3gm); var animation = new ObjectAnimation[0]; if (animationName != null) { var oban = FindSharedInstance(TemplateTag.OBAN, animationName, objectLoadContext); animation = new[] { ObjectDatReader.ReadAnimation(oban) }; } nodes.Add(new ObjectNode(new[] { new ObjectGeometry(geometry) }) { FileName = Path.GetFileName(geometryName), Name = m3gm.Name, ScriptId = scriptId, Flags = flags, Animations = animation }); } for (int i = 0; i < nodes.Count; i++) { var node = nodes[i]; var setup = new ObjectSetup { Name = node.Name, FileName = node.FileName, ScriptId = scriptId++, Flags = flags, PhysicsType = physicsType, }; setup.Particles.AddRange(particles); setup.Geometries = node.Geometries .Where(n => (n.Flags & GunkFlags.Invisible) == 0) .Select(n => n.Geometry.Name).ToArray(); foreach (var nodeGeometry in node.Geometries.Where(g => (g.Flags & GunkFlags.Invisible) == 0)) { var writer = new DatWriter(); GeometryDatWriter.Write(nodeGeometry.Geometry, writer.ImporterFile); writer.Write(outputDirPath); } setup.Position = position; setup.Orientation = rotation; setup.Scale = scale; setup.Origin = Matrix.CreateFromQuaternion(setup.Orientation) * Matrix.CreateScale(setup.Scale) * Matrix.CreateTranslation(setup.Position); foreach (var animation in node.Animations) { if (nodes.Count > 1) animation.Name += i.ToString("d2", CultureInfo.InvariantCulture); if ((animation.Flags & ObjectAnimationFlags.Local) != 0) { //animation.Scale = Matrix.CreateScale(setup.Scale); foreach (var key in animation.Keys) { key.Rotation = setup.Orientation * key.Rotation; key.Translation += setup.Position; } } if ((animation.Flags & ObjectAnimationFlags.AutoStart) != 0) { setup.Animation = animation; setup.PhysicsType = ObjectPhysicsType.Animated; } var writer = new DatWriter(); ObjectDatWriter.WriteAnimation(animation, writer); writer.Write(outputDirPath); } if (setup.Animation == null && node.Animations.Length > 0) { setup.Animation = node.Animations[0]; } if (setup.Animation != null) { var frame0 = setup.Animation.Keys[0]; setup.Scale = frame0.Scale.X; setup.Orientation = frame0.Rotation; setup.Position = frame0.Translation; } level.physics.Add(setup); } } private IEnumerable ImportObjectGeometry(XmlReader xml, string basePath) { var filePath = xml.GetAttribute("Path"); if (filePath == null) filePath = xml.GetAttribute("Url"); var scene = LoadScene(Path.Combine(basePath, filePath)); var animClips = new List(); if (!xml.SkipEmpty()) { xml.ReadStartElement(); while (xml.IsStartElement()) { switch (xml.LocalName) { case "Animation": animClips.Add(ReadAnimationClip(xml)); break; default: error.WriteLine("Unknown element {0}", xml.LocalName); xml.Skip(); break; } } xml.ReadEndElement(); } var importer = new ObjectDaeImporter(textureImporter, null); importer.Import(scene); return importer.Nodes; } } }