internal SoundEvent(double TrackPositionDelta, int SoundIndex, bool PlayerTrainOnly, bool Once, bool Dynamic, World.Vector3D Position, double Speed) { this.TrackPositionDelta = TrackPositionDelta; this.DontTriggerAnymore = false; this.SoundIndex = SoundIndex; this.PlayerTrainOnly = PlayerTrainOnly; this.Once = Once; this.Dynamic = Dynamic; this.Position = Position; this.Speed = Speed; }
internal TrackElement(double StartingTrackPosition) { this.StartingTrackPosition = StartingTrackPosition; this.CurveRadius = 0.0; this.CurveCant = 0.0; this.CurveCantTangent = 0.0; this.AdhesionMultiplier = 1.0; this.CsvRwAccuracyLevel = 2.0; this.WorldPosition = new World.Vector3D(0.0, 0.0, 0.0); this.WorldDirection = new World.Vector3D(0.0, 0.0, 1.0); this.WorldUp = new World.Vector3D(0.0, 1.0, 0.0); this.WorldSide = new World.Vector3D(1.0, 0.0, 0.0); this.Events = new GeneralEvent[] { }; }
internal Transformation(Transformation BaseTransformation, Transformation AuxTransformation) { World.Vector3D x = BaseTransformation.X; World.Vector3D y = BaseTransformation.Y; World.Vector3D z = BaseTransformation.Z; World.Vector3D s = AuxTransformation.X; World.Vector3D u = AuxTransformation.Y; World.Vector3D d = AuxTransformation.Z; Rotate(ref x.X, ref x.Y, ref x.Z, d.X, d.Y, d.Z, u.X, u.Y, u.Z, s.X, s.Y, s.Z); Rotate(ref y.X, ref y.Y, ref y.Z, d.X, d.Y, d.Z, u.X, u.Y, u.Z, s.X, s.Y, s.Z); Rotate(ref z.X, ref z.Y, ref z.Z, d.X, d.Y, d.Z, u.X, u.Y, u.Z, s.X, s.Y, s.Z); this.X = x; this.Y = y; this.Z = z; }
internal static void MouseEvent(object sender, MouseButtonEventArgs e) { MouseCameraPosition = World.AbsoluteCameraPosition; MouseCameraDirection = World.AbsoluteCameraDirection; MouseCameraUp = World.AbsoluteCameraUp; MouseCameraSide = World.AbsoluteCameraSide; if (e.Button == OpenTK.Input.MouseButton.Left) { MouseButton = e.Mouse.LeftButton == ButtonState.Pressed ? 1 : 0; } if (e.Button == OpenTK.Input.MouseButton.Right) { MouseButton = e.Mouse.RightButton == ButtonState.Pressed ? 2 : 0; } if (e.Button == OpenTK.Input.MouseButton.Middle) { MouseButton = e.Mouse.RightButton == ButtonState.Pressed ? 3 : 0; } previousMouseState = Mouse.GetState(); }
internal static void UpdateTrackFollower(ref TrackFollower Follower, double NewTrackPosition, bool UpdateWorldCoordinates, bool AddTrackInaccurary) { if (CurrentTrack.Elements.Length == 0) return; int i = Follower.LastTrackElement; while (i >= 0 && NewTrackPosition < CurrentTrack.Elements[i].StartingTrackPosition) { double ta = Follower.TrackPosition - CurrentTrack.Elements[i].StartingTrackPosition; double tb = -0.01; CheckEvents(ref Follower, i, -1, ta, tb); i--; } if (i >= 0) { while (i < CurrentTrack.Elements.Length - 1) { if (NewTrackPosition < CurrentTrack.Elements[i + 1].StartingTrackPosition) break; double ta = Follower.TrackPosition - CurrentTrack.Elements[i].StartingTrackPosition; double tb = CurrentTrack.Elements[i + 1].StartingTrackPosition - CurrentTrack.Elements[i].StartingTrackPosition + 0.01; CheckEvents(ref Follower, i, 1, ta, tb); i++; } } else { i = 0; } double da = Follower.TrackPosition - CurrentTrack.Elements[i].StartingTrackPosition; double db = NewTrackPosition - CurrentTrack.Elements[i].StartingTrackPosition; // track if (UpdateWorldCoordinates) { if (db != 0.0) { if (CurrentTrack.Elements[i].CurveRadius != 0.0) { // curve double r = CurrentTrack.Elements[i].CurveRadius; double p = CurrentTrack.Elements[i].WorldDirection.Y / Math.Sqrt(CurrentTrack.Elements[i].WorldDirection.X * CurrentTrack.Elements[i].WorldDirection.X + CurrentTrack.Elements[i].WorldDirection.Z * CurrentTrack.Elements[i].WorldDirection.Z); double s = db / Math.Sqrt(1.0 + p * p); double h = s * p; double b = s / Math.Abs(r); double f = 2.0 * r * r * (1.0 - Math.Cos(b)); double c = (double)Math.Sign(db) * Math.Sqrt(f >= 0.0 ? f : 0.0); double a = 0.5 * (double)Math.Sign(r) * b; World.Vector3D D = new World.Vector3D(CurrentTrack.Elements[i].WorldDirection.X, 0.0, CurrentTrack.Elements[i].WorldDirection.Z); World.Normalize(ref D.X, ref D.Y, ref D.Z); double cosa = Math.Cos(a); double sina = Math.Sin(a); World.Rotate(ref D.X, ref D.Y, ref D.Z, 0.0, 1.0, 0.0, cosa, sina); Follower.WorldPosition.X = CurrentTrack.Elements[i].WorldPosition.X + c * D.X; Follower.WorldPosition.Y = CurrentTrack.Elements[i].WorldPosition.Y + h; Follower.WorldPosition.Z = CurrentTrack.Elements[i].WorldPosition.Z + c * D.Z; World.Rotate(ref D.X, ref D.Y, ref D.Z, 0.0, 1.0, 0.0, cosa, sina); Follower.WorldDirection.X = D.X; Follower.WorldDirection.Y = p; Follower.WorldDirection.Z = D.Z; World.Normalize(ref Follower.WorldDirection.X, ref Follower.WorldDirection.Y, ref Follower.WorldDirection.Z); double cos2a = Math.Cos(2.0 * a); double sin2a = Math.Sin(2.0 * a); Follower.WorldSide = CurrentTrack.Elements[i].WorldSide; World.Rotate(ref Follower.WorldSide.X, ref Follower.WorldSide.Y, ref Follower.WorldSide.Z, 0.0, 1.0, 0.0, cos2a, sin2a); World.Cross(Follower.WorldDirection.X, Follower.WorldDirection.Y, Follower.WorldDirection.Z, Follower.WorldSide.X, Follower.WorldSide.Y, Follower.WorldSide.Z, out Follower.WorldUp.X, out Follower.WorldUp.Y, out Follower.WorldUp.Z); Follower.CurveRadius = CurrentTrack.Elements[i].CurveRadius; } else { // straight Follower.WorldPosition.X = CurrentTrack.Elements[i].WorldPosition.X + db * CurrentTrack.Elements[i].WorldDirection.X; Follower.WorldPosition.Y = CurrentTrack.Elements[i].WorldPosition.Y + db * CurrentTrack.Elements[i].WorldDirection.Y; Follower.WorldPosition.Z = CurrentTrack.Elements[i].WorldPosition.Z + db * CurrentTrack.Elements[i].WorldDirection.Z; Follower.WorldDirection = CurrentTrack.Elements[i].WorldDirection; Follower.WorldUp = CurrentTrack.Elements[i].WorldUp; Follower.WorldSide = CurrentTrack.Elements[i].WorldSide; Follower.CurveRadius = 0.0; } // cant if (i < CurrentTrack.Elements.Length - 1) { double t = db / (CurrentTrack.Elements[i + 1].StartingTrackPosition - CurrentTrack.Elements[i].StartingTrackPosition); if (t < 0.0) { t = 0.0; } else if (t > 1.0) { t = 1.0; } double t2 = t * t; double t3 = t2 * t; Follower.CurveCant = (2.0 * t3 - 3.0 * t2 + 1.0) * CurrentTrack.Elements[i].CurveCant + (t3 - 2.0 * t2 + t) * CurrentTrack.Elements[i].CurveCantTangent + (-2.0 * t3 + 3.0 * t2) * CurrentTrack.Elements[i + 1].CurveCant + (t3 - t2) * CurrentTrack.Elements[i + 1].CurveCantTangent; } else { Follower.CurveCant = CurrentTrack.Elements[i].CurveCant; } } else { Follower.WorldPosition = CurrentTrack.Elements[i].WorldPosition; Follower.WorldDirection = CurrentTrack.Elements[i].WorldDirection; Follower.WorldUp = CurrentTrack.Elements[i].WorldUp; Follower.WorldSide = CurrentTrack.Elements[i].WorldSide; Follower.CurveRadius = CurrentTrack.Elements[i].CurveRadius; Follower.CurveCant = CurrentTrack.Elements[i].CurveCant; } } else { if (db != 0.0) { if (CurrentTrack.Elements[i].CurveRadius != 0.0) { Follower.CurveRadius = CurrentTrack.Elements[i].CurveRadius; } else { Follower.CurveRadius = 0.0; } if (i < CurrentTrack.Elements.Length - 1) { double t = db / (CurrentTrack.Elements[i + 1].StartingTrackPosition - CurrentTrack.Elements[i].StartingTrackPosition); if (t < 0.0) { t = 0.0; } else if (t > 1.0) { t = 1.0; } double t2 = t * t; double t3 = t2 * t; Follower.CurveCant = (2.0 * t3 - 3.0 * t2 + 1.0) * CurrentTrack.Elements[i].CurveCant + (t3 - 2.0 * t2 + t) * CurrentTrack.Elements[i].CurveCantTangent + (-2.0 * t3 + 3.0 * t2) * CurrentTrack.Elements[i + 1].CurveCant + (t3 - t2) * CurrentTrack.Elements[i + 1].CurveCantTangent; } else { Follower.CurveCant = CurrentTrack.Elements[i].CurveCant; } } else { Follower.CurveRadius = CurrentTrack.Elements[i].CurveRadius; Follower.CurveCant = CurrentTrack.Elements[i].CurveCant; } } Follower.AdhesionMultiplier = CurrentTrack.Elements[i].AdhesionMultiplier; // inaccuracy if (AddTrackInaccurary) { double x, y, c; if (i < CurrentTrack.Elements.Length - 1) { double t = db / (CurrentTrack.Elements[i + 1].StartingTrackPosition - CurrentTrack.Elements[i].StartingTrackPosition); if (t < 0.0) { t = 0.0; } else if (t > 1.0) { t = 1.0; } double x1, y1, c1; double x2, y2, c2; GetInaccuracies(NewTrackPosition, CurrentTrack.Elements[i].CsvRwAccuracyLevel, out x1, out y1, out c1); GetInaccuracies(NewTrackPosition, CurrentTrack.Elements[i + 1].CsvRwAccuracyLevel, out x2, out y2, out c2); x = (1.0 - t) * x1 + t * x2; y = (1.0 - t) * y1 + t * y2; c = (1.0 - t) * c1 + t * c2; } else { GetInaccuracies(NewTrackPosition, CurrentTrack.Elements[i].CsvRwAccuracyLevel, out x, out y, out c); } Follower.WorldPosition.X += x * Follower.WorldSide.X + y * Follower.WorldUp.X; Follower.WorldPosition.Y += x * Follower.WorldSide.Y + y * Follower.WorldUp.Y; Follower.WorldPosition.Z += x * Follower.WorldSide.Z + y * Follower.WorldUp.Z; Follower.CurveCant += c; Follower.CantDueToInaccuracy = c; } else { Follower.CantDueToInaccuracy = 0.0; } // events CheckEvents(ref Follower, i, Math.Sign(db - da), da, db); // finish Follower.TrackPosition = NewTrackPosition; Follower.LastTrackElement = i; }
// render cube private static void RenderBox(World.Vector3D Position, World.Vector3D Direction, World.Vector3D Up, World.Vector3D Side, World.Vector3D Size, double CameraX, double CameraY, double CameraZ) { if (TexturingEnabled) { GL.Disable(EnableCap.Texture2D); TexturingEnabled = false; } World.Vector3D[] v = new World.Vector3D[8]; v[0] = new World.Vector3D(Size.X, Size.Y, -Size.Z); v[1] = new World.Vector3D(Size.X, -Size.Y, -Size.Z); v[2] = new World.Vector3D(-Size.X, -Size.Y, -Size.Z); v[3] = new World.Vector3D(-Size.X, Size.Y, -Size.Z); v[4] = new World.Vector3D(Size.X, Size.Y, Size.Z); v[5] = new World.Vector3D(Size.X, -Size.Y, Size.Z); v[6] = new World.Vector3D(-Size.X, -Size.Y, Size.Z); v[7] = new World.Vector3D(-Size.X, Size.Y, Size.Z); 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 }; for (int i = 0; i < 6; i++) { GL.Begin(PrimitiveType.Quads); for (int j = 0; j < 4; j++) { GL.Vertex3(v[Faces[i][j]].X, v[Faces[i][j]].Y, v[Faces[i][j]].Z); } GL.End(); } }
private static void PlaySound(ref int SoundSourceIndex, bool ReturnHandle, int SoundBufferIndex, TrainManager.Train Train, int CarIndex, World.Vector3D Position, Importance Important, bool Looped, double Pitch, double Gain) { if (OpenAlContext != IntPtr.Zero) { if (Game.MinimalisticSimulation & Important == Importance.DontCare | SoundBufferIndex == -1) { return; } if (SoundSourceIndex >= 0) { StopSound(ref SoundSourceIndex); } int i; for (i = 0; i < SoundSources.Length; i++) { if (SoundSources[i] == null) { break; } } if (i >= SoundSources.Length) { Array.Resize <SoundSource>(ref SoundSources, SoundSources.Length << 1); } SoundSources[i] = new SoundSourceX(); SoundSources[i].Position = Position; SoundSources[i].OpenAlPosition = new float[] { 0.0f, 0.0f, 0.0f }; SoundSources[i].OpenAlVelocity = new float[] { 0.0f, 0.0f, 0.0f }; SoundSources[i].SoundBufferIndex = SoundBufferIndex; SoundSources[i].Radius = SoundBuffers[SoundBufferIndex].Radius; SoundSources[i].Pitch = (float)Pitch; SoundSources[i].Gain = (float)Gain; SoundSources[i].Looped = Looped; SoundSources[i].Suppressed = true; SoundSources[i].FinishedPlaying = false; SoundSources[i].Train = Train; SoundSources[i].CarIndex = CarIndex; SoundSources[i].OpenAlSourceIndex = new OpenAlIndex(0, false); SoundSources[i].HasHandle = ReturnHandle; SoundSourceIndex = i; } }
internal static void PlaySound(ref int SoundSourceIndex, int SoundBufferIndex, TrainManager.Train Train, int CarIndex, World.Vector3D Position, Importance Important, bool Looped, double Pitch, double Gain) { PlaySound(ref SoundSourceIndex, true, SoundBufferIndex, Train, CarIndex, Position, Important, Looped, Pitch, Gain); }
internal TrackElement(double StartingTrackPosition) { this.StartingTrackPosition = StartingTrackPosition; this.CurveRadius = 0.0; this.CurveCant = 0.0; this.CurveCantInterpolation = CantInterpolationMode.Linear; this.Inaccuracy = 0.0; this.AdhesionMultiplier = 1.0; this.WorldPosition = new World.Vector3D(0.0, 0.0, 0.0); this.WorldDirection = new World.Vector3D(0.0, 0.0, 1.0); this.WorldUp = new World.Vector3D(0.0, 1.0, 0.0); this.WorldSide = new World.Vector3D(1.0, 0.0, 0.0); this.Events = new GeneralEvent[] { }; }
// update absolute camera internal static void UpdateAbsoluteCamera(double TimeElapsed) { // zoom double zm = World.CameraCurrentAlignment.Zoom; AdjustAlignment(ref World.CameraCurrentAlignment.Zoom, World.CameraAlignmentDirection.Zoom, ref World.CameraAlignmentSpeed.Zoom, TimeElapsed, World.CameraAlignmentSpeed.Zoom != 0.0); if (zm != World.CameraCurrentAlignment.Zoom) { ApplyZoom(); } // current alignment AdjustAlignment(ref World.CameraCurrentAlignment.Position.X, World.CameraAlignmentDirection.Position.X, ref World.CameraAlignmentSpeed.Position.X, TimeElapsed); AdjustAlignment(ref World.CameraCurrentAlignment.Position.Y, World.CameraAlignmentDirection.Position.Y, ref World.CameraAlignmentSpeed.Position.Y, TimeElapsed); bool q = World.CameraAlignmentSpeed.Yaw != 0.0 | World.CameraAlignmentSpeed.Pitch != 0.0 | World.CameraAlignmentSpeed.Roll != 0.0; AdjustAlignment(ref World.CameraCurrentAlignment.Yaw, World.CameraAlignmentDirection.Yaw, ref World.CameraAlignmentSpeed.Yaw, TimeElapsed); AdjustAlignment(ref World.CameraCurrentAlignment.Pitch, World.CameraAlignmentDirection.Pitch, ref World.CameraAlignmentSpeed.Pitch, TimeElapsed); AdjustAlignment(ref World.CameraCurrentAlignment.Roll, World.CameraAlignmentDirection.Roll, ref World.CameraAlignmentSpeed.Roll, TimeElapsed); double tr = World.CameraCurrentAlignment.TrackPosition; AdjustAlignment(ref World.CameraCurrentAlignment.TrackPosition, World.CameraAlignmentDirection.TrackPosition, ref World.CameraAlignmentSpeed.TrackPosition, TimeElapsed); if (tr != World.CameraCurrentAlignment.TrackPosition) { TrackManager.UpdateTrackFollower(ref World.CameraTrackFollower, World.CameraCurrentAlignment.TrackPosition, true, false); q = true; } if (q) { UpdateViewingDistances(); } double dx = World.CameraTrackFollower.WorldDirection.X; double dy = World.CameraTrackFollower.WorldDirection.Y; double dz = World.CameraTrackFollower.WorldDirection.Z; double ux = World.CameraTrackFollower.WorldUp.X; double uy = World.CameraTrackFollower.WorldUp.Y; double uz = World.CameraTrackFollower.WorldUp.Z; double sx = World.CameraTrackFollower.WorldSide.X; double sy = World.CameraTrackFollower.WorldSide.Y; double sz = World.CameraTrackFollower.WorldSide.Z; double tx = World.CameraCurrentAlignment.Position.X; double ty = World.CameraCurrentAlignment.Position.Y; double tz = World.CameraCurrentAlignment.Position.Z; double dx2 = dx, dy2 = dy, dz2 = dz; double ux2 = ux, uy2 = uy, uz2 = uz; double cx = World.CameraTrackFollower.WorldPosition.X + sx * tx + ux2 * ty + dx2 * tz; double cy = World.CameraTrackFollower.WorldPosition.Y + sy * tx + uy2 * ty + dy2 * tz; double cz = World.CameraTrackFollower.WorldPosition.Z + sz * tx + uz2 * ty + dz2 * tz; if (World.CameraCurrentAlignment.Yaw != 0.0) { double cosa = Math.Cos(World.CameraCurrentAlignment.Yaw); double sina = Math.Sin(World.CameraCurrentAlignment.Yaw); World.Rotate(ref dx, ref dy, ref dz, ux, uy, uz, cosa, sina); World.Rotate(ref sx, ref sy, ref sz, ux, uy, uz, cosa, sina); } double p = World.CameraCurrentAlignment.Pitch; if (p != 0.0) { double cosa = Math.Cos(-p); double sina = Math.Sin(-p); World.Rotate(ref dx, ref dy, ref dz, sx, sy, sz, cosa, sina); World.Rotate(ref ux, ref uy, ref uz, sx, sy, sz, cosa, sina); } if (World.CameraCurrentAlignment.Roll != 0.0) { double cosa = Math.Cos(-World.CameraCurrentAlignment.Roll); double sina = Math.Sin(-World.CameraCurrentAlignment.Roll); World.Rotate(ref ux, ref uy, ref uz, dx, dy, dz, cosa, sina); World.Rotate(ref sx, ref sy, ref sz, dx, dy, dz, cosa, sina); } AbsoluteCameraPosition = new Vector3D(cx, cy, cz); AbsoluteCameraDirection = new Vector3D(dx, dy, dz); AbsoluteCameraUp = new Vector3D(ux, uy, uz); AbsoluteCameraSide = new Vector3D(sx, sy, sz); }
// process events private static void ProcessEvents() { SDL.SDL_Event Event; while (SDL.SDL_PollEvent(out Event) != 0) { switch (Event.type) { // quit case SDL.SDL_EventType.SDL_QUIT: Quit = true; return; // resize case SDL.SDL_EventType.SDL_WINDOWEVENT: if (Event.window.windowEvent == SDL.SDL_WindowEventID.SDL_WINDOWEVENT_RESIZED) { Renderer.ScreenWidth = Event.window.data1; Renderer.ScreenHeight = Event.window.data2; UpdateViewport(); } break; // mouse case SDL.SDL_EventType.SDL_MOUSEBUTTONDOWN: MouseCenterX = (short)Event.button.x; MouseCenterY = (short)Event.button.y; MouseCameraPosition = World.AbsoluteCameraPosition; MouseCameraDirection = World.AbsoluteCameraDirection; MouseCameraUp = World.AbsoluteCameraUp; MouseCameraSide = World.AbsoluteCameraSide; MouseButton = Event.button.button; break; case SDL.SDL_EventType.SDL_MOUSEBUTTONUP: MouseButton = 0; break; case SDL.SDL_EventType.SDL_MOUSEMOTION: if (MouseButton == SDL.SDL_BUTTON_LEFT) { World.AbsoluteCameraDirection = MouseCameraDirection; World.AbsoluteCameraUp = MouseCameraUp; World.AbsoluteCameraSide = MouseCameraSide; { double dx = 0.0025 * (double)(MouseCenterX - Event.motion.x); double cosa = Math.Cos(dx); double sina = Math.Sin(dx); World.Rotate(ref World.AbsoluteCameraDirection.X, ref World.AbsoluteCameraDirection.Y, ref World.AbsoluteCameraDirection.Z, 0.0, 1.0, 0.0, cosa, sina); World.Rotate(ref World.AbsoluteCameraUp.X, ref World.AbsoluteCameraUp.Y, ref World.AbsoluteCameraUp.Z, 0.0, 1.0, 0.0, cosa, sina); World.Rotate(ref World.AbsoluteCameraSide.X, ref World.AbsoluteCameraSide.Y, ref World.AbsoluteCameraSide.Z, 0.0, 1.0, 0.0, cosa, sina); } { double dy = 0.0025 * (double)(MouseCenterY - Event.motion.y); double cosa = Math.Cos(dy); double sina = Math.Sin(dy); World.Rotate(ref World.AbsoluteCameraDirection.X, ref World.AbsoluteCameraDirection.Y, ref World.AbsoluteCameraDirection.Z, World.AbsoluteCameraSide.X, World.AbsoluteCameraSide.Y, World.AbsoluteCameraSide.Z, cosa, sina); World.Rotate(ref World.AbsoluteCameraUp.X, ref World.AbsoluteCameraUp.Y, ref World.AbsoluteCameraUp.Z, World.AbsoluteCameraSide.X, World.AbsoluteCameraSide.Y, World.AbsoluteCameraSide.Z, cosa, sina); } ReducedMode = false; } else if (MouseButton == SDL.SDL_BUTTON_RIGHT) { World.AbsoluteCameraPosition = MouseCameraPosition; double dx = -0.025 * (double)(Event.motion.x - MouseCenterX); World.AbsoluteCameraPosition.X += dx * World.AbsoluteCameraSide.X; World.AbsoluteCameraPosition.Y += dx * World.AbsoluteCameraSide.Y; World.AbsoluteCameraPosition.Z += dx * World.AbsoluteCameraSide.Z; double dy = 0.025 * (double)(Event.motion.y - MouseCenterY); World.AbsoluteCameraPosition.X += dy * World.AbsoluteCameraUp.X; World.AbsoluteCameraPosition.Y += dy * World.AbsoluteCameraUp.Y; World.AbsoluteCameraPosition.Z += dy * World.AbsoluteCameraUp.Z; ReducedMode = false; } else if (MouseButton == SDL.SDL_BUTTON_MIDDLE) { World.AbsoluteCameraPosition = MouseCameraPosition; double dx = -0.025 * (double)(Event.motion.x - MouseCenterX); World.AbsoluteCameraPosition.X += dx * World.AbsoluteCameraSide.X; World.AbsoluteCameraPosition.Y += dx * World.AbsoluteCameraSide.Y; World.AbsoluteCameraPosition.Z += dx * World.AbsoluteCameraSide.Z; double dz = -0.025 * (double)(Event.motion.y - MouseCenterY); World.AbsoluteCameraPosition.X += dz * World.AbsoluteCameraDirection.X; World.AbsoluteCameraPosition.Y += dz * World.AbsoluteCameraDirection.Y; World.AbsoluteCameraPosition.Z += dz * World.AbsoluteCameraDirection.Z; ReducedMode = false; } break; // key down case SDL.SDL_EventType.SDL_KEYDOWN: switch (Event.key.keysym.sym) { case SDL.SDL_Keycode.SDLK_LSHIFT: case SDL.SDL_Keycode.SDLK_RSHIFT: ShiftPressed = true; break; case SDL.SDL_Keycode.SDLK_F5: // reset ReducedMode = false; LightingRelative = -1.0; Game.Reset(); TextureManager.UnuseAllTextures(); Fonts.Initialize(); Interface.ClearMessages(); for (int i = 0; i < Files.Length; i++) { #if !DEBUG try { #endif ObjectManager.UnifiedObject o = ObjectManager.LoadObject(Files[i], System.Text.Encoding.UTF8, ObjectManager.ObjectLoadMode.Normal, false, false, false); ObjectManager.CreateObject(o, new World.Vector3D(0.0, 0.0, 0.0), new World.Transformation(0.0, 0.0, 0.0), new World.Transformation(0.0, 0.0, 0.0), true, 0.0, 0.0, 25.0, 0.0); #if !DEBUG } catch (Exception ex) { Interface.AddMessage(Interface.MessageType.Critical, false, "Unhandled error (" + ex.Message + ") encountered while processing the file " + Files[i] + "."); } #endif } ObjectManager.InitializeVisibility(); ObjectManager.UpdateVisibility(0.0, true); ObjectManager.UpdateAnimatedWorldObjects(0.01, true); break; case SDL.SDL_Keycode.SDLK_F7: { OpenFileDialog Dialog = new OpenFileDialog(); Dialog.CheckFileExists = true; Dialog.Multiselect = true; Dialog.Filter = "CSV/B3D/X/ANIMATED files|*.csv;*.b3d;*.x;*.animated|All files|*"; if (Dialog.ShowDialog() == DialogResult.OK) { string[] f = Dialog.FileNames; int n = Files.Length; Array.Resize<string>(ref Files, n + f.Length); for (int i = 0; i < f.Length; i++) { Files[n + i] = f[i]; } // reset ReducedMode = false; LightingRelative = -1.0; Game.Reset(); TextureManager.UnuseAllTextures(); Fonts.Initialize(); Interface.ClearMessages(); for (int i = 0; i < Files.Length; i++) { #if !DEBUG try { #endif ObjectManager.UnifiedObject o = ObjectManager.LoadObject(Files[i], System.Text.Encoding.UTF8, ObjectManager.ObjectLoadMode.Normal, false, false, false); ObjectManager.CreateObject(o, new World.Vector3D(0.0, 0.0, 0.0), new World.Transformation(0.0, 0.0, 0.0), new World.Transformation(0.0, 0.0, 0.0), true, 0.0, 0.0, 25.0, 0.0); #if !DEBUG } catch (Exception ex) { Interface.AddMessage(Interface.MessageType.Critical, false, "Unhandled error (" + ex.Message + ") encountered while processing the file " + Files[i] + "."); } #endif } ObjectManager.InitializeVisibility(); ObjectManager.FinishCreatingObjects(); ObjectManager.UpdateVisibility(0.0, true); ObjectManager.UpdateAnimatedWorldObjects(0.01, true); } } break; case SDL.SDL_Keycode.SDLK_F9: if (Interface.MessageCount != 0) { formMessages.ShowMessages(); } break; case SDL.SDL_Keycode.SDLK_DELETE: ReducedMode = false; LightingRelative = -1.0; Game.Reset(); TextureManager.UnuseAllTextures(); Fonts.Initialize(); Interface.ClearMessages(); Files = new string[] { }; UpdateCaption(); break; case SDL.SDL_Keycode.SDLK_LEFT: RotateX = -1; ReducedMode = false; break; case SDL.SDL_Keycode.SDLK_RIGHT: RotateX = 1; ReducedMode = false; break; case SDL.SDL_Keycode.SDLK_UP: RotateY = -1; ReducedMode = false; break; case SDL.SDL_Keycode.SDLK_DOWN: RotateY = 1; ReducedMode = false; break; case SDL.SDL_Keycode.SDLK_a: case SDL.SDL_Keycode.SDLK_KP_4: MoveX = -1; ReducedMode = false; break; case SDL.SDL_Keycode.SDLK_d: case SDL.SDL_Keycode.SDLK_KP_6: MoveX = 1; ReducedMode = false; break; case SDL.SDL_Keycode.SDLK_KP_8: MoveY = 1; ReducedMode = false; break; case SDL.SDL_Keycode.SDLK_KP_2: MoveY = -1; ReducedMode = false; break; case SDL.SDL_Keycode.SDLK_w: case SDL.SDL_Keycode.SDLK_KP_9: MoveZ = 1; ReducedMode = false; break; case SDL.SDL_Keycode.SDLK_s: case SDL.SDL_Keycode.SDLK_KP_3: MoveZ = -1; ReducedMode = false; break; case SDL.SDL_Keycode.SDLK_KP_5: ResetCamera(); break; case SDL.SDL_Keycode.SDLK_f: case SDL.SDL_Keycode.SDLK_F1: Renderer.OptionWireframe = !Renderer.OptionWireframe; if (Renderer.OptionWireframe) { GL.PolygonMode(MaterialFace.FrontAndBack, PolygonMode.Line); } else { GL.PolygonMode(MaterialFace.FrontAndBack, PolygonMode.Fill); } break; case SDL.SDL_Keycode.SDLK_n: case SDL.SDL_Keycode.SDLK_F2: Renderer.OptionNormals = !Renderer.OptionNormals; break; case SDL.SDL_Keycode.SDLK_l: case SDL.SDL_Keycode.SDLK_F3: LightingTarget = 1 - LightingTarget; ReducedMode = false; break; case SDL.SDL_Keycode.SDLK_i: case SDL.SDL_Keycode.SDLK_F4: Renderer.OptionInterface = !Renderer.OptionInterface; ReducedMode = false; break; case SDL.SDL_Keycode.SDLK_g: case SDL.SDL_Keycode.SDLK_c: Renderer.OptionCoordinateSystem = !Renderer.OptionCoordinateSystem; ReducedMode = false; break; case SDL.SDL_Keycode.SDLK_b: if (ShiftPressed) { ColorDialog dialog = new ColorDialog(); dialog.FullOpen = true; if (dialog.ShowDialog() == DialogResult.OK) { Renderer.BackgroundColor = -1; Renderer.ApplyBackgroundColor(dialog.Color.R, dialog.Color.G, dialog.Color.B); } } else { Renderer.BackgroundColor++; if (Renderer.BackgroundColor >= Renderer.MaxBackgroundColor) { Renderer.BackgroundColor = 0; } Renderer.ApplyBackgroundColor(); } ReducedMode = false; break; } break; // key up case SDL.SDL_EventType.SDL_KEYUP: switch (Event.key.keysym.sym) { case SDL.SDL_Keycode.SDLK_LSHIFT: case SDL.SDL_Keycode.SDLK_RSHIFT: ShiftPressed = false; break; case SDL.SDL_Keycode.SDLK_LEFT: case SDL.SDL_Keycode.SDLK_RIGHT: RotateX = 0; break; case SDL.SDL_Keycode.SDLK_UP: case SDL.SDL_Keycode.SDLK_DOWN: RotateY = 0; break; case SDL.SDL_Keycode.SDLK_a: case SDL.SDL_Keycode.SDLK_d: case SDL.SDL_Keycode.SDLK_KP_4: case SDL.SDL_Keycode.SDLK_KP_6: MoveX = 0; break; case SDL.SDL_Keycode.SDLK_KP_8: case SDL.SDL_Keycode.SDLK_KP_2: MoveY = 0; break; case SDL.SDL_Keycode.SDLK_w: case SDL.SDL_Keycode.SDLK_s: case SDL.SDL_Keycode.SDLK_KP_9: case SDL.SDL_Keycode.SDLK_KP_3: MoveZ = 0; break; } break; } } }
// 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(-1, 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 World.Vector3D Position = new World.Vector3D(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 World.ColorRGB(128, 128, 128), -Data.BlockInterval); Game.Fog CurrentFog = new Game.Fog(Game.NoFogStart, Game.NoFogEnd, new World.ColorRGB(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 = new World.Vector3D(Direction, Data.Blocks[i].Pitch); TrackManager.CurrentTrack.Elements[n].WorldSide = new World.Vector3D(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, TrackManager.SoundEvent.SoundIndexTrainPoint, false, false, true, new World.Vector3D(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; int t = Data.Markers[j].Texture; TrackManager.CurrentTrack.Elements[n].Events[m] = new TrackManager.MarkerStartEvent(d, t); } 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; int t = Data.Markers[j].Texture; TrackManager.CurrentTrack.Elements[n].Events[m] = new TrackManager.MarkerEndEvent(d, t); } } } // 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].SoundIndex, true, true, false, new World.Vector3D(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].SoundIndex, false, false, true, new World.Vector3D(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]], World.Vector3D.Add(Position, new World.Vector3D(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; World.Vector3D wpos = World.Vector3D.Add(Position, new World.Vector3D(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 World.Vector3D 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; World.Vector3D offset = new World.Vector3D(Direction.Y * x, y, -Direction.X * x); pos = World.Vector3D.Add(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; World.Vector3D 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; World.Vector3D offset2 = new World.Vector3D(Direction2.Y * x2, y2, -Direction2.X * x2); World.Vector3D pos2 = World.Vector3D.Add(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 World.Vector3D(rx, ry, rz); RailTransformation.X = new World.Vector3D(rz, 0.0, -rx); World.Normalize(ref RailTransformation.X.X, ref RailTransformation.X.Z); RailTransformation.Y = World.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 World.Vector3D(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 World.Vector3D(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; World.Vector3D wpos = World.Vector3D.Add(pos, new World.Vector3D(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].SoundIndex >= 0) { 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); World.Vector3D wpos = World.Vector3D.Add(pos, new World.Vector3D(sx * dx + ux * dy + wx * d, sy * dx + uy * dy + wy * d, sz * dx + uz * dy + wz * d)); SoundManager.PlaySound(Data.Blocks[i].Sound[k].SoundIndex, null, -1, wpos, SoundManager.Importance.AlwaysPlay, true, 1.0, 1.0); } } } } // 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; World.Vector3D 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 TrackManager.TransponderType.SLong: obj = TransponderS; break; case TrackManager.TransponderType.SN: obj = TransponderSN; break; case TrackManager.TransponderType.AccidentalDeparture: obj = TransponderFalseStart; break; case TrackManager.TransponderType.AtsPPatternOrigin: obj = TransponderPOrigin; break; case TrackManager.TransponderType.AtsPImmediateStop: 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; World.Vector3D 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; World.Vector3D 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; World.Vector3D 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 * Game.Generator.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] >= 0 || l < b4sd.GlowTextures.Length && b4sd.GlowTextures[l] >= 0) { 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] >= 0; bool qg = l < b4sd.GlowTextures.Length && b4sd.GlowTextures[l] >= 0; if (qs & qg) { ObjectManager.StaticObject so = ObjectManager.CloneObject(b4sd.BaseObject, b4sd.SignalTextures[l], -1); ObjectManager.StaticObject go = ObjectManager.CloneObject(b4sd.GlowObject, b4sd.GlowTextures[l], -1); 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], -1); aoc.Objects[0].States[zi].Object = so; } else if (qg) { ObjectManager.StaticObject go = ObjectManager.CloneObject(b4sd.GlowObject, b4sd.GlowTextures[l], -1); 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 * Game.Generator.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 != TrackManager.TransponderType.None & 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].SwitchSubsystem, Data.Blocks[g].Transponder[l].OptionalInteger, Data.Blocks[g].Transponder[l].OptionalFloat, m); Data.Blocks[g].Transponder[l].Type = TrackManager.TransponderType.None; } } } // 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 != TrackManager.TransponderType.None) { 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].SwitchSubsystem, Data.Blocks[i].Transponder[l].OptionalInteger, Data.Blocks[i].Transponder[l].OptionalFloat, t); Data.Blocks[i].Transponder[l].Type = TrackManager.TransponderType.None; } } } } // 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; World.Vector3D 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) { ObjectManager.Objects[o].Mesh.Materials[0].DaytimeTextureIndex = TextureManager.RegisterTexture(OpenBveApi.Path.CombineFile(LimitGraphicsPath, "limit_" + d0 + ".png"), new World.ColorRGB(0, 0, 0), 0, TextureManager.TextureWrapMode.ClampToEdge, TextureManager.TextureWrapMode.ClampToEdge, false); } } 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) { ObjectManager.Objects[o].Mesh.Materials[0].DaytimeTextureIndex = TextureManager.RegisterTexture(OpenBveApi.Path.CombineFile(LimitGraphicsPath, "limit_" + d1 + ".png"), new World.ColorRGB(0, 0, 0), 0, TextureManager.TextureWrapMode.ClampToEdge, TextureManager.TextureWrapMode.ClampToEdge, false); } if (ObjectManager.Objects[o].Mesh.Materials.Length >= 2) { ObjectManager.Objects[o].Mesh.Materials[1].DaytimeTextureIndex = TextureManager.RegisterTexture(OpenBveApi.Path.CombineFile(LimitGraphicsPath, "limit_" + d0 + ".png"), new World.ColorRGB(0, 0, 0), 0, TextureManager.TextureWrapMode.ClampToEdge, TextureManager.TextureWrapMode.ClampToEdge, false); } } 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) { ObjectManager.Objects[o].Mesh.Materials[0].DaytimeTextureIndex = TextureManager.RegisterTexture(OpenBveApi.Path.CombineFile(LimitGraphicsPath, "limit_" + d2 + ".png"), new World.ColorRGB(0, 0, 0), 0, TextureManager.TextureWrapMode.ClampToEdge, TextureManager.TextureWrapMode.ClampToEdge, false); } if (ObjectManager.Objects[o].Mesh.Materials.Length >= 2) { ObjectManager.Objects[o].Mesh.Materials[1].DaytimeTextureIndex = TextureManager.RegisterTexture(OpenBveApi.Path.CombineFile(LimitGraphicsPath, "limit_" + d1 + ".png"), new World.ColorRGB(0, 0, 0), 0, TextureManager.TextureWrapMode.ClampToEdge, TextureManager.TextureWrapMode.ClampToEdge, false); } if (ObjectManager.Objects[o].Mesh.Materials.Length >= 3) { ObjectManager.Objects[o].Mesh.Materials[2].DaytimeTextureIndex = TextureManager.RegisterTexture(OpenBveApi.Path.CombineFile(LimitGraphicsPath, "limit_" + d0 + ".png"), new World.ColorRGB(0, 0, 0), 0, TextureManager.TextureWrapMode.ClampToEdge, TextureManager.TextureWrapMode.ClampToEdge, false); } } } } } } // 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; World.Vector3D 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 != TrackManager.TransponderType.None) { 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].SwitchSubsystem, Data.Blocks[i].Transponder[j].OptionalInteger, Data.Blocks[i].Transponder[j].OptionalFloat, s); Data.Blocks[i].Transponder[j].Type = TrackManager.TransponderType.None; } } } } // 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 OpenBve.World.Vector3D(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); } if (!PreviewOnly) { ComputeCantTangents(); int subdivisions = (int)Math.Floor(Data.BlockInterval / 5.0); if (subdivisions >= 2) { SmoothenOutTurns(subdivisions); ComputeCantTangents(); } } }
internal static void UpdateTrackFollower(ref TrackFollower Follower, double NewTrackPosition, bool UpdateWorldCoordinates, bool AddTrackInaccurary) { if (CurrentTrack.Elements.Length == 0) { return; } int i = Follower.LastTrackElement; while (i >= 0 && NewTrackPosition < CurrentTrack.Elements[i].StartingTrackPosition) { double ta = Follower.TrackPosition - CurrentTrack.Elements[i].StartingTrackPosition; double tb = -0.01; CheckEvents(ref Follower, i, -1, ta, tb); i--; } if (i >= 0) { while (i < CurrentTrack.Elements.Length - 1) { if (NewTrackPosition < CurrentTrack.Elements[i + 1].StartingTrackPosition) { break; } double ta = Follower.TrackPosition - CurrentTrack.Elements[i].StartingTrackPosition; double tb = CurrentTrack.Elements[i + 1].StartingTrackPosition - CurrentTrack.Elements[i].StartingTrackPosition + 0.01; CheckEvents(ref Follower, i, 1, ta, tb); i++; } } else { i = 0; } double da = Follower.TrackPosition - CurrentTrack.Elements[i].StartingTrackPosition; double db = NewTrackPosition - CurrentTrack.Elements[i].StartingTrackPosition; // track if (UpdateWorldCoordinates) { if (db != 0.0) { if (CurrentTrack.Elements[i].CurveRadius != 0.0) { // curve double r = CurrentTrack.Elements[i].CurveRadius; double p = CurrentTrack.Elements[i].WorldDirection.Y / Math.Sqrt(CurrentTrack.Elements[i].WorldDirection.X * CurrentTrack.Elements[i].WorldDirection.X + CurrentTrack.Elements[i].WorldDirection.Z * CurrentTrack.Elements[i].WorldDirection.Z); double s = db / Math.Sqrt(1.0 + p * p); double h = s * p; double b = s / Math.Abs(r); double f = 2.0 * r * r * (1.0 - Math.Cos(b)); double c = (double)Math.Sign(db) * Math.Sqrt(f >= 0.0 ? f : 0.0); double a = 0.5 * (double)Math.Sign(r) * b; World.Vector3D D = new World.Vector3D(CurrentTrack.Elements[i].WorldDirection.X, 0.0, CurrentTrack.Elements[i].WorldDirection.Z); World.Normalize(ref D.X, ref D.Y, ref D.Z); double cosa = Math.Cos(a); double sina = Math.Sin(a); World.Rotate(ref D.X, ref D.Y, ref D.Z, 0.0, 1.0, 0.0, cosa, sina); Follower.WorldPosition.X = CurrentTrack.Elements[i].WorldPosition.X + c * D.X; Follower.WorldPosition.Y = CurrentTrack.Elements[i].WorldPosition.Y + h; Follower.WorldPosition.Z = CurrentTrack.Elements[i].WorldPosition.Z + c * D.Z; World.Rotate(ref D.X, ref D.Y, ref D.Z, 0.0, 1.0, 0.0, cosa, sina); Follower.WorldDirection.X = D.X; Follower.WorldDirection.Y = p; Follower.WorldDirection.Z = D.Z; World.Normalize(ref Follower.WorldDirection.X, ref Follower.WorldDirection.Y, ref Follower.WorldDirection.Z); double cos2a = Math.Cos(2.0 * a); double sin2a = Math.Sin(2.0 * a); Follower.WorldSide = CurrentTrack.Elements[i].WorldSide; World.Rotate(ref Follower.WorldSide.X, ref Follower.WorldSide.Y, ref Follower.WorldSide.Z, 0.0, 1.0, 0.0, cos2a, sin2a); World.Cross(Follower.WorldDirection.X, Follower.WorldDirection.Y, Follower.WorldDirection.Z, Follower.WorldSide.X, Follower.WorldSide.Y, Follower.WorldSide.Z, out Follower.WorldUp.X, out Follower.WorldUp.Y, out Follower.WorldUp.Z); Follower.CurveRadius = CurrentTrack.Elements[i].CurveRadius; } else { // straight Follower.WorldPosition.X = CurrentTrack.Elements[i].WorldPosition.X + db * CurrentTrack.Elements[i].WorldDirection.X; Follower.WorldPosition.Y = CurrentTrack.Elements[i].WorldPosition.Y + db * CurrentTrack.Elements[i].WorldDirection.Y; Follower.WorldPosition.Z = CurrentTrack.Elements[i].WorldPosition.Z + db * CurrentTrack.Elements[i].WorldDirection.Z; Follower.WorldDirection = CurrentTrack.Elements[i].WorldDirection; Follower.WorldUp = CurrentTrack.Elements[i].WorldUp; Follower.WorldSide = CurrentTrack.Elements[i].WorldSide; Follower.CurveRadius = 0.0; } // cant if (i < CurrentTrack.Elements.Length - 1) { double t = db / (CurrentTrack.Elements[i + 1].StartingTrackPosition - CurrentTrack.Elements[i].StartingTrackPosition); if (t < 0.0) { t = 0.0; } else if (t > 1.0) { t = 1.0; } double t2 = t * t; double t3 = t2 * t; Follower.CurveCant = (2.0 * t3 - 3.0 * t2 + 1.0) * CurrentTrack.Elements[i].CurveCant + (t3 - 2.0 * t2 + t) * CurrentTrack.Elements[i].CurveCantTangent + (-2.0 * t3 + 3.0 * t2) * CurrentTrack.Elements[i + 1].CurveCant + (t3 - t2) * CurrentTrack.Elements[i + 1].CurveCantTangent; } else { Follower.CurveCant = CurrentTrack.Elements[i].CurveCant; } } else { Follower.WorldPosition = CurrentTrack.Elements[i].WorldPosition; Follower.WorldDirection = CurrentTrack.Elements[i].WorldDirection; Follower.WorldUp = CurrentTrack.Elements[i].WorldUp; Follower.WorldSide = CurrentTrack.Elements[i].WorldSide; Follower.CurveRadius = CurrentTrack.Elements[i].CurveRadius; Follower.CurveCant = CurrentTrack.Elements[i].CurveCant; } } else { if (db != 0.0) { if (CurrentTrack.Elements[i].CurveRadius != 0.0) { Follower.CurveRadius = CurrentTrack.Elements[i].CurveRadius; } else { Follower.CurveRadius = 0.0; } if (i < CurrentTrack.Elements.Length - 1) { double t = db / (CurrentTrack.Elements[i + 1].StartingTrackPosition - CurrentTrack.Elements[i].StartingTrackPosition); if (t < 0.0) { t = 0.0; } else if (t > 1.0) { t = 1.0; } double t2 = t * t; double t3 = t2 * t; Follower.CurveCant = (2.0 * t3 - 3.0 * t2 + 1.0) * CurrentTrack.Elements[i].CurveCant + (t3 - 2.0 * t2 + t) * CurrentTrack.Elements[i].CurveCantTangent + (-2.0 * t3 + 3.0 * t2) * CurrentTrack.Elements[i + 1].CurveCant + (t3 - t2) * CurrentTrack.Elements[i + 1].CurveCantTangent; } else { Follower.CurveCant = CurrentTrack.Elements[i].CurveCant; } } else { Follower.CurveRadius = CurrentTrack.Elements[i].CurveRadius; Follower.CurveCant = CurrentTrack.Elements[i].CurveCant; } } Follower.AdhesionMultiplier = CurrentTrack.Elements[i].AdhesionMultiplier; // inaccuracy if (AddTrackInaccurary) { double x, y, c; if (i < CurrentTrack.Elements.Length - 1) { double t = db / (CurrentTrack.Elements[i + 1].StartingTrackPosition - CurrentTrack.Elements[i].StartingTrackPosition); if (t < 0.0) { t = 0.0; } else if (t > 1.0) { t = 1.0; } double x1, y1, c1; double x2, y2, c2; GetInaccuracies(NewTrackPosition, CurrentTrack.Elements[i].CsvRwAccuracyLevel, out x1, out y1, out c1); GetInaccuracies(NewTrackPosition, CurrentTrack.Elements[i + 1].CsvRwAccuracyLevel, out x2, out y2, out c2); x = (1.0 - t) * x1 + t * x2; y = (1.0 - t) * y1 + t * y2; c = (1.0 - t) * c1 + t * c2; } else { GetInaccuracies(NewTrackPosition, CurrentTrack.Elements[i].CsvRwAccuracyLevel, out x, out y, out c); } Follower.WorldPosition.X += x * Follower.WorldSide.X + y * Follower.WorldUp.X; Follower.WorldPosition.Y += x * Follower.WorldSide.Y + y * Follower.WorldUp.Y; Follower.WorldPosition.Z += x * Follower.WorldSide.Z + y * Follower.WorldUp.Z; Follower.CurveCant += c; Follower.CantDueToInaccuracy = c; } else { Follower.CantDueToInaccuracy = 0.0; } // events CheckEvents(ref Follower, i, Math.Sign(db - da), da, db); // finish Follower.TrackPosition = NewTrackPosition; Follower.LastTrackElement = i; }
internal static void UpdateTrackFollower(ref TrackFollower Follower, double NewTrackPosition, bool UpdateWorldCoordinates, bool AddTrackInaccurary) { if (CurrentTrack.Elements == null) return; if (CurrentTrack.Elements.Length == 0) return; int i = Follower.LastTrackElement; while (i >= 0 && NewTrackPosition < CurrentTrack.Elements[i].StartingTrackPosition) { double ta = Follower.TrackPosition - CurrentTrack.Elements[i].StartingTrackPosition; double tb = -0.01; CheckEvents(ref Follower, i, -1, ta, tb); i--; } if (i >= 0) { while (i < CurrentTrack.Elements.Length - 1) { if (NewTrackPosition < CurrentTrack.Elements[i + 1].StartingTrackPosition) break; double ta = Follower.TrackPosition - CurrentTrack.Elements[i].StartingTrackPosition; double tb = CurrentTrack.Elements[i + 1].StartingTrackPosition - CurrentTrack.Elements[i].StartingTrackPosition + 0.01; CheckEvents(ref Follower, i, 1, ta, tb); i++; } } else i = 0; double da = Follower.TrackPosition - CurrentTrack.Elements[i].StartingTrackPosition; double db = NewTrackPosition - CurrentTrack.Elements[i].StartingTrackPosition; // track if (UpdateWorldCoordinates) { if (db != 0.0) { if (CurrentTrack.Elements[i].CurveRadius != 0.0) { // side curve double r = CurrentTrack.Elements[i].CurveRadius; double p = CurrentTrack.Elements[i].WorldDirection.Y / Math.Sqrt(CurrentTrack.Elements[i].WorldDirection.X * CurrentTrack.Elements[i].WorldDirection.X + CurrentTrack.Elements[i].WorldDirection.Z * CurrentTrack.Elements[i].WorldDirection.Z); double s = db / Math.Sqrt(1.0 + p * p); double h = s * p; double b = s / Math.Abs(r); double f = 2.0 * r * r * (1.0 - Math.Cos(b)); double c = (double)Math.Sign(db) * Math.Sqrt(f >= 0.0 ? f : 0.0); double a = 0.5 * (double)Math.Sign(r) * b; World.Vector3D D = new World.Vector3D(CurrentTrack.Elements[i].WorldDirection.X, 0.0, CurrentTrack.Elements[i].WorldDirection.Z); World.Normalize(ref D.X, ref D.Y, ref D.Z); double cosa = Math.Cos(a); double sina = Math.Sin(a); World.Rotate(ref D.X, ref D.Y, ref D.Z, 0.0, 1.0, 0.0, cosa, sina); Follower.WorldPosition.X = CurrentTrack.Elements[i].WorldPosition.X + c * D.X; Follower.WorldPosition.Y = CurrentTrack.Elements[i].WorldPosition.Y + h; Follower.WorldPosition.Z = CurrentTrack.Elements[i].WorldPosition.Z + c * D.Z; World.Rotate(ref D.X, ref D.Y, ref D.Z, 0.0, 1.0, 0.0, cosa, sina); Follower.WorldDirection.X = D.X; Follower.WorldDirection.Y = p; Follower.WorldDirection.Z = D.Z; World.Normalize(ref Follower.WorldDirection.X, ref Follower.WorldDirection.Y, ref Follower.WorldDirection.Z); double cos2a = Math.Cos(2.0 * a); double sin2a = Math.Sin(2.0 * a); Follower.WorldSide = CurrentTrack.Elements[i].WorldSide; World.Rotate(ref Follower.WorldSide.X, ref Follower.WorldSide.Y, ref Follower.WorldSide.Z, 0.0, 1.0, 0.0, cos2a, sin2a); World.Cross(Follower.WorldDirection.X, Follower.WorldDirection.Y, Follower.WorldDirection.Z, Follower.WorldSide.X, Follower.WorldSide.Y, Follower.WorldSide.Z, out Follower.WorldUp.X, out Follower.WorldUp.Y, out Follower.WorldUp.Z); Follower.CurveRadius = CurrentTrack.Elements[i].CurveRadius; } else { // straight Follower.WorldPosition.X = CurrentTrack.Elements[i].WorldPosition.X + db * CurrentTrack.Elements[i].WorldDirection.X; Follower.WorldPosition.Y = CurrentTrack.Elements[i].WorldPosition.Y + db * CurrentTrack.Elements[i].WorldDirection.Y; Follower.WorldPosition.Z = CurrentTrack.Elements[i].WorldPosition.Z + db * CurrentTrack.Elements[i].WorldDirection.Z; Follower.WorldDirection = CurrentTrack.Elements[i].WorldDirection; Follower.WorldUp = CurrentTrack.Elements[i].WorldUp; Follower.WorldSide = CurrentTrack.Elements[i].WorldSide; Follower.CurveRadius = 0.0; } // cant if (i < CurrentTrack.Elements.Length - 1) { double t = db / (CurrentTrack.Elements[i + 1].StartingTrackPosition - CurrentTrack.Elements[i].StartingTrackPosition); switch (CurrentTrack.Elements[i].CurveCantInterpolation) { case CantInterpolationMode.BiasForward: t *= t; t = 1.0 - t * t; t = 1.0 - t * t; break; case CantInterpolationMode.BiasBackward: t = 1.0 - t; t *= t; t = 1.0 - t * t; t *= t; break; } Follower.CurveCant = (1.0 - t) * CurrentTrack.Elements[i].CurveCant + t * CurrentTrack.Elements[i + 1].CurveCant; } else { Follower.CurveCant = CurrentTrack.Elements[i].CurveCant; } } else { Follower.WorldPosition = CurrentTrack.Elements[i].WorldPosition; Follower.WorldDirection = CurrentTrack.Elements[i].WorldDirection; Follower.WorldUp = CurrentTrack.Elements[i].WorldUp; Follower.WorldSide = CurrentTrack.Elements[i].WorldSide; Follower.CurveRadius = CurrentTrack.Elements[i].CurveRadius; Follower.CurveCant = CurrentTrack.Elements[i].CurveCant; } } Follower.AdhesionMultiplier = CurrentTrack.Elements[i].AdhesionMultiplier; if (AddTrackInaccurary) { double f = NewTrackPosition; f = 0.3121 * Math.Sin(0.9843 * f) + 1.1217 * Math.Sin(0.1874 * f) + 1.6421 * Math.Sin(0.1126 * f) + 1.8421 * Math.Sin(0.2546 * f); f *= 0.15 * CurrentTrack.Elements[i].Inaccuracy; double g = NewTrackPosition; g = 0.3495 * Math.Sin(0.8272 * g) + 1.6321 * Math.Sin(0.2356 * g); g *= 0.15 * CurrentTrack.Elements[i].Inaccuracy; Follower.WorldPosition.X += f * Follower.WorldSide.X + g * Follower.WorldUp.X; Follower.WorldPosition.Y += f * Follower.WorldSide.Y + g * Follower.WorldUp.Y; Follower.WorldPosition.Z += f * Follower.WorldSide.Z + g * Follower.WorldUp.Z; } // events CheckEvents(ref Follower, i, Math.Sign(db - da), da, db); // finish Follower.TrackPosition = NewTrackPosition; Follower.LastTrackElement = i; }
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(); } } }
// parse animated object config /// <summary>Loads a collection of animated objects from a file.</summary> /// <param name="FileName">The text file to load the animated object from. Must be an absolute file name.</param> /// <param name="Encoding">The encoding the file is saved in. If the file uses a byte order mark, the encoding indicated by the byte order mark is used and the Encoding parameter is ignored.</param> /// <param name="LoadMode">The texture load mode.</param> /// <returns>The collection of animated objects.</returns> internal static ObjectManager.AnimatedObjectCollection ReadObject(string FileName, System.Text.Encoding Encoding, ObjectManager.ObjectLoadMode LoadMode) { System.Globalization.CultureInfo Culture = System.Globalization.CultureInfo.InvariantCulture; ObjectManager.AnimatedObjectCollection Result = new ObjectManager.AnimatedObjectCollection(); Result.Objects = new ObjectManager.AnimatedObject[4]; int ObjectCount = 0; // load file string[] Lines = System.IO.File.ReadAllLines(FileName, Encoding); bool rpnUsed = false; for (int i = 0; i < Lines.Length; i++) { int j = Lines[i].IndexOf(';'); if (j >= 0) { Lines[i] = Lines[i].Substring(0, j).Trim(); } else { Lines[i] = Lines[i].Trim(); } if (Lines[i].IndexOf("functionrpn", StringComparison.OrdinalIgnoreCase) >= 0) { rpnUsed = true; } } if (rpnUsed) { Interface.AddMessage(Interface.MessageType.Error, false, "An animated object file contains RPN functions. These were never meant to be used directly, only for debugging. They won't be supported indefinately. Please get rid of them in file " + FileName); } for (int i = 0; i < Lines.Length; i++) { if (Lines[i].Length != 0) { switch (Lines[i].ToLowerInvariant()) { case "[include]": { i++; World.Vector3D position = new World.Vector3D(0.0, 0.0, 0.0); ObjectManager.UnifiedObject[] obj = new OpenBve.ObjectManager.UnifiedObject[4]; int objCount = 0; while (i < Lines.Length && !(Lines[i].StartsWith("[", StringComparison.Ordinal) & Lines[i].EndsWith("]", StringComparison.Ordinal))) { if (Lines[i].Length != 0) { int j = Lines[i].IndexOf("=", StringComparison.Ordinal); if (j > 0) { string a = Lines[i].Substring(0, j).TrimEnd(); string b = Lines[i].Substring(j + 1).TrimStart(); switch (a.ToLowerInvariant()) { case "position": { string[] s = b.Split(','); if (s.Length == 3) { double x, y, z; if (!double.TryParse(s[0], System.Globalization.NumberStyles.Float, Culture, out x)) { Interface.AddMessage(Interface.MessageType.Error, false, "X is invalid in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName); } else if (!double.TryParse(s[1], System.Globalization.NumberStyles.Float, Culture, out y)) { Interface.AddMessage(Interface.MessageType.Error, false, "Y is invalid in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName); } else if (!double.TryParse(s[2], System.Globalization.NumberStyles.Float, Culture, out z)) { Interface.AddMessage(Interface.MessageType.Error, false, "Z is invalid in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName); } else { position = new World.Vector3D(x, y, z); } } else { Interface.AddMessage(Interface.MessageType.Error, false, "Exactly 3 arguments are expected in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName); } } break; default: Interface.AddMessage(Interface.MessageType.Error, false, "The attribute " + a + " is not supported at line " + (i + 1).ToString(Culture) + " in file " + FileName); break; } } else { string Folder = System.IO.Path.GetDirectoryName(FileName); if (Path.ContainsInvalidChars(Lines[i])) { Interface.AddMessage(Interface.MessageType.Error, false, Lines[i] + " contains illegal characters at line " + (i + 1).ToString(Culture) + " in file " + FileName); } else { string file = OpenBveApi.Path.CombineFile(Folder, Lines[i]); if (System.IO.File.Exists(file)) { if (obj.Length == objCount) { Array.Resize <ObjectManager.UnifiedObject>(ref obj, obj.Length << 1); } obj[objCount] = ObjectManager.LoadObject(file, Encoding, LoadMode, false, false, false); objCount++; } else { Interface.AddMessage(Interface.MessageType.Error, true, "File " + file + " not found at line " + (i + 1).ToString(Culture) + " in file " + FileName); } } } } i++; } i--; for (int j = 0; j < objCount; j++) { if (obj[j] != null) { if (obj[j] is ObjectManager.StaticObject) { ObjectManager.StaticObject s = (ObjectManager.StaticObject)obj[j]; s.Dynamic = true; if (ObjectCount >= Result.Objects.Length) { Array.Resize <ObjectManager.AnimatedObject>(ref Result.Objects, Result.Objects.Length << 1); } ObjectManager.AnimatedObject a = new ObjectManager.AnimatedObject(); ObjectManager.AnimatedObjectState aos = new ObjectManager.AnimatedObjectState(); aos.Object = s; aos.Position = position; a.States = new ObjectManager.AnimatedObjectState[] { aos }; Result.Objects[ObjectCount] = a; ObjectCount++; } else if (obj[j] is ObjectManager.AnimatedObjectCollection) { ObjectManager.AnimatedObjectCollection a = (ObjectManager.AnimatedObjectCollection)obj[j]; for (int k = 0; k < a.Objects.Length; k++) { if (ObjectCount >= Result.Objects.Length) { Array.Resize <ObjectManager.AnimatedObject>(ref Result.Objects, Result.Objects.Length << 1); } for (int h = 0; h < a.Objects[k].States.Length; h++) { a.Objects[k].States[h].Position.X += position.X; a.Objects[k].States[h].Position.Y += position.Y; a.Objects[k].States[h].Position.Z += position.Z; } Result.Objects[ObjectCount] = a.Objects[k]; ObjectCount++; } } } } } break; case "[object]": { i++; if (Result.Objects.Length == ObjectCount) { Array.Resize <ObjectManager.AnimatedObject>(ref Result.Objects, Result.Objects.Length << 1); } Result.Objects[ObjectCount] = new ObjectManager.AnimatedObject(); Result.Objects[ObjectCount].States = new ObjectManager.AnimatedObjectState[] { }; Result.Objects[ObjectCount].CurrentState = -1; Result.Objects[ObjectCount].TranslateXDirection = new World.Vector3D(1.0, 0.0, 0.0); Result.Objects[ObjectCount].TranslateYDirection = new World.Vector3D(0.0, 1.0, 0.0); Result.Objects[ObjectCount].TranslateZDirection = new World.Vector3D(0.0, 0.0, 1.0); Result.Objects[ObjectCount].RotateXDirection = new World.Vector3D(1.0, 0.0, 0.0); Result.Objects[ObjectCount].RotateYDirection = new World.Vector3D(0.0, 1.0, 0.0); Result.Objects[ObjectCount].RotateZDirection = new World.Vector3D(0.0, 0.0, 1.0); Result.Objects[ObjectCount].TextureShiftXDirection = new World.Vector2D(1.0, 0.0); Result.Objects[ObjectCount].TextureShiftYDirection = new World.Vector2D(0.0, 1.0); Result.Objects[ObjectCount].RefreshRate = 0.0; Result.Objects[ObjectCount].ObjectIndex = -1; World.Vector3D Position = new World.Vector3D(0.0, 0.0, 0.0); bool timetableUsed = false; string[] StateFiles = null; string StateFunctionRpn = null; int StateFunctionLine = -1; while (i < Lines.Length && !(Lines[i].StartsWith("[", StringComparison.Ordinal) & Lines[i].EndsWith("]", StringComparison.Ordinal))) { if (Lines[i].Length != 0) { int j = Lines[i].IndexOf("=", StringComparison.Ordinal); if (j > 0) { string a = Lines[i].Substring(0, j).TrimEnd(); string b = Lines[i].Substring(j + 1).TrimStart(); switch (a.ToLowerInvariant()) { case "position": { string[] s = b.Split(','); if (s.Length == 3) { double x, y, z; if (!double.TryParse(s[0], System.Globalization.NumberStyles.Float, Culture, out x)) { Interface.AddMessage(Interface.MessageType.Error, false, "X is invalid in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName); } else if (!double.TryParse(s[1], System.Globalization.NumberStyles.Float, Culture, out y)) { Interface.AddMessage(Interface.MessageType.Error, false, "Y is invalid in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName); } else if (!double.TryParse(s[2], System.Globalization.NumberStyles.Float, Culture, out z)) { Interface.AddMessage(Interface.MessageType.Error, false, "Z is invalid in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName); } else { Position = new World.Vector3D(x, y, z); } } else { Interface.AddMessage(Interface.MessageType.Error, false, "Exactly 3 arguments are expected in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName); } } break; case "states": { string[] s = b.Split(','); if (s.Length >= 1) { string Folder = System.IO.Path.GetDirectoryName(FileName); StateFiles = new string[s.Length]; bool NullObject = true; for (int k = 0; k < s.Length; k++) { s[k] = s[k].Trim(); if (s[k].Length == 0) { Interface.AddMessage(Interface.MessageType.Error, false, "File" + k.ToString(Culture) + " is an empty string - did you mean something else? - in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName); StateFiles[k] = null; } else if (Path.ContainsInvalidChars(s[k])) { Interface.AddMessage(Interface.MessageType.Error, false, "File" + k.ToString(Culture) + " contains illegal characters in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName); StateFiles[k] = null; } else { StateFiles[k] = OpenBveApi.Path.CombineFile(Folder, s[k]); if (!System.IO.File.Exists(StateFiles[k])) { Interface.AddMessage(Interface.MessageType.Error, true, "File " + StateFiles[k] + " not found in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName); StateFiles[k] = null; } } if (StateFiles[k] != null) { NullObject = false; } } if (NullObject == true) { Interface.AddMessage(Interface.MessageType.Error, false, "No statefiles were found in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName); return(null); } } else { Interface.AddMessage(Interface.MessageType.Error, false, "At least one argument is expected in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName); return(null); } } break; case "statefunction": try { StateFunctionLine = i; StateFunctionRpn = FunctionScripts.GetPostfixNotationFromInfixNotation(b); } catch (Exception ex) { Interface.AddMessage(Interface.MessageType.Error, false, ex.Message + " in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName); } break; case "statefunctionrpn": { StateFunctionLine = i; StateFunctionRpn = b; } break; case "translatexdirection": case "translateydirection": case "translatezdirection": { string[] s = b.Split(','); if (s.Length == 3) { double x, y, z; if (!double.TryParse(s[0], System.Globalization.NumberStyles.Float, Culture, out x)) { Interface.AddMessage(Interface.MessageType.Error, false, "X is invalid in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName); } else if (!double.TryParse(s[1], System.Globalization.NumberStyles.Float, Culture, out y)) { Interface.AddMessage(Interface.MessageType.Error, false, "Y is invalid in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName); } else if (!double.TryParse(s[2], System.Globalization.NumberStyles.Float, Culture, out z)) { Interface.AddMessage(Interface.MessageType.Error, false, "Z is invalid in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName); } else { switch (a.ToLowerInvariant()) { case "translatexdirection": Result.Objects[ObjectCount].TranslateXDirection = new World.Vector3D(x, y, z); break; case "translateydirection": Result.Objects[ObjectCount].TranslateYDirection = new World.Vector3D(x, y, z); break; case "translatezdirection": Result.Objects[ObjectCount].TranslateZDirection = new World.Vector3D(x, y, z); break; } } } else { Interface.AddMessage(Interface.MessageType.Error, false, "Exactly 3 arguments are expected in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName); } } break; case "translatexfunction": try { Result.Objects[ObjectCount].TranslateXFunction = FunctionScripts.GetFunctionScriptFromInfixNotation(b); } catch (Exception ex) { Interface.AddMessage(Interface.MessageType.Error, false, ex.Message + " in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName); } break; case "translateyfunction": try { Result.Objects[ObjectCount].TranslateYFunction = FunctionScripts.GetFunctionScriptFromInfixNotation(b); } catch (Exception ex) { Interface.AddMessage(Interface.MessageType.Error, false, ex.Message + " in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName); } break; case "translatezfunction": try { Result.Objects[ObjectCount].TranslateZFunction = FunctionScripts.GetFunctionScriptFromInfixNotation(b); } catch (Exception ex) { Interface.AddMessage(Interface.MessageType.Error, false, ex.Message + " in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName); } break; case "translatexfunctionrpn": try { Result.Objects[ObjectCount].TranslateXFunction = FunctionScripts.GetFunctionScriptFromPostfixNotation(b); } catch (Exception ex) { Interface.AddMessage(Interface.MessageType.Error, false, ex.Message + " in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName); } break; case "translateyfunctionrpn": try { Result.Objects[ObjectCount].TranslateYFunction = FunctionScripts.GetFunctionScriptFromPostfixNotation(b); } catch (Exception ex) { Interface.AddMessage(Interface.MessageType.Error, false, ex.Message + " in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName); } break; case "translatezfunctionrpn": try { Result.Objects[ObjectCount].TranslateZFunction = FunctionScripts.GetFunctionScriptFromPostfixNotation(b); } catch (Exception ex) { Interface.AddMessage(Interface.MessageType.Error, false, ex.Message + " in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName); } break; case "rotatexdirection": case "rotateydirection": case "rotatezdirection": { string[] s = b.Split(','); if (s.Length == 3) { double x, y, z; if (!double.TryParse(s[0], System.Globalization.NumberStyles.Float, Culture, out x)) { Interface.AddMessage(Interface.MessageType.Error, false, "X is invalid in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName); } else if (!double.TryParse(s[1], System.Globalization.NumberStyles.Float, Culture, out y)) { Interface.AddMessage(Interface.MessageType.Error, false, "Y is invalid in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName); } else if (!double.TryParse(s[2], System.Globalization.NumberStyles.Float, Culture, out z)) { Interface.AddMessage(Interface.MessageType.Error, false, "Z is invalid in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName); } else if (x == 0.0 & y == 0.0 & z == 0.0) { Interface.AddMessage(Interface.MessageType.Error, false, "The direction indicated by X, Y and Z is expected to be non-zero in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName); } else { switch (a.ToLowerInvariant()) { case "rotatexdirection": Result.Objects[ObjectCount].RotateXDirection = new World.Vector3D(x, y, z); break; case "rotateydirection": Result.Objects[ObjectCount].RotateYDirection = new World.Vector3D(x, y, z); break; case "rotatezdirection": Result.Objects[ObjectCount].RotateZDirection = new World.Vector3D(x, y, z); break; } } } else { Interface.AddMessage(Interface.MessageType.Error, false, "Exactly 3 arguments are expected in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName); } } break; case "rotatexfunction": try { Result.Objects[ObjectCount].RotateXFunction = FunctionScripts.GetFunctionScriptFromInfixNotation(b); } catch (Exception ex) { Interface.AddMessage(Interface.MessageType.Error, false, ex.Message + " in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName); } break; case "rotateyfunction": try { Result.Objects[ObjectCount].RotateYFunction = FunctionScripts.GetFunctionScriptFromInfixNotation(b); } catch (Exception ex) { Interface.AddMessage(Interface.MessageType.Error, false, ex.Message + " in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName); } break; case "rotatezfunction": try { Result.Objects[ObjectCount].RotateZFunction = FunctionScripts.GetFunctionScriptFromInfixNotation(b); } catch (Exception ex) { Interface.AddMessage(Interface.MessageType.Error, false, ex.Message + " in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName); } break; case "rotatexfunctionrpn": try { Result.Objects[ObjectCount].RotateXFunction = FunctionScripts.GetFunctionScriptFromPostfixNotation(b); } catch (Exception ex) { Interface.AddMessage(Interface.MessageType.Error, false, ex.Message + " in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName); } break; case "rotateyfunctionrpn": try { Result.Objects[ObjectCount].RotateYFunction = FunctionScripts.GetFunctionScriptFromPostfixNotation(b); } catch (Exception ex) { Interface.AddMessage(Interface.MessageType.Error, false, ex.Message + " in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName); } break; case "rotatezfunctionrpn": try { Result.Objects[ObjectCount].RotateZFunction = FunctionScripts.GetFunctionScriptFromPostfixNotation(b); } catch (Exception ex) { Interface.AddMessage(Interface.MessageType.Error, false, ex.Message + " in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName); } break; case "rotatexdamping": case "rotateydamping": case "rotatezdamping": { string[] s = b.Split(','); if (s.Length == 2) { double nf, dr; if (!double.TryParse(s[0], System.Globalization.NumberStyles.Float, Culture, out nf)) { Interface.AddMessage(Interface.MessageType.Error, false, "NaturalFrequency is invalid in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName); } else if (!double.TryParse(s[1], System.Globalization.NumberStyles.Float, Culture, out dr)) { Interface.AddMessage(Interface.MessageType.Error, false, "DampingRatio is invalid in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName); } else if (nf <= 0.0) { Interface.AddMessage(Interface.MessageType.Error, false, "NaturalFrequency is expected to be positive in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName); } else if (dr <= 0.0) { Interface.AddMessage(Interface.MessageType.Error, false, "DampingRatio is expected to be positive in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName); } else { switch (a.ToLowerInvariant()) { case "rotatexdamping": Result.Objects[ObjectCount].RotateXDamping = new ObjectManager.Damping(nf, dr); break; case "rotateydamping": Result.Objects[ObjectCount].RotateYDamping = new ObjectManager.Damping(nf, dr); break; case "rotatezdamping": Result.Objects[ObjectCount].RotateZDamping = new ObjectManager.Damping(nf, dr); break; } } } else { Interface.AddMessage(Interface.MessageType.Error, false, "Exactly 2 arguments are expected in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName); } } break; case "textureshiftxdirection": case "textureshiftydirection": { string[] s = b.Split(','); if (s.Length == 2) { double x, y; if (!double.TryParse(s[0], System.Globalization.NumberStyles.Float, Culture, out x)) { Interface.AddMessage(Interface.MessageType.Error, false, "X is invalid in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName); } else if (!double.TryParse(s[1], System.Globalization.NumberStyles.Float, Culture, out y)) { Interface.AddMessage(Interface.MessageType.Error, false, "Y is invalid in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName); } else { switch (a.ToLowerInvariant()) { case "textureshiftxdirection": Result.Objects[ObjectCount].TextureShiftXDirection = new World.Vector2D(x, y); break; case "textureshiftydirection": Result.Objects[ObjectCount].TextureShiftYDirection = new World.Vector2D(x, y); break; } } } else { Interface.AddMessage(Interface.MessageType.Error, false, "Exactly 2 arguments are expected in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName); } } break; case "textureshiftxfunction": try { Result.Objects[ObjectCount].TextureShiftXFunction = FunctionScripts.GetFunctionScriptFromInfixNotation(b); } catch (Exception ex) { Interface.AddMessage(Interface.MessageType.Error, false, ex.Message + " in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName); } break; case "textureshiftyfunction": try { Result.Objects[ObjectCount].TextureShiftYFunction = FunctionScripts.GetFunctionScriptFromInfixNotation(b); } catch (Exception ex) { Interface.AddMessage(Interface.MessageType.Error, false, ex.Message + " in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName); } break; case "textureshiftxfunctionrpn": try { Result.Objects[ObjectCount].TextureShiftXFunction = FunctionScripts.GetFunctionScriptFromPostfixNotation(b); } catch (Exception ex) { Interface.AddMessage(Interface.MessageType.Error, false, ex.Message + " in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName); } break; case "textureshiftyfunctionrpn": try { Result.Objects[ObjectCount].TextureShiftYFunction = FunctionScripts.GetFunctionScriptFromPostfixNotation(b); } catch (Exception ex) { Interface.AddMessage(Interface.MessageType.Error, false, ex.Message + " in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName); } break; case "textureoverride": switch (b.ToLowerInvariant()) { case "none": break; case "timetable": if (!timetableUsed) { Timetable.AddObjectForCustomTimetable(Result.Objects[ObjectCount]); timetableUsed = true; } break; default: Interface.AddMessage(Interface.MessageType.Error, false, "Unrecognized value in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName); break; } break; case "refreshrate": { double r; if (!double.TryParse(b, System.Globalization.NumberStyles.Float, Culture, out r)) { Interface.AddMessage(Interface.MessageType.Error, false, "Value is invalid in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName); } else if (r < 0.0) { Interface.AddMessage(Interface.MessageType.Error, false, "Value is expected to be non-negative in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName); } else { Result.Objects[ObjectCount].RefreshRate = r; } } break; default: Interface.AddMessage(Interface.MessageType.Error, false, "The attribute " + a + " is not supported at line " + (i + 1).ToString(Culture) + " in file " + FileName); break; } } else { Interface.AddMessage(Interface.MessageType.Error, false, "Invalid statement " + Lines[i] + " encountered at line " + (i + 1).ToString(Culture) + " in file " + FileName); return(null); } } i++; } i--; if (StateFiles != null) { // create the object if (timetableUsed) { if (StateFunctionRpn != null) { StateFunctionRpn = "timetable 0 == " + StateFunctionRpn + " -1 ?"; } else { StateFunctionRpn = "timetable"; } } if (StateFunctionRpn != null) { try { Result.Objects[ObjectCount].StateFunction = FunctionScripts.GetFunctionScriptFromPostfixNotation(StateFunctionRpn); } catch (Exception ex) { Interface.AddMessage(Interface.MessageType.Error, false, ex.Message + " in StateFunction at line " + (StateFunctionLine + 1).ToString(Culture) + " in file " + FileName); } } Result.Objects[ObjectCount].States = new ObjectManager.AnimatedObjectState[StateFiles.Length]; bool ForceTextureRepeatX = Result.Objects[ObjectCount].TextureShiftXFunction != null & Result.Objects[ObjectCount].TextureShiftXDirection.X != 0.0 | Result.Objects[ObjectCount].TextureShiftYFunction != null & Result.Objects[ObjectCount].TextureShiftYDirection.Y != 0.0; bool ForceTextureRepeatY = Result.Objects[ObjectCount].TextureShiftXFunction != null & Result.Objects[ObjectCount].TextureShiftXDirection.X != 0.0 | Result.Objects[ObjectCount].TextureShiftYFunction != null & Result.Objects[ObjectCount].TextureShiftYDirection.Y != 0.0; for (int k = 0; k < StateFiles.Length; k++) { Result.Objects[ObjectCount].States[k].Position = new World.Vector3D(0.0, 0.0, 0.0); if (StateFiles[k] != null) { Result.Objects[ObjectCount].States[k].Object = ObjectManager.LoadStaticObject(StateFiles[k], Encoding, LoadMode, false, ForceTextureRepeatX, ForceTextureRepeatY); if (Result.Objects[ObjectCount].States[k].Object != null) { Result.Objects[ObjectCount].States[k].Object.Dynamic = true; } } else { Result.Objects[ObjectCount].States[k].Object = null; } for (int j = 0; j < Result.Objects[ObjectCount].States.Length; j++) { Result.Objects[ObjectCount].States[j].Position = Position; } } } else { Result.Objects[ObjectCount].States = new ObjectManager.AnimatedObjectState[] { }; } ObjectCount++; } break; default: Interface.AddMessage(Interface.MessageType.Error, false, "Invalid statement " + Lines[i] + " encountered at line " + (i + 1).ToString(Culture) + " in file " + FileName); return(null); } } } Array.Resize <ObjectManager.AnimatedObject>(ref Result.Objects, ObjectCount); return(Result); }
// process events private static void ProcessEvents() { SDL.SDL_Event Event; while (SDL.SDL_PollEvent(out Event) != 0) { switch (Event.type) { // quit case SDL.SDL_EventType.SDL_QUIT: Quit = true; return; // resize case SDL.SDL_EventType.SDL_WINDOWEVENT: if (Event.window.windowEvent == SDL.SDL_WindowEventID.SDL_WINDOWEVENT_RESIZED) { Renderer.ScreenWidth = Event.window.data1; Renderer.ScreenHeight = Event.window.data2; UpdateViewport(); } break; // mouse case SDL.SDL_EventType.SDL_MOUSEBUTTONDOWN: MouseCenterX = (short)Event.button.x; MouseCenterY = (short)Event.button.y; MouseCameraPosition = World.AbsoluteCameraPosition; MouseCameraDirection = World.AbsoluteCameraDirection; MouseCameraUp = World.AbsoluteCameraUp; MouseCameraSide = World.AbsoluteCameraSide; MouseButton = Event.button.button; break; case SDL.SDL_EventType.SDL_MOUSEBUTTONUP: MouseButton = 0; break; case SDL.SDL_EventType.SDL_MOUSEMOTION: if (MouseButton == SDL.SDL_BUTTON_LEFT) { World.AbsoluteCameraDirection = MouseCameraDirection; World.AbsoluteCameraUp = MouseCameraUp; World.AbsoluteCameraSide = MouseCameraSide; { double dx = 0.0025 * (double)(MouseCenterX - Event.motion.x); double cosa = Math.Cos(dx); double sina = Math.Sin(dx); World.Rotate(ref World.AbsoluteCameraDirection.X, ref World.AbsoluteCameraDirection.Y, ref World.AbsoluteCameraDirection.Z, 0.0, 1.0, 0.0, cosa, sina); World.Rotate(ref World.AbsoluteCameraUp.X, ref World.AbsoluteCameraUp.Y, ref World.AbsoluteCameraUp.Z, 0.0, 1.0, 0.0, cosa, sina); World.Rotate(ref World.AbsoluteCameraSide.X, ref World.AbsoluteCameraSide.Y, ref World.AbsoluteCameraSide.Z, 0.0, 1.0, 0.0, cosa, sina); } { double dy = 0.0025 * (double)(MouseCenterY - Event.motion.y); double cosa = Math.Cos(dy); double sina = Math.Sin(dy); World.Rotate(ref World.AbsoluteCameraDirection.X, ref World.AbsoluteCameraDirection.Y, ref World.AbsoluteCameraDirection.Z, World.AbsoluteCameraSide.X, World.AbsoluteCameraSide.Y, World.AbsoluteCameraSide.Z, cosa, sina); World.Rotate(ref World.AbsoluteCameraUp.X, ref World.AbsoluteCameraUp.Y, ref World.AbsoluteCameraUp.Z, World.AbsoluteCameraSide.X, World.AbsoluteCameraSide.Y, World.AbsoluteCameraSide.Z, cosa, sina); } ReducedMode = false; } else if (MouseButton == SDL.SDL_BUTTON_RIGHT) { World.AbsoluteCameraPosition = MouseCameraPosition; double dx = -0.025 * (double)(Event.motion.x - MouseCenterX); World.AbsoluteCameraPosition.X += dx * World.AbsoluteCameraSide.X; World.AbsoluteCameraPosition.Y += dx * World.AbsoluteCameraSide.Y; World.AbsoluteCameraPosition.Z += dx * World.AbsoluteCameraSide.Z; double dy = 0.025 * (double)(Event.motion.y - MouseCenterY); World.AbsoluteCameraPosition.X += dy * World.AbsoluteCameraUp.X; World.AbsoluteCameraPosition.Y += dy * World.AbsoluteCameraUp.Y; World.AbsoluteCameraPosition.Z += dy * World.AbsoluteCameraUp.Z; ReducedMode = false; } else if (MouseButton == SDL.SDL_BUTTON_MIDDLE) { World.AbsoluteCameraPosition = MouseCameraPosition; double dx = -0.025 * (double)(Event.motion.x - MouseCenterX); World.AbsoluteCameraPosition.X += dx * World.AbsoluteCameraSide.X; World.AbsoluteCameraPosition.Y += dx * World.AbsoluteCameraSide.Y; World.AbsoluteCameraPosition.Z += dx * World.AbsoluteCameraSide.Z; double dz = -0.025 * (double)(Event.motion.y - MouseCenterY); World.AbsoluteCameraPosition.X += dz * World.AbsoluteCameraDirection.X; World.AbsoluteCameraPosition.Y += dz * World.AbsoluteCameraDirection.Y; World.AbsoluteCameraPosition.Z += dz * World.AbsoluteCameraDirection.Z; ReducedMode = false; } break; // key down case SDL.SDL_EventType.SDL_KEYDOWN: switch (Event.key.keysym.sym) { case SDL.SDL_Keycode.SDLK_LSHIFT: case SDL.SDL_Keycode.SDLK_RSHIFT: ShiftPressed = true; break; case SDL.SDL_Keycode.SDLK_F5: // reset ReducedMode = false; LightingRelative = -1.0; Game.Reset(); TextureManager.UnuseAllTextures(); Fonts.Initialize(); Interface.ClearMessages(); for (int i = 0; i < Files.Length; i++) { #if !DEBUG try { #endif ObjectManager.UnifiedObject o = ObjectManager.LoadObject(Files[i], System.Text.Encoding.UTF8, ObjectManager.ObjectLoadMode.Normal, false, false, false); ObjectManager.CreateObject(o, new World.Vector3D(0.0, 0.0, 0.0), new World.Transformation(0.0, 0.0, 0.0), new World.Transformation(0.0, 0.0, 0.0), true, 0.0, 0.0, 25.0, 0.0); #if !DEBUG } catch (Exception ex) { Interface.AddMessage(Interface.MessageType.Critical, false, "Unhandled error (" + ex.Message + ") encountered while processing the file " + Files[i] + "."); } #endif } ObjectManager.InitializeVisibility(); ObjectManager.UpdateVisibility(0.0, true); ObjectManager.UpdateAnimatedWorldObjects(0.01, true); break; case SDL.SDL_Keycode.SDLK_F7: { OpenFileDialog Dialog = new OpenFileDialog(); Dialog.CheckFileExists = true; Dialog.Multiselect = true; Dialog.Filter = "CSV/B3D/X/ANIMATED files|*.csv;*.b3d;*.x;*.animated|All files|*"; if (Dialog.ShowDialog() == DialogResult.OK) { string[] f = Dialog.FileNames; int n = Files.Length; Array.Resize <string>(ref Files, n + f.Length); for (int i = 0; i < f.Length; i++) { Files[n + i] = f[i]; } // reset ReducedMode = false; LightingRelative = -1.0; Game.Reset(); TextureManager.UnuseAllTextures(); Fonts.Initialize(); Interface.ClearMessages(); for (int i = 0; i < Files.Length; i++) { #if !DEBUG try { #endif ObjectManager.UnifiedObject o = ObjectManager.LoadObject(Files[i], System.Text.Encoding.UTF8, ObjectManager.ObjectLoadMode.Normal, false, false, false); ObjectManager.CreateObject(o, new World.Vector3D(0.0, 0.0, 0.0), new World.Transformation(0.0, 0.0, 0.0), new World.Transformation(0.0, 0.0, 0.0), true, 0.0, 0.0, 25.0, 0.0); #if !DEBUG } catch (Exception ex) { Interface.AddMessage(Interface.MessageType.Critical, false, "Unhandled error (" + ex.Message + ") encountered while processing the file " + Files[i] + "."); } #endif } ObjectManager.InitializeVisibility(); ObjectManager.FinishCreatingObjects(); ObjectManager.UpdateVisibility(0.0, true); ObjectManager.UpdateAnimatedWorldObjects(0.01, true); } } break; case SDL.SDL_Keycode.SDLK_F9: if (Interface.MessageCount != 0) { formMessages.ShowMessages(); } break; case SDL.SDL_Keycode.SDLK_DELETE: ReducedMode = false; LightingRelative = -1.0; Game.Reset(); TextureManager.UnuseAllTextures(); Fonts.Initialize(); Interface.ClearMessages(); Files = new string[] { }; UpdateCaption(); break; case SDL.SDL_Keycode.SDLK_LEFT: RotateX = -1; ReducedMode = false; break; case SDL.SDL_Keycode.SDLK_RIGHT: RotateX = 1; ReducedMode = false; break; case SDL.SDL_Keycode.SDLK_UP: RotateY = -1; ReducedMode = false; break; case SDL.SDL_Keycode.SDLK_DOWN: RotateY = 1; ReducedMode = false; break; case SDL.SDL_Keycode.SDLK_a: case SDL.SDL_Keycode.SDLK_KP_4: MoveX = -1; ReducedMode = false; break; case SDL.SDL_Keycode.SDLK_d: case SDL.SDL_Keycode.SDLK_KP_6: MoveX = 1; ReducedMode = false; break; case SDL.SDL_Keycode.SDLK_KP_8: MoveY = 1; ReducedMode = false; break; case SDL.SDL_Keycode.SDLK_KP_2: MoveY = -1; ReducedMode = false; break; case SDL.SDL_Keycode.SDLK_w: case SDL.SDL_Keycode.SDLK_KP_9: MoveZ = 1; ReducedMode = false; break; case SDL.SDL_Keycode.SDLK_s: case SDL.SDL_Keycode.SDLK_KP_3: MoveZ = -1; ReducedMode = false; break; case SDL.SDL_Keycode.SDLK_KP_5: ResetCamera(); break; case SDL.SDL_Keycode.SDLK_f: case SDL.SDL_Keycode.SDLK_F1: Renderer.OptionWireframe = !Renderer.OptionWireframe; if (Renderer.OptionWireframe) { GL.PolygonMode(MaterialFace.FrontAndBack, PolygonMode.Line); } else { GL.PolygonMode(MaterialFace.FrontAndBack, PolygonMode.Fill); } break; case SDL.SDL_Keycode.SDLK_n: case SDL.SDL_Keycode.SDLK_F2: Renderer.OptionNormals = !Renderer.OptionNormals; break; case SDL.SDL_Keycode.SDLK_l: case SDL.SDL_Keycode.SDLK_F3: LightingTarget = 1 - LightingTarget; ReducedMode = false; break; case SDL.SDL_Keycode.SDLK_i: case SDL.SDL_Keycode.SDLK_F4: Renderer.OptionInterface = !Renderer.OptionInterface; ReducedMode = false; break; case SDL.SDL_Keycode.SDLK_g: case SDL.SDL_Keycode.SDLK_c: Renderer.OptionCoordinateSystem = !Renderer.OptionCoordinateSystem; ReducedMode = false; break; case SDL.SDL_Keycode.SDLK_b: if (ShiftPressed) { ColorDialog dialog = new ColorDialog(); dialog.FullOpen = true; if (dialog.ShowDialog() == DialogResult.OK) { Renderer.BackgroundColor = -1; Renderer.ApplyBackgroundColor(dialog.Color.R, dialog.Color.G, dialog.Color.B); } } else { Renderer.BackgroundColor++; if (Renderer.BackgroundColor >= Renderer.MaxBackgroundColor) { Renderer.BackgroundColor = 0; } Renderer.ApplyBackgroundColor(); } ReducedMode = false; break; } break; // key up case SDL.SDL_EventType.SDL_KEYUP: switch (Event.key.keysym.sym) { case SDL.SDL_Keycode.SDLK_LSHIFT: case SDL.SDL_Keycode.SDLK_RSHIFT: ShiftPressed = false; break; case SDL.SDL_Keycode.SDLK_LEFT: case SDL.SDL_Keycode.SDLK_RIGHT: RotateX = 0; break; case SDL.SDL_Keycode.SDLK_UP: case SDL.SDL_Keycode.SDLK_DOWN: RotateY = 0; break; case SDL.SDL_Keycode.SDLK_a: case SDL.SDL_Keycode.SDLK_d: case SDL.SDL_Keycode.SDLK_KP_4: case SDL.SDL_Keycode.SDLK_KP_6: MoveX = 0; break; case SDL.SDL_Keycode.SDLK_KP_8: case SDL.SDL_Keycode.SDLK_KP_2: MoveY = 0; break; case SDL.SDL_Keycode.SDLK_w: case SDL.SDL_Keycode.SDLK_s: case SDL.SDL_Keycode.SDLK_KP_9: case SDL.SDL_Keycode.SDLK_KP_3: MoveZ = 0; break; } break; } } }
// ------------------ // smoothen out turns private static void SmoothenOutTurns(int subdivisions) { if (subdivisions < 2) { throw new InvalidOperationException(); } // subdivide track int length = TrackManager.CurrentTrack.Elements.Length; int newLength = (length - 1) * subdivisions + 1; double[] midpointsTrackPositions = new double[newLength]; World.Vector3D[] midpointsWorldPositions = new World.Vector3D[newLength]; World.Vector3D[] midpointsWorldDirections = new World.Vector3D[newLength]; World.Vector3D[] midpointsWorldUps = new World.Vector3D[newLength]; World.Vector3D[] midpointsWorldSides = new World.Vector3D[newLength]; double[] midpointsCant = new double[newLength]; for (int i = 0; i < newLength; i++) { int m = i % subdivisions; if (m != 0) { int q = i / subdivisions; TrackManager.TrackFollower follower = new TrackManager.TrackFollower(); double r = (double)m / (double)subdivisions; double p = (1.0 - r) * TrackManager.CurrentTrack.Elements[q].StartingTrackPosition + r * TrackManager.CurrentTrack.Elements[q + 1].StartingTrackPosition; TrackManager.UpdateTrackFollower(ref follower, -1.0, true, false); TrackManager.UpdateTrackFollower(ref follower, p, true, false); midpointsTrackPositions[i] = p; midpointsWorldPositions[i] = follower.WorldPosition; midpointsWorldDirections[i] = follower.WorldDirection; midpointsWorldUps[i] = follower.WorldUp; midpointsWorldSides[i] = follower.WorldSide; midpointsCant[i] = follower.CurveCant; } } Array.Resize<TrackManager.TrackElement>(ref TrackManager.CurrentTrack.Elements, newLength); for (int i = length - 1; i >= 1; i--) { TrackManager.CurrentTrack.Elements[subdivisions * i] = TrackManager.CurrentTrack.Elements[i]; } for (int i = 0; i < TrackManager.CurrentTrack.Elements.Length; i++) { int m = i % subdivisions; if (m != 0) { int q = i / subdivisions; int j = q * subdivisions; TrackManager.CurrentTrack.Elements[i] = TrackManager.CurrentTrack.Elements[j]; TrackManager.CurrentTrack.Elements[i].Events = new TrackManager.GeneralEvent[] { }; TrackManager.CurrentTrack.Elements[i].StartingTrackPosition = midpointsTrackPositions[i]; TrackManager.CurrentTrack.Elements[i].WorldPosition = midpointsWorldPositions[i]; TrackManager.CurrentTrack.Elements[i].WorldDirection = midpointsWorldDirections[i]; TrackManager.CurrentTrack.Elements[i].WorldUp = midpointsWorldUps[i]; TrackManager.CurrentTrack.Elements[i].WorldSide = midpointsWorldSides[i]; TrackManager.CurrentTrack.Elements[i].CurveCant = midpointsCant[i]; TrackManager.CurrentTrack.Elements[i].CurveCantTangent = 0.0; } } // find turns bool[] isTurn = new bool[TrackManager.CurrentTrack.Elements.Length]; { TrackManager.TrackFollower follower = new TrackManager.TrackFollower(); for (int i = 1; i < TrackManager.CurrentTrack.Elements.Length - 1; i++) { int m = i % subdivisions; if (m == 0) { double p = 0.00000001 * TrackManager.CurrentTrack.Elements[i - 1].StartingTrackPosition + 0.99999999 * TrackManager.CurrentTrack.Elements[i].StartingTrackPosition; TrackManager.UpdateTrackFollower(ref follower, p, true, false); World.Vector3D d1 = TrackManager.CurrentTrack.Elements[i].WorldDirection; World.Vector3D d2 = follower.WorldDirection; World.Vector3D d = World.Vector3D.Subtract(d1, d2); double t = d.X * d.X + d.Z * d.Z; const double e = 0.0001; if (t > e) { isTurn[i] = true; } } } } // replace turns by curves double totalShortage = 0.0; for (int i = 0; i < TrackManager.CurrentTrack.Elements.Length; i++) { if (isTurn[i]) { // estimate radius World.Vector3D AP = TrackManager.CurrentTrack.Elements[i - 1].WorldPosition; World.Vector3D AS = TrackManager.CurrentTrack.Elements[i - 1].WorldSide; World.Vector3D BP = TrackManager.CurrentTrack.Elements[i + 1].WorldPosition; World.Vector3D BS = TrackManager.CurrentTrack.Elements[i + 1].WorldSide; World.Vector3D S = World.Vector3D.Subtract(AS, BS); double rx; if (S.X * S.X > 0.000001) { rx = (BP.X - AP.X) / S.X; } else { rx = 0.0; } double rz; if (S.Z * S.Z > 0.000001) { rz = (BP.Z - AP.Z) / S.Z; } else { rz = 0.0; } if (rx != 0.0 | rz != 0.0) { double r; if (rx != 0.0 & rz != 0.0) { if (Math.Sign(rx) == Math.Sign(rz)) { double f = rx / rz; if (f > -1.1 & f < -0.9 | f > 0.9 & f < 1.1) { r = Math.Sqrt(Math.Abs(rx * rz)) * Math.Sign(rx); } else { r = 0.0; } } else { r = 0.0; } } else if (rx != 0.0) { r = rx; } else { r = rz; } if (r * r > 1.0) { // apply radius TrackManager.TrackFollower follower = new TrackManager.TrackFollower(); TrackManager.CurrentTrack.Elements[i - 1].CurveRadius = r; double p = 0.00000001 * TrackManager.CurrentTrack.Elements[i - 1].StartingTrackPosition + 0.99999999 * TrackManager.CurrentTrack.Elements[i].StartingTrackPosition; TrackManager.UpdateTrackFollower(ref follower, p - 1.0, true, false); TrackManager.UpdateTrackFollower(ref follower, p, true, false); TrackManager.CurrentTrack.Elements[i].CurveRadius = r; //TrackManager.CurrentTrack.Elements[i].CurveCant = TrackManager.CurrentTrack.Elements[i].CurveCant; //TrackManager.CurrentTrack.Elements[i].CurveCantInterpolation = TrackManager.CurrentTrack.Elements[i].CurveCantInterpolation; TrackManager.CurrentTrack.Elements[i].WorldPosition = follower.WorldPosition; TrackManager.CurrentTrack.Elements[i].WorldDirection = follower.WorldDirection; TrackManager.CurrentTrack.Elements[i].WorldUp = follower.WorldUp; TrackManager.CurrentTrack.Elements[i].WorldSide = follower.WorldSide; // iterate to shorten track element length p = 0.00000001 * TrackManager.CurrentTrack.Elements[i].StartingTrackPosition + 0.99999999 * TrackManager.CurrentTrack.Elements[i + 1].StartingTrackPosition; TrackManager.UpdateTrackFollower(ref follower, p - 1.0, true, false); TrackManager.UpdateTrackFollower(ref follower, p, true, false); World.Vector3D d = World.Vector3D.Subtract(TrackManager.CurrentTrack.Elements[i + 1].WorldPosition, follower.WorldPosition); double bestT = d.X * d.X + d.Y * d.Y + d.Z * d.Z; int bestJ = 0; int n = 1000; double a = 1.0 / (double)n * (TrackManager.CurrentTrack.Elements[i + 1].StartingTrackPosition - TrackManager.CurrentTrack.Elements[i].StartingTrackPosition); for (int j = 1; j < n - 1; j++) { TrackManager.UpdateTrackFollower(ref follower, TrackManager.CurrentTrack.Elements[i + 1].StartingTrackPosition - (double)j * a, true, false); d = World.Vector3D.Subtract(TrackManager.CurrentTrack.Elements[i + 1].WorldPosition, follower.WorldPosition); double t = d.X * d.X + d.Y * d.Y + d.Z * d.Z; if (t < bestT) { bestT = t; bestJ = j; } else { break; } } double s = (double)bestJ * a; for (int j = i + 1; j < TrackManager.CurrentTrack.Elements.Length; j++) { TrackManager.CurrentTrack.Elements[j].StartingTrackPosition -= s; } totalShortage += s; // introduce turn to compensate for curve p = 0.00000001 * TrackManager.CurrentTrack.Elements[i].StartingTrackPosition + 0.99999999 * TrackManager.CurrentTrack.Elements[i + 1].StartingTrackPosition; TrackManager.UpdateTrackFollower(ref follower, p - 1.0, true, false); TrackManager.UpdateTrackFollower(ref follower, p, true, false); World.Vector3D AB = World.Vector3D.Subtract(TrackManager.CurrentTrack.Elements[i + 1].WorldPosition, follower.WorldPosition); World.Vector3D AC = World.Vector3D.Subtract(TrackManager.CurrentTrack.Elements[i + 1].WorldPosition, TrackManager.CurrentTrack.Elements[i].WorldPosition); World.Vector3D BC = World.Vector3D.Subtract(follower.WorldPosition, TrackManager.CurrentTrack.Elements[i].WorldPosition); double sa = Math.Sqrt(BC.X * BC.X + BC.Z * BC.Z); double sb = Math.Sqrt(AC.X * AC.X + AC.Z * AC.Z); double sc = Math.Sqrt(AB.X * AB.X + AB.Z * AB.Z); double denominator = 2.0 * sa * sb; if (denominator != 0.0) { double originalAngle; { double value = (sa * sa + sb * sb - sc * sc) / denominator; if (value < -1.0) { originalAngle = Math.PI; } else if (value > 1.0) { originalAngle = 0; } else { originalAngle = Math.Acos(value); } } TrackManager.TrackElement originalTrackElement = TrackManager.CurrentTrack.Elements[i]; bestT = double.MaxValue; bestJ = 0; for (int j = -1; j <= 1; j++) { double g = (double)j * originalAngle; double cosg = Math.Cos(g); double sing = Math.Sin(g); TrackManager.CurrentTrack.Elements[i] = originalTrackElement; World.Rotate(ref TrackManager.CurrentTrack.Elements[i].WorldDirection.X, ref TrackManager.CurrentTrack.Elements[i].WorldDirection.Y, ref TrackManager.CurrentTrack.Elements[i].WorldDirection.Z, 0.0, 1.0, 0.0, cosg, sing); World.Rotate(ref TrackManager.CurrentTrack.Elements[i].WorldUp.X, ref TrackManager.CurrentTrack.Elements[i].WorldUp.Y, ref TrackManager.CurrentTrack.Elements[i].WorldUp.Z, 0.0, 1.0, 0.0, cosg, sing); World.Rotate(ref TrackManager.CurrentTrack.Elements[i].WorldSide.X, ref TrackManager.CurrentTrack.Elements[i].WorldSide.Y, ref TrackManager.CurrentTrack.Elements[i].WorldSide.Z, 0.0, 1.0, 0.0, cosg, sing); p = 0.00000001 * TrackManager.CurrentTrack.Elements[i].StartingTrackPosition + 0.99999999 * TrackManager.CurrentTrack.Elements[i + 1].StartingTrackPosition; TrackManager.UpdateTrackFollower(ref follower, p - 1.0, true, false); TrackManager.UpdateTrackFollower(ref follower, p, true, false); d = World.Vector3D.Subtract(TrackManager.CurrentTrack.Elements[i + 1].WorldPosition, follower.WorldPosition); double t = d.X * d.X + d.Y * d.Y + d.Z * d.Z; if (t < bestT) { bestT = t; bestJ = j; } } { double newAngle = (double)bestJ * originalAngle; double cosg = Math.Cos(newAngle); double sing = Math.Sin(newAngle); TrackManager.CurrentTrack.Elements[i] = originalTrackElement; World.Rotate(ref TrackManager.CurrentTrack.Elements[i].WorldDirection.X, ref TrackManager.CurrentTrack.Elements[i].WorldDirection.Y, ref TrackManager.CurrentTrack.Elements[i].WorldDirection.Z, 0.0, 1.0, 0.0, cosg, sing); World.Rotate(ref TrackManager.CurrentTrack.Elements[i].WorldUp.X, ref TrackManager.CurrentTrack.Elements[i].WorldUp.Y, ref TrackManager.CurrentTrack.Elements[i].WorldUp.Z, 0.0, 1.0, 0.0, cosg, sing); World.Rotate(ref TrackManager.CurrentTrack.Elements[i].WorldSide.X, ref TrackManager.CurrentTrack.Elements[i].WorldSide.Y, ref TrackManager.CurrentTrack.Elements[i].WorldSide.Z, 0.0, 1.0, 0.0, cosg, sing); } // iterate again to further shorten track element length p = 0.00000001 * TrackManager.CurrentTrack.Elements[i].StartingTrackPosition + 0.99999999 * TrackManager.CurrentTrack.Elements[i + 1].StartingTrackPosition; TrackManager.UpdateTrackFollower(ref follower, p - 1.0, true, false); TrackManager.UpdateTrackFollower(ref follower, p, true, false); d = World.Vector3D.Subtract(TrackManager.CurrentTrack.Elements[i + 1].WorldPosition, follower.WorldPosition); bestT = d.X * d.X + d.Y * d.Y + d.Z * d.Z; bestJ = 0; n = 1000; a = 1.0 / (double)n * (TrackManager.CurrentTrack.Elements[i + 1].StartingTrackPosition - TrackManager.CurrentTrack.Elements[i].StartingTrackPosition); for (int j = 1; j < n - 1; j++) { TrackManager.UpdateTrackFollower(ref follower, TrackManager.CurrentTrack.Elements[i + 1].StartingTrackPosition - (double)j * a, true, false); d = World.Vector3D.Subtract(TrackManager.CurrentTrack.Elements[i + 1].WorldPosition, follower.WorldPosition); double t = d.X * d.X + d.Y * d.Y + d.Z * d.Z; if (t < bestT) { bestT = t; bestJ = j; } else { break; } } s = (double)bestJ * a; for (int j = i + 1; j < TrackManager.CurrentTrack.Elements.Length; j++) { TrackManager.CurrentTrack.Elements[j].StartingTrackPosition -= s; } totalShortage += s; } // compensate for height difference p = 0.00000001 * TrackManager.CurrentTrack.Elements[i].StartingTrackPosition + 0.99999999 * TrackManager.CurrentTrack.Elements[i + 1].StartingTrackPosition; TrackManager.UpdateTrackFollower(ref follower, p - 1.0, true, false); TrackManager.UpdateTrackFollower(ref follower, p, true, false); World.Vector3D d1 = World.Vector3D.Subtract(TrackManager.CurrentTrack.Elements[i + 1].WorldPosition, TrackManager.CurrentTrack.Elements[i].WorldPosition); double a1 = Math.Atan(d1.Y / Math.Sqrt(d1.X * d1.X + d1.Z * d1.Z)); World.Vector3D d2 = World.Vector3D.Subtract(follower.WorldPosition, TrackManager.CurrentTrack.Elements[i].WorldPosition); double a2 = Math.Atan(d2.Y / Math.Sqrt(d2.X * d2.X + d2.Z * d2.Z)); double b = a2 - a1; if (b * b > 0.00000001) { double cosa = Math.Cos(b); double sina = Math.Sin(b); World.Rotate(ref TrackManager.CurrentTrack.Elements[i].WorldDirection.X, ref TrackManager.CurrentTrack.Elements[i].WorldDirection.Y, ref TrackManager.CurrentTrack.Elements[i].WorldDirection.Z, TrackManager.CurrentTrack.Elements[i].WorldSide.X, TrackManager.CurrentTrack.Elements[i].WorldSide.Y, TrackManager.CurrentTrack.Elements[i].WorldSide.Z, cosa, sina); World.Rotate(ref TrackManager.CurrentTrack.Elements[i].WorldUp.X, ref TrackManager.CurrentTrack.Elements[i].WorldUp.Y, ref TrackManager.CurrentTrack.Elements[i].WorldUp.Z, TrackManager.CurrentTrack.Elements[i].WorldSide.X, TrackManager.CurrentTrack.Elements[i].WorldSide.Y, TrackManager.CurrentTrack.Elements[i].WorldSide.Z, cosa, sina); } } } } } // correct events for (int i = 0; i < TrackManager.CurrentTrack.Elements.Length - 1; i++) { double startingTrackPosition = TrackManager.CurrentTrack.Elements[i].StartingTrackPosition; double endingTrackPosition = TrackManager.CurrentTrack.Elements[i + 1].StartingTrackPosition; for (int j = 0; j < TrackManager.CurrentTrack.Elements[i].Events.Length; j++) { double p = startingTrackPosition + TrackManager.CurrentTrack.Elements[i].Events[j].TrackPositionDelta; if (p >= endingTrackPosition) { int len = TrackManager.CurrentTrack.Elements[i + 1].Events.Length; Array.Resize<TrackManager.GeneralEvent>(ref TrackManager.CurrentTrack.Elements[i + 1].Events, len + 1); TrackManager.CurrentTrack.Elements[i + 1].Events[len] = TrackManager.CurrentTrack.Elements[i].Events[j]; TrackManager.CurrentTrack.Elements[i + 1].Events[len].TrackPositionDelta += startingTrackPosition - endingTrackPosition; for (int k = j; k < TrackManager.CurrentTrack.Elements[i].Events.Length - 1; k++) { TrackManager.CurrentTrack.Elements[i].Events[k] = TrackManager.CurrentTrack.Elements[i].Events[k + 1]; } len = TrackManager.CurrentTrack.Elements[i].Events.Length; Array.Resize<TrackManager.GeneralEvent>(ref TrackManager.CurrentTrack.Elements[i].Events, len - 1); j--; } } } }
internal static void PlaySound(ref int SoundSourceIndex, int SoundBufferIndex, World.Vector3D Position, Importance Important, bool Looped) { PlaySound(ref SoundSourceIndex, true, SoundBufferIndex, null, -1, Position, Important, Looped, 1.0, 1.0); }
// parse animated object config /// <summary>Loads a collection of animated objects from a file.</summary> /// <param name="FileName">The text file to load the animated object from. Must be an absolute file name.</param> /// <param name="Encoding">The encoding the file is saved in. If the file uses a byte order mark, the encoding indicated by the byte order mark is used and the Encoding parameter is ignored.</param> /// <param name="LoadMode">The texture load mode.</param> /// <returns>The collection of animated objects.</returns> internal static ObjectManager.AnimatedObjectCollection ReadObject(string FileName, System.Text.Encoding Encoding, ObjectManager.ObjectLoadMode LoadMode) { System.Globalization.CultureInfo Culture = System.Globalization.CultureInfo.InvariantCulture; ObjectManager.AnimatedObjectCollection Result = new ObjectManager.AnimatedObjectCollection(); Result.Objects = new ObjectManager.AnimatedObject[4]; int ObjectCount = 0; // load file string[] Lines = System.IO.File.ReadAllLines(FileName, Encoding); bool rpnUsed = false; for (int i = 0; i < Lines.Length; i++) { int j = Lines[i].IndexOf(';'); if (j >= 0) { Lines[i] = Lines[i].Substring(0, j).Trim(); } else { Lines[i] = Lines[i].Trim(); } if (Program.CurrentProgramType == Program.ProgramType.ObjectViewer | Program.CurrentProgramType == Program.ProgramType.RouteViewer) { if (Lines[i].IndexOf("functionrpn", StringComparison.OrdinalIgnoreCase) >= 0) { rpnUsed = true; } } } if (rpnUsed) { Interface.AddMessage(Interface.MessageType.Warning, false, "An animated object file contains non-official RPN functions. Please get rid of them in file " + FileName); } for (int i = 0; i < Lines.Length; i++) { if (Lines[i].Length != 0) { switch (Lines[i].ToLowerInvariant()) { case "[include]": { i++; World.Vector3D position = new World.Vector3D(0.0, 0.0, 0.0); ObjectManager.UnifiedObject[] obj = new OpenBve.ObjectManager.UnifiedObject[4]; int objCount = 0; while (i < Lines.Length && !(Lines[i].StartsWith("[", StringComparison.Ordinal) & Lines[i].EndsWith("]", StringComparison.Ordinal))) { if (Lines[i].Length != 0) { int j = Lines[i].IndexOf("=", StringComparison.Ordinal); if (j > 0) { string a = Lines[i].Substring(0, j).TrimEnd(); string b = Lines[i].Substring(j + 1).TrimStart(); switch (a.ToLowerInvariant()) { case "position": { string[] s = b.Split(','); if (s.Length == 3) { double x, y, z; if (!double.TryParse(s[0], System.Globalization.NumberStyles.Float, Culture, out x)) { Interface.AddMessage(Interface.MessageType.Error, false, "X is invalid in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName); } else if (!double.TryParse(s[1], System.Globalization.NumberStyles.Float, Culture, out y)) { Interface.AddMessage(Interface.MessageType.Error, false, "Y is invalid in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName); } else if (!double.TryParse(s[2], System.Globalization.NumberStyles.Float, Culture, out z)) { Interface.AddMessage(Interface.MessageType.Error, false, "Z is invalid in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName); } else { position = new World.Vector3D(x, y, z); } } else { Interface.AddMessage(Interface.MessageType.Error, false, "Exactly 3 arguments are expected in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName); } } break; default: Interface.AddMessage(Interface.MessageType.Error, false, "The attribute " + a + " is not supported at line " + (i + 1).ToString(Culture) + " in file " + FileName); break; } } else { string Folder = System.IO.Path.GetDirectoryName(FileName); if (Interface.ContainsInvalidPathChars(Lines[i])) { Interface.AddMessage(Interface.MessageType.Error, false, Lines[i] + " contains illegal characters at line " + (i + 1).ToString(Culture) + " in file " + FileName); } else { string file = Interface.GetCombinedFileName(Folder, Lines[i]); if (System.IO.File.Exists(file)) { if (obj.Length == objCount) { Array.Resize<ObjectManager.UnifiedObject>(ref obj, obj.Length << 1); } obj[objCount] = ObjectManager.LoadObject(file, Encoding, LoadMode, false, false, false); objCount++; } else { Interface.AddMessage(Interface.MessageType.Error, true, "File " + file + " not found at line " + (i + 1).ToString(Culture) + " in file " + FileName); } } } } i++; } i--; for (int j = 0; j < objCount; j++) { if (obj[j] != null) { if (obj[j] is ObjectManager.StaticObject) { ObjectManager.StaticObject s = (ObjectManager.StaticObject)obj[j]; s.Dynamic = 1; if (ObjectCount >= Result.Objects.Length) { Array.Resize<ObjectManager.AnimatedObject>(ref Result.Objects, Result.Objects.Length << 1); } ObjectManager.AnimatedObject a = new ObjectManager.AnimatedObject(); ObjectManager.AnimatedObjectState aos = new ObjectManager.AnimatedObjectState(); aos.Object = s; aos.Position = position; a.States = new ObjectManager.AnimatedObjectState[] { aos }; Result.Objects[ObjectCount] = a; ObjectCount++; } else if (obj[j] is ObjectManager.AnimatedObjectCollection) { ObjectManager.AnimatedObjectCollection a = (ObjectManager.AnimatedObjectCollection)obj[j]; for (int k = 0; k < a.Objects.Length; k++) { if (ObjectCount >= Result.Objects.Length) { Array.Resize<ObjectManager.AnimatedObject>(ref Result.Objects, Result.Objects.Length << 1); } for (int h = 0; h < a.Objects[k].States.Length; h++) { a.Objects[k].States[h].Position.X += position.X; a.Objects[k].States[h].Position.Y += position.Y; a.Objects[k].States[h].Position.Z += position.Z; } Result.Objects[ObjectCount] = a.Objects[k]; ObjectCount++; } } } } } break; case "[object]": { i++; if (Result.Objects.Length == ObjectCount) { Array.Resize<ObjectManager.AnimatedObject>(ref Result.Objects, Result.Objects.Length << 1); } Result.Objects[ObjectCount] = new ObjectManager.AnimatedObject(); Result.Objects[ObjectCount].States = new ObjectManager.AnimatedObjectState[] { }; Result.Objects[ObjectCount].CurrentState = -1; Result.Objects[ObjectCount].TranslateXDirection = new World.Vector3D(1.0, 0.0, 0.0); Result.Objects[ObjectCount].TranslateYDirection = new World.Vector3D(0.0, 1.0, 0.0); Result.Objects[ObjectCount].TranslateZDirection = new World.Vector3D(0.0, 0.0, 1.0); Result.Objects[ObjectCount].RotateXDirection = new World.Vector3D(1.0, 0.0, 0.0); Result.Objects[ObjectCount].RotateYDirection = new World.Vector3D(0.0, 1.0, 0.0); Result.Objects[ObjectCount].RotateZDirection = new World.Vector3D(0.0, 0.0, 1.0); Result.Objects[ObjectCount].TextureShiftXDirection = new World.Vector2D(1.0, 0.0); Result.Objects[ObjectCount].TextureShiftYDirection = new World.Vector2D(0.0, 1.0); Result.Objects[ObjectCount].RefreshRate = 0.0; Result.Objects[ObjectCount].ObjectIndex = -1; World.Vector3D Position = new World.Vector3D(0.0, 0.0, 0.0); string[] StateFiles = null; while (i < Lines.Length && !(Lines[i].StartsWith("[", StringComparison.Ordinal) & Lines[i].EndsWith("]", StringComparison.Ordinal))) { if (Lines[i].Length != 0) { int j = Lines[i].IndexOf("=", StringComparison.Ordinal); if (j > 0) { string a = Lines[i].Substring(0, j).TrimEnd(); string b = Lines[i].Substring(j + 1).TrimStart(); switch (a.ToLowerInvariant()) { case "position": { string[] s = b.Split(','); if (s.Length == 3) { double x, y, z; if (!double.TryParse(s[0], System.Globalization.NumberStyles.Float, Culture, out x)) { Interface.AddMessage(Interface.MessageType.Error, false, "X is invalid in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName); } else if (!double.TryParse(s[1], System.Globalization.NumberStyles.Float, Culture, out y)) { Interface.AddMessage(Interface.MessageType.Error, false, "Y is invalid in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName); } else if (!double.TryParse(s[2], System.Globalization.NumberStyles.Float, Culture, out z)) { Interface.AddMessage(Interface.MessageType.Error, false, "Z is invalid in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName); } else { Position = new World.Vector3D(x, y, z); } } else { Interface.AddMessage(Interface.MessageType.Error, false, "Exactly 3 arguments are expected in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName); } } break; case "states": { string[] s = b.Split(','); if (s.Length >= 1) { string Folder = System.IO.Path.GetDirectoryName(FileName); StateFiles = new string[s.Length]; for (int k = 0; k < s.Length; k++) { s[k] = s[k].Trim(); if (Interface.ContainsInvalidPathChars(s[k])) { Interface.AddMessage(Interface.MessageType.Error, false, "File" + k.ToString(Culture) + " contains illegal characters in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName); StateFiles[k] = null; } else { StateFiles[k] = Interface.GetCombinedFileName(Folder, s[k]); if (!System.IO.File.Exists(StateFiles[k])) { Interface.AddMessage(Interface.MessageType.Error, true, "File " + StateFiles[k] + " not found in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName); StateFiles[k] = null; } } } } else { Interface.AddMessage(Interface.MessageType.Error, false, "At least one argument is expected in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName); return null; } } break; case "statefunction": try { Result.Objects[ObjectCount].StateFunction = FunctionScripts.GetFunctionScriptFromInfixNotation(b); } catch (Exception ex) { Interface.AddMessage(Interface.MessageType.Error, false, ex.Message + " in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName); } break; case "statefunctionrpn": try { Result.Objects[ObjectCount].StateFunction = FunctionScripts.GetFunctionScriptFromPostfixNotation(b); } catch (Exception ex) { Interface.AddMessage(Interface.MessageType.Error, false, ex.Message + " in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName); } break; case "translatexdirection": case "translateydirection": case "translatezdirection": { string[] s = b.Split(','); if (s.Length == 3) { double x, y, z; if (!double.TryParse(s[0], System.Globalization.NumberStyles.Float, Culture, out x)) { Interface.AddMessage(Interface.MessageType.Error, false, "X is invalid in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName); } else if (!double.TryParse(s[1], System.Globalization.NumberStyles.Float, Culture, out y)) { Interface.AddMessage(Interface.MessageType.Error, false, "Y is invalid in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName); } else if (!double.TryParse(s[2], System.Globalization.NumberStyles.Float, Culture, out z)) { Interface.AddMessage(Interface.MessageType.Error, false, "Z is invalid in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName); } else { switch (a.ToLowerInvariant()) { case "translatexdirection": Result.Objects[ObjectCount].TranslateXDirection = new World.Vector3D(x, y, z); break; case "translateydirection": Result.Objects[ObjectCount].TranslateYDirection = new World.Vector3D(x, y, z); break; case "translatezdirection": Result.Objects[ObjectCount].TranslateZDirection = new World.Vector3D(x, y, z); break; } } } else { Interface.AddMessage(Interface.MessageType.Error, false, "Exactly 3 arguments are expected in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName); } } break; case "translatexfunction": try { Result.Objects[ObjectCount].TranslateXFunction = FunctionScripts.GetFunctionScriptFromInfixNotation(b); } catch (Exception ex) { Interface.AddMessage(Interface.MessageType.Error, false, ex.Message + " in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName); } break; case "translateyfunction": try { Result.Objects[ObjectCount].TranslateYFunction = FunctionScripts.GetFunctionScriptFromInfixNotation(b); } catch (Exception ex) { Interface.AddMessage(Interface.MessageType.Error, false, ex.Message + " in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName); } break; case "translatezfunction": try { Result.Objects[ObjectCount].TranslateZFunction = FunctionScripts.GetFunctionScriptFromInfixNotation(b); } catch (Exception ex) { Interface.AddMessage(Interface.MessageType.Error, false, ex.Message + " in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName); } break; case "translatexfunctionrpn": try { Result.Objects[ObjectCount].TranslateXFunction = FunctionScripts.GetFunctionScriptFromPostfixNotation(b); } catch (Exception ex) { Interface.AddMessage(Interface.MessageType.Error, false, ex.Message + " in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName); } break; case "translateyfunctionrpn": try { Result.Objects[ObjectCount].TranslateYFunction = FunctionScripts.GetFunctionScriptFromPostfixNotation(b); } catch (Exception ex) { Interface.AddMessage(Interface.MessageType.Error, false, ex.Message + " in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName); } break; case "translatezfunctionrpn": try { Result.Objects[ObjectCount].TranslateZFunction = FunctionScripts.GetFunctionScriptFromPostfixNotation(b); } catch (Exception ex) { Interface.AddMessage(Interface.MessageType.Error, false, ex.Message + " in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName); } break; case "rotatexdirection": case "rotateydirection": case "rotatezdirection": { string[] s = b.Split(','); if (s.Length == 3) { double x, y, z; if (!double.TryParse(s[0], System.Globalization.NumberStyles.Float, Culture, out x)) { Interface.AddMessage(Interface.MessageType.Error, false, "X is invalid in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName); } else if (!double.TryParse(s[1], System.Globalization.NumberStyles.Float, Culture, out y)) { Interface.AddMessage(Interface.MessageType.Error, false, "Y is invalid in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName); } else if (!double.TryParse(s[2], System.Globalization.NumberStyles.Float, Culture, out z)) { Interface.AddMessage(Interface.MessageType.Error, false, "Z is invalid in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName); } else if (x == 0.0 & y == 0.0 & z == 0.0) { Interface.AddMessage(Interface.MessageType.Error, false, "The direction indicated by X, Y and Z is expected to be non-zero in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName); } else { switch (a.ToLowerInvariant()) { case "rotatexdirection": Result.Objects[ObjectCount].RotateXDirection = new World.Vector3D(x, y, z); break; case "rotateydirection": Result.Objects[ObjectCount].RotateYDirection = new World.Vector3D(x, y, z); break; case "rotatezdirection": Result.Objects[ObjectCount].RotateZDirection = new World.Vector3D(x, y, z); break; } } } else { Interface.AddMessage(Interface.MessageType.Error, false, "Exactly 3 arguments are expected in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName); } } break; case "rotatexfunction": try { Result.Objects[ObjectCount].RotateXFunction = FunctionScripts.GetFunctionScriptFromInfixNotation(b); } catch (Exception ex) { Interface.AddMessage(Interface.MessageType.Error, false, ex.Message + " in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName); } break; case "rotateyfunction": try { Result.Objects[ObjectCount].RotateYFunction = FunctionScripts.GetFunctionScriptFromInfixNotation(b); } catch (Exception ex) { Interface.AddMessage(Interface.MessageType.Error, false, ex.Message + " in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName); } break; case "rotatezfunction": try { Result.Objects[ObjectCount].RotateZFunction = FunctionScripts.GetFunctionScriptFromInfixNotation(b); } catch (Exception ex) { Interface.AddMessage(Interface.MessageType.Error, false, ex.Message + " in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName); } break; case "rotatexfunctionrpn": try { Result.Objects[ObjectCount].RotateXFunction = FunctionScripts.GetFunctionScriptFromPostfixNotation(b); } catch (Exception ex) { Interface.AddMessage(Interface.MessageType.Error, false, ex.Message + " in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName); } break; case "rotateyfunctionrpn": try { Result.Objects[ObjectCount].RotateYFunction = FunctionScripts.GetFunctionScriptFromPostfixNotation(b); } catch (Exception ex) { Interface.AddMessage(Interface.MessageType.Error, false, ex.Message + " in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName); } break; case "rotatezfunctionrpn": try { Result.Objects[ObjectCount].RotateZFunction = FunctionScripts.GetFunctionScriptFromPostfixNotation(b); } catch (Exception ex) { Interface.AddMessage(Interface.MessageType.Error, false, ex.Message + " in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName); } break; case "rotatexdamping": case "rotateydamping": case "rotatezdamping": { string[] s = b.Split(','); if (s.Length == 2) { double nf, dr; if (!double.TryParse(s[0], System.Globalization.NumberStyles.Float, Culture, out nf)) { Interface.AddMessage(Interface.MessageType.Error, false, "NaturalFrequency is invalid in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName); } else if (!double.TryParse(s[1], System.Globalization.NumberStyles.Float, Culture, out dr)) { Interface.AddMessage(Interface.MessageType.Error, false, "DampingRatio is invalid in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName); } else if (nf <= 0.0) { Interface.AddMessage(Interface.MessageType.Error, false, "NaturalFrequency is expected to be positive in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName); } else if (dr <= 0.0) { Interface.AddMessage(Interface.MessageType.Error, false, "DampingRatio is expected to be positive in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName); } else { switch (a.ToLowerInvariant()) { case "rotatexdamping": Result.Objects[ObjectCount].RotateXDamping = new ObjectManager.Damping(nf, dr); break; case "rotateydamping": Result.Objects[ObjectCount].RotateYDamping = new ObjectManager.Damping(nf, dr); break; case "rotatezdamping": Result.Objects[ObjectCount].RotateZDamping = new ObjectManager.Damping(nf, dr); break; } } } else { Interface.AddMessage(Interface.MessageType.Error, false, "Exactly 2 arguments are expected in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName); } } break; case "textureshiftxdirection": case "textureshiftydirection": { string[] s = b.Split(','); if (s.Length == 2) { double x, y; if (!double.TryParse(s[0], System.Globalization.NumberStyles.Float, Culture, out x)) { Interface.AddMessage(Interface.MessageType.Error, false, "X is invalid in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName); } else if (!double.TryParse(s[1], System.Globalization.NumberStyles.Float, Culture, out y)) { Interface.AddMessage(Interface.MessageType.Error, false, "Y is invalid in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName); } else { switch (a.ToLowerInvariant()) { case "textureshiftxdirection": Result.Objects[ObjectCount].TextureShiftXDirection = new World.Vector2D(x, y); break; case "textureshiftydirection": Result.Objects[ObjectCount].TextureShiftYDirection = new World.Vector2D(x, y); break; } } } else { Interface.AddMessage(Interface.MessageType.Error, false, "Exactly 2 arguments are expected in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName); } } break; case "textureshiftxfunction": try { Result.Objects[ObjectCount].TextureShiftXFunction = FunctionScripts.GetFunctionScriptFromInfixNotation(b); } catch (Exception ex) { Interface.AddMessage(Interface.MessageType.Error, false, ex.Message + " in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName); } break; case "textureshiftyfunction": try { Result.Objects[ObjectCount].TextureShiftYFunction = FunctionScripts.GetFunctionScriptFromInfixNotation(b); } catch (Exception ex) { Interface.AddMessage(Interface.MessageType.Error, false, ex.Message + " in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName); } break; case "textureshiftxfunctionrpn": try { Result.Objects[ObjectCount].TextureShiftXFunction = FunctionScripts.GetFunctionScriptFromPostfixNotation(b); } catch (Exception ex) { Interface.AddMessage(Interface.MessageType.Error, false, ex.Message + " in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName); } break; case "textureshiftyfunctionrpn": try { Result.Objects[ObjectCount].TextureShiftYFunction = FunctionScripts.GetFunctionScriptFromPostfixNotation(b); } catch (Exception ex) { Interface.AddMessage(Interface.MessageType.Error, false, ex.Message + " in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName); } break; case "refreshrate": { double r; if (!double.TryParse(b, System.Globalization.NumberStyles.Float, Culture, out r)) { Interface.AddMessage(Interface.MessageType.Error, false, "Value is invalid in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName); } else if (r < 0.0) { Interface.AddMessage(Interface.MessageType.Error, false, "Value is expected to be non-negative in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName); } else { Result.Objects[ObjectCount].RefreshRate = r; } } break; default: Interface.AddMessage(Interface.MessageType.Error, false, "The attribute " + a + " is not supported at line " + (i + 1).ToString(Culture) + " in file " + FileName); break; } } else { Interface.AddMessage(Interface.MessageType.Error, false, "Invalid statement " + Lines[i] + " encountered at line " + (i + 1).ToString(Culture) + " in file " + FileName); return null; } } i++; } i--; if (StateFiles != null) { Result.Objects[ObjectCount].States = new ObjectManager.AnimatedObjectState[StateFiles.Length]; bool ForceTextureRepeatX = Result.Objects[ObjectCount].TextureShiftXFunction != null & Result.Objects[ObjectCount].TextureShiftXDirection.X != 0.0 | Result.Objects[ObjectCount].TextureShiftYFunction != null & Result.Objects[ObjectCount].TextureShiftYDirection.Y != 0.0; bool ForceTextureRepeatY = Result.Objects[ObjectCount].TextureShiftXFunction != null & Result.Objects[ObjectCount].TextureShiftXDirection.X != 0.0 | Result.Objects[ObjectCount].TextureShiftYFunction != null & Result.Objects[ObjectCount].TextureShiftYDirection.Y != 0.0; for (int k = 0; k < StateFiles.Length; k++) { Result.Objects[ObjectCount].States[k].Position = new World.Vector3D(0.0, 0.0, 0.0); if (StateFiles[k] != null) { Result.Objects[ObjectCount].States[k].Object = ObjectManager.LoadStaticObject(StateFiles[k], Encoding, LoadMode, false, ForceTextureRepeatX, ForceTextureRepeatY); Result.Objects[ObjectCount].States[k].Object.Dynamic = 1; } else { Result.Objects[ObjectCount].States[k].Object = null; } for (int j = 0; j < Result.Objects[ObjectCount].States.Length; j++) { Result.Objects[ObjectCount].States[j].Position = Position; } } } else { Result.Objects[ObjectCount].States = new ObjectManager.AnimatedObjectState[] { }; } ObjectCount++; } break; default: Interface.AddMessage(Interface.MessageType.Error, false, "Invalid statement " + Lines[i] + " encountered at line " + (i + 1).ToString(Culture) + " in file " + FileName); return null; } } } Array.Resize<ObjectManager.AnimatedObject>(ref Result.Objects, ObjectCount); return Result; }
internal static void PlaySound(int SoundBufferIndex, World.Vector3D Position, Importance Important, bool Looped) { int a = -1; PlaySound(ref a, false, SoundBufferIndex, null, -1, Position, Important, Looped, 1.0, 1.0); }
internal static void PlaySound(int SoundBufferIndex, TrainManager.Train Train, int CarIndex, World.Vector3D Position, Importance Important, bool Looped) { int a = -1; PlaySound(ref a, false, SoundBufferIndex, Train, CarIndex, Position, Important, Looped, 1.0, 1.0); }