/// <summary>Loads a Loksim3D GruppenObject</summary> /// <param name="FileName">The filename to load</param> /// <param name="Encoding">The text encoding of the containing file (Currently ignored, REMOVE??)</param> /// <param name="Rotation">A three-dimemsional vector describing the rotation to be applied</param> /// <returns>A new animated object collection, containing the GruppenObject's meshes etc.</returns> internal static ObjectManager.AnimatedObjectCollection ReadObject(string FileName, Encoding Encoding, Vector3 Rotation) { XmlDocument currentXML = new XmlDocument(); ObjectManager.AnimatedObjectCollection Result = new ObjectManager.AnimatedObjectCollection(); Result.Objects = new ObjectManager.AnimatedObject[0]; try { currentXML.Load(FileName); } catch (Exception ex) { //The XML is not strictly valid string[] Lines = File.ReadAllLines(FileName); using (var stringReader = new StringReader(Lines[0])) { var settings = new XmlReaderSettings { ConformanceLevel = ConformanceLevel.Fragment }; using (var xmlReader = XmlReader.Create(stringReader, settings)) { if (xmlReader.Read()) { //Attempt to find the text encoding and re-read the file var result = xmlReader.GetAttribute("encoding"); if (result != null) { var e = System.Text.Encoding.GetEncoding(result); Lines = File.ReadAllLines(FileName, e); //Turf out the old encoding, as our string array should now be UTF-8 Lines[0] = "<?xml version=\"1.0\"?>"; } } } } for (int i = 0; i < Lines.Length; i++) { while (Lines[i].IndexOf("\"\"", StringComparison.InvariantCulture) != -1) { //Loksim parser tolerates multiple quotes, strict XML does not Lines[i] = Lines[i].Replace("\"\"", "\""); } while (Lines[i].IndexOf(" ", StringComparison.InvariantCulture) != -1) { //Replace double-spaces with singles Lines[i] = Lines[i].Replace(" ", " "); } } bool tryLoad = false; try { //Horrible hack: Write out our string array to a new memory stream, then load from this stream //Why can't XmlDocument.Load() just take a string array...... using (var stream = new MemoryStream()) { var sw = new StreamWriter(stream); foreach (var line in Lines) { sw.Write(line); sw.Flush(); } sw.Flush(); stream.Position = 0; currentXML.Load(stream); tryLoad = true; } } catch { //Generic catch-all clause } if (!tryLoad) { //Pass out the *original* XML error, not anything generated when we've tried to correct it Interface.AddMessage(MessageType.Error, false, "Error parsing Loksim3D XML: " + ex.Message); return(null); } } string BaseDir = System.IO.Path.GetDirectoryName(FileName); GruppenObject[] CurrentObjects = new GruppenObject[0]; //Check for null if (currentXML.DocumentElement != null) { UnifiedObject[] obj = new UnifiedObject[0]; XmlNodeList DocumentNodes = currentXML.DocumentElement.SelectNodes("/GRUPPENOBJECT"); if (DocumentNodes != null) { foreach (XmlNode outerNode in DocumentNodes) { if (outerNode.ChildNodes.OfType <XmlElement>().Any()) { foreach (XmlNode node in outerNode.ChildNodes) { if (node.Name == "Object" && node.ChildNodes.OfType <XmlElement>().Any()) { foreach (XmlNode childNode in node.ChildNodes) { if (childNode.Name == "Props" && childNode.Attributes != null) { GruppenObject Object = new GruppenObject { Rotation = Rotation }; foreach (XmlAttribute attribute in childNode.Attributes) { switch (attribute.Name) { case "Name": string ObjectFile = OpenBveApi.Path.Loksim3D.CombineFile(BaseDir, attribute.Value, Program.FileSystem.LoksimPackageInstallationDirectory); if (!File.Exists(ObjectFile)) { Object.Name = null; Interface.AddMessage(MessageType.Warning, true, "Ls3d Object file " + attribute.Value + " not found."); } else { Object.Name = ObjectFile; } break; case "Position": string[] SplitPosition = attribute.Value.Split(';'); double.TryParse(SplitPosition[0], out Object.Position.X); double.TryParse(SplitPosition[1], out Object.Position.Y); double.TryParse(SplitPosition[2], out Object.Position.Z); break; case "Rotation": string[] SplitRotation = attribute.Value.Split(';'); Vector3 r; double.TryParse(SplitRotation[0], out r.X); double.TryParse(SplitRotation[1], out r.Y); double.TryParse(SplitRotation[2], out r.Z); Object.Rotation += r; break; case "ShowOn": //Defines when the object should be shown Object.FunctionScript = FunctionScriptNotation.GetPostfixNotationFromInfixNotation(GetAnimatedFunction(attribute.Value, false)); break; case "HideOn": //Defines when the object should be hidden Object.FunctionScript = FunctionScriptNotation.GetPostfixNotationFromInfixNotation(GetAnimatedFunction(attribute.Value, true)); break; case "FixedDynamicVisibility": if (attribute.Value.ToLowerInvariant() == "true") { Object.FixedDynamicVisibility = true; } else { Object.FixedDynamicVisibility = false; } break; case "DynamicVisibility": if (Object.FixedDynamicVisibility) { Object.FunctionScript = FunctionScriptNotation.GetPostfixNotationFromInfixNotation(GetDynamicFunction(attribute.Value)); } break; } } if (Object.Name != null) { Array.Resize <GruppenObject>(ref CurrentObjects, CurrentObjects.Length + 1); CurrentObjects[CurrentObjects.Length - 1] = Object; } } } } } } } //We've loaded the XML references, now load the objects into memory //Single mesh object, containing all static components of the LS3D object //If we use multiples, the Z-sorting throws a wobbly StaticObject staticObject = null; for (int i = 0; i < CurrentObjects.Length; i++) { if (CurrentObjects[i] == null || string.IsNullOrEmpty(CurrentObjects[i].Name)) { continue; } StaticObject Object = null; ObjectManager.AnimatedObjectCollection AnimatedObject = null; try { if (CurrentObjects[i].Name.ToLowerInvariant().EndsWith(".l3dgrp")) { AnimatedObject = ReadObject(CurrentObjects[i].Name, Encoding, CurrentObjects[i].Rotation); } else if (CurrentObjects[i].Name.ToLowerInvariant().EndsWith(".l3dobj")) { Object = (StaticObject)ObjectManager.LoadObject(CurrentObjects[i].Name, Encoding, false, false, false, CurrentObjects[i].Rotation); } else { throw new Exception("Format " + System.IO.Path.GetExtension(CurrentObjects[i].Name) + " is not currently supported by the Loksim3D object parser"); } } catch (Exception ex) { Interface.AddMessage(MessageType.Error, false, ex.Message); } if (Object != null) { if (!string.IsNullOrEmpty(CurrentObjects[i].FunctionScript)) { //If the function script is not empty, this is a new animated object bit Array.Resize <UnifiedObject>(ref obj, obj.Length + 1); obj[obj.Length - 1] = Object; int aL = Result.Objects.Length; Array.Resize <ObjectManager.AnimatedObject>(ref Result.Objects, aL + 1); ObjectManager.AnimatedObject a = new ObjectManager.AnimatedObject(); AnimatedObjectState aos = new AnimatedObjectState(Object, CurrentObjects[i].Position); a.States = new AnimatedObjectState[] { aos }; Result.Objects[aL] = a; Result.Objects[aL].StateFunction = new FunctionScript(Program.CurrentHost, CurrentObjects[i].FunctionScript + " 1 == --", false); } else { //Otherwise, join to the main static mesh & update co-ords for (int j = 0; j < Object.Mesh.Vertices.Length; j++) { Object.Mesh.Vertices[j].Coordinates += CurrentObjects[i].Position; } staticObject.JoinObjects(Object); } } else if (AnimatedObject != null) { int rl = Result.Objects.Length; int l = AnimatedObject.Objects.Length; Array.Resize <ObjectManager.AnimatedObject>(ref Result.Objects, Result.Objects.Length + l); for (int o = rl; o < rl + l; o++) { if (AnimatedObject.Objects[o - rl] != null) { Result.Objects[o] = AnimatedObject.Objects[o - rl].Clone(); for (int si = 0; si < Result.Objects[o].States.Length; si++) { Result.Objects[o].States[si].Position += CurrentObjects[i].Position; } } else { Result.Objects[o] = new ObjectManager.AnimatedObject(); Result.Objects[o].States = new AnimatedObjectState[0]; } } } } if (staticObject != null) { Array.Resize <ObjectManager.AnimatedObject>(ref Result.Objects, Result.Objects.Length + 1); ObjectManager.AnimatedObject a = new ObjectManager.AnimatedObject(); AnimatedObjectState aos = new AnimatedObjectState(staticObject, Vector3.Zero); a.States = new AnimatedObjectState[] { aos }; Result.Objects[Result.Objects.Length - 1] = a; } } return(Result); } //Didn't find an acceptable XML object //Probably will cause things to throw an absolute wobbly somewhere.... return(null); }
internal static ObjectManager.AnimatedObjectCollection ReadObject(string FileName, System.Text.Encoding Encoding, ObjectManager.ObjectLoadMode LoadMode) { XmlDocument currentXML = new XmlDocument(); //May need to be changed to use de-DE System.Globalization.CultureInfo Culture = System.Globalization.CultureInfo.InvariantCulture; ObjectManager.AnimatedObjectCollection Result = new ObjectManager.AnimatedObjectCollection(); Result.Objects = new ObjectManager.AnimatedObject[0]; int ObjectCount = 0; currentXML.Load(FileName); string BaseDir = System.IO.Path.GetDirectoryName(FileName); GruppenObject[] CurrentObjects = new GruppenObject[0]; //Check for null if (currentXML.DocumentElement != null) { ObjectManager.UnifiedObject[] obj = new OpenBve.ObjectManager.UnifiedObject[0]; XmlNodeList DocumentNodes = currentXML.DocumentElement.SelectNodes("/GRUPPENOBJECT"); if (DocumentNodes != null) { foreach (XmlNode outerNode in DocumentNodes) { if (outerNode.HasChildNodes) { foreach (XmlNode node in outerNode.ChildNodes) { if (node.Name == "Object" && node.HasChildNodes) { foreach (XmlNode childNode in node.ChildNodes) { if (childNode.Name == "Props" && childNode.Attributes != null) { Array.Resize <GruppenObject>(ref CurrentObjects, CurrentObjects.Length + 1); GruppenObject Object = new GruppenObject(); foreach (XmlAttribute attribute in childNode.Attributes) { switch (attribute.Name) { case "Name": string ObjectFile = OpenBveApi.Path.CombineFile(BaseDir, attribute.Value); Object.Name = ObjectFile; ObjectCount++; break; case "Position": string[] SplitPosition = attribute.Value.Split(';'); double.TryParse(SplitPosition[0], out Object.Position.X); double.TryParse(SplitPosition[1], out Object.Position.Y); double.TryParse(SplitPosition[2], out Object.Position.Z); break; case "Rotation": string[] SplitRotation = attribute.Value.Split(';'); double.TryParse(SplitRotation[0], out Object.RotationX); double.TryParse(SplitRotation[1], out Object.RotationY); double.TryParse(SplitRotation[2], out Object.RotationZ); break; } } CurrentObjects[CurrentObjects.Length - 1] = Object; } } } } } } //We've loaded the XML references, now load the objects into memory for (int i = 0; i < CurrentObjects.Length; i++) { var Object = ObjectManager.LoadObject(CurrentObjects[i].Name, Encoding, LoadMode, false, false, false, CurrentObjects[i].RotationX, CurrentObjects[i].RotationY, CurrentObjects[i].RotationZ); if (Object != null) { Array.Resize <ObjectManager.UnifiedObject>(ref obj, obj.Length + 1); obj[obj.Length - 1] = Object; } } for (int j = 0; j < obj.Length; j++) { if (obj[j] != null) { Array.Resize <ObjectManager.AnimatedObject>(ref Result.Objects, Result.Objects.Length + 1); if (obj[j] is ObjectManager.StaticObject) { ObjectManager.StaticObject s = (ObjectManager.StaticObject)obj[j]; s.Dynamic = true; ObjectManager.AnimatedObject a = new ObjectManager.AnimatedObject(); ObjectManager.AnimatedObjectState aos = new ObjectManager.AnimatedObjectState { Object = s, Position = CurrentObjects[j].Position }; a.States = new ObjectManager.AnimatedObjectState[] { aos }; Result.Objects[j] = a; ObjectCount++; } else if (obj[j] is ObjectManager.AnimatedObjectCollection) { ObjectManager.AnimatedObjectCollection a = (ObjectManager.AnimatedObjectCollection)obj[j]; for (int k = 0; k < a.Objects.Length; k++) { for (int h = 0; h < a.Objects[k].States.Length; h++) { a.Objects[k].States[h].Position.X += CurrentObjects[j].Position.X; a.Objects[k].States[h].Position.Y += CurrentObjects[j].Position.Y; a.Objects[k].States[h].Position.Z += CurrentObjects[j].Position.Z; } Result.Objects[j] = a.Objects[k]; ObjectCount++; } } } } } return(Result); } //Didn't find an acceptable XML object //Probably will cause things to throw an absolute wobbly somewhere.... return(null); }
/// <summary>Loads a Loksim3D GruppenObject</summary> /// <param name="FileName">The filename to load</param> /// <param name="Encoding">The text encoding of the containing file (Currently ignored, REMOVE??)</param> /// <param name="LoadMode">The object load mode</param> /// <returns>A new animated object collection, containing the GruppenObject's meshes etc.</returns> internal static ObjectManager.AnimatedObjectCollection ReadObject(string FileName, System.Text.Encoding Encoding, ObjectManager.ObjectLoadMode LoadMode) { XmlDocument currentXML = new XmlDocument(); //May need to be changed to use de-DE System.Globalization.CultureInfo Culture = System.Globalization.CultureInfo.InvariantCulture; ObjectManager.AnimatedObjectCollection Result = new ObjectManager.AnimatedObjectCollection(); Result.Objects = new ObjectManager.AnimatedObject[0]; try { currentXML.Load(FileName); } catch (Exception ex) { //The XML is not strictly valid string[] Lines = File.ReadAllLines(FileName); using (var stringReader = new StringReader(Lines[0])) { var settings = new XmlReaderSettings { ConformanceLevel = ConformanceLevel.Fragment }; using (var xmlReader = XmlReader.Create(stringReader, settings)) { if (xmlReader.Read()) { //Attempt to find the text encoding and re-read the file var result = xmlReader.GetAttribute("encoding"); var e = System.Text.Encoding.GetEncoding(result); Lines = File.ReadAllLines(FileName, e); //Turf out the old encoding, as our string array should now be UTF-8 Lines[0] = "<?xml version=\"1.0\"?>"; } } } for (int i = 0; i < Lines.Length; i++) { while (Lines[i].IndexOf("\"\"") != -1) { //Loksim parser tolerates multiple quotes, strict XML does not Lines[i] = Lines[i].Replace("\"\"", "\""); } while (Lines[i].IndexOf(" ") != -1) { //Replace double-spaces with singles Lines[i] = Lines[i].Replace(" ", " "); } } bool tryLoad = false; try { //Horrible hack: Write out our string array to a new memory stream, then load from this stream //Why can't XmlDocument.Load() just take a string array...... using (var stream = new MemoryStream()) { var sw = new StreamWriter(stream); foreach (var line in Lines) { sw.Write(line); sw.Flush(); } sw.Flush(); stream.Position = 0; currentXML.Load(stream); tryLoad = true; } } catch { //Generic catch-all clause } if (!tryLoad) { //Pass out the *original* XML error, not anything generated when we've tried to correct it Interface.AddMessage(Interface.MessageType.Error, false, "Error parsing Loksim3D XML: " + ex.Message); return(null); } } string BaseDir = System.IO.Path.GetDirectoryName(FileName); GruppenObject[] CurrentObjects = new GruppenObject[0]; //Check for null if (currentXML.DocumentElement != null) { ObjectManager.UnifiedObject[] obj = new OpenBve.ObjectManager.UnifiedObject[0]; XmlNodeList DocumentNodes = currentXML.DocumentElement.SelectNodes("/GRUPPENOBJECT"); if (DocumentNodes != null) { foreach (XmlNode outerNode in DocumentNodes) { if (outerNode.HasChildNodes) { foreach (XmlNode node in outerNode.ChildNodes) { if (node.Name == "Object" && node.HasChildNodes) { foreach (XmlNode childNode in node.ChildNodes) { if (childNode.Name == "Props" && childNode.Attributes != null) { GruppenObject Object = new GruppenObject(); foreach (XmlAttribute attribute in childNode.Attributes) { switch (attribute.Name) { case "Name": string ObjectFile = OpenBveApi.Path.Loksim3D.CombineFile(BaseDir, attribute.Value, Program.FileSystem.LoksimPackageInstallationDirectory); if (!File.Exists(ObjectFile)) { Object.Name = null; Interface.AddMessage(Interface.MessageType.Warning, true, "Ls3d Object file " + attribute.Value + " not found."); } else { Object.Name = ObjectFile; } break; case "Position": string[] SplitPosition = attribute.Value.Split(';'); double.TryParse(SplitPosition[0], out Object.Position.X); double.TryParse(SplitPosition[1], out Object.Position.Y); double.TryParse(SplitPosition[2], out Object.Position.Z); break; case "Rotation": string[] SplitRotation = attribute.Value.Split(';'); double.TryParse(SplitRotation[0], out Object.Rotation.X); double.TryParse(SplitRotation[1], out Object.Rotation.Y); double.TryParse(SplitRotation[2], out Object.Rotation.Z); break; case "ShowOn": //Defines when the object should be shown Object.FunctionScript = FunctionScripts.GetPostfixNotationFromInfixNotation(GetAnimatedFunction(attribute.Value, false)); break; case "HideOn": //Defines when the object should be hidden Object.FunctionScript = FunctionScripts.GetPostfixNotationFromInfixNotation(GetAnimatedFunction(attribute.Value, true)); break; } } if (Object.Name != null) { Array.Resize <GruppenObject>(ref CurrentObjects, CurrentObjects.Length + 1); CurrentObjects[CurrentObjects.Length - 1] = Object; } } } } } } } //We've loaded the XML references, now load the objects into memory for (int i = 0; i < CurrentObjects.Length; i++) { if (CurrentObjects[i] == null || string.IsNullOrEmpty(CurrentObjects[i].Name)) { continue; } var Object = (ObjectManager.StaticObject)ObjectManager.LoadObject(CurrentObjects[i].Name, Encoding, LoadMode, false, false, false, CurrentObjects[i].Rotation); if (Object != null) { Array.Resize <ObjectManager.UnifiedObject>(ref obj, obj.Length + 1); obj[obj.Length - 1] = Object; Array.Resize <ObjectManager.AnimatedObject>(ref Result.Objects, Result.Objects.Length + 1); ObjectManager.AnimatedObject a = new ObjectManager.AnimatedObject(); ObjectManager.AnimatedObjectState aos = new ObjectManager.AnimatedObjectState { Object = Object, Position = CurrentObjects[i].Position, }; a.States = new ObjectManager.AnimatedObjectState[] { aos }; Result.Objects[i] = a; if (!string.IsNullOrEmpty(CurrentObjects[i].FunctionScript)) { Result.Objects[i].StateFunction = FunctionScripts.GetFunctionScriptFromPostfixNotation(CurrentObjects[i].FunctionScript + " 1 == --"); } } } } return(Result); } //Didn't find an acceptable XML object //Probably will cause things to throw an absolute wobbly somewhere.... return(null); }
internal static ObjectManager.AnimatedObjectCollection ReadObject(string FileName, System.Text.Encoding Encoding, ObjectManager.ObjectLoadMode LoadMode) { XmlDocument currentXML = new XmlDocument(); //May need to be changed to use de-DE System.Globalization.CultureInfo Culture = System.Globalization.CultureInfo.InvariantCulture; ObjectManager.AnimatedObjectCollection Result = new ObjectManager.AnimatedObjectCollection(); Result.Objects = new ObjectManager.AnimatedObject[0]; int ObjectCount = 0; currentXML.Load(FileName); string BaseDir = System.IO.Path.GetDirectoryName(FileName); GruppenObject[] CurrentObjects = new GruppenObject[0]; //Check for null if (currentXML.DocumentElement != null) { ObjectManager.UnifiedObject[] obj = new OpenBve.ObjectManager.UnifiedObject[0]; XmlNodeList DocumentNodes = currentXML.DocumentElement.SelectNodes("/GRUPPENOBJECT"); if (DocumentNodes != null) { foreach (XmlNode outerNode in DocumentNodes) { if (outerNode.HasChildNodes) { foreach (XmlNode node in outerNode.ChildNodes) { if (node.Name == "Object" && node.HasChildNodes) { foreach (XmlNode childNode in node.ChildNodes) { if (childNode.Name == "Props" && childNode.Attributes != null) { Array.Resize<GruppenObject>(ref CurrentObjects, CurrentObjects.Length + 1); GruppenObject Object = new GruppenObject(); foreach (XmlAttribute attribute in childNode.Attributes) { switch (attribute.Name) { case "Name": string ObjectFile = OpenBveApi.Path.CombineFile(BaseDir,attribute.Value); Object.Name = ObjectFile; ObjectCount++; break; case "Position": string[] SplitPosition = attribute.Value.Split(';'); double.TryParse(SplitPosition[0], out Object.Position.X); double.TryParse(SplitPosition[1], out Object.Position.Y); double.TryParse(SplitPosition[2], out Object.Position.Z); break; case "Rotation": string[] SplitRotation = attribute.Value.Split(';'); double.TryParse(SplitRotation[0], out Object.RotationX); double.TryParse(SplitRotation[1], out Object.RotationY); double.TryParse(SplitRotation[2], out Object.RotationZ); break; } } CurrentObjects[CurrentObjects.Length - 1] = Object; } } } } } } //We've loaded the XML references, now load the objects into memory for (int i = 0; i < CurrentObjects.Length; i++) { var Object = ObjectManager.LoadObject(CurrentObjects[i].Name, Encoding, LoadMode, false, false, false, CurrentObjects[i].RotationX, CurrentObjects[i].RotationY, CurrentObjects[i].RotationZ); if (Object != null) { Array.Resize<ObjectManager.UnifiedObject>(ref obj, obj.Length +1); obj[obj.Length - 1] = Object; } } for (int j = 0; j < obj.Length; j++) { if (obj[j] != null) { Array.Resize<ObjectManager.AnimatedObject>(ref Result.Objects, Result.Objects.Length + 1); if (obj[j] is ObjectManager.StaticObject) { ObjectManager.StaticObject s = (ObjectManager.StaticObject) obj[j]; s.Dynamic = true; ObjectManager.AnimatedObject a = new ObjectManager.AnimatedObject(); ObjectManager.AnimatedObjectState aos = new ObjectManager.AnimatedObjectState { Object = s, Position = CurrentObjects[j].Position }; a.States = new ObjectManager.AnimatedObjectState[] {aos}; Result.Objects[j] = a; ObjectCount++; } else if (obj[j] is ObjectManager.AnimatedObjectCollection) { ObjectManager.AnimatedObjectCollection a = (ObjectManager.AnimatedObjectCollection) obj[j]; for (int k = 0; k < a.Objects.Length; k++) { for (int h = 0; h < a.Objects[k].States.Length; h++) { a.Objects[k].States[h].Position.X += CurrentObjects[j].Position.X; a.Objects[k].States[h].Position.Y += CurrentObjects[j].Position.Y; a.Objects[k].States[h].Position.Z += CurrentObjects[j].Position.Z; } Result.Objects[j] = a.Objects[k]; ObjectCount++; } } } } } return Result; } //Didn't find an acceptable XML object //Probably will cause things to throw an absolute wobbly somewhere.... return null; }