internal static void ApplyScale(ObjectManager.StaticObject Object, double x, double y, double z)
 {
     float rx = (float)(1.0 / x);
     float ry = (float)(1.0 / y);
     float rz = (float)(1.0 / z);
     float rx2 = rx * rx;
     float ry2 = ry * ry;
     float rz2 = rz * rz;
     bool reverse = x * y * z < 0.0;
     for (int j = 0; j < Object.Mesh.Vertices.Length; j++) {
         Object.Mesh.Vertices[j].Coordinates.X *= x;
         Object.Mesh.Vertices[j].Coordinates.Y *= y;
         Object.Mesh.Vertices[j].Coordinates.Z *= z;
     }
     for (int j = 0; j < Object.Mesh.Faces.Length; j++) {
         for (int k = 0; k < Object.Mesh.Faces[j].Vertices.Length; k++) {
             float nx2 = Object.Mesh.Faces[j].Vertices[k].Normal.X * Object.Mesh.Faces[j].Vertices[k].Normal.X;
             float ny2 = Object.Mesh.Faces[j].Vertices[k].Normal.Y * Object.Mesh.Faces[j].Vertices[k].Normal.Y;
             float nz2 = Object.Mesh.Faces[j].Vertices[k].Normal.Z * Object.Mesh.Faces[j].Vertices[k].Normal.Z;
             float u = nx2 * rx2 + ny2 * ry2 + nz2 * rz2;
             if (u != 0.0) {
                 u = (float)Math.Sqrt((double)((nx2 + ny2 + nz2) / u));
                 Object.Mesh.Faces[j].Vertices[k].Normal.X *= rx * u;
                 Object.Mesh.Faces[j].Vertices[k].Normal.Y *= ry * u;
                 Object.Mesh.Faces[j].Vertices[k].Normal.Z *= rz * u;
             }
         }
     }
     if (reverse) {
         for (int j = 0; j < Object.Mesh.Faces.Length; j++) {
             Object.Mesh.Faces[j].Flip();
         }
     }
 }
Beispiel #2
0
 // add object for custom timetable
 internal static void AddObjectForCustomTimetable(ObjectManager.AnimatedObject obj)
 {
     if (CustomObjectsUsed >= CustomObjects.Length) {
         Array.Resize<ObjectManager.AnimatedObject>(ref CustomObjects, CustomObjects.Length << 1);
     }
     CustomObjects[CustomObjectsUsed] = obj;
     CustomObjectsUsed++;
 }
Beispiel #3
0
        /// <summary>This method is called once the route and train data have been preprocessed, in order to physically setup the simulation</summary>
        private void SetupSimulation()
        {
            if (Loading.Cancel)
            {
                Close();
            }

            lock (Illustrations.Locker)
            {
                Timetable.CreateTimetable();
            }
            //Check if any critical errors have occured during the route or train loading
            for (int i = 0; i < Interface.MessageCount; i++)
            {
                if (Interface.LogMessages[i].Type == MessageType.Critical)
                {
                    MessageBox.Show("A critical error has occured:\n\n" + Interface.LogMessages[i].Text + "\n\nPlease inspect the error log file for further information.", "Load", MessageBoxButtons.OK, MessageBoxIcon.Hand);
                    Close();
                }
            }
            Program.Renderer.Lighting.Initialize();
            Game.LogRouteName = System.IO.Path.GetFileName(MainLoop.currentResult.RouteFile);
            Game.LogTrainName = System.IO.Path.GetFileName(MainLoop.currentResult.TrainFolder);
            Game.LogDateTime  = DateTime.Now;

            if (Interface.CurrentOptions.LoadInAdvance)
            {
                Textures.LoadAllTextures();
            }
            else
            {
                Program.Renderer.TextureManager.UnloadAllTextures();
            }
            // camera
            Program.Renderer.InitializeVisibility();
            TrainManager.PlayerTrain.DriverBody = new DriverBody(TrainManager.PlayerTrain);
            World.CameraTrackFollower.UpdateAbsolute(0.0, true, false);
            World.CameraTrackFollower.UpdateAbsolute(-0.1, true, false);
            World.CameraTrackFollower.UpdateAbsolute(0.1, true, false);
            World.CameraTrackFollower.TriggerType = EventTriggerType.Camera;
            // starting time and track position
            Program.CurrentRoute.SecondsSinceMidnight = 0.0;
            Game.StartupTime = 0.0;
            int    PlayerFirstStationIndex = -1;
            double PlayerFirstStationPosition;
            int    os = -1;
            bool   f  = false;

            for (int i = 0; i < Program.CurrentRoute.Stations.Length; i++)
            {
                if (!String.IsNullOrEmpty(Game.InitialStationName))
                {
                    if (Game.InitialStationName.ToLowerInvariant() == Program.CurrentRoute.Stations[i].Name.ToLowerInvariant())
                    {
                        PlayerFirstStationIndex = i;
                    }
                }
                if (Program.CurrentRoute.Stations[i].StopMode == StationStopMode.AllStop | Program.CurrentRoute.Stations[i].StopMode == StationStopMode.PlayerStop & Program.CurrentRoute.Stations[i].Stops.Length != 0)
                {
                    if (f == false)
                    {
                        os = i;
                        f  = true;
                    }
                }
            }
            if (PlayerFirstStationIndex == -1)
            {
                PlayerFirstStationIndex = os;
            }
            {
                int s = Program.CurrentRoute.Stations[PlayerFirstStationIndex].GetStopIndex(TrainManager.PlayerTrain.NumberOfCars);
                if (s >= 0)
                {
                    PlayerFirstStationPosition = Program.CurrentRoute.Stations[PlayerFirstStationIndex].Stops[s].TrackPosition;

                    double TrainLength = 0.0;
                    for (int c = 0; c < TrainManager.PlayerTrain.Cars.Length; c++)
                    {
                        TrainLength += TrainManager.PlayerTrain.Cars[c].Length;
                    }

                    for (int j = 0; j < Program.CurrentRoute.BufferTrackPositions.Length; j++)
                    {
                        if (PlayerFirstStationPosition > Program.CurrentRoute.BufferTrackPositions[j] && PlayerFirstStationPosition - TrainLength < Program.CurrentRoute.BufferTrackPositions[j])
                        {
                            /*
                             * HACK: The initial start position for the player train is stuck on a set of buffers
                             * This means we have to make some one the fly adjustments to the first station stop position
                             */

                            //Set the start position to be the buffer position plus the train length plus 1m
                            PlayerFirstStationPosition = Program.CurrentRoute.BufferTrackPositions[j] + TrainLength + 1;
                            //Update the station stop location
                            if (s >= 0)
                            {
                                Program.CurrentRoute.Stations[PlayerFirstStationIndex].Stops[s].TrackPosition = PlayerFirstStationPosition;
                            }
                            else
                            {
                                Program.CurrentRoute.Stations[PlayerFirstStationIndex].DefaultTrackPosition = PlayerFirstStationPosition;
                            }
                            break;
                        }
                    }
                }
                else
                {
                    PlayerFirstStationPosition = Program.CurrentRoute.Stations[PlayerFirstStationIndex].DefaultTrackPosition;
                }
                if (Game.InitialStationTime != -1)
                {
                    Program.CurrentRoute.SecondsSinceMidnight = Game.InitialStationTime;
                    Game.StartupTime = Game.InitialStationTime;
                }
                else
                {
                    if (Program.CurrentRoute.Stations[PlayerFirstStationIndex].ArrivalTime < 0.0)
                    {
                        if (Program.CurrentRoute.Stations[PlayerFirstStationIndex].DepartureTime < 0.0)
                        {
                            Program.CurrentRoute.SecondsSinceMidnight = 0.0;
                            Game.StartupTime = 0.0;
                        }
                        else
                        {
                            Program.CurrentRoute.SecondsSinceMidnight = Program.CurrentRoute.Stations[PlayerFirstStationIndex].DepartureTime -
                                                                        Program.CurrentRoute.Stations[PlayerFirstStationIndex].StopTime;
                            Game.StartupTime = Program.CurrentRoute.Stations[PlayerFirstStationIndex].DepartureTime -
                                               Program.CurrentRoute.Stations[PlayerFirstStationIndex].StopTime;
                        }
                    }
                    else
                    {
                        Program.CurrentRoute.SecondsSinceMidnight = Program.CurrentRoute.Stations[PlayerFirstStationIndex].ArrivalTime;
                        Game.StartupTime = Program.CurrentRoute.Stations[PlayerFirstStationIndex].ArrivalTime;
                    }
                }
            }
            int    OtherFirstStationIndex    = -1;
            double OtherFirstStationPosition = 0.0;
            double OtherFirstStationTime     = 0.0;

            for (int i = 0; i < Program.CurrentRoute.Stations.Length; i++)
            {
                if (Program.CurrentRoute.Stations[i].StopMode == StationStopMode.AllStop | Program.CurrentRoute.Stations[i].StopMode == StationStopMode.PlayerPass & Program.CurrentRoute.Stations[i].Stops.Length != 0)
                {
                    OtherFirstStationIndex = i;
                    int s = Program.CurrentRoute.Stations[i].GetStopIndex(TrainManager.PlayerTrain.Cars.Length);
                    if (s >= 0)
                    {
                        OtherFirstStationPosition = Program.CurrentRoute.Stations[i].Stops[s].TrackPosition;
                    }
                    else
                    {
                        OtherFirstStationPosition = Program.CurrentRoute.Stations[i].DefaultTrackPosition;
                    }
                    if (Program.CurrentRoute.Stations[i].ArrivalTime < 0.0)
                    {
                        if (Program.CurrentRoute.Stations[i].DepartureTime < 0.0)
                        {
                            OtherFirstStationTime = 0.0;
                        }
                        else
                        {
                            OtherFirstStationTime = Program.CurrentRoute.Stations[i].DepartureTime - Program.CurrentRoute.Stations[i].StopTime;
                        }
                    }
                    else
                    {
                        OtherFirstStationTime = Program.CurrentRoute.Stations[i].ArrivalTime;
                    }
                    break;
                }
            }
            if (Game.PrecedingTrainTimeDeltas.Length != 0)
            {
                OtherFirstStationTime -= Game.PrecedingTrainTimeDeltas[Game.PrecedingTrainTimeDeltas.Length - 1];
                if (OtherFirstStationTime < Program.CurrentRoute.SecondsSinceMidnight)
                {
                    Program.CurrentRoute.SecondsSinceMidnight = OtherFirstStationTime;
                }
            }
            // initialize trains
            for (int i = 0; i < TrainManager.Trains.Length; i++)
            {
                TrainManager.Trains[i].Initialize();
                int s = TrainManager.Trains[i].IsPlayerTrain ? PlayerFirstStationIndex : OtherFirstStationIndex;
                if (s >= 0)
                {
                    if (Program.CurrentRoute.Stations[s].OpenLeftDoors)
                    {
                        for (int j = 0; j < TrainManager.Trains[i].Cars.Length; j++)
                        {
                            TrainManager.Trains[i].Cars[j].Doors[0].AnticipatedOpen = true;
                        }
                    }
                    if (Program.CurrentRoute.Stations[s].OpenRightDoors)
                    {
                        for (int j = 0; j < TrainManager.Trains[i].Cars.Length; j++)
                        {
                            TrainManager.Trains[i].Cars[j].Doors[1].AnticipatedOpen = true;
                        }
                    }
                }
                if (Program.CurrentRoute.Sections.Length != 0)
                {
                    Program.CurrentRoute.Sections[0].Enter(TrainManager.Trains[i]);
                }
                for (int j = 0; j < TrainManager.Trains[i].Cars.Length; j++)
                {
                    double length = TrainManager.Trains[i].Cars[0].Length;
                    TrainManager.Trains[i].Cars[j].Move(-length);
                    TrainManager.Trains[i].Cars[j].Move(length);
                }
            }

            foreach (var Train in TrainManager.TFOs)
            {
                Train.Initialize();

                foreach (var Car in Train.Cars)
                {
                    double length = Train.Cars[0].Length;
                    Car.Move(-length);
                    Car.Move(length);
                }
            }

            // score
            Game.CurrentScore.ArrivalStation   = PlayerFirstStationIndex + 1;
            Game.CurrentScore.DepartureStation = PlayerFirstStationIndex;
            Game.CurrentScore.Maximum          = 0;
            for (int i = 0; i < Program.CurrentRoute.Stations.Length; i++)
            {
                if (i != PlayerFirstStationIndex & Program.CurrentRoute.Stations[i].PlayerStops())
                {
                    if (i == 0 || Program.CurrentRoute.Stations[i - 1].Type != StationType.ChangeEnds && Program.CurrentRoute.Stations[i - 1].Type != StationType.Jump)
                    {
                        Game.CurrentScore.Maximum += Game.ScoreValueStationArrival;
                    }
                }
            }
            if (Game.CurrentScore.Maximum <= 0)
            {
                Game.CurrentScore.Maximum = Game.ScoreValueStationArrival;
            }
            // signals
            if (Program.CurrentRoute.Sections.Length > 0)
            {
                Program.CurrentRoute.UpdateAllSections();
            }
            // move train in position
            for (int i = 0; i < TrainManager.Trains.Length; i++)
            {
                double p;
                if (TrainManager.Trains[i].IsPlayerTrain)
                {
                    p = PlayerFirstStationPosition;
                }
                else if (TrainManager.Trains[i].State == TrainState.Bogus)
                {
                    p = Program.CurrentRoute.BogusPreTrainInstructions[0].TrackPosition;
                    TrainManager.Trains[i].AI = new Game.BogusPretrainAI(TrainManager.Trains[i]);
                }
                else
                {
                    p = OtherFirstStationPosition;
                }
                for (int j = 0; j < TrainManager.Trains[i].Cars.Length; j++)
                {
                    TrainManager.Trains[i].Cars[j].Move(p);
                }
            }
            // timetable
            if (Timetable.DefaultTimetableDescription.Length == 0)
            {
                Timetable.DefaultTimetableDescription = Game.LogTrainName;
            }

            // initialize camera
            if (Program.Renderer.Camera.CurrentRestriction == CameraRestrictionMode.NotAvailable)
            {
                Program.Renderer.Camera.CurrentMode = CameraViewMode.InteriorLookAhead;
            }
            //Place the initial camera in the driver car
            TrainManager.PlayerTrain.Cars[TrainManager.PlayerTrain.DriverCar].UpdateCamera();
            World.CameraTrackFollower.UpdateAbsolute(-1.0, true, false);
            Program.Renderer.UpdateVisibility(World.CameraTrackFollower.TrackPosition + Program.Renderer.Camera.Alignment.Position.Z);
            World.CameraSavedExterior = new CameraAlignment(new OpenBveApi.Math.Vector3(-2.5, 1.5, -15.0), 0.3, -0.2, 0.0, PlayerFirstStationPosition, 1.0);
            World.CameraSavedTrack    = new CameraAlignment(new OpenBveApi.Math.Vector3(-3.0, 2.5, 0.0), 0.3, 0.0, 0.0, TrainManager.PlayerTrain.Cars[0].TrackPosition - 10.0, 1.0);
            // signalling sections
            for (int i = 0; i < TrainManager.Trains.Length; i++)
            {
                int s = TrainManager.Trains[i].CurrentSectionIndex;
                Program.CurrentRoute.Sections[s].Enter(TrainManager.Trains[i]);
            }
            if (Program.CurrentRoute.Sections.Length > 0)
            {
                Program.CurrentRoute.UpdateAllSections();
            }
            // fast-forward until start time
            {
                Game.MinimalisticSimulation = true;
                const double w = 0.25;
                double       u = Game.StartupTime - Program.CurrentRoute.SecondsSinceMidnight;
                if (u > 0)
                {
                    while (true)
                    {
                        double v = u < w ? u : w; u -= v;
                        Program.CurrentRoute.SecondsSinceMidnight += v;
                        TrainManager.UpdateTrains(v);
                        if (u <= 0.0)
                        {
                            break;
                        }
                        TotalTimeElapsedForSectionUpdate += v;
                        if (TotalTimeElapsedForSectionUpdate >= 1.0)
                        {
                            if (Program.CurrentRoute.Sections.Length > 0)
                            {
                                Program.CurrentRoute.UpdateAllSections();
                            }
                            TotalTimeElapsedForSectionUpdate = 0.0;
                        }
                    }
                }
                Game.MinimalisticSimulation = false;
            }
            // animated objects
            ObjectManager.UpdateAnimatedWorldObjects(0.0, true);
            TrainManager.UpdateTrainObjects(0.0, true);
            //HACK: This function calls a single update on all objects attached to the player's train
            //      but ignores any specified damping so that all needles etc. are in the correct place
            //      for the first frame, rather than spinning wildly to get to the starting point.
            TrainManager.PlayerTrain.UpdateCabObjects();
            // timetable
            if (TrainManager.PlayerTrain.Station >= 0)
            {
                Timetable.UpdateCustomTimetable(Program.CurrentRoute.Stations[TrainManager.PlayerTrain.Station].TimetableDaytimeTexture, Program.CurrentRoute.Stations[TrainManager.PlayerTrain.Station].TimetableNighttimeTexture);
                if (Timetable.CustomObjectsUsed != 0 & Timetable.CustomTimetableAvailable && Interface.CurrentOptions.TimeTableStyle != Interface.TimeTableMode.AutoGenerated && Interface.CurrentOptions.TimeTableStyle != Interface.TimeTableMode.None)
                {
                    Timetable.CurrentTimetable = Timetable.TimetableState.Custom;
                }
            }
            //Create AI driver for the player train if specified via the commmand line
            if (Game.InitialAIDriver == true)
            {
                TrainManager.PlayerTrain.AI = new Game.SimpleHumanDriverAI(TrainManager.PlayerTrain);
                if (TrainManager.PlayerTrain.Plugin != null && !TrainManager.PlayerTrain.Plugin.SupportsAI)
                {
                    Game.AddMessage(Translations.GetInterfaceString("notification_aiunable"), MessageDependency.None, GameMode.Expert,
                                    OpenBveApi.Colors.MessageColor.White, Program.CurrentRoute.SecondsSinceMidnight + 10.0, null);
                }
            }

            // warnings / errors
            if (Interface.MessageCount != 0)
            {
                int filesNotFound = 0;
                int errors        = 0;
                int warnings      = 0;
                for (int i = 0; i < Interface.MessageCount; i++)
                {
                    if (Interface.LogMessages[i].FileNotFound)
                    {
                        filesNotFound++;
                    }
                    else if (Interface.LogMessages[i].Type == MessageType.Error)
                    {
                        errors++;
                    }
                    else if (Interface.LogMessages[i].Type == MessageType.Warning)
                    {
                        warnings++;
                    }
                }
                string NotFound = null;
                string Messages;
                if (filesNotFound != 0)
                {
                    NotFound = filesNotFound.ToString() + " file(s) not found";
                    Game.AddMessage(NotFound, MessageDependency.None, GameMode.Expert, MessageColor.Magenta, Program.CurrentRoute.SecondsSinceMidnight + 10.0, null);
                }
                if (errors != 0 & warnings != 0)
                {
                    Messages = errors.ToString() + " error(s), " + warnings.ToString() + " warning(s)";
                    Game.AddMessage(Messages, MessageDependency.None, GameMode.Expert, MessageColor.Magenta, Program.CurrentRoute.SecondsSinceMidnight + 10.0, null);
                }
                else if (errors != 0)
                {
                    Messages = errors.ToString() + " error(s)";
                    Game.AddMessage(Messages, MessageDependency.None, GameMode.Expert, MessageColor.Magenta, Program.CurrentRoute.SecondsSinceMidnight + 10.0, null);
                }
                else
                {
                    Messages = warnings.ToString() + " warning(s)";
                    Game.AddMessage(Messages, MessageDependency.None, GameMode.Expert, MessageColor.Magenta, Program.CurrentRoute.SecondsSinceMidnight + 10.0, null);
                }
                Game.RouteInformation.FilesNotFound     = NotFound;
                Game.RouteInformation.ErrorsAndWarnings = Messages;
                //Print the plugin error encountered (If any) for 10s
                //This must be done after the simulation has init, as otherwise the timeout doesn't work
                if (Loading.PluginError != null)
                {
                    Game.AddMessage(Loading.PluginError, MessageDependency.None, GameMode.Expert, OpenBveApi.Colors.MessageColor.Red, Program.CurrentRoute.SecondsSinceMidnight + 5.0, null);
                    Game.AddMessage(Translations.GetInterfaceString("errors_plugin_failure2"), MessageDependency.None, GameMode.Expert, OpenBveApi.Colors.MessageColor.Red, Program.CurrentRoute.SecondsSinceMidnight + 5.0, null);
                }
            }
            loadComplete          = true;
            RenderRealTimeElapsed = 0.0;
            RenderTimeElapsed     = 0.0;
            World.InitializeCameraRestriction();
            Loading.SimulationSetup = true;
            switch (Game.InitialViewpoint)
            {
            case 1:
                //Switch camera to exterior
                MainLoop.SaveCameraSettings();
                Program.Renderer.Camera.CurrentMode = CameraViewMode.Exterior;
                MainLoop.RestoreCameraSettings();
                for (int j = 0; j < TrainManager.PlayerTrain.Cars.Length; j++)
                {
                    TrainManager.PlayerTrain.Cars[j].ChangeCarSection(TrainManager.CarSectionType.Exterior);
                    //Make bogies visible
                    TrainManager.PlayerTrain.Cars[j].FrontBogie.ChangeSection(0);
                    TrainManager.PlayerTrain.Cars[j].RearBogie.ChangeSection(0);
                    TrainManager.PlayerTrain.Cars[j].Coupler.ChangeSection(0);
                }
                Program.Renderer.Camera.AlignmentDirection = new CameraAlignment();
                Program.Renderer.Camera.AlignmentSpeed     = new CameraAlignment();
                Program.Renderer.UpdateViewport(ViewportChangeMode.NoChange);
                World.UpdateAbsoluteCamera(0.0);
                World.UpdateViewingDistances();
                break;

            case 2:
                //Switch camera to track
                MainLoop.SaveCameraSettings();
                Program.Renderer.Camera.CurrentMode = CameraViewMode.Track;
                MainLoop.RestoreCameraSettings();
                for (int j = 0; j < TrainManager.PlayerTrain.Cars.Length; j++)
                {
                    TrainManager.PlayerTrain.Cars[j].ChangeCarSection(TrainManager.CarSectionType.Exterior);
                    TrainManager.PlayerTrain.Cars[j].FrontBogie.ChangeSection(0);
                    TrainManager.PlayerTrain.Cars[j].RearBogie.ChangeSection(0);
                    TrainManager.PlayerTrain.Cars[j].Coupler.ChangeSection(0);
                }

                Program.Renderer.Camera.AlignmentDirection = new CameraAlignment();
                Program.Renderer.Camera.AlignmentSpeed     = new CameraAlignment();
                Program.Renderer.UpdateViewport(ViewportChangeMode.NoChange);
                World.UpdateAbsoluteCamera(0.0);
                World.UpdateViewingDistances();
                break;

            case 3:
                //Switch camera to flyby
                MainLoop.SaveCameraSettings();
                Program.Renderer.Camera.CurrentMode = CameraViewMode.FlyBy;
                MainLoop.RestoreCameraSettings();
                for (int j = 0; j < TrainManager.PlayerTrain.Cars.Length; j++)
                {
                    TrainManager.PlayerTrain.Cars[j].ChangeCarSection(TrainManager.CarSectionType.Exterior);
                    TrainManager.PlayerTrain.Cars[j].FrontBogie.ChangeSection(0);
                    TrainManager.PlayerTrain.Cars[j].RearBogie.ChangeSection(0);
                    TrainManager.PlayerTrain.Cars[j].Coupler.ChangeSection(0);
                }

                Program.Renderer.Camera.AlignmentDirection = new CameraAlignment();
                Program.Renderer.Camera.AlignmentSpeed     = new CameraAlignment();
                Program.Renderer.UpdateViewport(ViewportChangeMode.NoChange);
                World.UpdateAbsoluteCamera(0.0);
                World.UpdateViewingDistances();
                break;

            case 4:
                //Switch camera to flyby
                MainLoop.SaveCameraSettings();
                Program.Renderer.Camera.CurrentMode = CameraViewMode.FlyByZooming;
                MainLoop.RestoreCameraSettings();
                for (int j = 0; j < TrainManager.PlayerTrain.Cars.Length; j++)
                {
                    TrainManager.PlayerTrain.Cars[j].ChangeCarSection(TrainManager.CarSectionType.Exterior);
                    TrainManager.PlayerTrain.Cars[j].FrontBogie.ChangeSection(0);
                    TrainManager.PlayerTrain.Cars[j].RearBogie.ChangeSection(0);
                    TrainManager.PlayerTrain.Cars[j].Coupler.ChangeSection(0);
                }

                Program.Renderer.Camera.AlignmentDirection = new CameraAlignment();
                Program.Renderer.Camera.AlignmentSpeed     = new CameraAlignment();
                Program.Renderer.UpdateViewport(ViewportChangeMode.NoChange);
                World.UpdateAbsoluteCamera(0.0);
                World.UpdateViewingDistances();
                break;
            }
        }
Beispiel #4
0
 private static void ApplyMeshBuilder(ref ObjectManager.StaticObject Object, MeshBuilder Builder, ObjectManager.ObjectLoadMode LoadMode, bool ForceTextureRepeatX, bool ForceTextureRepeatY)
 {
     if (Builder.Faces.Length != 0)
     {
         int mf = Object.Mesh.Faces.Length;
         int mm = Object.Mesh.Materials.Length;
         int mv = Object.Mesh.Vertices.Length;
         Array.Resize<World.MeshFace>(ref Object.Mesh.Faces, mf + Builder.Faces.Length);
         Array.Resize<World.MeshMaterial>(ref Object.Mesh.Materials, mm + Builder.Materials.Length);
         Array.Resize<World.Vertex>(ref Object.Mesh.Vertices, mv + Builder.Vertices.Length);
         for (int i = 0; i < Builder.Vertices.Length; i++)
         {
             Object.Mesh.Vertices[mv + i] = Builder.Vertices[i];
         }
         for (int i = 0; i < Builder.Faces.Length; i++)
         {
             Object.Mesh.Faces[mf + i] = Builder.Faces[i];
             for (int j = 0; j < Object.Mesh.Faces[mf + i].Vertices.Length; j++)
             {
                 Object.Mesh.Faces[mf + i].Vertices[j].Index += (ushort)mv;
             }
             Object.Mesh.Faces[mf + i].Material += (ushort)mm;
         }
         for (int i = 0; i < Builder.Materials.Length; i++)
         {
             Object.Mesh.Materials[mm + i].Flags = (byte)((Builder.Materials[i].EmissiveColorUsed ? World.MeshMaterial.EmissiveColorMask : 0) | (Builder.Materials[i].TransparentColorUsed ? World.MeshMaterial.TransparentColorMask : 0));
             Object.Mesh.Materials[mm + i].Color = Builder.Materials[i].Color;
             Object.Mesh.Materials[mm + i].TransparentColor = Builder.Materials[i].TransparentColor;
             TextureManager.TextureWrapMode WrapX, WrapY;
             if (ForceTextureRepeatX)
             {
                 WrapX = TextureManager.TextureWrapMode.Repeat;
             }
             else
             {
                 WrapX = TextureManager.TextureWrapMode.ClampToEdge;
             }
             if (ForceTextureRepeatY)
             {
                 WrapY = TextureManager.TextureWrapMode.Repeat;
             }
             else
             {
                 WrapY = TextureManager.TextureWrapMode.ClampToEdge;
             }
             if (WrapX != TextureManager.TextureWrapMode.Repeat | WrapY != TextureManager.TextureWrapMode.Repeat)
             {
                 for (int j = 0; j < Builder.Vertices.Length; j++)
                 {
                     if (Builder.Vertices[j].TextureCoordinates.X < 0.0 | Builder.Vertices[j].TextureCoordinates.X > 1.0)
                     {
                         WrapX = TextureManager.TextureWrapMode.Repeat;
                     }
                     if (Builder.Vertices[j].TextureCoordinates.Y < 0.0 | Builder.Vertices[j].TextureCoordinates.Y > 1.0)
                     {
                         WrapY = TextureManager.TextureWrapMode.Repeat;
                     }
                 }
             }
             if (Builder.Materials[i].DaytimeTexture != null)
             {
                 int tday = TextureManager.RegisterTexture(Builder.Materials[i].DaytimeTexture, Builder.Materials[i].TransparentColor, Builder.Materials[i].TransparentColorUsed ? (byte)1 : (byte)0, WrapX, WrapY, LoadMode != ObjectManager.ObjectLoadMode.Normal);
                 Object.Mesh.Materials[mm + i].DaytimeTextureIndex = tday;
             }
             else
             {
                 Object.Mesh.Materials[mm + i].DaytimeTextureIndex = -1;
             }
             Object.Mesh.Materials[mm + i].EmissiveColor = Builder.Materials[i].EmissiveColor;
             if (Builder.Materials[i].NighttimeTexture != null)
             {
                 int tnight = TextureManager.RegisterTexture(Builder.Materials[i].NighttimeTexture, Builder.Materials[i].TransparentColor, Builder.Materials[i].TransparentColorUsed ? (byte)1 : (byte)0, WrapX, WrapY, LoadMode != ObjectManager.ObjectLoadMode.Normal);
                 Object.Mesh.Materials[mm + i].NighttimeTextureIndex = tnight;
             }
             else
             {
                 Object.Mesh.Materials[mm + i].NighttimeTextureIndex = -1;
             }
             Object.Mesh.Materials[mm + i].DaytimeNighttimeBlend = 0;
             Object.Mesh.Materials[mm + i].BlendMode = Builder.Materials[i].BlendMode;
             Object.Mesh.Materials[mm + i].GlowAttenuationData = Builder.Materials[i].GlowAttenuationData;
         }
     }
 }
 // parse animated object config
 /// <summary>Loads a collection of animated objects from a file.</summary>
 /// <param name="FileName">The text file to load the animated object from. Must be an absolute file name.</param>
 /// <param name="Encoding">The encoding the file is saved in. If the file uses a byte order mark, the encoding indicated by the byte order mark is used and the Encoding parameter is ignored.</param>
 /// <param name="LoadMode">The texture load mode.</param>
 /// <returns>The collection of animated objects.</returns>
 internal static ObjectManager.AnimatedObjectCollection ReadObject(string FileName, System.Text.Encoding Encoding, ObjectManager.ObjectLoadMode LoadMode)
 {
     System.Globalization.CultureInfo Culture = System.Globalization.CultureInfo.InvariantCulture;
     ObjectManager.AnimatedObjectCollection Result = new ObjectManager.AnimatedObjectCollection();
     Result.Objects = new ObjectManager.AnimatedObject[4];
     int ObjectCount = 0;
     // load file
     string[] Lines = System.IO.File.ReadAllLines(FileName, Encoding);
     bool rpnUsed = false;
     for (int i = 0; i < Lines.Length; i++) {
         int j = Lines[i].IndexOf(';');
         if (j >= 0) {
             Lines[i] = Lines[i].Substring(0, j).Trim();
         } else {
             Lines[i] = Lines[i].Trim();
         }
         if (Program.CurrentProgramType == Program.ProgramType.ObjectViewer | Program.CurrentProgramType == Program.ProgramType.RouteViewer) {
             if (Lines[i].IndexOf("functionrpn", StringComparison.OrdinalIgnoreCase) >= 0) {
                 rpnUsed = true;
             }
         }
     }
     if (rpnUsed) {
         Interface.AddMessage(Interface.MessageType.Warning, false, "An animated object file contains non-official RPN functions. Please get rid of them in file " + FileName);
     }
     for (int i = 0; i < Lines.Length; i++) {
         if (Lines[i].Length != 0) {
             switch (Lines[i].ToLowerInvariant()) {
                 case "[include]":
                     {
                         i++;
                         World.Vector3D position = new World.Vector3D(0.0, 0.0, 0.0);
                         ObjectManager.UnifiedObject[] obj = new OpenBve.ObjectManager.UnifiedObject[4];
                         int objCount = 0;
                         while (i < Lines.Length && !(Lines[i].StartsWith("[", StringComparison.Ordinal) & Lines[i].EndsWith("]", StringComparison.Ordinal))) {
                             if (Lines[i].Length != 0) {
                                 int j = Lines[i].IndexOf("=", StringComparison.Ordinal);
                                 if (j > 0) {
                                     string a = Lines[i].Substring(0, j).TrimEnd();
                                     string b = Lines[i].Substring(j + 1).TrimStart();
                                     switch (a.ToLowerInvariant()) {
                                         case "position":
                                             {
                                                 string[] s = b.Split(',');
                                                 if (s.Length == 3) {
                                                     double x, y, z;
                                                     if (!double.TryParse(s[0], System.Globalization.NumberStyles.Float, Culture, out x)) {
                                                         Interface.AddMessage(Interface.MessageType.Error, false, "X is invalid in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                                                     } else if (!double.TryParse(s[1], System.Globalization.NumberStyles.Float, Culture, out y)) {
                                                         Interface.AddMessage(Interface.MessageType.Error, false, "Y is invalid in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                                                     } else if (!double.TryParse(s[2], System.Globalization.NumberStyles.Float, Culture, out z)) {
                                                         Interface.AddMessage(Interface.MessageType.Error, false, "Z is invalid in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                                                     } else {
                                                         position = new World.Vector3D(x, y, z);
                                                     }
                                                 } else {
                                                     Interface.AddMessage(Interface.MessageType.Error, false, "Exactly 3 arguments are expected in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                                                 }
                                             } break;
                                         default:
                                             Interface.AddMessage(Interface.MessageType.Error, false, "The attribute " + a + " is not supported at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                                             break;
                                     }
                                 } else {
                                     string Folder = System.IO.Path.GetDirectoryName(FileName);
                                     if (Interface.ContainsInvalidPathChars(Lines[i])) {
                                         Interface.AddMessage(Interface.MessageType.Error, false, Lines[i] + " contains illegal characters at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                                     } else {
                                         string file = Interface.GetCombinedFileName(Folder, Lines[i]);
                                         if (System.IO.File.Exists(file)) {
                                             if (obj.Length == objCount) {
                                                 Array.Resize<ObjectManager.UnifiedObject>(ref obj, obj.Length << 1);
                                             }
                                             obj[objCount] = ObjectManager.LoadObject(file, Encoding, LoadMode, false, false, false);
                                             objCount++;
                                         } else {
                                             Interface.AddMessage(Interface.MessageType.Error, true, "File " + file + " not found at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                                         }
                                     }
                                 }
                             }
                             i++;
                         }
                         i--;
                         for (int j = 0; j < objCount; j++) {
                             if (obj[j] != null) {
                                 if (obj[j] is ObjectManager.StaticObject) {
                                     ObjectManager.StaticObject s = (ObjectManager.StaticObject)obj[j];
                                     s.Dynamic = 1;
                                     if (ObjectCount >= Result.Objects.Length) {
                                         Array.Resize<ObjectManager.AnimatedObject>(ref Result.Objects, Result.Objects.Length << 1);
                                     }
                                     ObjectManager.AnimatedObject a = new ObjectManager.AnimatedObject();
                                     ObjectManager.AnimatedObjectState aos = new ObjectManager.AnimatedObjectState();
                                     aos.Object = s;
                                     aos.Position = position;
                                     a.States = new ObjectManager.AnimatedObjectState[] { aos };
                                     Result.Objects[ObjectCount] = 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++) {
                                         if (ObjectCount >= Result.Objects.Length) {
                                             Array.Resize<ObjectManager.AnimatedObject>(ref Result.Objects, Result.Objects.Length << 1);
                                         }
                                         for (int h = 0; h < a.Objects[k].States.Length; h++) {
                                             a.Objects[k].States[h].Position.X += position.X;
                                             a.Objects[k].States[h].Position.Y += position.Y;
                                             a.Objects[k].States[h].Position.Z += position.Z;
                                         }
                                         Result.Objects[ObjectCount] = a.Objects[k];
                                         ObjectCount++;
                                     }
                                 }
                             }
                         }
                     }
                     break;
                 case "[object]":
                     {
                         i++;
                         if (Result.Objects.Length == ObjectCount) {
                             Array.Resize<ObjectManager.AnimatedObject>(ref Result.Objects, Result.Objects.Length << 1);
                         }
                         Result.Objects[ObjectCount] = new ObjectManager.AnimatedObject();
                         Result.Objects[ObjectCount].States = new ObjectManager.AnimatedObjectState[] { };
                         Result.Objects[ObjectCount].CurrentState = -1;
                         Result.Objects[ObjectCount].TranslateXDirection = new World.Vector3D(1.0, 0.0, 0.0);
                         Result.Objects[ObjectCount].TranslateYDirection = new World.Vector3D(0.0, 1.0, 0.0);
                         Result.Objects[ObjectCount].TranslateZDirection = new World.Vector3D(0.0, 0.0, 1.0);
                         Result.Objects[ObjectCount].RotateXDirection = new World.Vector3D(1.0, 0.0, 0.0);
                         Result.Objects[ObjectCount].RotateYDirection = new World.Vector3D(0.0, 1.0, 0.0);
                         Result.Objects[ObjectCount].RotateZDirection = new World.Vector3D(0.0, 0.0, 1.0);
                         Result.Objects[ObjectCount].TextureShiftXDirection = new World.Vector2D(1.0, 0.0);
                         Result.Objects[ObjectCount].TextureShiftYDirection = new World.Vector2D(0.0, 1.0);
                         Result.Objects[ObjectCount].RefreshRate = 0.0;
                         Result.Objects[ObjectCount].ObjectIndex = -1;
                         World.Vector3D Position = new World.Vector3D(0.0, 0.0, 0.0);
                         string[] StateFiles = null;
                         while (i < Lines.Length && !(Lines[i].StartsWith("[", StringComparison.Ordinal) & Lines[i].EndsWith("]", StringComparison.Ordinal))) {
                             if (Lines[i].Length != 0) {
                                 int j = Lines[i].IndexOf("=", StringComparison.Ordinal);
                                 if (j > 0) {
                                     string a = Lines[i].Substring(0, j).TrimEnd();
                                     string b = Lines[i].Substring(j + 1).TrimStart();
                                     switch (a.ToLowerInvariant()) {
                                         case "position":
                                             {
                                                 string[] s = b.Split(',');
                                                 if (s.Length == 3) {
                                                     double x, y, z;
                                                     if (!double.TryParse(s[0], System.Globalization.NumberStyles.Float, Culture, out x)) {
                                                         Interface.AddMessage(Interface.MessageType.Error, false, "X is invalid in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                                                     } else if (!double.TryParse(s[1], System.Globalization.NumberStyles.Float, Culture, out y)) {
                                                         Interface.AddMessage(Interface.MessageType.Error, false, "Y is invalid in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                                                     } else if (!double.TryParse(s[2], System.Globalization.NumberStyles.Float, Culture, out z)) {
                                                         Interface.AddMessage(Interface.MessageType.Error, false, "Z is invalid in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                                                     } else {
                                                         Position = new World.Vector3D(x, y, z);
                                                     }
                                                 } else {
                                                     Interface.AddMessage(Interface.MessageType.Error, false, "Exactly 3 arguments are expected in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                                                 }
                                             } break;
                                         case "states":
                                             {
                                                 string[] s = b.Split(',');
                                                 if (s.Length >= 1) {
                                                     string Folder = System.IO.Path.GetDirectoryName(FileName);
                                                     StateFiles = new string[s.Length];
                                                     for (int k = 0; k < s.Length; k++) {
                                                         s[k] = s[k].Trim();
                                                         if (Interface.ContainsInvalidPathChars(s[k])) {
                                                             Interface.AddMessage(Interface.MessageType.Error, false, "File" + k.ToString(Culture) + " contains illegal characters in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                                                             StateFiles[k] = null;
                                                         } else {
                                                             StateFiles[k] = Interface.GetCombinedFileName(Folder, s[k]);
                                                             if (!System.IO.File.Exists(StateFiles[k])) {
                                                                 Interface.AddMessage(Interface.MessageType.Error, true, "File " + StateFiles[k] + " not found in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                                                                 StateFiles[k] = null;
                                                             }
                                                         }
                                                     }
                                                 } else {
                                                     Interface.AddMessage(Interface.MessageType.Error, false, "At least one argument is expected in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                                                     return null;
                                                 }
                                             } break;
                                         case "statefunction":
                                             try {
                                                 Result.Objects[ObjectCount].StateFunction = FunctionScripts.GetFunctionScriptFromInfixNotation(b);
                                             } catch (Exception ex) {
                                                 Interface.AddMessage(Interface.MessageType.Error, false, ex.Message + " in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                                             } break;
                                         case "statefunctionrpn":
                                             try {
                                                 Result.Objects[ObjectCount].StateFunction = FunctionScripts.GetFunctionScriptFromPostfixNotation(b);
                                             } catch (Exception ex) {
                                                 Interface.AddMessage(Interface.MessageType.Error, false, ex.Message + " in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                                             } break;
                                         case "translatexdirection":
                                         case "translateydirection":
                                         case "translatezdirection":
                                             {
                                                 string[] s = b.Split(',');
                                                 if (s.Length == 3) {
                                                     double x, y, z;
                                                     if (!double.TryParse(s[0], System.Globalization.NumberStyles.Float, Culture, out x)) {
                                                         Interface.AddMessage(Interface.MessageType.Error, false, "X is invalid in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                                                     } else if (!double.TryParse(s[1], System.Globalization.NumberStyles.Float, Culture, out y)) {
                                                         Interface.AddMessage(Interface.MessageType.Error, false, "Y is invalid in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                                                     } else if (!double.TryParse(s[2], System.Globalization.NumberStyles.Float, Culture, out z)) {
                                                         Interface.AddMessage(Interface.MessageType.Error, false, "Z is invalid in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                                                     } else {
                                                         switch (a.ToLowerInvariant()) {
                                                             case "translatexdirection":
                                                                 Result.Objects[ObjectCount].TranslateXDirection = new World.Vector3D(x, y, z);
                                                                 break;
                                                             case "translateydirection":
                                                                 Result.Objects[ObjectCount].TranslateYDirection = new World.Vector3D(x, y, z);
                                                                 break;
                                                             case "translatezdirection":
                                                                 Result.Objects[ObjectCount].TranslateZDirection = new World.Vector3D(x, y, z);
                                                                 break;
                                                         }
                                                     }
                                                 } else {
                                                     Interface.AddMessage(Interface.MessageType.Error, false, "Exactly 3 arguments are expected in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                                                 }
                                             } break;
                                         case "translatexfunction":
                                             try {
                                                 Result.Objects[ObjectCount].TranslateXFunction = FunctionScripts.GetFunctionScriptFromInfixNotation(b);
                                             } catch (Exception ex) {
                                                 Interface.AddMessage(Interface.MessageType.Error, false, ex.Message + " in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                                             } break;
                                         case "translateyfunction":
                                             try {
                                                 Result.Objects[ObjectCount].TranslateYFunction = FunctionScripts.GetFunctionScriptFromInfixNotation(b);
                                             } catch (Exception ex) {
                                                 Interface.AddMessage(Interface.MessageType.Error, false, ex.Message + " in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                                             } break;
                                         case "translatezfunction":
                                             try {
                                                 Result.Objects[ObjectCount].TranslateZFunction = FunctionScripts.GetFunctionScriptFromInfixNotation(b);
                                             } catch (Exception ex) {
                                                 Interface.AddMessage(Interface.MessageType.Error, false, ex.Message + " in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                                             } break;
                                         case "translatexfunctionrpn":
                                             try {
                                                 Result.Objects[ObjectCount].TranslateXFunction = FunctionScripts.GetFunctionScriptFromPostfixNotation(b);
                                             } catch (Exception ex) {
                                                 Interface.AddMessage(Interface.MessageType.Error, false, ex.Message + " in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                                             } break;
                                         case "translateyfunctionrpn":
                                             try {
                                                 Result.Objects[ObjectCount].TranslateYFunction = FunctionScripts.GetFunctionScriptFromPostfixNotation(b);
                                             } catch (Exception ex) {
                                                 Interface.AddMessage(Interface.MessageType.Error, false, ex.Message + " in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                                             } break;
                                         case "translatezfunctionrpn":
                                             try {
                                                 Result.Objects[ObjectCount].TranslateZFunction = FunctionScripts.GetFunctionScriptFromPostfixNotation(b);
                                             } catch (Exception ex) {
                                                 Interface.AddMessage(Interface.MessageType.Error, false, ex.Message + " in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                                             } break;
                                         case "rotatexdirection":
                                         case "rotateydirection":
                                         case "rotatezdirection":
                                             {
                                                 string[] s = b.Split(',');
                                                 if (s.Length == 3) {
                                                     double x, y, z;
                                                     if (!double.TryParse(s[0], System.Globalization.NumberStyles.Float, Culture, out x)) {
                                                         Interface.AddMessage(Interface.MessageType.Error, false, "X is invalid in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                                                     } else if (!double.TryParse(s[1], System.Globalization.NumberStyles.Float, Culture, out y)) {
                                                         Interface.AddMessage(Interface.MessageType.Error, false, "Y is invalid in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                                                     } else if (!double.TryParse(s[2], System.Globalization.NumberStyles.Float, Culture, out z)) {
                                                         Interface.AddMessage(Interface.MessageType.Error, false, "Z is invalid in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                                                     } else if (x == 0.0 & y == 0.0 & z == 0.0) {
                                                         Interface.AddMessage(Interface.MessageType.Error, false, "The direction indicated by X, Y and Z is expected to be non-zero in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                                                     } else {
                                                         switch (a.ToLowerInvariant()) {
                                                             case "rotatexdirection":
                                                                 Result.Objects[ObjectCount].RotateXDirection = new World.Vector3D(x, y, z);
                                                                 break;
                                                             case "rotateydirection":
                                                                 Result.Objects[ObjectCount].RotateYDirection = new World.Vector3D(x, y, z);
                                                                 break;
                                                             case "rotatezdirection":
                                                                 Result.Objects[ObjectCount].RotateZDirection = new World.Vector3D(x, y, z);
                                                                 break;
                                                         }
                                                     }
                                                 } else {
                                                     Interface.AddMessage(Interface.MessageType.Error, false, "Exactly 3 arguments are expected in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                                                 }
                                             } break;
                                         case "rotatexfunction":
                                             try {
                                                 Result.Objects[ObjectCount].RotateXFunction = FunctionScripts.GetFunctionScriptFromInfixNotation(b);
                                             } catch (Exception ex) {
                                                 Interface.AddMessage(Interface.MessageType.Error, false, ex.Message + " in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                                             } break;
                                         case "rotateyfunction":
                                             try {
                                                 Result.Objects[ObjectCount].RotateYFunction = FunctionScripts.GetFunctionScriptFromInfixNotation(b);
                                             } catch (Exception ex) {
                                                 Interface.AddMessage(Interface.MessageType.Error, false, ex.Message + " in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                                             } break;
                                         case "rotatezfunction":
                                             try {
                                                 Result.Objects[ObjectCount].RotateZFunction = FunctionScripts.GetFunctionScriptFromInfixNotation(b);
                                             } catch (Exception ex) {
                                                 Interface.AddMessage(Interface.MessageType.Error, false, ex.Message + " in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                                             } break;
                                         case "rotatexfunctionrpn":
                                             try {
                                                 Result.Objects[ObjectCount].RotateXFunction = FunctionScripts.GetFunctionScriptFromPostfixNotation(b);
                                             } catch (Exception ex) {
                                                 Interface.AddMessage(Interface.MessageType.Error, false, ex.Message + " in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                                             } break;
                                         case "rotateyfunctionrpn":
                                             try {
                                                 Result.Objects[ObjectCount].RotateYFunction = FunctionScripts.GetFunctionScriptFromPostfixNotation(b);
                                             } catch (Exception ex) {
                                                 Interface.AddMessage(Interface.MessageType.Error, false, ex.Message + " in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                                             } break;
                                         case "rotatezfunctionrpn":
                                             try {
                                                 Result.Objects[ObjectCount].RotateZFunction = FunctionScripts.GetFunctionScriptFromPostfixNotation(b);
                                             } catch (Exception ex) {
                                                 Interface.AddMessage(Interface.MessageType.Error, false, ex.Message + " in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                                             } break;
                                         case "rotatexdamping":
                                         case "rotateydamping":
                                         case "rotatezdamping":
                                             {
                                                 string[] s = b.Split(',');
                                                 if (s.Length == 2) {
                                                     double nf, dr;
                                                     if (!double.TryParse(s[0], System.Globalization.NumberStyles.Float, Culture, out nf)) {
                                                         Interface.AddMessage(Interface.MessageType.Error, false, "NaturalFrequency is invalid in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                                                     } else if (!double.TryParse(s[1], System.Globalization.NumberStyles.Float, Culture, out dr)) {
                                                         Interface.AddMessage(Interface.MessageType.Error, false, "DampingRatio is invalid in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                                                     } else if (nf <= 0.0) {
                                                         Interface.AddMessage(Interface.MessageType.Error, false, "NaturalFrequency is expected to be positive in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                                                     } else if (dr <= 0.0) {
                                                         Interface.AddMessage(Interface.MessageType.Error, false, "DampingRatio is expected to be positive in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                                                     } else {
                                                         switch (a.ToLowerInvariant()) {
                                                             case "rotatexdamping":
                                                                 Result.Objects[ObjectCount].RotateXDamping = new ObjectManager.Damping(nf, dr);
                                                                 break;
                                                             case "rotateydamping":
                                                                 Result.Objects[ObjectCount].RotateYDamping = new ObjectManager.Damping(nf, dr);
                                                                 break;
                                                             case "rotatezdamping":
                                                                 Result.Objects[ObjectCount].RotateZDamping = new ObjectManager.Damping(nf, dr);
                                                                 break;
                                                         }
                                                     }
                                                 } else {
                                                     Interface.AddMessage(Interface.MessageType.Error, false, "Exactly 2 arguments are expected in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                                                 }
                                             } break;
                                         case "textureshiftxdirection":
                                         case "textureshiftydirection":
                                             {
                                                 string[] s = b.Split(',');
                                                 if (s.Length == 2) {
                                                     double x, y;
                                                     if (!double.TryParse(s[0], System.Globalization.NumberStyles.Float, Culture, out x)) {
                                                         Interface.AddMessage(Interface.MessageType.Error, false, "X is invalid in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                                                     } else if (!double.TryParse(s[1], System.Globalization.NumberStyles.Float, Culture, out y)) {
                                                         Interface.AddMessage(Interface.MessageType.Error, false, "Y is invalid in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                                                     } else {
                                                         switch (a.ToLowerInvariant()) {
                                                             case "textureshiftxdirection":
                                                                 Result.Objects[ObjectCount].TextureShiftXDirection = new World.Vector2D(x, y);
                                                                 break;
                                                             case "textureshiftydirection":
                                                                 Result.Objects[ObjectCount].TextureShiftYDirection = new World.Vector2D(x, y);
                                                                 break;
                                                         }
                                                     }
                                                 } else {
                                                     Interface.AddMessage(Interface.MessageType.Error, false, "Exactly 2 arguments are expected in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                                                 }
                                             } break;
                                         case "textureshiftxfunction":
                                             try {
                                                 Result.Objects[ObjectCount].TextureShiftXFunction = FunctionScripts.GetFunctionScriptFromInfixNotation(b);
                                             } catch (Exception ex) {
                                                 Interface.AddMessage(Interface.MessageType.Error, false, ex.Message + " in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                                             } break;
                                         case "textureshiftyfunction":
                                             try {
                                                 Result.Objects[ObjectCount].TextureShiftYFunction = FunctionScripts.GetFunctionScriptFromInfixNotation(b);
                                             } catch (Exception ex) {
                                                 Interface.AddMessage(Interface.MessageType.Error, false, ex.Message + " in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                                             } break;
                                         case "textureshiftxfunctionrpn":
                                             try {
                                                 Result.Objects[ObjectCount].TextureShiftXFunction = FunctionScripts.GetFunctionScriptFromPostfixNotation(b);
                                             } catch (Exception ex) {
                                                 Interface.AddMessage(Interface.MessageType.Error, false, ex.Message + " in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                                             } break;
                                         case "textureshiftyfunctionrpn":
                                             try {
                                                 Result.Objects[ObjectCount].TextureShiftYFunction = FunctionScripts.GetFunctionScriptFromPostfixNotation(b);
                                             } catch (Exception ex) {
                                                 Interface.AddMessage(Interface.MessageType.Error, false, ex.Message + " in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                                             } break;
                                         case "refreshrate":
                                             {
                                                 double r;
                                                 if (!double.TryParse(b, System.Globalization.NumberStyles.Float, Culture, out r)) {
                                                     Interface.AddMessage(Interface.MessageType.Error, false, "Value is invalid in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                                                 } else if (r < 0.0) {
                                                     Interface.AddMessage(Interface.MessageType.Error, false, "Value is expected to be non-negative in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                                                 } else {
                                                     Result.Objects[ObjectCount].RefreshRate = r;
                                                 }
                                             } break;
                                         default:
                                             Interface.AddMessage(Interface.MessageType.Error, false, "The attribute " + a + " is not supported at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                                             break;
                                     }
                                 } else {
                                     Interface.AddMessage(Interface.MessageType.Error, false, "Invalid statement " + Lines[i] + " encountered at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                                     return null;
                                 }
                             }
                             i++;
                         }
                         i--;
                         if (StateFiles != null) {
                             Result.Objects[ObjectCount].States = new ObjectManager.AnimatedObjectState[StateFiles.Length];
                             bool ForceTextureRepeatX = Result.Objects[ObjectCount].TextureShiftXFunction != null & Result.Objects[ObjectCount].TextureShiftXDirection.X != 0.0 |
                                 Result.Objects[ObjectCount].TextureShiftYFunction != null & Result.Objects[ObjectCount].TextureShiftYDirection.Y != 0.0;
                             bool ForceTextureRepeatY = Result.Objects[ObjectCount].TextureShiftXFunction != null & Result.Objects[ObjectCount].TextureShiftXDirection.X != 0.0 |
                                 Result.Objects[ObjectCount].TextureShiftYFunction != null & Result.Objects[ObjectCount].TextureShiftYDirection.Y != 0.0;
                             for (int k = 0; k < StateFiles.Length; k++) {
                                 Result.Objects[ObjectCount].States[k].Position = new World.Vector3D(0.0, 0.0, 0.0);
                                 if (StateFiles[k] != null) {
                                     Result.Objects[ObjectCount].States[k].Object = ObjectManager.LoadStaticObject(StateFiles[k], Encoding, LoadMode, false, ForceTextureRepeatX, ForceTextureRepeatY);
                                     Result.Objects[ObjectCount].States[k].Object.Dynamic = 1;
                                 } else {
                                     Result.Objects[ObjectCount].States[k].Object = null;
                                 }
                                 for (int j = 0; j < Result.Objects[ObjectCount].States.Length; j++) {
                                     Result.Objects[ObjectCount].States[j].Position = Position;
                                 }
                             }
                         } else {
                             Result.Objects[ObjectCount].States = new ObjectManager.AnimatedObjectState[] { };
                         }
                         ObjectCount++;
                     }
                     break;
                 default:
                     Interface.AddMessage(Interface.MessageType.Error, false, "Invalid statement " + Lines[i] + " encountered at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                     return null;
             }
         }
     }
     Array.Resize<ObjectManager.AnimatedObject>(ref Result.Objects, ObjectCount);
     return Result;
 }
Beispiel #6
0
 // get mirrored object
 private static ObjectManager.UnifiedObject GetMirroredObject(ObjectManager.UnifiedObject Prototype)
 {
     if (Prototype is ObjectManager.StaticObject) {
         ObjectManager.StaticObject s = (ObjectManager.StaticObject)Prototype;
         return GetMirroredStaticObject(s);
     } else if (Prototype is ObjectManager.AnimatedObjectCollection) {
         ObjectManager.AnimatedObjectCollection a = (ObjectManager.AnimatedObjectCollection)Prototype;
         ObjectManager.AnimatedObjectCollection Result = new ObjectManager.AnimatedObjectCollection();
         Result.Objects = new ObjectManager.AnimatedObject[a.Objects.Length];
         for (int i = 0; i < a.Objects.Length; i++) {
             Result.Objects[i] = a.Objects[i].Clone();
             for (int j = 0; j < a.Objects[i].States.Length; j++) {
                 Result.Objects[i].States[j].Object = GetMirroredStaticObject(a.Objects[i].States[j].Object);
             }
             Result.Objects[i].TranslateXDirection.X *= -1.0;
             Result.Objects[i].TranslateYDirection.X *= -1.0;
             Result.Objects[i].TranslateZDirection.X *= -1.0;
             Result.Objects[i].RotateXDirection.X *= -1.0;
             Result.Objects[i].RotateYDirection.X *= -1.0;
             Result.Objects[i].RotateZDirection.X *= -1.0;
         }
         return Result;
     } else {
         return null;
     }
 }
Beispiel #7
0
 // get transformed object
 private static ObjectManager.StaticObject GetTransformedStaticObject(ObjectManager.StaticObject Prototype, double NearDistance, double FarDistance)
 {
     ObjectManager.StaticObject Result = ObjectManager.CloneObject(Prototype);
     int n = 0;
     double x2 = 0.0, x3 = 0.0, x6 = 0.0, x7 = 0.0;
     for (int i = 0; i < Result.Mesh.Vertices.Length; i++) {
         if (n == 2) {
             x2 = Result.Mesh.Vertices[i].Coordinates.X;
         } else if (n == 3) {
             x3 = Result.Mesh.Vertices[i].Coordinates.X;
         } else if (n == 6) {
             x6 = Result.Mesh.Vertices[i].Coordinates.X;
         } else if (n == 7) {
             x7 = Result.Mesh.Vertices[i].Coordinates.X;
         }
         n++;
         if (n == 8) {
             break;
         }
     }
     if (n >= 4) {
         int m = 0;
         for (int i = 0; i < Result.Mesh.Vertices.Length; i++) {
             if (m == 0) {
                 Result.Mesh.Vertices[i].Coordinates.X = NearDistance - x3;
             } else if (m == 1) {
                 Result.Mesh.Vertices[i].Coordinates.X = FarDistance - x2;
                 if (n < 8) {
                     m = 8;
                     break;
                 }
             } else if (m == 4) {
                 Result.Mesh.Vertices[i].Coordinates.X = NearDistance - x7;
             } else if (m == 5) {
                 Result.Mesh.Vertices[i].Coordinates.X = NearDistance - x6;
                 m = 8;
                 break;
             }
             m++;
             if (m == 8) {
                 break;
             }
         }
     }
     return Result;
 }
Beispiel #8
0
		// ================================

		// load binary x
		private static ObjectManager.StaticObject LoadBinaryX(string FileName, byte[] Data, int StartingPosition, System.Text.Encoding Encoding, int FloatingPointSize, ObjectManager.ObjectLoadMode LoadMode, bool ForceTextureRepeatX, bool ForceTextureRepeatY) {
			// parse file
			Structure Structure;
			try {
				bool Result;
				using (System.IO.MemoryStream Stream = new System.IO.MemoryStream(Data)) {
					using (System.IO.BinaryReader Reader = new System.IO.BinaryReader(Stream)) {
						Stream.Position = StartingPosition;
						BinaryCache Cache = new BinaryCache();
						Cache.IntegersRemaining = 0;
						Cache.FloatsRemaining = 0;
						Result = ReadBinaryTemplate(FileName, Reader, FloatingPointSize, new Template("", new string[] { "[...]" }), false, ref Cache, out Structure);
						Reader.Close();
					}
					Stream.Close();
				} if (!Result) {
					return null;
				}
			} catch (Exception ex) {
				Interface.AddMessage(Interface.MessageType.Error, false, "Unhandled error (" + ex.Message + ") encountered in binary X object file " + FileName);
				return null;
			}
			// process structure
			ObjectManager.StaticObject Object;
			if (!ProcessStructure(FileName, Structure, out Object, LoadMode, ForceTextureRepeatX, ForceTextureRepeatY)) {
				return null;
			} return Object;
		}
Beispiel #9
0
		internal static void AddObjectForCustomTimetable(ObjectManager.AnimatedObject obj) { }
		private static void ApplyTranslation(ObjectManager.StaticObject Object, double x, double y, double z) {
			for (int i = 0; i < Object.Mesh.Vertices.Length; i++) {
				Object.Mesh.Vertices[i].Coordinates.X += x;
				Object.Mesh.Vertices[i].Coordinates.Y += y;
				Object.Mesh.Vertices[i].Coordinates.Z += z;
			}
		}
Beispiel #11
0
		/// <summary>Checks whether the camera can move in the selected direction, due to a bounding box.</summary>
		/// <returns>True if we are able to move the camera, false otherwise</returns>
		internal static bool PerformBoundingBoxTest(ref ObjectManager.StaticObject bounding, ref Vector3 cameraLocation)
		{
			if (cameraLocation.X < bounding.Mesh.BoundingBox[0].X || cameraLocation.X > bounding.Mesh.BoundingBox[1].X ||
				cameraLocation.Y < bounding.Mesh.BoundingBox[0].Y || cameraLocation.Y > bounding.Mesh.BoundingBox[1].Y ||
				cameraLocation.Z < bounding.Mesh.BoundingBox[0].Z || cameraLocation.Z > bounding.Mesh.BoundingBox[1].Z)
			{
				//Our bounding boxes do not intersect
				return true;
			}
			return false;
		}
        //Parses an XML background definition
        public static BackgroundManager.BackgroundHandle ReadBackgroundXML(string fileName)
        {
            List <BackgroundManager.StaticBackground> Backgrounds = new List <BackgroundManager.StaticBackground>();
            //The current XML file to load
            XmlDocument currentXML = new XmlDocument();

            //Load the object's XML file
            currentXML.Load(fileName);
            string Path = System.IO.Path.GetDirectoryName(fileName);

            double[] UnitOfLength = { 1.0 };
            //Check for null
            if (currentXML.DocumentElement != null)
            {
                XmlNodeList DocumentNodes = currentXML.DocumentElement.SelectNodes("/openBVE/Background");
                //Check this file actually contains OpenBVE light definition nodes
                if (DocumentNodes != null)
                {
                    foreach (XmlNode n in DocumentNodes)
                    {
                        if (n.ChildNodes.OfType <XmlElement>().Any())
                        {
                            double DisplayTime = -1;
                            //The time to transition between backgrounds in seconds
                            double TransitionTime = 0.8;
                            //The texture to use (if static)
                            Texture t = null;
                            //The object to use (if object based)
                            ObjectManager.StaticObject o = null;
                            //The transition mode between backgrounds
                            BackgroundManager.BackgroundTransitionMode mode = BackgroundManager.BackgroundTransitionMode.FadeIn;
                            //The number of times the texture is repeated around the viewing frustrum (if appropriate)
                            double repetitions = 6;
                            foreach (XmlNode c in n.ChildNodes)
                            {
                                string[] Arguments = c.InnerText.Split(',');
                                switch (c.Name.ToLowerInvariant())
                                {
                                case "mode":
                                    switch (c.InnerText.ToLowerInvariant())
                                    {
                                    case "fadein":
                                        mode = BackgroundManager.BackgroundTransitionMode.FadeIn;
                                        break;

                                    case "fadeout":
                                        mode = BackgroundManager.BackgroundTransitionMode.FadeOut;
                                        break;

                                    case "none":
                                        mode = BackgroundManager.BackgroundTransitionMode.None;
                                        break;

                                    default:
                                        Interface.AddMessage(MessageType.Error, true, c.InnerText + "is not a valid background fade mode in file " + fileName);
                                        break;
                                    }
                                    break;

                                case "object":
                                    string f;
                                    try
                                    {
                                        f = OpenBveApi.Path.CombineFile(System.IO.Path.GetDirectoryName(fileName), c.InnerText);
                                    }
                                    catch
                                    {
                                        Interface.AddMessage(MessageType.Error, true, "BackgroundObject FileName is malformed in file " + fileName);
                                        break;
                                    }
                                    if (!System.IO.File.Exists(f))
                                    {
                                        Interface.AddMessage(MessageType.Error, true, "FileName " + f + " not found in file " + fileName);
                                    }
                                    else
                                    {
                                        UnifiedObject b = ObjectManager.LoadObject(f, System.Text.Encoding.Default, false, false, false);
                                        o = (ObjectManager.StaticObject)b;
                                    }
                                    break;

                                case "repetitions":
                                    if (!NumberFormats.TryParseDoubleVb6(Arguments[0], UnitOfLength, out repetitions))
                                    {
                                        Interface.AddMessage(MessageType.Error, false, c.InnerText + " does not parse to a valid number of repetitions in " + fileName);
                                    }
                                    break;

                                case "texture":
                                    string file;
                                    try
                                    {
                                        file = OpenBveApi.Path.CombineFile(Path, c.InnerText);
                                    }
                                    catch
                                    {
                                        Interface.AddMessage(MessageType.Error, true, "BackgroundTexture FileName is malformed in file " + fileName);
                                        break;
                                    }
                                    if (!System.IO.File.Exists(file))
                                    {
                                        Interface.AddMessage(MessageType.Error, false, "The background texture file " + c.InnerText + " does not exist in " + fileName);
                                    }
                                    else
                                    {
                                        Textures.RegisterTexture(file, out t);
                                    }
                                    break;

                                case "time":
                                    if (!Interface.TryParseTime(Arguments[0].Trim(), out DisplayTime))
                                    {
                                        Interface.AddMessage(MessageType.Error, false, c.InnerText + " does not parse to a valid time in file " + fileName);
                                    }
                                    break;

                                case "transitiontime":
                                    if (!NumberFormats.TryParseDoubleVb6(Arguments[0], UnitOfLength, out TransitionTime))
                                    {
                                        Interface.AddMessage(MessageType.Error, false, c.InnerText + " is not a valid background transition time in " + fileName);
                                    }
                                    break;
                                }
                            }
                            //Create background if texture is not null
                            if (t != null && o == null)
                            {
                                Backgrounds.Add(new BackgroundManager.StaticBackground(t, repetitions, false, TransitionTime, mode, DisplayTime));
                            }
                            if (t == null && o != null)
                            {
                                //All other parameters are ignored if an object has been defined
                                //TODO: Error message stating they have been ignored
                                return(new BackgroundManager.BackgroundObject(o));
                            }
                        }
                    }
                    if (Backgrounds.Count == 1)
                    {
                        return(Backgrounds[0]);
                    }
                    if (Backgrounds.Count > 1)
                    {
                        //Sort list- Not worried about when they start or end, so use simple LINQ
                        Backgrounds = Backgrounds.OrderBy(o => o.Time).ToList();
                        //If more than 2 backgrounds, convert to array and return a new dynamic background
                        return(new BackgroundManager.DynamicBackground(Backgrounds.ToArray()));
                    }
                }
            }
            //We couldn't find any valid XML, so return false
            throw new InvalidDataException();
        }
Beispiel #13
0
        private void button1_Click(object sender, EventArgs e)
        {
            TextureManager.InterpolationMode previousInterpolationMode = Interface.CurrentOptions.Interpolation;
            int previousAntialasingLevel = Interface.CurrentOptions.AntialiasingLevel;
            int previousAnsiotropicLevel = Interface.CurrentOptions.AnisotropicFilteringLevel;

            //Interpolation mode
            switch (InterpolationMode.SelectedIndex)
            {
            case 0:
                Interface.CurrentOptions.Interpolation = TextureManager.InterpolationMode.NearestNeighbor;
                break;

            case 1:
                Interface.CurrentOptions.Interpolation = TextureManager.InterpolationMode.Bilinear;
                break;

            case 2:
                Interface.CurrentOptions.Interpolation = TextureManager.InterpolationMode.NearestNeighborMipmapped;
                break;

            case 3:
                Interface.CurrentOptions.Interpolation = TextureManager.InterpolationMode.BilinearMipmapped;
                break;

            case 4:
                Interface.CurrentOptions.Interpolation = TextureManager.InterpolationMode.TrilinearMipmapped;
                break;

            case 5:
                Interface.CurrentOptions.Interpolation = TextureManager.InterpolationMode.AnisotropicFiltering;
                break;
            }
            //Ansiotropic filtering level
            Interface.CurrentOptions.AnisotropicFilteringLevel = (int)AnsiotropicLevel.Value;
            //Antialiasing level
            Interface.CurrentOptions.AntialiasingLevel = (int)AntialiasingLevel.Value;
            if (Interface.CurrentOptions.AntialiasingLevel != previousAntialasingLevel)
            {
                Program.currentGraphicsMode = new GraphicsMode(new ColorFormat(8, 8, 8, 8), 24, 8, Interface.CurrentOptions.AntialiasingLevel);
            }
            //Transparency quality
            switch (TransparencyQuality.SelectedIndex)
            {
            case 0:
                Interface.CurrentOptions.TransparencyMode = Renderer.TransparencyMode.Sharp;
                break;

            default:
                Interface.CurrentOptions.TransparencyMode = Renderer.TransparencyMode.Smooth;
                break;
            }
            //Set width and height
            if (Renderer.ScreenWidth != width.Value || Renderer.ScreenHeight != height.Value)
            {
                Renderer.ScreenWidth             = (int)width.Value;
                Renderer.ScreenHeight            = (int)height.Value;
                Program.currentGameWindow.Width  = (int)width.Value;
                Program.currentGameWindow.Height = (int)height.Value;
                Program.UpdateViewport();
            }
            //Check if interpolation mode or ansiotropic filtering level has changed, and trigger a reload
            if (previousInterpolationMode != Interface.CurrentOptions.Interpolation || previousAnsiotropicLevel != Interface.CurrentOptions.AnisotropicFilteringLevel)
            {
                Program.ReducedMode      = false;
                Program.LightingRelative = -1.0;
                Game.Reset();
                TextureManager.UnuseAllTextures();
                Fonts.Initialize();
                Interface.ClearMessages();
                for (int i = 0; i < Program.Files.Length; i++)
                {
#if !DEBUG
                    try {
#endif
                    ObjectManager.UnifiedObject o = ObjectManager.LoadObject(Program.Files[i], System.Text.Encoding.UTF8, ObjectManager.ObjectLoadMode.Normal, false, false, false);
                    ObjectManager.CreateObject(o, new Vector3(0.0, 0.0, 0.0),
                                               new World.Transformation(0.0, 0.0, 0.0), new World.Transformation(0.0, 0.0, 0.0), true, 0.0,
                                               0.0, 25.0, 0.0);
#if !DEBUG
                }
                catch (Exception ex) {
                    Interface.AddMessage(Interface.MessageType.Critical, false, "Unhandled error (" + ex.Message + ") encountered while processing the file " + Program.Files[i] + ".");
                }
#endif
                }
                ObjectManager.InitializeVisibility();
                ObjectManager.UpdateVisibility(0.0, true);
                ObjectManager.UpdateAnimatedWorldObjects(0.01, true);
            }
            Renderer.TransparentColorDepthSorting = Interface.CurrentOptions.TransparencyMode == Renderer.TransparencyMode.Smooth & Interface.CurrentOptions.Interpolation != TextureManager.InterpolationMode.NearestNeighbor & Interface.CurrentOptions.Interpolation != TextureManager.InterpolationMode.Bilinear;
            Options.SaveOptions();
            this.Close();
        }
Beispiel #14
0
			/// <summary>Creates a new background object</summary>
			/// <param name="Object">The object to use for the background</param>
			internal BackgroundObject(ObjectManager.StaticObject Object)
			{
				this.ObjectBackground = Object;
			}
Beispiel #15
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];
            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;
        }
Beispiel #16
0
        // parse animated object config
        /// <summary>Loads a collection of animated objects from a file.</summary>
        /// <param name="FileName">The text file to load the animated object from. Must be an absolute file name.</param>
        /// <param name="Encoding">The encoding the file is saved in. If the file uses a byte order mark, the encoding indicated by the byte order mark is used and the Encoding parameter is ignored.</param>
        /// <param name="LoadMode">The texture load mode.</param>
        /// <returns>The collection of animated objects.</returns>
        internal static ObjectManager.AnimatedObjectCollection ReadObject(string FileName, System.Text.Encoding Encoding, ObjectManager.ObjectLoadMode LoadMode)
        {
            ObjectManager.AnimatedObjectCollection Result = new ObjectManager.AnimatedObjectCollection();
            Result.Objects = new ObjectManager.AnimatedObject[4];
            int ObjectCount = 0;

            // load file
            string[] Lines   = System.IO.File.ReadAllLines(FileName, Encoding);
            bool     rpnUsed = false;

            for (int i = 0; i < Lines.Length; i++)
            {
                int j = Lines[i].IndexOf(';');
                // cut comments out
                Lines[i] = j >= 0 ? Lines[i].Substring(0, j).Trim() : Lines[i].Trim();
                rpnUsed  = Lines[i].IndexOf("functionrpn", StringComparison.OrdinalIgnoreCase) >= 0;
            }
            if (rpnUsed)
            {
                Debug.AddMessage(Debug.MessageType.Error, false, "An animated object file contains RPN functions. These were never meant to be used directly, only for debugging. They won't be supported indefinately. Please get rid of them in file " + FileName);
            }
            for (int i = 0; i < Lines.Length; i++)
            {
                if (Lines[i].Length != 0)
                {
                    switch (Lines[i].ToLowerInvariant())
                    {
                    case "[include]":
                    {
                        i++;
                        Vector3D position = new Vector3D(0.0, 0.0, 0.0);
                        ObjectManager.UnifiedObject[] obj = new ObjectManager.UnifiedObject[4];
                        int objCount = 0;
                        while (i < Lines.Length && !(Lines[i].StartsWith("[", StringComparison.Ordinal) && Lines[i].EndsWith("]", StringComparison.Ordinal)))
                        {
                            if (Lines[i].Length != 0)
                            {
                                int equals = Lines[i].IndexOf("=", StringComparison.Ordinal);
                                if (equals > 0)
                                {
                                    /*
                                     * Process key-value pair, the only supported key is position.
                                     */
                                    string before = Lines[i].Substring(0, equals).TrimEnd();
                                    string after  = Lines[i].Substring(equals + 1).TrimStart();
                                    switch (before.ToLowerInvariant())
                                    {
                                    case "position":
                                        ParsePosition(after, ref position, before, i + 1, FileName);
                                        break;

                                    default:
                                        Debug.AddMessage(Debug.MessageType.Error, false, "The attribute " + before + " is not supported at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                                        break;
                                    }
                                }
                                else
                                {
                                    /*
                                     * Process object with file name relative to the location of this ANIMATED file.
                                     */
                                    string Folder = System.IO.Path.GetDirectoryName(FileName);
                                    if (Path.ContainsInvalidPathChars(Lines[i]))
                                    {
                                        Debug.AddMessage(Debug.MessageType.Error, false, Lines[i] + " contains illegal characters at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                                    }
                                    else
                                    {
                                        string file = OpenBveApi.Path.CombineFile(Folder, Lines[i]);
                                        if (System.IO.File.Exists(file))
                                        {
                                            if (obj.Length == objCount)
                                            {
                                                Array.Resize <ObjectManager.UnifiedObject>(ref obj, obj.Length << 1);
                                            }
                                            obj[objCount] = ObjectManager.LoadObject(file, Encoding, LoadMode, false, false, false);
                                            objCount++;
                                        }
                                        else
                                        {
                                            Debug.AddMessage(Debug.MessageType.Error, true, "File " + file + " not found at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                                        }
                                    }
                                }
                            }
                            i++;
                        }
                        i--;
                        for (int j = 0; j < objCount; j++)
                        {
                            if (obj[j] != null)
                            {
                                if (obj[j] is ObjectManager.StaticObject)
                                {
                                    ObjectManager.StaticObject s = (ObjectManager.StaticObject)obj[j];
                                    s.Dynamic = true;
                                    if (ObjectCount >= Result.Objects.Length)
                                    {
                                        Array.Resize <ObjectManager.AnimatedObject>(ref Result.Objects, Result.Objects.Length << 1);
                                    }
                                    ObjectManager.AnimatedObject      a   = new ObjectManager.AnimatedObject();
                                    ObjectManager.AnimatedObjectState aos = new ObjectManager.AnimatedObjectState();
                                    aos.Object   = s;
                                    aos.Position = position;
                                    a.States     = new[] { aos };
                                    Result.Objects[ObjectCount] = 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++)
                                    {
                                        if (ObjectCount >= Result.Objects.Length)
                                        {
                                            Array.Resize <ObjectManager.AnimatedObject>(ref Result.Objects, Result.Objects.Length << 1);
                                        }
                                        for (int h = 0; h < a.Objects[k].States.Length; h++)
                                        {
                                            a.Objects[k].States[h].Position.X += position.X;
                                            a.Objects[k].States[h].Position.Y += position.Y;
                                            a.Objects[k].States[h].Position.Z += position.Z;
                                        }
                                        Result.Objects[ObjectCount] = a.Objects[k];
                                        ObjectCount++;
                                    }
                                }
                            }
                        }
                    }
                    break;

                    case "[object]":
                    {
                        i++;
                        if (Result.Objects.Length == ObjectCount)
                        {
                            Array.Resize <ObjectManager.AnimatedObject>(ref Result.Objects, Result.Objects.Length << 1);
                        }
                        Result.Objects[ObjectCount]                        = new ObjectManager.AnimatedObject();
                        Result.Objects[ObjectCount].States                 = new ObjectManager.AnimatedObjectState[] { };
                        Result.Objects[ObjectCount].CurrentState           = -1;
                        Result.Objects[ObjectCount].TranslateXDirection    = new Vector3D(1.0, 0.0, 0.0);
                        Result.Objects[ObjectCount].TranslateYDirection    = new Vector3D(0.0, 1.0, 0.0);
                        Result.Objects[ObjectCount].TranslateZDirection    = new Vector3D(0.0, 0.0, 1.0);
                        Result.Objects[ObjectCount].RotateXDirection       = new Vector3D(1.0, 0.0, 0.0);
                        Result.Objects[ObjectCount].RotateYDirection       = new Vector3D(0.0, 1.0, 0.0);
                        Result.Objects[ObjectCount].RotateZDirection       = new Vector3D(0.0, 0.0, 1.0);
                        Result.Objects[ObjectCount].TextureShiftXDirection = new Vector2D(1.0, 0.0);
                        Result.Objects[ObjectCount].TextureShiftYDirection = new Vector2D(0.0, 1.0);
                        Result.Objects[ObjectCount].RefreshRate            = 0.0;
                        Result.Objects[ObjectCount].ObjectIndex            = -1;
                        Vector3D Position          = new Vector3D(0.0, 0.0, 0.0);
                        bool     timetableUsed     = false;
                        string[] StateFiles        = null;
                        string   StateFunctionRpn  = null;
                        int      StateFunctionLine = -1;
                        while (i < Lines.Length && !(Lines[i].StartsWith("[", StringComparison.Ordinal) && Lines[i].EndsWith("]", StringComparison.Ordinal)))
                        {
                            if (Lines[i].Length != 0)
                            {
                                int equals = Lines[i].IndexOf("=", StringComparison.Ordinal);
                                if (equals > 0)
                                {
                                    string before = Lines[i].Substring(0, equals).TrimEnd();
                                    string after  = Lines[i].Substring(equals + 1).TrimStart();
                                    switch (before.ToLowerInvariant())
                                    {
                                    case "position":
                                        ParsePosition(after, ref Position, before, i + 1, FileName);
                                        break;

                                    case "states":
                                        if (!ParseState(after, ref StateFiles, before, i + 1, FileName))
                                        {
                                            return(null);
                                        }
                                        break;

                                    case "statefunction":
                                        try {
                                            StateFunctionLine = i;
                                            StateFunctionRpn  = FunctionScripts.GetPostfixNotationFromInfixNotation(after);
                                        } catch (Exception ex) {
                                            Debug.AddMessage(Debug.MessageType.Error, false, ex.Message + " in " + before + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                                        } break;

                                    case "statefunctionrpn":
                                    {
                                        StateFunctionLine = i;
                                        StateFunctionRpn  = after;
                                    } break;

                                    case "translatexdirection":
                                        ParseTranslateDirection(after, ref Result.Objects[ObjectCount].TranslateXDirection,
                                                                before, i + 1, FileName);
                                        break;

                                    case "translateydirection":
                                        ParseTranslateDirection(after, ref Result.Objects[ObjectCount].TranslateYDirection,
                                                                before, i + 1, FileName);
                                        break;

                                    case "translatezdirection":
                                        ParseTranslateDirection(after, ref Result.Objects[ObjectCount].TranslateZDirection,
                                                                before, i + 1, FileName);
                                        break;

                                    case "translatexfunction":
                                        ParseInfixFunc(after, ref Result.Objects[ObjectCount].TranslateXFunction, before, i + 1, FileName);
                                        break;

                                    case "translateyfunction":
                                        ParseInfixFunc(after, ref Result.Objects[ObjectCount].TranslateYFunction, before, i + 1, FileName);
                                        break;

                                    case "translatezfunction":
                                        ParseInfixFunc(after, ref Result.Objects[ObjectCount].TranslateZFunction, before, i + 1, FileName);
                                        break;

                                    case "translatexfunctionrpn":
                                        ParsePostfixFunc(after, ref Result.Objects[ObjectCount].TranslateXFunction, before, i + 1, FileName);
                                        break;

                                    case "translateyfunctionrpn":
                                        ParsePostfixFunc(after, ref Result.Objects[ObjectCount].TranslateYFunction, before, i + 1, FileName);
                                        break;

                                    case "translatezfunctionrpn":
                                        ParsePostfixFunc(after, ref Result.Objects[ObjectCount].TranslateZFunction, before, i + 1, FileName);
                                        break;

                                    case "rotatexdirection":
                                        ParseRotateDirection(after, ref Result.Objects[ObjectCount].RotateXDirection, before, i + 1, FileName);
                                        break;

                                    case "rotateydirection":
                                        ParseRotateDirection(after, ref Result.Objects[ObjectCount].RotateYDirection, before, i + 1, FileName);
                                        break;

                                    case "rotatezdirection":
                                        ParseRotateDirection(after, ref Result.Objects[ObjectCount].RotateZDirection, before, i + 1, FileName);
                                        break;

                                    case "rotatexfunction":
                                        ParseInfixFunc(after, ref Result.Objects[ObjectCount].RotateXFunction, before, i + 1, FileName);
                                        break;

                                    case "rotateyfunction":
                                        ParseInfixFunc(after, ref Result.Objects[ObjectCount].RotateYFunction, before, i + 1, FileName);
                                        break;

                                    case "rotatezfunction":
                                        ParseInfixFunc(after, ref Result.Objects[ObjectCount].RotateZFunction, before, i + 1, FileName);
                                        break;

                                    case "rotatexfunctionrpn":
                                        ParsePostfixFunc(after, ref Result.Objects[ObjectCount].RotateXFunction, before, i + 1, FileName);
                                        break;

                                    case "rotateyfunctionrpn":
                                        ParsePostfixFunc(after, ref Result.Objects[ObjectCount].RotateYFunction, before, i + 1, FileName);
                                        break;

                                    case "rotatezfunctionrpn":
                                        ParsePostfixFunc(after, ref Result.Objects[ObjectCount].RotateZFunction, before, i + 1, FileName);
                                        break;

                                    case "rotatexdamping":
                                        ParseRotateDamping(after, ref Result.Objects[ObjectCount].RotateXDamping, before, i + 1, FileName);
                                        break;

                                    case "rotateydamping":
                                        ParseRotateDamping(after, ref Result.Objects[ObjectCount].RotateYDamping, before, i + 1, FileName);
                                        break;

                                    case "rotatezdamping":
                                        ParseRotateDamping(after, ref Result.Objects[ObjectCount].RotateZDamping, before, i + 1, FileName);
                                        break;

                                    case "textureshiftxdirection":
                                        ParseTextureShift(after, ref Result.Objects[ObjectCount].TextureShiftXDirection, before, i + 1, FileName);
                                        break;

                                    case "textureshiftydirection":
                                        ParseTextureShift(after, ref Result.Objects[ObjectCount].TextureShiftYDirection, before, i + 1, FileName);
                                        break;

                                    case "textureshiftxfunction":
                                        ParseInfixFunc(after, ref Result.Objects[ObjectCount].TextureShiftXFunction, before, i + 1, FileName);
                                        break;

                                    case "textureshiftyfunction":
                                        ParseInfixFunc(after, ref Result.Objects[ObjectCount].TextureShiftYFunction, before, i + 1, FileName);
                                        break;

                                    case "textureshiftxfunctionrpn":
                                        ParsePostfixFunc(after, ref Result.Objects[ObjectCount].TextureShiftXFunction, before, i + 1, FileName);
                                        break;

                                    case "textureshiftyfunctionrpn":
                                        ParsePostfixFunc(after, ref Result.Objects[ObjectCount].TextureShiftYFunction, before, i + 1, FileName);
                                        break;

                                    case "textureoverride":
                                        switch (after.ToLowerInvariant())
                                        {
                                        case "none":
                                            break;

                                        case "timetable":
                                            if (!timetableUsed)
                                            {
                                                Timetable.AddObjectForCustomTimetable(Result.Objects[ObjectCount]);
                                                timetableUsed = true;
                                            }
                                            break;

                                        default:
                                            Debug.AddMessage(Debug.MessageType.Error, false, "Unrecognized value in " + before + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                                            break;
                                        }
                                        break;

                                    case "refreshrate":
                                    {
                                        double r;
                                        if (!double.TryParse(after, System.Globalization.NumberStyles.Float, Culture, out r))
                                        {
                                            Debug.AddMessage(Debug.MessageType.Error, false, "Value is invalid in " + before + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                                        }
                                        else if (r < 0.0)
                                        {
                                            Debug.AddMessage(Debug.MessageType.Error, false, "Value is expected to be non-negative in " + before + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                                        }
                                        else
                                        {
                                            Result.Objects[ObjectCount].RefreshRate = r;
                                        }
                                    } break;

                                    default:
                                        Debug.AddMessage(Debug.MessageType.Error, false, "The attribute " + before + " is not supported at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                                        break;
                                    }
                                }
                                else
                                {
                                    Debug.AddMessage(Debug.MessageType.Error, false, "Invalid statement " + Lines[i] + " encountered at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                                    return(null);
                                }
                            }
                            i++;
                        }
                        i--;
                        if (StateFiles != null)
                        {
                            // create the object
                            if (timetableUsed)
                            {
                                if (StateFunctionRpn != null)
                                {
                                    StateFunctionRpn = "timetable 0 == " + StateFunctionRpn + " -1 ?";
                                }
                                else
                                {
                                    StateFunctionRpn = "timetable";
                                }
                            }
                            if (StateFunctionRpn != null)
                            {
                                try {
                                    Result.Objects[ObjectCount].StateFunction = FunctionScripts.GetFunctionScriptFromPostfixNotation(StateFunctionRpn);
                                } catch (Exception ex) {
                                    Debug.AddMessage(Debug.MessageType.Error, false, ex.Message + " in StateFunction at line " + (StateFunctionLine + 1).ToString(Culture) + " in file " + FileName);
                                }
                            }
                            Result.Objects[ObjectCount].States = new ObjectManager.AnimatedObjectState[StateFiles.Length];
                            bool ForceTextureRepeatX = Result.Objects[ObjectCount].TextureShiftXFunction != null && Result.Objects[ObjectCount].TextureShiftXDirection.X != 0.0 ||
                                                       Result.Objects[ObjectCount].TextureShiftYFunction != null && Result.Objects[ObjectCount].TextureShiftYDirection.Y != 0.0;
                            bool ForceTextureRepeatY = Result.Objects[ObjectCount].TextureShiftXFunction != null && Result.Objects[ObjectCount].TextureShiftXDirection.X != 0.0 ||
                                                       Result.Objects[ObjectCount].TextureShiftYFunction != null && Result.Objects[ObjectCount].TextureShiftYDirection.Y != 0.0;
                            for (int k = 0; k < StateFiles.Length; k++)
                            {
                                Result.Objects[ObjectCount].States[k].Position = new Vector3D(0.0, 0.0, 0.0);
                                if (StateFiles[k] != null)
                                {
                                    Result.Objects[ObjectCount].States[k].Object = ObjectManager.LoadStaticObject(StateFiles[k], Encoding, LoadMode, false, ForceTextureRepeatX, ForceTextureRepeatY);
                                    if (Result.Objects[ObjectCount].States[k].Object != null)
                                    {
                                        Result.Objects[ObjectCount].States[k].Object.Dynamic = true;
                                    }
                                }
                                else
                                {
                                    Result.Objects[ObjectCount].States[k].Object = null;
                                }
                                for (int j = 0; j < Result.Objects[ObjectCount].States.Length; j++)
                                {
                                    Result.Objects[ObjectCount].States[j].Position = Position;
                                }
                            }
                        }
                        else
                        {
                            Result.Objects[ObjectCount].States = new ObjectManager.AnimatedObjectState[] { };
                        }
                        ObjectCount++;
                    }
                    break;

                    default:
                        Debug.AddMessage(Debug.MessageType.Error, false, "Invalid statement " + Lines[i] + " encountered at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                        return(null);
                    }
                }
            }
            Array.Resize <ObjectManager.AnimatedObject>(ref Result.Objects, ObjectCount);
            return(Result);
        }
		/// <summary>
		/// Parses the string representing rotation damping to a ObjectManager.Damping. Error messages are written when necessary.
		/// </summary>
		/// <param name="value">String representation.</param>
		/// <param name="damp">Output damping.</param>
		/// <param name="field">Actual field name.</param>
		/// <param name="filename">File name.</param>
		/// <param name="line">Actual line number string.</param>
		private static void ParseRotateDamping(string value, ref ObjectManager.Damping damp, string field, int line, string filename){
			string[] s = value.Split(',');
			if (s.Length == 2) {
				double nf, dr;
				if (!double.TryParse(s[0], System.Globalization.NumberStyles.Float, Culture, out nf)) {
					Debug.AddMessage(Debug.MessageType.Error, false, "NaturalFrequency is invalid in " + field + " at line " + line.ToString(Culture) + " in file " + filename);
				} else if (!double.TryParse(s[1], System.Globalization.NumberStyles.Float, Culture, out dr)) {
					Debug.AddMessage(Debug.MessageType.Error, false, "DampingRatio is invalid in " + field + " at line " + line.ToString(Culture) + " in file " + filename);
				} else if (nf <= 0.0) {
					Debug.AddMessage(Debug.MessageType.Error, false, "NaturalFrequency is expected to be positive in " + field + " at line " + line.ToString(Culture) + " in file " + filename);
				} else if (dr <= 0.0) {
					Debug.AddMessage(Debug.MessageType.Error, false, "DampingRatio is expected to be positive in " + field + " at line " + line.ToString(Culture) + " in file " + filename);
				} else {
					damp = new ObjectManager.Damping(nf, dr);
				}
			} else {
				Debug.AddMessage(Debug.MessageType.Error, false, "Exactly 2 arguments are expected in " + field + " at line " + line.ToString(Culture) + " in file " + filename);
			}
		}
		// parse animated object config
		/// <summary>Loads a collection of animated objects from a file.</summary>
		/// <param name="FileName">The text file to load the animated object from. Must be an absolute file name.</param>
		/// <param name="Encoding">The encoding the file is saved in. If the file uses a byte order mark, the encoding indicated by the byte order mark is used and the Encoding parameter is ignored.</param>
		/// <param name="LoadMode">The texture load mode.</param>
		/// <returns>The collection of animated objects.</returns>
		internal static ObjectManager.AnimatedObjectCollection ReadObject(string FileName, System.Text.Encoding Encoding, ObjectManager.ObjectLoadMode LoadMode) {
			ObjectManager.AnimatedObjectCollection Result = new ObjectManager.AnimatedObjectCollection();
			Result.Objects = new ObjectManager.AnimatedObject[4];
			int ObjectCount = 0;
			// load file
			string[] Lines = System.IO.File.ReadAllLines(FileName, Encoding);
			bool rpnUsed = false;
			for (int i = 0; i < Lines.Length; i++) {
				int j = Lines[i].IndexOf(';');
				// cut comments out
				Lines[i] = j >= 0 ? Lines[i].Substring(0, j).Trim() : Lines[i].Trim();
				rpnUsed = Lines[i].IndexOf("functionrpn", StringComparison.OrdinalIgnoreCase) >= 0;
			}
			if (rpnUsed) {
				Debug.AddMessage(Debug.MessageType.Error, false, "An animated object file contains RPN functions. These were never meant to be used directly, only for debugging. They won't be supported indefinately. Please get rid of them in file " + FileName);
			}
			for (int i = 0; i < Lines.Length; i++) {
				if (Lines[i].Length != 0) {
					switch (Lines[i].ToLowerInvariant()) {
						case "[include]":
							{
								i++;
								Vector3D position = new Vector3D(0.0, 0.0, 0.0);
								ObjectManager.UnifiedObject[] obj = new ObjectManager.UnifiedObject[4];
								int objCount = 0;
								while (i < Lines.Length && !(Lines[i].StartsWith("[", StringComparison.Ordinal) && Lines[i].EndsWith("]", StringComparison.Ordinal))) {
									if (Lines[i].Length != 0) {
										int equals = Lines[i].IndexOf("=", StringComparison.Ordinal);
										if (equals > 0) {
											/*
											 * Process key-value pair, the only supported key is position.
											 */
											string before = Lines[i].Substring(0, equals).TrimEnd();
											string after = Lines[i].Substring(equals + 1).TrimStart();
											switch (before.ToLowerInvariant()) {
												case "position":
													ParsePosition(after, ref position, before, i + 1, FileName);
													break;
												default:
													Debug.AddMessage(Debug.MessageType.Error, false, "The attribute " + before + " is not supported at line " + (i + 1).ToString(Culture) + " in file " + FileName);
													break;
											}
										} else {
											/*
											 * Process object with file name relative to the location of this ANIMATED file.
											 */
											string Folder = System.IO.Path.GetDirectoryName(FileName);
											if (Path.ContainsInvalidPathChars(Lines[i])) {
												Debug.AddMessage(Debug.MessageType.Error, false, Lines[i] + " contains illegal characters at line " + (i + 1).ToString(Culture) + " in file " + FileName);
											} else {
												string file = OpenBveApi.Path.CombineFile(Folder, Lines[i]);
												if (System.IO.File.Exists(file)) {
													if (obj.Length == objCount) {
														Array.Resize<ObjectManager.UnifiedObject>(ref obj, obj.Length << 1);
													}
													obj[objCount] = ObjectManager.LoadObject(file, Encoding, LoadMode, false, false, false);
													objCount++;
												} else {
													Debug.AddMessage(Debug.MessageType.Error, true, "File " + file + " not found at line " + (i + 1).ToString(Culture) + " in file " + FileName);
												}
											}
										}
									}
									i++;
								}
								i--;
								for (int j = 0; j < objCount; j++) {
									if (obj[j] != null) {
										if (obj[j] is ObjectManager.StaticObject) {
											ObjectManager.StaticObject s = (ObjectManager.StaticObject)obj[j];
											s.Dynamic = true;
											if (ObjectCount >= Result.Objects.Length) {
												Array.Resize<ObjectManager.AnimatedObject>(ref Result.Objects, Result.Objects.Length << 1);
											}
											ObjectManager.AnimatedObject a = new ObjectManager.AnimatedObject();
											ObjectManager.AnimatedObjectState aos = new ObjectManager.AnimatedObjectState();
											aos.Object = s;
											aos.Position = position;
											a.States = new[] { aos };
											Result.Objects[ObjectCount] = 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++) {
												if (ObjectCount >= Result.Objects.Length) {
													Array.Resize<ObjectManager.AnimatedObject>(ref Result.Objects, Result.Objects.Length << 1);
												}
												for (int h = 0; h < a.Objects[k].States.Length; h++) {
													a.Objects[k].States[h].Position.X += position.X;
													a.Objects[k].States[h].Position.Y += position.Y;
													a.Objects[k].States[h].Position.Z += position.Z;
												}
												Result.Objects[ObjectCount] = a.Objects[k];
												ObjectCount++;
											}
										}
									}
								}
							}
							break;
						case "[object]":
							{
								i++;
								if (Result.Objects.Length == ObjectCount) {
									Array.Resize<ObjectManager.AnimatedObject>(ref Result.Objects, Result.Objects.Length << 1);
								}
								Result.Objects[ObjectCount] = new ObjectManager.AnimatedObject();
								Result.Objects[ObjectCount].States = new ObjectManager.AnimatedObjectState[] { };
								Result.Objects[ObjectCount].CurrentState = -1;
								Result.Objects[ObjectCount].TranslateXDirection = new Vector3D(1.0, 0.0, 0.0);
								Result.Objects[ObjectCount].TranslateYDirection = new Vector3D(0.0, 1.0, 0.0);
								Result.Objects[ObjectCount].TranslateZDirection = new Vector3D(0.0, 0.0, 1.0);
								Result.Objects[ObjectCount].RotateXDirection = new Vector3D(1.0, 0.0, 0.0);
								Result.Objects[ObjectCount].RotateYDirection = new Vector3D(0.0, 1.0, 0.0);
								Result.Objects[ObjectCount].RotateZDirection = new Vector3D(0.0, 0.0, 1.0);
								Result.Objects[ObjectCount].TextureShiftXDirection = new Vector2D(1.0, 0.0);
								Result.Objects[ObjectCount].TextureShiftYDirection = new Vector2D(0.0, 1.0);
								Result.Objects[ObjectCount].RefreshRate = 0.0;
								Result.Objects[ObjectCount].ObjectIndex = -1;
								Vector3D Position = new Vector3D(0.0, 0.0, 0.0);
								bool timetableUsed = false;
								string[] StateFiles = null;
								string StateFunctionRpn = null;
								int StateFunctionLine = -1;
								while (i < Lines.Length && !(Lines[i].StartsWith("[", StringComparison.Ordinal) && Lines[i].EndsWith("]", StringComparison.Ordinal))) {
									if (Lines[i].Length != 0) {
										int equals = Lines[i].IndexOf("=", StringComparison.Ordinal);
										if (equals > 0) {
											string before = Lines[i].Substring(0, equals).TrimEnd();
											string after = Lines[i].Substring(equals + 1).TrimStart();
											switch (before.ToLowerInvariant()) {
												case "position":
													ParsePosition(after, ref Position, before, i + 1, FileName);
													break;
												case "states":
													if (!ParseState(after, ref StateFiles, before, i + 1, FileName))
														return null;
													break;
												case "statefunction":
													try {
														StateFunctionLine = i;
														StateFunctionRpn = FunctionScripts.GetPostfixNotationFromInfixNotation(after);
													} catch (Exception ex) {
														Debug.AddMessage(Debug.MessageType.Error, false, ex.Message + " in " + before + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
													} break;
												case "statefunctionrpn":
													{
														StateFunctionLine = i;
														StateFunctionRpn = after;
													} break;
												case "translatexdirection":
													ParseTranslateDirection(after, ref Result.Objects[ObjectCount].TranslateXDirection,
														before, i + 1, FileName);
													break;
												case "translateydirection":
													ParseTranslateDirection(after, ref Result.Objects[ObjectCount].TranslateYDirection,
														before, i + 1, FileName);
													break;
												case "translatezdirection":
													ParseTranslateDirection(after, ref Result.Objects[ObjectCount].TranslateZDirection,
														before, i + 1, FileName);
													break;
												case "translatexfunction":
													ParseInfixFunc(after, ref Result.Objects[ObjectCount].TranslateXFunction, before, i + 1, FileName);
													break;
												case "translateyfunction":
													ParseInfixFunc(after, ref Result.Objects[ObjectCount].TranslateYFunction, before, i + 1, FileName);
													break;
												case "translatezfunction":
													ParseInfixFunc(after, ref Result.Objects[ObjectCount].TranslateZFunction, before, i + 1, FileName);
													break;
												case "translatexfunctionrpn":
													ParsePostfixFunc(after, ref Result.Objects[ObjectCount].TranslateXFunction, before, i + 1, FileName);
													break;
												case "translateyfunctionrpn":
													ParsePostfixFunc(after, ref Result.Objects[ObjectCount].TranslateYFunction, before, i + 1, FileName);
													break;
												case "translatezfunctionrpn":
													ParsePostfixFunc(after, ref Result.Objects[ObjectCount].TranslateZFunction, before, i + 1, FileName);
													break;
												case "rotatexdirection":
													ParseRotateDirection(after, ref Result.Objects[ObjectCount].RotateXDirection, before, i + 1, FileName);
													break;
												case "rotateydirection":
													ParseRotateDirection(after, ref Result.Objects[ObjectCount].RotateYDirection, before, i + 1, FileName);
													break;
												case "rotatezdirection":
													ParseRotateDirection(after, ref Result.Objects[ObjectCount].RotateZDirection, before, i + 1, FileName);
													break;
												case "rotatexfunction":
													ParseInfixFunc(after,ref Result.Objects[ObjectCount].RotateXFunction, before,i+1,FileName);
													break;
												case "rotateyfunction":
													ParseInfixFunc(after,ref Result.Objects[ObjectCount].RotateYFunction, before,i+1,FileName);
													break;
												case "rotatezfunction":
													ParseInfixFunc(after,ref Result.Objects[ObjectCount].RotateZFunction, before,i+1,FileName);
													break;
												case "rotatexfunctionrpn":
													ParsePostfixFunc(after,ref Result.Objects[ObjectCount].RotateXFunction, before,i+1,FileName);
													break;
												case "rotateyfunctionrpn":
													ParsePostfixFunc(after,ref Result.Objects[ObjectCount].RotateYFunction, before,i+1,FileName);
													break;
												case "rotatezfunctionrpn":
													ParsePostfixFunc(after,ref Result.Objects[ObjectCount].RotateZFunction, before,i+1,FileName);
													break;
												case "rotatexdamping":
													ParseRotateDamping(after, ref Result.Objects[ObjectCount].RotateXDamping,before, i + 1, FileName);
													break;
												case "rotateydamping":
													ParseRotateDamping(after, ref Result.Objects[ObjectCount].RotateYDamping,before, i + 1, FileName);
													break;
												case "rotatezdamping":
													ParseRotateDamping(after, ref Result.Objects[ObjectCount].RotateZDamping,before, i + 1, FileName);
													break;
												case "textureshiftxdirection":
													ParseTextureShift(after, ref Result.Objects[ObjectCount].TextureShiftXDirection, before, i + 1, FileName);
													break;
												case "textureshiftydirection":
													ParseTextureShift(after, ref Result.Objects[ObjectCount].TextureShiftYDirection, before, i + 1, FileName);
													break;
												case "textureshiftxfunction":
													ParseInfixFunc(after, ref Result.Objects[ObjectCount].TextureShiftXFunction, before, i + 1, FileName);
													break;
												case "textureshiftyfunction":
													ParseInfixFunc(after, ref Result.Objects[ObjectCount].TextureShiftYFunction, before, i + 1, FileName);
													break;
												case "textureshiftxfunctionrpn":
													ParsePostfixFunc(after, ref Result.Objects[ObjectCount].TextureShiftXFunction, before, i + 1, FileName);
													break;
												case "textureshiftyfunctionrpn":
													ParsePostfixFunc(after, ref Result.Objects[ObjectCount].TextureShiftYFunction, before, i + 1, FileName);
													break;
												case "textureoverride":
													switch (after.ToLowerInvariant()) {
														case "none":
															break;
														case "timetable":
															if (!timetableUsed) {
																Timetable.AddObjectForCustomTimetable(Result.Objects[ObjectCount]);
																timetableUsed = true;
															}
															break;
														default:
															Debug.AddMessage(Debug.MessageType.Error, false, "Unrecognized value in " + before + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
															break;
													}
													break;
												case "refreshrate":
													{
														double r;
														if (!double.TryParse(after, System.Globalization.NumberStyles.Float, Culture, out r)) {
															Debug.AddMessage(Debug.MessageType.Error, false, "Value is invalid in " + before + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
														} else if (r < 0.0) {
															Debug.AddMessage(Debug.MessageType.Error, false, "Value is expected to be non-negative in " + before + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
														} else {
															Result.Objects[ObjectCount].RefreshRate = r;
														}
													} break;
												default:
													Debug.AddMessage(Debug.MessageType.Error, false, "The attribute " + before + " is not supported at line " + (i + 1).ToString(Culture) + " in file " + FileName);
													break;
											}
										} else {
											Debug.AddMessage(Debug.MessageType.Error, false, "Invalid statement " + Lines[i] + " encountered at line " + (i + 1).ToString(Culture) + " in file " + FileName);
											return null;
										}
									}
									i++;
								}
								i--;
								if (StateFiles != null) {
									// create the object
									if (timetableUsed) {
										if (StateFunctionRpn != null) {
											StateFunctionRpn = "timetable 0 == " + StateFunctionRpn + " -1 ?";
										} else {
											StateFunctionRpn = "timetable";
										}
									}
									if (StateFunctionRpn != null) {
										try {
											Result.Objects[ObjectCount].StateFunction = FunctionScripts.GetFunctionScriptFromPostfixNotation(StateFunctionRpn);
										} catch (Exception ex) {
											Debug.AddMessage(Debug.MessageType.Error, false, ex.Message + " in StateFunction at line " + (StateFunctionLine + 1).ToString(Culture) + " in file " + FileName);
										}
									}
									Result.Objects[ObjectCount].States = new ObjectManager.AnimatedObjectState[StateFiles.Length];
									bool ForceTextureRepeatX = Result.Objects[ObjectCount].TextureShiftXFunction != null && Result.Objects[ObjectCount].TextureShiftXDirection.X != 0.0 ||
										Result.Objects[ObjectCount].TextureShiftYFunction != null && Result.Objects[ObjectCount].TextureShiftYDirection.Y != 0.0;
									bool ForceTextureRepeatY = Result.Objects[ObjectCount].TextureShiftXFunction != null && Result.Objects[ObjectCount].TextureShiftXDirection.X != 0.0 ||
										Result.Objects[ObjectCount].TextureShiftYFunction != null && Result.Objects[ObjectCount].TextureShiftYDirection.Y != 0.0;
									for (int k = 0; k < StateFiles.Length; k++) {
										Result.Objects[ObjectCount].States[k].Position = new Vector3D(0.0, 0.0, 0.0);
										if (StateFiles[k] != null) {
											Result.Objects[ObjectCount].States[k].Object = ObjectManager.LoadStaticObject(StateFiles[k], Encoding, LoadMode, false, ForceTextureRepeatX, ForceTextureRepeatY);
											if (Result.Objects[ObjectCount].States[k].Object != null) {
												Result.Objects[ObjectCount].States[k].Object.Dynamic = true;
											}
										} else {
											Result.Objects[ObjectCount].States[k].Object = null;
										}
										for (int j = 0; j < Result.Objects[ObjectCount].States.Length; j++) {
											Result.Objects[ObjectCount].States[j].Position = Position;
										}
									}
								} else {
									Result.Objects[ObjectCount].States = new ObjectManager.AnimatedObjectState[] { };
								}
								ObjectCount++;
							}
							break;
						default:
							Debug.AddMessage(Debug.MessageType.Error, false, "Invalid statement " + Lines[i] + " encountered at line " + (i + 1).ToString(Culture) + " in file " + FileName);
							return null;
					}
				}
			}
			Array.Resize<ObjectManager.AnimatedObject>(ref Result.Objects, ObjectCount);
			return Result;
		}
		private static void ApplyShear(ObjectManager.StaticObject Object, double dx, double dy, double dz, double sx, double sy, double sz, double r) {
			for (int j = 0; j < Object.Mesh.Vertices.Length; j++) {
				double n = r * (dx * Object.Mesh.Vertices[j].Coordinates.X + dy * Object.Mesh.Vertices[j].Coordinates.Y + dz * Object.Mesh.Vertices[j].Coordinates.Z);
				Object.Mesh.Vertices[j].Coordinates.X += sx * n;
				Object.Mesh.Vertices[j].Coordinates.Y += sy * n;
				Object.Mesh.Vertices[j].Coordinates.Z += sz * n;
			}
			double ux, uy, uz;
			World.Cross(sx, sy, sz, dx, dy, dz, out ux, out uy, out uz);
			for (int j = 0; j < Object.Mesh.Faces.Length; j++) {
				for (int k = 0; k < Object.Mesh.Faces[j].Vertices.Length; k++) {
					if (Object.Mesh.Faces[j].Vertices[k].Normal.X != 0.0f | Object.Mesh.Faces[j].Vertices[k].Normal.Y != 0.0f | Object.Mesh.Faces[j].Vertices[k].Normal.Z != 0.0f) {
						double nx = (double)Object.Mesh.Faces[j].Vertices[k].Normal.X;
						double ny = (double)Object.Mesh.Faces[j].Vertices[k].Normal.Y;
						double nz = (double)Object.Mesh.Faces[j].Vertices[k].Normal.Z;
						double n = r * (sx * nx + sy * ny + sz * nz);
						nx -= dx * n;
						ny -= dy * n;
						nz -= dz * n;
						World.Normalize(ref nx, ref ny, ref nz);
						Object.Mesh.Faces[j].Vertices[k].Normal.X = (float)nx;
						Object.Mesh.Faces[j].Vertices[k].Normal.Y = (float)ny;
						Object.Mesh.Faces[j].Vertices[k].Normal.Z = (float)nz;
					}
				}
			}
		}
Beispiel #20
0
        //This renders the frame
        protected override void OnRenderFrame(FrameEventArgs e)
        {
            if (!firstFrame)
            {
                //If the load is not complete, then we shouldn't be running the mainloop
                return;
            }
            double TimeElapsed     = RenderTimeElapsed;
            double RealTimeElapsed = RenderRealTimeElapsed;

            //Next, check if we're in paused/ in a menu
            if (Game.CurrentInterface != Game.InterfaceType.Normal)
            {
                MainLoop.UpdateControlRepeats(0.0);
                MainLoop.ProcessKeyboard();
                MainLoop.ProcessControls(0.0);
                if (Game.CurrentInterface == Game.InterfaceType.Pause)
                {
                    System.Threading.Thread.Sleep(10);
                }
                //Renderer.UpdateLighting();
                Program.Renderer.RenderScene(TimeElapsed);
                Program.currentGameWindow.SwapBuffers();
                if (MainLoop.Quit != MainLoop.QuitMode.ContinueGame)
                {
                    Close();
                    if (Program.CurrentlyRunningOnMono && MainLoop.Quit == MainLoop.QuitMode.QuitProgram)
                    {
                        Environment.Exit(0);
                    }
                }
                //If the menu state has not changed, don't update the rendered simulation
                return;
            }

            //Use the OpenTK framerate as this is much more accurate
            //Also avoids running a calculation
            if (TotalTimeElapsedForInfo >= 0.2)
            {
                Program.Renderer.FrameRate = RenderFrequency;
                TotalTimeElapsedForInfo    = 0.0;
            }


            if (Game.PreviousInterface != Game.InterfaceType.Normal)
            {
                ObjectManager.UpdateAnimatedWorldObjects(0.0, false);
                Game.PreviousInterface = Game.InterfaceType.Normal;
            }
            else
            {
                ObjectManager.UpdateAnimatedWorldObjects(TimeElapsed, false);
            }

            //We need to update the camera position in the render sequence
            //Not doing this means that the camera doesn't move
            // update in one piece
            if (Program.Renderer.Camera.CurrentMode == CameraViewMode.Interior | Program.Renderer.Camera.CurrentMode == CameraViewMode.InteriorLookAhead)
            {
                //Update the in-car camera based upon the current driver car (Cabview or passenger view)
                TrainManager.PlayerTrain.Cars[World.CameraCar].UpdateCamera();
            }
            else if (Program.Renderer.Camera.CurrentMode == CameraViewMode.Exterior)
            {
                //Update the camera position based upon the relative car position
                TrainManager.PlayerTrain.Cars[World.CameraCar].UpdateCamera();
            }
            if (Program.Renderer.Camera.CurrentRestriction == CameraRestrictionMode.NotAvailable)
            {
                TrainManager.PlayerTrain.DriverBody.Update(TimeElapsed);
            }
            //Check if we are running at an accelerated time factor-
            //Camera motion speed should be the same whatever the game speed is
            if (TimeFactor != 1)
            {
                World.UpdateAbsoluteCamera(TimeElapsed / TimeFactor);
            }
            else
            {
                World.UpdateAbsoluteCamera(TimeElapsed);
            }
            TrainManager.UpdateTrainObjects(TimeElapsed, false);
            if (Program.Renderer.Camera.CurrentMode == CameraViewMode.Interior | Program.Renderer.Camera.CurrentMode == CameraViewMode.InteriorLookAhead | Program.Renderer.Camera.CurrentMode == CameraViewMode.Exterior)
            {
                Program.Renderer.UpdateVisibility(World.CameraTrackFollower.TrackPosition + Program.Renderer.Camera.Alignment.Position.Z);
                int d = TrainManager.PlayerTrain.DriverCar;
                Program.Renderer.Camera.CurrentSpeed = TrainManager.PlayerTrain.Cars[d].CurrentSpeed;
            }
            else
            {
                Program.Renderer.Camera.CurrentSpeed = 0.0;
            }

            Program.Renderer.Camera.AlignmentDirection = new CameraAlignment();
            if (MainLoop.Quit != MainLoop.QuitMode.ContinueGame)
            {
                Program.currentGameWindow.Exit();
                if (Program.CurrentlyRunningOnMono && MainLoop.Quit == MainLoop.QuitMode.QuitProgram)
                {
                    Environment.Exit(0);
                }
            }
            Program.Renderer.Lighting.UpdateLighting(Program.CurrentRoute.SecondsSinceMidnight);
            Program.Renderer.RenderScene(TimeElapsed);
            Program.Sounds.Update(TimeElapsed, Interface.CurrentOptions.SoundModel);
            Program.currentGameWindow.SwapBuffers();
            Game.UpdateBlackBox();
            // pause/menu

            // limit framerate
            if (MainLoop.LimitFramerate)
            {
                System.Threading.Thread.Sleep(10);
            }
            MainLoop.UpdateControlRepeats(RealTimeElapsed);
            MainLoop.ProcessKeyboard();
            MainLoop.UpdateMouse(RealTimeElapsed);
            MainLoop.ProcessControls(TimeElapsed);
            for (int i = 0; i < JoystickManager.AttachedJoysticks.Length; i++)
            {
                var railDriver = JoystickManager.AttachedJoysticks[i] as JoystickManager.Raildriver;
                if (railDriver != null)
                {
                    if (Interface.CurrentOptions.RailDriverMPH)
                    {
                        railDriver.SetDisplay((int)(TrainManager.PlayerTrain.Cars[TrainManager.PlayerTrain.DriverCar].Specs
                                                    .CurrentPerceivedSpeed * 2.23694));
                    }
                    else
                    {
                        railDriver.SetDisplay((int)(TrainManager.PlayerTrain.Cars[TrainManager.PlayerTrain.DriverCar].Specs
                                                    .CurrentPerceivedSpeed * 3.6));
                    }
                }
            }
            RenderRealTimeElapsed = 0.0;
            RenderTimeElapsed     = 0.0;



#if DEBUG
            MainLoop.CheckForOpenGlError("MainLoop");
#endif
            if (Interface.CurrentOptions.UnloadUnusedTextures)
            {
                Textures.UnloadUnusedTextures(TimeElapsed);
            }
            // finish
            try
            {
                Interface.SaveLogs();
            }
            catch { }
        }
Beispiel #21
0
		// ================================

		// load textual x
		private static ObjectManager.StaticObject LoadTextualX(string FileName, string Text, System.Text.Encoding Encoding, ObjectManager.ObjectLoadMode LoadMode, bool ForceTextureRepeatX, bool ForceTextureRepeatY) {
			// load
			string[] Lines = Text.Replace("\u000D\u000A", "\u2028").Split(new char[] { '\u000A', '\u000C', '\u000D', '\u0085', '\u2028', '\u2029' }, StringSplitOptions.None);
			// strip away comments
			bool Quote = false;
			for (int i = 0; i < Lines.Length; i++) {
				for (int j = 0; j < Lines[i].Length; j++) {
					if (Lines[i][j] == '"') Quote = !Quote;
					if (!Quote) {
						if (Lines[i][j] == '#' || j < Lines[i].Length - 1 && Lines[i].Substring(j, 2) == "//") {
							Lines[i] = Lines[i].Substring(0, j);
							break;
						}
					}
				}
			}
			// strip away header
			if (Lines.Length == 0 || Lines[0].Length < 16) {
				Interface.AddMessage(Interface.MessageType.Error, false, "The textual X object file is invalid at line 1 in " + FileName);
				return null;
			}
			Lines[0] = Lines[0].Substring(16);
			// join lines
			System.Text.StringBuilder Builder = new System.Text.StringBuilder();
			for (int i = 0; i < Lines.Length; i++) {
				Builder.Append(Lines[i]);
			}
			string Content = Builder.ToString();
			// parse file
			int Position = 0;
			Structure Structure;
			if (!ReadTextualTemplate(FileName, Content, ref Position, new Template("", new string[] { "[...]" }), false, out Structure)) {
				return null;
			}
			// process structure
			ObjectManager.StaticObject Object;
			if (!ProcessStructure(FileName, Structure, out Object, LoadMode, ForceTextureRepeatX, ForceTextureRepeatY)) {
				return null;
			}
			return Object;
		}
Beispiel #22
0
        /// <summary>Attempts to load and parse the current train's panel configuration file.</summary>
        /// <param name="TrainPath">The absolute on-disk path to the train folder.</param>
        /// <param name="Encoding">The automatically detected or manually set encoding of the panel configuration file.</param>
        /// <param name="Train">The base train on which to apply the panel configuration.</param>
        internal static void ParsePanelConfig(string TrainPath, System.Text.Encoding Encoding, Train Train)
        {
            Train.Cars[Train.DriverCar].CarSections    = new CarSection[1];
            Train.Cars[Train.DriverCar].CarSections[0] = new CarSection
            {
                Elements = new ObjectManager.AnimatedObject[] { },
                Overlay  = true
            };
            string File = OpenBveApi.Path.CombineFile(TrainPath, "panel.animated");

            if (System.IO.File.Exists(File))
            {
                Program.AppendToLogFile("Loading train panel: " + File);
                ObjectManager.AnimatedObjectCollection a = AnimatedObjectParser.ReadObject(File, Encoding, ObjectManager.ObjectLoadMode.DontAllowUnloadOfTextures);
                if (a != null)
                {
                    //HACK: If a == null , loading our animated object completely failed (Missing objects?). Fallback to trying the panel2.cfg
                    try
                    {
                        for (int i = 0; i < a.Objects.Length; i++)
                        {
                            a.Objects[i].ObjectIndex = ObjectManager.CreateDynamicObject();
                        }
                        Train.Cars[Train.DriverCar].CarSections[0].Elements = a.Objects;
                        Train.Cars[Train.DriverCar].CameraRestrictionMode   = Camera.RestrictionMode.NotAvailable;
                        World.CameraRestriction = Camera.RestrictionMode.NotAvailable;
                        World.UpdateViewingDistances();
                        return;
                    }
                    catch
                    {
                        var currentError = Interface.GetInterfaceString("errors_critical_file");
                        currentError = currentError.Replace("[file]", "panel.animated");
                        MessageBox.Show(currentError, Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Hand);
                        Program.RestartArguments = " ";
                        Loading.Cancel           = true;
                        return;
                    }
                }
            }

            var Panel2 = false;

            try
            {
                File = OpenBveApi.Path.CombineFile(TrainPath, "panel2.cfg");
                if (System.IO.File.Exists(File))
                {
                    Program.AppendToLogFile("Loading train panel: " + File);
                    Panel2 = true;
                    Panel2CfgParser.ParsePanel2Config("panel2.cfg", TrainPath, Encoding, Train, Train.DriverCar);
                    Train.Cars[Train.DriverCar].CameraRestrictionMode = Camera.RestrictionMode.On;
                    World.CameraRestriction = Camera.RestrictionMode.On;
                }
                else
                {
                    File = OpenBveApi.Path.CombineFile(TrainPath, "panel.cfg");
                    if (System.IO.File.Exists(File))
                    {
                        Program.AppendToLogFile("Loading train panel: " + File);
                        PanelCfgParser.ParsePanelConfig(TrainPath, Encoding, Train);
                        Train.Cars[Train.DriverCar].CameraRestrictionMode = Camera.RestrictionMode.On;
                        World.CameraRestriction = Camera.RestrictionMode.On;
                    }
                    else
                    {
                        World.CameraRestriction = Camera.RestrictionMode.NotAvailable;
                    }
                }
            }
            catch
            {
                var currentError = Interface.GetInterfaceString("errors_critical_file");
                currentError = currentError.Replace("[file]", Panel2 == true ? "panel2.cfg" : "panel.cfg");
                MessageBox.Show(currentError, Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Hand);
                Program.RestartArguments = " ";
                Loading.Cancel           = true;
            }
        }
Beispiel #23
0
		// read object
		internal static ObjectManager.StaticObject ReadObject(string FileName, System.Text.Encoding Encoding, ObjectManager.ObjectLoadMode LoadMode, bool ForceTextureRepeatX, bool ForceTextureRepeatY) {
			byte[] Data = System.IO.File.ReadAllBytes(FileName);
			if (Data.Length < 16 || Data[0] != 120 | Data[1] != 111 | Data[2] != 102 | Data[3] != 32) {
				// not an x object
				Interface.AddMessage(Interface.MessageType.Error, false, "Invalid X object file encountered in " + FileName);
				return null;
			}
			if (Data[4] != 48 | Data[5] != 51 | Data[6] != 48 | Data[7] != 50 & Data[7] != 51) {
				// unrecognized version
				System.Text.ASCIIEncoding Ascii = new System.Text.ASCIIEncoding();
				string s = new string(Ascii.GetChars(Data, 4, 4));
				Interface.AddMessage(Interface.MessageType.Error, false, "Unsupported X object file version " + s + " encountered in " + FileName);
			}
			// floating-point format
			int FloatingPointSize;
			if (Data[12] == 48 & Data[13] == 48 & Data[14] == 51 & Data[15] == 50) {
				FloatingPointSize = 32;
			} else if (Data[12] == 48 & Data[13] == 48 & Data[14] == 54 & Data[15] == 52) {
				FloatingPointSize = 64;
			} else {
				Interface.AddMessage(Interface.MessageType.Error, false, "Unsupported floating point format encountered in X object file " + FileName);
				return null;
			}
			// supported floating point format
			if (Data[8] == 116 & Data[9] == 120 & Data[10] == 116 & Data[11] == 32) {
				// textual flavor
				return LoadTextualX(FileName, System.IO.File.ReadAllText(FileName), Encoding, LoadMode, ForceTextureRepeatX, ForceTextureRepeatY);
			} else if (Data[8] == 98 & Data[9] == 105 & Data[10] == 110 & Data[11] == 32) {
				// binary flavor
				return LoadBinaryX(FileName, Data, 16, Encoding, FloatingPointSize, LoadMode, ForceTextureRepeatX, ForceTextureRepeatY);
			} else if (Data[8] == 116 & Data[9] == 122 & Data[10] == 105 & Data[11] == 112) {
				// compressed textual flavor
				#if !DEBUG
				try {
					#endif
					byte[] Uncompressed = Decompress(Data);
					string Text = Encoding.GetString(Uncompressed);
					return LoadTextualX(FileName, Text, Encoding, LoadMode, ForceTextureRepeatX, ForceTextureRepeatY);
					#if !DEBUG
				} catch (Exception ex) {
					Interface.AddMessage(Interface.MessageType.Error, false, "An unexpected error occured (" + ex.Message + ") while attempting to decompress the binary X object file encountered in " + FileName);
					return null;
				}
				#endif
			} else if (Data[8] == 98 & Data[9] == 122 & Data[10] == 105 & Data[11] == 112) {
				// compressed binary flavor
				#if !DEBUG
				try {
					#endif
					byte[] Uncompressed = Decompress(Data);
					return LoadBinaryX(FileName, Uncompressed, 0, Encoding, FloatingPointSize, LoadMode, ForceTextureRepeatX, ForceTextureRepeatY);
					#if !DEBUG
				} catch (Exception ex) {
					Interface.AddMessage(Interface.MessageType.Error, false, "An unexpected error occured (" + ex.Message + ") while attempting to decompress the binary X object file encountered in " + FileName);
					return null;
				}
				#endif
			} else {
				// unsupported flavor
				Interface.AddMessage(Interface.MessageType.Error, false, "Unsupported X object file encountered in " + FileName);
				return null;
			}
		}
Beispiel #24
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];
            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);
        }
		// parse extensions config
		internal static void ParseExtensionsConfig(string TrainPath, System.Text.Encoding Encoding, out ObjectManager.UnifiedObject[] CarObjects, TrainManager.Train Train) {
			CarObjects = new ObjectManager.UnifiedObject[Train.Cars.Length];
			bool[] CarObjectsReversed = new bool[Train.Cars.Length];
			System.Globalization.CultureInfo Culture = System.Globalization.CultureInfo.InvariantCulture;
			string FileName = Path.CombineFile(TrainPath, "extensions.cfg");
			if (System.IO.File.Exists(FileName)) {
				// load file
				string[] Lines = System.IO.File.ReadAllLines(FileName, Encoding);
				for (int i = 0; i < Lines.Length; i++) {
					int j = Lines[i].IndexOf(';');
					if (j >= 0) {
						Lines[i] = Lines[i].Substring(0, j).Trim();
					} else {
						Lines[i] = Lines[i].Trim();
					}
				}
				for (int i = 0; i < Lines.Length; i++) {
					if (Lines[i].Length != 0) {
						switch (Lines[i].ToLowerInvariant()) {
							case "[exterior]":
								// exterior
								i++;
								while (i < Lines.Length && !Lines[i].StartsWith("[", StringComparison.Ordinal) & !Lines[i].EndsWith("]", StringComparison.Ordinal)) {
									if (Lines[i].Length != 0) {
										int j = Lines[i].IndexOf("=", StringComparison.Ordinal);
										if (j >= 0) {
											string a = Lines[i].Substring(0, j).TrimEnd();
											string b = Lines[i].Substring(j + 1).TrimStart();
											int n;
											if (int.TryParse(a, System.Globalization.NumberStyles.Integer, Culture, out n)) {
												if (n >= 0 & n < Train.Cars.Length) {
													if (Path.ContainsInvalidPathChars(b)) {
														Debug.AddMessage(Debug.MessageType.Error, false, "File contains illegal characters at line " + (i + 1).ToString(Culture) + " in file " + FileName);
													} else {
														string File = Path.CombineFile(TrainPath, b);
														if (System.IO.File.Exists(File)) {
															CarObjects[n] = ObjectManager.LoadObject(File, Encoding, ObjectManager.ObjectLoadMode.Normal, false, false, false);
														} else {
															Debug.AddMessage(Debug.MessageType.Error, true, "The car object " + File + " does not exist at line " + (i + 1).ToString(Culture) + " in file " + FileName);
														}
													}
												} else {
													Debug.AddMessage(Debug.MessageType.Error, false, "The car index " + a + " does not reference an existing car at line " + (i + 1).ToString(Culture) + " in file " + FileName);
												}
											} else {
												Debug.AddMessage(Debug.MessageType.Error, false, "The car index is expected to be an integer at line " + (i + 1).ToString(Culture) + " in file " + FileName);
											}
										} else {
											Debug.AddMessage(Debug.MessageType.Error, false, "Invalid statement " + Lines[i] + " encountered at line " + (i + 1).ToString(Culture) + " in file " + FileName);
										}
									}
									i++;
								}
								i--;
								break;
							default:
								if (Lines[i].StartsWith("[car", StringComparison.OrdinalIgnoreCase) & Lines[i].EndsWith("]", StringComparison.Ordinal)) {
									// car
									string t = Lines[i].Substring(4, Lines[i].Length - 5);
									int n; if (int.TryParse(t, System.Globalization.NumberStyles.Integer, Culture, out n)) {
										if (n >= 0 & n < Train.Cars.Length) {
											bool DefinedLength = false;
											bool DefinedAxles = false;
											i++;
											while (i < Lines.Length && !Lines[i].StartsWith("[", StringComparison.Ordinal) & !Lines[i].EndsWith("]", StringComparison.Ordinal)) {
												if (Lines[i].Length != 0) {
													int j = Lines[i].IndexOf("=", StringComparison.Ordinal);
													if (j >= 0) {
														string a = Lines[i].Substring(0, j).TrimEnd();
														string b = Lines[i].Substring(j + 1).TrimStart();
														switch (a.ToLowerInvariant()) {
															case "object":
																if (Path.ContainsInvalidPathChars(b)) {
																	Debug.AddMessage(Debug.MessageType.Error, false, "File contains illegal characters at line " + (i + 1).ToString(Culture) + " in file " + FileName);
																} else {
																	string File = Path.CombineFile(TrainPath, b);
																	if (System.IO.File.Exists(File)) {
																		CarObjects[n] = ObjectManager.LoadObject(File, Encoding, ObjectManager.ObjectLoadMode.Normal, false, false, false);
																	} else {
																		Debug.AddMessage(Debug.MessageType.Error, true, "The car object " + File + " does not exist at line " + (i + 1).ToString(Culture) + " in file " + FileName);
																	}
																}
																break;
															case "length":
																{
																	double m;
																	if (double.TryParse(b, System.Globalization.NumberStyles.Float, Culture, out m)) {
																		if (m > 0.0) {
																			Train.Cars[n].Length = m;
																			Train.Cars[n].BeaconReceiverPosition = 0.5 * m;
																			DefinedLength = true;
																		} else {
																			Debug.AddMessage(Debug.MessageType.Error, false, "Value is expected to be a positive floating-point number in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
																		}
																	} else {
																		Debug.AddMessage(Debug.MessageType.Error, false, "Value is expected to be a positive floating-point number in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
																	}
																}
																break;
															case "axles":
																{
																	int k = b.IndexOf(',');
																	if (k >= 0) {
																		string c = b.Substring(0, k).TrimEnd();
																		string d = b.Substring(k + 1).TrimStart();
																		double rear, front;
																		if (!double.TryParse(c, System.Globalization.NumberStyles.Float, Culture, out rear)) {
																			Debug.AddMessage(Debug.MessageType.Error, false, "Rear is expected to be a floating-point number in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
																		} else if (!double.TryParse(d, System.Globalization.NumberStyles.Float, Culture, out front)) {
																			Debug.AddMessage(Debug.MessageType.Error, false, "Front is expected to be a floating-point number in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
																		} else if (rear >= front) {
																			Debug.AddMessage(Debug.MessageType.Error, false, "Rear is expected to be less than Front in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
																		} else {
																			Train.Cars[n].RearAxlePosition = rear;
																			Train.Cars[n].FrontAxlePosition = front;
																			DefinedAxles = true;
																		}
																	} else {
																		Debug.AddMessage(Debug.MessageType.Error, false, "An argument-separating comma is expected in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
																	}
																}
																break;
															case "reversed":
																CarObjectsReversed[n] = b.Equals("true", StringComparison.OrdinalIgnoreCase);
																break;
															default:
																Debug.AddMessage(Debug.MessageType.Warning, false, "Unsupported key-value pair " + a + " encountered at line " + (i + 1).ToString(Culture) + " in file " + FileName);
																break;
														}
													} else {
														Debug.AddMessage(Debug.MessageType.Error, false, "Invalid statement " + Lines[i] + " encountered at line " + (i + 1).ToString(Culture) + " in file " + FileName);
													}
												}
												i++;
											}
											i--;
											if (DefinedLength & !DefinedAxles) {
												double AxleDistance = 0.4 * Train.Cars[n].Length;
												Train.Cars[n].RearAxlePosition = -AxleDistance;
												Train.Cars[n].FrontAxlePosition = AxleDistance;
											}
										} else {
											Debug.AddMessage(Debug.MessageType.Error, false, "The car index " + t + " does not reference an existing car at line " + (i + 1).ToString(Culture) + " in file " + FileName);
										}
									} else {
										Debug.AddMessage(Debug.MessageType.Error, false, "The car index is expected to be an integer at line " + (i + 1).ToString(Culture) + " in file " + FileName);
									}
								} else if (Lines[i].StartsWith("[coupler", StringComparison.OrdinalIgnoreCase) & Lines[i].EndsWith("]", StringComparison.Ordinal)) {
									// coupler
									string t = Lines[i].Substring(8, Lines[i].Length - 9);
									int n; if (int.TryParse(t, System.Globalization.NumberStyles.Integer, Culture, out n)) {
										if (n >= 0 & n < Train.Couplers.Length) {
											i++; while (i < Lines.Length && !Lines[i].StartsWith("[", StringComparison.Ordinal) & !Lines[i].EndsWith("]", StringComparison.Ordinal)) {
												if (Lines[i].Length != 0) {
													int j = Lines[i].IndexOf("=", StringComparison.Ordinal);
													if (j >= 0) {
														string a = Lines[i].Substring(0, j).TrimEnd();
														string b = Lines[i].Substring(j + 1).TrimStart();
														switch (a.ToLowerInvariant()) {
															case "distances":
																{
																	int k = b.IndexOf(',');
																	if (k >= 0) {
																		string c = b.Substring(0, k).TrimEnd();
																		string d = b.Substring(k + 1).TrimStart();
																		double min, max;
																		if (!double.TryParse(c, System.Globalization.NumberStyles.Float, Culture, out min)) {
																			Debug.AddMessage(Debug.MessageType.Error, false, "Minimum is expected to be a floating-point number in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
																		} else if (!double.TryParse(d, System.Globalization.NumberStyles.Float, Culture, out max)) {
																			Debug.AddMessage(Debug.MessageType.Error, false, "Maximum is expected to be a floating-point number in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
																		} else if (min > max) {
																			Debug.AddMessage(Debug.MessageType.Error, false, "Minimum is expected to be less than Maximum in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
																		} else {
																			Train.Couplers[n].MinimumDistanceBetweenCars = min;
																			Train.Couplers[n].MaximumDistanceBetweenCars = max;
																		}
																	} else {
																		Debug.AddMessage(Debug.MessageType.Error, false, "An argument-separating comma is expected in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
																	}
																} break;
															default:
																Debug.AddMessage(Debug.MessageType.Warning, false, "Unsupported key-value pair " + a + " encountered at line " + (i + 1).ToString(Culture) + " in file " + FileName);
																break;
														}
													} else {
														Debug.AddMessage(Debug.MessageType.Error, false, "Invalid statement " + Lines[i] + " encountered at line " + (i + 1).ToString(Culture) + " in file " + FileName);
													}
												} i++;
											} i--;
										} else {
											Debug.AddMessage(Debug.MessageType.Error, false, "The coupler index " + t + " does not reference an existing coupler at line " + (i + 1).ToString(Culture) + " in file " + FileName);
										}
									} else {
										Debug.AddMessage(Debug.MessageType.Error, false, "The coupler index is expected to be an integer at line " + (i + 1).ToString(Culture) + " in file " + FileName);
									}
								} else {
									// default
									Debug.AddMessage(Debug.MessageType.Error, false, "Invalid statement " + Lines[i] + " encountered at line " + (i + 1).ToString(Culture) + " in file " + FileName);
								}
								break;
						}
					}
				}
				// check for car objects and reverse if necessary
				int carObjects = 0;
				for (int i = 0; i < Train.Cars.Length; i++) {
					if (CarObjects[i] != null) {
						carObjects++;
						if (CarObjectsReversed[i]) {
							{
								// reverse axle positions
								double temp = Train.Cars[i].FrontAxlePosition;
								Train.Cars[i].FrontAxlePosition = -Train.Cars[i].RearAxlePosition;
								Train.Cars[i].RearAxlePosition = -temp;
							}
							if (CarObjects[i] is ObjectManager.StaticObject) {
								ObjectManager.StaticObject obj = (ObjectManager.StaticObject)CarObjects[i];
								CsvB3dObjectParser.ApplyScale(obj, -1.0, 1.0, -1.0);
							} else if (CarObjects[i] is ObjectManager.AnimatedObjectCollection) {
								ObjectManager.AnimatedObjectCollection obj = (ObjectManager.AnimatedObjectCollection)CarObjects[i];
								for (int j = 0; j < obj.Objects.Length; j++) {
									for (int h = 0; h < obj.Objects[j].States.Length; h++) {
										CsvB3dObjectParser.ApplyScale(obj.Objects[j].States[h].Object, -1.0, 1.0, -1.0);
										obj.Objects[j].States[h].Position.X *= -1.0;
										obj.Objects[j].States[h].Position.Z *= -1.0;
									}
									obj.Objects[j].TranslateXDirection.X *= -1.0;
									obj.Objects[j].TranslateXDirection.Z *= -1.0;
									obj.Objects[j].TranslateYDirection.X *= -1.0;
									obj.Objects[j].TranslateYDirection.Z *= -1.0;
									obj.Objects[j].TranslateZDirection.X *= -1.0;
									obj.Objects[j].TranslateZDirection.Z *= -1.0;
								}
							} else {
								throw new NotImplementedException();
							}
						}
					}
				}
				if (carObjects > 0 & carObjects < Train.Cars.Length) {
					Debug.AddMessage(Debug.MessageType.Warning, false, "An incomplete set of exterior objects was provided in file " + FileName);
				}
			}
		}
Beispiel #26
0
        private static void LoadEverythingThreaded()
        {
            Program.FileSystem.AppendToLogFile("Loading route file: " + CurrentRouteFile);
            Program.FileSystem.AppendToLogFile("INFO: Route file hash " + CsvRwRouteParser.GetChecksum(CurrentRouteFile));
            string RailwayFolder = GetRailwayFolder(CurrentRouteFile);
            string ObjectFolder  = OpenBveApi.Path.CombineDirectory(RailwayFolder, "Object");
            string SoundFolder   = OpenBveApi.Path.CombineDirectory(RailwayFolder, "Sound");

            // reset
            Game.Reset(true);
            Game.MinimalisticSimulation = true;
            // screen
            World.CameraTrackFollower = new TrackManager.TrackFollower {
                Train = null, CarIndex = -1
            };
            Camera.CurrentMode = CameraViewMode.Interior;
            //First, check the format of the route file
            //RW routes were written for BVE1 / 2, and have a different command syntax
            bool IsRW = CsvRwRouteParser.isRWFile(CurrentRouteFile);

            Program.FileSystem.AppendToLogFile("Route file format is: " + (IsRW ? "RW" : "CSV"));
            CsvRwRouteParser.ParseRoute(CurrentRouteFile, IsRW, CurrentRouteEncoding, CurrentTrainFolder, ObjectFolder, SoundFolder, false);
            Thread createIllustrations = new Thread(Game.RouteInformation.LoadInformation)
            {
                IsBackground = true
            };

            createIllustrations.Start();
            System.Threading.Thread.Sleep(1); if (Cancel)
            {
                return;
            }
            Game.CalculateSeaLevelConstants();
            if (CurrentRoute.BogusPretrainInstructions.Length != 0)
            {
                double t = CurrentRoute.BogusPretrainInstructions[0].Time;
                double p = CurrentRoute.BogusPretrainInstructions[0].TrackPosition;
                for (int i = 1; i < CurrentRoute.BogusPretrainInstructions.Length; i++)
                {
                    if (CurrentRoute.BogusPretrainInstructions[i].Time > t)
                    {
                        t = CurrentRoute.BogusPretrainInstructions[i].Time;
                    }
                    else
                    {
                        t += 1.0;
                        CurrentRoute.BogusPretrainInstructions[i].Time = t;
                    }
                    if (CurrentRoute.BogusPretrainInstructions[i].TrackPosition > p)
                    {
                        p = CurrentRoute.BogusPretrainInstructions[i].TrackPosition;
                    }
                    else
                    {
                        p += 1.0;
                        CurrentRoute.BogusPretrainInstructions[i].TrackPosition = p;
                    }
                }
            }

            if (Game.Stations.Length == 1)
            {
                //Log the fact that only a single station is present, as this is probably not right
                Program.FileSystem.AppendToLogFile("The processed route file only contains a single station.");
            }
            Program.FileSystem.AppendToLogFile("Route file loaded successfully.");
            RouteProgress = 1.0;
            // initialize trains
            System.Threading.Thread.Sleep(1); if (Cancel)
            {
                return;
            }
            TrainManager.Trains = new TrainManager.Train[Game.PrecedingTrainTimeDeltas.Length + 1 + (CurrentRoute.BogusPretrainInstructions.Length != 0 ? 1 : 0)];
            for (int k = 0; k < TrainManager.Trains.Length; k++)
            {
                if (k == TrainManager.Trains.Length - 1 & CurrentRoute.BogusPretrainInstructions.Length != 0)
                {
                    TrainManager.Trains[k] = new TrainManager.Train(TrainState.Bogus);
                }
                else
                {
                    TrainManager.Trains[k] = new TrainManager.Train(TrainState.Pending);
                }
            }
            TrainManager.PlayerTrain = TrainManager.Trains[Game.PrecedingTrainTimeDeltas.Length];

            UnifiedObject[] CarObjects   = null;
            UnifiedObject[] BogieObjects = null;

            // load trains
            double TrainProgressMaximum = 0.7 + 0.3 * (double)TrainManager.Trains.Length;

            for (int k = 0; k < TrainManager.Trains.Length; k++)
            {
                //Sleep for 20ms to allow route loading locks to release
                Thread.Sleep(20);
                if (TrainManager.Trains[k].State == TrainState.Bogus)
                {
                    // bogus train
                    string TrainData = OpenBveApi.Path.CombineFile(Program.FileSystem.GetDataFolder("Compatibility", "PreTrain"), "train.dat");
                    TrainDatParser.ParseTrainData(TrainData, System.Text.Encoding.UTF8, TrainManager.Trains[k]);
                    System.Threading.Thread.Sleep(1); if (Cancel)
                    {
                        return;
                    }
                    TrainManager.Trains[k].InitializeCarSounds();
                    System.Threading.Thread.Sleep(1); if (Cancel)
                    {
                        return;
                    }
                    TrainProgressCurrentWeight = 0.3 / TrainProgressMaximum;
                    TrainProgressCurrentSum   += TrainProgressCurrentWeight;
                }
                else
                {
                    TrainManager.Trains[k].TrainFolder = CurrentTrainFolder;
                    // real train
                    if (TrainManager.Trains[k] == TrainManager.PlayerTrain)
                    {
                        Program.FileSystem.AppendToLogFile("Loading player train: " + TrainManager.Trains[k].TrainFolder);
                    }
                    else
                    {
                        Program.FileSystem.AppendToLogFile("Loading AI train: " + TrainManager.Trains[k].TrainFolder);
                    }
                    TrainProgressCurrentWeight = 0.1 / TrainProgressMaximum;
                    string TrainData = OpenBveApi.Path.CombineFile(TrainManager.Trains[k].TrainFolder, "train.dat");
                    TrainDatParser.ParseTrainData(TrainData, CurrentTrainEncoding, TrainManager.Trains[k]);
                    TrainProgressCurrentSum += TrainProgressCurrentWeight;
                    System.Threading.Thread.Sleep(1); if (Cancel)
                    {
                        return;
                    }
                    TrainProgressCurrentWeight = 0.2 / TrainProgressMaximum;
                    SoundCfgParser.ParseSoundConfig(TrainManager.Trains[k].TrainFolder, CurrentTrainEncoding, TrainManager.Trains[k]);
                    TrainProgressCurrentSum += TrainProgressCurrentWeight;
                    System.Threading.Thread.Sleep(1); if (Cancel)
                    {
                        return;
                    }
                    // door open/close speed
                    for (int i = 0; i < TrainManager.Trains[k].Cars.Length; i++)
                    {
                        if (TrainManager.Trains[k].Cars[i].Specs.DoorOpenFrequency <= 0.0)
                        {
                            if (TrainManager.Trains[k].Cars[i].Doors[0].OpenSound.Buffer != null & TrainManager.Trains[k].Cars[i].Doors[1].OpenSound.Buffer != null)
                            {
                                Sounds.LoadBuffer(TrainManager.Trains[k].Cars[i].Doors[0].OpenSound.Buffer);
                                Sounds.LoadBuffer(TrainManager.Trains[k].Cars[i].Doors[1].OpenSound.Buffer);
                                double a = TrainManager.Trains[k].Cars[i].Doors[0].OpenSound.Buffer.Duration;
                                double b = TrainManager.Trains[k].Cars[i].Doors[1].OpenSound.Buffer.Duration;
                                TrainManager.Trains[k].Cars[i].Specs.DoorOpenFrequency = a + b > 0.0 ? 2.0 / (a + b) : 0.8;
                            }
                            else if (TrainManager.Trains[k].Cars[i].Doors[0].OpenSound.Buffer != null)
                            {
                                Sounds.LoadBuffer(TrainManager.Trains[k].Cars[i].Doors[0].OpenSound.Buffer);
                                double a = TrainManager.Trains[k].Cars[i].Doors[0].OpenSound.Buffer.Duration;
                                TrainManager.Trains[k].Cars[i].Specs.DoorOpenFrequency = a > 0.0 ? 1.0 / a : 0.8;
                            }
                            else if (TrainManager.Trains[k].Cars[i].Doors[1].OpenSound.Buffer != null)
                            {
                                Sounds.LoadBuffer(TrainManager.Trains[k].Cars[i].Doors[0].OpenSound.Buffer);
                                double b = TrainManager.Trains[k].Cars[i].Doors[1].OpenSound.Buffer.Duration;
                                TrainManager.Trains[k].Cars[i].Specs.DoorOpenFrequency = b > 0.0 ? 1.0 / b : 0.8;
                            }
                            else
                            {
                                TrainManager.Trains[k].Cars[i].Specs.DoorOpenFrequency = 0.8;
                            }
                        }
                        if (TrainManager.Trains[k].Cars[i].Specs.DoorCloseFrequency <= 0.0)
                        {
                            if (TrainManager.Trains[k].Cars[i].Doors[0].CloseSound.Buffer != null & TrainManager.Trains[k].Cars[i].Doors[1].CloseSound.Buffer != null)
                            {
                                Sounds.LoadBuffer(TrainManager.Trains[k].Cars[i].Doors[0].CloseSound.Buffer);
                                Sounds.LoadBuffer(TrainManager.Trains[k].Cars[i].Doors[1].CloseSound.Buffer);
                                double a = TrainManager.Trains[k].Cars[i].Doors[0].CloseSound.Buffer.Duration;
                                double b = TrainManager.Trains[k].Cars[i].Doors[1].CloseSound.Buffer.Duration;
                                TrainManager.Trains[k].Cars[i].Specs.DoorCloseFrequency = a + b > 0.0 ? 2.0 / (a + b) : 0.8;
                            }
                            else if (TrainManager.Trains[k].Cars[i].Doors[0].CloseSound.Buffer != null)
                            {
                                Sounds.LoadBuffer(TrainManager.Trains[k].Cars[i].Doors[0].CloseSound.Buffer);
                                double a = TrainManager.Trains[k].Cars[i].Doors[0].CloseSound.Buffer.Duration;
                                TrainManager.Trains[k].Cars[i].Specs.DoorCloseFrequency = a > 0.0 ? 1.0 / a : 0.8;
                            }
                            else if (TrainManager.Trains[k].Cars[i].Doors[1].CloseSound.Buffer != null)
                            {
                                Sounds.LoadBuffer(TrainManager.Trains[k].Cars[i].Doors[0].CloseSound.Buffer);
                                double b = TrainManager.Trains[k].Cars[i].Doors[1].CloseSound.Buffer.Duration;
                                TrainManager.Trains[k].Cars[i].Specs.DoorCloseFrequency = b > 0.0 ? 1.0 / b : 0.8;
                            }
                            else
                            {
                                TrainManager.Trains[k].Cars[i].Specs.DoorCloseFrequency = 0.8;
                            }
                        }
                        const double f = 0.015;
                        const double g = 2.75;
                        TrainManager.Trains[k].Cars[i].Specs.DoorOpenPitch       = Math.Exp(f * Math.Tan(g * (Program.RandomNumberGenerator.NextDouble() - 0.5)));
                        TrainManager.Trains[k].Cars[i].Specs.DoorClosePitch      = Math.Exp(f * Math.Tan(g * (Program.RandomNumberGenerator.NextDouble() - 0.5)));
                        TrainManager.Trains[k].Cars[i].Specs.DoorOpenFrequency  /= TrainManager.Trains[k].Cars[i].Specs.DoorOpenPitch;
                        TrainManager.Trains[k].Cars[i].Specs.DoorCloseFrequency /= TrainManager.Trains[k].Cars[i].Specs.DoorClosePitch;

                        /*
                         * Remove the following two lines, then the pitch at which doors play
                         * takes their randomized opening and closing times into account.
                         * */
                        TrainManager.Trains[k].Cars[i].Specs.DoorOpenPitch  = 1.0;
                        TrainManager.Trains[k].Cars[i].Specs.DoorClosePitch = 1.0;
                    }
                }
                // add panel section
                if (TrainManager.Trains[k] == TrainManager.PlayerTrain)
                {
                    TrainProgressCurrentWeight = 0.7 / TrainProgressMaximum;
                    TrainManager.ParsePanelConfig(TrainManager.Trains[k].TrainFolder, CurrentTrainEncoding, TrainManager.Trains[k]);
                    TrainProgressCurrentSum += TrainProgressCurrentWeight;
                    System.Threading.Thread.Sleep(1); if (Cancel)
                    {
                        return;
                    }
                    Program.FileSystem.AppendToLogFile("Train panel loaded sucessfully.");
                }
                // add exterior section
                if (TrainManager.Trains[k].State != TrainState.Bogus)
                {
                    bool LoadObjects = false;
                    if (CarObjects == null)
                    {
                        CarObjects   = new UnifiedObject[TrainManager.Trains[k].Cars.Length];
                        BogieObjects = new UnifiedObject[TrainManager.Trains[k].Cars.Length * 2];
                        LoadObjects  = true;
                    }
                    string tXml = OpenBveApi.Path.CombineFile(TrainManager.Trains[k].TrainFolder, "train.xml");
                    if (System.IO.File.Exists(tXml))
                    {
                        TrainXmlParser.Parse(tXml, TrainManager.Trains[k], ref CarObjects, ref BogieObjects);
                    }
                    else
                    {
                        ExtensionsCfgParser.ParseExtensionsConfig(TrainManager.Trains[k].TrainFolder, CurrentTrainEncoding, ref CarObjects, ref BogieObjects, TrainManager.Trains[k], LoadObjects);
                    }
                    World.CameraCar = TrainManager.Trains[k].DriverCar;
                    System.Threading.Thread.Sleep(1); if (Cancel)
                    {
                        return;
                    }
                    //Stores the current array index of the bogie object to add
                    //Required as there are two bogies per car, and we're using a simple linear array....
                    int currentBogieObject = 0;
                    for (int i = 0; i < TrainManager.Trains[k].Cars.Length; i++)
                    {
                        if (CarObjects[i] == null)
                        {
                            // load default exterior object
                            string       file = OpenBveApi.Path.CombineFile(Program.FileSystem.GetDataFolder("Compatibility"), "exterior.csv");
                            StaticObject so   = ObjectManager.LoadStaticObject(file, System.Text.Encoding.UTF8, false);
                            if (so == null)
                            {
                                CarObjects[i] = null;
                            }
                            else
                            {
                                double sx = TrainManager.Trains[k].Cars[i].Width;
                                double sy = TrainManager.Trains[k].Cars[i].Height;
                                double sz = TrainManager.Trains[k].Cars[i].Length;
                                so.ApplyScale(sx, sy, sz);
                                CarObjects[i] = so;
                            }
                        }
                        if (CarObjects[i] != null)
                        {
                            // add object
                            TrainManager.Trains[k].Cars[i].LoadCarSections(CarObjects[i]);
                        }

                        //Load bogie objects
                        if (BogieObjects[currentBogieObject] != null)
                        {
                            TrainManager.Trains[k].Cars[i].FrontBogie.LoadCarSections(BogieObjects[currentBogieObject]);
                        }
                        currentBogieObject++;
                        if (BogieObjects[currentBogieObject] != null)
                        {
                            TrainManager.Trains[k].Cars[i].RearBogie.LoadCarSections(BogieObjects[currentBogieObject]);
                        }
                        currentBogieObject++;
                    }
                }
                // place cars
                TrainManager.Trains[k].PlaceCars(0.0);

                // configure ai / timetable
                if (TrainManager.Trains[k] == TrainManager.PlayerTrain)
                {
                    TrainManager.Trains[k].TimetableDelta = 0.0;
                }
                else if (TrainManager.Trains[k].State != TrainState.Bogus)
                {
                    TrainManager.Trains[k].AI                  = new Game.SimpleHumanDriverAI(TrainManager.Trains[k]);
                    TrainManager.Trains[k].TimetableDelta      = Game.PrecedingTrainTimeDeltas[k];
                    TrainManager.Trains[k].Specs.DoorOpenMode  = TrainManager.DoorMode.Manual;
                    TrainManager.Trains[k].Specs.DoorCloseMode = TrainManager.DoorMode.Manual;
                }
            }
            TrainProgress = 1.0;
            // finished created objects
            System.Threading.Thread.Sleep(1); if (Cancel)
            {
                return;
            }
            Array.Resize(ref ObjectManager.Objects, ObjectManager.ObjectsUsed);
            Array.Resize(ref ObjectManager.AnimatedWorldObjects, ObjectManager.AnimatedWorldObjectsUsed);
            // update sections
            if (CurrentRoute.Sections.Length > 0)
            {
                Game.UpdateSection(CurrentRoute.Sections.Length - 1);
            }
            // load plugin
            for (int i = 0; i < TrainManager.Trains.Length; i++)
            {
                if (TrainManager.Trains[i].State != TrainState.Bogus)
                {
                    if (TrainManager.Trains[i] == TrainManager.PlayerTrain)
                    {
                        if (!PluginManager.LoadCustomPlugin(TrainManager.Trains[i], TrainManager.Trains[i].TrainFolder, CurrentTrainEncoding))
                        {
                            PluginManager.LoadDefaultPlugin(TrainManager.Trains[i], TrainManager.Trains[i].TrainFolder);
                        }
                    }
                    else
                    {
                        PluginManager.LoadDefaultPlugin(TrainManager.Trains[i], TrainManager.Trains[i].TrainFolder);
                    }
                }
            }
        }
Beispiel #27
0
 private static ObjectManager.StaticObject GetMirroredStaticObject(ObjectManager.StaticObject Prototype)
 {
     ObjectManager.StaticObject Result = ObjectManager.CloneObject(Prototype);
     for (int i = 0; i < Result.Mesh.Vertices.Length; i++) {
         Result.Mesh.Vertices[i].Coordinates.X = -Result.Mesh.Vertices[i].Coordinates.X;
     }
     for (int i = 0; i < Result.Mesh.Faces.Length; i++) {
         for (int k = 0; k < Result.Mesh.Faces[i].Vertices.Length; k++) {
             Result.Mesh.Faces[i].Vertices[k].Normal.X = -Result.Mesh.Faces[i].Vertices[k].Normal.X;
         }
         Result.Mesh.Faces[i].Flip();
     }
     return Result;
 }
Beispiel #28
0
        //The XML Parser Class will allow loading of an object with more advanced
        //properties than are currently available with the CSV and B3D formats, whilst
        //not requiring backwards incompatible changes

        public static ObjectManager.UnifiedObject ReadObject(string fileName, Encoding encoding,ObjectManager.ObjectLoadMode LoadMode,bool ForceTextureRepeatX,bool ForceTextureRepeatY)
        {
            //The current XML file to load
            XmlDocument currentXML = new XmlDocument();
            ObjectManager.StaticObject Object = null;
            //Load the object's XML file 
            currentXML.Load(fileName);
            //Check for null
            if (currentXML.DocumentElement != null)
            {
                XmlNodeList DocumentNodes = currentXML.DocumentElement.SelectNodes("/openbve/object");
                //Check this file actually contains OpenBVE object nodes
                if (DocumentNodes != null)
                    foreach (XmlNode node in DocumentNodes)
                    {
                        string objectPath;
                        try
                        {
                            var fn = System.IO.Path.GetDirectoryName(fileName);
                            var InnerNode = node.SelectSingleNode("filename").InnerText;
                            InnerNode = InnerNode.Trim();
                            objectPath = OpenBveApi.Path.CombineFile(fn, InnerNode);
                        }
                        catch (Exception)
                        {
                            Interface.AddMessage(Interface.MessageType.Error, false,
                                "The XML does not contain a valid object path: " + fileName);
                            return null;
                        }
                        if (objectPath != null && System.IO.File.Exists(objectPath))
                        {
                            switch (System.IO.Path.GetExtension(objectPath).ToLowerInvariant())
                            {
                                case ".csv":
                                case ".b3d":
                                    Object = CsvB3dObjectParser.ReadObject(objectPath, encoding, LoadMode,
                                        ForceTextureRepeatX, ForceTextureRepeatY);
                                    break;
                                case ".x":
                                    Object = XObjectParser.ReadObject(objectPath, encoding, LoadMode, ForceTextureRepeatX,
                                        ForceTextureRepeatY);
                                    break;
                                case ".animated":
                                    //Not currently working.
                                    //Object = AnimatedObjectParser.ReadObject(objectPath, encoding, LoadMode);
                                    break;                                  
                            }
                            try
                            {
                                var BoundingBoxUpper = node.SelectSingleNode("boundingboxupper").InnerText;
                                var BoundingBoxLower = node.SelectSingleNode("boundingboxlower").InnerText;
                                Object.Mesh.BoundingBox = new Vector3[2];
                                var splitStrings = BoundingBoxUpper.Split(',');
                                if (splitStrings.Length != 3)
                                {
                                    //Throw exception, as this isn't a valid 3D point
                                    throw new Exception();
                                }
                                Object.Mesh.BoundingBox[0].X = Double.Parse(splitStrings[0]);
                                Object.Mesh.BoundingBox[0].Y = Double.Parse(splitStrings[1]);
                                Object.Mesh.BoundingBox[0].Z = Double.Parse(splitStrings[2]);
                                splitStrings = BoundingBoxLower.Split(',');
                                if (splitStrings.Length != 3)
                                {
                                    //Throw exception, as this isn't a valid 3D point
                                    throw new Exception();
                                }
                                Object.Mesh.BoundingBox[1].X = Double.Parse(splitStrings[0]);
                                Object.Mesh.BoundingBox[1].Y = Double.Parse(splitStrings[1]);
                                Object.Mesh.BoundingBox[1].Y = Double.Parse(splitStrings[2]);
                            }
                            catch (Exception)
                            {
                                Interface.AddMessage(Interface.MessageType.Error, false,
                                "The XML contained an invalid bounding box entry: " + fileName);
                            }
                            var selectSingleNode = node.SelectSingleNode("author");
                            if (selectSingleNode != null)
                            {
                                //Attempt to load author information from XML
								Object.Author = selectSingleNode.InnerText.Trim();
                            }
                            selectSingleNode = node.SelectSingleNode("copyright");
                            if (selectSingleNode != null)
                            {
                                //Attempt to load copyright information from XML
                                Object.Copyright = selectSingleNode.InnerText.Trim();
                            }
                            return Object;
                        }
                        Interface.AddMessage(Interface.MessageType.Error, false,
                                        "The file extension is not supported: " + objectPath);
                        return null;

                    }
            }
            //We couldn't find any valid XML, so return a null object
            return null;
        }
Beispiel #29
0
 internal CompatibilitySignalData(int[] Numbers, ObjectManager.StaticObject[] Objects)
 {
     this.Numbers = Numbers;
     this.Objects = Objects;
 }
Beispiel #30
0
        /// <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
                    ObjectManager.StaticObject staticObject = null;
                    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, CurrentObjects[i].Rotation);
                            }
                            else if (CurrentObjects[i].Name.ToLowerInvariant().EndsWith(".l3dobj"))
                            {
                                Object = (ObjectManager.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();
                                ObjectManager.AnimatedObjectState aos = new ObjectManager.AnimatedObjectState(Object, CurrentObjects[i].Position);
                                a.States           = new ObjectManager.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 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(staticObject, Vector3.Zero);
                        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);
        }
Beispiel #31
0
        // read object
        /// <summary>Loads a Loksim3D object from a file.</summary>
        /// <param name="FileName">The text file to load the animated object from. Must be an absolute file name.</param>
        /// <param name="Encoding">The encoding the file is saved in. If the file uses a byte order mark, the encoding indicated by the byte order mark is used and the Encoding parameter is ignored.</param>
        /// <param name="LoadMode">The texture load mode.</param>
        /// <param name="ForceTextureRepeatX">Whether to force TextureWrapMode.Repeat for the X-axis</param>
        /// /// <param name="ForceTextureRepeatY">Whether to force TextureWrapMode.Repeat for the Y-axis</param>
        /// <returns>The object loaded.</returns>
        internal static ObjectManager.StaticObject ReadObject(string FileName, System.Text.Encoding Encoding,ObjectManager.ObjectLoadMode LoadMode, bool ForceTextureRepeatX, bool ForceTextureRepeatY, double RotationX, double RotationY, double RotationZ)
        {
            XmlDocument currentXML = new XmlDocument();
            //May need to be changed to use de-DE
            System.Globalization.CultureInfo Culture = System.Globalization.CultureInfo.InvariantCulture;
            //Initialise the object
            ObjectManager.StaticObject Object = new ObjectManager.StaticObject();
			Object.Mesh.Faces = new World.MeshFace[] { };
			Object.Mesh.Materials = new World.MeshMaterial[] { };
			Object.Mesh.Vertices = new World.Vertex[] { };
            MeshBuilder Builder = new MeshBuilder();
			World.Vector3Df[] Normals = new World.Vector3Df[4];
            bool PropertiesFound = false;

            World.Vertex[] tempVertices = new World.Vertex[0];
            World.Vector3Df[] tempNormals = new World.Vector3Df[0];
            World.ColorRGB transparentColor = new World.ColorRGB();
            string tday = null;
            string tnight = null;
            bool TransparencyUsed = false;
            bool Face2 = false;
            int TextureWidth = 0;
            int TextureHeight = 0;
            if (File.Exists(FileName))
            {
                currentXML.Load(FileName);
            }
            else
            {
                return null;
            }
            //Check for null
            if (currentXML.DocumentElement != null)
            {
                XmlNodeList DocumentNodes = currentXML.DocumentElement.SelectNodes("/OBJECT");
                //Check this file actually contains Loksim3D object nodes
                if (DocumentNodes != null)
                {
                    foreach (XmlNode outerNode in DocumentNodes)
                    {
                        if (outerNode.HasChildNodes)
                        {
                            foreach (XmlNode node in outerNode.ChildNodes)
                            {
                                //I think there should only be one properties node??
                                //Need better format documentation
                                if (node.Name == "Props" && PropertiesFound == false)
                                {
                                    if (node.Attributes != null)
                                    {
                                        //Our node has child nodes, therefore this properties node should be valid
                                        //Needs better validation
                                        PropertiesFound = true;
                                        foreach (XmlAttribute attribute in node.Attributes)
                                        {
                                            switch (attribute.Name)
                                            {
                                                //Sets the texture
                                                //Loksim3D objects only support daytime textures
                                                case "Texture":
                                                    tday = OpenBveApi.Path.CombineFile(System.IO.Path.GetDirectoryName(FileName), attribute.Value);
                                                    if (File.Exists(tday))
                                                    {
                                                        try
                                                        {
                                                            using (Bitmap TextureInformation = new Bitmap(tday))
                                                            {
                                                                TextureWidth = TextureInformation.Width;
                                                                TextureHeight = TextureInformation.Height;
                                                                Color color = TextureInformation.GetPixel(1, 1);
                                                                transparentColor = new World.ColorRGB((byte) color.R, (byte) color.G, (byte) color.B);
                                                            }
                                                        }
                                                        catch
                                                        {
                                                            Interface.AddMessage(Interface.MessageType.Error, true, "An error occured loading daytime texture " + tday + " in file " + FileName);
                                                            tday = null;
                                                        }
                                                    }
                                                    else
                                                    {
                                                        Interface.AddMessage(Interface.MessageType.Error, true, "DaytimeTexture " + tday + " could not be found in file " + FileName);
                                                    }
                                                    break;
                                                //Defines whether the texture uses transparency
                                                //May be omitted
                                                case "Transparent":
                                                    if (attribute.Value == "TRUE")
                                                    {
                                                        TransparencyUsed = true;
                                                    }
                                                    else
                                                    {
                                                        TransparencyUsed = false;
                                                    }
                                                    break;
                                                //Sets the transparency type
                                                case "TransparentTyp":
                                                    switch (attribute.Value)
                                                    {
                                                        case "0":
                                                            //Transparency is disabled
                                                            TransparencyUsed = false;
                                                            break;
                                                        case "1":
                                                            //Transparency is solid black
                                                            TransparencyUsed = true;
                                                            transparentColor = new World.ColorRGB(0,0,0);
                                                            break;
                                                        case "2":
                                                            //Transparency is the color at Pixel 1,1
                                                            TransparencyUsed = true;
                                                            break;
                                                        case "3":
                                                            //This is used when transparency is used with an alpha bitmap
                                                            //Not currently supported
                                                            TransparencyUsed = false;
                                                            break;
                                                    }
                                                    break;
                                                //Sets whether the rears of the faces are to be drawn
                                                case "Drawrueckseiten":
                                                    Face2 = true;
                                                    break;

                                                /*
                                         * MISSING PROPERTIES:
                                         * AutoRotate - Rotate with tracks?? LS3D presumably uses a 3D world system.
                                         * Beleuchtet- Translates as illuminated. Presume something to do with lighting? - What emissive color?
                                         * FileAuthor
                                         * FileInfo
                                         * FilePicture
                                         */
                                            }
                                        }
                                    }
                                }
                                //The point command is eqivilant to a vertex
                                else if (node.Name == "Point" && node.HasChildNodes)
                                {
                                    foreach (XmlNode childNode in node.ChildNodes)
                                    {
                                        if (childNode.Name == "Props" && childNode.Attributes != null)
                                        {
                                            //Vertex
                                            double vx = 0.0, vy = 0.0, vz = 0.0;
                                            //Normals
                                            double nx = 0.0, ny = 0.0, nz = 0.0;
                                            foreach (XmlAttribute attribute in childNode.Attributes)
                                            {
                                                switch (attribute.Name)
                                                {
                                                    //Sets the vertex normals
                                                    case "Normal":
                                                        string[] NormalPoints = attribute.Value.Split(';');
                                                        double.TryParse(NormalPoints[0], out nx);
                                                        double.TryParse(NormalPoints[1], out ny);
                                                        double.TryParse(NormalPoints[2], out nz);
                                                        break;
                                                    //Sets the vertex 3D co-ordinates
                                                    case "Vekt":
                                                        string[] VertexPoints = attribute.Value.Split(';');
                                                        double.TryParse(VertexPoints[0], out vx);
                                                        double.TryParse(VertexPoints[1], out vy);
                                                        double.TryParse(VertexPoints[2], out vz);
                                                        break;
                                                }
                                            }
                                            World.Normalize(ref nx, ref ny, ref nz);

                                            {
                                                //Resize temp arrays
                                                Array.Resize<World.Vertex>(ref tempVertices, tempVertices.Length + 1);
                                                Array.Resize<World.Vector3Df>(ref tempNormals, tempNormals.Length + 1);
                                                //Add vertex and normals to temp array
                                                tempVertices[tempVertices.Length - 1].Coordinates = new World.Vector3D(vx, vy, vz);
                                                tempNormals[tempNormals.Length - 1] = new World.Vector3Df((float)nx, (float)ny, (float)nz);
                                            }

                                            Array.Resize<World.Vertex>(ref Builder.Vertices, Builder.Vertices.Length + 1);
                                            while (Builder.Vertices.Length >= Normals.Length)
                                            {
                                                Array.Resize<World.Vector3Df>(ref Normals, Normals.Length << 1);
                                            }
                                            Builder.Vertices[Builder.Vertices.Length - 1].Coordinates = new World.Vector3D(vx, vy, vz);
                                            Normals[Builder.Vertices.Length - 1] = new World.Vector3Df((float) nx, (float) ny, (float) nz);
                                        }
                                    }
                                }
                                //The Flaeche command creates a face
                                else if (node.Name == "Flaeche" && node.HasChildNodes)
                                {
                                    foreach (XmlNode childNode in node.ChildNodes)
                                    {
                                        if (childNode.Name == "Props" && childNode.Attributes != null)
                                        {
                                            //Defines the verticies in this face
                                            //**NOTE**: A vertex may appear in multiple faces with different texture co-ordinates
                                            if (childNode.Attributes["Points"] != null)
                                            {
                                                string[] Verticies = childNode.Attributes["Points"].Value.Split(';');
                                                int f = Builder.Faces.Length;
                                                //Add 1 to the length of the face array
                                                Array.Resize<World.MeshFace>(ref Builder.Faces, f + 1);
                                                Builder.Faces[f] = new World.MeshFace();
                                                //Create the vertex array for the face
                                                Builder.Faces[f].Vertices = new World.MeshFaceVertex[Verticies.Length];
                                                while (Builder.Vertices.Length > Normals.Length)
                                                {
                                                    Array.Resize<World.Vector3Df>(ref Normals,
                                                        Normals.Length << 1);
                                                }
                                                //Run through the vertices list and grab from the temp array
                                                for (int j = 0; j < Verticies.Length; j++)
                                                {
                                                    //This is the position of the vertex in the temp array
                                                    int currentVertex;
                                                    int.TryParse(Verticies[j], out currentVertex);
                                                    //Add one to the actual vertex array
                                                    Array.Resize<World.Vertex>(ref Builder.Vertices, Builder.Vertices.Length + 1);
                                                    //Set coordinates
                                                    Builder.Vertices[Builder.Vertices.Length - 1].Coordinates = tempVertices[currentVertex].Coordinates;
                                                    //Set the vertex index
                                                    Builder.Faces[f].Vertices[j].Index = (ushort)(Builder.Vertices.Length - 1);
                                                    //Set the normals
                                                    Builder.Faces[f].Vertices[j].Normal = tempNormals[currentVertex];
                                                    //Now deal with the texture
                                                    //Texture mapping points are in pixels X,Y and are relative to the face in question rather than the vertex
                                                    if (childNode.Attributes["Texture"] != null)
                                                    {
                                                        string[] TextureCoords = childNode.Attributes["Texture"].Value.Split(';');
                                                        World.Vector2Df currentCoords;
                                                        float OpenBVEWidth;
                                                        float OpenBVEHeight;
                                                        string[] splitCoords = TextureCoords[j].Split(',');
                                                        float.TryParse(splitCoords[0], out OpenBVEWidth);
                                                        float.TryParse(splitCoords[1], out OpenBVEHeight);
                                                        if (TextureWidth != 0 && TextureHeight != 0)
                                                        {
                                                            currentCoords.X = (OpenBVEWidth / TextureWidth);
                                                            currentCoords.Y = (OpenBVEHeight / TextureHeight);
                                                        }
                                                        else
                                                        {
                                                            currentCoords.X = 0;
                                                            currentCoords.Y = 0;
                                                        }
                                                        Builder.Vertices[Builder.Vertices.Length - 1].TextureCoordinates = currentCoords;
                                                    }
                                                    if (Face2)
                                                    {
                                                        Builder.Faces[f].Flags = (byte) World.MeshFace.Face2Mask;
                                                    }
                                                }
                                            }

                                        }
                                    }
                                }

                            }
                        }
                    }
                }
                
                //Apply rotation
                /*
                 * NOTES:
                 * No rotation order is specified
                 * The rotation string in a .l3dgrp file is ordered Y, X, Z    ??? Can't find a good reason for this ???
                 * Rotations must still be performed in X,Y,Z order to produce correct results
                 */

                if (RotationX != 0.0)
                {
                    //This is actually the Y-Axis rotation
                    //Convert to radians
                    RotationX *= 0.0174532925199433;
                    //Apply rotation
                    ApplyRotation(Builder, 0, 1, 0, RotationX);
                }
                if (RotationY != 0.0)
                {
                    //This is actually the X-Axis rotation
                    //Convert to radians
                    RotationY *= 0.0174532925199433;
                    //Apply rotation
                    ApplyRotation(Builder, 1, 0, 0, RotationY);
                }
                if (RotationZ != 0.0)
                {
                    //Convert to radians
                    RotationZ *= 0.0174532925199433;
                    //Apply rotation
                    ApplyRotation(Builder, 0, 0, 1, RotationZ);
                }
                
                //These files appear to only have one texture defined
                //Therefore import later- May have to change
                if (File.Exists(tday))
                {
                    for (int j = 0; j < Builder.Materials.Length; j++)
                    {
                        Builder.Materials[j].DaytimeTexture = tday;
                        Builder.Materials[j].NighttimeTexture = tnight;
                    }
                }
                if (TransparencyUsed == true)
                {
                    for (int j = 0; j < Builder.Materials.Length; j++)
                    {
                        Builder.Materials[j].TransparentColor = transparentColor;
                        Builder.Materials[j].TransparentColorUsed = true;
                    }
                }
                 
            }
            ApplyMeshBuilder(ref Object, Builder, LoadMode, ForceTextureRepeatX, ForceTextureRepeatY);
            World.CreateNormals(ref Object.Mesh);
            return Object;
        }
Beispiel #32
0
        protected override void OnRenderFrame(FrameEventArgs e)
        {
            Program.MouseMovement();
            double   timeElapsed = CPreciseTimer.GetElapsedTime();
            DateTime time        = DateTime.Now;

            Game.SecondsSinceMidnight = (double)(3600 * time.Hour + 60 * time.Minute + time.Second) + 0.001 * (double)time.Millisecond;
            lock (Program.LockObj)
            {
                ObjectManager.UpdateAnimatedWorldObjects(timeElapsed, false);
            }
            if (Program.ReducedMode)
            {
                System.Threading.Thread.Sleep(125);
            }
            else
            {
                System.Threading.Thread.Sleep(1);
            }
            bool updatelight = false;
            bool keep        = false;

            // rotate x
            if (Program.RotateX == 0)
            {
                double d = (1.0 + Math.Abs(RotateXSpeed)) * timeElapsed;
                if (RotateXSpeed >= -d & RotateXSpeed <= d)
                {
                    RotateXSpeed = 0.0;
                }
                else
                {
                    RotateXSpeed -= (double)Math.Sign(RotateXSpeed) * d;
                }
            }
            else
            {
                double d = (1.0 + 1.0 - 1.0 / (1.0 + RotateXSpeed * RotateXSpeed)) * timeElapsed;
                double m = 1.0;
                RotateXSpeed += (double)Program.RotateX * d;
                if (RotateXSpeed < -m)
                {
                    RotateXSpeed = -m;
                }
                else if (RotateXSpeed > m)
                {
                    RotateXSpeed = m;
                }
            }
            if (RotateXSpeed != 0.0)
            {
                double cosa = Math.Cos(RotateXSpeed * timeElapsed);
                double sina = Math.Sin(RotateXSpeed * timeElapsed);
                Program.Renderer.Camera.AbsoluteDirection.Rotate(Vector3.Down, cosa, sina);
                Program.Renderer.Camera.AbsoluteUp.Rotate(Vector3.Down, cosa, sina);
                Program.Renderer.Camera.AbsoluteSide.Rotate(Vector3.Down, cosa, sina);
                keep = true;
            }
            // rotate y
            if (Program.RotateY == 0)
            {
                double d = (1.0 + Math.Abs(RotateYSpeed)) * timeElapsed;
                if (RotateYSpeed >= -d & RotateYSpeed <= d)
                {
                    RotateYSpeed = 0.0;
                }
                else
                {
                    RotateYSpeed -= (double)Math.Sign(RotateYSpeed) * d;
                }
            }
            else
            {
                double d = (1.0 + 1.0 - 1.0 / (1.0 + RotateYSpeed * RotateYSpeed)) * timeElapsed;
                double m = 1.0;
                RotateYSpeed += (double)Program.RotateY * d;
                if (RotateYSpeed < -m)
                {
                    RotateYSpeed = -m;
                }
                else if (RotateYSpeed > m)
                {
                    RotateYSpeed = m;
                }
            }
            if (RotateYSpeed != 0.0)
            {
                double cosa = Math.Cos(RotateYSpeed * timeElapsed);
                double sina = Math.Sin(RotateYSpeed * timeElapsed);
                Program.Renderer.Camera.AbsoluteDirection.Rotate(Program.Renderer.Camera.AbsoluteSide, cosa, sina);
                Program.Renderer.Camera.AbsoluteUp.Rotate(Program.Renderer.Camera.AbsoluteSide, cosa, sina);
                keep = true;
            }
            // move x
            if (Program.MoveX == 0)
            {
                double d = (2.5 + Math.Abs(MoveXSpeed)) * timeElapsed;
                if (MoveXSpeed >= -d & MoveXSpeed <= d)
                {
                    MoveXSpeed = 0.0;
                }
                else
                {
                    MoveXSpeed -= (double)Math.Sign(MoveXSpeed) * d;
                }
            }
            else
            {
                double d = (5.0 + 10.0 - 10.0 / (1.0 + MoveXSpeed * MoveXSpeed)) * timeElapsed;
                double m = 25.0;
                MoveXSpeed += (double)Program.MoveX * d;
                if (MoveXSpeed < -m)
                {
                    MoveXSpeed = -m;
                }
                else if (MoveXSpeed > m)
                {
                    MoveXSpeed = m;
                }
            }
            if (MoveXSpeed != 0.0)
            {
                Program.Renderer.Camera.AbsolutePosition += MoveXSpeed * timeElapsed * Program.Renderer.Camera.AbsoluteSide;
                keep = true;
            }
            // move y
            if (Program.MoveY == 0)
            {
                double d = (2.5 + Math.Abs(MoveYSpeed)) * timeElapsed;
                if (MoveYSpeed >= -d & MoveYSpeed <= d)
                {
                    MoveYSpeed = 0.0;
                }
                else
                {
                    MoveYSpeed -= (double)Math.Sign(MoveYSpeed) * d;
                }
            }
            else
            {
                double d = (5.0 + 10.0 - 10.0 / (1.0 + MoveYSpeed * MoveYSpeed)) * timeElapsed;
                double m = 25.0;
                MoveYSpeed += (double)Program.MoveY * d;
                if (MoveYSpeed < -m)
                {
                    MoveYSpeed = -m;
                }
                else if (MoveYSpeed > m)
                {
                    MoveYSpeed = m;
                }
            }
            if (MoveYSpeed != 0.0)
            {
                Program.Renderer.Camera.AbsolutePosition += MoveYSpeed * timeElapsed * Program.Renderer.Camera.AbsoluteUp;
                keep = true;
            }
            // move z
            if (Program.MoveZ == 0)
            {
                double d = (2.5 + Math.Abs(MoveZSpeed)) * timeElapsed;
                if (MoveZSpeed >= -d & MoveZSpeed <= d)
                {
                    MoveZSpeed = 0.0;
                }
                else
                {
                    MoveZSpeed -= (double)Math.Sign(MoveZSpeed) * d;
                }
            }
            else
            {
                double d = (5.0 + 10.0 - 10.0 / (1.0 + MoveZSpeed * MoveZSpeed)) * timeElapsed;
                double m = 25.0;
                MoveZSpeed += (double)Program.MoveZ * d;
                if (MoveZSpeed < -m)
                {
                    MoveZSpeed = -m;
                }
                else if (MoveZSpeed > m)
                {
                    MoveZSpeed = m;
                }
            }
            if (MoveZSpeed != 0.0)
            {
                Program.Renderer.Camera.AbsolutePosition += MoveZSpeed * timeElapsed * Program.Renderer.Camera.AbsoluteDirection;

                keep = true;
            }
            // lighting
            if (Program.LightingRelative == -1)
            {
                Program.LightingRelative = (double)Program.LightingTarget;
                updatelight = true;
            }
            if (Program.LightingTarget == 0)
            {
                if (Program.LightingRelative != 0.0)
                {
                    Program.LightingRelative -= 0.5 * timeElapsed;
                    if (Program.LightingRelative < 0.0)
                    {
                        Program.LightingRelative = 0.0;
                    }
                    updatelight = true;
                    keep        = true;
                }
            }
            else
            {
                if (Program.LightingRelative != 1.0)
                {
                    Program.LightingRelative += 0.5 * timeElapsed;
                    if (Program.LightingRelative > 1.0)
                    {
                        Program.LightingRelative = 1.0;
                    }
                    updatelight = true;
                    keep        = true;
                }
            }
            // continue
            if (Program.ReducedMode)
            {
                ReducedModeEnteringTime = 3.0;
            }
            else
            {
                if (keep)
                {
                    ReducedModeEnteringTime = 3.0;
                }
                else if (ReducedModeEnteringTime <= 0)
                {
                    Program.ReducedMode = true;
                    Program.Renderer.Camera.AbsoluteSide.Y = 0.0;
                    Program.Renderer.Camera.AbsoluteSide.Normalize();
                    Program.Renderer.Camera.AbsoluteDirection.Normalize();
                    Program.Renderer.Camera.AbsoluteUp = Vector3.Cross(Program.Renderer.Camera.AbsoluteDirection, Program.Renderer.Camera.AbsoluteSide);
                }
                else
                {
                    ReducedModeEnteringTime -= timeElapsed;
                }
            }
            if (updatelight)
            {
                Program.Renderer.Lighting.OptionAmbientColor.R = (byte)Math.Round(32.0 + 128.0 * Program.LightingRelative * (2.0 - Program.LightingRelative));
                Program.Renderer.Lighting.OptionAmbientColor.G = (byte)Math.Round(32.0 + 128.0 * 0.5 * (Program.LightingRelative + Program.LightingRelative * (2.0 - Program.LightingRelative)));
                Program.Renderer.Lighting.OptionAmbientColor.B = (byte)Math.Round(32.0 + 128.0 * Program.LightingRelative);
                Program.Renderer.Lighting.OptionDiffuseColor.R = (byte)Math.Round(32.0 + 128.0 * Program.LightingRelative);
                Program.Renderer.Lighting.OptionDiffuseColor.G = (byte)Math.Round(32.0 + 128.0 * Program.LightingRelative);
                Program.Renderer.Lighting.OptionDiffuseColor.B = (byte)Math.Round(32.0 + 128.0 * Math.Sqrt(Program.LightingRelative));
                Program.Renderer.Lighting.Initialize();
            }
            Program.Renderer.RenderScene();
            SwapBuffers();
        }
Beispiel #33
0
		// parse animated object config
		/// <summary>Loads a collection of animated objects from a file.</summary>
		/// <param name="FileName">The text file to load the animated object from. Must be an absolute file name.</param>
		/// <param name="Encoding">The encoding the file is saved in. If the file uses a byte order mark, the encoding indicated by the byte order mark is used and the Encoding parameter is ignored.</param>
		/// <param name="LoadMode">The texture load mode.</param>
		/// <returns>The collection of animated objects.</returns>
		internal static ObjectManager.AnimatedObjectCollection ReadObject(string FileName, System.Text.Encoding Encoding, ObjectManager.ObjectLoadMode LoadMode)
		{
			System.Globalization.CultureInfo Culture = System.Globalization.CultureInfo.InvariantCulture;
			ObjectManager.AnimatedObjectCollection Result = new ObjectManager.AnimatedObjectCollection
			{
				Objects = new ObjectManager.AnimatedObject[4]
			};
			int ObjectCount = 0;
			// load file
			string[] Lines = System.IO.File.ReadAllLines(FileName, Encoding);
			bool rpnUsed = false;
			for (int i = 0; i < Lines.Length; i++)
			{
				int j = Lines[i].IndexOf(';');
				//Trim out comments
				Lines[i] = j >= 0 ? Lines[i].Substring(0, j).Trim() : Lines[i].Trim();
				//Test whether RPN functions have been used
				rpnUsed = Lines[i].IndexOf("functionrpn", StringComparison.OrdinalIgnoreCase) >= 0;
			}
			if (rpnUsed)
			{
				Interface.AddMessage(Interface.MessageType.Error, false, "An animated object file contains RPN functions. These were never meant to be used directly, only for debugging. They won't be supported indefinately. Please get rid of them in file " + FileName);
			}
			for (int i = 0; i < Lines.Length; i++)
			{
				if (Lines[i].Length != 0)
				{
					switch (Lines[i].ToLowerInvariant())
					{
						case "[include]":
							{
								i++;
								Vector3 position = new Vector3(0.0, 0.0, 0.0);
								ObjectManager.UnifiedObject[] obj = new OpenBve.ObjectManager.UnifiedObject[4];
								int objCount = 0;
								while (i < Lines.Length && !(Lines[i].StartsWith("[", StringComparison.Ordinal) & Lines[i].EndsWith("]", StringComparison.Ordinal)))
								{
									if (Lines[i].Length != 0)
									{
										int j = Lines[i].IndexOf("=", StringComparison.Ordinal);
										if (j > 0)
										{
											string a = Lines[i].Substring(0, j).TrimEnd();
											string b = Lines[i].Substring(j + 1).TrimStart();
											switch (a.ToLowerInvariant())
											{
												case "position":
													{
														string[] s = b.Split(',');
														if (s.Length == 3)
														{
															double x, y, z;
															if (!double.TryParse(s[0], System.Globalization.NumberStyles.Float, Culture, out x))
															{
																Interface.AddMessage(Interface.MessageType.Error, false, "X is invalid in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
															}
															else if (!double.TryParse(s[1], System.Globalization.NumberStyles.Float, Culture, out y))
															{
																Interface.AddMessage(Interface.MessageType.Error, false, "Y is invalid in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
															}
															else if (!double.TryParse(s[2], System.Globalization.NumberStyles.Float, Culture, out z))
															{
																Interface.AddMessage(Interface.MessageType.Error, false, "Z is invalid in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
															}
															else
															{
																position = new Vector3(x, y, z);
															}
														}
														else
														{
															Interface.AddMessage(Interface.MessageType.Error, false, "Exactly 3 arguments are expected in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
														}
													} break;
												default:
													Interface.AddMessage(Interface.MessageType.Error, false, "The attribute " + a + " is not supported at line " + (i + 1).ToString(Culture) + " in file " + FileName);
													break;
											}
										}
										else
										{
											string Folder = System.IO.Path.GetDirectoryName(FileName);
											if (Interface.ContainsInvalidPathChars(Lines[i]))
											{
												Interface.AddMessage(Interface.MessageType.Error, false, Lines[i] + " contains illegal characters at line " + (i + 1).ToString(Culture) + " in file " + FileName);
											}
											else
											{
												string file = OpenBveApi.Path.CombineFile(Folder, Lines[i]);
												if (System.IO.File.Exists(file))
												{
													if (obj.Length == objCount)
													{
														Array.Resize<ObjectManager.UnifiedObject>(ref obj, obj.Length << 1);
													}
													obj[objCount] = ObjectManager.LoadObject(file, Encoding, LoadMode, false, false, false);
													objCount++;
												}
												else
												{
													Interface.AddMessage(Interface.MessageType.Error, true, "File " + file + " not found at line " + (i + 1).ToString(Culture) + " in file " + FileName);
												}
											}
										}
									}
									i++;
								}
								i--;
								for (int j = 0; j < objCount; j++)
								{
									if (obj[j] != null)
									{
										if (obj[j] is ObjectManager.StaticObject)
										{
											ObjectManager.StaticObject s = (ObjectManager.StaticObject)obj[j];
											s.Dynamic = true;
											if (ObjectCount >= Result.Objects.Length)
											{
												Array.Resize<ObjectManager.AnimatedObject>(ref Result.Objects, Result.Objects.Length << 1);
											}
											ObjectManager.AnimatedObject a = new ObjectManager.AnimatedObject();
											ObjectManager.AnimatedObjectState aos = new ObjectManager.AnimatedObjectState
											{
												Object = s,
												Position = position
											};
											a.States = new ObjectManager.AnimatedObjectState[] { aos };
											Result.Objects[ObjectCount] = 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++)
											{
												if (ObjectCount >= Result.Objects.Length)
												{
													Array.Resize<ObjectManager.AnimatedObject>(ref Result.Objects, Result.Objects.Length << 1);
												}
												for (int h = 0; h < a.Objects[k].States.Length; h++)
												{
													a.Objects[k].States[h].Position.X += position.X;
													a.Objects[k].States[h].Position.Y += position.Y;
													a.Objects[k].States[h].Position.Z += position.Z;
												}
												Result.Objects[ObjectCount] = a.Objects[k];
												ObjectCount++;
											}
										}
									}
								}
							}
							break;
						case "[object]":
							{
								i++;
								if (Result.Objects.Length == ObjectCount)
								{
									Array.Resize<ObjectManager.AnimatedObject>(ref Result.Objects, Result.Objects.Length << 1);
								}
								Result.Objects[ObjectCount] = new ObjectManager.AnimatedObject
								{
									States = new ObjectManager.AnimatedObjectState[] {},
									CurrentState = -1,
									TranslateXDirection = new Vector3(1.0, 0.0, 0.0),
									TranslateYDirection = new Vector3(0.0, 1.0, 0.0),
									TranslateZDirection = new Vector3(0.0, 0.0, 1.0),
									RotateXDirection = new Vector3(1.0, 0.0, 0.0),
									RotateYDirection = new Vector3(0.0, 1.0, 0.0),
									RotateZDirection = new Vector3(0.0, 0.0, 1.0),
									TextureShiftXDirection = new Vector2(1.0, 0.0),
									TextureShiftYDirection = new Vector2(0.0, 1.0),
									RefreshRate = 0.0,
									ObjectIndex = -1
								};
								Vector3 Position = new Vector3(0.0, 0.0, 0.0);
								double RotateX = 0;
								bool StaticXRotation = false;
								double RotateY = 0;
								bool StaticYRotation = false;
								double RotateZ = 0;
								bool StaticZRotation = false;
								bool timetableUsed = false;
								string[] StateFiles = null;
								string StateFunctionRpn = null;
								int StateFunctionLine = -1;
								while (i < Lines.Length && !(Lines[i].StartsWith("[", StringComparison.Ordinal) & Lines[i].EndsWith("]", StringComparison.Ordinal)))
								{
									if (Lines[i].Length != 0)
									{
										int j = Lines[i].IndexOf("=", StringComparison.Ordinal);
										if (j > 0)
										{
											string a = Lines[i].Substring(0, j).TrimEnd();
											string b = Lines[i].Substring(j + 1).TrimStart();
											switch (a.ToLowerInvariant())
											{
												case "position":
													{
														string[] s = b.Split(',');
														if (s.Length == 3)
														{
															double x, y, z;
															if (!double.TryParse(s[0], System.Globalization.NumberStyles.Float, Culture, out x))
															{
																Interface.AddMessage(Interface.MessageType.Error, false, "X is invalid in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
															}
															else if (!double.TryParse(s[1], System.Globalization.NumberStyles.Float, Culture, out y))
															{
																Interface.AddMessage(Interface.MessageType.Error, false, "Y is invalid in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
															}
															else if (!double.TryParse(s[2], System.Globalization.NumberStyles.Float, Culture, out z))
															{
																Interface.AddMessage(Interface.MessageType.Error, false, "Z is invalid in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
															}
															else
															{
																Position = new Vector3(x, y, z);
															}
														}
														else
														{
															Interface.AddMessage(Interface.MessageType.Error, false, "Exactly 3 arguments are expected in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
														}
													} break;
												case "states":
													{
														string[] s = b.Split(',');
														if (s.Length >= 1)
														{
															string Folder = System.IO.Path.GetDirectoryName(FileName);
															StateFiles = new string[s.Length];
															bool NullObject = true;
															for (int k = 0; k < s.Length; k++)
															{
																s[k] = s[k].Trim();
																if (s[k].Length == 0)
																{
																	Interface.AddMessage(Interface.MessageType.Error, false, "File" + k.ToString(Culture) + " is an empty string - did you mean something else? - in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
																	StateFiles[k] = null;
																}
																else if (Interface.ContainsInvalidPathChars(s[k]))
																{
																	Interface.AddMessage(Interface.MessageType.Error, false, "File" + k.ToString(Culture) + " contains illegal characters in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
																	StateFiles[k] = null;
																}
																else
																{
																	StateFiles[k] = OpenBveApi.Path.CombineFile(Folder, s[k]);
																	if (!System.IO.File.Exists(StateFiles[k]))
																	{
																		Interface.AddMessage(Interface.MessageType.Error, true, "File " + StateFiles[k] + " not found in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
																		StateFiles[k] = null;
																	}
																}
																if (StateFiles[k] != null)
																{
																	NullObject = false;
																}	
															}
															if (NullObject == true)
															{
																Interface.AddMessage(Interface.MessageType.Error, false, "None of the specified files were found in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
																return null;
															}
														}
														else
														{
															Interface.AddMessage(Interface.MessageType.Error, false, "At least one argument is expected in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
															return null;
														}
													} break;
												case "statefunction":
													try
													{
														StateFunctionLine = i;
														StateFunctionRpn = FunctionScripts.GetPostfixNotationFromInfixNotation(b);
													}
													catch (Exception ex)
													{
														Interface.AddMessage(Interface.MessageType.Error, false, ex.Message + " in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
													} break;
												case "statefunctionrpn":
													{
														StateFunctionLine = i;
														StateFunctionRpn = b;
													} break;
												case "translatexdirection":
												case "translateydirection":
												case "translatezdirection":
													{
														string[] s = b.Split(',');
														if (s.Length == 3)
														{
															double x, y, z;
															if (!double.TryParse(s[0], System.Globalization.NumberStyles.Float, Culture, out x))
															{
																Interface.AddMessage(Interface.MessageType.Error, false, "X is invalid in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
															}
															else if (!double.TryParse(s[1], System.Globalization.NumberStyles.Float, Culture, out y))
															{
																Interface.AddMessage(Interface.MessageType.Error, false, "Y is invalid in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
															}
															else if (!double.TryParse(s[2], System.Globalization.NumberStyles.Float, Culture, out z))
															{
																Interface.AddMessage(Interface.MessageType.Error, false, "Z is invalid in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
															}
															else
															{
																switch (a.ToLowerInvariant())
																{
																	case "translatexdirection":
																		Result.Objects[ObjectCount].TranslateXDirection = new Vector3(x, y, z);
																		break;
																	case "translateydirection":
																		Result.Objects[ObjectCount].TranslateYDirection = new Vector3(x, y, z);
																		break;
																	case "translatezdirection":
																		Result.Objects[ObjectCount].TranslateZDirection = new Vector3(x, y, z);
																		break;
																}
															}
														}
														else
														{
															Interface.AddMessage(Interface.MessageType.Error, false, "Exactly 3 arguments are expected in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
														}
													} break;
												case "translatexfunction":
													try
													{
														double X;
														if (double.TryParse(b, NumberStyles.Float, Culture, out X))
														{
															Position.X = X;
															//A function script must be evaluated every frame, no matter if it is a constant value
															//If we add this to the position instead, this gives a minor speedup
															break;
														}
														Result.Objects[ObjectCount].TranslateXFunction = FunctionScripts.GetFunctionScriptFromInfixNotation(b);
													}
													catch (Exception ex)
													{
														Interface.AddMessage(Interface.MessageType.Error, false, ex.Message + " in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
													} break;
												case "translatexscript":
													try
													{
														Result.Objects[ObjectCount].TranslateXScriptFile = OpenBveApi.Path.CombineDirectory(System.IO.Path.GetDirectoryName(FileName), b);
													}
													catch (Exception ex)
													{
														Interface.AddMessage(Interface.MessageType.Error, false, ex.Message + " in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
													} break;
												case "translateyfunction":
													try
													{
														double Y;
														if (double.TryParse(b, NumberStyles.Float, Culture, out Y))
														{
															Position.Y = Y;
															//A function script must be evaluated every frame, no matter if it is a constant value
															//If we add this to the position instead, this gives a minor speedup
															break;
														}
														Result.Objects[ObjectCount].TranslateYFunction = FunctionScripts.GetFunctionScriptFromInfixNotation(b);
													}
													catch (Exception ex)
													{
														Interface.AddMessage(Interface.MessageType.Error, false, ex.Message + " in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
													} break;
												case "translateyscript":
													try
													{
														Result.Objects[ObjectCount].TranslateYScriptFile = OpenBveApi.Path.CombineDirectory(System.IO.Path.GetDirectoryName(FileName), b);
													}
													catch (Exception ex)
													{
														Interface.AddMessage(Interface.MessageType.Error, false, ex.Message + " in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
													} break;
												case "translatezfunction":
													try
													{
														double Z;
														if (double.TryParse(b, NumberStyles.Float, Culture, out Z))
														{
															Position.Z = Z;
															//A function script must be evaluated every frame, no matter if it is a constant value
															//If we add this to the position instead, this gives a minor speedup
															break;
														}
														Result.Objects[ObjectCount].TranslateZFunction = FunctionScripts.GetFunctionScriptFromInfixNotation(b);
													}
													catch (Exception ex)
													{
														Interface.AddMessage(Interface.MessageType.Error, false, ex.Message + " in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
													} break;
												case "translatezscript":
													try
													{
														Result.Objects[ObjectCount].TranslateZScriptFile = OpenBveApi.Path.CombineDirectory(System.IO.Path.GetDirectoryName(FileName), b);
													}
													catch (Exception ex)
													{
														Interface.AddMessage(Interface.MessageType.Error, false, ex.Message + " in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
													} break;
												case "trackfollowerfunction":
													try
													{
														Result.Objects[ObjectCount].TrackFollowerFunction = FunctionScripts.GetFunctionScriptFromInfixNotation(b);
													}
													catch (Exception ex)
													{
														Interface.AddMessage(Interface.MessageType.Error, false, ex.Message + " in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
													} break;
												case "axles":
													try
													{
														double FrontAxlePosition;
														double RearAxlePosition;
														var splitValue = b.Split(',');
														Double.TryParse(splitValue[0], out FrontAxlePosition);
														Double.TryParse(splitValue[1], out RearAxlePosition);
														if (FrontAxlePosition > RearAxlePosition)
														{
															Result.Objects[ObjectCount].FrontAxlePosition = FrontAxlePosition;
															Result.Objects[ObjectCount].RearAxlePosition = RearAxlePosition;
														}
														else if (FrontAxlePosition < RearAxlePosition)
														{
															Interface.AddMessage(Interface.MessageType.Error, false,"Rear is expected to be less than Front in " + a + " at line " + (i + 1).ToString(Culture) + " in file " +FileName);
														}
														else
														{
															Interface.AddMessage(Interface.MessageType.Error, false, "Rear must not equal Front in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
														}

													}
													catch(Exception ex)
													{
														Interface.AddMessage(Interface.MessageType.Error, false, ex.Message + " in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
													}
													break;
													/*
													 * RPN Functions were added by Michelle, and she stated that they should not be used other than in debugging
													 * Not aware of any uses, but these should stay there anyway
													 * 
													 */
												case "translatexfunctionrpn":
													try
													{
														Result.Objects[ObjectCount].TranslateXFunction = FunctionScripts.GetFunctionScriptFromPostfixNotation(b);
													}
													catch (Exception ex)
													{
														Interface.AddMessage(Interface.MessageType.Error, false, ex.Message + " in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
													} break;
												case "translateyfunctionrpn":
													try
													{
														Result.Objects[ObjectCount].TranslateYFunction = FunctionScripts.GetFunctionScriptFromPostfixNotation(b);
													}
													catch (Exception ex)
													{
														Interface.AddMessage(Interface.MessageType.Error, false, ex.Message + " in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
													} break;
												case "translatezfunctionrpn":
													try
													{
														Result.Objects[ObjectCount].TranslateZFunction = FunctionScripts.GetFunctionScriptFromPostfixNotation(b);
													}
													catch (Exception ex)
													{
														Interface.AddMessage(Interface.MessageType.Error, false, ex.Message + " in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
													} break;
												case "rotatexdirection":
												case "rotateydirection":
												case "rotatezdirection":
													{
														string[] s = b.Split(',');
														if (s.Length == 3)
														{
															double x, y, z;
															if (!double.TryParse(s[0], System.Globalization.NumberStyles.Float, Culture, out x))
															{
																Interface.AddMessage(Interface.MessageType.Error, false, "X is invalid in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
															}
															else if (!double.TryParse(s[1], System.Globalization.NumberStyles.Float, Culture, out y))
															{
																Interface.AddMessage(Interface.MessageType.Error, false, "Y is invalid in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
															}
															else if (!double.TryParse(s[2], System.Globalization.NumberStyles.Float, Culture, out z))
															{
																Interface.AddMessage(Interface.MessageType.Error, false, "Z is invalid in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
															}
															else if (x == 0.0 & y == 0.0 & z == 0.0)
															{
																Interface.AddMessage(Interface.MessageType.Error, false, "The direction indicated by X, Y and Z is expected to be non-zero in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
															}
															else
															{
																switch (a.ToLowerInvariant())
																{
																	case "rotatexdirection":
																		Result.Objects[ObjectCount].RotateXDirection = new Vector3(x, y, z);
																		break;
																	case "rotateydirection":
																		Result.Objects[ObjectCount].RotateYDirection = new Vector3(x, y, z);
																		break;
																	case "rotatezdirection":
																		Result.Objects[ObjectCount].RotateZDirection = new Vector3(x, y, z);
																		break;
																}
															}
														}
														else
														{
															Interface.AddMessage(Interface.MessageType.Error, false, "Exactly 3 arguments are expected in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
														}
													} break;
												case "rotatexfunction":
													try
													{
														if (double.TryParse(b, NumberStyles.Float, Culture, out RotateX))
														{
															//A function script must be evaluated every frame, no matter if it is a constant value
															//If we add this to the position instead, this gives a minor speedup
															StaticXRotation = true;
														}
														Result.Objects[ObjectCount].RotateXFunction = FunctionScripts.GetFunctionScriptFromInfixNotation(b);
													}
													catch (Exception ex)
													{
														Interface.AddMessage(Interface.MessageType.Error, false, ex.Message + " in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
													} break;
												case "rotateyfunction":
													try
													{
														if (double.TryParse(b, NumberStyles.Float, Culture, out RotateY))
														{
															StaticYRotation = true;
														}
														Result.Objects[ObjectCount].RotateYFunction = FunctionScripts.GetFunctionScriptFromInfixNotation(b);
													}
													catch (Exception ex)
													{
														Interface.AddMessage(Interface.MessageType.Error, false, ex.Message + " in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
													} break;
												case "rotatezfunction":
													try
													{
														if (double.TryParse(b, NumberStyles.Float, Culture, out RotateZ))
														{
															StaticZRotation = true;
														}
														Result.Objects[ObjectCount].RotateZFunction = FunctionScripts.GetFunctionScriptFromInfixNotation(b);
													}
													catch (Exception ex)
													{
														Interface.AddMessage(Interface.MessageType.Error, false, ex.Message + " in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
													} break;
												case "rotatexfunctionrpn":
													try
													{
														Result.Objects[ObjectCount].RotateXFunction = FunctionScripts.GetFunctionScriptFromPostfixNotation(b);
													}
													catch (Exception ex)
													{
														Interface.AddMessage(Interface.MessageType.Error, false, ex.Message + " in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
													} break;
												case "rotateyfunctionrpn":
													try
													{
														Result.Objects[ObjectCount].RotateYFunction = FunctionScripts.GetFunctionScriptFromPostfixNotation(b);
													}
													catch (Exception ex)
													{
														Interface.AddMessage(Interface.MessageType.Error, false, ex.Message + " in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
													} break;
												case "rotatezfunctionrpn":
													try
													{
														Result.Objects[ObjectCount].RotateZFunction = FunctionScripts.GetFunctionScriptFromPostfixNotation(b);
													}
													catch (Exception ex)
													{
														Interface.AddMessage(Interface.MessageType.Error, false, ex.Message + " in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
													} break;
												case "rotatexdamping":
												case "rotateydamping":
												case "rotatezdamping":
													{
														string[] s = b.Split(',');
														if (s.Length == 2)
														{
															double nf, dr;
															if (!double.TryParse(s[0], System.Globalization.NumberStyles.Float, Culture, out nf))
															{
																Interface.AddMessage(Interface.MessageType.Error, false, "NaturalFrequency is invalid in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
															}
															else if (!double.TryParse(s[1], System.Globalization.NumberStyles.Float, Culture, out dr))
															{
																Interface.AddMessage(Interface.MessageType.Error, false, "DampingRatio is invalid in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
															}
															else if (nf <= 0.0)
															{
																Interface.AddMessage(Interface.MessageType.Error, false, "NaturalFrequency is expected to be positive in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
															}
															else if (dr <= 0.0)
															{
																Interface.AddMessage(Interface.MessageType.Error, false, "DampingRatio is expected to be positive in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
															}
															else
															{
																switch (a.ToLowerInvariant())
																{
																	case "rotatexdamping":
																		Result.Objects[ObjectCount].RotateXDamping = new ObjectManager.Damping(nf, dr);
																		break;
																	case "rotateydamping":
																		Result.Objects[ObjectCount].RotateYDamping = new ObjectManager.Damping(nf, dr);
																		break;
																	case "rotatezdamping":
																		Result.Objects[ObjectCount].RotateZDamping = new ObjectManager.Damping(nf, dr);
																		break;
																}
															}
														}
														else
														{
															Interface.AddMessage(Interface.MessageType.Error, false, "Exactly 2 arguments are expected in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
														}
													} break;
												case "textureshiftxdirection":
												case "textureshiftydirection":
													{
														string[] s = b.Split(',');
														if (s.Length == 2)
														{
															double x, y;
															if (!double.TryParse(s[0], System.Globalization.NumberStyles.Float, Culture, out x))
															{
																Interface.AddMessage(Interface.MessageType.Error, false, "X is invalid in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
															}
															else if (!double.TryParse(s[1], System.Globalization.NumberStyles.Float, Culture, out y))
															{
																Interface.AddMessage(Interface.MessageType.Error, false, "Y is invalid in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
															}
															else
															{
																switch (a.ToLowerInvariant())
																{
																	case "textureshiftxdirection":
																		Result.Objects[ObjectCount].TextureShiftXDirection = new Vector2(x, y);
																		break;
																	case "textureshiftydirection":
																		Result.Objects[ObjectCount].TextureShiftYDirection = new Vector2(x, y);
																		break;
																}
															}
														}
														else
														{
															Interface.AddMessage(Interface.MessageType.Error, false, "Exactly 2 arguments are expected in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
														}
													} break;
												case "textureshiftxfunction":
													try
													{
														Result.Objects[ObjectCount].TextureShiftXFunction = FunctionScripts.GetFunctionScriptFromInfixNotation(b);
													}
													catch (Exception ex)
													{
														Interface.AddMessage(Interface.MessageType.Error, false, ex.Message + " in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
													} break;
												case "textureshiftyfunction":
													try
													{
														Result.Objects[ObjectCount].TextureShiftYFunction = FunctionScripts.GetFunctionScriptFromInfixNotation(b);
													}
													catch (Exception ex)
													{
														Interface.AddMessage(Interface.MessageType.Error, false, ex.Message + " in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
													} break;
												case "textureshiftxfunctionrpn":
													try
													{
														Result.Objects[ObjectCount].TextureShiftXFunction = FunctionScripts.GetFunctionScriptFromPostfixNotation(b);
													}
													catch (Exception ex)
													{
														Interface.AddMessage(Interface.MessageType.Error, false, ex.Message + " in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
													} break;
												case "textureshiftyfunctionrpn":
													try
													{
														Result.Objects[ObjectCount].TextureShiftYFunction = FunctionScripts.GetFunctionScriptFromPostfixNotation(b);
													}
													catch (Exception ex)
													{
														Interface.AddMessage(Interface.MessageType.Error, false, ex.Message + " in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
													} break;
												case "textureoverride":
													switch (b.ToLowerInvariant())
													{
														case "none":
															break;
														case "timetable":
															if (!timetableUsed)
															{
																Timetable.AddObjectForCustomTimetable(Result.Objects[ObjectCount]);
																timetableUsed = true;
															}
															break;
														default:
															Interface.AddMessage(Interface.MessageType.Error, false, "Unrecognized value in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
															break;
													}
													break;
												case "refreshrate":
													{
														double r;
														if (!double.TryParse(b, System.Globalization.NumberStyles.Float, Culture, out r))
														{
															Interface.AddMessage(Interface.MessageType.Error, false, "Value is invalid in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
														}
														else if (r < 0.0)
														{
															Interface.AddMessage(Interface.MessageType.Error, false, "Value is expected to be non-negative in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
														}
														else
														{
															Result.Objects[ObjectCount].RefreshRate = r;
														}
													} break;
												default:
													Interface.AddMessage(Interface.MessageType.Error, false, "The attribute " + a + " is not supported at line " + (i + 1).ToString(Culture) + " in file " + FileName);
													break;
											}
										}
										else
										{
											Interface.AddMessage(Interface.MessageType.Error, false, "Invalid statement " + Lines[i] + " encountered at line " + (i + 1).ToString(Culture) + " in file " + FileName);
											return null;
										}
									}
									i++;
								}
								i--;
								if (StateFiles != null)
								{
									// create the object
									if (timetableUsed)
									{
										if (StateFunctionRpn != null)
										{
											StateFunctionRpn = "timetable 0 == " + StateFunctionRpn + " -1 ?";
										}
										else
										{
											StateFunctionRpn = "timetable";
										}
									}
									if (StateFunctionRpn != null)
									{
										try
										{
											Result.Objects[ObjectCount].StateFunction = FunctionScripts.GetFunctionScriptFromPostfixNotation(StateFunctionRpn);
										}
										catch (Exception ex)
										{
											Interface.AddMessage(Interface.MessageType.Error, false, ex.Message + " in StateFunction at line " + (StateFunctionLine + 1).ToString(Culture) + " in file " + FileName);
										}
									}
									Result.Objects[ObjectCount].States = new ObjectManager.AnimatedObjectState[StateFiles.Length];
									bool ForceTextureRepeatX = Result.Objects[ObjectCount].TextureShiftXFunction != null & Result.Objects[ObjectCount].TextureShiftXDirection.X != 0.0 |
										Result.Objects[ObjectCount].TextureShiftYFunction != null & Result.Objects[ObjectCount].TextureShiftYDirection.Y != 0.0;
									bool ForceTextureRepeatY = Result.Objects[ObjectCount].TextureShiftXFunction != null & Result.Objects[ObjectCount].TextureShiftXDirection.X != 0.0 |
										Result.Objects[ObjectCount].TextureShiftYFunction != null & Result.Objects[ObjectCount].TextureShiftYDirection.Y != 0.0;
									for (int k = 0; k < StateFiles.Length; k++)
									{
										Result.Objects[ObjectCount].States[k].Position = new Vector3(0.0, 0.0, 0.0);
										if (StateFiles[k] != null)
										{
											Result.Objects[ObjectCount].States[k].Object = ObjectManager.LoadStaticObject(StateFiles[k], Encoding, LoadMode, false, ForceTextureRepeatX, ForceTextureRepeatY);
											if (Result.Objects[ObjectCount].States[k].Object != null)
											{
												Result.Objects[ObjectCount].States[k].Object.Dynamic = true;
											}
										}
										else
										{
											Result.Objects[ObjectCount].States[k].Object = null;
										}
										
									}
									for (int j = 0; j < Result.Objects[ObjectCount].States.Length; j++)
									{

										//Rotate X
										if (Result.Objects[ObjectCount].States[j].Object == null)
										{
											continue;
										}
										for (int l = 0; l < Result.Objects[ObjectCount].States[j].Object.Mesh.Vertices.Length; l++)
										{
											//Apply position
											Result.Objects[ObjectCount].States[j].Position = Position;
											//Test whether the object contains non static rotation functions
											//If so, the results may be off so don't optimise
											if (!StaticXRotation)
											{
												if (Result.Objects[ObjectCount].RotateXFunction != null)
												{
													break;
												}
											}
											if (!StaticYRotation)
											{
												if (Result.Objects[ObjectCount].RotateYFunction != null)
												{
													break;
												}
											}
											if (!StaticZRotation)
											{
												if (Result.Objects[ObjectCount].RotateZFunction != null)
												{
													break;
												}
											}
											if (StaticXRotation)
											{
												double x = Result.Objects[ObjectCount].RotateXDirection.X;
												double y = Result.Objects[ObjectCount].RotateXDirection.Y;
												double z = Result.Objects[ObjectCount].RotateXDirection.Z;
												double t = x * x + y * y + z * z;
												if (t == 0.0)
												{
													x = 1.0;
													y = 0.0;
													z = 0.0;
													t = 1.0;
												}
												if (RotateX != 0.0)
												{
													t = 1.0 / Math.Sqrt(t);
													x *= t;
													y *= t;
													z *= t;
												}
												double cosX = Math.Cos(RotateX);
												double sinX = Math.Sin(RotateX);
												World.Rotate(ref Result.Objects[ObjectCount].States[j].Object.Mesh.Vertices[l].Coordinates, x, y, z, cosX, sinX);
												Result.Objects[ObjectCount].RotateXFunction = null;
											}
											if (StaticYRotation)
											{
												double x = Result.Objects[ObjectCount].RotateYDirection.X;
												double y = Result.Objects[ObjectCount].RotateYDirection.Y;
												double z = Result.Objects[ObjectCount].RotateYDirection.Z;
												double t = x * x + y * y + z * z;
												if (t == 0.0)
												{
													x = 1.0;
													y = 0.0;
													z = 0.0;
													t = 1.0;
												}
												if (RotateY != 0.0)
												{
													t = 1.0 / Math.Sqrt(t);
													x *= t;
													y *= t;
													z *= t;
												}
												double cosY = Math.Cos(RotateY);
												double sinY = Math.Sin(RotateY);
												World.Rotate(ref Result.Objects[ObjectCount].States[j].Object.Mesh.Vertices[l].Coordinates, x, y, z, cosY, sinY);
												Result.Objects[ObjectCount].RotateYFunction = null;
											}
											if (StaticZRotation)
											{
												double x = Result.Objects[ObjectCount].RotateZDirection.X;
												double y = Result.Objects[ObjectCount].RotateZDirection.Y;
												double z = Result.Objects[ObjectCount].RotateZDirection.Z;
												double t = x * x + y * y + z * z;
												if (t == 0.0)
												{
													x = 1.0;
													y = 0.0;
													z = 0.0;
													t = 1.0;
												}
												if (RotateZ != 0.0)
												{
													t = 1.0 / Math.Sqrt(t);
													x *= t;
													y *= t;
													z *= t;
												}
												double cosZ = Math.Cos(RotateZ);
												double sinZ = Math.Sin(RotateZ);
												World.Rotate(ref Result.Objects[ObjectCount].States[j].Object.Mesh.Vertices[l].Coordinates, x, y, z, cosZ, sinZ);
												Result.Objects[ObjectCount].RotateZFunction = null;
											}

											
										}
									}
								}
								else
								{
									Result.Objects[ObjectCount].States = new ObjectManager.AnimatedObjectState[] { };
								}
								ObjectCount++;
							}
							break;
						default:
							Interface.AddMessage(Interface.MessageType.Error, false, "Invalid statement " + Lines[i] + " encountered at line " + (i + 1).ToString(Culture) + " in file " + FileName);
							return null;
					}
				}
			}
			Array.Resize<ObjectManager.AnimatedObject>(ref Result.Objects, ObjectCount);
			return Result;
		}
Beispiel #34
0
		// apply mesh builder
		private static void ApplyMeshBuilder(ref ObjectManager.StaticObject Object, MeshBuilder Builder) {
			if (Builder.Faces.Length != 0) {
				int mf = Object.Mesh.Faces.Length;
				int mm = Object.Mesh.Materials.Length;
				int mv = Object.Mesh.Vertices.Length;
				Array.Resize<World.MeshFace>(ref Object.Mesh.Faces, mf + Builder.Faces.Length);
				Array.Resize<World.MeshMaterial>(ref Object.Mesh.Materials, mm + Builder.Materials.Length);
				Array.Resize<World.Vertex>(ref Object.Mesh.Vertices, mv + Builder.Vertices.Length);
				for (int i = 0; i < Builder.Vertices.Length; i++) {
					Object.Mesh.Vertices[mv + i] = Builder.Vertices[i];
				}
				for (int i = 0; i < Builder.Faces.Length; i++) {
					Object.Mesh.Faces[mf + i] = Builder.Faces[i];
					for (int j = 0; j < Object.Mesh.Faces[mf + i].Vertices.Length; j++) {
						Object.Mesh.Faces[mf + i].Vertices[j].Index += (ushort)mv;
					}
					Object.Mesh.Faces[mf + i].Material += (ushort)mm;
				}
				for (int i = 0; i < Builder.Materials.Length; i++) {
					Object.Mesh.Materials[mm + i].Flags = (byte)((Builder.Materials[i].EmissiveColorUsed ? World.MeshMaterial.EmissiveColorMask : 0) | (Builder.Materials[i].TransparentColorUsed ? World.MeshMaterial.TransparentColorMask : 0));
					Object.Mesh.Materials[mm + i].Color = Builder.Materials[i].Color;
					Object.Mesh.Materials[mm + i].TransparentColor = Builder.Materials[i].TransparentColor;
					if (Builder.Materials[i].DaytimeTexture != null || Builder.Materials[i].Text != null)
					{
						Textures.Texture tday;
						if (Builder.Materials[i].Text != null)
						{
							Bitmap bitmap = null;
							if (Builder.Materials[i].DaytimeTexture != null)
							{
								bitmap = new Bitmap(Builder.Materials[i].DaytimeTexture);
							}
							Bitmap texture = TextOverlay.AddTextToBitmap(bitmap, Builder.Materials[i].Text, Builder.Materials[i].Font, 12, Builder.Materials[i].BackgroundColor, Builder.Materials[i].TextColor, Builder.Materials[i].TextPadding);
							tday = Textures.RegisterTexture(texture, new OpenBveApi.Textures.TextureParameters(null, new Color24(Builder.Materials[i].TransparentColor.R, Builder.Materials[i].TransparentColor.G, Builder.Materials[i].TransparentColor.B)));
						}
						else
						{
							if (Builder.Materials[i].TransparentColorUsed)
							{
								Textures.RegisterTexture(Builder.Materials[i].DaytimeTexture,
									new OpenBveApi.Textures.TextureParameters(null,
										new Color24(Builder.Materials[i].TransparentColor.R, Builder.Materials[i].TransparentColor.G,
											Builder.Materials[i].TransparentColor.B)), out tday);
							}
							else
							{
								Textures.RegisterTexture(Builder.Materials[i].DaytimeTexture, out tday);
							}
						}
						Object.Mesh.Materials[mm + i].DaytimeTexture = tday;
					}
					else
					{
						Object.Mesh.Materials[mm + i].DaytimeTexture = null;
					}
					Object.Mesh.Materials[mm + i].EmissiveColor = Builder.Materials[i].EmissiveColor;
					if (Builder.Materials[i].NighttimeTexture != null) {
						Textures.Texture tnight;
						if (Builder.Materials[i].TransparentColorUsed) {
							Textures.RegisterTexture(Builder.Materials[i].NighttimeTexture, new OpenBveApi.Textures.TextureParameters(null, new Color24(Builder.Materials[i].TransparentColor.R, Builder.Materials[i].TransparentColor.G, Builder.Materials[i].TransparentColor.B)), out tnight);
						} else {
							Textures.RegisterTexture(Builder.Materials[i].NighttimeTexture, out tnight);
						}
						Object.Mesh.Materials[mm + i].NighttimeTexture = tnight;
					} else {
						Object.Mesh.Materials[mm + i].NighttimeTexture = null;
					}
					Object.Mesh.Materials[mm + i].DaytimeNighttimeBlend = 0;
					Object.Mesh.Materials[mm + i].BlendMode = Builder.Materials[i].BlendMode;
					Object.Mesh.Materials[mm + i].GlowAttenuationData = Builder.Materials[i].GlowAttenuationData;
				}
			}
		}
		// read object
		/// <summary>Loads a CSV or B3D object from a file.</summary>
		/// <param name="FileName">The text file to load the animated object from. Must be an absolute file name.</param>
		/// <param name="Encoding">The encoding the file is saved in. If the file uses a byte order mark, the encoding indicated by the byte order mark is used and the Encoding parameter is ignored.</param>
		/// <param name="LoadMode">The texture load mode.</param>
		/// <param name="ForceTextureRepeatX">Whether to force TextureWrapMode.Repeat for X axis of referenced textures.</param>
		/// <param name="ForceTextureRepeatY">Whether to force TextureWrapMode.Repeat for Y axis of referenced textures.</param>
		/// <returns>The object loaded.</returns>
		internal static ObjectManager.StaticObject ReadObject(string FileName, System.Text.Encoding Encoding, ObjectManager.ObjectLoadMode LoadMode, bool ForceTextureRepeatX, bool ForceTextureRepeatY) {
			System.Globalization.CultureInfo Culture = System.Globalization.CultureInfo.InvariantCulture;
			bool IsB3D = string.Equals(System.IO.Path.GetExtension(FileName), ".b3d", StringComparison.OrdinalIgnoreCase);
			// initialize object
			ObjectManager.StaticObject Object = new ObjectManager.StaticObject();
			Object.Mesh.Faces = new World.MeshFace[] { };
			Object.Mesh.Materials = new World.MeshMaterial[] { };
			Object.Mesh.Vertices = new World.Vertex[] { };
			// read lines
			string[] Lines = System.IO.File.ReadAllLines(FileName, Encoding);
			// parse lines
			MeshBuilder Builder = new MeshBuilder();
			Vector3f[] Normals = new Vector3f[4];
			for (int i = 0; i < Lines.Length; i++) {
				{
					// strip away comments
					int j = Lines[i].IndexOf(';');
					if (j >= 0) {
						Lines[i] = Lines[i].Substring(0, j);
					}
				}
				// collect arguments
				string[] Arguments = Lines[i].Split(new char[] { ',' }, StringSplitOptions.None);
				for (int j = 0; j < Arguments.Length; j++) {
					Arguments[j] = Arguments[j].Trim();
				}
				{
					// remove unused arguments at the end of the chain
					int j;
					for (j = Arguments.Length - 1; j >= 0; j--) {
						if (Arguments[j].Length != 0) break;
					}
					Array.Resize<string>(ref Arguments, j + 1);
				}
				// style
				string Command;
				if (IsB3D & Arguments.Length != 0) {
					// b3d
					int space = Arguments[0].IndexOf(' ');
					if (space >= 0) {
						Command = Arguments[0].Substring(0, space).TrimEnd();
						Arguments[0] = Arguments[0].Substring(space + 1).TrimStart();
					} else {
						Command = Arguments[0];
						if (Arguments.Length != 1) {
							Debug.AddMessage(Debug.MessageType.Error, false, "Invalid syntax at line " + (i + 1).ToString(Culture) + " in file " + FileName);
						}
						Arguments = new string[] { };
					}
				} else if (Arguments.Length != 0) {
					// csv
					Command = Arguments[0];
					for (int j = 0; j < Arguments.Length - 1; j++) {
						Arguments[j] = Arguments[j + 1];
					}
					Array.Resize<string>(ref Arguments, Arguments.Length - 1);
				} else {
					// empty
					Command = null;
				}
				// parse terms
				if (Command != null) {
					string cmd = Command.ToLowerInvariant();
					switch(cmd) {
						case "createmeshbuilder":
						case "[meshbuilder]":
							{
								if (cmd == "createmeshbuilder" & IsB3D) {
									Debug.AddMessage(Debug.MessageType.Warning, false, "CreateMeshBuilder is not a supported command - did you mean [MeshBuilder]? - at line " + (i + 1).ToString(Culture) + " in file " + FileName);
								} else if (cmd == "[meshbuilder]" & !IsB3D) {
									Debug.AddMessage(Debug.MessageType.Warning, false, "[MeshBuilder] is not a supported command - did you mean CreateMeshBuilder? - at line " + (i + 1).ToString(Culture) + " in file " + FileName);
								}
								if (Arguments.Length > 0) {
									Debug.AddMessage(Debug.MessageType.Warning, false, "0 arguments are expected in " + Command + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
								}
								ApplyMeshBuilder(ref Object, Builder, LoadMode, ForceTextureRepeatX, ForceTextureRepeatY);
								Builder = new MeshBuilder();
								Normals = new Vector3f[4];
							} break;
						case "addvertex":
						case "vertex":
							{
								if (cmd == "addvertex" & IsB3D) {
									Debug.AddMessage(Debug.MessageType.Warning, false, "AddVertex is not a supported command - did you mean Vertex? - at line " + (i + 1).ToString(Culture) + " in file " + FileName);
								} else if (cmd == "vertex" & !IsB3D) {
									Debug.AddMessage(Debug.MessageType.Warning, false, "Vertex is not a supported command - did you mean AddVertex? - at line " + (i + 1).ToString(Culture) + " in file " + FileName);
								}
								if (Arguments.Length > 6) {
									Debug.AddMessage(Debug.MessageType.Warning, false, "At most 6 arguments are expected in " + Command + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
								}
								double vx = 0.0, vy = 0.0, vz = 0.0;
								if (Arguments.Length >= 1 && Arguments[0].Length > 0 && !Conversions.TryParseDoubleVb6(Arguments[0], out vx)) {
									Debug.AddMessage(Debug.MessageType.Error, false, "Invalid argument vX in " + Command + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
									vx = 0.0;
								}
								if (Arguments.Length >= 2 && Arguments[1].Length > 0 && !Conversions.TryParseDoubleVb6(Arguments[1], out vy)) {
									Debug.AddMessage(Debug.MessageType.Error, false, "Invalid argument vY in " + Command + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
									vy = 0.0;
								}
								if (Arguments.Length >= 3 && Arguments[2].Length > 0 && !Conversions.TryParseDoubleVb6(Arguments[2], out vz)) {
									Debug.AddMessage(Debug.MessageType.Error, false, "Invalid argument vZ in " + Command + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
									vz = 0.0;
								}
								double nx = 0.0, ny = 0.0, nz = 0.0;
								if (Arguments.Length >= 4 && Arguments[3].Length > 0 && !Conversions.TryParseDoubleVb6(Arguments[3], out nx)) {
									Debug.AddMessage(Debug.MessageType.Error, false, "Invalid argument nX in " + Command + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
									nx = 0.0;
								}
								if (Arguments.Length >= 5 && Arguments[4].Length > 0 && !Conversions.TryParseDoubleVb6(Arguments[4], out ny)) {
									Debug.AddMessage(Debug.MessageType.Error, false, "Invalid argument nY in " + Command + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
									ny = 0.0;
								}
								if (Arguments.Length >= 6 && Arguments[5].Length > 0 && !Conversions.TryParseDoubleVb6(Arguments[5], out nz)) {
									Debug.AddMessage(Debug.MessageType.Error, false, "Invalid argument nZ in " + Command + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
									nz = 0.0;
								}
								World.Normalize(ref nx, ref ny, ref nz);
								Array.Resize<World.Vertex>(ref Builder.Vertices, Builder.Vertices.Length + 1);
								while (Builder.Vertices.Length >= Normals.Length) {
									Array.Resize<Vector3f>(ref Normals, Normals.Length << 1);
								}
								Builder.Vertices[Builder.Vertices.Length - 1].Coordinates = new Vector3D(vx, vy, vz);
								Normals[Builder.Vertices.Length - 1] = new Vector3f((float)nx, (float)ny, (float)nz);
							} break;
						case "addface":
						case "addface2":
						case "face":
						case "face2":
							{
								if (IsB3D) {
									if (cmd == "addface") {
										Debug.AddMessage(Debug.MessageType.Warning, false, "AddFace is not a supported command - did you mean Face? - at line " + (i + 1).ToString(Culture) + " in file " + FileName);
									} else if (cmd == "addface2") {
										Debug.AddMessage(Debug.MessageType.Warning, false, "AddFace2 is not a supported command - did you mean Face2? - at line " + (i + 1).ToString(Culture) + " in file " + FileName);
									}
								} else {
									if (cmd == "face") {
										Debug.AddMessage(Debug.MessageType.Warning, false, "Face is not a supported command - did you mean AddFace? - at line " + (i + 1).ToString(Culture) + " in file " + FileName);
									} else if (cmd == "face2") {
										Debug.AddMessage(Debug.MessageType.Warning, false, "Face2 is not a supported command - did you mean AddFace2? - at line " + (i + 1).ToString(Culture) + " in file " + FileName);
									}
								}
								if (Arguments.Length < 3) {
									Debug.AddMessage(Debug.MessageType.Error, false, "At least 3 arguments are required in " + Command + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
								} else {
									bool valid = true;
									int[] indices = new int[Arguments.Length];
									for (int j = 0; j < Arguments.Length; j++) {
										if (!Conversions.TryParseIntVb6(Arguments[j], out indices[j])) {
											Debug.AddMessage(Debug.MessageType.Error, false, "v" + j.ToString(Culture) + " is invalid in " + Command + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
											valid = false;
											break;
										} else if (indices[j] < 0 | indices[j] >= Builder.Vertices.Length) {
											Debug.AddMessage(Debug.MessageType.Error, false, "v" + j.ToString(Culture) + " references a non-existing vertex in " + Command + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
											valid = false;
											break;
										} else if (indices[j] > 65535) {
											Debug.AddMessage(Debug.MessageType.Error, false, "v" + j.ToString(Culture) + " indexes a vertex above 65535 which is not currently supported in " + Command + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
											valid = false;
											break;
										}
									}
									if (valid) {
										int last = Builder.Faces.Length;
										Array.Resize<World.MeshFace>(ref Builder.Faces, last + 1);
										Builder.Faces[last] = new World.MeshFace();
										Builder.Faces[last].Vertices = new World.MeshFaceVertex[Arguments.Length];
										while (Builder.Vertices.Length > Normals.Length) {
											Array.Resize<Vector3f>(ref Normals, Normals.Length << 1);
										}
										for (int j = 0; j < Arguments.Length; j++) {
											Builder.Faces[last].Vertices[j].Index = (ushort)indices[j];
											Builder.Faces[last].Vertices[j].Normal = Normals[indices[j]];
										}
										if (cmd == "addface2" | cmd == "face2") {
											Builder.Faces[last].Flags = (byte)World.MeshFace.Face2Mask;
										}
									}
								}
							} break;
						case "cube":
							{
								if (Arguments.Length > 3) {
									Debug.AddMessage(Debug.MessageType.Warning, false, "At most 3 arguments are expected in " + Command + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
								}
								double x = 0.0;
								if (Arguments.Length >= 1 && Arguments[0].Length > 0 && !Conversions.TryParseDoubleVb6(Arguments[0], out x)) {
									Debug.AddMessage(Debug.MessageType.Error, false, "Invalid argument HalfWidth in " + Command + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
									x = 1.0;
								}
								double y = x, z = x;
								if (Arguments.Length >= 2 && Arguments[1].Length > 0 && !Conversions.TryParseDoubleVb6(Arguments[1], out y)) {
									Debug.AddMessage(Debug.MessageType.Error, false, "Invalid argument HalfHeight in " + Command + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
									y = 1.0;
								}
								if (Arguments.Length >= 3 && Arguments[2].Length > 0 && !Conversions.TryParseDoubleVb6(Arguments[2], out z)) {
									Debug.AddMessage(Debug.MessageType.Error, false, "Invalid argument HalfDepth in " + Command + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
									z = 1.0;
								}
								CreateCube(ref Builder, x, y, z);
							} break;
						case "cylinder":
							{
								if (Arguments.Length > 4) {
									Debug.AddMessage(Debug.MessageType.Warning, false, "At most 4 arguments are expected in " + Command + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
								}
								int n = 8;
								if (Arguments.Length >= 1 && Arguments[0].Length > 0 && !Conversions.TryParseIntVb6(Arguments[0], out n)) {
									Debug.AddMessage(Debug.MessageType.Error, false, "Invalid argument n in " + Command + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
									n = 8;
								}
								if (n < 2) {
									Debug.AddMessage(Debug.MessageType.Error, false, "n is expected to be at least 2 in " + Command + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
									n = 8;
								}
								double r1 = 0.0, r2 = 0.0, h = 1.0;
								if (Arguments.Length >= 2 && Arguments[1].Length > 0 && !Conversions.TryParseDoubleVb6(Arguments[1], out r1)) {
									Debug.AddMessage(Debug.MessageType.Error, false, "Invalid argument UpperRadius in " + Command + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
									r1 = 1.0;
								}
								if (Arguments.Length >= 3 && Arguments[2].Length > 0 && !Conversions.TryParseDoubleVb6(Arguments[2], out r2)) {
									Debug.AddMessage(Debug.MessageType.Error, false, "Invalid argument LowerRadius in " + Command + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
									r2 = 1.0;
								}
								if (Arguments.Length >= 4 && Arguments[3].Length > 0 && !Conversions.TryParseDoubleVb6(Arguments[3], out h)) {
									Debug.AddMessage(Debug.MessageType.Error, false, "Invalid argument Height in " + Command + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
									h = 1.0;
								}
								CreateCylinder(ref Builder, n, r1, r2, h);
							} break;
						case "translate":
						case "translateall":
							{
								if (Arguments.Length > 3) {
									Debug.AddMessage(Debug.MessageType.Warning, false, "At most 3 arguments are expected in " + Command + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
								}
								double x = 0.0, y = 0.0, z = 0.0;
								if (Arguments.Length >= 1 && Arguments[0].Length > 0 && !Conversions.TryParseDoubleVb6(Arguments[0], out x)) {
									Debug.AddMessage(Debug.MessageType.Error, false, "Invalid argument X in " + Command + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
									x = 0.0;
								}
								if (Arguments.Length >= 2 && Arguments[1].Length > 0 && !Conversions.TryParseDoubleVb6(Arguments[1], out y)) {
									Debug.AddMessage(Debug.MessageType.Error, false, "Invalid argument Y in " + Command + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
									y = 0.0;
								}
								if (Arguments.Length >= 3 && Arguments[2].Length > 0 && !Conversions.TryParseDoubleVb6(Arguments[2], out z)) {
									Debug.AddMessage(Debug.MessageType.Error, false, "Invalid argument Z in " + Command + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
									z = 0.0;
								}
								ApplyTranslation(Builder, x, y, z);
								if (cmd == "translateall") {
									ApplyTranslation(Object, x, y, z);
								}
							} break;
						case "scale":
						case "scaleall":
							{
								if (Arguments.Length > 3) {
									Debug.AddMessage(Debug.MessageType.Warning, false, "At most 3 arguments are expected in " + Command + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
								}
								double x = 1.0, y = 1.0, z = 1.0;
								if (Arguments.Length >= 1 && Arguments[0].Length > 0 && !Conversions.TryParseDoubleVb6(Arguments[0], out x)) {
									Debug.AddMessage(Debug.MessageType.Error, false, "Invalid argument X in " + Command + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
									x = 1.0;
								} else if (x == 0.0) {
									Debug.AddMessage(Debug.MessageType.Error, false, "X is required to be different from zero in " + Command + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
									x = 1.0;
								}
								if (Arguments.Length >= 2 && Arguments[1].Length > 0 && !Conversions.TryParseDoubleVb6(Arguments[1], out y)) {
									Debug.AddMessage(Debug.MessageType.Error, false, "Invalid argument Y in " + Command + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
									y = 1.0;
								} else if (y == 0.0) {
									Debug.AddMessage(Debug.MessageType.Error, false, "Y is required to be different from zero in " + Command + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
									y = 1.0;
								}
								if (Arguments.Length >= 3 && Arguments[2].Length > 0 && !Conversions.TryParseDoubleVb6(Arguments[2], out z)) {
									Debug.AddMessage(Debug.MessageType.Error, false, "Invalid argument Z in " + Command + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
									z = 1.0;
								} else if (z == 0.0) {
									Debug.AddMessage(Debug.MessageType.Error, false, "Z is required to be different from zero in " + Command + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
									z = 1.0;
								}
								ApplyScale(Builder, x, y, z);
								if (cmd == "scaleall") {
									ApplyScale(Object, x, y, z);
								}
							} break;
						case "rotate":
						case "rotateall":
							{
								if (Arguments.Length > 4) {
									Debug.AddMessage(Debug.MessageType.Warning, false, "At most 4 arguments are expected in " + Command + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
								}
								double x = 0.0, y = 0.0, z = 0.0, a = 0.0;
								if (Arguments.Length >= 1 && Arguments[0].Length > 0 && !Conversions.TryParseDoubleVb6(Arguments[0], out x)) {
									Debug.AddMessage(Debug.MessageType.Error, false, "Invalid argument X in " + Command + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
									x = 0.0;
								}
								if (Arguments.Length >= 2 && Arguments[1].Length > 0 && !Conversions.TryParseDoubleVb6(Arguments[1], out y)) {
									Debug.AddMessage(Debug.MessageType.Error, false, "Invalid argument Y in " + Command + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
									y = 0.0;
								}
								if (Arguments.Length >= 3 && Arguments[2].Length > 0 && !Conversions.TryParseDoubleVb6(Arguments[2], out z)) {
									Debug.AddMessage(Debug.MessageType.Error, false, "Invalid argument Z in " + Command + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
									z = 0.0;
								}
								if (Arguments.Length >= 4 && Arguments[3].Length > 0 && !Conversions.TryParseDoubleVb6(Arguments[3], out a)) {
									Debug.AddMessage(Debug.MessageType.Error, false, "Invalid argument Angle in " + Command + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
									a = 0.0;
								}
								double t = x * x + y * y + z * z;
								if (t == 0.0) {
									x = 1.0;
									y = 0.0;
									z = 0.0;
									t = 1.0;
								}
								if (a != 0.0) {
									t = 1.0 / Math.Sqrt(t);
									x *= t;
									y *= t;
									z *= t;
									a *= 0.0174532925199433;
									ApplyRotation(Builder, x, y, z, a);
									if (cmd == "rotateall") {
										ApplyRotation(Object, x, y, z, a);
									}
								}
							} break;
						case "shear":
						case "shearall":
							{
								if (Arguments.Length > 7) {
									Debug.AddMessage(Debug.MessageType.Warning, false, "At most 7 arguments are expected in " + Command + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
								}
								double dx = 0.0, dy = 0.0, dz = 0.0;
								double sx = 0.0, sy = 0.0, sz = 0.0;
								double r = 0.0;
								if (Arguments.Length >= 1 && Arguments[0].Length > 0 && !Conversions.TryParseDoubleVb6(Arguments[0], out dx)) {
									Debug.AddMessage(Debug.MessageType.Error, false, "Invalid argument dX in " + Command + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
									dx = 0.0;
								}
								if (Arguments.Length >= 2 && Arguments[1].Length > 0 && !Conversions.TryParseDoubleVb6(Arguments[1], out dy)) {
									Debug.AddMessage(Debug.MessageType.Error, false, "Invalid argument dY in " + Command + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
									dy = 0.0;
								}
								if (Arguments.Length >= 3 && Arguments[2].Length > 0 && !Conversions.TryParseDoubleVb6(Arguments[2], out dz)) {
									Debug.AddMessage(Debug.MessageType.Error, false, "Invalid argument dZ in " + Command + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
									dz = 0.0;
								}
								if (Arguments.Length >= 4 && Arguments[3].Length > 0 && !Conversions.TryParseDoubleVb6(Arguments[3], out sx)) {
									Debug.AddMessage(Debug.MessageType.Error, false, "Invalid argument sX in " + Command + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
									sx = 0.0;
								}
								if (Arguments.Length >= 5 && Arguments[4].Length > 0 && !Conversions.TryParseDoubleVb6(Arguments[4], out sy)) {
									Debug.AddMessage(Debug.MessageType.Error, false, "Invalid argument sY in " + Command + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
									sy = 0.0;
								}
								if (Arguments.Length >= 6 && Arguments[5].Length > 0 && !Conversions.TryParseDoubleVb6(Arguments[5], out sz)) {
									Debug.AddMessage(Debug.MessageType.Error, false, "Invalid argument sZ in " + Command + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
									sz = 0.0;
								}
								if (Arguments.Length >= 7 && Arguments[6].Length > 0 && !Conversions.TryParseDoubleVb6(Arguments[6], out r)) {
									Debug.AddMessage(Debug.MessageType.Error, false, "Invalid argument Ratio in " + Command + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
									r = 0.0;
								}
								World.Normalize(ref dx, ref dy, ref dz);
								World.Normalize(ref sx, ref sy, ref sz);
								ApplyShear(Builder, dx, dy, dz, sx, sy, sz, r);
								if (cmd == "shearall") {
									ApplyShear(Object, dx, dy, dz, sx, sy, sz, r);
								}
							} break;
						case "generatenormals":
						case "[texture]":
							if (cmd == "generatenormals" & IsB3D) {
								Debug.AddMessage(Debug.MessageType.Warning, false, "GenerateNormals is not a supported command - did you mean [Texture]? - at line " + (i + 1).ToString(Culture) + " in file " + FileName);
							} else if (cmd == "[texture]" & !IsB3D) {
								Debug.AddMessage(Debug.MessageType.Warning, false, "[Texture] is not a supported command - did you mean GenerateNormals? - at line " + (i + 1).ToString(Culture) + " in file " + FileName);
							}
							// TODO do something?
							break;
						case "setcolor":
						case "color":
							{
								if (cmd == "setcolor" & IsB3D) {
									Debug.AddMessage(Debug.MessageType.Warning, false, "SetColor is not a supported command - did you mean Color? - at line " + (i + 1).ToString(Culture) + " in file " + FileName);
								} else if (cmd == "color" & !IsB3D) {
									Debug.AddMessage(Debug.MessageType.Warning, false, "Color is not a supported command - did you mean SetColor? - at line " + (i + 1).ToString(Culture) + " in file " + FileName);
								}
								if (Arguments.Length > 4) {
									Debug.AddMessage(Debug.MessageType.Warning, false, "At most 4 arguments are expected in " + Command + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
								}
								int r = 0, g = 0, b = 0, a = 255;
								if (Arguments.Length >= 1 && Arguments[0].Length > 0 && !Conversions.TryParseIntVb6(Arguments[0], out r)) {
									Debug.AddMessage(Debug.MessageType.Error, false, "Invalid argument Red in " + Command + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
									r = 0;
								} else if (r < 0 | r > 255) {
									Debug.AddMessage(Debug.MessageType.Error, false, "Red is required to be within the range from 0 to 255 in " + Command + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
									r = r < 0 ? 0 : 255;
								}
								if (Arguments.Length >= 2 && Arguments[1].Length > 0 && !Conversions.TryParseIntVb6(Arguments[1], out g)) {
									Debug.AddMessage(Debug.MessageType.Error, false, "Invalid argument Green in " + Command + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
									g = 0;
								} else if (g < 0 | g > 255) {
									Debug.AddMessage(Debug.MessageType.Error, false, "Green is required to be within the range from 0 to 255 in " + Command + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
									g = g < 0 ? 0 : 255;
								}
								if (Arguments.Length >= 3 && Arguments[2].Length > 0 && !Conversions.TryParseIntVb6(Arguments[2], out b)) {
									Debug.AddMessage(Debug.MessageType.Error, false, "Invalid argument Blue in " + Command + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
									b = 0;
								} else if (b < 0 | b > 255) {
									Debug.AddMessage(Debug.MessageType.Error, false, "Blue is required to be within the range from 0 to 255 in " + Command + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
									b = b < 0 ? 0 : 255;
								}
								if (Arguments.Length >= 4 && Arguments[3].Length > 0 && !Conversions.TryParseIntVb6(Arguments[3], out a)) {
									Debug.AddMessage(Debug.MessageType.Error, false, "Invalid argument Alpha in " + Command + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
									a = 255;
								} else if (a < 0 | a > 255) {
									Debug.AddMessage(Debug.MessageType.Error, false, "Alpha is required to be within the range from 0 to 255 in " + Command + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
									a = a < 0 ? 0 : 255;
								}
								int m = Builder.Materials.Length;
								Array.Resize<Material>(ref Builder.Materials, m << 1);
								for (int j = m; j < Builder.Materials.Length; j++) {
									Builder.Materials[j] = new Material(Builder.Materials[j - m]);
									Builder.Materials[j].Color = new Color32((byte)r, (byte)g, (byte)b, (byte)a);
									Builder.Materials[j].BlendMode = Builder.Materials[0].BlendMode;
									Builder.Materials[j].GlowAttenuationData = Builder.Materials[0].GlowAttenuationData;
									Builder.Materials[j].DaytimeTexture = Builder.Materials[0].DaytimeTexture;
									Builder.Materials[j].NighttimeTexture = Builder.Materials[0].NighttimeTexture;
									Builder.Materials[j].TransparentColor = Builder.Materials[0].TransparentColor;
									Builder.Materials[j].TransparentColorUsed = Builder.Materials[0].TransparentColorUsed;
								}
								for (int j = 0; j < Builder.Faces.Length; j++) {
									Builder.Faces[j].Material += (ushort)m;
								}
							} break;
						case "setemissivecolor":
						case "emissivecolor":
							{
								if (cmd == "setemissivecolor" & IsB3D) {
									Debug.AddMessage(Debug.MessageType.Warning, false, "SetEmissiveColor is not a supported command - did you mean EmissiveColor? - at line " + (i + 1).ToString(Culture) + " in file " + FileName);
								} else if (cmd == "emissivecolor" & !IsB3D) {
									Debug.AddMessage(Debug.MessageType.Warning, false, "EmissiveColor is not a supported command - did you mean SetEmissiveColor? - at line " + (i + 1).ToString(Culture) + " in file " + FileName);
								}
								if (Arguments.Length > 3) {
									Debug.AddMessage(Debug.MessageType.Warning, false, "At most 3 arguments are expected in " + Command + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
								}
								int r = 0, g = 0, b = 0;
								if (Arguments.Length >= 1 && Arguments[0].Length > 0 && !Conversions.TryParseIntVb6(Arguments[0], out r)) {
									Debug.AddMessage(Debug.MessageType.Error, false, "Invalid argument Red in " + Command + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
									r = 0;
								} else if (r < 0 | r > 255) {
									Debug.AddMessage(Debug.MessageType.Error, false, "Red is required to be within the range from 0 to 255 in " + Command + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
									r = r < 0 ? 0 : 255;
								}
								if (Arguments.Length >= 2 && Arguments[1].Length > 0 && !Conversions.TryParseIntVb6(Arguments[1], out g)) {
									Debug.AddMessage(Debug.MessageType.Error, false, "Invalid argument Green in " + Command + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
									g = 0;
								} else if (g < 0 | g > 255) {
									Debug.AddMessage(Debug.MessageType.Error, false, "Green is required to be within the range from 0 to 255 in " + Command + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
									g = g < 0 ? 0 : 255;
								}
								if (Arguments.Length >= 3 && Arguments[2].Length > 0 && !Conversions.TryParseIntVb6(Arguments[2], out b)) {
									Debug.AddMessage(Debug.MessageType.Error, false, "Invalid argument Blue in " + Command + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
									b = 0;
								} else if (b < 0 | b > 255) {
									Debug.AddMessage(Debug.MessageType.Error, false, "Blue is required to be within the range from 0 to 255 in " + Command + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
									b = b < 0 ? 0 : 255;
								}
								int m = Builder.Materials.Length;
								Array.Resize<Material>(ref Builder.Materials, m << 1);
								for (int j = m; j < Builder.Materials.Length; j++) {
									Builder.Materials[j] = new Material(Builder.Materials[j - m]);
									Builder.Materials[j].EmissiveColor = new Color24((byte)r, (byte)g, (byte)b);
									Builder.Materials[j].EmissiveColorUsed = true;
									Builder.Materials[j].BlendMode = Builder.Materials[0].BlendMode;
									Builder.Materials[j].GlowAttenuationData = Builder.Materials[0].GlowAttenuationData;
									Builder.Materials[j].DaytimeTexture = Builder.Materials[0].DaytimeTexture;
									Builder.Materials[j].NighttimeTexture = Builder.Materials[0].NighttimeTexture;
									Builder.Materials[j].TransparentColor = Builder.Materials[0].TransparentColor;
									Builder.Materials[j].TransparentColorUsed = Builder.Materials[0].TransparentColorUsed;
								}
								for (int j = 0; j < Builder.Faces.Length; j++) {
									Builder.Faces[j].Material += (ushort)m;
								}
							} break;
						case "setdecaltransparentcolor":
						case "transparent":
							{
								if (cmd == "setdecaltransparentcolor" & IsB3D) {
									Debug.AddMessage(Debug.MessageType.Warning, false, "SetDecalTransparentColor is not a supported command - did you mean Transparent? - at line " + (i + 1).ToString(Culture) + " in file " + FileName);
								} else if (cmd == "transparent" & !IsB3D) {
									Debug.AddMessage(Debug.MessageType.Warning, false, "Transparent is not a supported command - did you mean SetDecalTransparentColor? - at line " + (i + 1).ToString(Culture) + " in file " + FileName);
								}
								if (Arguments.Length > 3) {
									Debug.AddMessage(Debug.MessageType.Warning, false, "At most 3 arguments are expected in " + Command + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
								}
								int r = 0, g = 0, b = 0;
								if (Arguments.Length >= 1 && Arguments[0].Length > 0 && !Conversions.TryParseIntVb6(Arguments[0], out r)) {
									Debug.AddMessage(Debug.MessageType.Error, false, "Invalid argument Red in " + Command + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
									r = 0;
								} else if (r < 0 | r > 255) {
									Debug.AddMessage(Debug.MessageType.Error, false, "Red is required to be within the range from 0 to 255 in " + Command + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
									r = r < 0 ? 0 : 255;
								}
								if (Arguments.Length >= 2 && Arguments[1].Length > 0 && !Conversions.TryParseIntVb6(Arguments[1], out g)) {
									Debug.AddMessage(Debug.MessageType.Error, false, "Invalid argument Green in " + Command + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
									g = 0;
								} else if (g < 0 | g > 255) {
									Debug.AddMessage(Debug.MessageType.Error, false, "Green is required to be within the range from 0 to 255 in " + Command + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
									g = g < 0 ? 0 : 255;
								}
								if (Arguments.Length >= 3 && Arguments[2].Length > 0 && !Conversions.TryParseIntVb6(Arguments[2], out b)) {
									Debug.AddMessage(Debug.MessageType.Error, false, "Invalid argument Blue in " + Command + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
									b = 0;
								} else if (b < 0 | b > 255) {
									Debug.AddMessage(Debug.MessageType.Error, false, "Blue is required to be within the range from 0 to 255 in " + Command + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
									b = b < 0 ? 0 : 255;
								}
								for (int j = 0; j < Builder.Materials.Length; j++) {
									Builder.Materials[j].TransparentColor = new Color24((byte)r, (byte)g, (byte)b);
									Builder.Materials[j].TransparentColorUsed = true;
								}
							} break;
						case "setblendmode":
						case "blendmode":
							{
								if (cmd == "setblendmode" & IsB3D) {
									Debug.AddMessage(Debug.MessageType.Warning, false, "SetBlendMode is not a supported command - did you mean BlendMode? - at line " + (i + 1).ToString(Culture) + " in file " + FileName);
								} else if (cmd == "blendmode" & !IsB3D) {
									Debug.AddMessage(Debug.MessageType.Warning, false, "BlendMode is not a supported command - did you mean SetBlendMode? - at line " + (i + 1).ToString(Culture) + " in file " + FileName);
								}
								if (Arguments.Length > 3) {
									Debug.AddMessage(Debug.MessageType.Warning, false, "At most 3 arguments are expected in " + Command + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
								}
								World.MeshMaterialBlendMode blendmode = World.MeshMaterialBlendMode.Normal;
								if (Arguments.Length >= 1 && Arguments[0].Length > 0) {
									switch (Arguments[0].ToLowerInvariant()) {
										case "normal":
											blendmode = World.MeshMaterialBlendMode.Normal;
											break;
										case "additive":
											blendmode = World.MeshMaterialBlendMode.Additive;
											break;
										default:
											Debug.AddMessage(Debug.MessageType.Error, false, "The given BlendMode is not supported in " + Command + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
											blendmode = World.MeshMaterialBlendMode.Normal;
											break;
									}
								}
								double glowhalfdistance = 0.0;
								if (Arguments.Length >= 2 && Arguments[1].Length > 0 && !Conversions.TryParseDoubleVb6(Arguments[1], out glowhalfdistance)) {
									Debug.AddMessage(Debug.MessageType.Error, false, "Invalid argument GlowHalfDistance in " + Command + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
									glowhalfdistance = 0;
								}
								World.GlowAttenuationMode glowmode = World.GlowAttenuationMode.DivisionExponent4;
								if (Arguments.Length >= 3 && Arguments[2].Length > 0) {
									switch (Arguments[2].ToLowerInvariant()) {
											case "divideexponent2": glowmode = World.GlowAttenuationMode.DivisionExponent2; break;
											case "divideexponent4": glowmode = World.GlowAttenuationMode.DivisionExponent4; break;
										default:
											Debug.AddMessage(Debug.MessageType.Error, false, "The given GlowAttenuationMode is not supported in " + Command + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
											break;
									}
								}
								for (int j = 0; j < Builder.Materials.Length; j++) {
									Builder.Materials[j].BlendMode = blendmode;
									Builder.Materials[j].GlowAttenuationData = World.GetGlowAttenuationData(glowhalfdistance, glowmode);
								}
							} break;
						case "loadtexture":
						case "load":
							{
								if (cmd == "loadtexture" & IsB3D) {
									Debug.AddMessage(Debug.MessageType.Warning, false, "LoadTexture is not a supported command - did you mean Load? - at line " + (i + 1).ToString(Culture) + " in file " + FileName);
								} else if (cmd == "load" & !IsB3D) {
									Debug.AddMessage(Debug.MessageType.Warning, false, "Load is not a supported command - did you mean LoadTexture? - at line " + (i + 1).ToString(Culture) + " in file " + FileName);
								}
								if (Arguments.Length > 2) {
									Debug.AddMessage(Debug.MessageType.Warning, false, "At most 2 arguments are expected in " + Command + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
								}
								string tday = null, tnight = null;
								if (Arguments.Length >= 1 && Arguments[0].Length != 0) {
									if (OpenBveApi.Path.ContainsInvalidPathChars(Arguments[0])) {
										Debug.AddMessage(Debug.MessageType.Error, false, "DaytimeTexture contains illegal characters in " + Command + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
									} else {
										tday = OpenBveApi.Path.CombineFile(System.IO.Path.GetDirectoryName(FileName), Arguments[0]);
										if (!System.IO.File.Exists(tday)) {
											Debug.AddMessage(Debug.MessageType.Error, true, "DaytimeTexture " + tday + " could not be found in " + Command + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
											tday = null;
										}
									}
								}
								if (Arguments.Length >= 2 && Arguments[1].Length != 0) {
									if (Arguments[0].Length == 0) {
										Debug.AddMessage(Debug.MessageType.Error, true, "DaytimeTexture is required to be specified in " + Command + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
									} else {
										if (OpenBveApi.Path.ContainsInvalidPathChars(Arguments[1])) {
											Debug.AddMessage(Debug.MessageType.Error, false, "NighttimeTexture contains illegal characters in " + Command + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
										} else {
											tnight = OpenBveApi.Path.CombineFile(System.IO.Path.GetDirectoryName(FileName), Arguments[1]);
											if (!System.IO.File.Exists(tnight)) {
												Debug.AddMessage(Debug.MessageType.Error, true, "The NighttimeTexture " + tnight + " could not be found in " + Command + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
												tnight = null;
											}
										}
									}
								}
								for (int j = 0; j < Builder.Materials.Length; j++) {
									Builder.Materials[j].DaytimeTexture = tday;
									Builder.Materials[j].NighttimeTexture = tnight;
								}
							} break;
						case "settexturecoordinates":
						case "coordinates":
							{
								if (cmd == "settexturecoordinates" & IsB3D) {
									Debug.AddMessage(Debug.MessageType.Warning, false, "SetTextureCoordinates is not a supported command - did you mean Coordinates? - at line " + (i + 1).ToString(Culture) + " in file " + FileName);
								} else if (cmd == "coordinates" & !IsB3D) {
									Debug.AddMessage(Debug.MessageType.Warning, false, "Coordinates is not a supported command - did you mean SetTextureCoordinates? - at line " + (i + 1).ToString(Culture) + " in file " + FileName);
								}
								if (Arguments.Length > 3) {
									Debug.AddMessage(Debug.MessageType.Warning, false, "At most 3 arguments are expected in " + Command + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
								}
								int j = 0; float x = 0.0f, y = 0.0f;
								if (Arguments.Length >= 1 && Arguments[0].Length > 0 && !Conversions.TryParseIntVb6(Arguments[0], out j)) {
									Debug.AddMessage(Debug.MessageType.Error, false, "Invalid argument VertexIndex in " + Command + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
									j = 0;
								}
								if (Arguments.Length >= 2 && Arguments[1].Length > 0 && !Conversions.TryParseFloatVb6(Arguments[1], out x)) {
									Debug.AddMessage(Debug.MessageType.Error, false, "Invalid argument X in " + Command + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
									x = 0.0f;
								}
								if (Arguments.Length >= 3 && Arguments[2].Length > 0 && !Conversions.TryParseFloatVb6(Arguments[2], out y)) {
									Debug.AddMessage(Debug.MessageType.Error, false, "Invalid argument Y in " + Command + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
									y = 0.0f;
								}
								if (j >= 0 & j < Builder.Vertices.Length) {
									Builder.Vertices[j].TextureCoordinates = new Vector2f(x, y);
								} else {
									Debug.AddMessage(Debug.MessageType.Error, false, "VertexIndex references a non-existing vertex in " + Command + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
								}
							} break;
						default:
							if (Command.Length != 0) {
								Debug.AddMessage(Debug.MessageType.Error, false, "The command " + Command + " is not supported at line " + (i + 1).ToString(Culture) + " in file " + FileName);
							}
							break;
					}
				}
			}
			// finalize object
			ApplyMeshBuilder(ref Object, Builder, LoadMode, ForceTextureRepeatX, ForceTextureRepeatY);
			World.CreateNormals(ref Object.Mesh);
			return Object;
		}
Beispiel #36
0
        /// <summary>Jumps a train to a new station</summary>
        /// <param name="train">The train</param>
        /// <param name="stationIndex">The zero-based index of the station</param>
        internal static void JumpTrain(Train train, int stationIndex)
        {
            if (train.IsPlayerTrain)
            {
                for (int i = 0; i < ObjectManager.AnimatedWorldObjects.Length; i++)
                {
                    var obj = ObjectManager.AnimatedWorldObjects[i] as ObjectManager.TrackFollowingObject;
                    if (obj != null)
                    {
                        //Track followers should be reset if we jump between stations
                        obj.FrontAxleFollower.TrackPosition = ObjectManager.AnimatedWorldObjects[i].TrackPosition + obj.FrontAxlePosition;
                        obj.FrontAxleFollower.TrackPosition = ObjectManager.AnimatedWorldObjects[i].TrackPosition + obj.RearAxlePosition;
                        obj.FrontAxleFollower.UpdateWorldCoordinates(false);
                        obj.RearAxleFollower.UpdateWorldCoordinates(false);
                    }
                }
            }
            train.StationState = TrainStopState.Jumping;
            int stopIndex = CurrentRoute.Stations[stationIndex].GetStopIndex(train.NumberOfCars);

            if (stopIndex >= 0)
            {
                if (train.IsPlayerTrain)
                {
                    if (train.Plugin != null)
                    {
                        train.Plugin.BeginJump((OpenBveApi.Runtime.InitializationModes)Game.TrainStart);
                    }
                }
                for (int h = 0; h < train.Cars.Length; h++)
                {
                    train.Cars[h].CurrentSpeed = 0.0;
                }
                double d = CurrentRoute.Stations[stationIndex].Stops[stopIndex].TrackPosition - train.Cars[0].FrontAxle.Follower.TrackPosition + train.Cars[0].FrontAxle.Position - 0.5 * train.Cars[0].Length;
                if (train.IsPlayerTrain)
                {
                    TrackManager.SuppressSoundEvents = true;
                }
                while (d != 0.0)
                {
                    double x;
                    if (Math.Abs(d) > 1.0)
                    {
                        x = (double)Math.Sign(d);
                    }
                    else
                    {
                        x = d;
                    }
                    for (int h = 0; h < train.Cars.Length; h++)
                    {
                        train.Cars[h].Move(x);
                    }
                    if (Math.Abs(d) >= 1.0)
                    {
                        d -= x;
                    }
                    else
                    {
                        break;
                    }
                }
                if (train.IsPlayerTrain)
                {
                    TrainManager.UnderailTrains();
                    TrackManager.SuppressSoundEvents = false;
                }
                if (train.Handles.EmergencyBrake.Driver)
                {
                    train.ApplyNotch(0, false, 0, true);
                }
                else
                {
                    train.ApplyNotch(0, false, train.Handles.Brake.MaximumNotch, false);
                    train.ApplyAirBrakeHandle(TrainManager.AirBrakeHandleState.Service);
                }
                if (CurrentRoute.Sections.Length > 0)
                {
                    Game.UpdateSection(CurrentRoute.Sections.Length - 1);
                }
                if (train.IsPlayerTrain)
                {
                    if (Game.CurrentScore.ArrivalStation <= stationIndex)
                    {
                        Game.CurrentScore.ArrivalStation = stationIndex + 1;
                    }
                }
                if (train.IsPlayerTrain)
                {
                    if (CurrentRoute.Stations[stationIndex].ArrivalTime >= 0.0)
                    {
                        Game.SecondsSinceMidnight = CurrentRoute.Stations[stationIndex].ArrivalTime;
                    }
                    else if (CurrentRoute.Stations[stationIndex].DepartureTime >= 0.0)
                    {
                        Game.SecondsSinceMidnight = CurrentRoute.Stations[stationIndex].DepartureTime - CurrentRoute.Stations[stationIndex].StopTime;
                    }
                }
                for (int i = 0; i < train.Cars.Length; i++)
                {
                    train.Cars[i].Doors[0].AnticipatedOpen = CurrentRoute.Stations[stationIndex].OpenLeftDoors;
                    train.Cars[i].Doors[1].AnticipatedOpen = CurrentRoute.Stations[stationIndex].OpenRightDoors;
                }
                if (train.IsPlayerTrain)
                {
                    Game.CurrentScore.DepartureStation = stationIndex;
                    Game.CurrentInterface = Game.InterfaceType.Normal;
                    //Game.Messages = new Game.Message[] { };
                }
                ObjectManager.UpdateAnimatedWorldObjects(0.0, true);
                TrainManager.UpdateTrainObjects(0.0, true);
                if (train.IsPlayerTrain)
                {
                    if (train.Plugin != null)
                    {
                        train.Plugin.EndJump();
                    }
                }
                train.StationState = TrainStopState.Pending;
                if (train.IsPlayerTrain)
                {
                    train.LastStation = stationIndex;
                }
            }
        }
		private static void ApplyRotation(ObjectManager.StaticObject Object, double x, double y, double z, double a) {
			double cosa = Math.Cos(a);
			double sina = Math.Sin(a);
			for (int j = 0; j < Object.Mesh.Vertices.Length; j++) {
				World.Rotate(ref Object.Mesh.Vertices[j].Coordinates.X, ref Object.Mesh.Vertices[j].Coordinates.Y, ref Object.Mesh.Vertices[j].Coordinates.Z, x, y, z, cosa, sina);
			}
			for (int j = 0; j < Object.Mesh.Faces.Length; j++) {
				for (int k = 0; k < Object.Mesh.Faces[j].Vertices.Length; k++) {
					World.Rotate(ref Object.Mesh.Faces[j].Vertices[k].Normal.X, ref Object.Mesh.Faces[j].Vertices[k].Normal.Y, ref Object.Mesh.Faces[j].Vertices[k].Normal.Z, x, y, z, cosa, sina);
				}
			}
		}
Beispiel #38
0
		// process structure
		private static bool ProcessStructure(string FileName, Structure Structure, out ObjectManager.StaticObject Object, ObjectManager.ObjectLoadMode LoadMode, bool ForceTextureRepeatX, bool ForceTextureRepeatY) {
			System.Globalization.CultureInfo Culture = System.Globalization.CultureInfo.InvariantCulture;
			Object = new ObjectManager.StaticObject();
			Object.Mesh.Faces = new World.MeshFace[] { };
			Object.Mesh.Materials = new World.MeshMaterial[] { };
			Object.Mesh.Vertices = new World.Vertex[] { };
			// file
			for (int i = 0; i < Structure.Data.Length; i++) {
				Structure f = Structure.Data[i] as Structure;
				if (f == null) {
					Interface.AddMessage(Interface.MessageType.Error, false, "Top-level inlined arguments are invalid in x object file " + FileName);
					return false;
				}
				switch (f.Name) {
					case "Mesh":
						{
							// mesh
							if (f.Data.Length < 4) {
								Interface.AddMessage(Interface.MessageType.Error, false, "Mesh is expected to have at least 4 arguments in x object file " + FileName);
								return false;
							} else if (!(f.Data[0] is int)) {
								Interface.AddMessage(Interface.MessageType.Error, false, "nVertices is expected to be a DWORD in Mesh in x object file " + FileName);
								return false;
							} else if (!(f.Data[1] is Structure[])) {
								Interface.AddMessage(Interface.MessageType.Error, false, "vertices[nVertices] is expected to be a Vector array in Mesh in x object file " + FileName);
								return false;
							} else if (!(f.Data[2] is int)) {
								Interface.AddMessage(Interface.MessageType.Error, false, "nFaces is expected to be a DWORD in Mesh in x object file " + FileName);
								return false;
							} else if (!(f.Data[3] is Structure[])) {
								Interface.AddMessage(Interface.MessageType.Error, false, "faces[nFaces] is expected to be a MeshFace array in Mesh in x object file " + FileName);
								return false;
							}
							int nVertices = (int)f.Data[0];
							if (nVertices < 0) {
								Interface.AddMessage(Interface.MessageType.Error, false, "nVertices is expected to be non-negative in Mesh in x object file " + FileName);
								return false;
							}
							Structure[] vertices = (Structure[])f.Data[1];
							if (nVertices != vertices.Length) {
								Interface.AddMessage(Interface.MessageType.Error, false, "nVertices does not match with the length of array vertices in Mesh in x object file " + FileName);
								return false;
							}
							int nFaces = (int)f.Data[2];
							if (nFaces < 0) {
								Interface.AddMessage(Interface.MessageType.Error, false, "nFaces is expected to be non-negative in Mesh in x object file " + FileName);
								return false;
							}
							Structure[] faces = (Structure[])f.Data[3];
							if (nFaces != faces.Length) {
								Interface.AddMessage(Interface.MessageType.Error, false, "nFaces does not match with the length of array faces in Mesh in x object file " + FileName);
								return false;
							}
							// collect vertices
							World.Vertex[] Vertices = new World.Vertex[nVertices];
							for (int j = 0; j < nVertices; j++) {
								if (vertices[j].Name != "Vector") {
									Interface.AddMessage(Interface.MessageType.Error, false, "vertices[" + j.ToString(Culture) + "] is expected to be of template Vertex in Mesh in x object file " + FileName);
									return false;
								} else if (vertices[j].Data.Length != 3) {
									Interface.AddMessage(Interface.MessageType.Error, false, "vertices[" + j.ToString(Culture) + "] is expected to have 3 arguments in Mesh in x object file " + FileName);
									return false;
								} else if (!(vertices[j].Data[0] is double)) {
									Interface.AddMessage(Interface.MessageType.Error, false, "x is expected to be a float in vertices[" + j.ToString(Culture) + "] in Mesh in x object file " + FileName);
									return false;
								} else if (!(vertices[j].Data[1] is double)) {
									Interface.AddMessage(Interface.MessageType.Error, false, "y is expected to be a float in vertices[" + j.ToString(Culture) + "] in Mesh in x object file " + FileName);
									return false;
								} else if (!(vertices[j].Data[2] is double)) {
									Interface.AddMessage(Interface.MessageType.Error, false, "z is expected to be a float in vertices[" + j.ToString(Culture) + "] in Mesh in x object file " + FileName);
									return false;
								}
								double x = (double)vertices[j].Data[0];
								double y = (double)vertices[j].Data[1];
								double z = (double)vertices[j].Data[2];
								Vertices[j].Coordinates = new World.Vector3D(x, y, z);
							}
							// collect faces
							int[][] Faces = new int[nFaces][];
							World.Vector3Df[][] FaceNormals = new World.Vector3Df[nFaces][];
							int[] FaceMaterials = new int[nFaces];
							for (int j = 0; j < nFaces; j++) {
								FaceMaterials[j] = -1;
							}
							for (int j = 0; j < nFaces; j++) {
								if (faces[j].Name != "MeshFace") {
									Interface.AddMessage(Interface.MessageType.Error, false, "faces[" + j.ToString(Culture) + "] is expected to be of template MeshFace in Mesh in x object file " + FileName);
									return false;
								} else if (faces[j].Data.Length != 2) {
									Interface.AddMessage(Interface.MessageType.Error, false, "face[" + j.ToString(Culture) + "] is expected to have 2 arguments in Mesh in x object file " + FileName);
									return false;
								} else if (!(faces[j].Data[0] is int)) {
									Interface.AddMessage(Interface.MessageType.Error, false, "nFaceVertexIndices is expected to be a DWORD in face[" + j.ToString(Culture) + "] in Mesh in x object file " + FileName);
									return false;
								} else if (!(faces[j].Data[1] is int[])) {
									Interface.AddMessage(Interface.MessageType.Error, false, "faceVertexIndices[nFaceVertexIndices] is expected to be a DWORD array in face[" + j.ToString(Culture) + "] in Mesh in x object file " + FileName);
									return false;
								}
								int nFaceVertexIndices = (int)faces[j].Data[0];
								if (nFaceVertexIndices < 0) {
									Interface.AddMessage(Interface.MessageType.Error, false, "nFaceVertexIndices is expected to be non-negative in MeshFace in Mesh in x object file " + FileName);
									return false;
								}
								int[] faceVertexIndices = (int[])faces[j].Data[1];
								if (nFaceVertexIndices != faceVertexIndices.Length) {
									Interface.AddMessage(Interface.MessageType.Error, false, "nFaceVertexIndices does not match with the length of array faceVertexIndices in face[" + j.ToString(Culture) + "] in Mesh in x object file " + FileName);
									return false;
								}
								Faces[j] = new int[nFaceVertexIndices];
								FaceNormals[j] = new World.Vector3Df[nFaceVertexIndices];
								for (int k = 0; k < nFaceVertexIndices; k++) {
									if (faceVertexIndices[k] < 0 | faceVertexIndices[k] >= nVertices) {
										Interface.AddMessage(Interface.MessageType.Error, false, "faceVertexIndices[" + k.ToString(Culture) + "] does not reference a valid vertex in face[" + j.ToString(Culture) + "] in Mesh in x object file " + FileName);
										return false;
									}
									Faces[j][k] = faceVertexIndices[k];
									FaceNormals[j][k] = new World.Vector3Df(0.0f, 0.0f, 0.0f);
								}
							}
							// collect additional templates
							Material[] Materials = new Material[] { };
							for (int j = 4; j < f.Data.Length; j++) {
								Structure g = f.Data[j] as Structure;
								if (g == null) {
									Interface.AddMessage(Interface.MessageType.Error, false, "Unexpected inlined argument encountered in Mesh in x object file " + FileName);
									return false;
								}
								switch (g.Name) {
									case "MeshMaterialList":
										{
											// meshmateriallist
											if (g.Data.Length < 3) {
												Interface.AddMessage(Interface.MessageType.Error, false, "MeshMaterialList is expected to have at least 3 arguments in Mesh in x object file " + FileName);
												return false;
											} else if (!(g.Data[0] is int)) {
												Interface.AddMessage(Interface.MessageType.Error, false, "nMaterials is expected to be a DWORD in MeshMaterialList in Mesh in x object file " + FileName);
												return false;
											} else if (!(g.Data[1] is int)) {
												Interface.AddMessage(Interface.MessageType.Error, false, "nFaceIndexes is expected to be a DWORD in MeshMaterialList in Mesh in x object file " + FileName);
												return false;
											} else if (!(g.Data[2] is int[])) {
												Interface.AddMessage(Interface.MessageType.Error, false, "faceIndexes[nFaceIndexes] is expected to be a DWORD array in MeshMaterialList in Mesh in x object file " + FileName);
												return false;
											}
											int nMaterials = (int)g.Data[0];
											if (nMaterials < 0) {
												Interface.AddMessage(Interface.MessageType.Error, false, "nMaterials is expected to be non-negative in MeshMaterialList in Mesh in x object file " + FileName);
												return false;
											}
											int nFaceIndexes = (int)g.Data[1];
											if (nFaceIndexes < 0) {
												Interface.AddMessage(Interface.MessageType.Error, false, "nFaceIndexes is expected to be non-negative in MeshMaterialList in Mesh in x object file " + FileName);
												return false;
											} else if (nFaceIndexes > nFaces) {
												Interface.AddMessage(Interface.MessageType.Error, false, "nFaceIndexes does not reference valid faces in MeshMaterialList in Mesh in x object file " + FileName);
												return false;
											}
											int[] faceIndexes = (int[])g.Data[2];
											if (nFaceIndexes != faceIndexes.Length) {
												Interface.AddMessage(Interface.MessageType.Error, false, "nFaceIndexes does not match with the length of array faceIndexes in face[" + j.ToString(Culture) + "] in Mesh in x object file " + FileName);
												return false;
											}
											for (int k = 0; k < nFaceIndexes; k++) {
												if (faceIndexes[k] < 0 | faceIndexes[k] >= nMaterials) {
													Interface.AddMessage(Interface.MessageType.Error, false, "faceIndexes[" + k.ToString(Culture) + "] does not reference a valid Material template in MeshMaterialList in Mesh in x object file " + FileName);
													return false;
												}
											}
											// collect material templates
											int mn = Materials.Length;
											Array.Resize<Material>(ref Materials, mn + nMaterials);
											for (int k = 0; k < nMaterials; k++) {
												Materials[mn + k].faceColor = new World.ColorRGBA(255, 255, 255, 255);
												Materials[mn + k].specularColor = new World.ColorRGB(0, 0, 0);
												Materials[mn + k].emissiveColor = new World.ColorRGB(0, 0, 0);
												Materials[mn + k].TextureFilename = null;
											}
											int MaterialIndex = mn;
											for (int k = 3; k < g.Data.Length; k++) {
												Structure h = g.Data[k] as Structure;
												if (h == null) {
													Interface.AddMessage(Interface.MessageType.Error, false, "Unexpected inlined argument encountered in MeshMaterialList in Mesh in x object file " + FileName);
													return false;
												} else if (h.Name != "Material") {
													Interface.AddMessage(Interface.MessageType.Error, false, "Material template expected in MeshMaterialList in Mesh in x object file " + FileName);
													return false;
												} else {
													// material
													if (h.Data.Length < 4) {
														Interface.AddMessage(Interface.MessageType.Error, false, "Material is expected to have at least 4 arguments in Material in MeshMaterialList in Mesh in x object file " + FileName);
														return false;
													} else if (!(h.Data[0] is Structure)) {
														Interface.AddMessage(Interface.MessageType.Error, false, "faceColor is expected to be a ColorRGBA in Material in MeshMaterialList in Mesh in x object file " + FileName);
														return false;
													} else if (!(h.Data[1] is double)) {
														Interface.AddMessage(Interface.MessageType.Error, false, "power is expected to be a float in Material in MeshMaterialList in Mesh in x object file " + FileName);
														return false;
													} else if (!(h.Data[2] is Structure)) {
														Interface.AddMessage(Interface.MessageType.Error, false, "specularColor is expected to be a ColorRGBA in Material in MeshMaterialList in Mesh in x object file " + FileName);
														return false;
													} else if (!(h.Data[3] is Structure)) {
														Interface.AddMessage(Interface.MessageType.Error, false, "emissiveColor is expected to be a ColorRGBA in Material in MeshMaterialList in Mesh in x object file " + FileName);
														return false;
													}
													Structure faceColor = (Structure)h.Data[0];
													Structure specularColor = (Structure)h.Data[2];
													Structure emissiveColor = (Structure)h.Data[3];
													double red, green, blue, alpha;
													// collect face color
													if (faceColor.Name != "ColorRGBA") {
														Interface.AddMessage(Interface.MessageType.Error, false, "faceColor is expected to be a ColorRGBA in Material in MeshMaterialList in Mesh in x object file " + FileName);
														return false;
													} else if (faceColor.Data.Length != 4) {
														Interface.AddMessage(Interface.MessageType.Error, false, "faceColor is expected to have 4 arguments in Material in MeshMaterialList in Mesh in x object file " + FileName);
														return false;
													} else if (!(faceColor.Data[0] is double)) {
														Interface.AddMessage(Interface.MessageType.Error, false, "red is expected to be a float in faceColor in Material in MeshMaterialList in Mesh in x object file " + FileName);
														return false;
													} else if (!(faceColor.Data[1] is double)) {
														Interface.AddMessage(Interface.MessageType.Error, false, "green is expected to be a float in faceColor in Material in MeshMaterialList in Mesh in x object file " + FileName);
														return false;
													} else if (!(faceColor.Data[2] is double)) {
														Interface.AddMessage(Interface.MessageType.Error, false, "blue is expected to be a float in faceColor in Material in MeshMaterialList in Mesh in x object file " + FileName);
														return false;
													} else if (!(faceColor.Data[3] is double)) {
														Interface.AddMessage(Interface.MessageType.Error, false, "alpha is expected to be a float in faceColor in Material in MeshMaterialList in Mesh in x object file " + FileName);
														return false;
													}
													red = (double)faceColor.Data[0];
													green = (double)faceColor.Data[1];
													blue = (double)faceColor.Data[2];
													alpha = (double)faceColor.Data[3];
													if (red < 0.0 | red > 1.0) {
														Interface.AddMessage(Interface.MessageType.Error, false, "red is expected to be in the range from 0.0 to 1.0 in faceColor in Material in MeshMaterialList in Mesh in x object file " + FileName);
														red = red < 0.5 ? 0.0 : 1.0;
													}
													if (green < 0.0 | green > 1.0) {
														Interface.AddMessage(Interface.MessageType.Error, false, "green is expected to be in the range from 0.0 to 1.0 in faceColor in Material in MeshMaterialList in Mesh in x object file " + FileName);
														green = green < 0.5 ? 0.0 : 1.0;
													}
													if (blue < 0.0 | blue > 1.0) {
														Interface.AddMessage(Interface.MessageType.Error, false, "blue is expected to be in the range from 0.0 to 1.0 in faceColor in Material in MeshMaterialList in Mesh in x object file " + FileName);
														blue = blue < 0.5 ? 0.0 : 1.0;
													}
													if (alpha < 0.0 | alpha > 1.0) {
														Interface.AddMessage(Interface.MessageType.Error, false, "alpha is expected to be in the range from 0.0 to 1.0 in faceColor in Material in MeshMaterialList in Mesh in x object file " + FileName);
														alpha = alpha < 0.5 ? 0.0 : 1.0;
													}
													Materials[MaterialIndex].faceColor = new World.ColorRGBA((byte)Math.Round(255.0 * red), (byte)Math.Round(255.0 * green), (byte)Math.Round(255.0 * blue), (byte)Math.Round(255.0 * alpha));
													// collect specular color
													if (specularColor.Name != "ColorRGB") {
														Interface.AddMessage(Interface.MessageType.Error, false, "specularColor is expected to be a ColorRGB in Material in MeshMaterialList in Mesh in x object file " + FileName);
														return false;
													} else if (specularColor.Data.Length != 3) {
														Interface.AddMessage(Interface.MessageType.Error, false, "specularColor is expected to have 3 arguments in Material in MeshMaterialList in Mesh in x object file " + FileName);
														return false;
													} else if (!(specularColor.Data[0] is double)) {
														Interface.AddMessage(Interface.MessageType.Error, false, "red is expected to be a float in specularColor in Material in MeshMaterialList in Mesh in x object file " + FileName);
														return false;
													} else if (!(specularColor.Data[1] is double)) {
														Interface.AddMessage(Interface.MessageType.Error, false, "green is expected to be a float in specularColor in Material in MeshMaterialList in Mesh in x object file " + FileName);
														return false;
													} else if (!(specularColor.Data[2] is double)) {
														Interface.AddMessage(Interface.MessageType.Error, false, "blue is expected to be a float in specularColor in Material in MeshMaterialList in Mesh in x object file " + FileName);
														return false;
													}
													red = (double)specularColor.Data[0];
													green = (double)specularColor.Data[1];
													blue = (double)specularColor.Data[2];
													if (red < 0.0 | red > 1.0) {
														Interface.AddMessage(Interface.MessageType.Error, false, "red is expected to be in the range from 0.0 to 1.0 in specularColor in Material in MeshMaterialList in Mesh in x object file " + FileName);
														red = red < 0.5 ? 0.0 : 1.0;
													}
													if (green < 0.0 | green > 1.0) {
														Interface.AddMessage(Interface.MessageType.Error, false, "green is expected to be in the range from 0.0 to 1.0 in specularColor in Material in MeshMaterialList in Mesh in x object file " + FileName);
														green = green < 0.5 ? 0.0 : 1.0;
													}
													if (blue < 0.0 | blue > 1.0) {
														Interface.AddMessage(Interface.MessageType.Error, false, "blue is expected to be in the range from 0.0 to 1.0 in specularColor in Material in MeshMaterialList in Mesh in x object file " + FileName);
														blue = blue < 0.5 ? 0.0 : 1.0;
													}
													Materials[MaterialIndex].specularColor = new World.ColorRGB((byte)Math.Round(255.0 * red), (byte)Math.Round(255.0 * green), (byte)Math.Round(255.0 * blue));
													// collect emissive color
													if (emissiveColor.Name != "ColorRGB") {
														Interface.AddMessage(Interface.MessageType.Error, false, "emissiveColor is expected to be a ColorRGBA in Material in MeshMaterialList in Mesh in x object file " + FileName);
														return false;
													} else if (emissiveColor.Data.Length != 3) {
														Interface.AddMessage(Interface.MessageType.Error, false, "emissiveColor is expected to have 3 arguments in Material in MeshMaterialList in Mesh in x object file " + FileName);
														return false;
													} else if (!(emissiveColor.Data[0] is double)) {
														Interface.AddMessage(Interface.MessageType.Error, false, "red is expected to be a float in emissiveColor in Material in MeshMaterialList in Mesh in x object file " + FileName);
														return false;
													} else if (!(emissiveColor.Data[1] is double)) {
														Interface.AddMessage(Interface.MessageType.Error, false, "green is expected to be a float in emissiveColor in Material in MeshMaterialList in Mesh in x object file " + FileName);
														return false;
													} else if (!(emissiveColor.Data[2] is double)) {
														Interface.AddMessage(Interface.MessageType.Error, false, "blue is expected to be a float in emissiveColor in Material in MeshMaterialList in Mesh in x object file " + FileName);
														return false;
													}
													red = (double)emissiveColor.Data[0];
													green = (double)emissiveColor.Data[1];
													blue = (double)emissiveColor.Data[2];
													if (red < 0.0 | red > 1.0) {
														Interface.AddMessage(Interface.MessageType.Error, false, "red is expected to be in the range from 0.0 to 1.0 in emissiveColor in Material in MeshMaterialList in Mesh in x object file " + FileName);
														red = red < 0.5 ? 0.0 : 1.0;
													}
													if (green < 0.0 | green > 1.0) {
														Interface.AddMessage(Interface.MessageType.Error, false, "green is expected to be in the range from 0.0 to 1.0 in emissiveColor in Material in MeshMaterialList in Mesh in x object file " + FileName);
														green = green < 0.5 ? 0.0 : 1.0;
													}
													if (blue < 0.0 | blue > 1.0) {
														Interface.AddMessage(Interface.MessageType.Error, false, "blue is expected to be in the range from 0.0 to 1.0 in emissiveColor in Material in MeshMaterialList in Mesh in x object file " + FileName);
														blue = blue < 0.5 ? 0.0 : 1.0;
													}
													Materials[MaterialIndex].emissiveColor = new World.ColorRGB((byte)Math.Round(255.0 * red), (byte)Math.Round(255.0 * green), (byte)Math.Round(255.0 * blue));
													// collect additional templates
													for (int l = 4; l < h.Data.Length; l++) {
														Structure e = h.Data[l] as Structure;
														if (e == null) {
															Interface.AddMessage(Interface.MessageType.Error, false, "Unexpected inlined argument encountered in Material in MeshMaterialList in Mesh in x object file " + FileName);
															return false;
														}
														switch (e.Name) {
															case "TextureFilename":
																{
																	// texturefilename
																	if (e.Data.Length != 1) {
																		Interface.AddMessage(Interface.MessageType.Error, false, "filename is expected to have 1 argument in TextureFilename in Material in MeshMaterialList in Mesh in x object file " + FileName);
																		return false;
																	} else if (!(e.Data[0] is string)) {
																		Interface.AddMessage(Interface.MessageType.Error, false, "filename is expected to be a string in TextureFilename in Material in MeshMaterialList in Mesh in x object file " + FileName);
																		return false;
																	}
																	string filename = (string)e.Data[0];
																	if (Interface.ContainsInvalidPathChars(filename)) {
																		Interface.AddMessage(Interface.MessageType.Error, false, "filename contains illegal characters in TextureFilename in Material in MeshMaterialList in Mesh in x object file " + FileName);
																	} else {
																		string File = OpenBveApi.Path.CombineFile(System.IO.Path.GetDirectoryName(FileName), filename);
																		if (System.IO.File.Exists(File)) {
																			Materials[MaterialIndex].TextureFilename = File;
																		} else {
																			Interface.AddMessage(Interface.MessageType.Error, true, "The texture file " + File + " could not be found in TextureFilename in Material in MeshMaterialList in Mesh in x object file " + FileName);
																		}
																	}
																} break;
															default:
																// unknown
																Interface.AddMessage(Interface.MessageType.Warning, false, "Unsupported template " + e.Name + " encountered in MeshMaterialList in Mesh in x object file " + FileName);
																break;
														}
													}
													// finish
													MaterialIndex++;
												}
											} if (MaterialIndex != mn + nMaterials) {
												Interface.AddMessage(Interface.MessageType.Error, false, "nMaterials does not match the number of Material templates encountered in Material in MeshMaterialList in Mesh in x object file " + FileName);
												return false;
											}
											// assign materials
											for (int k = 0; k < nFaceIndexes; k++) {
												FaceMaterials[k] = faceIndexes[k];
											}
											if (nMaterials != 0) {
												for (int k = 0; k < nFaces; k++) {
													if (FaceMaterials[k] == -1) {
														FaceMaterials[k] = 0;
													}
												}
											}
										} break;
									case "MeshTextureCoords":
										{
											// meshtexturecoords
											if (g.Data.Length != 2) {
												Interface.AddMessage(Interface.MessageType.Error, false, "MeshTextureCoords is expected to have 2 arguments in Mesh in x object file " + FileName);
												return false;
											} else if (!(g.Data[0] is int)) {
												Interface.AddMessage(Interface.MessageType.Error, false, "nTextureCoords is expected to be a DWORD in MeshTextureCoords in Mesh in x object file " + FileName);
												return false;
											} else if (!(g.Data[1] is Structure[])) {
												Interface.AddMessage(Interface.MessageType.Error, false, "textureCoords[nTextureCoords] is expected to be a Coords2d array in MeshTextureCoords in Mesh in x object file " + FileName);
												return false;
											}
											int nTextureCoords = (int)g.Data[0];
											Structure[] textureCoords = (Structure[])g.Data[1];
											if (nTextureCoords < 0 | nTextureCoords > nVertices) {
												Interface.AddMessage(Interface.MessageType.Error, false, "nTextureCoords does not reference valid vertices in MeshTextureCoords in Mesh in x object file " + FileName);
												return false;
											}
											for (int k = 0; k < nTextureCoords; k++) {
												if (textureCoords[k].Name != "Coords2d") {
													Interface.AddMessage(Interface.MessageType.Error, false, "textureCoords[" + k.ToString(Culture) + "] is expected to be a Coords2d in MeshTextureCoords in Mesh in x object file " + FileName);
													return false;
												} else if (textureCoords[k].Data.Length != 2) {
													Interface.AddMessage(Interface.MessageType.Error, false, "textureCoords[" + k.ToString(Culture) + "] is expected to have 2 arguments in MeshTextureCoords in Mesh in x object file " + FileName);
													return false;
												} else if (!(textureCoords[k].Data[0] is double)) {
													Interface.AddMessage(Interface.MessageType.Error, false, "u is expected to be a float in textureCoords[" + k.ToString(Culture) + "] in MeshTextureCoords in Mesh in x object file " + FileName);
													return false;
												} else if (!(textureCoords[k].Data[1] is double)) {
													Interface.AddMessage(Interface.MessageType.Error, false, "v is expected to be a float in textureCoords[" + k.ToString(Culture) + "] in MeshTextureCoords in Mesh in x object file " + FileName);
													return false;
												}
												double u = (double)textureCoords[k].Data[0];
												double v = (double)textureCoords[k].Data[1];
												Vertices[k].TextureCoordinates = new World.Vector2Df((float)u, (float)v);
											}
										} break;
									case "MeshNormals":
										{
											// meshnormals
											if (g.Data.Length != 4) {
												Interface.AddMessage(Interface.MessageType.Error, false, "MeshNormals is expected to have 4 arguments in Mesh in x object file " + FileName);
												return false;
											} else if (!(g.Data[0] is int)) {
												Interface.AddMessage(Interface.MessageType.Error, false, "nNormals is expected to be a DWORD in MeshNormals in Mesh in x object file " + FileName);
												return false;
											} else if (!(g.Data[1] is Structure[])) {
												Interface.AddMessage(Interface.MessageType.Error, false, "normals is expected to be a Vector array in MeshNormals in Mesh in x object file " + FileName);
												return false;
											} else if (!(g.Data[2] is int)) {
												Interface.AddMessage(Interface.MessageType.Error, false, "nFaceNormals is expected to be a DWORD in MeshNormals in Mesh in x object file " + FileName);
												return false;
											} else if (!(g.Data[3] is Structure[])) {
												Interface.AddMessage(Interface.MessageType.Error, false, "faceNormals is expected to be a MeshFace array in MeshNormals in Mesh in x object file " + FileName);
												return false;
											}
											int nNormals = (int)g.Data[0];
											if (nNormals < 0) {
												Interface.AddMessage(Interface.MessageType.Error, false, "nNormals is expected to be non-negative in MeshNormals in Mesh in x object file " + FileName);
												return false;
											}
											Structure[] normals = (Structure[])g.Data[1];
											if (nNormals != normals.Length) {
												Interface.AddMessage(Interface.MessageType.Error, false, "nNormals does not match with the length of array normals in MeshNormals in Mesh in x object file " + FileName);
												return false;
											}
											int nFaceNormals = (int)g.Data[2];
											if (nFaceNormals < 0 | nFaceNormals > nFaces) {
												Interface.AddMessage(Interface.MessageType.Error, false, "nNormals does not reference valid vertices in MeshNormals in Mesh in x object file " + FileName);
												return false;
											}
											Structure[] faceNormals = (Structure[])g.Data[3];
											if (nFaceNormals != faceNormals.Length) {
												Interface.AddMessage(Interface.MessageType.Error, false, "nFaceNormals does not match with the length of array faceNormals in MeshNormals in Mesh in x object file " + FileName);
												return false;
											}
											// collect normals
											World.Vector3Df[] Normals = new World.Vector3Df[nNormals];
											for (int k = 0; k < nNormals; k++) {
												if (normals[k].Name != "Vector") {
													Interface.AddMessage(Interface.MessageType.Error, false, "normals[" + k.ToString(Culture) + "] is expected to be of template Vertex in MeshNormals in Mesh in x object file " + FileName);
													return false;
												} else if (normals[k].Data.Length != 3) {
													Interface.AddMessage(Interface.MessageType.Error, false, "normals[" + k.ToString(Culture) + "] is expected to have 3 arguments in MeshNormals in Mesh in x object file " + FileName);
													return false;
												} else if (!(normals[k].Data[0] is double)) {
													Interface.AddMessage(Interface.MessageType.Error, false, "x is expected to be a float in normals[" + k.ToString(Culture) + "] in MeshNormals in Mesh in x object file " + FileName);
													return false;
												} else if (!(normals[k].Data[1] is double)) {
													Interface.AddMessage(Interface.MessageType.Error, false, "y is expected to be a float in normals[" + k.ToString(Culture) + " ]in MeshNormals in Mesh in x object file " + FileName);
													return false;
												} else if (!(normals[k].Data[2] is double)) {
													Interface.AddMessage(Interface.MessageType.Error, false, "z is expected to be a float in normals[" + k.ToString(Culture) + "] in MeshNormals in Mesh in x object file " + FileName);
													return false;
												}
												double x = (double)normals[k].Data[0];
												double y = (double)normals[k].Data[1];
												double z = (double)normals[k].Data[2];
												World.Normalize(ref x, ref y, ref z);
												Normals[k] = new World.Vector3Df((float)x, (float)y, (float)z);
											}
											// collect faces
											for (int k = 0; k < nFaceNormals; k++) {
												if (faceNormals[k].Name != "MeshFace") {
													Interface.AddMessage(Interface.MessageType.Error, false, "faceNormals[" + k.ToString(Culture) + "] is expected to be of template MeshFace in MeshNormals in Mesh in x object file " + FileName);
													return false;
												} else if (faceNormals[k].Data.Length != 2) {
													Interface.AddMessage(Interface.MessageType.Error, false, "faceNormals[" + k.ToString(Culture) + "] is expected to have 2 arguments in MeshNormals in Mesh in x object file " + FileName);
													return false;
												} else if (!(faceNormals[k].Data[0] is int)) {
													Interface.AddMessage(Interface.MessageType.Error, false, "nFaceVertexIndices is expected to be a DWORD in faceNormals[" + k.ToString(Culture) + "] in MeshNormals in Mesh in x object file " + FileName);
													return false;
												} else if (!(faceNormals[k].Data[1] is int[])) {
													Interface.AddMessage(Interface.MessageType.Error, false, "faceVertexIndices[nFaceVertexIndices] is expected to be a DWORD array in faceNormals[" + k.ToString(Culture) + "] in MeshNormals in Mesh in x object file " + FileName);
													return false;
												}
												int nFaceVertexIndices = (int)faceNormals[k].Data[0];
												if (nFaceVertexIndices < 0 | nFaceVertexIndices > Faces[k].Length) {
													Interface.AddMessage(Interface.MessageType.Error, false, "nFaceVertexIndices does not reference a valid vertex in MeshFace in MeshNormals in Mesh in x object file " + FileName);
													return false;
												}
												int[] faceVertexIndices = (int[])faceNormals[k].Data[1];
												if (nFaceVertexIndices != faceVertexIndices.Length) {
													Interface.AddMessage(Interface.MessageType.Error, false, "nFaceVertexIndices does not match with the length of array faceVertexIndices in faceNormals[" + k.ToString(Culture) + "] in MeshFace in MeshNormals in Mesh in x object file " + FileName);
													return false;
												}
												for (int l = 0; l < nFaceVertexIndices; l++) {
													if (faceVertexIndices[l] < 0 | faceVertexIndices[l] >= nNormals) {
														Interface.AddMessage(Interface.MessageType.Error, false, "faceVertexIndices[" + l.ToString(Culture) + "] does not reference a valid normal in faceNormals[" + k.ToString(Culture) + "] in MeshFace in MeshNormals in Mesh in x object file " + FileName);
														return false;
													}
													FaceNormals[k][l] = Normals[faceVertexIndices[l]];
												}
											}
										} break;
									default:
										// unknown
										Interface.AddMessage(Interface.MessageType.Warning, false, "Unsupported template " + g.Name + " encountered in Mesh in x object file " + FileName);
										break;

								}
							}
							// default material
							if (Materials.Length == 0) {
								Materials = new Material[1];
								Materials[0].faceColor = new World.ColorRGBA(255, 255, 255, 255);
								Materials[0].emissiveColor = new World.ColorRGB(0, 0, 0);
								Materials[0].specularColor = new World.ColorRGB(0, 0, 0);
								Materials[0].TextureFilename = null;
								for (int j = 0; j < nFaces; j++) {
									FaceMaterials[j] = 0;
								}
							}
							// create mesh
							int mf = Object.Mesh.Faces.Length;
							int mm = Object.Mesh.Materials.Length;
							int mv = Object.Mesh.Vertices.Length;
							Array.Resize<World.MeshFace>(ref Object.Mesh.Faces, mf + nFaces);
							Array.Resize<World.MeshMaterial>(ref Object.Mesh.Materials, mm + Materials.Length);
							Array.Resize<World.Vertex>(ref Object.Mesh.Vertices, mv + Vertices.Length);
							for (int j = 0; j < Materials.Length; j++) {
								bool emissive = Materials[j].emissiveColor.R != 0 | Materials[j].emissiveColor.G != 0 | Materials[j].emissiveColor.B != 0;
								bool transparent;
								if (Materials[j].TextureFilename != null) {
									TextureManager.TextureWrapMode WrapX, WrapY;
									if (ForceTextureRepeatX) {
										WrapX = TextureManager.TextureWrapMode.Repeat;
									} else {
										WrapX = TextureManager.TextureWrapMode.ClampToEdge;
									}
									if (ForceTextureRepeatY) {
										WrapY = TextureManager.TextureWrapMode.Repeat;
									} else {
										WrapY = TextureManager.TextureWrapMode.ClampToEdge;
									}
									if (WrapX != TextureManager.TextureWrapMode.Repeat | WrapY != TextureManager.TextureWrapMode.Repeat) {
										for (int k = 0; k < nFaces; k++) {
											for (int h = 0; h < Faces[k].Length; h++) {
												if (Vertices[Faces[k][h]].TextureCoordinates.X < 0.0 | Vertices[Faces[k][h]].TextureCoordinates.X > 1.0) {
													WrapX = TextureManager.TextureWrapMode.Repeat;
												}
												if (Vertices[Faces[k][h]].TextureCoordinates.Y < 0.0 | Vertices[Faces[k][h]].TextureCoordinates.Y > 1.0) {
													WrapY = TextureManager.TextureWrapMode.Repeat;
												}
											}
										}
									}
									int tday = TextureManager.RegisterTexture(Materials[j].TextureFilename, new World.ColorRGB(0, 0, 0), 1, TextureManager.TextureLoadMode.Normal, WrapX, WrapY, LoadMode != ObjectManager.ObjectLoadMode.Normal, 0, 0, 0, 0);
									Object.Mesh.Materials[mm + j].DaytimeTextureIndex = tday;
									transparent = true;
								} else {
									Object.Mesh.Materials[mm + j].DaytimeTextureIndex = -1;
									transparent = false;
								}
								Object.Mesh.Materials[mm + j].Flags = (byte)((transparent ? World.MeshMaterial.TransparentColorMask : 0) | (emissive ? World.MeshMaterial.EmissiveColorMask : 0));
								Object.Mesh.Materials[mm + j].Color = Materials[j].faceColor;
								Object.Mesh.Materials[mm + j].TransparentColor = new World.ColorRGB(0, 0, 0);
								Object.Mesh.Materials[mm + j].EmissiveColor = Materials[j].emissiveColor;
								Object.Mesh.Materials[mm + j].NighttimeTextureIndex = -1;
								Object.Mesh.Materials[mm + j].BlendMode = World.MeshMaterialBlendMode.Normal;
								Object.Mesh.Materials[mm + j].GlowAttenuationData = 0;
							}
							for (int j = 0; j < nFaces; j++) {
								Object.Mesh.Faces[mf + j].Material = (ushort)FaceMaterials[j];
								Object.Mesh.Faces[mf + j].Vertices = new World.MeshFaceVertex[Faces[j].Length];
								for (int k = 0; k < Faces[j].Length; k++) {
									Object.Mesh.Faces[mf + j].Vertices[mv + k] = new World.MeshFaceVertex(mv + Faces[j][k], FaceNormals[j][k]);
								}
							}
							for (int j = 0; j < Vertices.Length; j++) {
								Object.Mesh.Vertices[mv + j] = Vertices[j];
							}
							break;
						}
					case "Header":
						break;
					default:
						// unknown
						Interface.AddMessage(Interface.MessageType.Warning, false, "Unsupported template " + f.Name + " encountered in x object file " + FileName);
						break;
				}
			}
			// return
			World.CreateNormals(ref Object.Mesh);
			return true;
		}
		// apply mesh builder
		private static void ApplyMeshBuilder(ref ObjectManager.StaticObject Object, MeshBuilder Builder, ObjectManager.ObjectLoadMode LoadMode, bool ForceTextureRepeatX, bool ForceTextureRepeatY) {
			if (Builder.Faces.Length != 0) {
				int mf = Object.Mesh.Faces.Length;
				int mm = Object.Mesh.Materials.Length;
				int mv = Object.Mesh.Vertices.Length;
				Array.Resize<World.MeshFace>(ref Object.Mesh.Faces, mf + Builder.Faces.Length);
				Array.Resize<World.MeshMaterial>(ref Object.Mesh.Materials, mm + Builder.Materials.Length);
				Array.Resize<World.Vertex>(ref Object.Mesh.Vertices, mv + Builder.Vertices.Length);
				for (int i = 0; i < Builder.Vertices.Length; i++) {
					Object.Mesh.Vertices[mv + i] = Builder.Vertices[i];
				}
				for (int i = 0; i < Builder.Faces.Length; i++) {
					Object.Mesh.Faces[mf + i] = Builder.Faces[i];
					for (int j = 0; j < Object.Mesh.Faces[mf + i].Vertices.Length; j++) {
						Object.Mesh.Faces[mf + i].Vertices[j].Index += (ushort)mv;
					}
					Object.Mesh.Faces[mf + i].Material += (ushort)mm;
				}
				for (int i = 0; i < Builder.Materials.Length; i++) {
					Object.Mesh.Materials[mm + i].Flags = (byte)((Builder.Materials[i].EmissiveColorUsed ? World.MeshMaterial.EmissiveColorMask : 0) |
						(Builder.Materials[i].TransparentColorUsed ? World.MeshMaterial.TransparentColorMask : 0));
					Object.Mesh.Materials[mm + i].Color = Builder.Materials[i].Color;
					Object.Mesh.Materials[mm + i].TransparentColor = Builder.Materials[i].TransparentColor;
					if (Builder.Materials[i].DaytimeTexture != null) {
						Textures.Texture tday;
						if (Builder.Materials[i].TransparentColorUsed) {
							Textures.RegisterTexture(Builder.Materials[i].DaytimeTexture, new OpenBveApi.Textures.TextureParameters(null, 
								new Color24(Builder.Materials[i].TransparentColor.R, Builder.Materials[i].TransparentColor.G, Builder.Materials[i].TransparentColor.B)), out tday);
						} else {
							Textures.RegisterTexture(Builder.Materials[i].DaytimeTexture, out tday);
						}
						Object.Mesh.Materials[mm + i].DaytimeTexture = tday;
					} else {
						Object.Mesh.Materials[mm + i].DaytimeTexture = null;
					}
					Object.Mesh.Materials[mm + i].EmissiveColor = Builder.Materials[i].EmissiveColor;
					if (Builder.Materials[i].NighttimeTexture != null) {
						Textures.Texture tnight;
						if (Builder.Materials[i].TransparentColorUsed) {
							Textures.RegisterTexture(Builder.Materials[i].NighttimeTexture, new OpenBveApi.Textures.TextureParameters(null, 
								new Color24(Builder.Materials[i].TransparentColor.R, Builder.Materials[i].TransparentColor.G, Builder.Materials[i].TransparentColor.B)), out tnight);
						} else {
							Textures.RegisterTexture(Builder.Materials[i].NighttimeTexture, out tnight);
						}
						Object.Mesh.Materials[mm + i].NighttimeTexture = tnight;
					} else {
						Object.Mesh.Materials[mm + i].NighttimeTexture = null;
					}
					Object.Mesh.Materials[mm + i].DaytimeNighttimeBlend = 0;
					Object.Mesh.Materials[mm + i].BlendMode = Builder.Materials[i].BlendMode;
					Object.Mesh.Materials[mm + i].GlowAttenuationData = Builder.Materials[i].GlowAttenuationData;
				}
			}
		}
Beispiel #40
0
        // parse extensions config
        internal static void ParseExtensionsConfig(string TrainPath, System.Text.Encoding Encoding, ref UnifiedObject[] CarObjects, ref UnifiedObject[] BogieObjects, ref UnifiedObject[] CouplerObjects, TrainManager.Train Train, bool LoadObjects)
        {
            bool[] CarObjectsReversed   = new bool[Train.Cars.Length];
            bool[] BogieObjectsReversed = new bool[Train.Cars.Length * 2];

            bool[] CarsDefined   = new bool[Train.Cars.Length];
            bool[] BogiesDefined = new bool[Train.Cars.Length * 2];
            System.Globalization.CultureInfo Culture = System.Globalization.CultureInfo.InvariantCulture;
            string FileName = OpenBveApi.Path.CombineFile(TrainPath, "extensions.cfg");

            if (System.IO.File.Exists(FileName))
            {
                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;
                    }
                }

                string[] Lines = System.IO.File.ReadAllLines(FileName, Encoding);
                for (int i = 0; i < Lines.Length; i++)
                {
                    int j = Lines[i].IndexOf(';');
                    if (j >= 0)
                    {
                        Lines[i] = Lines[i].Substring(0, j).Trim(new char[] { });
                    }
                    else
                    {
                        Lines[i] = Lines[i].Trim(new char[] { });
                    }
                }
                for (int i = 0; i < Lines.Length; i++)
                {
                    if (Lines[i].Length != 0)
                    {
                        switch (Lines[i].ToLowerInvariant())
                        {
                        case "[exterior]":
                            // exterior
                            i++;
                            while (i < Lines.Length && !Lines[i].StartsWith("[", StringComparison.Ordinal) & !Lines[i].EndsWith("]", StringComparison.Ordinal))
                            {
                                if (Lines[i].Length != 0)
                                {
                                    int j = Lines[i].IndexOf("=", StringComparison.Ordinal);
                                    if (j >= 0)
                                    {
                                        string a = Lines[i].Substring(0, j).TrimEnd(new char[] { });
                                        string b = Lines[i].Substring(j + 1).TrimStart(new char[] { });
                                        int    n;
                                        if (int.TryParse(a, System.Globalization.NumberStyles.Integer, Culture, out n))
                                        {
                                            if (n >= 0 & n < Train.Cars.Length)
                                            {
                                                if (Path.ContainsInvalidChars(b))
                                                {
                                                    Interface.AddMessage(MessageType.Error, false, "File contains illegal characters at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                                                }
                                                else
                                                {
                                                    string File = OpenBveApi.Path.CombineFile(TrainPath, b);
                                                    if (System.IO.File.Exists(File))
                                                    {
                                                        if (LoadObjects)
                                                        {
                                                            CarObjects[n] = ObjectManager.LoadObject(File, Encoding, false);
                                                        }
                                                    }
                                                    else
                                                    {
                                                        Interface.AddMessage(MessageType.Error, true, "The car object " + File + " does not exist at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                                                    }
                                                }
                                            }
                                            else
                                            {
                                                Interface.AddMessage(MessageType.Error, false, "The car index " + a + " does not reference an existing car at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                                            }
                                        }
                                        else
                                        {
                                            Interface.AddMessage(MessageType.Error, false, "The car index is expected to be an integer at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                                        }
                                    }
                                    else
                                    {
                                        Interface.AddMessage(MessageType.Error, false, "Invalid statement " + Lines[i] + " encountered at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                                    }
                                }
                                i++;
                            }
                            i--;
                            break;

                        default:
                            if (Lines[i].StartsWith("[car", StringComparison.OrdinalIgnoreCase) & Lines[i].EndsWith("]", StringComparison.Ordinal))
                            {
                                // car
                                string t = Lines[i].Substring(4, Lines[i].Length - 5);
                                int    n; if (int.TryParse(t, System.Globalization.NumberStyles.Integer, Culture, out n))
                                {
                                    if (n >= 0 & n < Train.Cars.Length)
                                    {
                                        if (CarsDefined[n])
                                        {
                                            Interface.AddMessage(MessageType.Error, false, "Car " + n.ToString(Culture) + " has already been declared at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                                        }
                                        CarsDefined[n] = true;
                                        bool DefinedLength = false;
                                        bool DefinedAxles  = false;
                                        i++;
                                        while (i < Lines.Length && !Lines[i].StartsWith("[", StringComparison.Ordinal) & !Lines[i].EndsWith("]", StringComparison.Ordinal))
                                        {
                                            if (Lines[i].Length != 0)
                                            {
                                                int j = Lines[i].IndexOf("=", StringComparison.Ordinal);
                                                if (j >= 0)
                                                {
                                                    string a = Lines[i].Substring(0, j).TrimEnd(new char[] { });
                                                    string b = Lines[i].Substring(j + 1).TrimStart(new char[] { });
                                                    switch (a.ToLowerInvariant())
                                                    {
                                                    case "object":
                                                        if (string.IsNullOrEmpty(b))
                                                        {
                                                            Interface.AddMessage(MessageType.Error, true, "An empty car object was supplied at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                                                            break;
                                                        }
                                                        if (Path.ContainsInvalidChars(b))
                                                        {
                                                            Interface.AddMessage(MessageType.Error, false, "File contains illegal characters at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                                                        }
                                                        else
                                                        {
                                                            string File = OpenBveApi.Path.CombineFile(TrainPath, b);
                                                            if (System.IO.File.Exists(File))
                                                            {
                                                                if (LoadObjects)
                                                                {
                                                                    CarObjects[n] = ObjectManager.LoadObject(File, Encoding, false);
                                                                }
                                                            }
                                                            else
                                                            {
                                                                Interface.AddMessage(MessageType.Error, true, "The car object " + File + " does not exist at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                                                            }
                                                        }
                                                        break;

                                                    case "length":
                                                    {
                                                        double m;
                                                        if (double.TryParse(b, System.Globalization.NumberStyles.Float, Culture, out m))
                                                        {
                                                            if (m > 0.0)
                                                            {
                                                                Train.Cars[n].Length = m;
                                                                Train.Cars[n].BeaconReceiverPosition = 0.5 * m;
                                                                DefinedLength = true;
                                                            }
                                                            else
                                                            {
                                                                Interface.AddMessage(MessageType.Error, false, "Value is expected to be a positive floating-point number in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                                                            }
                                                        }
                                                        else
                                                        {
                                                            Interface.AddMessage(MessageType.Error, false, "Value is expected to be a positive floating-point number in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                                                        }
                                                    }
                                                    break;

                                                    case "axles":
                                                    {
                                                        int k = b.IndexOf(',');
                                                        if (k >= 0)
                                                        {
                                                            string c = b.Substring(0, k).TrimEnd(new char[] { });
                                                            string d = b.Substring(k + 1).TrimStart(new char[] { });
                                                            double rear, front;
                                                            if (!double.TryParse(c, System.Globalization.NumberStyles.Float, Culture, out rear))
                                                            {
                                                                Interface.AddMessage(MessageType.Error, false, "Rear is expected to be a floating-point number in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                                                            }
                                                            else if (!double.TryParse(d, System.Globalization.NumberStyles.Float, Culture, out front))
                                                            {
                                                                Interface.AddMessage(MessageType.Error, false, "Front is expected to be a floating-point number in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                                                            }
                                                            else if (rear >= front)
                                                            {
                                                                Interface.AddMessage(MessageType.Error, false, "Rear is expected to be less than Front in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                                                            }
                                                            else
                                                            {
                                                                Train.Cars[n].RearAxle.Position  = rear;
                                                                Train.Cars[n].FrontAxle.Position = front;
                                                                DefinedAxles = true;
                                                            }
                                                        }
                                                        else
                                                        {
                                                            Interface.AddMessage(MessageType.Error, false, "An argument-separating comma is expected in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                                                        }
                                                    }
                                                    break;

                                                    case "reversed":
                                                        CarObjectsReversed[n] = b.Equals("true", StringComparison.OrdinalIgnoreCase);
                                                        break;

                                                    case "loadingsway":
                                                        Train.Cars[n].EnableLoadingSway = b.Equals("true", StringComparison.OrdinalIgnoreCase);
                                                        break;

                                                    default:
                                                        Interface.AddMessage(MessageType.Warning, false, "Unsupported key-value pair " + a + " encountered at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                                                        break;
                                                    }
                                                }
                                                else
                                                {
                                                    Interface.AddMessage(MessageType.Error, false, "Invalid statement " + Lines[i] + " encountered at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                                                }
                                            }
                                            i++;
                                        }
                                        i--;
                                        if (DefinedLength & !DefinedAxles)
                                        {
                                            double AxleDistance = 0.4 * Train.Cars[n].Length;
                                            Train.Cars[n].RearAxle.Position  = -AxleDistance;
                                            Train.Cars[n].FrontAxle.Position = AxleDistance;
                                        }
                                    }
                                    else
                                    {
                                        Interface.AddMessage(MessageType.Error, false, "The car index " + t + " does not reference an existing car at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                                    }
                                }
                                else
                                {
                                    Interface.AddMessage(MessageType.Error, false, "The car index is expected to be an integer at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                                }
                            }
                            else if (Lines[i].StartsWith("[coupler", StringComparison.OrdinalIgnoreCase) & Lines[i].EndsWith("]", StringComparison.Ordinal))
                            {
                                // coupler
                                string t = Lines[i].Substring(8, Lines[i].Length - 9);
                                int    n; if (int.TryParse(t, System.Globalization.NumberStyles.Integer, Culture, out n))
                                {
                                    if (n >= 0 & n < Train.Cars.Length - 1)
                                    {
                                        i++; while (i < Lines.Length && !Lines[i].StartsWith("[", StringComparison.Ordinal) & !Lines[i].EndsWith("]", StringComparison.Ordinal))
                                        {
                                            if (Lines[i].Length != 0)
                                            {
                                                int j = Lines[i].IndexOf("=", StringComparison.Ordinal);
                                                if (j >= 0)
                                                {
                                                    string a = Lines[i].Substring(0, j).TrimEnd(new char[] { });
                                                    string b = Lines[i].Substring(j + 1).TrimStart(new char[] { });
                                                    switch (a.ToLowerInvariant())
                                                    {
                                                    case "distances":
                                                    {
                                                        int k = b.IndexOf(',');
                                                        if (k >= 0)
                                                        {
                                                            string c = b.Substring(0, k).TrimEnd(new char[] { });
                                                            string d = b.Substring(k + 1).TrimStart(new char[] { });
                                                            double min, max;
                                                            if (!double.TryParse(c, System.Globalization.NumberStyles.Float, Culture, out min))
                                                            {
                                                                Interface.AddMessage(MessageType.Error, false, "Minimum is expected to be a floating-point number in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                                                            }
                                                            else if (!double.TryParse(d, System.Globalization.NumberStyles.Float, Culture, out max))
                                                            {
                                                                Interface.AddMessage(MessageType.Error, false, "Maximum is expected to be a floating-point number in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                                                            }
                                                            else if (min > max)
                                                            {
                                                                Interface.AddMessage(MessageType.Error, false, "Minimum is expected to be less than Maximum in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                                                            }
                                                            else
                                                            {
                                                                Train.Cars[n].Coupler.MinimumDistanceBetweenCars = min;
                                                                Train.Cars[n].Coupler.MaximumDistanceBetweenCars = max;
                                                            }
                                                        }
                                                        else
                                                        {
                                                            Interface.AddMessage(MessageType.Error, false, "An argument-separating comma is expected in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                                                        }
                                                    } break;

                                                    case "object":
                                                        if (string.IsNullOrEmpty(b))
                                                        {
                                                            Interface.AddMessage(MessageType.Error, true, "An empty coupler object was supplied at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                                                            break;
                                                        }
                                                        if (Path.ContainsInvalidChars(b))
                                                        {
                                                            Interface.AddMessage(MessageType.Error, false, "File contains illegal characters at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                                                        }
                                                        else
                                                        {
                                                            string File = OpenBveApi.Path.CombineFile(TrainPath, b);
                                                            if (System.IO.File.Exists(File))
                                                            {
                                                                if (LoadObjects)
                                                                {
                                                                    CouplerObjects[n] = ObjectManager.LoadObject(File, Encoding, false);
                                                                }
                                                            }
                                                            else
                                                            {
                                                                Interface.AddMessage(MessageType.Error, true, "The coupler object " + File + " does not exist at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                                                            }
                                                        }
                                                        break;

                                                    default:
                                                        Interface.AddMessage(MessageType.Warning, false, "Unsupported key-value pair " + a + " encountered at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                                                        break;
                                                    }
                                                }
                                                else
                                                {
                                                    Interface.AddMessage(MessageType.Error, false, "Invalid statement " + Lines[i] + " encountered at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                                                }
                                            }
                                            i++;
                                        }
                                        i--;
                                    }
                                    else
                                    {
                                        Interface.AddMessage(MessageType.Error, false, "The coupler index " + t + " does not reference an existing coupler at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                                    }
                                }
                                else
                                {
                                    Interface.AddMessage(MessageType.Error, false, "The coupler index is expected to be an integer at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                                }
                            }
                            else if (Lines[i].StartsWith("[bogie", StringComparison.OrdinalIgnoreCase) & Lines[i].EndsWith("]", StringComparison.Ordinal))
                            {
                                // car
                                string t = Lines[i].Substring(6, Lines[i].Length - 7);
                                int    n; if (int.TryParse(t, System.Globalization.NumberStyles.Integer, Culture, out n))
                                {
                                    if (n > BogiesDefined.Length - 1)
                                    {
                                        continue;
                                    }
                                    if (BogiesDefined[n])
                                    {
                                        Interface.AddMessage(MessageType.Error, false, "Bogie " + n.ToString(Culture) + " has already been declared at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                                    }
                                    BogiesDefined[n] = true;
                                    //Assuming that there are two bogies per car
                                    bool IsOdd    = (n % 2 != 0);
                                    int  CarIndex = n / 2;
                                    if (n >= 0 & n < Train.Cars.Length * 2)
                                    {
                                        bool DefinedAxles = false;
                                        i++;
                                        while (i < Lines.Length && !Lines[i].StartsWith("[", StringComparison.Ordinal) & !Lines[i].EndsWith("]", StringComparison.Ordinal))
                                        {
                                            if (Lines[i].Length != 0)
                                            {
                                                int j = Lines[i].IndexOf("=", StringComparison.Ordinal);
                                                if (j >= 0)
                                                {
                                                    string a = Lines[i].Substring(0, j).TrimEnd(new char[] { });
                                                    string b = Lines[i].Substring(j + 1).TrimStart(new char[] { });
                                                    switch (a.ToLowerInvariant())
                                                    {
                                                    case "object":
                                                        if (Path.ContainsInvalidChars(b))
                                                        {
                                                            Interface.AddMessage(MessageType.Error, false, "File contains illegal characters at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                                                        }
                                                        else
                                                        {
                                                            if (string.IsNullOrEmpty(b))
                                                            {
                                                                Interface.AddMessage(MessageType.Error, true, "An empty bogie object was supplied at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                                                                break;
                                                            }
                                                            string File = OpenBveApi.Path.CombineFile(TrainPath, b);
                                                            if (System.IO.File.Exists(File))
                                                            {
                                                                if (LoadObjects)
                                                                {
                                                                    BogieObjects[n] = ObjectManager.LoadObject(File, Encoding, false);
                                                                }
                                                            }
                                                            else
                                                            {
                                                                Interface.AddMessage(MessageType.Error, true, "The bogie object " + File + " does not exist at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                                                            }
                                                        }
                                                        break;

                                                    case "length":
                                                    {
                                                        Interface.AddMessage(MessageType.Error, false, "A defined length is not supported for bogies at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                                                    }
                                                    break;

                                                    case "axles":
                                                    {
                                                        int k = b.IndexOf(',');
                                                        if (k >= 0)
                                                        {
                                                            string c = b.Substring(0, k).TrimEnd(new char[] { });
                                                            string d = b.Substring(k + 1).TrimStart(new char[] { });
                                                            double rear, front;
                                                            if (!double.TryParse(c, System.Globalization.NumberStyles.Float, Culture, out rear))
                                                            {
                                                                Interface.AddMessage(MessageType.Error, false, "Rear is expected to be a floating-point number in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                                                            }
                                                            else if (!double.TryParse(d, System.Globalization.NumberStyles.Float, Culture, out front))
                                                            {
                                                                Interface.AddMessage(MessageType.Error, false, "Front is expected to be a floating-point number in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                                                            }
                                                            else if (rear >= front)
                                                            {
                                                                Interface.AddMessage(MessageType.Error, false, "Rear is expected to be less than Front in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                                                            }
                                                            else
                                                            {
                                                                if (IsOdd)
                                                                {
                                                                    Train.Cars[CarIndex].FrontBogie.RearAxle.Position  = rear;
                                                                    Train.Cars[CarIndex].FrontBogie.FrontAxle.Position = front;
                                                                }
                                                                else
                                                                {
                                                                    Train.Cars[CarIndex].RearBogie.RearAxle.Position  = rear;
                                                                    Train.Cars[CarIndex].RearBogie.FrontAxle.Position = front;
                                                                }
                                                                DefinedAxles = true;
                                                            }
                                                        }
                                                        else
                                                        {
                                                            Interface.AddMessage(MessageType.Error, false, "An argument-separating comma is expected in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                                                        }
                                                    }
                                                    break;

                                                    case "reversed":
                                                        BogieObjectsReversed[n] = b.Equals("true", StringComparison.OrdinalIgnoreCase);
                                                        break;

                                                    default:
                                                        Interface.AddMessage(MessageType.Warning, false, "Unsupported key-value pair " + a + " encountered at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                                                        break;
                                                    }
                                                }
                                                else
                                                {
                                                    Interface.AddMessage(MessageType.Error, false, "Invalid statement " + Lines[i] + " encountered at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                                                }
                                            }
                                            i++;
                                        }
                                        i--;
                                        if (!DefinedAxles)
                                        {
                                            if (IsOdd)
                                            {
                                                double AxleDistance = 0.4 * Train.Cars[CarIndex].FrontBogie.Length;
                                                Train.Cars[CarIndex].FrontBogie.RearAxle.Position  = -AxleDistance;
                                                Train.Cars[CarIndex].FrontBogie.FrontAxle.Position = AxleDistance;
                                            }
                                            else
                                            {
                                                double AxleDistance = 0.4 * Train.Cars[CarIndex].RearBogie.Length;
                                                Train.Cars[CarIndex].RearBogie.RearAxle.Position  = -AxleDistance;
                                                Train.Cars[CarIndex].RearBogie.FrontAxle.Position = AxleDistance;
                                            }
                                        }
                                    }
                                    else
                                    {
                                        Interface.AddMessage(MessageType.Error, false, "The car index " + t + " does not reference an existing car at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                                    }
                                }
                                else
                                {
                                    Interface.AddMessage(MessageType.Error, false, "The car index is expected to be an integer at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                                }
                            }
                            else
                            {
                                // default
                                if (Lines.Length == 1 && Encoding.Equals(Encoding.Unicode))
                                {
                                    /*
                                     * If only one line, there's a good possibility that our file is NOT Unicode at all
                                     * and that the misdetection has turned it into garbage
                                     *
                                     * Try again with ASCII instead
                                     */
                                    ParseExtensionsConfig(TrainPath, Encoding.GetEncoding(1252), ref CarObjects, ref BogieObjects, ref CouplerObjects, Train, LoadObjects);
                                    return;
                                }
                                Interface.AddMessage(MessageType.Error, false, "Invalid statement " + Lines[i] + " encountered at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                            }
                            break;
                        }
                    }
                }

                // check for car objects and reverse if necessary
                int carObjects = 0;
                for (int i = 0; i < Train.Cars.Length; i++)
                {
                    if (CarObjects[i] != null)
                    {
                        carObjects++;
                        if (CarObjectsReversed[i] && LoadObjects)
                        {
                            {
                                // reverse axle positions
                                double temp = Train.Cars[i].FrontAxle.Position;
                                Train.Cars[i].FrontAxle.Position = -Train.Cars[i].RearAxle.Position;
                                Train.Cars[i].RearAxle.Position  = -temp;
                            }
                            if (CarObjects[i] is StaticObject)
                            {
                                StaticObject obj = (StaticObject)CarObjects[i];
                                obj.ApplyScale(-1.0, 1.0, -1.0);
                            }
                            else if (CarObjects[i] is AnimatedObjectCollection)
                            {
                                AnimatedObjectCollection obj = (AnimatedObjectCollection)CarObjects[i];
                                for (int j = 0; j < obj.Objects.Length; j++)
                                {
                                    for (int h = 0; h < obj.Objects[j].States.Length; h++)
                                    {
                                        if (obj.Objects[j].States[h].Prototype == null)
                                        {
                                            continue;                                             //object failed to load?
                                        }
                                        obj.Objects[j].States[h].Prototype.ApplyScale(-1.0, 1.0, -1.0);
                                        Matrix4D t = obj.Objects[j].States[h].Translation;
                                        t.Row3.X *= -1.0f;
                                        t.Row3.Z *= -1.0f;
                                        obj.Objects[j].States[h].Translation = t;
                                    }
                                    obj.Objects[j].TranslateXDirection.X *= -1.0;
                                    obj.Objects[j].TranslateXDirection.Z *= -1.0;
                                    obj.Objects[j].TranslateYDirection.X *= -1.0;
                                    obj.Objects[j].TranslateYDirection.Z *= -1.0;
                                    obj.Objects[j].TranslateZDirection.X *= -1.0;
                                    obj.Objects[j].TranslateZDirection.Z *= -1.0;
                                }
                            }
                            else
                            {
                                throw new NotImplementedException();
                            }
                        }
                    }
                }

                //Check for bogie objects and reverse if necessary.....
                int bogieObjects = 0;
                for (int i = 0; i < Train.Cars.Length * 2; i++)
                {
                    bool IsOdd    = (i % 2 != 0);
                    int  CarIndex = i / 2;
                    if (BogieObjects[i] != null)
                    {
                        bogieObjects++;
                        if (BogieObjectsReversed[i] && LoadObjects)
                        {
                            {
                                // reverse axle positions
                                if (IsOdd)
                                {
                                    double temp = Train.Cars[CarIndex].FrontBogie.FrontAxle.Position;
                                    Train.Cars[CarIndex].FrontBogie.FrontAxle.Position = -Train.Cars[CarIndex].FrontBogie.RearAxle.Position;
                                    Train.Cars[CarIndex].FrontBogie.RearAxle.Position  = -temp;
                                }
                                else
                                {
                                    double temp = Train.Cars[CarIndex].RearBogie.FrontAxle.Position;
                                    Train.Cars[CarIndex].RearBogie.FrontAxle.Position = -Train.Cars[CarIndex].RearBogie.RearAxle.Position;
                                    Train.Cars[CarIndex].RearBogie.RearAxle.Position  = -temp;
                                }
                            }
                            if (BogieObjects[i] is StaticObject)
                            {
                                StaticObject obj = (StaticObject)BogieObjects[i];
                                obj.ApplyScale(-1.0, 1.0, -1.0);
                            }
                            else if (BogieObjects[i] is AnimatedObjectCollection)
                            {
                                AnimatedObjectCollection obj = (AnimatedObjectCollection)BogieObjects[i];
                                for (int j = 0; j < obj.Objects.Length; j++)
                                {
                                    for (int h = 0; h < obj.Objects[j].States.Length; h++)
                                    {
                                        if (obj.Objects[j].States[h].Prototype == null)
                                        {
                                            continue;                                             //object failed to load?
                                        }
                                        obj.Objects[j].States[h].Prototype.ApplyScale(-1.0, 1.0, -1.0);
                                        Matrix4D t = obj.Objects[j].States[h].Translation;
                                        t.Row3.X *= -1.0f;
                                        t.Row3.Z *= -1.0f;
                                        obj.Objects[j].States[h].Translation = t;
                                    }
                                    obj.Objects[j].TranslateXDirection.X *= -1.0;
                                    obj.Objects[j].TranslateXDirection.Z *= -1.0;
                                    obj.Objects[j].TranslateYDirection.X *= -1.0;
                                    obj.Objects[j].TranslateYDirection.Z *= -1.0;
                                    obj.Objects[j].TranslateZDirection.X *= -1.0;
                                    obj.Objects[j].TranslateZDirection.Z *= -1.0;
                                }
                            }
                            else
                            {
                                throw new NotImplementedException();
                            }
                        }
                    }
                }

                if (carObjects > 0 & carObjects < Train.Cars.Length)
                {
                    Interface.AddMessage(MessageType.Warning, false, "An incomplete set of exterior objects was provided in file " + FileName);
                }

                if (bogieObjects > 0 & bogieObjects < Train.Cars.Length * 2)
                {
                    Interface.AddMessage(MessageType.Warning, false, "An incomplete set of bogie objects was provided in file " + FileName);
                }
            }
        }