Represents a 2D vector of System.Double coordinates.
コード例 #1
0
ファイル: CsvRwRouteParser.cs プロジェクト: sladen/openbve
 // apply route data
 private static void ApplyRouteData(string FileName, System.Text.Encoding Encoding, ref RouteData Data, bool PreviewOnly)
 {
     string SignalPath, LimitPath, LimitGraphicsPath, TransponderPath;
     ObjectManager.StaticObject SignalPost, LimitPostStraight, LimitPostLeft, LimitPostRight, LimitPostInfinite;
     ObjectManager.StaticObject LimitOneDigit, LimitTwoDigits, LimitThreeDigits, StopPost;
     ObjectManager.StaticObject TransponderS, TransponderSN, TransponderFalseStart, TransponderPOrigin, TransponderPStop;
     if (!PreviewOnly) {
         string CompatibilityFolder = Program.FileSystem.GetDataFolder("Compatibility");
         // load compatibility objects
         SignalPath = OpenBveApi.Path.CombineDirectory(CompatibilityFolder, "Signals");
         SignalPost = ObjectManager.LoadStaticObject(OpenBveApi.Path.CombineFile(SignalPath, "signal_post.csv"), Encoding, ObjectManager.ObjectLoadMode.Normal, false, false, false);
         LimitPath = OpenBveApi.Path.CombineDirectory(CompatibilityFolder, "Limits");
         LimitGraphicsPath = OpenBveApi.Path.CombineDirectory(LimitPath, "Graphics");
         LimitPostStraight = ObjectManager.LoadStaticObject(OpenBveApi.Path.CombineFile(LimitPath, "limit_straight.csv"), Encoding, ObjectManager.ObjectLoadMode.Normal, false, false, false);
         LimitPostLeft = ObjectManager.LoadStaticObject(OpenBveApi.Path.CombineFile(LimitPath, "limit_left.csv"), Encoding, ObjectManager.ObjectLoadMode.Normal, false, false, false);
         LimitPostRight = ObjectManager.LoadStaticObject(OpenBveApi.Path.CombineFile(LimitPath, "limit_right.csv"), Encoding, ObjectManager.ObjectLoadMode.Normal, false, false, false);
         LimitPostInfinite = ObjectManager.LoadStaticObject(OpenBveApi.Path.CombineFile(LimitPath, "limit_infinite.csv"), Encoding, ObjectManager.ObjectLoadMode.Normal, false, false, false);
         LimitOneDigit = ObjectManager.LoadStaticObject(OpenBveApi.Path.CombineFile(LimitPath, "limit_1_digit.csv"), Encoding, ObjectManager.ObjectLoadMode.Normal, false, false, false);
         LimitTwoDigits = ObjectManager.LoadStaticObject(OpenBveApi.Path.CombineFile(LimitPath, "limit_2_digits.csv"), Encoding, ObjectManager.ObjectLoadMode.Normal, false, false, false);
         LimitThreeDigits = ObjectManager.LoadStaticObject(OpenBveApi.Path.CombineFile(LimitPath, "limit_3_digits.csv"), Encoding, ObjectManager.ObjectLoadMode.Normal, false, false, false);
         StopPost = ObjectManager.LoadStaticObject(OpenBveApi.Path.CombineFile(CompatibilityFolder, "stop.csv"), Encoding, ObjectManager.ObjectLoadMode.Normal, false, false, false);
         TransponderPath = OpenBveApi.Path.CombineDirectory(CompatibilityFolder, "Transponders");
         TransponderS = ObjectManager.LoadStaticObject(OpenBveApi.Path.CombineFile(TransponderPath, "s.csv"), Encoding, ObjectManager.ObjectLoadMode.Normal, false, false, false);
         TransponderSN = ObjectManager.LoadStaticObject(OpenBveApi.Path.CombineFile(TransponderPath, "sn.csv"), Encoding, ObjectManager.ObjectLoadMode.Normal, false, false, false);
         TransponderFalseStart = ObjectManager.LoadStaticObject(OpenBveApi.Path.CombineFile(TransponderPath, "falsestart.csv"), Encoding, ObjectManager.ObjectLoadMode.Normal, false, false, false);
         TransponderPOrigin = ObjectManager.LoadStaticObject(OpenBveApi.Path.CombineFile(TransponderPath, "porigin.csv"), Encoding, ObjectManager.ObjectLoadMode.Normal, false, false, false);
         TransponderPStop = ObjectManager.LoadStaticObject(OpenBveApi.Path.CombineFile(TransponderPath, "pstop.csv"), Encoding, ObjectManager.ObjectLoadMode.Normal, false, false, false);
     } else {
         SignalPath = null;
         LimitPath = null;
         LimitGraphicsPath = null;
         TransponderPath = null;
         SignalPost = null;
         LimitPostStraight = null;
         LimitPostLeft = null;
         LimitPostRight = null;
         LimitPostInfinite = null;
         LimitOneDigit = null;
         LimitTwoDigits = null;
         LimitThreeDigits = null;
         StopPost = null;
         TransponderS = null;
         TransponderSN = null;
         TransponderFalseStart = null;
         TransponderPOrigin = null;
         TransponderPStop = null;
     }
     // initialize
     System.Globalization.CultureInfo Culture = System.Globalization.CultureInfo.InvariantCulture;
     int LastBlock = (int)Math.Floor((Data.TrackPosition + 600.0) / Data.BlockInterval + 0.001) + 1;
     int BlocksUsed = Data.Blocks.Length;
     CreateMissingBlocks(ref Data, ref BlocksUsed, LastBlock, PreviewOnly);
     Array.Resize<Block>(ref Data.Blocks, BlocksUsed);
     // interpolate height
     if (!PreviewOnly) {
         int z = 0;
         for (int i = 0; i < Data.Blocks.Length; i++) {
             if (!double.IsNaN(Data.Blocks[i].Height)) {
                 for (int j = i - 1; j >= 0; j--) {
                     if (!double.IsNaN(Data.Blocks[j].Height)) {
                         double a = Data.Blocks[j].Height;
                         double b = Data.Blocks[i].Height;
                         double d = (b - a) / (double)(i - j);
                         for (int k = j + 1; k < i; k++) {
                             a += d;
                             Data.Blocks[k].Height = a;
                         }
                         break;
                     }
                 }
                 z = i;
             }
         }
         for (int i = z + 1; i < Data.Blocks.Length; i++) {
             Data.Blocks[i].Height = Data.Blocks[z].Height;
         }
     }
     // background
     if (!PreviewOnly) {
         if (Data.Blocks[0].Background >= 0 & Data.Blocks[0].Background < Data.Backgrounds.Length) {
             World.CurrentBackground = Data.Backgrounds[Data.Blocks[0].Background];
         } else {
             World.CurrentBackground = new World.Background(null, 6, false);
         }
         World.TargetBackground = World.CurrentBackground;
     }
     // brightness
     int CurrentBrightnessElement = -1;
     int CurrentBrightnessEvent = -1;
     float CurrentBrightnessValue = 1.0f;
     double CurrentBrightnessTrackPosition = (double)Data.FirstUsedBlock * Data.BlockInterval;
     if (!PreviewOnly) {
         for (int i = Data.FirstUsedBlock; i < Data.Blocks.Length; i++) {
             if (Data.Blocks[i].Brightness != null && Data.Blocks[i].Brightness.Length != 0) {
                 CurrentBrightnessValue = Data.Blocks[i].Brightness[0].Value;
                 CurrentBrightnessTrackPosition = Data.Blocks[i].Brightness[0].Value;
                 break;
             }
         }
     }
     // create objects and track
     Vector3 Position = new Vector3(0.0, 0.0, 0.0);
     World.Vector2D Direction = new World.Vector2D(0.0, 1.0);
     TrackManager.CurrentTrack = new TrackManager.Track();
     TrackManager.CurrentTrack.Elements = new TrackManager.TrackElement[] { };
     double CurrentSpeedLimit = double.PositiveInfinity;
     int CurrentRunIndex = 0;
     int CurrentFlangeIndex = 0;
     if (Data.FirstUsedBlock < 0) Data.FirstUsedBlock = 0;
     TrackManager.CurrentTrack.Elements = new TrackManager.TrackElement[256];
     int CurrentTrackLength = 0;
     int PreviousFogElement = -1;
     int PreviousFogEvent = -1;
     Game.Fog PreviousFog = new Game.Fog(Game.NoFogStart, Game.NoFogEnd, new Color24(128, 128, 128), -Data.BlockInterval);
     Game.Fog CurrentFog = new Game.Fog(Game.NoFogStart, Game.NoFogEnd, new Color24(128, 128, 128), 0.0);
     // process blocks
     double progressFactor = Data.Blocks.Length - Data.FirstUsedBlock == 0 ? 0.5 : 0.5 / (double)(Data.Blocks.Length - Data.FirstUsedBlock);
     for (int i = Data.FirstUsedBlock; i < Data.Blocks.Length; i++) {
         Loading.RouteProgress = 0.6667 + (double)(i - Data.FirstUsedBlock) * progressFactor;
         if ((i & 15) == 0) {
             System.Threading.Thread.Sleep(1);
             if (Loading.Cancel) return;
         }
         double StartingDistance = (double)i * Data.BlockInterval;
         double EndingDistance = StartingDistance + Data.BlockInterval;
         // normalize
         World.Normalize(ref Direction.X, ref Direction.Y);
         // track
         if (!PreviewOnly) {
             if (Data.Blocks[i].Cycle.Length == 1 && Data.Blocks[i].Cycle[0] == -1) {
                 if (Data.Structure.Cycle.Length == 0 || Data.Structure.Cycle[0] == null) {
                     Data.Blocks[i].Cycle = new int[] { 0 };
                 } else {
                     Data.Blocks[i].Cycle = Data.Structure.Cycle[0];
                 }
             }
         }
         TrackManager.TrackElement WorldTrackElement = Data.Blocks[i].CurrentTrackState;
         int n = CurrentTrackLength;
         if (n >= TrackManager.CurrentTrack.Elements.Length) {
             Array.Resize<TrackManager.TrackElement>(ref TrackManager.CurrentTrack.Elements, TrackManager.CurrentTrack.Elements.Length << 1);
         }
         CurrentTrackLength++;
         TrackManager.CurrentTrack.Elements[n] = WorldTrackElement;
         TrackManager.CurrentTrack.Elements[n].WorldPosition = Position;
         TrackManager.CurrentTrack.Elements[n].WorldDirection = World.GetVector3(Direction, Data.Blocks[i].Pitch);
         TrackManager.CurrentTrack.Elements[n].WorldSide = new Vector3(Direction.Y, 0.0, -Direction.X);
         World.Cross(TrackManager.CurrentTrack.Elements[n].WorldDirection.X, TrackManager.CurrentTrack.Elements[n].WorldDirection.Y, TrackManager.CurrentTrack.Elements[n].WorldDirection.Z, TrackManager.CurrentTrack.Elements[n].WorldSide.X, TrackManager.CurrentTrack.Elements[n].WorldSide.Y, TrackManager.CurrentTrack.Elements[n].WorldSide.Z, out TrackManager.CurrentTrack.Elements[n].WorldUp.X, out TrackManager.CurrentTrack.Elements[n].WorldUp.Y, out TrackManager.CurrentTrack.Elements[n].WorldUp.Z);
         TrackManager.CurrentTrack.Elements[n].StartingTrackPosition = StartingDistance;
         TrackManager.CurrentTrack.Elements[n].Events = new TrackManager.GeneralEvent[] { };
         TrackManager.CurrentTrack.Elements[n].AdhesionMultiplier = Data.Blocks[i].AdhesionMultiplier;
         TrackManager.CurrentTrack.Elements[n].CsvRwAccuracyLevel = Data.Blocks[i].Accuracy;
         // background
         if (!PreviewOnly) {
             if (Data.Blocks[i].Background >= 0) {
                 int typ;
                 if (i == Data.FirstUsedBlock) {
                     typ = Data.Blocks[i].Background;
                 } else {
                     typ = Data.Backgrounds.Length > 0 ? 0 : -1;
                     for (int j = i - 1; j >= Data.FirstUsedBlock; j--) {
                         if (Data.Blocks[j].Background >= 0) {
                             typ = Data.Blocks[j].Background;
                             break;
                         }
                     }
                 }
                 if (typ >= 0 & typ < Data.Backgrounds.Length) {
                     int m = TrackManager.CurrentTrack.Elements[n].Events.Length;
                     Array.Resize<TrackManager.GeneralEvent>(ref TrackManager.CurrentTrack.Elements[n].Events, m + 1);
                     TrackManager.CurrentTrack.Elements[n].Events[m] = new TrackManager.BackgroundChangeEvent(0.0, Data.Backgrounds[typ], Data.Backgrounds[Data.Blocks[i].Background]);
                 }
             }
         }
         // brightness
         if (!PreviewOnly) {
             for (int j = 0; j < Data.Blocks[i].Brightness.Length; j++) {
                 int m = TrackManager.CurrentTrack.Elements[n].Events.Length;
                 Array.Resize<TrackManager.GeneralEvent>(ref TrackManager.CurrentTrack.Elements[n].Events, m + 1);
                 double d = Data.Blocks[i].Brightness[j].TrackPosition - StartingDistance;
                 TrackManager.CurrentTrack.Elements[n].Events[m] = new TrackManager.BrightnessChangeEvent(d, Data.Blocks[i].Brightness[j].Value, CurrentBrightnessValue, Data.Blocks[i].Brightness[j].TrackPosition - CurrentBrightnessTrackPosition, Data.Blocks[i].Brightness[j].Value, 0.0);
                 if (CurrentBrightnessElement >= 0 & CurrentBrightnessEvent >= 0) {
                     TrackManager.BrightnessChangeEvent bce = (TrackManager.BrightnessChangeEvent)TrackManager.CurrentTrack.Elements[CurrentBrightnessElement].Events[CurrentBrightnessEvent];
                     bce.NextBrightness = Data.Blocks[i].Brightness[j].Value;
                     bce.NextDistance = Data.Blocks[i].Brightness[j].TrackPosition - CurrentBrightnessTrackPosition;
                 }
                 CurrentBrightnessElement = n;
                 CurrentBrightnessEvent = m;
                 CurrentBrightnessValue = Data.Blocks[i].Brightness[j].Value;
                 CurrentBrightnessTrackPosition = Data.Blocks[i].Brightness[j].TrackPosition;
             }
         }
         // fog
         if (!PreviewOnly) {
             if (Data.FogTransitionMode) {
                 if (Data.Blocks[i].FogDefined) {
                     Data.Blocks[i].Fog.TrackPosition = StartingDistance;
                     int m = TrackManager.CurrentTrack.Elements[n].Events.Length;
                     Array.Resize<TrackManager.GeneralEvent>(ref TrackManager.CurrentTrack.Elements[n].Events, m + 1);
                     TrackManager.CurrentTrack.Elements[n].Events[m] = new TrackManager.FogChangeEvent(0.0, PreviousFog, Data.Blocks[i].Fog, Data.Blocks[i].Fog);
                     if (PreviousFogElement >= 0 & PreviousFogEvent >= 0) {
                         TrackManager.FogChangeEvent e = (TrackManager.FogChangeEvent)TrackManager.CurrentTrack.Elements[PreviousFogElement].Events[PreviousFogEvent];
                         e.NextFog = Data.Blocks[i].Fog;
                     } else {
                         Game.PreviousFog = PreviousFog;
                         Game.CurrentFog = PreviousFog;
                         Game.NextFog = Data.Blocks[i].Fog;
                     }
                     PreviousFog = Data.Blocks[i].Fog;
                     PreviousFogElement = n;
                     PreviousFogEvent = m;
                 }
             } else {
                 Data.Blocks[i].Fog.TrackPosition = StartingDistance + Data.BlockInterval;
                 int m = TrackManager.CurrentTrack.Elements[n].Events.Length;
                 Array.Resize<TrackManager.GeneralEvent>(ref TrackManager.CurrentTrack.Elements[n].Events, m + 1);
                 TrackManager.CurrentTrack.Elements[n].Events[m] = new TrackManager.FogChangeEvent(0.0, PreviousFog, CurrentFog, Data.Blocks[i].Fog);
                 PreviousFog = CurrentFog;
                 CurrentFog = Data.Blocks[i].Fog;
             }
         }
         // rail sounds
         if (!PreviewOnly) {
             int j = Data.Blocks[i].RailType[0];
             int r = j < Data.Structure.Run.Length ? Data.Structure.Run[j] : 0;
             int f = j < Data.Structure.Flange.Length ? Data.Structure.Flange[j] : 0;
             int m = TrackManager.CurrentTrack.Elements[n].Events.Length;
             Array.Resize<TrackManager.GeneralEvent>(ref TrackManager.CurrentTrack.Elements[n].Events, m + 1);
             TrackManager.CurrentTrack.Elements[n].Events[m] = new TrackManager.RailSoundsChangeEvent(0.0, CurrentRunIndex, CurrentFlangeIndex, r, f);
             CurrentRunIndex = r;
             CurrentFlangeIndex = f;
         }
         // point sound
         if (!PreviewOnly) {
             if (i < Data.Blocks.Length - 1) {
                 bool q = false;
                 for (int j = 0; j < Data.Blocks[i].Rail.Length; j++) {
                     if (Data.Blocks[i].Rail[j].RailStart & Data.Blocks[i + 1].Rail.Length > j) {
                         bool qx = Math.Sign(Data.Blocks[i].Rail[j].RailStartX) != Math.Sign(Data.Blocks[i + 1].Rail[j].RailEndX);
                         bool qy = Data.Blocks[i].Rail[j].RailStartY * Data.Blocks[i + 1].Rail[j].RailEndY <= 0.0;
                         if (qx & qy) {
                             q = true;
                             break;
                         }
                     }
                 }
                 if (q) {
                     int m = TrackManager.CurrentTrack.Elements[n].Events.Length;
                     Array.Resize<TrackManager.GeneralEvent>(ref TrackManager.CurrentTrack.Elements[n].Events, m + 1);
                     TrackManager.CurrentTrack.Elements[n].Events[m] = new TrackManager.SoundEvent(0.0, null, false, false, true, new Vector3(0.0, 0.0, 0.0), 12.5);
                 }
             }
         }
         // station
         if (Data.Blocks[i].Station >= 0) {
             // station
             int s = Data.Blocks[i].Station;
             int m = TrackManager.CurrentTrack.Elements[n].Events.Length;
             Array.Resize<TrackManager.GeneralEvent>(ref TrackManager.CurrentTrack.Elements[n].Events, m + 1);
             TrackManager.CurrentTrack.Elements[n].Events[m] = new TrackManager.StationStartEvent(0.0, s);
             double dx, dy = 3.0;
             if (Game.Stations[s].OpenLeftDoors & !Game.Stations[s].OpenRightDoors) {
                 dx = -5.0;
             } else if (!Game.Stations[s].OpenLeftDoors & Game.Stations[s].OpenRightDoors) {
                 dx = 5.0;
             } else {
                 dx = 0.0;
             }
             Game.Stations[s].SoundOrigin.X = Position.X + dx * TrackManager.CurrentTrack.Elements[n].WorldSide.X + dy * TrackManager.CurrentTrack.Elements[n].WorldUp.X;
             Game.Stations[s].SoundOrigin.Y = Position.Y + dx * TrackManager.CurrentTrack.Elements[n].WorldSide.Y + dy * TrackManager.CurrentTrack.Elements[n].WorldUp.Y;
             Game.Stations[s].SoundOrigin.Z = Position.Z + dx * TrackManager.CurrentTrack.Elements[n].WorldSide.Z + dy * TrackManager.CurrentTrack.Elements[n].WorldUp.Z;
             // passalarm
             if (!PreviewOnly) {
                 if (Data.Blocks[i].StationPassAlarm) {
                     int b = i - 6;
                     if (b >= 0) {
                         int j = b - Data.FirstUsedBlock;
                         if (j >= 0) {
                             m = TrackManager.CurrentTrack.Elements[j].Events.Length;
                             Array.Resize<TrackManager.GeneralEvent>(ref TrackManager.CurrentTrack.Elements[j].Events, m + 1);
                             TrackManager.CurrentTrack.Elements[j].Events[m] = new TrackManager.StationPassAlarmEvent(0.0);
                         }
                     }
                 }
             }
         }
         // stop
         for (int j = 0; j < Data.Blocks[i].Stop.Length; j++) {
             int s = Data.Blocks[i].Stop[j].Station;
             int t = Game.Stations[s].Stops.Length;
             Array.Resize<Game.StationStop>(ref Game.Stations[s].Stops, t + 1);
             Game.Stations[s].Stops[t].TrackPosition = Data.Blocks[i].Stop[j].TrackPosition;
             Game.Stations[s].Stops[t].ForwardTolerance = Data.Blocks[i].Stop[j].ForwardTolerance;
             Game.Stations[s].Stops[t].BackwardTolerance = Data.Blocks[i].Stop[j].BackwardTolerance;
             Game.Stations[s].Stops[t].Cars = Data.Blocks[i].Stop[j].Cars;
             double dx, dy = 2.0;
             if (Game.Stations[s].OpenLeftDoors & !Game.Stations[s].OpenRightDoors) {
                 dx = -5.0;
             } else if (!Game.Stations[s].OpenLeftDoors & Game.Stations[s].OpenRightDoors) {
                 dx = 5.0;
             } else {
                 dx = 0.0;
             }
             Game.Stations[s].SoundOrigin.X = Position.X + dx * TrackManager.CurrentTrack.Elements[n].WorldSide.X + dy * TrackManager.CurrentTrack.Elements[n].WorldUp.X;
             Game.Stations[s].SoundOrigin.Y = Position.Y + dx * TrackManager.CurrentTrack.Elements[n].WorldSide.Y + dy * TrackManager.CurrentTrack.Elements[n].WorldUp.Y;
             Game.Stations[s].SoundOrigin.Z = Position.Z + dx * TrackManager.CurrentTrack.Elements[n].WorldSide.Z + dy * TrackManager.CurrentTrack.Elements[n].WorldUp.Z;
         }
         // limit
         for (int j = 0; j < Data.Blocks[i].Limit.Length; j++) {
             int m = TrackManager.CurrentTrack.Elements[n].Events.Length;
             Array.Resize<TrackManager.GeneralEvent>(ref TrackManager.CurrentTrack.Elements[n].Events, m + 1);
             double d = Data.Blocks[i].Limit[j].TrackPosition - StartingDistance;
             TrackManager.CurrentTrack.Elements[n].Events[m] = new TrackManager.LimitChangeEvent(d, CurrentSpeedLimit, Data.Blocks[i].Limit[j].Speed);
             CurrentSpeedLimit = Data.Blocks[i].Limit[j].Speed;
         }
         // marker
         if (!PreviewOnly) {
             for (int j = 0; j < Data.Markers.Length; j++) {
                 if (Data.Markers[j].StartingPosition >= StartingDistance & Data.Markers[j].StartingPosition < EndingDistance) {
                     int m = TrackManager.CurrentTrack.Elements[n].Events.Length;
                     Array.Resize<TrackManager.GeneralEvent>(ref TrackManager.CurrentTrack.Elements[n].Events, m + 1);
                     double d = Data.Markers[j].StartingPosition - StartingDistance;
                     TrackManager.CurrentTrack.Elements[n].Events[m] = new TrackManager.MarkerStartEvent(d, Data.Markers[j].Texture);
                 }
                 if (Data.Markers[j].EndingPosition >= StartingDistance & Data.Markers[j].EndingPosition < EndingDistance) {
                     int m = TrackManager.CurrentTrack.Elements[n].Events.Length;
                     Array.Resize<TrackManager.GeneralEvent>(ref TrackManager.CurrentTrack.Elements[n].Events, m + 1);
                     double d = Data.Markers[j].EndingPosition - StartingDistance;
                     TrackManager.CurrentTrack.Elements[n].Events[m] = new TrackManager.MarkerEndEvent(d, Data.Markers[j].Texture);
                 }
             }
         }
         // sound
         if (!PreviewOnly) {
             for (int j = 0; j < Data.Blocks[i].Sound.Length; j++) {
                 if (Data.Blocks[i].Sound[j].Type == SoundType.TrainStatic | Data.Blocks[i].Sound[j].Type == SoundType.TrainDynamic) {
                     int m = TrackManager.CurrentTrack.Elements[n].Events.Length;
                     Array.Resize<TrackManager.GeneralEvent>(ref TrackManager.CurrentTrack.Elements[n].Events, m + 1);
                     double d = Data.Blocks[i].Sound[j].TrackPosition - StartingDistance;
                     switch (Data.Blocks[i].Sound[j].Type) {
                         case SoundType.TrainStatic:
                             TrackManager.CurrentTrack.Elements[n].Events[m] = new TrackManager.SoundEvent(d, Data.Blocks[i].Sound[j].SoundBuffer, true, true, false, new Vector3(0.0, 0.0, 0.0), 0.0);
                             break;
                         case SoundType.TrainDynamic:
                             TrackManager.CurrentTrack.Elements[n].Events[m] = new TrackManager.SoundEvent(d, Data.Blocks[i].Sound[j].SoundBuffer, false, false, true, new Vector3(0.0, 0.0, 0.0), Data.Blocks[i].Sound[j].Speed);
                             break;
                     }
                 }
             }
         }
         // turn
         if (Data.Blocks[i].Turn != 0.0) {
             double ag = -Math.Atan(Data.Blocks[i].Turn);
             double cosag = Math.Cos(ag);
             double sinag = Math.Sin(ag);
             World.Rotate(ref Direction, cosag, sinag);
             World.RotatePlane(ref TrackManager.CurrentTrack.Elements[n].WorldDirection, cosag, sinag);
             World.RotatePlane(ref TrackManager.CurrentTrack.Elements[n].WorldSide, cosag, sinag);
             World.Cross(TrackManager.CurrentTrack.Elements[n].WorldDirection.X, TrackManager.CurrentTrack.Elements[n].WorldDirection.Y, TrackManager.CurrentTrack.Elements[n].WorldDirection.Z, TrackManager.CurrentTrack.Elements[n].WorldSide.X, TrackManager.CurrentTrack.Elements[n].WorldSide.Y, TrackManager.CurrentTrack.Elements[n].WorldSide.Z, out TrackManager.CurrentTrack.Elements[n].WorldUp.X, out TrackManager.CurrentTrack.Elements[n].WorldUp.Y, out TrackManager.CurrentTrack.Elements[n].WorldUp.Z);
         }
         // curves
         double a = 0.0;
         double c = Data.BlockInterval;
         double h = 0.0;
         if (WorldTrackElement.CurveRadius != 0.0 & Data.Blocks[i].Pitch != 0.0) {
             double d = Data.BlockInterval;
             double p = Data.Blocks[i].Pitch;
             double r = WorldTrackElement.CurveRadius;
             double s = d / Math.Sqrt(1.0 + p * p);
             h = s * p;
             double b = s / Math.Abs(r);
             c = Math.Sqrt(2.0 * r * r * (1.0 - Math.Cos(b)));
             a = 0.5 * (double)Math.Sign(r) * b;
             World.Rotate(ref Direction, Math.Cos(-a), Math.Sin(-a));
         } else if (WorldTrackElement.CurveRadius != 0.0) {
             double d = Data.BlockInterval;
             double r = WorldTrackElement.CurveRadius;
             double b = d / Math.Abs(r);
             c = Math.Sqrt(2.0 * r * r * (1.0 - Math.Cos(b)));
             a = 0.5 * (double)Math.Sign(r) * b;
             World.Rotate(ref Direction, Math.Cos(-a), Math.Sin(-a));
         } else if (Data.Blocks[i].Pitch != 0.0) {
             double p = Data.Blocks[i].Pitch;
             double d = Data.BlockInterval;
             c = d / Math.Sqrt(1.0 + p * p);
             h = c * p;
         }
         double TrackYaw = Math.Atan2(Direction.X, Direction.Y);
         double TrackPitch = Math.Atan(Data.Blocks[i].Pitch);
         World.Transformation GroundTransformation = new World.Transformation(TrackYaw, 0.0, 0.0);
         World.Transformation TrackTransformation = new World.Transformation(TrackYaw, TrackPitch, 0.0);
         World.Transformation NullTransformation = new World.Transformation(0.0, 0.0, 0.0);
         // ground
         if (!PreviewOnly) {
             int cb = (int)Math.Floor((double)i + 0.001);
             int ci = (cb % Data.Blocks[i].Cycle.Length + Data.Blocks[i].Cycle.Length) % Data.Blocks[i].Cycle.Length;
             int gi = Data.Blocks[i].Cycle[ci];
             if (gi >= 0 & gi < Data.Structure.Ground.Length) {
                 if (Data.Structure.Ground[gi] != null) {
                     ObjectManager.CreateObject(Data.Structure.Ground[Data.Blocks[i].Cycle[ci]], Position + new Vector3(0.0, -Data.Blocks[i].Height, 0.0), GroundTransformation, NullTransformation, Data.AccurateObjectDisposal, StartingDistance, EndingDistance, Data.BlockInterval, StartingDistance);
                 }
             }
         }
         // ground-aligned free objects
         if (!PreviewOnly) {
             for (int j = 0; j < Data.Blocks[i].GroundFreeObj.Length; j++) {
                 int sttype = Data.Blocks[i].GroundFreeObj[j].Type;
                 double d = Data.Blocks[i].GroundFreeObj[j].TrackPosition - StartingDistance;
                 double dx = Data.Blocks[i].GroundFreeObj[j].X;
                 double dy = Data.Blocks[i].GroundFreeObj[j].Y;
                 Vector3 wpos = Position + new Vector3(Direction.X * d + Direction.Y * dx, dy - Data.Blocks[i].Height, Direction.Y * d - Direction.X * dx);
                 double tpos = Data.Blocks[i].GroundFreeObj[j].TrackPosition;
                 ObjectManager.CreateObject(Data.Structure.FreeObj[sttype], wpos, GroundTransformation, new World.Transformation(Data.Blocks[i].GroundFreeObj[j].Yaw, Data.Blocks[i].GroundFreeObj[j].Pitch, Data.Blocks[i].GroundFreeObj[j].Roll), Data.AccurateObjectDisposal, StartingDistance, EndingDistance, Data.BlockInterval, tpos);
             }
         }
         // rail-aligned objects
         if (!PreviewOnly) {
             for (int j = 0; j < Data.Blocks[i].Rail.Length; j++) {
                 if (j > 0 && !Data.Blocks[i].Rail[j].RailStart) continue;
                 // rail
                 Vector3 pos;
                 World.Transformation RailTransformation;
                 double planar, updown;
                 if (j == 0) {
                     // rail 0
                     pos = Position;
                     planar = 0.0;
                     updown = 0.0;
                     RailTransformation = new World.Transformation(TrackTransformation, planar, updown, 0.0);
                     pos = Position;
                 } else {
                     // rails 1-infinity
                     double x = Data.Blocks[i].Rail[j].RailStartX;
                     double y = Data.Blocks[i].Rail[j].RailStartY;
                     Vector3 offset = new Vector3(Direction.Y * x, y, -Direction.X * x);
                     pos = Position + offset;
                     double dh;
                     if (i < Data.Blocks.Length - 1 && Data.Blocks[i + 1].Rail.Length > j) {
                         // take orientation of upcoming block into account
                         World.Vector2D Direction2 = Direction;
                         Vector3 Position2 = Position;
                         Position2.X += Direction.X * c;
                         Position2.Y += h;
                         Position2.Z += Direction.Y * c;
                         if (a != 0.0) {
                             World.Rotate(ref Direction2, Math.Cos(-a), Math.Sin(-a));
                         }
                         if (Data.Blocks[i + 1].Turn != 0.0) {
                             double ag = -Math.Atan(Data.Blocks[i + 1].Turn);
                             double cosag = Math.Cos(ag);
                             double sinag = Math.Sin(ag);
                             World.Rotate(ref Direction2, cosag, sinag);
                         }
                         double a2 = 0.0;
                         double c2 = Data.BlockInterval;
                         double h2 = 0.0;
                         if (Data.Blocks[i + 1].CurrentTrackState.CurveRadius != 0.0 & Data.Blocks[i + 1].Pitch != 0.0) {
                             double d2 = Data.BlockInterval;
                             double p2 = Data.Blocks[i + 1].Pitch;
                             double r2 = Data.Blocks[i + 1].CurrentTrackState.CurveRadius;
                             double s2 = d2 / Math.Sqrt(1.0 + p2 * p2);
                             h2 = s2 * p2;
                             double b2 = s2 / Math.Abs(r2);
                             c2 = Math.Sqrt(2.0 * r2 * r2 * (1.0 - Math.Cos(b2)));
                             a2 = 0.5 * (double)Math.Sign(r2) * b2;
                             World.Rotate(ref Direction2, Math.Cos(-a2), Math.Sin(-a2));
                         } else if (Data.Blocks[i + 1].CurrentTrackState.CurveRadius != 0.0) {
                             double d2 = Data.BlockInterval;
                             double r2 = Data.Blocks[i + 1].CurrentTrackState.CurveRadius;
                             double b2 = d2 / Math.Abs(r2);
                             c2 = Math.Sqrt(2.0 * r2 * r2 * (1.0 - Math.Cos(b2)));
                             a2 = 0.5 * (double)Math.Sign(r2) * b2;
                             World.Rotate(ref Direction2, Math.Cos(-a2), Math.Sin(-a2));
                         } else if (Data.Blocks[i + 1].Pitch != 0.0) {
                             double p2 = Data.Blocks[i + 1].Pitch;
                             double d2 = Data.BlockInterval;
                             c2 = d2 / Math.Sqrt(1.0 + p2 * p2);
                             h2 = c2 * p2;
                         }
                         double TrackYaw2 = Math.Atan2(Direction2.X, Direction2.Y);
                         double TrackPitch2 = Math.Atan(Data.Blocks[i + 1].Pitch);
                         World.Transformation GroundTransformation2 = new World.Transformation(TrackYaw2, 0.0, 0.0);
                         World.Transformation TrackTransformation2 = new World.Transformation(TrackYaw2, TrackPitch2, 0.0);
                         double x2 = Data.Blocks[i + 1].Rail[j].RailEndX;
                         double y2 = Data.Blocks[i + 1].Rail[j].RailEndY;
                         Vector3 offset2 = new Vector3(Direction2.Y * x2, y2, -Direction2.X * x2);
                         Vector3 pos2 = Position2 + offset2;
                         double rx = pos2.X - pos.X;
                         double ry = pos2.Y - pos.Y;
                         double rz = pos2.Z - pos.Z;
                         World.Normalize(ref rx, ref ry, ref rz);
                         RailTransformation.Z = new Vector3(rx, ry, rz);
                         RailTransformation.X = new Vector3(rz, 0.0, -rx);
                         World.Normalize(ref RailTransformation.X.X, ref RailTransformation.X.Z);
                         RailTransformation.Y = Vector3.Cross(RailTransformation.Z, RailTransformation.X);
                         double dx = Data.Blocks[i + 1].Rail[j].RailEndX - Data.Blocks[i].Rail[j].RailStartX;
                         double dy = Data.Blocks[i + 1].Rail[j].RailEndY - Data.Blocks[i].Rail[j].RailStartY;
                         planar = Math.Atan(dx / c);
                         dh = dy / c;
                         updown = Math.Atan(dh);
                     } else {
                         planar = 0.0;
                         dh = 0.0;
                         updown = 0.0;
                         RailTransformation = new World.Transformation(TrackTransformation, 0.0, 0.0, 0.0);
                     }
                 }
                 if (Data.Blocks[i].RailType[j] < Data.Structure.Rail.Length) {
                     if (Data.Structure.Rail[Data.Blocks[i].RailType[j]] != null) {
                         ObjectManager.CreateObject(Data.Structure.Rail[Data.Blocks[i].RailType[j]], pos, RailTransformation, NullTransformation, Data.AccurateObjectDisposal, StartingDistance, EndingDistance, Data.BlockInterval, StartingDistance);
                     }
                 }
                 // points of interest
                 for (int k = 0; k < Data.Blocks[i].PointsOfInterest.Length; k++) {
                     if (Data.Blocks[i].PointsOfInterest[k].RailIndex == j) {
                         double d = Data.Blocks[i].PointsOfInterest[k].TrackPosition - StartingDistance;
                         double x = Data.Blocks[i].PointsOfInterest[k].X;
                         double y = Data.Blocks[i].PointsOfInterest[k].Y;
                         int m = Game.PointsOfInterest.Length;
                         Array.Resize<Game.PointOfInterest>(ref Game.PointsOfInterest, m + 1);
                         Game.PointsOfInterest[m].TrackPosition = Data.Blocks[i].PointsOfInterest[k].TrackPosition;
                         if (i < Data.Blocks.Length - 1 && Data.Blocks[i + 1].Rail.Length > j) {
                             double dx = Data.Blocks[i + 1].Rail[j].RailEndX - Data.Blocks[i].Rail[j].RailStartX;
                             double dy = Data.Blocks[i + 1].Rail[j].RailEndY - Data.Blocks[i].Rail[j].RailStartY;
                             dx = Data.Blocks[i].Rail[j].RailStartX + d / Data.BlockInterval * dx;
                             dy = Data.Blocks[i].Rail[j].RailStartY + d / Data.BlockInterval * dy;
                             Game.PointsOfInterest[m].TrackOffset = new Vector3(x + dx, y + dy, 0.0);
                         } else {
                             double dx = Data.Blocks[i].Rail[j].RailStartX;
                             double dy = Data.Blocks[i].Rail[j].RailStartY;
                             Game.PointsOfInterest[m].TrackOffset = new Vector3(x + dx, y + dy, 0.0);
                         }
                         Game.PointsOfInterest[m].TrackYaw = Data.Blocks[i].PointsOfInterest[k].Yaw + planar;
                         Game.PointsOfInterest[m].TrackPitch = Data.Blocks[i].PointsOfInterest[k].Pitch + updown;
                         Game.PointsOfInterest[m].TrackRoll = Data.Blocks[i].PointsOfInterest[k].Roll;
                         Game.PointsOfInterest[m].Text = Data.Blocks[i].PointsOfInterest[k].Text;
                     }
                 }
                 // poles
                 if (Data.Blocks[i].RailPole.Length > j && Data.Blocks[i].RailPole[j].Exists) {
                     double dz = StartingDistance / Data.Blocks[i].RailPole[j].Interval;
                     dz -= Math.Floor(dz + 0.5);
                     if (dz >= -0.01 & dz <= 0.01) {
                         if (Data.Blocks[i].RailPole[j].Mode == 0) {
                             if (Data.Blocks[i].RailPole[j].Location <= 0.0) {
                                 ObjectManager.CreateObject(Data.Structure.Poles[0][Data.Blocks[i].RailPole[j].Type], pos, RailTransformation, NullTransformation, Data.AccurateObjectDisposal, StartingDistance, EndingDistance, Data.BlockInterval, StartingDistance);
                             } else {
                                 ObjectManager.UnifiedObject Pole = GetMirroredObject(Data.Structure.Poles[0][Data.Blocks[i].RailPole[j].Type]);
                                 ObjectManager.CreateObject(Pole, pos, RailTransformation, NullTransformation, Data.AccurateObjectDisposal, StartingDistance, EndingDistance, Data.BlockInterval, StartingDistance);
                             }
                         } else {
                             int m = Data.Blocks[i].RailPole[j].Mode;
                             double dx = -Data.Blocks[i].RailPole[j].Location * 3.8;
                             double wa = Math.Atan2(Direction.Y, Direction.X) - planar;
                             double wx = Math.Cos(wa);
                             double wy = Math.Tan(updown);
                             double wz = Math.Sin(wa);
                             World.Normalize(ref wx, ref wy, ref wz);
                             double sx = Direction.Y;
                             double sy = 0.0;
                             double sz = -Direction.X;
                             Vector3 wpos = pos + new Vector3(sx * dx + wx * dz, sy * dx + wy * dz, sz * dx + wz * dz);
                             int type = Data.Blocks[i].RailPole[j].Type;
                             ObjectManager.CreateObject(Data.Structure.Poles[m][type], wpos, RailTransformation, NullTransformation, Data.AccurateObjectDisposal, StartingDistance, EndingDistance, Data.BlockInterval, StartingDistance);
                         }
                     }
                 }
                 // walls
                 if (Data.Blocks[i].RailWall.Length > j && Data.Blocks[i].RailWall[j].Exists) {
                     if (Data.Blocks[i].RailWall[j].Direction <= 0) {
                         ObjectManager.CreateObject(Data.Structure.WallL[Data.Blocks[i].RailWall[j].Type], pos, RailTransformation, NullTransformation, Data.AccurateObjectDisposal, StartingDistance, EndingDistance, Data.BlockInterval, StartingDistance);
                     }
                     if (Data.Blocks[i].RailWall[j].Direction >= 0) {
                         ObjectManager.CreateObject(Data.Structure.WallR[Data.Blocks[i].RailWall[j].Type], pos, RailTransformation, NullTransformation, Data.AccurateObjectDisposal, StartingDistance, EndingDistance, Data.BlockInterval, StartingDistance);
                     }
                 }
                 // dikes
                 if (Data.Blocks[i].RailDike.Length > j && Data.Blocks[i].RailDike[j].Exists) {
                     if (Data.Blocks[i].RailDike[j].Direction <= 0) {
                         ObjectManager.CreateObject(Data.Structure.DikeL[Data.Blocks[i].RailDike[j].Type], pos, RailTransformation, NullTransformation, Data.AccurateObjectDisposal, StartingDistance, EndingDistance, Data.BlockInterval, StartingDistance);
                     }
                     if (Data.Blocks[i].RailDike[j].Direction >= 0) {
                         ObjectManager.CreateObject(Data.Structure.DikeR[Data.Blocks[i].RailDike[j].Type], pos, RailTransformation, NullTransformation, Data.AccurateObjectDisposal, StartingDistance, EndingDistance, Data.BlockInterval, StartingDistance);
                     }
                 }
                 // sounds
                 if (j == 0) {
                     for (int k = 0; k < Data.Blocks[i].Sound.Length; k++) {
                         if (Data.Blocks[i].Sound[k].Type == SoundType.World) {
                             if (Data.Blocks[i].Sound[k].SoundBuffer != null) {
                                 double d = Data.Blocks[i].Sound[k].TrackPosition - StartingDistance;
                                 double dx = Data.Blocks[i].Sound[k].X;
                                 double dy = Data.Blocks[i].Sound[k].Y;
                                 double wa = Math.Atan2(Direction.Y, Direction.X) - planar;
                                 double wx = Math.Cos(wa);
                                 double wy = Math.Tan(updown);
                                 double wz = Math.Sin(wa);
                                 World.Normalize(ref wx, ref wy, ref wz);
                                 double sx = Direction.Y;
                                 double sy = 0.0;
                                 double sz = -Direction.X;
                                 double ux, uy, uz;
                                 World.Cross(wx, wy, wz, sx, sy, sz, out ux, out uy, out uz);
                                 Vector3 wpos = pos + new Vector3(sx * dx + ux * dy + wx * d, sy * dx + uy * dy + wy * d, sz * dx + uz * dy + wz * d);
                                 Sounds.PlaySound(Data.Blocks[i].Sound[k].SoundBuffer, 1.0, 1.0, wpos, true);
                             }
                         }
                     }
                 }
                 // forms
                 for (int k = 0; k < Data.Blocks[i].Form.Length; k++) {
                     // primary rail
                     if (Data.Blocks[i].Form[k].PrimaryRail == j) {
                         if (Data.Blocks[i].Form[k].SecondaryRail == Form.SecondaryRailStub) {
                             if (Data.Blocks[i].Form[k].FormType >= Data.Structure.FormL.Length || Data.Structure.FormL[Data.Blocks[i].Form[k].FormType] == null) {
                                 Interface.AddMessage(Interface.MessageType.Error, false, "FormStructureIndex references a FormL not loaded in Track.Form at track position " + StartingDistance.ToString(Culture) + " in file " + FileName + ".");
                             } else {
                                 ObjectManager.CreateObject(Data.Structure.FormL[Data.Blocks[i].Form[k].FormType], pos, RailTransformation, NullTransformation, Data.AccurateObjectDisposal, StartingDistance, EndingDistance, Data.BlockInterval, StartingDistance);
                                 if (Data.Blocks[i].Form[k].RoofType > 0) {
                                     if (Data.Blocks[i].Form[k].RoofType >= Data.Structure.RoofL.Length || Data.Structure.RoofL[Data.Blocks[i].Form[k].RoofType] == null) {
                                         Interface.AddMessage(Interface.MessageType.Error, false, "RoofStructureIndex references a RoofL not loaded in Track.Form at track position " + StartingDistance.ToString(Culture) + " in file " + FileName + ".");
                                     } else {
                                         ObjectManager.CreateObject(Data.Structure.RoofL[Data.Blocks[i].Form[k].RoofType], pos, RailTransformation, NullTransformation, Data.AccurateObjectDisposal, StartingDistance, EndingDistance, Data.BlockInterval, StartingDistance);
                                     }
                                 }
                             }
                         } else if (Data.Blocks[i].Form[k].SecondaryRail == Form.SecondaryRailL) {
                             if (Data.Blocks[i].Form[k].FormType >= Data.Structure.FormL.Length || Data.Structure.FormL[Data.Blocks[i].Form[k].FormType] == null) {
                                 Interface.AddMessage(Interface.MessageType.Error, false, "FormStructureIndex references a FormL not loaded in Track.Form at track position " + StartingDistance.ToString(Culture) + " in file " + FileName + ".");
                             } else {
                                 ObjectManager.CreateObject(Data.Structure.FormL[Data.Blocks[i].Form[k].FormType], pos, RailTransformation, NullTransformation, Data.AccurateObjectDisposal, StartingDistance, EndingDistance, Data.BlockInterval, StartingDistance);
                             }
                             if (Data.Blocks[i].Form[k].FormType >= Data.Structure.FormCL.Length || Data.Structure.FormCL[Data.Blocks[i].Form[k].FormType] == null) {
                                 Interface.AddMessage(Interface.MessageType.Error, false, "FormStructureIndex references a FormCL not loaded in Track.Form at track position " + StartingDistance.ToString(Culture) + " in file " + FileName + ".");
                             } else {
                                 ObjectManager.CreateStaticObject(Data.Structure.FormCL[Data.Blocks[i].Form[k].FormType], pos, RailTransformation, NullTransformation, Data.AccurateObjectDisposal, StartingDistance, EndingDistance, Data.BlockInterval, StartingDistance);
                             }
                             if (Data.Blocks[i].Form[k].RoofType > 0) {
                                 if (Data.Blocks[i].Form[k].RoofType >= Data.Structure.RoofL.Length || Data.Structure.RoofL[Data.Blocks[i].Form[k].RoofType] == null) {
                                     Interface.AddMessage(Interface.MessageType.Error, false, "RoofStructureIndex references a RoofL not loaded in Track.Form at track position " + StartingDistance.ToString(Culture) + " in file " + FileName + ".");
                                 } else {
                                     ObjectManager.CreateObject(Data.Structure.RoofL[Data.Blocks[i].Form[k].RoofType], pos, RailTransformation, NullTransformation, Data.AccurateObjectDisposal, StartingDistance, EndingDistance, Data.BlockInterval, StartingDistance);
                                 }
                                 if (Data.Blocks[i].Form[k].RoofType >= Data.Structure.RoofCL.Length || Data.Structure.RoofCL[Data.Blocks[i].Form[k].RoofType] == null) {
                                     Interface.AddMessage(Interface.MessageType.Error, false, "RoofStructureIndex references a RoofCL not loaded in Track.Form at track position " + StartingDistance.ToString(Culture) + " in file " + FileName + ".");
                                 } else {
                                     ObjectManager.CreateStaticObject(Data.Structure.RoofCL[Data.Blocks[i].Form[k].RoofType], pos, RailTransformation, NullTransformation, Data.AccurateObjectDisposal, StartingDistance, EndingDistance, Data.BlockInterval, StartingDistance);
                                 }
                             }
                         } else if (Data.Blocks[i].Form[k].SecondaryRail == Form.SecondaryRailR) {
                             if (Data.Blocks[i].Form[k].FormType >= Data.Structure.FormR.Length || Data.Structure.FormR[Data.Blocks[i].Form[k].FormType] == null) {
                                 Interface.AddMessage(Interface.MessageType.Error, false, "FormStructureIndex references a FormR not loaded in Track.Form at track position " + StartingDistance.ToString(Culture) + " in file " + FileName + ".");
                             } else {
                                 ObjectManager.CreateObject(Data.Structure.FormR[Data.Blocks[i].Form[k].FormType], pos, RailTransformation, NullTransformation, Data.AccurateObjectDisposal, StartingDistance, EndingDistance, Data.BlockInterval, StartingDistance);
                             }
                             if (Data.Blocks[i].Form[k].FormType >= Data.Structure.FormCR.Length || Data.Structure.FormCR[Data.Blocks[i].Form[k].FormType] == null) {
                                 Interface.AddMessage(Interface.MessageType.Error, false, "FormStructureIndex references a FormCR not loaded in Track.Form at track position " + StartingDistance.ToString(Culture) + " in file " + FileName + ".");
                             } else {
                                 ObjectManager.CreateStaticObject(Data.Structure.FormCR[Data.Blocks[i].Form[k].FormType], pos, RailTransformation, NullTransformation, Data.AccurateObjectDisposal, StartingDistance, EndingDistance, Data.BlockInterval, StartingDistance);
                             }
                             if (Data.Blocks[i].Form[k].RoofType > 0) {
                                 if (Data.Blocks[i].Form[k].RoofType >= Data.Structure.RoofR.Length || Data.Structure.RoofR[Data.Blocks[i].Form[k].RoofType] == null) {
                                     Interface.AddMessage(Interface.MessageType.Error, false, "RoofStructureIndex references a RoofR not loaded in Track.Form at track position " + StartingDistance.ToString(Culture) + " in file " + FileName + ".");
                                 } else {
                                     ObjectManager.CreateObject(Data.Structure.RoofR[Data.Blocks[i].Form[k].RoofType], pos, RailTransformation, NullTransformation, Data.AccurateObjectDisposal, StartingDistance, EndingDistance, Data.BlockInterval, StartingDistance);
                                 }
                                 if (Data.Blocks[i].Form[k].RoofType >= Data.Structure.RoofCR.Length || Data.Structure.RoofCR[Data.Blocks[i].Form[k].RoofType] == null) {
                                     Interface.AddMessage(Interface.MessageType.Error, false, "RoofStructureIndex references a RoofCR not loaded in Track.Form at track position " + StartingDistance.ToString(Culture) + " in file " + FileName + ".");
                                 } else {
                                     ObjectManager.CreateStaticObject(Data.Structure.RoofCR[Data.Blocks[i].Form[k].RoofType], pos, RailTransformation, NullTransformation, Data.AccurateObjectDisposal, StartingDistance, EndingDistance, Data.BlockInterval, StartingDistance);
                                 }
                             }
                         } else if (Data.Blocks[i].Form[k].SecondaryRail > 0) {
                             int p = Data.Blocks[i].Form[k].PrimaryRail;
                             double px0 = p > 0 ? Data.Blocks[i].Rail[p].RailStartX : 0.0;
                             double px1 = p > 0 ? Data.Blocks[i + 1].Rail[p].RailEndX : 0.0;
                             int s = Data.Blocks[i].Form[k].SecondaryRail;
                             if (s < 0 || s >= Data.Blocks[i].Rail.Length || !Data.Blocks[i].Rail[s].RailStart) {
                                 Interface.AddMessage(Interface.MessageType.Error, false, "RailIndex2 is out of range in Track.Form at track position " + StartingDistance.ToString(Culture) + " in file " + FileName);
                             } else {
                                 double sx0 = Data.Blocks[i].Rail[s].RailStartX;
                                 double sx1 = Data.Blocks[i + 1].Rail[s].RailEndX;
                                 double d0 = sx0 - px0;
                                 double d1 = sx1 - px1;
                                 if (d0 < 0.0) {
                                     if (Data.Blocks[i].Form[k].FormType >= Data.Structure.FormL.Length || Data.Structure.FormL[Data.Blocks[i].Form[k].FormType] == null) {
                                         Interface.AddMessage(Interface.MessageType.Error, false, "FormStructureIndex references a FormL not loaded in Track.Form at track position " + StartingDistance.ToString(Culture) + " in file " + FileName + ".");
                                     } else {
                                         ObjectManager.CreateObject(Data.Structure.FormL[Data.Blocks[i].Form[k].FormType], pos, RailTransformation, NullTransformation, Data.AccurateObjectDisposal, StartingDistance, EndingDistance, Data.BlockInterval, StartingDistance);
                                     }
                                     if (Data.Blocks[i].Form[k].FormType >= Data.Structure.FormCL.Length || Data.Structure.FormCL[Data.Blocks[i].Form[k].FormType] == null) {
                                         Interface.AddMessage(Interface.MessageType.Error, false, "FormStructureIndex references a FormCL not loaded in Track.Form at track position " + StartingDistance.ToString(Culture) + " in file " + FileName + ".");
                                     } else {
                                         ObjectManager.StaticObject FormC = GetTransformedStaticObject(Data.Structure.FormCL[Data.Blocks[i].Form[k].FormType], d0, d1);
                                         ObjectManager.CreateStaticObject(FormC, pos, RailTransformation, NullTransformation, Data.AccurateObjectDisposal, StartingDistance, EndingDistance, Data.BlockInterval, StartingDistance);
                                     }
                                     if (Data.Blocks[i].Form[k].RoofType > 0) {
                                         if (Data.Blocks[i].Form[k].RoofType >= Data.Structure.RoofL.Length || Data.Structure.RoofL[Data.Blocks[i].Form[k].RoofType] == null) {
                                             Interface.AddMessage(Interface.MessageType.Error, false, "RoofStructureIndex references a RoofL not loaded in Track.Form at track position " + StartingDistance.ToString(Culture) + " in file " + FileName + ".");
                                         } else {
                                             ObjectManager.CreateObject(Data.Structure.RoofL[Data.Blocks[i].Form[k].RoofType], pos, RailTransformation, NullTransformation, Data.AccurateObjectDisposal, StartingDistance, EndingDistance, Data.BlockInterval, StartingDistance);
                                         }
                                         if (Data.Blocks[i].Form[k].RoofType >= Data.Structure.RoofCL.Length || Data.Structure.RoofCL[Data.Blocks[i].Form[k].RoofType] == null) {
                                             Interface.AddMessage(Interface.MessageType.Error, false, "RoofStructureIndex references a RoofCL not loaded in Track.Form at track position " + StartingDistance.ToString(Culture) + " in file " + FileName + ".");
                                         } else {
                                             ObjectManager.StaticObject RoofC = GetTransformedStaticObject(Data.Structure.RoofCL[Data.Blocks[i].Form[k].RoofType], d0, d1);
                                             ObjectManager.CreateStaticObject(RoofC, pos, RailTransformation, NullTransformation, Data.AccurateObjectDisposal, StartingDistance, EndingDistance, Data.BlockInterval, StartingDistance);
                                         }
                                     }
                                 } else if (d0 > 0.0) {
                                     if (Data.Blocks[i].Form[k].FormType >= Data.Structure.FormR.Length || Data.Structure.FormR[Data.Blocks[i].Form[k].FormType] == null) {
                                         Interface.AddMessage(Interface.MessageType.Error, false, "FormStructureIndex references a FormR not loaded in Track.Form at track position " + StartingDistance.ToString(Culture) + " in file " + FileName + ".");
                                     } else {
                                         ObjectManager.CreateObject(Data.Structure.FormR[Data.Blocks[i].Form[k].FormType], pos, RailTransformation, NullTransformation, Data.AccurateObjectDisposal, StartingDistance, EndingDistance, Data.BlockInterval, StartingDistance);
                                     }
                                     if (Data.Blocks[i].Form[k].FormType >= Data.Structure.FormCR.Length || Data.Structure.FormCR[Data.Blocks[i].Form[k].FormType] == null) {
                                         Interface.AddMessage(Interface.MessageType.Error, false, "FormStructureIndex references a FormCR not loaded in Track.Form at track position " + StartingDistance.ToString(Culture) + " in file " + FileName + ".");
                                     } else {
                                         ObjectManager.StaticObject FormC = GetTransformedStaticObject(Data.Structure.FormCR[Data.Blocks[i].Form[k].FormType], d0, d1);
                                         ObjectManager.CreateStaticObject(FormC, pos, RailTransformation, NullTransformation, Data.AccurateObjectDisposal, StartingDistance, EndingDistance, Data.BlockInterval, StartingDistance);
                                     }
                                     if (Data.Blocks[i].Form[k].RoofType > 0) {
                                         if (Data.Blocks[i].Form[k].RoofType >= Data.Structure.RoofR.Length || Data.Structure.RoofR[Data.Blocks[i].Form[k].RoofType] == null) {
                                             Interface.AddMessage(Interface.MessageType.Error, false, "RoofStructureIndex references a RoofR not loaded in Track.Form at track position " + StartingDistance.ToString(Culture) + " in file " + FileName + ".");
                                         } else {
                                             ObjectManager.CreateObject(Data.Structure.RoofR[Data.Blocks[i].Form[k].RoofType], pos, RailTransformation, NullTransformation, Data.AccurateObjectDisposal, StartingDistance, EndingDistance, Data.BlockInterval, StartingDistance);
                                         }
                                         if (Data.Blocks[i].Form[k].RoofType >= Data.Structure.RoofCR.Length || Data.Structure.RoofCR[Data.Blocks[i].Form[k].RoofType] == null) {
                                             Interface.AddMessage(Interface.MessageType.Error, false, "RoofStructureIndex references a RoofCR not loaded in Track.Form at track position " + StartingDistance.ToString(Culture) + " in file " + FileName + ".");
                                         } else {
                                             ObjectManager.StaticObject RoofC = GetTransformedStaticObject(Data.Structure.RoofCR[Data.Blocks[i].Form[k].RoofType], d0, d1);
                                             ObjectManager.CreateStaticObject(RoofC, pos, RailTransformation, NullTransformation, Data.AccurateObjectDisposal, StartingDistance, EndingDistance, Data.BlockInterval, StartingDistance);
                                         }
                                     }
                                 }
                             }
                         }
                     }
                     // secondary rail
                     if (Data.Blocks[i].Form[k].SecondaryRail == j) {
                         int p = Data.Blocks[i].Form[k].PrimaryRail;
                         double px = p > 0 ? Data.Blocks[i].Rail[p].RailStartX : 0.0;
                         int s = Data.Blocks[i].Form[k].SecondaryRail;
                         double sx = Data.Blocks[i].Rail[s].RailStartX;
                         double d = px - sx;
                         if (d < 0.0) {
                             if (Data.Blocks[i].Form[k].FormType >= Data.Structure.FormL.Length || Data.Structure.FormL[Data.Blocks[i].Form[k].FormType] == null) {
                                 Interface.AddMessage(Interface.MessageType.Error, false, "FormStructureIndex references a FormL not loaded in Track.Form at track position " + StartingDistance.ToString(Culture) + " in file " + FileName + ".");
                             } else {
                                 ObjectManager.CreateObject(Data.Structure.FormL[Data.Blocks[i].Form[k].FormType], pos, RailTransformation, NullTransformation, Data.AccurateObjectDisposal, StartingDistance, EndingDistance, Data.BlockInterval, StartingDistance);
                             }
                             if (Data.Blocks[i].Form[k].RoofType > 0) {
                                 if (Data.Blocks[i].Form[k].RoofType >= Data.Structure.RoofL.Length || Data.Structure.RoofL[Data.Blocks[i].Form[k].RoofType] == null) {
                                     Interface.AddMessage(Interface.MessageType.Error, false, "RoofStructureIndex references a RoofL not loaded in Track.Form at track position " + StartingDistance.ToString(Culture) + " in file " + FileName + ".");
                                 } else {
                                     ObjectManager.CreateObject(Data.Structure.RoofL[Data.Blocks[i].Form[k].RoofType], pos, RailTransformation, NullTransformation, Data.AccurateObjectDisposal, StartingDistance, EndingDistance, Data.BlockInterval, StartingDistance);
                                 }
                             }
                         } else {
                             if (Data.Blocks[i].Form[k].FormType >= Data.Structure.FormR.Length || Data.Structure.FormR[Data.Blocks[i].Form[k].FormType] == null) {
                                 Interface.AddMessage(Interface.MessageType.Error, false, "FormStructureIndex references a FormR not loaded in Track.Form at track position " + StartingDistance.ToString(Culture) + " in file " + FileName + ".");
                             } else {
                                 ObjectManager.CreateObject(Data.Structure.FormR[Data.Blocks[i].Form[k].FormType], pos, RailTransformation, NullTransformation, Data.AccurateObjectDisposal, StartingDistance, EndingDistance, Data.BlockInterval, StartingDistance);
                             }
                             if (Data.Blocks[i].Form[k].RoofType > 0) {
                                 if (Data.Blocks[i].Form[k].RoofType >= Data.Structure.RoofR.Length || Data.Structure.RoofR[Data.Blocks[i].Form[k].RoofType] == null) {
                                     Interface.AddMessage(Interface.MessageType.Error, false, "RoofStructureIndex references a RoofR not loaded in Track.Form at track position " + StartingDistance.ToString(Culture) + " in file " + FileName + ".");
                                 } else {
                                     ObjectManager.CreateObject(Data.Structure.RoofR[Data.Blocks[i].Form[k].RoofType], pos, RailTransformation, NullTransformation, Data.AccurateObjectDisposal, StartingDistance, EndingDistance, Data.BlockInterval, StartingDistance);
                                 }
                             }
                         }
                     }
                 }
                 // cracks
                 for (int k = 0; k < Data.Blocks[i].Crack.Length; k++) {
                     if (Data.Blocks[i].Crack[k].PrimaryRail == j) {
                         int p = Data.Blocks[i].Crack[k].PrimaryRail;
                         double px0 = p > 0 ? Data.Blocks[i].Rail[p].RailStartX : 0.0;
                         double px1 = p > 0 ? Data.Blocks[i + 1].Rail[p].RailEndX : 0.0;
                         int s = Data.Blocks[i].Crack[k].SecondaryRail;
                         if (s < 0 || s >= Data.Blocks[i].Rail.Length || !Data.Blocks[i].Rail[s].RailStart) {
                             Interface.AddMessage(Interface.MessageType.Error, false, "RailIndex2 is out of range in Track.Crack at track position " + StartingDistance.ToString(Culture) + " in file " + FileName);
                         } else {
                             double sx0 = Data.Blocks[i].Rail[s].RailStartX;
                             double sx1 = Data.Blocks[i + 1].Rail[s].RailEndX;
                             double d0 = sx0 - px0;
                             double d1 = sx1 - px1;
                             if (d0 < 0.0) {
                                 if (Data.Blocks[i].Crack[k].Type >= Data.Structure.CrackL.Length || Data.Structure.CrackL[Data.Blocks[i].Crack[k].Type] == null) {
                                     Interface.AddMessage(Interface.MessageType.Error, false, "CrackStructureIndex references a CrackL not loaded in Track.Crack at track position " + StartingDistance.ToString(Culture) + " in file " + FileName + ".");
                                 } else {
                                     ObjectManager.StaticObject Crack = GetTransformedStaticObject(Data.Structure.CrackL[Data.Blocks[i].Crack[k].Type], d0, d1);
                                     ObjectManager.CreateStaticObject(Crack, pos, RailTransformation, NullTransformation, Data.AccurateObjectDisposal, StartingDistance, EndingDistance, Data.BlockInterval, StartingDistance);
                                 }
                             } else if (d0 > 0.0) {
                                 if (Data.Blocks[i].Crack[k].Type >= Data.Structure.CrackR.Length || Data.Structure.CrackR[Data.Blocks[i].Crack[k].Type] == null) {
                                     Interface.AddMessage(Interface.MessageType.Error, false, "CrackStructureIndex references a CrackR not loaded in Track.Crack at track position " + StartingDistance.ToString(Culture) + " in file " + FileName + ".");
                                 } else {
                                     ObjectManager.StaticObject Crack = GetTransformedStaticObject(Data.Structure.CrackR[Data.Blocks[i].Crack[k].Type], d0, d1);
                                     ObjectManager.CreateStaticObject(Crack, pos, RailTransformation, NullTransformation, Data.AccurateObjectDisposal, StartingDistance, EndingDistance, Data.BlockInterval, StartingDistance);
                                 }
                             }
                         }
                     }
                 }
                 // free objects
                 if (Data.Blocks[i].RailFreeObj.Length > j && Data.Blocks[i].RailFreeObj[j] != null) {
                     for (int k = 0; k < Data.Blocks[i].RailFreeObj[j].Length; k++) {
                         int sttype = Data.Blocks[i].RailFreeObj[j][k].Type;
                         double dx = Data.Blocks[i].RailFreeObj[j][k].X;
                         double dy = Data.Blocks[i].RailFreeObj[j][k].Y;
                         double dz = Data.Blocks[i].RailFreeObj[j][k].TrackPosition - StartingDistance;
                         Vector3 wpos = pos;
                         wpos.X += dx * RailTransformation.X.X + dy * RailTransformation.Y.X + dz * RailTransformation.Z.X;
                         wpos.Y += dx * RailTransformation.X.Y + dy * RailTransformation.Y.Y + dz * RailTransformation.Z.Y;
                         wpos.Z += dx * RailTransformation.X.Z + dy * RailTransformation.Y.Z + dz * RailTransformation.Z.Z;
                         double tpos = Data.Blocks[i].RailFreeObj[j][k].TrackPosition;
                         ObjectManager.CreateObject(Data.Structure.FreeObj[sttype], wpos, RailTransformation, new World.Transformation(Data.Blocks[i].RailFreeObj[j][k].Yaw, Data.Blocks[i].RailFreeObj[j][k].Pitch, Data.Blocks[i].RailFreeObj[j][k].Roll), -1, Data.AccurateObjectDisposal, StartingDistance, EndingDistance, Data.BlockInterval, tpos, 1.0, false);
                     }
                 }
                 // transponder objects
                 if (j == 0) {
                     for (int k = 0; k < Data.Blocks[i].Transponder.Length; k++) {
                         ObjectManager.UnifiedObject obj = null;
                         if (Data.Blocks[i].Transponder[k].ShowDefaultObject) {
                             switch (Data.Blocks[i].Transponder[k].Type) {
                                     case 0: obj = TransponderS; break;
                                     case 1: obj = TransponderSN; break;
                                     case 2: obj = TransponderFalseStart; break;
                                     case 3: obj = TransponderPOrigin; break;
                                     case 4: obj = TransponderPStop; break;
                             }
                         } else {
                             int b = Data.Blocks[i].Transponder[k].BeaconStructureIndex;
                             if (b >= 0 & b < Data.Structure.Beacon.Length) {
                                 obj = Data.Structure.Beacon[b];
                             }
                         }
                         if (obj != null) {
                             double dx = Data.Blocks[i].Transponder[k].X;
                             double dy = Data.Blocks[i].Transponder[k].Y;
                             double dz = Data.Blocks[i].Transponder[k].TrackPosition - StartingDistance;
                             Vector3 wpos = pos;
                             wpos.X += dx * RailTransformation.X.X + dy * RailTransformation.Y.X + dz * RailTransformation.Z.X;
                             wpos.Y += dx * RailTransformation.X.Y + dy * RailTransformation.Y.Y + dz * RailTransformation.Z.Y;
                             wpos.Z += dx * RailTransformation.X.Z + dy * RailTransformation.Y.Z + dz * RailTransformation.Z.Z;
                             double tpos = Data.Blocks[i].Transponder[k].TrackPosition;
                             if (Data.Blocks[i].Transponder[k].ShowDefaultObject) {
                                 double b = 0.25 + 0.75 * GetBrightness(ref Data, tpos);
                                 ObjectManager.CreateObject(obj, wpos, RailTransformation, new World.Transformation(Data.Blocks[i].Transponder[k].Yaw, Data.Blocks[i].Transponder[k].Pitch, Data.Blocks[i].Transponder[k].Roll), -1, Data.AccurateObjectDisposal, StartingDistance, EndingDistance, Data.BlockInterval, tpos, b, false);
                             } else {
                                 ObjectManager.CreateObject(obj, wpos, RailTransformation, new World.Transformation(Data.Blocks[i].Transponder[k].Yaw, Data.Blocks[i].Transponder[k].Pitch, Data.Blocks[i].Transponder[k].Roll), Data.AccurateObjectDisposal, StartingDistance, EndingDistance, Data.BlockInterval, tpos);
                             }
                         }
                     }
                 }
                 // sections/signals/transponders
                 if (j == 0) {
                     // signals
                     for (int k = 0; k < Data.Blocks[i].Signal.Length; k++) {
                         SignalData sd;
                         if (Data.Blocks[i].Signal[k].SignalCompatibilityObjectIndex >= 0) {
                             sd = Data.CompatibilitySignalData[Data.Blocks[i].Signal[k].SignalCompatibilityObjectIndex];
                         } else {
                             sd = Data.SignalData[Data.Blocks[i].Signal[k].SignalObjectIndex];
                         }
                         // objects
                         double dz = Data.Blocks[i].Signal[k].TrackPosition - StartingDistance;
                         if (Data.Blocks[i].Signal[k].ShowPost) {
                             // post
                             double dx = Data.Blocks[i].Signal[k].X;
                             Vector3 wpos = pos;
                             wpos.X += dx * RailTransformation.X.X + dz * RailTransformation.Z.X;
                             wpos.Y += dx * RailTransformation.X.Y + dz * RailTransformation.Z.Y;
                             wpos.Z += dx * RailTransformation.X.Z + dz * RailTransformation.Z.Z;
                             double tpos = Data.Blocks[i].Signal[k].TrackPosition;
                             double b = 0.25 + 0.75 * GetBrightness(ref Data, tpos);
                             ObjectManager.CreateStaticObject(SignalPost, wpos, RailTransformation, NullTransformation, Data.AccurateObjectDisposal, 0.0, StartingDistance, EndingDistance, Data.BlockInterval, tpos, b, false);
                         }
                         if (Data.Blocks[i].Signal[k].ShowObject) {
                             // signal object
                             double dx = Data.Blocks[i].Signal[k].X;
                             double dy = Data.Blocks[i].Signal[k].Y;
                             Vector3 wpos = pos;
                             wpos.X += dx * RailTransformation.X.X + dy * RailTransformation.Y.X + dz * RailTransformation.Z.X;
                             wpos.Y += dx * RailTransformation.X.Y + dy * RailTransformation.Y.Y + dz * RailTransformation.Z.Y;
                             wpos.Z += dx * RailTransformation.X.Z + dy * RailTransformation.Y.Z + dz * RailTransformation.Z.Z;
                             double tpos = Data.Blocks[i].Signal[k].TrackPosition;
                             if (sd is AnimatedObjectSignalData) {
                                 AnimatedObjectSignalData aosd = (AnimatedObjectSignalData)sd;
                                 ObjectManager.CreateObject(aosd.Objects, wpos, RailTransformation, new World.Transformation(Data.Blocks[i].Signal[k].Yaw, Data.Blocks[i].Signal[k].Pitch, Data.Blocks[i].Signal[k].Roll), Data.Blocks[i].Signal[k].Section, Data.AccurateObjectDisposal, StartingDistance, EndingDistance, Data.BlockInterval, tpos, 1.0, false);
                             } else if (sd is CompatibilitySignalData) {
                                 CompatibilitySignalData csd = (CompatibilitySignalData)sd;
                                 if (csd.Numbers.Length != 0) {
                                     double brightness = 0.25 + 0.75 * GetBrightness(ref Data, tpos);
                                     ObjectManager.AnimatedObjectCollection aoc = new ObjectManager.AnimatedObjectCollection();
                                     aoc.Objects = new ObjectManager.AnimatedObject[1];
                                     aoc.Objects[0] = new ObjectManager.AnimatedObject();
                                     aoc.Objects[0].States = new ObjectManager.AnimatedObjectState[csd.Numbers.Length];
                                     for (int l = 0; l < csd.Numbers.Length; l++) {
                                         aoc.Objects[0].States[l].Object = ObjectManager.CloneObject(csd.Objects[l]);
                                     }
                                     string expr = "";
                                     for (int l = 0; l < csd.Numbers.Length - 1; l++) {
                                         expr += "section " + csd.Numbers[l].ToString(Culture) + " <= " + l.ToString(Culture) + " ";
                                     }
                                     expr += (csd.Numbers.Length - 1).ToString(Culture);
                                     for (int l = 0; l < csd.Numbers.Length - 1; l++) {
                                         expr += " ?";
                                     }
                                     aoc.Objects[0].StateFunction = FunctionScripts.GetFunctionScriptFromPostfixNotation(expr);
                                     aoc.Objects[0].RefreshRate = 1.0 + 0.01 * Program.RandomNumberGenerator.NextDouble();
                                     ObjectManager.CreateObject(aoc, wpos, RailTransformation, new World.Transformation(Data.Blocks[i].Signal[k].Yaw, Data.Blocks[i].Signal[k].Pitch, Data.Blocks[i].Signal[k].Roll), Data.Blocks[i].Signal[k].Section, Data.AccurateObjectDisposal, StartingDistance, EndingDistance, Data.BlockInterval, tpos, brightness, false);
                                 }
                             } else if (sd is Bve4SignalData) {
                                 Bve4SignalData b4sd = (Bve4SignalData)sd;
                                 if (b4sd.SignalTextures.Length != 0) {
                                     int m = Math.Max(b4sd.SignalTextures.Length, b4sd.GlowTextures.Length);
                                     int zn = 0;
                                     for (int l = 0; l < m; l++) {
                                         if (l < b4sd.SignalTextures.Length && b4sd.SignalTextures[l] != null || l < b4sd.GlowTextures.Length && b4sd.GlowTextures[l] != null) {
                                             zn++;
                                         }
                                     }
                                     ObjectManager.AnimatedObjectCollection aoc = new ObjectManager.AnimatedObjectCollection();
                                     aoc.Objects = new ObjectManager.AnimatedObject[1];
                                     aoc.Objects[0] = new ObjectManager.AnimatedObject();
                                     aoc.Objects[0].States = new ObjectManager.AnimatedObjectState[zn];
                                     int zi = 0;
                                     string expr = "";
                                     for (int l = 0; l < m; l++) {
                                         bool qs = l < b4sd.SignalTextures.Length && b4sd.SignalTextures[l] != null;
                                         bool qg = l < b4sd.GlowTextures.Length && b4sd.GlowTextures[l] != null;
                                         if (qs & qg) {
                                             ObjectManager.StaticObject so = ObjectManager.CloneObject(b4sd.BaseObject, b4sd.SignalTextures[l], null);
                                             ObjectManager.StaticObject go = ObjectManager.CloneObject(b4sd.GlowObject, b4sd.GlowTextures[l], null);
                                             ObjectManager.JoinObjects(ref so, go);
                                             aoc.Objects[0].States[zi].Object = so;
                                         } else if (qs) {
                                             ObjectManager.StaticObject so = ObjectManager.CloneObject(b4sd.BaseObject, b4sd.SignalTextures[l], null);
                                             aoc.Objects[0].States[zi].Object = so;
                                         } else if (qg) {
                                             ObjectManager.StaticObject go = ObjectManager.CloneObject(b4sd.GlowObject, b4sd.GlowTextures[l], null);
                                             aoc.Objects[0].States[zi].Object = go;
                                         }
                                         if (qs | qg) {
                                             if (zi < zn - 1) {
                                                 expr += "section " + l.ToString(Culture) + " <= " + zi.ToString(Culture) + " ";
                                             } else {
                                                 expr += zi.ToString(Culture);
                                             }
                                             zi++;
                                         }
                                     }
                                     for (int l = 0; l < zn - 1; l++) {
                                         expr += " ?";
                                     }
                                     aoc.Objects[0].StateFunction = FunctionScripts.GetFunctionScriptFromPostfixNotation(expr);
                                     aoc.Objects[0].RefreshRate = 1.0 + 0.01 * Program.RandomNumberGenerator.NextDouble();
                                     ObjectManager.CreateObject(aoc, wpos, RailTransformation, new World.Transformation(Data.Blocks[i].Signal[k].Yaw, Data.Blocks[i].Signal[k].Pitch, Data.Blocks[i].Signal[k].Roll), Data.Blocks[i].Signal[k].Section, Data.AccurateObjectDisposal, StartingDistance, EndingDistance, Data.BlockInterval, tpos, 1.0, false);
                                 }
                             }
                         }
                     }
                     // sections
                     for (int k = 0; k < Data.Blocks[i].Section.Length; k++) {
                         int m = Game.Sections.Length;
                         Array.Resize<Game.Section>(ref Game.Sections, m + 1);
                         Game.Sections[m].SignalIndices = new int[] { };
                         // create associated transponders
                         for (int g = 0; g <= i; g++) {
                             for (int l = 0; l < Data.Blocks[g].Transponder.Length; l++) {
                                 if (Data.Blocks[g].Transponder[l].Type != -1 & Data.Blocks[g].Transponder[l].Section == m) {
                                     int o = TrackManager.CurrentTrack.Elements[n - i + g].Events.Length;
                                     Array.Resize<TrackManager.GeneralEvent>(ref TrackManager.CurrentTrack.Elements[n - i + g].Events, o + 1);
                                     double dt = Data.Blocks[g].Transponder[l].TrackPosition - StartingDistance + (double)(i - g) * Data.BlockInterval;
                                     TrackManager.CurrentTrack.Elements[n - i + g].Events[o] = new TrackManager.TransponderEvent(dt, Data.Blocks[g].Transponder[l].Type, Data.Blocks[g].Transponder[l].Data, m);
                                     Data.Blocks[g].Transponder[l].Type = -1;
                                 }
                             }
                         }
                         // create section
                         Game.Sections[m].TrackPosition = Data.Blocks[i].Section[k].TrackPosition;
                         Game.Sections[m].Aspects = new Game.SectionAspect[Data.Blocks[i].Section[k].Aspects.Length];
                         for (int l = 0; l < Data.Blocks[i].Section[k].Aspects.Length; l++) {
                             Game.Sections[m].Aspects[l].Number = Data.Blocks[i].Section[k].Aspects[l];
                             if (Data.Blocks[i].Section[k].Aspects[l] >= 0 & Data.Blocks[i].Section[k].Aspects[l] < Data.SignalSpeeds.Length) {
                                 Game.Sections[m].Aspects[l].Speed = Data.SignalSpeeds[Data.Blocks[i].Section[k].Aspects[l]];
                             } else {
                                 Game.Sections[m].Aspects[l].Speed = double.PositiveInfinity;
                             }
                         }
                         Game.Sections[m].Type = Data.Blocks[i].Section[k].Type;
                         Game.Sections[m].CurrentAspect = -1;
                         if (m > 0) {
                             Game.Sections[m].PreviousSection = m - 1;
                             Game.Sections[m - 1].NextSection = m;
                         } else {
                             Game.Sections[m].PreviousSection = -1;
                         }
                         Game.Sections[m].NextSection = -1;
                         Game.Sections[m].StationIndex = Data.Blocks[i].Section[k].DepartureStationIndex;
                         Game.Sections[m].Invisible = Data.Blocks[i].Section[k].Invisible;
                         Game.Sections[m].Trains = new TrainManager.Train[] { };
                         // create section change event
                         double d = Data.Blocks[i].Section[k].TrackPosition - StartingDistance;
                         int p = TrackManager.CurrentTrack.Elements[n].Events.Length;
                         Array.Resize<TrackManager.GeneralEvent>(ref TrackManager.CurrentTrack.Elements[n].Events, p + 1);
                         TrackManager.CurrentTrack.Elements[n].Events[p] = new TrackManager.SectionChangeEvent(d, m - 1, m);
                     }
                     // transponders introduced after corresponding sections
                     for (int l = 0; l < Data.Blocks[i].Transponder.Length; l++) {
                         if (Data.Blocks[i].Transponder[l].Type != -1) {
                             int t = Data.Blocks[i].Transponder[l].Section;
                             if (t >= 0 & t < Game.Sections.Length) {
                                 int m = TrackManager.CurrentTrack.Elements[n].Events.Length;
                                 Array.Resize<TrackManager.GeneralEvent>(ref TrackManager.CurrentTrack.Elements[n].Events, m + 1);
                                 double dt = Data.Blocks[i].Transponder[l].TrackPosition - StartingDistance;
                                 TrackManager.CurrentTrack.Elements[n].Events[m] = new TrackManager.TransponderEvent(dt, Data.Blocks[i].Transponder[l].Type, Data.Blocks[i].Transponder[l].Data, t);
                                 Data.Blocks[i].Transponder[l].Type = -1;
                             }
                         }
                     }
                 }
                 // limit
                 if (j == 0) {
                     for (int k = 0; k < Data.Blocks[i].Limit.Length; k++) {
                         if (Data.Blocks[i].Limit[k].Direction != 0) {
                             double dx = 2.2 * (double)Data.Blocks[i].Limit[k].Direction;
                             double dz = Data.Blocks[i].Limit[k].TrackPosition - StartingDistance;
                             Vector3 wpos = pos;
                             wpos.X += dx * RailTransformation.X.X + dz * RailTransformation.Z.X;
                             wpos.Y += dx * RailTransformation.X.Y + dz * RailTransformation.Z.Y;
                             wpos.Z += dx * RailTransformation.X.Z + dz * RailTransformation.Z.Z;
                             double tpos = Data.Blocks[i].Limit[k].TrackPosition;
                             double b = 0.25 + 0.75 * GetBrightness(ref Data, tpos);
                             if (Data.Blocks[i].Limit[k].Speed <= 0.0 | Data.Blocks[i].Limit[k].Speed >= 1000.0) {
                                 ObjectManager.CreateStaticObject(LimitPostInfinite, wpos, RailTransformation, NullTransformation, Data.AccurateObjectDisposal, 0.0, StartingDistance, EndingDistance, Data.BlockInterval, tpos, b, false);
                             } else {
                                 if (Data.Blocks[i].Limit[k].Cource < 0) {
                                     ObjectManager.CreateStaticObject(LimitPostLeft, wpos, RailTransformation, NullTransformation, Data.AccurateObjectDisposal, 0.0, StartingDistance, EndingDistance, Data.BlockInterval, tpos, b, false);
                                 } else if (Data.Blocks[i].Limit[k].Cource > 0) {
                                     ObjectManager.CreateStaticObject(LimitPostRight, wpos, RailTransformation, NullTransformation, Data.AccurateObjectDisposal, 0.0, StartingDistance, EndingDistance, Data.BlockInterval, tpos, b, false);
                                 } else {
                                     ObjectManager.CreateStaticObject(LimitPostStraight, wpos, RailTransformation, NullTransformation, Data.AccurateObjectDisposal, 0.0, StartingDistance, EndingDistance, Data.BlockInterval, tpos, b, false);
                                 }
                                 double lim = Data.Blocks[i].Limit[k].Speed / Data.UnitOfSpeed;
                                 if (lim < 10.0) {
                                     int d0 = (int)Math.Round(lim);
                                     int o = ObjectManager.CreateStaticObject(LimitOneDigit, wpos, RailTransformation, NullTransformation, Data.AccurateObjectDisposal, 0.0, StartingDistance, EndingDistance, Data.BlockInterval, tpos, b, true);
                                     if (ObjectManager.Objects[o].Mesh.Materials.Length >= 1) {
                                         Textures.RegisterTexture(OpenBveApi.Path.CombineFile(LimitGraphicsPath, "limit_" + d0 + ".png"), out ObjectManager.Objects[o].Mesh.Materials[0].DaytimeTexture);
                                     }
                                 } else if (lim < 100.0) {
                                     int d1 = (int)Math.Round(lim);
                                     int d0 = d1 % 10;
                                     d1 /= 10;
                                     int o = ObjectManager.CreateStaticObject(LimitTwoDigits, wpos, RailTransformation, NullTransformation, Data.AccurateObjectDisposal, 0.0, StartingDistance, EndingDistance, Data.BlockInterval, tpos, b, true);
                                     if (ObjectManager.Objects[o].Mesh.Materials.Length >= 1) {
                                         Textures.RegisterTexture(OpenBveApi.Path.CombineFile(LimitGraphicsPath, "limit_" + d1 + ".png"), out ObjectManager.Objects[o].Mesh.Materials[0].DaytimeTexture);
                                     }
                                     if (ObjectManager.Objects[o].Mesh.Materials.Length >= 2) {
                                         Textures.RegisterTexture(OpenBveApi.Path.CombineFile(LimitGraphicsPath, "limit_" + d0 + ".png"), out ObjectManager.Objects[o].Mesh.Materials[1].DaytimeTexture);
                                     }
                                 } else {
                                     int d2 = (int)Math.Round(lim);
                                     int d0 = d2 % 10;
                                     int d1 = (d2 / 10) % 10;
                                     d2 /= 100;
                                     int o = ObjectManager.CreateStaticObject(LimitThreeDigits, wpos, RailTransformation, NullTransformation, Data.AccurateObjectDisposal, 0.0, StartingDistance, EndingDistance, Data.BlockInterval, tpos, b, true);
                                     if (ObjectManager.Objects[o].Mesh.Materials.Length >= 1) {
                                         Textures.RegisterTexture(OpenBveApi.Path.CombineFile(LimitGraphicsPath, "limit_" + d2 + ".png"), out ObjectManager.Objects[o].Mesh.Materials[0].DaytimeTexture);
                                     }
                                     if (ObjectManager.Objects[o].Mesh.Materials.Length >= 2) {
                                         Textures.RegisterTexture(OpenBveApi.Path.CombineFile(LimitGraphicsPath, "limit_" + d1 + ".png"), out ObjectManager.Objects[o].Mesh.Materials[1].DaytimeTexture);
                                     }
                                     if (ObjectManager.Objects[o].Mesh.Materials.Length >= 3) {
                                         Textures.RegisterTexture(OpenBveApi.Path.CombineFile(LimitGraphicsPath, "limit_" + d0 + ".png"), out ObjectManager.Objects[o].Mesh.Materials[2].DaytimeTexture);
                                     }
                                 }
                             }
                         }
                     }
                 }
                 // stop
                 if (j == 0) {
                     for (int k = 0; k < Data.Blocks[i].Stop.Length; k++) {
                         if (Data.Blocks[i].Stop[k].Direction != 0) {
                             double dx = 1.8 * (double)Data.Blocks[i].Stop[k].Direction;
                             double dz = Data.Blocks[i].Stop[k].TrackPosition - StartingDistance;
                             Vector3 wpos = pos;
                             wpos.X += dx * RailTransformation.X.X + dz * RailTransformation.Z.X;
                             wpos.Y += dx * RailTransformation.X.Y + dz * RailTransformation.Z.Y;
                             wpos.Z += dx * RailTransformation.X.Z + dz * RailTransformation.Z.Z;
                             double tpos = Data.Blocks[i].Stop[k].TrackPosition;
                             double b = 0.25 + 0.75 * GetBrightness(ref Data, tpos);
                             ObjectManager.CreateStaticObject(StopPost, wpos, RailTransformation, NullTransformation, Data.AccurateObjectDisposal, 0.0, StartingDistance, EndingDistance, Data.BlockInterval, tpos, b, false);
                         }
                     }
                 }
             }
         }
         // finalize block
         Position.X += Direction.X * c;
         Position.Y += h;
         Position.Z += Direction.Y * c;
         if (a != 0.0) {
             World.Rotate(ref Direction, Math.Cos(-a), Math.Sin(-a));
         }
     }
     // orphaned transponders
     if (!PreviewOnly) {
         for (int i = Data.FirstUsedBlock; i < Data.Blocks.Length; i++) {
             for (int j = 0; j < Data.Blocks[i].Transponder.Length; j++) {
                 if (Data.Blocks[i].Transponder[j].Type != -1) {
                     int n = i - Data.FirstUsedBlock;
                     int m = TrackManager.CurrentTrack.Elements[n].Events.Length;
                     Array.Resize<TrackManager.GeneralEvent>(ref TrackManager.CurrentTrack.Elements[n].Events, m + 1);
                     double d = Data.Blocks[i].Transponder[j].TrackPosition - TrackManager.CurrentTrack.Elements[n].StartingTrackPosition;
                     int s = Data.Blocks[i].Transponder[j].Section;
                     if (s >= 0) s = -1;
                     TrackManager.CurrentTrack.Elements[n].Events[m] = new TrackManager.TransponderEvent(d, Data.Blocks[i].Transponder[j].Type, Data.Blocks[i].Transponder[j].Data, s);
                     Data.Blocks[i].Transponder[j].Type = -1;
                 }
             }
         }
     }
     // insert station end events
     for (int i = 0; i < Game.Stations.Length; i++) {
         int j = Game.Stations[i].Stops.Length - 1;
         if (j >= 0) {
             double p = Game.Stations[i].Stops[j].TrackPosition + Game.Stations[i].Stops[j].ForwardTolerance + Data.BlockInterval;
             int k = (int)Math.Floor(p / (double)Data.BlockInterval) - Data.FirstUsedBlock;
             if (k >= 0 & k < Data.Blocks.Length) {
                 double d = p - (double)(k + Data.FirstUsedBlock) * (double)Data.BlockInterval;
                 int m = TrackManager.CurrentTrack.Elements[k].Events.Length;
                 Array.Resize<TrackManager.GeneralEvent>(ref TrackManager.CurrentTrack.Elements[k].Events, m + 1);
                 TrackManager.CurrentTrack.Elements[k].Events[m] = new TrackManager.StationEndEvent(d, i);
             }
         }
     }
     // create default point of interests
     if (Game.PointsOfInterest.Length == 0) {
         Game.PointsOfInterest = new OpenBve.Game.PointOfInterest[Game.Stations.Length];
         int n = 0;
         for (int i = 0; i < Game.Stations.Length; i++) {
             if (Game.Stations[i].Stops.Length != 0) {
                 Game.PointsOfInterest[n].Text = Game.Stations[i].Name;
                 Game.PointsOfInterest[n].TrackPosition = Game.Stations[i].Stops[0].TrackPosition;
                 Game.PointsOfInterest[n].TrackOffset = new Vector3(0.0, 2.8, 0.0);
                 if (Game.Stations[i].OpenLeftDoors & !Game.Stations[i].OpenRightDoors) {
                     Game.PointsOfInterest[n].TrackOffset.X = -2.5;
                 } else if (!Game.Stations[i].OpenLeftDoors & Game.Stations[i].OpenRightDoors) {
                     Game.PointsOfInterest[n].TrackOffset.X = 2.5;
                 }
                 n++;
             }
         }
         Array.Resize<Game.PointOfInterest>(ref Game.PointsOfInterest, n);
     }
     // convert block-based cant into point-based cant
     for (int i = CurrentTrackLength - 1; i >= 1; i--) {
         if (TrackManager.CurrentTrack.Elements[i].CurveCant == 0.0) {
             TrackManager.CurrentTrack.Elements[i].CurveCant = TrackManager.CurrentTrack.Elements[i - 1].CurveCant;
         } else if (TrackManager.CurrentTrack.Elements[i - 1].CurveCant != 0.0) {
             if (Math.Sign(TrackManager.CurrentTrack.Elements[i - 1].CurveCant) == Math.Sign(TrackManager.CurrentTrack.Elements[i].CurveCant)) {
                 if (Math.Abs(TrackManager.CurrentTrack.Elements[i - 1].CurveCant) > Math.Abs(TrackManager.CurrentTrack.Elements[i].CurveCant)) {
                     TrackManager.CurrentTrack.Elements[i].CurveCant = TrackManager.CurrentTrack.Elements[i - 1].CurveCant;
                 }
             } else {
                 TrackManager.CurrentTrack.Elements[i].CurveCant = 0.5 * (TrackManager.CurrentTrack.Elements[i].CurveCant + TrackManager.CurrentTrack.Elements[i - 1].CurveCant);
             }
         }
     }
     // finalize
     Array.Resize<TrackManager.TrackElement>(ref TrackManager.CurrentTrack.Elements, CurrentTrackLength);
     for (int i = 0; i < Game.Stations.Length; i++) {
         if (Game.Stations[i].Stops.Length == 0 & Game.Stations[i].StopMode != Game.StationStopMode.AllPass) {
             Interface.AddMessage(Interface.MessageType.Warning, false, "Station " + Game.Stations[i].Name + " expects trains to stop but does not define stop points at track position " + Game.Stations[i].DefaultTrackPosition.ToString(Culture) + " in file " + FileName);
             Game.Stations[i].StopMode = Game.StationStopMode.AllPass;
         }
         if (Game.Stations[i].StationType == Game.StationType.ChangeEnds) {
             if (i < Game.Stations.Length - 1) {
                 if (Game.Stations[i + 1].StopMode != Game.StationStopMode.AllStop) {
                     Interface.AddMessage(Interface.MessageType.Warning, false, "Station " + Game.Stations[i].Name + " is marked as \"change ends\" but the subsequent station does not expect all trains to stop in file " + FileName);
                     Game.Stations[i + 1].StopMode = Game.StationStopMode.AllStop;
                 }
             } else {
                 Interface.AddMessage(Interface.MessageType.Warning, false, "Station " + Game.Stations[i].Name + " is marked as \"change ends\" but there is no subsequent station defined in file " + FileName);
                 Game.Stations[i].StationType = Game.StationType.Terminal;
             }
         }
     }
     if (Game.Stations.Length != 0) {
         Game.Stations[Game.Stations.Length - 1].StationType = Game.StationType.Terminal;
     }
     if (TrackManager.CurrentTrack.Elements.Length != 0) {
         int n = TrackManager.CurrentTrack.Elements.Length - 1;
         int m = TrackManager.CurrentTrack.Elements[n].Events.Length;
         Array.Resize<TrackManager.GeneralEvent>(ref TrackManager.CurrentTrack.Elements[n].Events, m + 1);
         TrackManager.CurrentTrack.Elements[n].Events[m] = new TrackManager.TrackEndEvent(Data.BlockInterval);
     }
     // insert compatibility beacons
     if (!PreviewOnly) {
         List<TrackManager.TransponderEvent> transponders = new List<TrackManager.TransponderEvent>();
         bool atc = false;
         for (int i = 0; i < TrackManager.CurrentTrack.Elements.Length; i++) {
             for (int j = 0; j < TrackManager.CurrentTrack.Elements[i].Events.Length; j++) {
                 if (!atc) {
                     if (TrackManager.CurrentTrack.Elements[i].Events[j] is TrackManager.StationStartEvent) {
                         TrackManager.StationStartEvent station = (TrackManager.StationStartEvent)TrackManager.CurrentTrack.Elements[i].Events[j];
                         if (Game.Stations[station.StationIndex].SafetySystem == Game.SafetySystem.Atc) {
                             Array.Resize<TrackManager.GeneralEvent>(ref TrackManager.CurrentTrack.Elements[i].Events, TrackManager.CurrentTrack.Elements[i].Events.Length + 2);
                             TrackManager.CurrentTrack.Elements[i].Events[TrackManager.CurrentTrack.Elements[i].Events.Length - 2] = new TrackManager.TransponderEvent(0.0, TrackManager.SpecialTransponderTypes.AtcTrackStatus, 0, 0);
                             TrackManager.CurrentTrack.Elements[i].Events[TrackManager.CurrentTrack.Elements[i].Events.Length - 1] = new TrackManager.TransponderEvent(0.0, TrackManager.SpecialTransponderTypes.AtcTrackStatus, 1, 0);
                             atc = true;
                         }
                     }
                 } else {
                     if (TrackManager.CurrentTrack.Elements[i].Events[j] is TrackManager.StationStartEvent) {
                         TrackManager.StationStartEvent station = (TrackManager.StationStartEvent)TrackManager.CurrentTrack.Elements[i].Events[j];
                         if (Game.Stations[station.StationIndex].SafetySystem == Game.SafetySystem.Ats) {
                             Array.Resize<TrackManager.GeneralEvent>(ref TrackManager.CurrentTrack.Elements[i].Events, TrackManager.CurrentTrack.Elements[i].Events.Length + 2);
                             TrackManager.CurrentTrack.Elements[i].Events[TrackManager.CurrentTrack.Elements[i].Events.Length - 2] = new TrackManager.TransponderEvent(0.0, TrackManager.SpecialTransponderTypes.AtcTrackStatus, 2, 0);
                             TrackManager.CurrentTrack.Elements[i].Events[TrackManager.CurrentTrack.Elements[i].Events.Length - 1] = new TrackManager.TransponderEvent(0.0, TrackManager.SpecialTransponderTypes.AtcTrackStatus, 3, 0);
                         }
                     } else if (TrackManager.CurrentTrack.Elements[i].Events[j] is TrackManager.StationEndEvent) {
                         TrackManager.StationEndEvent station = (TrackManager.StationEndEvent)TrackManager.CurrentTrack.Elements[i].Events[j];
                         if (Game.Stations[station.StationIndex].SafetySystem == Game.SafetySystem.Atc) {
                             Array.Resize<TrackManager.GeneralEvent>(ref TrackManager.CurrentTrack.Elements[i].Events, TrackManager.CurrentTrack.Elements[i].Events.Length + 2);
                             TrackManager.CurrentTrack.Elements[i].Events[TrackManager.CurrentTrack.Elements[i].Events.Length - 2] = new TrackManager.TransponderEvent(0.0, TrackManager.SpecialTransponderTypes.AtcTrackStatus, 1, 0);
                             TrackManager.CurrentTrack.Elements[i].Events[TrackManager.CurrentTrack.Elements[i].Events.Length - 1] = new TrackManager.TransponderEvent(0.0, TrackManager.SpecialTransponderTypes.AtcTrackStatus, 2, 0);
                         } else if (Game.Stations[station.StationIndex].SafetySystem == Game.SafetySystem.Ats) {
                             Array.Resize<TrackManager.GeneralEvent>(ref TrackManager.CurrentTrack.Elements[i].Events, TrackManager.CurrentTrack.Elements[i].Events.Length + 2);
                             TrackManager.CurrentTrack.Elements[i].Events[TrackManager.CurrentTrack.Elements[i].Events.Length - 2] = new TrackManager.TransponderEvent(0.0, TrackManager.SpecialTransponderTypes.AtcTrackStatus, 3, 0);
                             TrackManager.CurrentTrack.Elements[i].Events[TrackManager.CurrentTrack.Elements[i].Events.Length - 1] = new TrackManager.TransponderEvent(0.0, TrackManager.SpecialTransponderTypes.AtcTrackStatus, 0, 0);
                             atc = false;
                         }
                     } else if (TrackManager.CurrentTrack.Elements[i].Events[j] is TrackManager.LimitChangeEvent) {
                         TrackManager.LimitChangeEvent limit = (TrackManager.LimitChangeEvent)TrackManager.CurrentTrack.Elements[i].Events[j];
                         int speed = (int)Math.Round(Math.Min(4095.0, 3.6 * limit.NextSpeedLimit));
                         int distance = Math.Min(1048575, (int)Math.Round(TrackManager.CurrentTrack.Elements[i].StartingTrackPosition + limit.TrackPositionDelta));
                         unchecked {
                             int value = (int)((uint)speed | ((uint)distance << 12));
                             transponders.Add(new TrackManager.TransponderEvent(0.0, TrackManager.SpecialTransponderTypes.AtcSpeedLimit, value, 0));
                         }
                     }
                 }
                 if (TrackManager.CurrentTrack.Elements[i].Events[j] is TrackManager.TransponderEvent) {
                     TrackManager.TransponderEvent transponder = TrackManager.CurrentTrack.Elements[i].Events[j] as TrackManager.TransponderEvent;
                     if (transponder.Type == TrackManager.SpecialTransponderTypes.InternalAtsPTemporarySpeedLimit) {
                         int speed = Math.Min(4095, transponder.Data);
                         int distance = Math.Min(1048575, (int)Math.Round(TrackManager.CurrentTrack.Elements[i].StartingTrackPosition + transponder.TrackPositionDelta));
                         unchecked {
                             int value = (int)((uint)speed | ((uint)distance << 12));
                             transponder.DontTriggerAnymore = true;
                         }
                     }
                 }
             }
         }
         int n = TrackManager.CurrentTrack.Elements[0].Events.Length;
         Array.Resize<TrackManager.GeneralEvent>(ref TrackManager.CurrentTrack.Elements[0].Events, n + transponders.Count);
         for (int i = 0; i < transponders.Count; i++) {
             TrackManager.CurrentTrack.Elements[0].Events[n + i] = transponders[i];
         }
     }
     // cant
     if (!PreviewOnly) {
         ComputeCantTangents();
         int subdivisions = (int)Math.Floor(Data.BlockInterval / 5.0);
         if (subdivisions >= 2) {
             SmoothenOutTurns(subdivisions);
             ComputeCantTangents();
         }
     }
 }
コード例 #2
0
ファイル: RendererR.cs プロジェクト: noidelsucre/OpenBVE
		private static void RenderCube(World.Vector3D Position, World.Vector3D Direction, World.Vector3D Up, World.Vector3D Side, double Size, double CameraX, double CameraY, double CameraZ, int TextureIndex) {
			int OpenGlTextureIndex = TextureManager.UseTexture(TextureIndex, TextureManager.UseMode.LoadImmediately);
			if (OpenGlTextureIndex > 0) {
				if (!TexturingEnabled) {
					Gl.glEnable(Gl.GL_TEXTURE_2D);
					TexturingEnabled = false;
				}
				Gl.glBindTexture(Gl.GL_TEXTURE_2D, OpenGlTextureIndex);
			} else {
				if (TexturingEnabled) {
					Gl.glDisable(Gl.GL_TEXTURE_2D);
					TexturingEnabled = false;
				}
			}
			World.Vector3D[] v = new World.Vector3D[8];
			v[0] = new World.Vector3D(Size, Size, -Size);
			v[1] = new World.Vector3D(Size, -Size, -Size);
			v[2] = new World.Vector3D(-Size, -Size, -Size);
			v[3] = new World.Vector3D(-Size, Size, -Size);
			v[4] = new World.Vector3D(Size, Size, Size);
			v[5] = new World.Vector3D(Size, -Size, Size);
			v[6] = new World.Vector3D(-Size, -Size, Size);
			v[7] = new World.Vector3D(-Size, Size, Size);
			for (int i = 0; i < 8; i++) {
				World.Rotate(ref v[i].X, ref v[i].Y, ref v[i].Z, Direction.X, Direction.Y, Direction.Z, Up.X, Up.Y, Up.Z, Side.X, Side.Y, Side.Z);
				v[i].X += Position.X - CameraX;
				v[i].Y += Position.Y - CameraY;
				v[i].Z += Position.Z - CameraZ;
			}
			int[][] Faces = new int[6][];
			Faces[0] = new int[] { 0, 1, 2, 3 };
			Faces[1] = new int[] { 0, 4, 5, 1 };
			Faces[2] = new int[] { 0, 3, 7, 4 };
			Faces[3] = new int[] { 6, 5, 4, 7 };
			Faces[4] = new int[] { 6, 7, 3, 2 };
			Faces[5] = new int[] { 6, 2, 1, 5 };
			if (OpenGlTextureIndex != 0) {
				World.Vector2D[][] t = new World.Vector2D[6][];
				t[0] = new World.Vector2D[] { new World.Vector2D(1.0, 0.0), new World.Vector2D(1.0, 1.0), new World.Vector2D(0.0, 1.0), new World.Vector2D(0.0, 0.0) };
				t[1] = new World.Vector2D[] { new World.Vector2D(0.0, 0.0), new World.Vector2D(1.0, 0.0), new World.Vector2D(1.0, 1.0), new World.Vector2D(0.0, 1.0) };
				t[2] = new World.Vector2D[] { new World.Vector2D(1.0, 1.0), new World.Vector2D(0.0, 1.0), new World.Vector2D(0.0, 0.0), new World.Vector2D(1.0, 0.0) };
				t[3] = new World.Vector2D[] { new World.Vector2D(1.0, 1.0), new World.Vector2D(0.0, 1.0), new World.Vector2D(0.0, 0.0), new World.Vector2D(1.0, 0.0) };
				t[4] = new World.Vector2D[] { new World.Vector2D(0.0, 1.0), new World.Vector2D(0.0, 0.0), new World.Vector2D(1.0, 0.0), new World.Vector2D(1.0, 1.0) };
				t[5] = new World.Vector2D[] { new World.Vector2D(0.0, 1.0), new World.Vector2D(0.0, 0.0), new World.Vector2D(1.0, 0.0), new World.Vector2D(1.0, 1.0) };
				for (int i = 0; i < 6; i++) {
					Gl.glBegin(Gl.GL_QUADS);
					Gl.glColor3d(1.0, 1.0, 1.0);
					for (int j = 0; j < 4; j++) {
						Gl.glTexCoord2d(t[i][j].X, t[i][j].Y);
						Gl.glVertex3d(v[Faces[i][j]].X, v[Faces[i][j]].Y, v[Faces[i][j]].Z);
					}
					Gl.glEnd();
				}
			} else {
				for (int i = 0; i < 6; i++) {
					Gl.glBegin(Gl.GL_QUADS);
					Gl.glColor3d(1.0, 1.0, 1.0);
					for (int j = 0; j < 4; j++) {
						Gl.glVertex3d(v[Faces[i][j]].X, v[Faces[i][j]].Y, v[Faces[i][j]].Z);
					}
					Gl.glEnd();
				}
			}
		}