Parses a Loksim3D xml format object
Exemplo n.º 1
0
        internal static ObjectManager.AnimatedObjectCollection ReadObject(string FileName, System.Text.Encoding Encoding, ObjectManager.ObjectLoadMode LoadMode, Vector3 Rotation)
        {
            XmlDocument currentXML = new XmlDocument();

            ObjectManager.AnimatedObjectCollection Result = new ObjectManager.AnimatedObjectCollection
            {
                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.Ordinal) != -1)
                    {
                        //Loksim parser tolerates multiple quotes, strict XML does not
                        Lines[i] = Lines[i].Replace("\"\"", "\"");
                    }
                    while (Lines[i].IndexOf("  ", StringComparison.Ordinal) != -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.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(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(';');
                                                    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 = 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

                    //Single mesh object, containing all static components of the LS3D object
                    //If we use multiples, the Z-sorting throws a wobbly
                    ObjectManager.StaticObject staticObject = new ObjectManager.StaticObject
                    {
                        Mesh = new World.Mesh
                        {
                            Vertices  = new World.Vertex[0],
                            Faces     = new World.MeshFace[0],
                            Materials = new World.MeshMaterial[0]
                        }
                    };
                    for (int i = 0; i < CurrentObjects.Length; i++)
                    {
                        if (CurrentObjects[i] == null || string.IsNullOrEmpty(CurrentObjects[i].Name))
                        {
                            continue;
                        }
                        ObjectManager.StaticObject             Object         = null;
                        ObjectManager.AnimatedObjectCollection AnimatedObject = null;
                        try {
                            if (CurrentObjects[i].Name.ToLowerInvariant().EndsWith(".l3dgrp"))
                            {
                                AnimatedObject = ReadObject(CurrentObjects[i].Name, Encoding, LoadMode, CurrentObjects[i].Rotation);
                            }
                            else if (CurrentObjects[i].Name.ToLowerInvariant().EndsWith(".l3dobj"))
                            {
                                Object = Ls3DObjectParser.ReadObject(CurrentObjects[i].Name, LoadMode, 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(Interface.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 <ObjectManager.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();
                                ObjectManager.AnimatedObjectState aos = new ObjectManager.AnimatedObjectState
                                {
                                    Object   = Object,
                                    Position = CurrentObjects[i].Position,
                                };
                                a.States           = new ObjectManager.AnimatedObjectState[] { aos };
                                Result.Objects[aL] = a;
                                Result.Objects[aL].StateFunction =
                                    FunctionScripts.GetFunctionScriptFromPostfixNotation(CurrentObjects[i].FunctionScript + " 1 == --");
                            }
                            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 ObjectManager.AnimatedObjectState[0];
                                }
                            }
                        }
                    }
                    if (staticObject != null)
                    {
                        Array.Resize <ObjectManager.AnimatedObject>(ref Result.Objects, Result.Objects.Length + 1);
                        ObjectManager.AnimatedObject      a   = new ObjectManager.AnimatedObject();
                        ObjectManager.AnimatedObjectState aos = new ObjectManager.AnimatedObjectState
                        {
                            Object = staticObject,
                        };
                        a.States = new ObjectManager.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);
        }
Exemplo n.º 2
0
        /// <summary>Loads an object</summary>
        /// <param name="FileName">The file to load</param>
        /// <param name="Encoding">The text endcoding of the base file (Used if the encoding cannot be auto-detected)</param>
        /// <param name="PreserveVertices">Whether object should be optimized to remove duplicate vertices</param>
        /// <returns>The new object, or a null reference if loading fails</returns>

        /*
         * Notes for refactoring:
         *   * Unused vertices must only be preserved in deformable objects (e.g. Crack and Form)
         *   * TODO / BUG: No detection of actual file contents, which will make all parsers barf
         */
        internal static UnifiedObject LoadObject(string FileName, Encoding Encoding, bool PreserveVertices)
        {
            if (String.IsNullOrEmpty(FileName))
            {
                return(null);
            }
#if !DEBUG
            try {
#endif
            if (!System.IO.Path.HasExtension(FileName))
            {
                while (true)
                {
                    var f = OpenBveApi.Path.CombineFile(System.IO.Path.GetDirectoryName(FileName), System.IO.Path.GetFileName(FileName) + ".x");
                    if (System.IO.File.Exists(f))
                    {
                        FileName = f;
                        break;
                    }
                    f = OpenBveApi.Path.CombineFile(System.IO.Path.GetDirectoryName(FileName), System.IO.Path.GetFileName(FileName) + ".csv");
                    if (System.IO.File.Exists(f))
                    {
                        FileName = f;
                        break;
                    }
                    f = OpenBveApi.Path.CombineFile(System.IO.Path.GetDirectoryName(FileName), System.IO.Path.GetFileName(FileName) + ".b3d");
                    if (System.IO.File.Exists(f))
                    {
                        FileName = f;
                        break;
                    }
                    f = OpenBveApi.Path.CombineFile(System.IO.Path.GetDirectoryName(FileName), System.IO.Path.GetFileName(FileName) + ".xml");
                    if (System.IO.File.Exists(f))
                    {
                        FileName = f;
                        break;
                    }
                    f = OpenBveApi.Path.CombineFile(System.IO.Path.GetDirectoryName(FileName), System.IO.Path.GetFileName(FileName) + ".l3dgrp");
                    if (System.IO.File.Exists(f))
                    {
                        FileName = f;
                        break;
                    }
                    f = OpenBveApi.Path.CombineFile(System.IO.Path.GetDirectoryName(FileName), System.IO.Path.GetFileName(FileName) + ".l3dobj");
                    if (System.IO.File.Exists(f))
                    {
                        FileName = f;
                        break;
                    }
                }
            }
            UnifiedObject Result;
            TextEncoding.Encoding newEncoding = TextEncoding.GetEncodingFromFile(FileName);
            if (newEncoding != TextEncoding.Encoding.Unknown)
            {
                switch (newEncoding)
                {
                case TextEncoding.Encoding.Utf7:
                    Encoding = System.Text.Encoding.UTF7;
                    break;

                case TextEncoding.Encoding.Utf8:
                    Encoding = System.Text.Encoding.UTF8;
                    break;

                case TextEncoding.Encoding.Utf16Le:
                    Encoding = System.Text.Encoding.Unicode;
                    break;

                case TextEncoding.Encoding.Utf16Be:
                    Encoding = System.Text.Encoding.BigEndianUnicode;
                    break;

                case TextEncoding.Encoding.Utf32Le:
                    Encoding = System.Text.Encoding.UTF32;
                    break;

                case TextEncoding.Encoding.Utf32Be:
                    Encoding = System.Text.Encoding.GetEncoding(12001);
                    break;

                case TextEncoding.Encoding.Shift_JIS:
                    Encoding = System.Text.Encoding.GetEncoding(932);
                    break;

                case TextEncoding.Encoding.Windows1252:
                    Encoding = System.Text.Encoding.GetEncoding(1252);
                    break;

                case TextEncoding.Encoding.Big5:
                    Encoding = System.Text.Encoding.GetEncoding(950);
                    break;

                case TextEncoding.Encoding.EUC_KR:
                    Encoding = System.Text.Encoding.GetEncoding(949);
                    break;
                }
            }
            string e = System.IO.Path.GetExtension(FileName);
            if (e == null)
            {
                Interface.AddMessage(MessageType.Error, false, "The file " + FileName + " does not have a recognised extension.");
                return(null);
            }
            switch (e.ToLowerInvariant())
            {
            case ".csv":
            case ".b3d":
            case ".x":
            case ".obj":
                Program.CurrentHost.LoadObject(FileName, Encoding, out Result);
                break;

            case ".animated":
                Result = AnimatedObjectParser.ReadObject(FileName, Encoding);
                break;

            case ".xml":
                Result = XMLParser.ReadObject(FileName, Encoding);
                break;

            case ".l3dgrp":
                Result = Ls3DGrpParser.ReadObject(FileName, Encoding, new Vector3());
                break;

            case ".l3dobj":
                Result = Ls3DObjectParser.ReadObject(FileName, new Vector3());
                break;

            case ".s":
                Result = MsTsShapeParser.ReadObject(FileName);
                break;

            default:
                Interface.AddMessage(MessageType.Error, false, "The file extension is not supported: " + FileName);
                return(null);
            }
            if (Result != null)
            {
                Result.OptimizeObject(PreserveVertices, Interface.CurrentOptions.ObjectOptimizationBasicThreshold, Interface.CurrentOptions.ObjectOptimizationVertexCulling);
            }
            return(Result);

#if !DEBUG
        }

        catch (Exception ex) {
            Interface.AddMessage(MessageType.Error, true, "An unexpected error occured (" + ex.Message + ") while attempting to load the file " + FileName);
            return(null);
        }
#endif
        }
Exemplo n.º 3
0
        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 = Ls3DObjectParser.ReadObject(CurrentObjects[i].Name, LoadMode, 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);
                            Object.Dynamic = true;
                            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);
        }