Cross() static private méthode

static private Cross ( OpenBveApi.Math.Vector3D A, OpenBveApi.Math.Vector3D B ) : World.Vector3D
A OpenBveApi.Math.Vector3D
B OpenBveApi.Math.Vector3D
Résultat World.Vector3D
            /// <summary>Updates the position and rotation of an animated object which follows a track</summary>
            private void UpdateObjectPosition()
            {
                //Get vectors
                double dx, dy, dz;
                double ux, uy, uz;
                double sx, sy, sz;

                {
                    dx = FrontAxleFollower.WorldPosition.X - RearAxleFollower.WorldPosition.X;
                    dy = FrontAxleFollower.WorldPosition.Y - RearAxleFollower.WorldPosition.Y;
                    dz = FrontAxleFollower.WorldPosition.Z - RearAxleFollower.WorldPosition.Z;
                    double t = 1.0 / Math.Sqrt(dx * dx + dy * dy + dz * dz);
                    dx *= t;
                    dy *= t;
                    dz *= t;
                    t   = 1.0 / Math.Sqrt(dx * dx + dz * dz);
                    double ex = dx * t;
                    double ez = dz * t;
                    sx = ez;
                    sy = 0.0;
                    sz = -ex;
                    World.Cross(dx, dy, dz, sx, sy, sz, out ux, out uy, out uz);
                }

                // apply position due to cant/toppling
                {
                    double a  = CurrentRollDueToTopplingAngle + CurrentRollDueToCantAngle;
                    double x  = Math.Sign(a) * 0.5 * Game.RouteRailGauge * (1.0 - Math.Cos(a));
                    double y  = Math.Abs(0.5 * Game.RouteRailGauge * Math.Sin(a));
                    double cx = sx * x + ux * y;
                    double cy = sy * x + uy * y;
                    double cz = sz * x + uz * y;
                    FrontAxleFollower.WorldPosition.X += cx;
                    FrontAxleFollower.WorldPosition.Y += cy;
                    FrontAxleFollower.WorldPosition.Z += cz;
                    RearAxleFollower.WorldPosition.X  += cx;
                    RearAxleFollower.WorldPosition.Y  += cy;
                    RearAxleFollower.WorldPosition.Z  += cz;
                }
                // apply rolling
                {
                    double a    = CurrentRollDueToTopplingAngle - CurrentRollDueToCantAngle;
                    double cosa = Math.Cos(a);
                    double sina = Math.Sin(a);
                    World.Rotate(ref sx, ref sy, ref sz, dx, dy, dz, cosa, sina);
                    World.Rotate(ref ux, ref uy, ref uz, dx, dy, dz, cosa, sina);
                    Up.X = ux;
                    Up.Y = uy;
                    Up.Z = uz;
                }
                Direction.X = dx;
                Direction.Y = dy;
                Direction.Z = dz;
                Side.X      = sx;
                Side.Y      = sy;
                Side.Z      = sz;
            }
Exemple #2
0
 // reset camera
 private static void ResetCamera()
 {
     World.AbsoluteCameraPosition  = new World.Vector3D(0.0, 2.5, -5.0);
     World.AbsoluteCameraDirection = new World.Vector3D(-World.AbsoluteCameraPosition.X, -World.AbsoluteCameraPosition.Y, -World.AbsoluteCameraPosition.Z);
     World.AbsoluteCameraSide      = new World.Vector3D(-World.AbsoluteCameraPosition.Z, 0.0, World.AbsoluteCameraPosition.X);
     World.Normalize(ref World.AbsoluteCameraDirection.X, ref World.AbsoluteCameraDirection.Y, ref World.AbsoluteCameraDirection.Z);
     World.Normalize(ref World.AbsoluteCameraSide.X, ref World.AbsoluteCameraSide.Y, ref World.AbsoluteCameraSide.Z);
     World.AbsoluteCameraUp             = World.Cross(World.AbsoluteCameraDirection, World.AbsoluteCameraSide);
     World.VerticalViewingAngle         = 45.0 * 0.0174532925199433;
     World.HorizontalViewingAngle       = 2.0 * Math.Atan(Math.Tan(0.5 * World.VerticalViewingAngle) * World.AspectRatio);
     World.OriginalVerticalViewingAngle = World.VerticalViewingAngle;
 }
Exemple #3
0
            internal void ApplyShear(double dx, double dy, double dz, double sx, double sy, double sz, double r)
            {
                for (int j = 0; j < Mesh.Vertices.Length; j++)
                {
                    double n = r * (dx * Mesh.Vertices[j].Coordinates.X + dy * Mesh.Vertices[j].Coordinates.Y + dz * Mesh.Vertices[j].Coordinates.Z);
                    Mesh.Vertices[j].Coordinates.X += sx * n;
                    Mesh.Vertices[j].Coordinates.Y += sy * n;
                    Mesh.Vertices[j].Coordinates.Z += sz * n;
                }

                // ReSharper disable NotAccessedVariable
                double ux, uy, uz;

                // ReSharper restore NotAccessedVariable
                World.Cross(sx, sy, sz, dx, dy, dz, out ux, out uy, out uz);
                for (int j = 0; j < Mesh.Faces.Length; j++)
                {
                    for (int k = 0; k < Mesh.Faces[j].Vertices.Length; k++)
                    {
                        if (Mesh.Faces[j].Vertices[k].Normal.X != 0.0f | Mesh.Faces[j].Vertices[k].Normal.Y != 0.0f | Mesh.Faces[j].Vertices[k].Normal.Z != 0.0f)
                        {
                            double nx = (double)Mesh.Faces[j].Vertices[k].Normal.X;
                            double ny = (double)Mesh.Faces[j].Vertices[k].Normal.Y;
                            double nz = (double)Mesh.Faces[j].Vertices[k].Normal.Z;
                            double n  = r * (sx * nx + sy * ny + sz * nz);
                            nx -= dx * n;
                            ny -= dy * n;
                            nz -= dz * n;
                            Mesh.Faces[j].Vertices[k].Normal.X = (float)nx;
                            Mesh.Faces[j].Vertices[k].Normal.Y = (float)ny;
                            Mesh.Faces[j].Vertices[k].Normal.Z = (float)nz;
                            Mesh.Faces[j].Vertices[k].Normal.Normalize();
                        }
                    }
                }
            }
Exemple #4
0
            /// <summary>Call this method to update a single track follower</summary>
            /// <param name="NewTrackPosition">The new track position of the follower</param>
            /// <param name="UpdateWorldCoordinates">Whether to update the world co-ordinates</param>
            /// <param name="AddTrackInaccurary">Whether to add track innacuracy</param>
            internal void Update(double NewTrackPosition, bool UpdateWorldCoordinates, bool AddTrackInaccurary)
            {
                if (CurrentTrack.Elements.Length == 0)
                {
                    return;
                }
                int i = LastTrackElement;

                while (i >= 0 && NewTrackPosition < CurrentTrack.Elements[i].StartingTrackPosition)
                {
                    double ta = TrackPosition - CurrentTrack.Elements[i].StartingTrackPosition;
                    double tb = -0.01;
                    CheckEvents(i, -1, ta, tb);
                    i--;
                }
                if (i >= 0)
                {
                    while (i < CurrentTrack.Elements.Length - 1)
                    {
                        if (NewTrackPosition < CurrentTrack.Elements[i + 1].StartingTrackPosition)
                        {
                            break;
                        }
                        double ta = TrackPosition - CurrentTrack.Elements[i].StartingTrackPosition;
                        double tb = CurrentTrack.Elements[i + 1].StartingTrackPosition - CurrentTrack.Elements[i].StartingTrackPosition + 0.01;
                        CheckEvents(i, 1, ta, tb);
                        i++;
                    }
                }
                else
                {
                    i = 0;
                }
                double da = 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;
                            Vector3 D = new Vector3(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, 0.0, 1.0, 0.0, cosa, sina);
                            WorldPosition.X = CurrentTrack.Elements[i].WorldPosition.X + c * D.X;
                            WorldPosition.Y = CurrentTrack.Elements[i].WorldPosition.Y + h;
                            WorldPosition.Z = CurrentTrack.Elements[i].WorldPosition.Z + c * D.Z;
                            World.Rotate(ref D, 0.0, 1.0, 0.0, cosa, sina);
                            WorldDirection.X = D.X;
                            WorldDirection.Y = p;
                            WorldDirection.Z = D.Z;
                            World.Normalize(ref WorldDirection.X, ref WorldDirection.Y, ref WorldDirection.Z);
                            double cos2a = Math.Cos(2.0 * a);
                            double sin2a = Math.Sin(2.0 * a);
                            WorldSide = CurrentTrack.Elements[i].WorldSide;
                            World.Rotate(ref WorldSide, 0.0, 1.0, 0.0, cos2a, sin2a);
                            World.Cross(WorldDirection, WorldSide, out WorldUp);
                        }
                        else
                        {
                            // straight
                            WorldPosition.X = CurrentTrack.Elements[i].WorldPosition.X + db * CurrentTrack.Elements[i].WorldDirection.X;
                            WorldPosition.Y = CurrentTrack.Elements[i].WorldPosition.Y + db * CurrentTrack.Elements[i].WorldDirection.Y;
                            WorldPosition.Z = CurrentTrack.Elements[i].WorldPosition.Z + db * CurrentTrack.Elements[i].WorldDirection.Z;
                            WorldDirection  = CurrentTrack.Elements[i].WorldDirection;
                            WorldUp         = CurrentTrack.Elements[i].WorldUp;
                            WorldSide       = CurrentTrack.Elements[i].WorldSide;
                            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;
                            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;
                            CurveRadius = CurrentTrack.Elements[i].CurveRadius;
                        }
                        else
                        {
                            CurveCant = CurrentTrack.Elements[i].CurveCant;
                        }
                    }
                    else
                    {
                        WorldPosition  = CurrentTrack.Elements[i].WorldPosition;
                        WorldDirection = CurrentTrack.Elements[i].WorldDirection;
                        WorldUp        = CurrentTrack.Elements[i].WorldUp;
                        WorldSide      = CurrentTrack.Elements[i].WorldSide;
                        CurveRadius    = CurrentTrack.Elements[i].CurveRadius;
                        CurveCant      = CurrentTrack.Elements[i].CurveCant;
                    }
                }
                else
                {
                    if (db != 0.0)
                    {
                        if (CurrentTrack.Elements[i].CurveRadius != 0.0)
                        {
                            CurveRadius = CurrentTrack.Elements[i].CurveRadius;
                        }
                        else
                        {
                            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;
                            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
                        {
                            CurveCant = CurrentTrack.Elements[i].CurveCant;
                        }
                    }
                    else
                    {
                        CurveRadius = CurrentTrack.Elements[i].CurveRadius;
                        CurveCant   = CurrentTrack.Elements[i].CurveCant;
                    }
                }
                AdhesionMultiplier = CurrentTrack.Elements[i].AdhesionMultiplier;
                //Pitch added for Plugin Data usage
                //Mutliply this by 1000 to get the original value
                Pitch = CurrentTrack.Elements[i].Pitch * 1000;
                // 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);
                    }
                    WorldPosition.X    += x * WorldSide.X + y * WorldUp.X;
                    WorldPosition.Y    += x * WorldSide.Y + y * WorldUp.Y;
                    WorldPosition.Z    += x * WorldSide.Z + y * WorldUp.Z;
                    CurveCant          += c;
                    CantDueToInaccuracy = c;
                }
                else
                {
                    CantDueToInaccuracy = 0.0;
                }
                // events
                CheckEvents(i, Math.Sign(db - da), da, db);
                //Update the odometer
                if (TrackPosition != NewTrackPosition)
                {
                    //HACK: Reset the odometer if we've moved more than 10m this frame
                    if (Math.Abs(NewTrackPosition - TrackPosition) > 10)
                    {
                        Odometer = 0;
                    }
                    else
                    {
                        Odometer += NewTrackPosition - TrackPosition;
                    }
                }
                // finish
                TrackPosition    = NewTrackPosition;
                LastTrackElement = i;
            }
Exemple #5
0
        protected override void OnRenderFrame(FrameEventArgs e)
        {
            Program.MouseMovement();
            double   timeElapsed = CPreciseTimer.GetElapsedTime();
            DateTime time        = DateTime.Now;

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

            // rotate x
            if (Program.RotateX == 0)
            {
                double d = (1.0 + Math.Abs(RotateXSpeed)) * timeElapsed;
                if (RotateXSpeed >= -d & RotateXSpeed <= d)
                {
                    RotateXSpeed = 0.0;
                }
                else
                {
                    RotateXSpeed -= (double)Math.Sign(RotateXSpeed) * d;
                }
            }
            else
            {
                double d = (1.0 + 1.0 - 1.0 / (1.0 + RotateXSpeed * RotateXSpeed)) * timeElapsed;
                double m = 1.0;
                RotateXSpeed += (double)Program.RotateX * d;
                if (RotateXSpeed < -m)
                {
                    RotateXSpeed = -m;
                }
                else if (RotateXSpeed > m)
                {
                    RotateXSpeed = m;
                }
            }
            if (RotateXSpeed != 0.0)
            {
                double cosa = Math.Cos(RotateXSpeed * timeElapsed);
                double sina = Math.Sin(RotateXSpeed * timeElapsed);
                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);
                keep = true;
            }
            // rotate y
            if (Program.RotateY == 0)
            {
                double d = (1.0 + Math.Abs(RotateYSpeed)) * timeElapsed;
                if (RotateYSpeed >= -d & RotateYSpeed <= d)
                {
                    RotateYSpeed = 0.0;
                }
                else
                {
                    RotateYSpeed -= (double)Math.Sign(RotateYSpeed) * d;
                }
            }
            else
            {
                double d = (1.0 + 1.0 - 1.0 / (1.0 + RotateYSpeed * RotateYSpeed)) * timeElapsed;
                double m = 1.0;
                RotateYSpeed += (double)Program.RotateY * d;
                if (RotateYSpeed < -m)
                {
                    RotateYSpeed = -m;
                }
                else if (RotateYSpeed > m)
                {
                    RotateYSpeed = m;
                }
            }
            if (RotateYSpeed != 0.0)
            {
                double cosa = Math.Cos(RotateYSpeed * timeElapsed);
                double sina = Math.Sin(RotateYSpeed * timeElapsed);
                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);
                keep = true;
            }
            // move x
            if (Program.MoveX == 0)
            {
                double d = (2.5 + Math.Abs(MoveXSpeed)) * timeElapsed;
                if (MoveXSpeed >= -d & MoveXSpeed <= d)
                {
                    MoveXSpeed = 0.0;
                }
                else
                {
                    MoveXSpeed -= (double)Math.Sign(MoveXSpeed) * d;
                }
            }
            else
            {
                double d = (5.0 + 10.0 - 10.0 / (1.0 + MoveXSpeed * MoveXSpeed)) * timeElapsed;
                double m = 25.0;
                MoveXSpeed += (double)Program.MoveX * d;
                if (MoveXSpeed < -m)
                {
                    MoveXSpeed = -m;
                }
                else if (MoveXSpeed > m)
                {
                    MoveXSpeed = m;
                }
            }
            if (MoveXSpeed != 0.0)
            {
                World.AbsoluteCameraPosition.X += MoveXSpeed * timeElapsed * World.AbsoluteCameraSide.X;
                World.AbsoluteCameraPosition.Y += MoveXSpeed * timeElapsed * World.AbsoluteCameraSide.Y;
                World.AbsoluteCameraPosition.Z += MoveXSpeed * timeElapsed * World.AbsoluteCameraSide.Z;
                keep = true;
            }
            // move y
            if (Program.MoveY == 0)
            {
                double d = (2.5 + Math.Abs(MoveYSpeed)) * timeElapsed;
                if (MoveYSpeed >= -d & MoveYSpeed <= d)
                {
                    MoveYSpeed = 0.0;
                }
                else
                {
                    MoveYSpeed -= (double)Math.Sign(MoveYSpeed) * d;
                }
            }
            else
            {
                double d = (5.0 + 10.0 - 10.0 / (1.0 + MoveYSpeed * MoveYSpeed)) * timeElapsed;
                double m = 25.0;
                MoveYSpeed += (double)Program.MoveY * d;
                if (MoveYSpeed < -m)
                {
                    MoveYSpeed = -m;
                }
                else if (MoveYSpeed > m)
                {
                    MoveYSpeed = m;
                }
            }
            if (MoveYSpeed != 0.0)
            {
                World.AbsoluteCameraPosition.X += MoveYSpeed * timeElapsed * World.AbsoluteCameraUp.X;
                World.AbsoluteCameraPosition.Y += MoveYSpeed * timeElapsed * World.AbsoluteCameraUp.Y;
                World.AbsoluteCameraPosition.Z += MoveYSpeed * timeElapsed * World.AbsoluteCameraUp.Z;
                keep = true;
            }
            // move z
            if (Program.MoveZ == 0)
            {
                double d = (2.5 + Math.Abs(MoveZSpeed)) * timeElapsed;
                if (MoveZSpeed >= -d & MoveZSpeed <= d)
                {
                    MoveZSpeed = 0.0;
                }
                else
                {
                    MoveZSpeed -= (double)Math.Sign(MoveZSpeed) * d;
                }
            }
            else
            {
                double d = (5.0 + 10.0 - 10.0 / (1.0 + MoveZSpeed * MoveZSpeed)) * timeElapsed;
                double m = 25.0;
                MoveZSpeed += (double)Program.MoveZ * d;
                if (MoveZSpeed < -m)
                {
                    MoveZSpeed = -m;
                }
                else if (MoveZSpeed > m)
                {
                    MoveZSpeed = m;
                }
            }
            if (MoveZSpeed != 0.0)
            {
                World.AbsoluteCameraPosition.X += MoveZSpeed * timeElapsed * World.AbsoluteCameraDirection.X;
                World.AbsoluteCameraPosition.Y += MoveZSpeed * timeElapsed * World.AbsoluteCameraDirection.Y;
                World.AbsoluteCameraPosition.Z += MoveZSpeed * timeElapsed * World.AbsoluteCameraDirection.Z;
                keep = true;
            }
            // lighting
            if (Program.LightingRelative == -1)
            {
                Program.LightingRelative = (double)Program.LightingTarget;
                updatelight = true;
            }
            if (Program.LightingTarget == 0)
            {
                if (Program.LightingRelative != 0.0)
                {
                    Program.LightingRelative -= 0.5 * timeElapsed;
                    if (Program.LightingRelative < 0.0)
                    {
                        Program.LightingRelative = 0.0;
                    }
                    updatelight = true;
                    keep        = true;
                }
            }
            else
            {
                if (Program.LightingRelative != 1.0)
                {
                    Program.LightingRelative += 0.5 * timeElapsed;
                    if (Program.LightingRelative > 1.0)
                    {
                        Program.LightingRelative = 1.0;
                    }
                    updatelight = true;
                    keep        = true;
                }
            }
            // continue
            if (Program.ReducedMode)
            {
                ReducedModeEnteringTime = 3.0;
            }
            else
            {
                if (keep)
                {
                    ReducedModeEnteringTime = 3.0;
                }
                else if (ReducedModeEnteringTime <= 0)
                {
                    Program.ReducedMode        = true;
                    World.AbsoluteCameraSide.Y = 0.0;
                    World.Normalize(ref World.AbsoluteCameraSide.X, ref World.AbsoluteCameraSide.Y, ref World.AbsoluteCameraSide.Z);
                    World.Normalize(ref World.AbsoluteCameraDirection.X, ref World.AbsoluteCameraDirection.Y, ref World.AbsoluteCameraDirection.Z);
                    World.AbsoluteCameraUp = World.Cross(World.AbsoluteCameraDirection, World.AbsoluteCameraSide);
                }
                else
                {
                    ReducedModeEnteringTime -= timeElapsed;
                }
            }
            if (updatelight)
            {
                Renderer.OptionAmbientColor.R = (byte)Math.Round(32.0 + 128.0 * Program.LightingRelative * (2.0 - Program.LightingRelative));
                Renderer.OptionAmbientColor.G = (byte)Math.Round(32.0 + 128.0 * 0.5 * (Program.LightingRelative + Program.LightingRelative * (2.0 - Program.LightingRelative)));
                Renderer.OptionAmbientColor.B = (byte)Math.Round(32.0 + 128.0 * Program.LightingRelative);
                Renderer.OptionDiffuseColor.R = (byte)Math.Round(32.0 + 128.0 * Program.LightingRelative);
                Renderer.OptionDiffuseColor.G = (byte)Math.Round(32.0 + 128.0 * Program.LightingRelative);
                Renderer.OptionDiffuseColor.B = (byte)Math.Round(32.0 + 128.0 * Math.Sqrt(Program.LightingRelative));
                Renderer.InitializeLighting();
            }
            Renderer.RenderScene();
            SwapBuffers();
        }
Exemple #6
0
        internal static void Main(string[] args)
        {
            // platform and mono
            int p = (int)Environment.OSVersion.Platform;

            if (p == 4 | p == 128)
            {
                // general Unix
                CurrentPlatform = Platform.Linux;
            }
            else if (p == 6)
            {
                // Mac
                CurrentPlatform = Platform.Mac;
            }
            else
            {
                // non-Unix
                CurrentPlatform = Platform.Windows;
            }
            CurrentlyRunOnMono = Type.GetType("Mono.Runtime") != null;
            // file system
            FileSystem = FileSystem.FromCommandLineArgs(args);
            FileSystem.CreateFileSystem();
            SetPackageLookupDirectories();
            // command line arguments
            bool[] SkipArgs = new bool[args.Length];
            if (args.Length != 0)
            {
                string File = System.IO.Path.Combine(Application.StartupPath, "RouteViewer.exe");
                if (System.IO.File.Exists(File))
                {
                    int Skips = 0;
                    System.Text.StringBuilder NewArgs = new System.Text.StringBuilder();
                    for (int i = 0; i < args.Length; i++)
                    {
                        if (System.IO.File.Exists(args[i]))
                        {
                            if (System.IO.Path.GetExtension(args[i]).Equals(".csv", StringComparison.OrdinalIgnoreCase))
                            {
                                string Text = System.IO.File.ReadAllText(args[i], System.Text.Encoding.UTF8);
                                if (Text.Length != -1 && Text.IndexOf("CreateMeshBuilder", StringComparison.OrdinalIgnoreCase) == -1)
                                {
                                    if (NewArgs.Length != 0)
                                    {
                                        NewArgs.Append(" ");
                                    }
                                    NewArgs.Append("\"" + args[i] + "\"");
                                    SkipArgs[i] = true;
                                    Skips++;
                                }
                            }
                        }
                        else
                        {
                            SkipArgs[i] = true;
                            Skips++;
                        }
                    }
                    if (NewArgs.Length != 0)
                    {
                        System.Diagnostics.Process.Start(File, NewArgs.ToString());
                    }
                    if (Skips == args.Length)
                    {
                        return;
                    }
                }
            }
            // application
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            if (SDL.SDL_Init(SDL.SDL_INIT_VIDEO) != 0)
            {
                MessageBox.Show("SDL failed to initialize the video subsystem.", Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Hand);
                return;
            }
            Interface.CurrentOptions.ObjectOptimizationBasicThreshold = 1000;
            Interface.CurrentOptions.ObjectOptimizationFullThreshold  = 250;
            // initialize sdl window
            SDL.SDL_GL_SetAttribute(SDL.SDL_GLattr.SDL_GL_DOUBLEBUFFER, 1);
            SDL.SDL_GL_SetAttribute(SDL.SDL_GLattr.SDL_GL_DEPTH_SIZE, 16);
            SDL.SDL_GL_SetAttribute(SDL.SDL_GLattr.SDL_GL_RED_SIZE, 8);
            SDL.SDL_GL_SetAttribute(SDL.SDL_GLattr.SDL_GL_GREEN_SIZE, 8);
            SDL.SDL_GL_SetAttribute(SDL.SDL_GLattr.SDL_GL_BLUE_SIZE, 8);
            SDL.SDL_GL_SetAttribute(SDL.SDL_GLattr.SDL_GL_ALPHA_SIZE, 8);
            SDL.SDL_ShowCursor(1);
            // initialize camera
            ResetCamera();
            // create window
            Renderer.ScreenWidth  = 960;
            Renderer.ScreenHeight = 600;
            // int Bits = 32;
            //Sdl.SDL_SetVideoMode(Renderer.ScreenWidth, Renderer.ScreenHeight, Bits, Sdl.SDL_OPENGL | Sdl.SDL_DOUBLEBUF);
            SDLWindow = SDL.SDL_CreateWindow(Application.ProductName,
                                             SDL.SDL_WINDOWPOS_UNDEFINED, SDL.SDL_WINDOWPOS_UNDEFINED,
                                             Renderer.ScreenWidth, Renderer.ScreenHeight,
                                             SDL.SDL_WindowFlags.SDL_WINDOW_OPENGL | SDL.SDL_WindowFlags.SDL_WINDOW_RESIZABLE);
            if (SDLWindow != IntPtr.Zero)
            {
                // create window
                string File = OpenBveApi.Path.CombineFile(Program.FileSystem.GetDataFolder(), "icon.png");
                if (System.IO.File.Exists(File))
                {
                    // set up icon
                    iconBmp  = new Bitmap(File);                    // load file
                    iconData = iconBmp.LockBits(new Rectangle(0, 0, iconBmp.Width, iconBmp.Height),
                                                System.Drawing.Imaging.ImageLockMode.ReadOnly,
                                                System.Drawing.Imaging.PixelFormat.Format32bppArgb);            // lock data
                    iconSurface = SDL.SDL_CreateRGBSurfaceFrom(iconData.Scan0, iconBmp.Width, iconBmp.Height, 32, iconData.Stride,
                                                               0x00FF0000, 0x0000FF00, 0x000000FF, 0xFF000000); // upload to sdl
                    SDL.SDL_SetWindowIcon(SDLWindow, iconSurface);                                              // use icon
                    // free is on the end of the program

                    /*
                     * IntPtr bitmap = SDL.SDL_LoadBMP(File);
                     * if (bitmap != IntPtr.Zero) {
                     *      SDL.SDL_Surface Surface = (SDL.SDL_Surface)System.Runtime.InteropServices.Marshal.PtrToStructure(bitmap, typeof(SDL.SDL_Surface));
                     *      uint ColorKey = SDL.SDL_MapRGB(Surface.format, 0, 0, 255);
                     *      SDL.SDL_SetColorKey(bitmap, 1, ColorKey);
                     *      SDL.SDL_SetWindowIcon(SDLWindow,bitmap);
                     * }
                     */
                }
                GLContext = SDL.SDL_GL_CreateContext(SDLWindow);
                tkContext = new GraphicsContext(new ContextHandle(GLContext),
                                                SDL.SDL_GL_GetProcAddress,
                                                () => new ContextHandle(SDL.SDL_GL_GetCurrentContext()));
                // anisotropic filtering
                string[] extensions = GL.GetString(StringName.Extensions).Split(new [] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
                Interface.CurrentOptions.AnisotropicFilteringMaximum = 0;
                for (int i = 0; i < extensions.Length; i++)
                {
                    if (extensions[i] == "GL_EXT_texture_filter_anisotropic")
                    {
                        float n;
                        GL.GetFloat((GetPName)ExtTextureFilterAnisotropic.MaxTextureMaxAnisotropyExt, out n);
                        Interface.CurrentOptions.AnisotropicFilteringMaximum = (int)Math.Round((double)n);
                        break;
                    }
                }
                if (Interface.CurrentOptions.AnisotropicFilteringMaximum <= 0)
                {
                    Interface.CurrentOptions.AnisotropicFilteringMaximum = 0;
                    Interface.CurrentOptions.AnisotropicFilteringLevel   = 0;
                    Interface.CurrentOptions.Interpolation = TextureManager.InterpolationMode.AnisotropicFiltering;
                }
                else
                {
                    Interface.CurrentOptions.AnisotropicFilteringLevel = Interface.CurrentOptions.AnisotropicFilteringMaximum;
                    Interface.CurrentOptions.Interpolation             = TextureManager.InterpolationMode.TrilinearMipmapped;
                }
                // module initialization
                Renderer.Initialize();
                Renderer.InitializeLighting();
                SDL.SDL_GL_SwapWindow(SDLWindow);
                Fonts.Initialize();
                UpdateViewport();
                // command line arguments
                for (int i = 0; i < args.Length; i++)
                {
                    if (!SkipArgs[i] && System.IO.File.Exists(args[i]))
                    {
                        try {
                            ObjectManager.UnifiedObject o = ObjectManager.LoadObject(args[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);
                        } catch (Exception ex) {
                            Interface.AddMessage(Interface.MessageType.Critical, false, "Unhandled error (" + ex.Message + ") encountered while processing the file " + args[i] + ".");
                        }
                        Array.Resize <string>(ref Files, Files.Length + 1);
                        Files[Files.Length - 1] = args[i];
                    }
                }
                ObjectManager.InitializeVisibility();
                ObjectManager.FinishCreatingObjects();
                ObjectManager.UpdateVisibility(0.0, true);
                ObjectManager.UpdateAnimatedWorldObjects(0.01, true);
                UpdateCaption();
                Stopwatch timer = new Stopwatch();
                timer.Start();
                LastTicks = timer.ElapsedMilliseconds;
                // loop
                while (!Quit)
                {
                    long   ticks       = timer.ElapsedMilliseconds;
                    double timeElapsed = 0.001 * (double)(ticks - LastTicks);
                    if (timeElapsed < 0.0001)
                    {
                        timeElapsed = 0.0001;
                    }
                    LastTicks = ticks;
                    DateTime time = DateTime.Now;
                    Game.SecondsSinceMidnight = (double)(3600 * time.Hour + 60 * time.Minute + time.Second) + 0.001 * (double)time.Millisecond;
                    ObjectManager.UpdateAnimatedWorldObjects(timeElapsed, false);
                    ProcessEvents();
                    if (ReducedMode)
                    {
                        System.Threading.Thread.Sleep(125);
                    }
                    else
                    {
                        System.Threading.Thread.Sleep(1);
                    }
                    bool updatelight = false;
                    bool keep        = false;
                    // rotate x
                    if (RotateX == 0)
                    {
                        double d = (1.0 + Math.Abs(RotateXSpeed)) * timeElapsed;
                        if (RotateXSpeed >= -d & RotateXSpeed <= d)
                        {
                            RotateXSpeed = 0.0;
                        }
                        else
                        {
                            RotateXSpeed -= (double)Math.Sign(RotateXSpeed) * d;
                        }
                    }
                    else
                    {
                        double d = (1.0 + 1.0 - 1.0 / (1.0 + RotateXSpeed * RotateXSpeed)) * timeElapsed;
                        double m = 1.0;
                        RotateXSpeed += (double)RotateX * d;
                        if (RotateXSpeed < -m)
                        {
                            RotateXSpeed = -m;
                        }
                        else if (RotateXSpeed > m)
                        {
                            RotateXSpeed = m;
                        }
                    }
                    if (RotateXSpeed != 0.0)
                    {
                        double cosa = Math.Cos(RotateXSpeed * timeElapsed);
                        double sina = Math.Sin(RotateXSpeed * timeElapsed);
                        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);
                        keep = true;
                    }
                    // rotate y
                    if (RotateY == 0)
                    {
                        double d = (1.0 + Math.Abs(RotateYSpeed)) * timeElapsed;
                        if (RotateYSpeed >= -d & RotateYSpeed <= d)
                        {
                            RotateYSpeed = 0.0;
                        }
                        else
                        {
                            RotateYSpeed -= (double)Math.Sign(RotateYSpeed) * d;
                        }
                    }
                    else
                    {
                        double d = (1.0 + 1.0 - 1.0 / (1.0 + RotateYSpeed * RotateYSpeed)) * timeElapsed;
                        double m = 1.0;
                        RotateYSpeed += (double)RotateY * d;
                        if (RotateYSpeed < -m)
                        {
                            RotateYSpeed = -m;
                        }
                        else if (RotateYSpeed > m)
                        {
                            RotateYSpeed = m;
                        }
                    }
                    if (RotateYSpeed != 0.0)
                    {
                        double cosa = Math.Cos(RotateYSpeed * timeElapsed);
                        double sina = Math.Sin(RotateYSpeed * timeElapsed);
                        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);
                        keep = true;
                    }
                    // move x
                    if (MoveX == 0)
                    {
                        double d = (2.5 + Math.Abs(MoveXSpeed)) * timeElapsed;
                        if (MoveXSpeed >= -d & MoveXSpeed <= d)
                        {
                            MoveXSpeed = 0.0;
                        }
                        else
                        {
                            MoveXSpeed -= (double)Math.Sign(MoveXSpeed) * d;
                        }
                    }
                    else
                    {
                        double d = (5.0 + 10.0 - 10.0 / (1.0 + MoveXSpeed * MoveXSpeed)) * timeElapsed;
                        double m = 25.0;
                        MoveXSpeed += (double)MoveX * d;
                        if (MoveXSpeed < -m)
                        {
                            MoveXSpeed = -m;
                        }
                        else if (MoveXSpeed > m)
                        {
                            MoveXSpeed = m;
                        }
                    }
                    if (MoveXSpeed != 0.0)
                    {
                        World.AbsoluteCameraPosition.X += MoveXSpeed * timeElapsed * World.AbsoluteCameraSide.X;
                        World.AbsoluteCameraPosition.Y += MoveXSpeed * timeElapsed * World.AbsoluteCameraSide.Y;
                        World.AbsoluteCameraPosition.Z += MoveXSpeed * timeElapsed * World.AbsoluteCameraSide.Z;
                        keep = true;
                    }
                    // move y
                    if (MoveY == 0)
                    {
                        double d = (2.5 + Math.Abs(MoveYSpeed)) * timeElapsed;
                        if (MoveYSpeed >= -d & MoveYSpeed <= d)
                        {
                            MoveYSpeed = 0.0;
                        }
                        else
                        {
                            MoveYSpeed -= (double)Math.Sign(MoveYSpeed) * d;
                        }
                    }
                    else
                    {
                        double d = (5.0 + 10.0 - 10.0 / (1.0 + MoveYSpeed * MoveYSpeed)) * timeElapsed;
                        double m = 25.0;
                        MoveYSpeed += (double)MoveY * d;
                        if (MoveYSpeed < -m)
                        {
                            MoveYSpeed = -m;
                        }
                        else if (MoveYSpeed > m)
                        {
                            MoveYSpeed = m;
                        }
                    }
                    if (MoveYSpeed != 0.0)
                    {
                        World.AbsoluteCameraPosition.X += MoveYSpeed * timeElapsed * World.AbsoluteCameraUp.X;
                        World.AbsoluteCameraPosition.Y += MoveYSpeed * timeElapsed * World.AbsoluteCameraUp.Y;
                        World.AbsoluteCameraPosition.Z += MoveYSpeed * timeElapsed * World.AbsoluteCameraUp.Z;
                        keep = true;
                    }
                    // move z
                    if (MoveZ == 0)
                    {
                        double d = (2.5 + Math.Abs(MoveZSpeed)) * timeElapsed;
                        if (MoveZSpeed >= -d & MoveZSpeed <= d)
                        {
                            MoveZSpeed = 0.0;
                        }
                        else
                        {
                            MoveZSpeed -= (double)Math.Sign(MoveZSpeed) * d;
                        }
                    }
                    else
                    {
                        double d = (5.0 + 10.0 - 10.0 / (1.0 + MoveZSpeed * MoveZSpeed)) * timeElapsed;
                        double m = 25.0;
                        MoveZSpeed += (double)MoveZ * d;
                        if (MoveZSpeed < -m)
                        {
                            MoveZSpeed = -m;
                        }
                        else if (MoveZSpeed > m)
                        {
                            MoveZSpeed = m;
                        }
                    }
                    if (MoveZSpeed != 0.0)
                    {
                        World.AbsoluteCameraPosition.X += MoveZSpeed * timeElapsed * World.AbsoluteCameraDirection.X;
                        World.AbsoluteCameraPosition.Y += MoveZSpeed * timeElapsed * World.AbsoluteCameraDirection.Y;
                        World.AbsoluteCameraPosition.Z += MoveZSpeed * timeElapsed * World.AbsoluteCameraDirection.Z;
                        keep = true;
                    }
                    // lighting
                    if (LightingRelative == -1)
                    {
                        LightingRelative = (double)LightingTarget;
                        updatelight      = true;
                    }
                    if (LightingTarget == 0)
                    {
                        if (LightingRelative != 0.0)
                        {
                            LightingRelative -= 0.5 * timeElapsed;
                            if (LightingRelative < 0.0)
                            {
                                LightingRelative = 0.0;
                            }
                            updatelight = true;
                            keep        = true;
                        }
                    }
                    else
                    {
                        if (LightingRelative != 1.0)
                        {
                            LightingRelative += 0.5 * timeElapsed;
                            if (LightingRelative > 1.0)
                            {
                                LightingRelative = 1.0;
                            }
                            updatelight = true;
                            keep        = true;
                        }
                    }
                    // continue
                    if (ReducedMode)
                    {
                        ReducedModeEnteringTime = (int)(ticks + 3000);
                    }
                    else
                    {
                        if (keep)
                        {
                            ReducedModeEnteringTime = (int)(ticks + 3000);
                        }
                        else if (ticks > ReducedModeEnteringTime)
                        {
                            ReducedMode = true;
                            World.AbsoluteCameraSide.Y = 0.0;
                            World.Normalize(ref World.AbsoluteCameraSide.X, ref World.AbsoluteCameraSide.Y, ref World.AbsoluteCameraSide.Z);
                            World.Normalize(ref World.AbsoluteCameraDirection.X, ref World.AbsoluteCameraDirection.Y, ref World.AbsoluteCameraDirection.Z);
                            World.AbsoluteCameraUp = World.Cross(World.AbsoluteCameraDirection, World.AbsoluteCameraSide);
                        }
                    }
                    if (updatelight)
                    {
                        Renderer.OptionAmbientColor.R = (byte)Math.Round(32.0 + 128.0 * LightingRelative * (2.0 - LightingRelative));
                        Renderer.OptionAmbientColor.G = (byte)Math.Round(32.0 + 128.0 * 0.5 * (LightingRelative + LightingRelative * (2.0 - LightingRelative)));
                        Renderer.OptionAmbientColor.B = (byte)Math.Round(32.0 + 128.0 * LightingRelative);
                        Renderer.OptionDiffuseColor.R = (byte)Math.Round(32.0 + 128.0 * LightingRelative);
                        Renderer.OptionDiffuseColor.G = (byte)Math.Round(32.0 + 128.0 * LightingRelative);
                        Renderer.OptionDiffuseColor.B = (byte)Math.Round(32.0 + 128.0 * Math.Sqrt(LightingRelative));
                        Renderer.InitializeLighting();
                    }
                    Renderer.RenderScene();
                    SDL.SDL_GL_SwapWindow(SDLWindow);
                }
                // quit
                TextureManager.UnuseAllTextures();
                if (iconSurface != IntPtr.Zero)
                {
                    SDL.SDL_FreeSurface(iconSurface);                     // free surface
                }
                if (iconBmp != null && iconData != null)
                {
                    iconBmp.UnlockBits(iconData);                     // free pixels
                    iconBmp.Dispose();
                }
                SDL.SDL_GL_DeleteContext(GLContext);
                SDL.SDL_DestroyWindow(SDLWindow);
                SDL.SDL_Quit();
            }
            else
            {
                MessageBox.Show("SDL failed to create the window.", Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Hand);
            }
        }
Exemple #7
0
            internal void UpdateTopplingCantAndSpring()
            {
                if (CarSections.Length != 0)
                {
                    //FRONT BOGIE

                    // get direction, up and side vectors
                    double dx, dy, dz;
                    double ux, uy, uz;
                    double sx, sy, sz;
                    {
                        dx = FrontAxle.Follower.WorldPosition.X -
                             RearAxle.Follower.WorldPosition.X;
                        dy = FrontAxle.Follower.WorldPosition.Y -
                             RearAxle.Follower.WorldPosition.Y;
                        dz = FrontAxle.Follower.WorldPosition.Z -
                             RearAxle.Follower.WorldPosition.Z;
                        double t = 1.0 / Math.Sqrt(dx * dx + dy * dy + dz * dz);
                        dx *= t;
                        dy *= t;
                        dz *= t;
                        t   = 1.0 / Math.Sqrt(dx * dx + dz * dz);
                        double ex = dx * t;
                        double ez = dz * t;
                        sx = ez;
                        sy = 0.0;
                        sz = -ex;
                        World.Cross(dx, dy, dz, sx, sy, sz, out ux, out uy, out uz);
                    }
                    // cant and radius

                    //TODO: This currently uses the figures from the base car
                    // apply position due to cant/toppling
                    {
                        double a = baseCar.Specs.CurrentRollDueToTopplingAngle +
                                   baseCar.Specs.CurrentRollDueToCantAngle;
                        double x  = Math.Sign(a) * 0.5 * Game.RouteRailGauge * (1.0 - Math.Cos(a));
                        double y  = Math.Abs(0.5 * Game.RouteRailGauge * Math.Sin(a));
                        double cx = sx * x + ux * y;
                        double cy = sy * x + uy * y;
                        double cz = sz * x + uz * y;
                        FrontAxle.Follower.WorldPosition.X += cx;
                        FrontAxle.Follower.WorldPosition.Y += cy;
                        FrontAxle.Follower.WorldPosition.Z += cz;
                        RearAxle.Follower.WorldPosition.X  += cx;
                        RearAxle.Follower.WorldPosition.Y  += cy;
                        RearAxle.Follower.WorldPosition.Z  += cz;
                    }
                    // apply rolling
                    {
                        double a = -baseCar.Specs.CurrentRollDueToTopplingAngle -
                                   baseCar.Specs.CurrentRollDueToCantAngle;
                        double cosa = Math.Cos(a);
                        double sina = Math.Sin(a);
                        World.Rotate(ref sx, ref sy, ref sz, dx, dy, dz, cosa, sina);
                        World.Rotate(ref ux, ref uy, ref uz, dx, dy, dz, cosa, sina);
                        Up.X = ux;
                        Up.Y = uy;
                        Up.Z = uz;
                    }
                    // apply pitching
                    if (CurrentCarSection >= 0 &&
                        CarSections[CurrentCarSection].Overlay)
                    {
                        double a    = baseCar.Specs.CurrentPitchDueToAccelerationAngle;
                        double cosa = Math.Cos(a);
                        double sina = Math.Sin(a);
                        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);
                        double cx = 0.5 *
                                    (FrontAxle.Follower.WorldPosition.X +
                                     RearAxle.Follower.WorldPosition.X);
                        double cy = 0.5 *
                                    (FrontAxle.Follower.WorldPosition.Y +
                                     RearAxle.Follower.WorldPosition.Y);
                        double cz = 0.5 *
                                    (FrontAxle.Follower.WorldPosition.Z +
                                     RearAxle.Follower.WorldPosition.Z);
                        FrontAxle.Follower.WorldPosition.X -= cx;
                        FrontAxle.Follower.WorldPosition.Y -= cy;
                        FrontAxle.Follower.WorldPosition.Z -= cz;
                        RearAxle.Follower.WorldPosition.X  -= cx;
                        RearAxle.Follower.WorldPosition.Y  -= cy;
                        RearAxle.Follower.WorldPosition.Z  -= cz;
                        World.Rotate(ref FrontAxle.Follower.WorldPosition, sx, sy, sz, cosa, sina);
                        World.Rotate(ref RearAxle.Follower.WorldPosition, sx, sy, sz, cosa, sina);
                        FrontAxle.Follower.WorldPosition.X += cx;
                        FrontAxle.Follower.WorldPosition.Y += cy;
                        FrontAxle.Follower.WorldPosition.Z += cz;
                        RearAxle.Follower.WorldPosition.X  += cx;
                        RearAxle.Follower.WorldPosition.Y  += cy;
                        RearAxle.Follower.WorldPosition.Z  += cz;
                        Up.X = ux;
                        Up.Y = uy;
                        Up.Z = uz;
                    }
                }
            }
        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;
        }