internal static void CreateObject(UnifiedObject Prototype, Vector3 Position, World.Transformation BaseTransformation, World.Transformation AuxTransformation, int SectionIndex, bool AccurateObjectDisposal, double StartingDistance, double EndingDistance, double BlockLength, double TrackPosition, double Brightness, bool DuplicateMaterials) { if (Prototype is StaticObject) { StaticObject s = (StaticObject)Prototype; CreateStaticObject(s, Position, BaseTransformation, AuxTransformation, AccurateObjectDisposal, 0.0, StartingDistance, EndingDistance, BlockLength, TrackPosition, Brightness, DuplicateMaterials); } else if (Prototype is AnimatedObjectCollection) { AnimatedObjectCollection a = (AnimatedObjectCollection)Prototype; CreateAnimatedWorldObjects(a.Objects, Position, BaseTransformation, AuxTransformation, SectionIndex, AccurateObjectDisposal, StartingDistance, EndingDistance, BlockLength, TrackPosition, Brightness, DuplicateMaterials); } }
internal static int CreateStaticObject(StaticObject Prototype, Vector3 Position, World.Transformation BaseTransformation, World.Transformation AuxTransformation, bool AccurateObjectDisposal, double AccurateObjectDisposalZOffset, double StartingDistance, double EndingDistance, double BlockLength, double TrackPosition, double Brightness, bool DuplicateMaterials) { int a = ObjectsUsed; if (a >= Objects.Length) { Array.Resize<StaticObject>(ref Objects, Objects.Length << 1); } ApplyStaticObjectData(ref Objects[a], Prototype, Position, BaseTransformation, AuxTransformation, AccurateObjectDisposal, AccurateObjectDisposalZOffset, StartingDistance, EndingDistance, BlockLength, TrackPosition, Brightness, DuplicateMaterials); for (int i = 0; i < Prototype.Mesh.Faces.Length; i++) { switch (Prototype.Mesh.Faces[i].Flags & World.MeshFace.FaceTypeMask) { case World.MeshFace.FaceTypeTriangles: Game.InfoTotalTriangles++; break; case World.MeshFace.FaceTypeTriangleStrip: Game.InfoTotalTriangleStrip++; break; case World.MeshFace.FaceTypeQuads: Game.InfoTotalQuads++; break; case World.MeshFace.FaceTypeQuadStrip: Game.InfoTotalQuadStrip++; break; case World.MeshFace.FaceTypePolygon: Game.InfoTotalPolygon++; break; } } ObjectsUsed++; return a; }
// load texture rgba private static void LoadTextureRGBAforData(Bitmap Bitmap, World.ColorRGB TransparentColor, byte TransparentColorUsed, int TextureIndex) { try { // load bytes int Width, Height, Stride; byte[] Data; { if (Textures[TextureIndex].ClipWidth == 0) Textures[TextureIndex].ClipWidth = Bitmap.Width; if (Textures[TextureIndex].ClipHeight == 0) Textures[TextureIndex].ClipHeight = Bitmap.Height; Width = Textures[TextureIndex].ClipWidth; Height = Textures[TextureIndex].ClipHeight; Bitmap c = new Bitmap(Width, Height, GDIPixelFormat.Format32bppArgb); Graphics g = Graphics.FromImage(c); Rectangle dst = new Rectangle(0, 0, Width, Height); Rectangle src = new Rectangle(Textures[TextureIndex].ClipLeft, Textures[TextureIndex].ClipTop, Textures[TextureIndex].ClipWidth, Textures[TextureIndex].ClipHeight); g.DrawImage(Bitmap, dst, src, GraphicsUnit.Pixel); g.Dispose(); BitmapData d = c.LockBits(new Rectangle(0, 0, Width, Height), ImageLockMode.ReadOnly, c.PixelFormat); Stride = d.Stride; Data = new byte[Stride * Height]; System.Runtime.InteropServices.Marshal.Copy(d.Scan0, Data, 0, Stride * Height); c.UnlockBits(d); c.Dispose(); } // load mode if (Textures[TextureIndex].LoadMode == TextureLoadMode.Bve4SignalGlow) { // bve 4 signal glow int p = 0, pn = Stride - 4 * Width; byte tr, tg, tb; if (TransparentColorUsed != 0) { tr = TransparentColor.R; tg = TransparentColor.G; tb = TransparentColor.B; } else { tr = 0; tg = 0; tb = 0; } // invert lightness byte[] Temp = new byte[Stride * Height]; for (int y = 0; y < Height; y++) { for (int x = 0; x < Width; x++) { if (Data[p] == tb & Data[p + 1] == tg & Data[p + 2] == tr) { Temp[p] = 0; Temp[p + 1] = 0; Temp[p + 2] = 0; } else if (Data[p] != 255 | Data[p + 1] != 255 | Data[p + 2] != 255) { int b = Data[p], g = Data[p + 1], r = Data[p + 2]; InvertLightness(ref r, ref g, ref b); int l = r >= g & r >= b ? r : g >= b ? g : b; Temp[p] = (byte)(l * b / 255); Temp[p + 1] = (byte)(l * g / 255); Temp[p + 2] = (byte)(l * r / 255); } else { Temp[p] = Data[p]; Temp[p + 1] = Data[p + 1]; Temp[p + 2] = Data[p + 2]; } p += 4; } p += pn; } p = 0; // blur the image and multiply by lightness int s = 4; int n = Stride - (2 * s + 1 << 2); for (int y = 0; y < Height; y++) { for (int x = 0; x < Width; x++) { int q = p - s * (Stride + 4); int r = 0, g = 0, b = 0, c = 0; for (int yr = y - s; yr <= y + s; yr++) { if (yr >= 0 & yr < Height) { for (int xr = x - s; xr <= x + s; xr++) { if (xr >= 0 & xr < Width) { b += (int)Temp[q]; g += (int)Temp[q + 1]; r += (int)Temp[q + 2]; c++; } q += 4; } q += n; } else q += Stride; } if (c == 0) { Data[p] = 0; Data[p + 1] = 0; Data[p + 2] = 0; Data[p + 3] = 255; } else { r /= c; g /= c; b /= c; int l = r >= g & r >= b ? r : g >= b ? g : b; Data[p] = (byte)(l * b / 255); Data[p + 1] = (byte)(l * g / 255); Data[p + 2] = (byte)(l * r / 255); Data[p + 3] = 255; } p += 4; } p += pn; } Textures[TextureIndex].Transparency = TextureTransparencyMode.None; Textures[TextureIndex].DontAllowUnload = true; } else if (TransparentColorUsed != 0) { // transparent color int p = 0, pn = Stride - 4 * Width; byte tr = TransparentColor.R; byte tg = TransparentColor.G; byte tb = TransparentColor.B; bool used = false; // check if alpha is actually used int y; for (y = 0; y < Height; y++) { int x; for (x = 0; x < Width; x++) { if (Data[p + 3] != 255) { break; } p += 4; } if (x < Width) break; p += pn; } if (y == Height) { Textures[TextureIndex].Transparency = TextureTransparencyMode.TransparentColor; } // duplicate color data from adjacent pixels p = 0; pn = Stride - 4 * Width; for (y = 0; y < Height; y++) { for (int x = 0; x < Width; x++) { if (Data[p] == tb & Data[p + 1] == tg & Data[p + 2] == tr) { used = true; if (x == 0) { int q = p; int v; for (v = y; v < Height; v++) { int u; for (u = v == y ? x + 1 : 0; u < Width; u++) { if (Data[q] != tb | Data[q + 1] != tg | Data[q + 2] != tr) { Data[p] = Data[q]; Data[p + 1] = Data[q + 1]; Data[p + 2] = Data[q + 2]; Data[p + 3] = 0; break; } q += 4; } if (u < Width) { break; } else q += pn; } if (v == Height) { if (y == 0) { Data[p] = 128; Data[p + 1] = 128; Data[p + 2] = 128; Data[p + 3] = 0; } else { Data[p] = Data[p - Stride]; Data[p + 1] = Data[p - Stride + 1]; Data[p + 2] = Data[p - Stride + 2]; Data[p + 3] = 0; } } } else { Data[p] = Data[p - 4]; Data[p + 1] = Data[p - 3]; Data[p + 2] = Data[p - 2]; Data[p + 3] = 0; } } p += 4; } p += pn; } // transparent color is not actually used if (!used & Textures[TextureIndex].Transparency == TextureTransparencyMode.TransparentColor) { Textures[TextureIndex].Transparency = TextureTransparencyMode.None; } } else if (Textures[TextureIndex].Transparency == TextureTransparencyMode.Alpha) { // check if alpha is actually used int p = 0, pn = Stride - 4 * Width; int y; for (y = 0; y < Height; y++) { int x; for (x = 0; x < Width; x++) { if (Data[p + 3] != 255) { break; } p += 4; } if (x < Width) break; p += pn; } if (y == Height) { Textures[TextureIndex].Transparency = TextureTransparencyMode.None; } } // non-power of two int TargetWidth = Interface.RoundToPowerOfTwo(Width); int TargetHeight = Interface.RoundToPowerOfTwo(Height); if (TargetWidth != Width | TargetHeight != Height) { Bitmap b = new Bitmap(Width, Height, GDIPixelFormat.Format32bppArgb); BitmapData d = b.LockBits(new Rectangle(0, 0, Width, Height), ImageLockMode.WriteOnly, b.PixelFormat); System.Runtime.InteropServices.Marshal.Copy(Data, 0, d.Scan0, d.Stride * d.Height); b.UnlockBits(d); Bitmap c = new Bitmap(TargetWidth, TargetHeight, GDIPixelFormat.Format32bppArgb); Graphics g = Graphics.FromImage(c); g.DrawImage(b, 0, 0, TargetWidth, TargetHeight); g.Dispose(); b.Dispose(); d = c.LockBits(new Rectangle(0, 0, TargetWidth, TargetHeight), ImageLockMode.ReadOnly, c.PixelFormat); Stride = d.Stride; Data = new byte[Stride * TargetHeight]; System.Runtime.InteropServices.Marshal.Copy(d.Scan0, Data, 0, Stride * TargetHeight); c.UnlockBits(d); c.Dispose(); } Textures[TextureIndex].Width = TargetWidth; Textures[TextureIndex].Height = TargetHeight; Textures[TextureIndex].Data = Data; } catch (Exception ex) { Interface.AddMessage(Interface.MessageType.Error, false, "Internal error in TextureManager.cs::LoadTextureRGBAForData: " + ex.Message); throw; } }
internal static void CreateAnimatedWorldObjects(AnimatedObject[] Prototypes, Vector3 Position, World.Transformation BaseTransformation, World.Transformation AuxTransformation, int SectionIndex, bool AccurateObjectDisposal, double StartingDistance, double EndingDistance, double BlockLength, double TrackPosition, double Brightness, bool DuplicateMaterials) { bool[] free = new bool[Prototypes.Length]; bool anyfree = false; for (int i = 0; i < Prototypes.Length; i++) { free[i] = Prototypes[i].IsFreeOfFunctions(); if (free[i]) anyfree = true; } if (anyfree) { for (int i = 0; i < Prototypes.Length; i++) { if (Prototypes[i].States.Length != 0) { if (free[i]) { Vector3 p = Position; World.Transformation t = new OpenBve.World.Transformation(BaseTransformation, AuxTransformation); Vector3 s = t.X; Vector3 u = t.Y; Vector3 d = t.Z; p.X += Prototypes[i].States[0].Position.X * s.X + Prototypes[i].States[0].Position.Y * u.X + Prototypes[i].States[0].Position.Z * d.X; p.Y += Prototypes[i].States[0].Position.X * s.Y + Prototypes[i].States[0].Position.Y * u.Y + Prototypes[i].States[0].Position.Z * d.Y; p.Z += Prototypes[i].States[0].Position.X * s.Z + Prototypes[i].States[0].Position.Y * u.Z + Prototypes[i].States[0].Position.Z * d.Z; double zOffset = Prototypes[i].States[0].Position.Z; CreateStaticObject(Prototypes[i].States[0].Object, p, BaseTransformation, AuxTransformation, AccurateObjectDisposal, zOffset, StartingDistance, EndingDistance, BlockLength, TrackPosition, Brightness, DuplicateMaterials); } else { CreateAnimatedWorldObject(Prototypes[i], Position, BaseTransformation, AuxTransformation, SectionIndex, TrackPosition, Brightness); } } } } else { for (int i = 0; i < Prototypes.Length; i++) { if (Prototypes[i].States.Length != 0) { CreateAnimatedWorldObject(Prototypes[i], Position, BaseTransformation, AuxTransformation, SectionIndex, TrackPosition, Brightness); } } } }
internal static int RegisterTexture(string FileName, World.ColorRGB TransparentColor, byte TransparentColorUsed, TextureWrapMode WrapModeX, TextureWrapMode WrapModeY, bool DontAllowUnload) { return RegisterTexture(FileName, TransparentColor, TransparentColorUsed, TextureLoadMode.Normal, WrapModeX, WrapModeY, DontAllowUnload, 0, 0, 0, 0); }
internal static int RegisterTexture(Bitmap Bitmap, World.ColorRGB TransparentColor) { int i = GetFreeTexture(); int[] a = new int[1]; GL.GenTextures(1, a); Textures[i] = new Texture { Queried = false, OpenGlTextureIndex = a[0], Transparency = TextureTransparencyMode.TransparentColor, TransparentColor = TransparentColor, TransparentColorUsed = 1, FileName = null, Loaded = true, Width = Bitmap.Width, Height = Bitmap.Height, DontAllowUnload = true }; LoadTextureRGBAforData(Bitmap, Textures[i].TransparentColor, Textures[i].TransparentColorUsed, i); LoadTextureRGBAforOpenGl(i); return i; }
internal static bool TryParseHexColor(string Expression, out World.ColorRGBA Color) { if (Expression.StartsWith("#")) { string a = Expression.Substring(1).TrimStart(); int x; if (int.TryParse(a, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out x)) { int r = (x >> 16) & 0xFF; int g = (x >> 8) & 0xFF; int b = x & 0xFF; if (r >= 0 & r <= 255 & g >= 0 & g <= 255 & b >= 0 & b <= 255) { Color = new World.ColorRGBA((byte)r, (byte)g, (byte)b, 255); return true; } else { Color = new World.ColorRGBA(0, 0, 255, 255); return false; } } else { Color = new World.ColorRGBA(0, 0, 255, 255); return false; } } else { Color = new World.ColorRGBA(0, 0, 255, 255); return false; } }
internal static void UpdateAnimatedObject(ref AnimatedObject Object, TrainManager.Train Train, int SectionIndex, double TrackPosition, World.Vector3D Position, World.Vector3D Direction, World.Vector3D Up, World.Vector3D Side, bool Overlay, bool UpdateFunctions, bool Show, double TimeElapsed) { int s = Object.CurrentState; int i = Object.ObjectIndex; // state change if (Object.StateFunction != null & UpdateFunctions) { double sd = Object.StateFunction.Perform(Train, Position, TrackPosition, SectionIndex, TimeElapsed); int si = (int)Math.Round(sd); int sn = Object.States.Length; if (si < 0 | si >= sn) si = -1; if (s != si) { InitializeAnimatedObject(ref Object, si, Overlay, Show); s = si; } } if (s == -1) return; // translation if (Object.TranslateXFunction != null) { double x; if (UpdateFunctions) { x = Object.TranslateXFunction.Perform(Train, Position, TrackPosition, SectionIndex, TimeElapsed); } else { x = Object.TranslateXFunction.LastResult; } double rx = Object.TranslateXDirection.X, ry = Object.TranslateXDirection.Y, rz = Object.TranslateXDirection.Z; World.Rotate(ref rx, ref ry, ref rz, Direction.X, Direction.Y, Direction.Z, Up.X, Up.Y, Up.Z, Side.X, Side.Y, Side.Z); Position.X += x * rx; Position.Y += x * ry; Position.Z += x * rz; } if (Object.TranslateYFunction != null) { double y; if (UpdateFunctions) { y = Object.TranslateYFunction.Perform(Train, Position, TrackPosition, SectionIndex, TimeElapsed); } else { y = Object.TranslateYFunction.LastResult; } double rx = Object.TranslateYDirection.X, ry = Object.TranslateYDirection.Y, rz = Object.TranslateYDirection.Z; World.Rotate(ref rx, ref ry, ref rz, Direction.X, Direction.Y, Direction.Z, Up.X, Up.Y, Up.Z, Side.X, Side.Y, Side.Z); Position.X += y * rx; Position.Y += y * ry; Position.Z += y * rz; } if (Object.TranslateZFunction != null) { double z; if (UpdateFunctions) { z = Object.TranslateZFunction.Perform(Train, Position, TrackPosition, SectionIndex, TimeElapsed); } else { z = Object.TranslateZFunction.LastResult; } double rx = Object.TranslateZDirection.X, ry = Object.TranslateZDirection.Y, rz = Object.TranslateZDirection.Z; World.Rotate(ref rx, ref ry, ref rz, Direction.X, Direction.Y, Direction.Z, Up.X, Up.Y, Up.Z, Side.X, Side.Y, Side.Z); Position.X += z * rx; Position.Y += z * ry; Position.Z += z * rz; } // rotation bool rotateX = Object.RotateXFunction != null; bool rotateY = Object.RotateYFunction != null; bool rotateZ = Object.RotateZFunction != null; double cosX, sinX; if (rotateX) { double a; if (UpdateFunctions) { a = Object.RotateXFunction.Perform(Train, Position, TrackPosition, SectionIndex, TimeElapsed); } else { a = Object.RotateXFunction.LastResult; } ObjectManager.UpdateDamping(ref Object.RotateXDamping, TimeElapsed, ref a); cosX = Math.Cos(a); sinX = Math.Sin(a); } else { cosX = 0.0; sinX = 0.0; } double cosY, sinY; if (rotateY) { double a; if (UpdateFunctions) { a = Object.RotateYFunction.Perform(Train, Position, TrackPosition, SectionIndex, TimeElapsed); } else { a = Object.RotateYFunction.LastResult; } ObjectManager.UpdateDamping(ref Object.RotateYDamping, TimeElapsed, ref a); cosY = Math.Cos(a); sinY = Math.Sin(a); } else { cosY = 0.0; sinY = 0.0; } double cosZ, sinZ; if (rotateZ) { double a; if (UpdateFunctions) { a = Object.RotateZFunction.Perform(Train, Position, TrackPosition, SectionIndex, TimeElapsed); } else { a = Object.RotateZFunction.LastResult; } ObjectManager.UpdateDamping(ref Object.RotateZDamping, TimeElapsed, ref a); cosZ = Math.Cos(a); sinZ = Math.Sin(a); } else { cosZ = 0.0; sinZ = 0.0; } // texture shift bool shiftx = Object.TextureShiftXFunction != null; bool shifty = Object.TextureShiftYFunction != null; if ((shiftx | shifty) & UpdateFunctions) { for (int k = 0; k < ObjectManager.Objects[i].Mesh.Vertices.Length; k++) { ObjectManager.Objects[i].Mesh.Vertices[k].TextureCoordinates = Object.States[s].Object.Mesh.Vertices[k].TextureCoordinates; } if (shiftx) { double x = Object.TextureShiftXFunction.Perform(Train, Position, TrackPosition, SectionIndex, TimeElapsed); x -= Math.Floor(x); for (int k = 0; k < ObjectManager.Objects[i].Mesh.Vertices.Length; k++) { ObjectManager.Objects[i].Mesh.Vertices[k].TextureCoordinates.X += (float)(x * Object.TextureShiftXDirection.X); ObjectManager.Objects[i].Mesh.Vertices[k].TextureCoordinates.Y += (float)(x * Object.TextureShiftXDirection.Y); } } if (shifty) { double y = Object.TextureShiftYFunction.Perform(Train, Position, TrackPosition, SectionIndex, TimeElapsed); y -= Math.Floor(y); for (int k = 0; k < ObjectManager.Objects[i].Mesh.Vertices.Length; k++) { ObjectManager.Objects[i].Mesh.Vertices[k].TextureCoordinates.X += (float)(y * Object.TextureShiftYDirection.X); ObjectManager.Objects[i].Mesh.Vertices[k].TextureCoordinates.Y += (float)(y * Object.TextureShiftYDirection.Y); } } } // led bool led = Object.LEDFunction != null; double ledangle; if (led) { if (UpdateFunctions) { ledangle = Object.LEDFunction.Perform(Train, Position, TrackPosition, SectionIndex, TimeElapsed); } else { ledangle = Object.LEDFunction.LastResult; } } else { ledangle = 0.0; } // null object if (Object.States[s].Object == null) { return; } // initialize vertices for (int k = 0; k < Object.States[s].Object.Mesh.Vertices.Length; k++) { ObjectManager.Objects[i].Mesh.Vertices[k].Coordinates = Object.States[s].Object.Mesh.Vertices[k].Coordinates; } // led if (led) { double max = Object.LEDMaximumAngle; for (int j = 0; j < 5; j++) { double pos1 = 0.0; double pos2 = 1.0; switch (j) { case 0: if (ledangle <= -0.5 * Math.PI) { pos1 = 0.5; } else if (ledangle >= 0.5 * Math.PI) { pos1 = 1.0; } else { pos1 = 0.5 * Math.Tan(ledangle - 2.0 * Math.PI) + 0.5; if (pos1 < 0.5) pos1 = 0.5; else if (pos1 > 1.0) pos1 = 1.0; } if (max <= -0.5 * Math.PI) { pos2 = 0.5; } else if (max >= 0.5 * Math.PI) { pos2 = 1.0; } else { pos2 = 0.5 * Math.Tan(max - 2.0 * Math.PI) + 0.5; if (pos2 < 0.5) pos2 = 0.5; else if (pos2 > 1.0) pos2 = 1.0; } break; case 1: if (ledangle <= 0.0) { pos1 = 0.0; } else if (ledangle >= Math.PI) { pos1 = 1.0; } else { pos1 = 0.5 * Math.Tan(ledangle - 0.5 * Math.PI) + 0.5; if (pos1 < 0.0) pos1 = 0.0; else if (pos1 > 1.0) pos1 = 1.0; } if (max <= 0.0) { pos2 = 0.0; } else if (max >= Math.PI) { pos2 = 1.0; } else { pos2 = 0.5 * Math.Tan(max - 0.5 * Math.PI) + 0.5; if (pos2 < 0.0) pos2 = 0.0; else if (pos2 > 1.0) pos2 = 1.0; } break; case 2: if (ledangle <= 0.5 * Math.PI) { pos1 = 0.0; } else if (ledangle >= 1.5 * Math.PI) { pos1 = 1.0; } else { pos1 = 0.5 * Math.Tan(ledangle - Math.PI) + 0.5; if (pos1 < 0.0) pos1 = 0.0; else if (pos1 > 1.0) pos1 = 1.0; } if (max <= 0.5 * Math.PI) { pos2 = 0.0; } else if (max >= 1.5 * Math.PI) { pos2 = 1.0; } else { pos2 = 0.5 * Math.Tan(max - Math.PI) + 0.5; if (pos2 < 0.0) pos2 = 0.0; else if (pos2 > 1.0) pos2 = 1.0; } break; case 3: if (ledangle <= Math.PI) { pos1 = 0.0; } else if (ledangle >= 2.0 * Math.PI) { pos1 = 1.0; } else { pos1 = 0.5 * Math.Tan(ledangle - 1.5 * Math.PI) + 0.5; if (pos1 < 0.0) pos1 = 0.0; else if (pos1 > 1.0) pos1 = 1.0; } if (max <= Math.PI) { pos2 = 0.0; } else if (max >= 2.0 * Math.PI) { pos2 = 1.0; } else { pos2 = 0.5 * Math.Tan(max - 1.5 * Math.PI) + 0.5; if (pos2 < 0.0) pos2 = 0.0; else if (pos2 > 1.0) pos2 = 1.0; } break; case 4: if (ledangle <= 1.5 * Math.PI) { pos1 = 0.0; } else if (ledangle >= 2.5 * Math.PI) { pos1 = 0.5; } else { pos1 = 0.5 * Math.Tan(ledangle - 2.0 * Math.PI) + 0.5; if (pos1 < 0.0) pos1 = 0.0; else if (pos1 > 0.5) pos1 = 0.5; } if (max <= 1.5 * Math.PI) { pos2 = 0.0; } else if (max >= 2.5 * Math.PI) { pos2 = 0.5; } else { pos2 = 0.5 * Math.Tan(max - 2.0 * Math.PI) + 0.5; if (pos2 < 0.0) pos2 = 0.0; else if (pos2 > 0.5) pos2 = 0.5; } break; } int k = 2 * j + 1; double cpos1 = 1.0 - pos1; double cpos2 = 1.0 - pos2; double x0 = Object.States[s].Object.Mesh.Vertices[k].Coordinates.X; double y0 = Object.States[s].Object.Mesh.Vertices[k].Coordinates.Y; double z0 = Object.States[s].Object.Mesh.Vertices[k].Coordinates.Z; double x1 = Object.States[s].Object.Mesh.Vertices[k + 1].Coordinates.X; double y1 = Object.States[s].Object.Mesh.Vertices[k + 1].Coordinates.Y; double z1 = Object.States[s].Object.Mesh.Vertices[k + 1].Coordinates.Z; if (Object.LEDClockwiseWinding) { ObjectManager.Objects[i].Mesh.Vertices[k].Coordinates.X = x0 * cpos1 + x1 * pos1; ObjectManager.Objects[i].Mesh.Vertices[k].Coordinates.Y = y0 * cpos1 + y1 * pos1; ObjectManager.Objects[i].Mesh.Vertices[k].Coordinates.Z = z0 * cpos1 + z1 * pos1; ObjectManager.Objects[i].Mesh.Vertices[k + 1].Coordinates.X = x0 * cpos2 + x1 * pos2; ObjectManager.Objects[i].Mesh.Vertices[k + 1].Coordinates.Y = y0 * cpos2 + y1 * pos2; ObjectManager.Objects[i].Mesh.Vertices[k + 1].Coordinates.Z = z0 * cpos2 + z1 * pos2; } else { ObjectManager.Objects[i].Mesh.Vertices[k].Coordinates.X = x0 * cpos2 + x1 * pos2; ObjectManager.Objects[i].Mesh.Vertices[k].Coordinates.Y = y0 * cpos2 + y1 * pos2; ObjectManager.Objects[i].Mesh.Vertices[k].Coordinates.Z = z0 * cpos2 + z1 * pos2; ObjectManager.Objects[i].Mesh.Vertices[k + 1].Coordinates.X = x0 * cpos1 + x1 * pos1; ObjectManager.Objects[i].Mesh.Vertices[k + 1].Coordinates.Y = y0 * cpos1 + y1 * pos1; ObjectManager.Objects[i].Mesh.Vertices[k + 1].Coordinates.Z = z0 * cpos1 + z1 * pos1; } } } // update vertices for (int k = 0; k < Object.States[s].Object.Mesh.Vertices.Length; k++) { // rotate if (rotateX) { World.Rotate(ref ObjectManager.Objects[i].Mesh.Vertices[k].Coordinates.X, ref ObjectManager.Objects[i].Mesh.Vertices[k].Coordinates.Y, ref ObjectManager.Objects[i].Mesh.Vertices[k].Coordinates.Z, Object.RotateXDirection.X, Object.RotateXDirection.Y, Object.RotateXDirection.Z, cosX, sinX); } if (rotateY) { World.Rotate(ref ObjectManager.Objects[i].Mesh.Vertices[k].Coordinates.X, ref ObjectManager.Objects[i].Mesh.Vertices[k].Coordinates.Y, ref ObjectManager.Objects[i].Mesh.Vertices[k].Coordinates.Z, Object.RotateYDirection.X, Object.RotateYDirection.Y, Object.RotateYDirection.Z, cosY, sinY); } if (rotateZ) { World.Rotate(ref ObjectManager.Objects[i].Mesh.Vertices[k].Coordinates.X, ref ObjectManager.Objects[i].Mesh.Vertices[k].Coordinates.Y, ref ObjectManager.Objects[i].Mesh.Vertices[k].Coordinates.Z, Object.RotateZDirection.X, Object.RotateZDirection.Y, Object.RotateZDirection.Z, cosZ, sinZ); } // translate if (Overlay & World.CameraRestriction != World.CameraRestrictionMode.NotAvailable) { ObjectManager.Objects[i].Mesh.Vertices[k].Coordinates.X += Object.States[s].Position.X - Position.X; ObjectManager.Objects[i].Mesh.Vertices[k].Coordinates.Y += Object.States[s].Position.Y - Position.Y; ObjectManager.Objects[i].Mesh.Vertices[k].Coordinates.Z += Object.States[s].Position.Z - Position.Z; World.Rotate(ref ObjectManager.Objects[i].Mesh.Vertices[k].Coordinates.X, ref ObjectManager.Objects[i].Mesh.Vertices[k].Coordinates.Y, ref ObjectManager.Objects[i].Mesh.Vertices[k].Coordinates.Z, World.AbsoluteCameraDirection.X, World.AbsoluteCameraDirection.Y, World.AbsoluteCameraDirection.Z, World.AbsoluteCameraUp.X, World.AbsoluteCameraUp.Y, World.AbsoluteCameraUp.Z, World.AbsoluteCameraSide.X, World.AbsoluteCameraSide.Y, World.AbsoluteCameraSide.Z); double dx = -Math.Tan(World.CameraCurrentAlignment.Yaw) - World.CameraCurrentAlignment.Position.X; double dy = -Math.Tan(World.CameraCurrentAlignment.Pitch) - World.CameraCurrentAlignment.Position.Y; double dz = -World.CameraCurrentAlignment.Position.Z; ObjectManager.Objects[i].Mesh.Vertices[k].Coordinates.X += World.AbsoluteCameraPosition.X + dx * World.AbsoluteCameraSide.X + dy * World.AbsoluteCameraUp.X + dz * World.AbsoluteCameraDirection.X; ObjectManager.Objects[i].Mesh.Vertices[k].Coordinates.Y += World.AbsoluteCameraPosition.Y + dx * World.AbsoluteCameraSide.Y + dy * World.AbsoluteCameraUp.Y + dz * World.AbsoluteCameraDirection.Y; ObjectManager.Objects[i].Mesh.Vertices[k].Coordinates.Z += World.AbsoluteCameraPosition.Z + dx * World.AbsoluteCameraSide.Z + dy * World.AbsoluteCameraUp.Z + dz * World.AbsoluteCameraDirection.Z; } else { ObjectManager.Objects[i].Mesh.Vertices[k].Coordinates.X += Object.States[s].Position.X; ObjectManager.Objects[i].Mesh.Vertices[k].Coordinates.Y += Object.States[s].Position.Y; ObjectManager.Objects[i].Mesh.Vertices[k].Coordinates.Z += Object.States[s].Position.Z; World.Rotate(ref ObjectManager.Objects[i].Mesh.Vertices[k].Coordinates.X, ref ObjectManager.Objects[i].Mesh.Vertices[k].Coordinates.Y, ref ObjectManager.Objects[i].Mesh.Vertices[k].Coordinates.Z, Direction.X, Direction.Y, Direction.Z, Up.X, Up.Y, Up.Z, Side.X, Side.Y, Side.Z); ObjectManager.Objects[i].Mesh.Vertices[k].Coordinates.X += Position.X; ObjectManager.Objects[i].Mesh.Vertices[k].Coordinates.Y += Position.Y; ObjectManager.Objects[i].Mesh.Vertices[k].Coordinates.Z += Position.Z; } } // update normals for (int k = 0; k < Object.States[s].Object.Mesh.Faces.Length; k++) { for (int h = 0; h < Object.States[s].Object.Mesh.Faces[k].Vertices.Length; h++) { ObjectManager.Objects[i].Mesh.Faces[k].Vertices[h].Normal = Object.States[s].Object.Mesh.Faces[k].Vertices[h].Normal; } for (int h = 0; h < Object.States[s].Object.Mesh.Faces[k].Vertices.Length; h++) { if (!Object.States[s].Object.Mesh.Faces[k].Vertices[h].Normal.IsZero()) { if (rotateX) { World.Rotate(ref ObjectManager.Objects[i].Mesh.Faces[k].Vertices[h].Normal.X, ref ObjectManager.Objects[i].Mesh.Faces[k].Vertices[h].Normal.Y, ref ObjectManager.Objects[i].Mesh.Faces[k].Vertices[h].Normal.Z, Object.RotateXDirection.X, Object.RotateXDirection.Y, Object.RotateXDirection.Z, cosX, sinX); } if (rotateY) { World.Rotate(ref ObjectManager.Objects[i].Mesh.Faces[k].Vertices[h].Normal.X, ref ObjectManager.Objects[i].Mesh.Faces[k].Vertices[h].Normal.Y, ref ObjectManager.Objects[i].Mesh.Faces[k].Vertices[h].Normal.Z, Object.RotateYDirection.X, Object.RotateYDirection.Y, Object.RotateYDirection.Z, cosY, sinY); } if (rotateZ) { World.Rotate(ref ObjectManager.Objects[i].Mesh.Faces[k].Vertices[h].Normal.X, ref ObjectManager.Objects[i].Mesh.Faces[k].Vertices[h].Normal.Y, ref ObjectManager.Objects[i].Mesh.Faces[k].Vertices[h].Normal.Z, Object.RotateZDirection.X, Object.RotateZDirection.Y, Object.RotateZDirection.Z, cosZ, sinZ); } World.Rotate(ref ObjectManager.Objects[i].Mesh.Faces[k].Vertices[h].Normal.X, ref ObjectManager.Objects[i].Mesh.Faces[k].Vertices[h].Normal.Y, ref ObjectManager.Objects[i].Mesh.Faces[k].Vertices[h].Normal.Z, Direction.X, Direction.Y, Direction.Z, Up.X, Up.Y, Up.Z, Side.X, Side.Y, Side.Z); } } // visibility changed if (Show) { Renderer.ShowObject(i, Overlay); } else { Renderer.HideObject(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(); } }
// load all textures private static int[] LoadAllTextures(string BaseFile, World.ColorRGB TransparentColor, byte TransparentColorUsed, TextureManager.TextureLoadMode LoadMode) { string Folder = System.IO.Path.GetDirectoryName(BaseFile); if (!System.IO.Directory.Exists(Folder)) return new int[] { }; string Name = System.IO.Path.GetFileNameWithoutExtension(BaseFile); int[] Textures = new int[] { }; string[] Files = System.IO.Directory.GetFiles(Folder); for (int i = 0; i < Files.Length; i++) { string a = System.IO.Path.GetFileNameWithoutExtension(Files[i]); if (a.StartsWith(Name, StringComparison.OrdinalIgnoreCase)) { if (a.Length > Name.Length) { string b = a.Substring(Name.Length).TrimStart(); int j; if (int.TryParse(b, System.Globalization.NumberStyles.Integer, System.Globalization.CultureInfo.InvariantCulture, out j)) { if (j >= 0) { string c = System.IO.Path.GetExtension(Files[i]); switch (c.ToLowerInvariant()) { case ".bmp": case ".gif": case ".jpg": case ".jpeg": case ".png": case ".tif": case ".tiff": if (j >= Textures.Length) { int n = Textures.Length; Array.Resize<int>(ref Textures, j + 1); for (int k = n; k < j; k++) { Textures[k] = -1; } } Textures[j] = TextureManager.RegisterTexture(Files[i], TransparentColor, TransparentColorUsed, LoadMode, TextureManager.TextureWrapMode.Repeat, TextureManager.TextureWrapMode.Repeat, true, 0, 0, 0, 0); TextureManager.UseTexture(Textures[j], TextureManager.UseMode.Normal); break; } } } } } } return Textures; }
private static void RenderFace(ref World.MeshMaterial Material, World.Vertex[] Vertices, ref World.MeshFace Face, double CameraX, double CameraY, double CameraZ) { // texture int OpenGlNighttimeTextureIndex = Material.NighttimeTextureIndex >= 0 ? TextureManager.UseTexture(Material.NighttimeTextureIndex, TextureManager.UseMode.Normal) : 0; int OpenGlDaytimeTextureIndex = Material.DaytimeTextureIndex >= 0 ? TextureManager.UseTexture(Material.DaytimeTextureIndex, TextureManager.UseMode.Normal) : 0; if (OpenGlDaytimeTextureIndex != 0) { if (!TexturingEnabled) { GL.Enable(EnableCap.Texture2D); TexturingEnabled = true; } if (OpenGlDaytimeTextureIndex != LastBoundTexture) { GL.BindTexture(TextureTarget.Texture2D, OpenGlDaytimeTextureIndex); LastBoundTexture = OpenGlDaytimeTextureIndex; } if (TextureManager.Textures[Material.DaytimeTextureIndex].Transparency != TextureManager.TextureTransparencyMode.None) { if (!AlphaTestEnabled) { GL.Enable(EnableCap.AlphaTest); AlphaTestEnabled = true; } } else if (AlphaTestEnabled) { GL.Disable(EnableCap.AlphaTest); AlphaTestEnabled = false; } } else { if (TexturingEnabled) { GL.Disable(EnableCap.Texture2D); TexturingEnabled = false; LastBoundTexture = 0; } if (AlphaTestEnabled) { GL.Disable(EnableCap.AlphaTest); AlphaTestEnabled = false; } } // blend mode float factor; if (Material.BlendMode == World.MeshMaterialBlendMode.Additive) { factor = 1.0f; if (!BlendEnabled) GL.Enable(EnableCap.Blend); GL.BlendFunc(BlendingFactorSrc.SrcAlpha, BlendingFactorDest.One); if (FogEnabled) { GL.Disable(EnableCap.Fog); } } else if (OpenGlNighttimeTextureIndex == 0) { float blend = inv255 * (float)Material.DaytimeNighttimeBlend + 1.0f - OptionLightingResultingAmount; if (blend > 1.0f) blend = 1.0f; factor = 1.0f - 0.8f * blend; } else { factor = 1.0f; } if (OpenGlNighttimeTextureIndex != 0) { if (LightingEnabled) { GL.Disable(EnableCap.Lighting); LightingEnabled = false; } } else { if (OptionLighting & !LightingEnabled) { GL.Enable(EnableCap.Lighting); LightingEnabled = true; } } // render daytime polygon int FaceType = Face.Flags & World.MeshFace.FaceTypeMask; switch (FaceType) { case World.MeshFace.FaceTypeTriangles: GL.Begin(PrimitiveType.Triangles); break; case World.MeshFace.FaceTypeTriangleStrip: GL.Begin(PrimitiveType.TriangleStrip); break; case World.MeshFace.FaceTypeQuads: GL.Begin(PrimitiveType.Quads); break; case World.MeshFace.FaceTypeQuadStrip: GL.Begin(PrimitiveType.QuadStrip); break; default: GL.Begin(PrimitiveType.Polygon); break; } if (Material.GlowAttenuationData != 0) { float alphafactor = (float)GetDistanceFactor(Vertices, ref Face, Material.GlowAttenuationData, CameraX, CameraY, CameraZ); GL.Color4(inv255 * (float)Material.Color.R * factor, inv255 * Material.Color.G * factor, inv255 * (float)Material.Color.B * factor, inv255 * (float)Material.Color.A * alphafactor); } else { GL.Color4(inv255 * (float)Material.Color.R * factor, inv255 * Material.Color.G * factor, inv255 * (float)Material.Color.B * factor, inv255 * (float)Material.Color.A); } if ((Material.Flags & World.MeshMaterial.EmissiveColorMask) != 0) { GL.Material(MaterialFace.FrontAndBack, MaterialParameter.Emission, new float[] { inv255 * (float)Material.EmissiveColor.R, inv255 * (float)Material.EmissiveColor.G, inv255 * (float)Material.EmissiveColor.B, 1.0f }); EmissiveEnabled = true; } else if (EmissiveEnabled) { GL.Material(MaterialFace.FrontAndBack, MaterialParameter.Emission, new float[] { 0.0f, 0.0f, 0.0f, 1.0f }); EmissiveEnabled = false; } if (OpenGlDaytimeTextureIndex != 0) { if (LightingEnabled) { for (int j = 0; j < Face.Vertices.Length; j++) { GL.Normal3(Face.Vertices[j].Normal.X, Face.Vertices[j].Normal.Y, Face.Vertices[j].Normal.Z); GL.TexCoord2(Vertices[Face.Vertices[j].Index].TextureCoordinates.X, Vertices[Face.Vertices[j].Index].TextureCoordinates.Y); GL.Vertex3((float)(Vertices[Face.Vertices[j].Index].Coordinates.X - CameraX), (float)(Vertices[Face.Vertices[j].Index].Coordinates.Y - CameraY), (float)(Vertices[Face.Vertices[j].Index].Coordinates.Z - CameraZ)); } } else { for (int j = 0; j < Face.Vertices.Length; j++) { GL.TexCoord2(Vertices[Face.Vertices[j].Index].TextureCoordinates.X, Vertices[Face.Vertices[j].Index].TextureCoordinates.Y); GL.Vertex3((float)(Vertices[Face.Vertices[j].Index].Coordinates.X - CameraX), (float)(Vertices[Face.Vertices[j].Index].Coordinates.Y - CameraY), (float)(Vertices[Face.Vertices[j].Index].Coordinates.Z - CameraZ)); } } } else { if (LightingEnabled) { for (int j = 0; j < Face.Vertices.Length; j++) { GL.Normal3(Face.Vertices[j].Normal.X, Face.Vertices[j].Normal.Y, Face.Vertices[j].Normal.Z); GL.Vertex3((float)(Vertices[Face.Vertices[j].Index].Coordinates.X - CameraX), (float)(Vertices[Face.Vertices[j].Index].Coordinates.Y - CameraY), (float)(Vertices[Face.Vertices[j].Index].Coordinates.Z - CameraZ)); } } else { for (int j = 0; j < Face.Vertices.Length; j++) { GL.Vertex3((float)(Vertices[Face.Vertices[j].Index].Coordinates.X - CameraX), (float)(Vertices[Face.Vertices[j].Index].Coordinates.Y - CameraY), (float)(Vertices[Face.Vertices[j].Index].Coordinates.Z - CameraZ)); } } } GL.End(); // render nighttime polygon if (OpenGlNighttimeTextureIndex != 0) { if (!TexturingEnabled) { GL.Enable(EnableCap.Texture2D); TexturingEnabled = true; } if (!BlendEnabled) { GL.Enable(EnableCap.Blend); } GL.BindTexture(TextureTarget.Texture2D, OpenGlNighttimeTextureIndex); LastBoundTexture = 0; SetAlphaFunc(AlphaFunction.Greater, 0.0f); switch (FaceType) { case World.MeshFace.FaceTypeTriangles: GL.Begin(PrimitiveType.Triangles); break; case World.MeshFace.FaceTypeTriangleStrip: GL.Begin(PrimitiveType.TriangleStrip); break; case World.MeshFace.FaceTypeQuads: GL.Begin(PrimitiveType.Quads); break; case World.MeshFace.FaceTypeQuadStrip: GL.Begin(PrimitiveType.QuadStrip); break; default: GL.Begin(PrimitiveType.Polygon); break; } float alphafactor; if (Material.GlowAttenuationData != 0) { alphafactor = (float)GetDistanceFactor(Vertices, ref Face, Material.GlowAttenuationData, CameraX, CameraY, CameraZ); float blend = inv255 * (float)Material.DaytimeNighttimeBlend + 1.0f - OptionLightingResultingAmount; if (blend > 1.0f) blend = 1.0f; alphafactor *= blend; } else { alphafactor = inv255 * (float)Material.DaytimeNighttimeBlend + 1.0f - OptionLightingResultingAmount; if (alphafactor > 1.0f) alphafactor = 1.0f; } GL.Color4(inv255 * (float)Material.Color.R * factor, inv255 * Material.Color.G * factor, inv255 * (float)Material.Color.B * factor, inv255 * (float)Material.Color.A * alphafactor); if ((Material.Flags & World.MeshMaterial.EmissiveColorMask) != 0) { GL.Material(MaterialFace.FrontAndBack, MaterialParameter.Emission, new float[] { inv255 * (float)Material.EmissiveColor.R, inv255 * (float)Material.EmissiveColor.G, inv255 * (float)Material.EmissiveColor.B, 1.0f }); EmissiveEnabled = true; } else if (EmissiveEnabled) { GL.Material(MaterialFace.FrontAndBack, MaterialParameter.Emission, new float[] { 0.0f, 0.0f, 0.0f, 1.0f }); EmissiveEnabled = false; } for (int j = 0; j < Face.Vertices.Length; j++) { GL.TexCoord2(Vertices[Face.Vertices[j].Index].TextureCoordinates.X, Vertices[Face.Vertices[j].Index].TextureCoordinates.Y); GL.Vertex3((float)(Vertices[Face.Vertices[j].Index].Coordinates.X - CameraX), (float)(Vertices[Face.Vertices[j].Index].Coordinates.Y - CameraY), (float)(Vertices[Face.Vertices[j].Index].Coordinates.Z - CameraZ)); } GL.End(); if (AlphaFuncValue != 0.0) { GL.AlphaFunc(AlphaFuncComparison, AlphaFuncValue); } if (!BlendEnabled) { GL.Disable(EnableCap.Blend); } } // normals if (OptionNormals) { if (TexturingEnabled) { GL.Disable(EnableCap.Texture2D); TexturingEnabled = false; } if (AlphaTestEnabled) { GL.Disable(EnableCap.AlphaTest); AlphaTestEnabled = false; } for (int j = 0; j < Face.Vertices.Length; j++) { GL.Begin(PrimitiveType.Lines); GL.Color4(inv255 * (float)Material.Color.R, inv255 * (float)Material.Color.G, inv255 * (float)Material.Color.B, 1.0f); GL.Vertex3((float)(Vertices[Face.Vertices[j].Index].Coordinates.X - CameraX), (float)(Vertices[Face.Vertices[j].Index].Coordinates.Y - CameraY), (float)(Vertices[Face.Vertices[j].Index].Coordinates.Z - CameraZ)); GL.Vertex3((float)(Vertices[Face.Vertices[j].Index].Coordinates.X + Face.Vertices[j].Normal.X - CameraX), (float)(Vertices[Face.Vertices[j].Index].Coordinates.Y + Face.Vertices[j].Normal.Y - CameraY), (float)(Vertices[Face.Vertices[j].Index].Coordinates.Z + Face.Vertices[j].Normal.Z - CameraZ)); GL.End(); } } // finalize if (Material.BlendMode == World.MeshMaterialBlendMode.Additive) { GL.BlendFunc(BlendingFactorSrc.SrcAlpha, BlendingFactorDest.OneMinusSrcAlpha); if (!BlendEnabled) GL.Disable(EnableCap.Blend); if (FogEnabled) { GL.Enable(EnableCap.Fog); } } }
internal static int RegisterTexture(Bitmap Bitmap, World.ColorRGB TransparentColor) { int i = GetFreeTexture(); int[] a = new int[1]; GL.GenTextures(1, a); Textures[i] = new Texture(); Textures[i].Queried = false; Textures[i].OpenGlTextureIndex = a[0]; Textures[i].Transparency = TextureTransparencyMode.TransparentColor; Textures[i].TransparentColor = TransparentColor; Textures[i].TransparentColorUsed = 1; Textures[i].FileName = null; Textures[i].Loaded = true; Textures[i].DontAllowUnload = true; LoadTextureRGBAforData(Bitmap, Textures[i].TransparentColor, Textures[i].TransparentColorUsed, i); LoadTextureRGBAforOpenGl(i); return i; }
// 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); }
internal double Perform(TrainManager.Train Train, int CarIndex, World.Vector3D Position, double TrackPosition, int SectionIndex, bool IsPartOfTrain, double TimeElapsed) { ExecuteFunctionScript(this, Train, CarIndex, Position, TrackPosition, SectionIndex, IsPartOfTrain, TimeElapsed); return this.LastResult; }
private static void RenderBackground(World.Background Data, double dx, double dy, double dz, float Alpha, float scale) { if (Data.Texture != null && Textures.LoadTexture(Data.Texture, Textures.OpenGlTextureWrapMode.RepeatClamp)) { if (LightingEnabled) { Gl.glDisable(Gl.GL_LIGHTING); LightingEnabled = false; } if (!TexturingEnabled) { Gl.glEnable(Gl.GL_TEXTURE_2D); TexturingEnabled = true; } if (Alpha == 1.0f) { if (BlendEnabled) { Gl.glDisable(Gl.GL_BLEND); BlendEnabled = false; } } else if (!BlendEnabled) { Gl.glEnable(Gl.GL_BLEND); BlendEnabled = true; } Gl.glBindTexture(Gl.GL_TEXTURE_2D, Data.Texture.OpenGlTextures[(int)Textures.OpenGlTextureWrapMode.RepeatClamp].Name); Gl.glColor4f(1.0f, 1.0f, 1.0f, Alpha); float y0, y1; if (Data.KeepAspectRatio) { int tw = Data.Texture.Width; int th = Data.Texture.Height; double hh = Math.PI * World.BackgroundImageDistance * (double)th / ((double)tw * (double)Data.Repetition); y0 = (float)(-0.5 * hh); y1 = (float)(1.5 * hh); } else { y0 = (float)(-0.125 * World.BackgroundImageDistance); y1 = (float)(0.375 * World.BackgroundImageDistance); } const int n = 32; World.Vector3Df[] bottom = new World.Vector3Df[n]; World.Vector3Df[] top = new World.Vector3Df[n]; double angleValue = 2.61799387799149 - 3.14159265358979 / (double)n; double angleIncrement = 6.28318530717958 / (double)n; /* * To ensure that the whole background cylinder is rendered inside the viewing frustum, * the background is rendered before the scene with z-buffer writes disabled. Then, * the actual distance from the camera is irrelevant as long as it is inside the frustum. * */ for (int i = 0; i < n; i++) { float x = (float)(World.BackgroundImageDistance * Math.Cos(angleValue)); float z = (float)(World.BackgroundImageDistance * Math.Sin(angleValue)); bottom[i] = new World.Vector3Df(scale * x, scale * y0, scale * z); top[i] = new World.Vector3Df(scale * x, scale * y1, scale * z); angleValue += angleIncrement; } float textureStart = 0.5f * (float)Data.Repetition / (float)n; float textureIncrement = -(float)Data.Repetition / (float)n; double textureX = textureStart; for (int i = 0; i < n; i++) { int j = (i + 1) % n; // side wall Gl.glBegin(Gl.GL_QUADS); Gl.glTexCoord2d(textureX, 0.005f); Gl.glVertex3f(top[i].X, top[i].Y, top[i].Z); Gl.glTexCoord2d(textureX, 0.995f); Gl.glVertex3f(bottom[i].X, bottom[i].Y, bottom[i].Z); Gl.glTexCoord2d(textureX + textureIncrement, 0.995f); Gl.glVertex3f(bottom[j].X, bottom[j].Y, bottom[j].Z); Gl.glTexCoord2d(textureX + textureIncrement, 0.005f); Gl.glVertex3f(top[j].X, top[j].Y, top[j].Z); Gl.glEnd(); // top cap Gl.glBegin(Gl.GL_TRIANGLES); Gl.glTexCoord2d(textureX, 0.005f); Gl.glVertex3f(top[i].X, top[i].Y, top[i].Z); Gl.glTexCoord2d(textureX + textureIncrement, 0.005f); Gl.glVertex3f(top[j].X, top[j].Y, top[j].Z); Gl.glTexCoord2d(textureX + 0.5 * textureIncrement, 0.1f); Gl.glVertex3f(0.0f, top[i].Y, 0.0f); // bottom cap Gl.glTexCoord2d(textureX + 0.5 * textureIncrement, 0.9f); Gl.glVertex3f(0.0f, bottom[i].Y, 0.0f); Gl.glTexCoord2d(textureX + textureIncrement, 0.995f); Gl.glVertex3f(bottom[j].X, bottom[j].Y, bottom[j].Z); Gl.glTexCoord2d(textureX, 0.995f); Gl.glVertex3f(bottom[i].X, bottom[i].Y, bottom[i].Z); Gl.glEnd(); // finish textureX += textureIncrement; } Gl.glDisable(Gl.GL_TEXTURE_2D); TexturingEnabled = false; if (!BlendEnabled) { Gl.glEnable(Gl.GL_BLEND); BlendEnabled = true; } } }
/// <summary>Moves the camera to a point of interest</summary> /// <param name="Value">The value of the jump to perform: /// -1= Previous POI /// 0= Return to currently selected POI (From cab etc.) /// 1= Next POI</param> /// <param name="Relative">Whether the relative camera position should be retained</param> /// <returns>False if the previous / next POI would be outside those defined, true otherwise</returns> internal static bool ApplyPointOfInterest(int Value, bool Relative) { double t = 0.0; int j = -1; if (Relative) { // relative if (Value < 0) { // previous poi t = double.NegativeInfinity; for (int i = 0; i < Program.CurrentRoute.PointsOfInterest.Length; i++) { if (Program.CurrentRoute.PointsOfInterest[i].TrackPosition < World.CameraTrackFollower.TrackPosition) { if (Program.CurrentRoute.PointsOfInterest[i].TrackPosition > t) { t = Program.CurrentRoute.PointsOfInterest[i].TrackPosition; j = i; } } } } else if (Value > 0) { // next poi t = double.PositiveInfinity; for (int i = 0; i < Program.CurrentRoute.PointsOfInterest.Length; i++) { if (Program.CurrentRoute.PointsOfInterest[i].TrackPosition > World.CameraTrackFollower.TrackPosition) { if (Program.CurrentRoute.PointsOfInterest[i].TrackPosition < t) { t = Program.CurrentRoute.PointsOfInterest[i].TrackPosition; j = i; } } } } } else { // absolute j = Value >= 0 & Value < Program.CurrentRoute.PointsOfInterest.Length ? Value : -1; } // process poi if (j < 0) { return(false); } World.CameraTrackFollower.UpdateAbsolute(t, true, false); Program.Renderer.Camera.Alignment.Position = Program.CurrentRoute.PointsOfInterest[j].TrackOffset; Program.Renderer.Camera.Alignment.Yaw = Program.CurrentRoute.PointsOfInterest[j].TrackYaw; Program.Renderer.Camera.Alignment.Pitch = Program.CurrentRoute.PointsOfInterest[j].TrackPitch; Program.Renderer.Camera.Alignment.Roll = Program.CurrentRoute.PointsOfInterest[j].TrackRoll; Program.Renderer.Camera.Alignment.TrackPosition = t; World.UpdateAbsoluteCamera(0.0); if (Program.CurrentRoute.PointsOfInterest[j].Text != null) { double n = 3.0 + 0.5 * Math.Sqrt((double)Program.CurrentRoute.PointsOfInterest[j].Text.Length); Game.AddMessage(Program.CurrentRoute.PointsOfInterest[j].Text, MessageDependency.PointOfInterest, GameMode.Expert, MessageColor.White, Program.CurrentRoute.SecondsSinceMidnight + n, null); } return(true); }
private static void RenderFace(ref World.MeshMaterial Material, World.Vertex[] Vertices, Textures.OpenGlTextureWrapMode wrap, ref World.MeshFace Face, double CameraX, double CameraY, double CameraZ) { // texture if (Material.DaytimeTexture != null) { if (Textures.LoadTexture(Material.DaytimeTexture, wrap)) { if (!TexturingEnabled) { Gl.glEnable(Gl.GL_TEXTURE_2D); TexturingEnabled = true; } if (Material.DaytimeTexture.OpenGlTextures[(int)wrap] != LastBoundTexture) { Gl.glBindTexture(Gl.GL_TEXTURE_2D, Material.DaytimeTexture.OpenGlTextures[(int)wrap].Name); LastBoundTexture = Material.DaytimeTexture.OpenGlTextures[(int)wrap]; } } else { if (TexturingEnabled) { Gl.glDisable(Gl.GL_TEXTURE_2D); TexturingEnabled = false; LastBoundTexture = null; } } } else { if (TexturingEnabled) { Gl.glDisable(Gl.GL_TEXTURE_2D); TexturingEnabled = false; LastBoundTexture = null; } } // blend mode float factor; if (Material.BlendMode == World.MeshMaterialBlendMode.Additive) { factor = 1.0f; if (!BlendEnabled) Gl.glEnable(Gl.GL_BLEND); Gl.glBlendFunc(Gl.GL_SRC_ALPHA, Gl.GL_ONE); if (FogEnabled) { Gl.glDisable(Gl.GL_FOG); } } else if (Material.NighttimeTexture == null) { float blend = inv255 * (float)Material.DaytimeNighttimeBlend + 1.0f - OptionLightingResultingAmount; if (blend > 1.0f) blend = 1.0f; factor = 1.0f - 0.7f * blend; } else { factor = 1.0f; } if (Material.NighttimeTexture != null) { if (LightingEnabled) { Gl.glDisable(Gl.GL_LIGHTING); LightingEnabled = false; } } else { if (OptionLighting & !LightingEnabled) { Gl.glEnable(Gl.GL_LIGHTING); LightingEnabled = true; } } // render daytime polygon int FaceType = Face.Flags & World.MeshFace.FaceTypeMask; switch (FaceType) { case World.MeshFace.FaceTypeTriangles: Gl.glBegin(Gl.GL_TRIANGLES); break; case World.MeshFace.FaceTypeTriangleStrip: Gl.glBegin(Gl.GL_TRIANGLE_STRIP); break; case World.MeshFace.FaceTypeQuads: Gl.glBegin(Gl.GL_QUADS); break; case World.MeshFace.FaceTypeQuadStrip: Gl.glBegin(Gl.GL_QUAD_STRIP); break; default: Gl.glBegin(Gl.GL_POLYGON); break; } if (Material.GlowAttenuationData != 0) { float alphafactor = (float)GetDistanceFactor(Vertices, ref Face, Material.GlowAttenuationData, CameraX, CameraY, CameraZ); Gl.glColor4f(inv255 * (float)Material.Color.R * factor, inv255 * Material.Color.G * factor, inv255 * (float)Material.Color.B * factor, inv255 * (float)Material.Color.A * alphafactor); } else { Gl.glColor4f(inv255 * (float)Material.Color.R * factor, inv255 * Material.Color.G * factor, inv255 * (float)Material.Color.B * factor, inv255 * (float)Material.Color.A); } if ((Material.Flags & World.MeshMaterial.EmissiveColorMask) != 0) { Gl.glMaterialfv(Gl.GL_FRONT_AND_BACK, Gl.GL_EMISSION, new float[] { inv255 * (float)Material.EmissiveColor.R, inv255 * (float)Material.EmissiveColor.G, inv255 * (float)Material.EmissiveColor.B, 1.0f }); EmissiveEnabled = true; } else if (EmissiveEnabled) { Gl.glMaterialfv(Gl.GL_FRONT_AND_BACK, Gl.GL_EMISSION, new float[] { 0.0f, 0.0f, 0.0f, 1.0f }); EmissiveEnabled = false; } if (Material.DaytimeTexture != null) { if (LightingEnabled) { for (int j = 0; j < Face.Vertices.Length; j++) { Gl.glNormal3f(Face.Vertices[j].Normal.X, Face.Vertices[j].Normal.Y, Face.Vertices[j].Normal.Z); Gl.glTexCoord2f(Vertices[Face.Vertices[j].Index].TextureCoordinates.X, Vertices[Face.Vertices[j].Index].TextureCoordinates.Y); Gl.glVertex3f((float)(Vertices[Face.Vertices[j].Index].Coordinates.X - CameraX), (float)(Vertices[Face.Vertices[j].Index].Coordinates.Y - CameraY), (float)(Vertices[Face.Vertices[j].Index].Coordinates.Z - CameraZ)); } } else { for (int j = 0; j < Face.Vertices.Length; j++) { Gl.glTexCoord2f(Vertices[Face.Vertices[j].Index].TextureCoordinates.X, Vertices[Face.Vertices[j].Index].TextureCoordinates.Y); Gl.glVertex3f((float)(Vertices[Face.Vertices[j].Index].Coordinates.X - CameraX), (float)(Vertices[Face.Vertices[j].Index].Coordinates.Y - CameraY), (float)(Vertices[Face.Vertices[j].Index].Coordinates.Z - CameraZ)); } } } else { if (LightingEnabled) { for (int j = 0; j < Face.Vertices.Length; j++) { Gl.glNormal3f(Face.Vertices[j].Normal.X, Face.Vertices[j].Normal.Y, Face.Vertices[j].Normal.Z); Gl.glVertex3f((float)(Vertices[Face.Vertices[j].Index].Coordinates.X - CameraX), (float)(Vertices[Face.Vertices[j].Index].Coordinates.Y - CameraY), (float)(Vertices[Face.Vertices[j].Index].Coordinates.Z - CameraZ)); } } else { for (int j = 0; j < Face.Vertices.Length; j++) { Gl.glVertex3f((float)(Vertices[Face.Vertices[j].Index].Coordinates.X - CameraX), (float)(Vertices[Face.Vertices[j].Index].Coordinates.Y - CameraY), (float)(Vertices[Face.Vertices[j].Index].Coordinates.Z - CameraZ)); } } } Gl.glEnd(); // render nighttime polygon if (Material.NighttimeTexture != null && Textures.LoadTexture(Material.NighttimeTexture, wrap)) { if (!TexturingEnabled) { Gl.glEnable(Gl.GL_TEXTURE_2D); TexturingEnabled = true; } if (!BlendEnabled) { Gl.glEnable(Gl.GL_BLEND); } Gl.glBindTexture(Gl.GL_TEXTURE_2D, Material.NighttimeTexture.OpenGlTextures[(int)wrap].Name); LastBoundTexture = null; Gl.glAlphaFunc(Gl.GL_GREATER, 0.0f); Gl.glEnable(Gl.GL_ALPHA_TEST); switch (FaceType) { case World.MeshFace.FaceTypeTriangles: Gl.glBegin(Gl.GL_TRIANGLES); break; case World.MeshFace.FaceTypeTriangleStrip: Gl.glBegin(Gl.GL_TRIANGLE_STRIP); break; case World.MeshFace.FaceTypeQuads: Gl.glBegin(Gl.GL_QUADS); break; case World.MeshFace.FaceTypeQuadStrip: Gl.glBegin(Gl.GL_QUAD_STRIP); break; default: Gl.glBegin(Gl.GL_POLYGON); break; } float alphafactor; if (Material.GlowAttenuationData != 0) { alphafactor = (float)GetDistanceFactor(Vertices, ref Face, Material.GlowAttenuationData, CameraX, CameraY, CameraZ); float blend = inv255 * (float)Material.DaytimeNighttimeBlend + 1.0f - OptionLightingResultingAmount; if (blend > 1.0f) blend = 1.0f; alphafactor *= blend; } else { alphafactor = inv255 * (float)Material.DaytimeNighttimeBlend + 1.0f - OptionLightingResultingAmount; if (alphafactor > 1.0f) alphafactor = 1.0f; } Gl.glColor4f(inv255 * (float)Material.Color.R * factor, inv255 * Material.Color.G * factor, inv255 * (float)Material.Color.B * factor, inv255 * (float)Material.Color.A * alphafactor); if ((Material.Flags & World.MeshMaterial.EmissiveColorMask) != 0) { Gl.glMaterialfv(Gl.GL_FRONT_AND_BACK, Gl.GL_EMISSION, new float[] { inv255 * (float)Material.EmissiveColor.R, inv255 * (float)Material.EmissiveColor.G, inv255 * (float)Material.EmissiveColor.B, 1.0f }); EmissiveEnabled = true; } else if (EmissiveEnabled) { Gl.glMaterialfv(Gl.GL_FRONT_AND_BACK, Gl.GL_EMISSION, new float[] { 0.0f, 0.0f, 0.0f, 1.0f }); EmissiveEnabled = false; } for (int j = 0; j < Face.Vertices.Length; j++) { Gl.glTexCoord2f(Vertices[Face.Vertices[j].Index].TextureCoordinates.X, Vertices[Face.Vertices[j].Index].TextureCoordinates.Y); Gl.glVertex3f((float)(Vertices[Face.Vertices[j].Index].Coordinates.X - CameraX), (float)(Vertices[Face.Vertices[j].Index].Coordinates.Y - CameraY), (float)(Vertices[Face.Vertices[j].Index].Coordinates.Z - CameraZ)); } Gl.glEnd(); RestoreAlphaFunc(); if (!BlendEnabled) { Gl.glDisable(Gl.GL_BLEND); } } // normals if (OptionNormals) { if (TexturingEnabled) { Gl.glDisable(Gl.GL_TEXTURE_2D); TexturingEnabled = false; } for (int j = 0; j < Face.Vertices.Length; j++) { Gl.glBegin(Gl.GL_LINES); Gl.glColor4f(inv255 * (float)Material.Color.R, inv255 * (float)Material.Color.G, inv255 * (float)Material.Color.B, 1.0f); Gl.glVertex3f((float)(Vertices[Face.Vertices[j].Index].Coordinates.X - CameraX), (float)(Vertices[Face.Vertices[j].Index].Coordinates.Y - CameraY), (float)(Vertices[Face.Vertices[j].Index].Coordinates.Z - CameraZ)); Gl.glVertex3f((float)(Vertices[Face.Vertices[j].Index].Coordinates.X + Face.Vertices[j].Normal.X - CameraX), (float)(Vertices[Face.Vertices[j].Index].Coordinates.Y + Face.Vertices[j].Normal.Y - CameraY), (float)(Vertices[Face.Vertices[j].Index].Coordinates.Z + Face.Vertices[j].Normal.Z - CameraZ)); Gl.glEnd(); } } // finalize if (Material.BlendMode == World.MeshMaterialBlendMode.Additive) { Gl.glBlendFunc(Gl.GL_SRC_ALPHA, Gl.GL_ONE_MINUS_SRC_ALPHA); if (!BlendEnabled) Gl.glDisable(Gl.GL_BLEND); if (FogEnabled) { Gl.glEnable(Gl.GL_FOG); } } }
internal static void UpdateAnimatedObject(ref AnimatedObject Object, bool IsPartOfTrain, TrainManager.Train Train, int CarIndex, int SectionIndex, double TrackPosition, World.Vector3D Position, World.Vector3D Direction, World.Vector3D Up, World.Vector3D Side, bool Overlay, bool UpdateFunctions, bool Show, double TimeElapsed) { int s = Object.CurrentState; int i = Object.ObjectIndex; // state change if (Object.StateFunction != null & UpdateFunctions) { double sd = Object.StateFunction.Perform(Train, CarIndex, Position, TrackPosition, SectionIndex, IsPartOfTrain, TimeElapsed); int si = (int)Math.Round(sd); int sn = Object.States.Length; if (si < 0 | si >= sn) si = -1; if (s != si) { InitializeAnimatedObject(ref Object, si, Overlay, Show); s = si; } } if (s == -1) return; // translation if (Object.TranslateXFunction != null) { double x; if (UpdateFunctions) { x = Object.TranslateXFunction.Perform(Train, CarIndex, Position, TrackPosition, SectionIndex, IsPartOfTrain, TimeElapsed); } else { x = Object.TranslateXFunction.LastResult; } double rx = Object.TranslateXDirection.X, ry = Object.TranslateXDirection.Y, rz = Object.TranslateXDirection.Z; World.Rotate(ref rx, ref ry, ref rz, Direction.X, Direction.Y, Direction.Z, Up.X, Up.Y, Up.Z, Side.X, Side.Y, Side.Z); Position.X += x * rx; Position.Y += x * ry; Position.Z += x * rz; } if (Object.TranslateYFunction != null) { double y; if (UpdateFunctions) { y = Object.TranslateYFunction.Perform(Train, CarIndex, Position, TrackPosition, SectionIndex, IsPartOfTrain, TimeElapsed); } else { y = Object.TranslateYFunction.LastResult; } double rx = Object.TranslateYDirection.X, ry = Object.TranslateYDirection.Y, rz = Object.TranslateYDirection.Z; World.Rotate(ref rx, ref ry, ref rz, Direction.X, Direction.Y, Direction.Z, Up.X, Up.Y, Up.Z, Side.X, Side.Y, Side.Z); Position.X += y * rx; Position.Y += y * ry; Position.Z += y * rz; } if (Object.TranslateZFunction != null) { double z; if (UpdateFunctions) { z = Object.TranslateZFunction.Perform(Train, CarIndex, Position, TrackPosition, SectionIndex, IsPartOfTrain, TimeElapsed); } else { z = Object.TranslateZFunction.LastResult; } double rx = Object.TranslateZDirection.X, ry = Object.TranslateZDirection.Y, rz = Object.TranslateZDirection.Z; World.Rotate(ref rx, ref ry, ref rz, Direction.X, Direction.Y, Direction.Z, Up.X, Up.Y, Up.Z, Side.X, Side.Y, Side.Z); Position.X += z * rx; Position.Y += z * ry; Position.Z += z * rz; } // rotation bool rotateX = Object.RotateXFunction != null; bool rotateY = Object.RotateYFunction != null; bool rotateZ = Object.RotateZFunction != null; double cosX, sinX; if (rotateX) { double a; if (UpdateFunctions) { a = Object.RotateXFunction.Perform(Train, CarIndex, Position, TrackPosition, SectionIndex, IsPartOfTrain, TimeElapsed); } else { a = Object.RotateXFunction.LastResult; } ObjectManager.UpdateDamping(ref Object.RotateXDamping, TimeElapsed, ref a); cosX = Math.Cos(a); sinX = Math.Sin(a); } else { cosX = 0.0; sinX = 0.0; } double cosY, sinY; if (rotateY) { double a; if (UpdateFunctions) { a = Object.RotateYFunction.Perform(Train, CarIndex, Position, TrackPosition, SectionIndex, IsPartOfTrain, TimeElapsed); } else { a = Object.RotateYFunction.LastResult; } ObjectManager.UpdateDamping(ref Object.RotateYDamping, TimeElapsed, ref a); cosY = Math.Cos(a); sinY = Math.Sin(a); } else { cosY = 0.0; sinY = 0.0; } double cosZ, sinZ; if (rotateZ) { double a; if (UpdateFunctions) { a = Object.RotateZFunction.Perform(Train, CarIndex, Position, TrackPosition, SectionIndex, IsPartOfTrain, TimeElapsed); } else { a = Object.RotateZFunction.LastResult; } ObjectManager.UpdateDamping(ref Object.RotateZDamping, TimeElapsed, ref a); cosZ = Math.Cos(a); sinZ = Math.Sin(a); } else { cosZ = 0.0; sinZ = 0.0; } // texture shift bool shiftx = Object.TextureShiftXFunction != null; bool shifty = Object.TextureShiftYFunction != null; if ((shiftx | shifty) & UpdateFunctions) { for (int k = 0; k < ObjectManager.Objects[i].Mesh.Vertices.Length; k++) { ObjectManager.Objects[i].Mesh.Vertices[k].TextureCoordinates = Object.States[s].Object.Mesh.Vertices[k].TextureCoordinates; } if (shiftx) { double x = Object.TextureShiftXFunction.Perform(Train, CarIndex, Position, TrackPosition, SectionIndex, IsPartOfTrain, TimeElapsed); x -= Math.Floor(x); for (int k = 0; k < ObjectManager.Objects[i].Mesh.Vertices.Length; k++) { ObjectManager.Objects[i].Mesh.Vertices[k].TextureCoordinates.X += (float)(x * Object.TextureShiftXDirection.X); ObjectManager.Objects[i].Mesh.Vertices[k].TextureCoordinates.Y += (float)(x * Object.TextureShiftXDirection.Y); } } if (shifty) { double y = Object.TextureShiftYFunction.Perform(Train, CarIndex, Position, TrackPosition, SectionIndex, IsPartOfTrain, TimeElapsed); y -= Math.Floor(y); for (int k = 0; k < ObjectManager.Objects[i].Mesh.Vertices.Length; k++) { ObjectManager.Objects[i].Mesh.Vertices[k].TextureCoordinates.X += (float)(y * Object.TextureShiftYDirection.X); ObjectManager.Objects[i].Mesh.Vertices[k].TextureCoordinates.Y += (float)(y * Object.TextureShiftYDirection.Y); } } } // led bool led = Object.LEDFunction != null; double ledangle; if (led) { if (UpdateFunctions) { double lastangle = Object.LEDFunction.LastResult; ledangle = Object.LEDFunction.Perform(Train, CarIndex, Position, TrackPosition, SectionIndex, IsPartOfTrain, TimeElapsed); } else { ledangle = Object.LEDFunction.LastResult; } } else { ledangle = 0.0; } // null object if (Object.States[s].Object == null) { return; } // initialize vertices for (int k = 0; k < Object.States[s].Object.Mesh.Vertices.Length; k++) { ObjectManager.Objects[i].Mesh.Vertices[k].Coordinates = Object.States[s].Object.Mesh.Vertices[k].Coordinates; } // led if (led) { /* * Edges: Vertices: * 0 - bottom 0 - bottom-left * 1 - left 1 - top-left * 2 - top 2 - top-right * 3 - right 3 - bottom-right * 4 - center * */ int v = 1; if (Object.LEDClockwiseWinding) { /* winding is clockwise*/ if (ledangle < Object.LEDInitialAngle) { ledangle = Object.LEDInitialAngle; } if (ledangle < Object.LEDLastAngle) { double currentEdgeFloat = Math.Floor(0.636619772367582 * (ledangle + 0.785398163397449)); int currentEdge = ((int)currentEdgeFloat % 4 + 4) % 4; double lastEdgeFloat = Math.Floor(0.636619772367582 * (Object.LEDLastAngle + 0.785398163397449)); int lastEdge = ((int)lastEdgeFloat % 4 + 4) % 4; if (lastEdge < currentEdge | lastEdge == currentEdge & Math.Abs(currentEdgeFloat - lastEdgeFloat) > 2.0) { lastEdge += 4; } if (currentEdge == lastEdge) { /* current angle to last angle */ { double t = 0.5 + (0.636619772367582 * ledangle) - currentEdgeFloat; if (t < 0.0) { t = 0.0; } else if (t > 1.0) { t = 1.0; } t = 0.5 * (1.0 - Math.Tan(0.25 * (Math.PI - 2.0 * Math.PI * t))); double cx = (1.0 - t) * Object.LEDVectors[(currentEdge + 3) % 4].X + t * Object.LEDVectors[currentEdge].X; double cy = (1.0 - t) * Object.LEDVectors[(currentEdge + 3) % 4].Y + t * Object.LEDVectors[currentEdge].Y; double cz = (1.0 - t) * Object.LEDVectors[(currentEdge + 3) % 4].Z + t * Object.LEDVectors[currentEdge].Z; Object.States[s].Object.Mesh.Vertices[v].Coordinates = new World.Vector3D(cx, cy, cz); v++; } { double t = 0.5 + (0.636619772367582 * Object.LEDLastAngle) - lastEdgeFloat; if (t < 0.0) { t = 0.0; } else if (t > 1.0) { t = 1.0; } t = 0.5 * (1.0 - Math.Tan(0.25 * (Math.PI - 2.0 * Math.PI * t))); double lx = (1.0 - t) * Object.LEDVectors[(lastEdge + 3) % 4].X + t * Object.LEDVectors[lastEdge].X; double ly = (1.0 - t) * Object.LEDVectors[(lastEdge + 3) % 4].Y + t * Object.LEDVectors[lastEdge].Y; double lz = (1.0 - t) * Object.LEDVectors[(lastEdge + 3) % 4].Z + t * Object.LEDVectors[lastEdge].Z; Object.States[s].Object.Mesh.Vertices[v].Coordinates = new World.Vector3D(lx, ly, lz); v++; } } else { { /* current angle to square vertex */ double t = 0.5 + (0.636619772367582 * ledangle) - currentEdgeFloat; if (t < 0.0) { t = 0.0; } else if (t > 1.0) { t = 1.0; } t = 0.5 * (1.0 - Math.Tan(0.25 * (Math.PI - 2.0 * Math.PI * t))); double cx = (1.0 - t) * Object.LEDVectors[(currentEdge + 3) % 4].X + t * Object.LEDVectors[currentEdge].X; double cy = (1.0 - t) * Object.LEDVectors[(currentEdge + 3) % 4].Y + t * Object.LEDVectors[currentEdge].Y; double cz = (1.0 - t) * Object.LEDVectors[(currentEdge + 3) % 4].Z + t * Object.LEDVectors[currentEdge].Z; Object.States[s].Object.Mesh.Vertices[v + 0].Coordinates = new World.Vector3D(cx, cy, cz); Object.States[s].Object.Mesh.Vertices[v + 1].Coordinates = Object.LEDVectors[currentEdge]; v += 2; } for (int j = currentEdge + 1; j < lastEdge; j++) { /* square-vertex to square-vertex */ Object.States[s].Object.Mesh.Vertices[v + 0].Coordinates = Object.LEDVectors[(j + 3) % 4]; Object.States[s].Object.Mesh.Vertices[v + 1].Coordinates = Object.LEDVectors[j % 4]; v += 2; } { /* square vertex to last angle */ double t = 0.5 + (0.636619772367582 * Object.LEDLastAngle) - lastEdgeFloat; if (t < 0.0) { t = 0.0; } else if (t > 1.0) { t = 1.0; } t = 0.5 * (1.0 - Math.Tan(0.25 * (Math.PI - 2.0 * Math.PI * t))); double lx = (1.0 - t) * Object.LEDVectors[(lastEdge + 3) % 4].X + t * Object.LEDVectors[lastEdge % 4].X; double ly = (1.0 - t) * Object.LEDVectors[(lastEdge + 3) % 4].Y + t * Object.LEDVectors[lastEdge % 4].Y; double lz = (1.0 - t) * Object.LEDVectors[(lastEdge + 3) % 4].Z + t * Object.LEDVectors[lastEdge % 4].Z; Object.States[s].Object.Mesh.Vertices[v + 0].Coordinates = Object.LEDVectors[(lastEdge + 3) % 4]; Object.States[s].Object.Mesh.Vertices[v + 1].Coordinates = new World.Vector3D(lx, ly, lz); v += 2; } } } } else { /* winding is counter-clockwise*/ if (ledangle > Object.LEDInitialAngle) { ledangle = Object.LEDInitialAngle; } if (ledangle > Object.LEDLastAngle) { double currentEdgeFloat = Math.Floor(0.636619772367582 * (ledangle + 0.785398163397449)); int currentEdge = ((int)currentEdgeFloat % 4 + 4) % 4; double lastEdgeFloat = Math.Floor(0.636619772367582 * (Object.LEDLastAngle + 0.785398163397449)); int lastEdge = ((int)lastEdgeFloat % 4 + 4) % 4; if (currentEdge < lastEdge | lastEdge == currentEdge & Math.Abs(currentEdgeFloat - lastEdgeFloat) > 2.0) { currentEdge += 4; } if (currentEdge == lastEdge) { /* current angle to last angle */ { double t = 0.5 + (0.636619772367582 * Object.LEDLastAngle) - lastEdgeFloat; if (t < 0.0) { t = 0.0; } else if (t > 1.0) { t = 1.0; } t = 0.5 * (1.0 - Math.Tan(0.25 * (Math.PI - 2.0 * Math.PI * t))); double lx = (1.0 - t) * Object.LEDVectors[(lastEdge + 3) % 4].X + t * Object.LEDVectors[lastEdge].X; double ly = (1.0 - t) * Object.LEDVectors[(lastEdge + 3) % 4].Y + t * Object.LEDVectors[lastEdge].Y; double lz = (1.0 - t) * Object.LEDVectors[(lastEdge + 3) % 4].Z + t * Object.LEDVectors[lastEdge].Z; Object.States[s].Object.Mesh.Vertices[v].Coordinates = new World.Vector3D(lx, ly, lz); v++; } { double t = 0.5 + (0.636619772367582 * ledangle) - currentEdgeFloat; if (t < 0.0) { t = 0.0; } else if (t > 1.0) { t = 1.0; } t = t - Math.Floor(t); t = 0.5 * (1.0 - Math.Tan(0.25 * (Math.PI - 2.0 * Math.PI * t))); double cx = (1.0 - t) * Object.LEDVectors[(currentEdge + 3) % 4].X + t * Object.LEDVectors[currentEdge].X; double cy = (1.0 - t) * Object.LEDVectors[(currentEdge + 3) % 4].Y + t * Object.LEDVectors[currentEdge].Y; double cz = (1.0 - t) * Object.LEDVectors[(currentEdge + 3) % 4].Z + t * Object.LEDVectors[currentEdge].Z; Object.States[s].Object.Mesh.Vertices[v].Coordinates = new World.Vector3D(cx, cy, cz); v++; } } else { { /* current angle to square vertex */ double t = 0.5 + (0.636619772367582 * ledangle) - currentEdgeFloat; if (t < 0.0) { t = 0.0; } else if (t > 1.0) { t = 1.0; } t = 0.5 * (1.0 - Math.Tan(0.25 * (Math.PI - 2.0 * Math.PI * t))); double cx = (1.0 - t) * Object.LEDVectors[(currentEdge + 3) % 4].X + t * Object.LEDVectors[currentEdge % 4].X; double cy = (1.0 - t) * Object.LEDVectors[(currentEdge + 3) % 4].Y + t * Object.LEDVectors[currentEdge % 4].Y; double cz = (1.0 - t) * Object.LEDVectors[(currentEdge + 3) % 4].Z + t * Object.LEDVectors[currentEdge % 4].Z; Object.States[s].Object.Mesh.Vertices[v + 0].Coordinates = Object.LEDVectors[(currentEdge + 3) % 4]; Object.States[s].Object.Mesh.Vertices[v + 1].Coordinates = new World.Vector3D(cx, cy, cz); v += 2; } for (int j = currentEdge - 1; j > lastEdge; j--) { /* square-vertex to square-vertex */ Object.States[s].Object.Mesh.Vertices[v + 0].Coordinates = Object.LEDVectors[(j + 3) % 4]; Object.States[s].Object.Mesh.Vertices[v + 1].Coordinates = Object.LEDVectors[j % 4]; v += 2; } { /* square vertex to last angle */ double t = 0.5 + (0.636619772367582 * Object.LEDLastAngle) - lastEdgeFloat; if (t < 0.0) { t = 0.0; } else if (t > 1.0) { t = 1.0; } t = 0.5 * (1.0 - Math.Tan(0.25 * (Math.PI - 2.0 * Math.PI * t))); double lx = (1.0 - t) * Object.LEDVectors[(lastEdge + 3) % 4].X + t * Object.LEDVectors[lastEdge].X; double ly = (1.0 - t) * Object.LEDVectors[(lastEdge + 3) % 4].Y + t * Object.LEDVectors[lastEdge].Y; double lz = (1.0 - t) * Object.LEDVectors[(lastEdge + 3) % 4].Z + t * Object.LEDVectors[lastEdge].Z; Object.States[s].Object.Mesh.Vertices[v + 0].Coordinates = new World.Vector3D(lx, ly, lz); Object.States[s].Object.Mesh.Vertices[v + 1].Coordinates = Object.LEDVectors[lastEdge % 4]; v += 2; } } } } for (int j = v; v < 11; v++) { Object.States[s].Object.Mesh.Vertices[j].Coordinates = Object.LEDVectors[4]; } } // update vertices for (int k = 0; k < Object.States[s].Object.Mesh.Vertices.Length; k++) { // rotate if (rotateX) { World.Rotate(ref ObjectManager.Objects[i].Mesh.Vertices[k].Coordinates.X, ref ObjectManager.Objects[i].Mesh.Vertices[k].Coordinates.Y, ref ObjectManager.Objects[i].Mesh.Vertices[k].Coordinates.Z, Object.RotateXDirection.X, Object.RotateXDirection.Y, Object.RotateXDirection.Z, cosX, sinX); } if (rotateY) { World.Rotate(ref ObjectManager.Objects[i].Mesh.Vertices[k].Coordinates.X, ref ObjectManager.Objects[i].Mesh.Vertices[k].Coordinates.Y, ref ObjectManager.Objects[i].Mesh.Vertices[k].Coordinates.Z, Object.RotateYDirection.X, Object.RotateYDirection.Y, Object.RotateYDirection.Z, cosY, sinY); } if (rotateZ) { World.Rotate(ref ObjectManager.Objects[i].Mesh.Vertices[k].Coordinates.X, ref ObjectManager.Objects[i].Mesh.Vertices[k].Coordinates.Y, ref ObjectManager.Objects[i].Mesh.Vertices[k].Coordinates.Z, Object.RotateZDirection.X, Object.RotateZDirection.Y, Object.RotateZDirection.Z, cosZ, sinZ); } // translate if (Overlay & World.CameraRestriction != World.CameraRestrictionMode.NotAvailable) { ObjectManager.Objects[i].Mesh.Vertices[k].Coordinates.X += Object.States[s].Position.X - Position.X; ObjectManager.Objects[i].Mesh.Vertices[k].Coordinates.Y += Object.States[s].Position.Y - Position.Y; ObjectManager.Objects[i].Mesh.Vertices[k].Coordinates.Z += Object.States[s].Position.Z - Position.Z; World.Rotate(ref ObjectManager.Objects[i].Mesh.Vertices[k].Coordinates.X, ref ObjectManager.Objects[i].Mesh.Vertices[k].Coordinates.Y, ref ObjectManager.Objects[i].Mesh.Vertices[k].Coordinates.Z, World.AbsoluteCameraDirection.X, World.AbsoluteCameraDirection.Y, World.AbsoluteCameraDirection.Z, World.AbsoluteCameraUp.X, World.AbsoluteCameraUp.Y, World.AbsoluteCameraUp.Z, World.AbsoluteCameraSide.X, World.AbsoluteCameraSide.Y, World.AbsoluteCameraSide.Z); double dx = -Math.Tan(World.CameraCurrentAlignment.Yaw) - World.CameraCurrentAlignment.Position.X; double dy = -Math.Tan(World.CameraCurrentAlignment.Pitch) - World.CameraCurrentAlignment.Position.Y; double dz = -World.CameraCurrentAlignment.Position.Z; ObjectManager.Objects[i].Mesh.Vertices[k].Coordinates.X += World.AbsoluteCameraPosition.X + dx * World.AbsoluteCameraSide.X + dy * World.AbsoluteCameraUp.X + dz * World.AbsoluteCameraDirection.X; ObjectManager.Objects[i].Mesh.Vertices[k].Coordinates.Y += World.AbsoluteCameraPosition.Y + dx * World.AbsoluteCameraSide.Y + dy * World.AbsoluteCameraUp.Y + dz * World.AbsoluteCameraDirection.Y; ObjectManager.Objects[i].Mesh.Vertices[k].Coordinates.Z += World.AbsoluteCameraPosition.Z + dx * World.AbsoluteCameraSide.Z + dy * World.AbsoluteCameraUp.Z + dz * World.AbsoluteCameraDirection.Z; } else { ObjectManager.Objects[i].Mesh.Vertices[k].Coordinates.X += Object.States[s].Position.X; ObjectManager.Objects[i].Mesh.Vertices[k].Coordinates.Y += Object.States[s].Position.Y; ObjectManager.Objects[i].Mesh.Vertices[k].Coordinates.Z += Object.States[s].Position.Z; World.Rotate(ref ObjectManager.Objects[i].Mesh.Vertices[k].Coordinates.X, ref ObjectManager.Objects[i].Mesh.Vertices[k].Coordinates.Y, ref ObjectManager.Objects[i].Mesh.Vertices[k].Coordinates.Z, Direction.X, Direction.Y, Direction.Z, Up.X, Up.Y, Up.Z, Side.X, Side.Y, Side.Z); ObjectManager.Objects[i].Mesh.Vertices[k].Coordinates.X += Position.X; ObjectManager.Objects[i].Mesh.Vertices[k].Coordinates.Y += Position.Y; ObjectManager.Objects[i].Mesh.Vertices[k].Coordinates.Z += Position.Z; } } // update normals for (int k = 0; k < Object.States[s].Object.Mesh.Faces.Length; k++) { for (int h = 0; h < Object.States[s].Object.Mesh.Faces[k].Vertices.Length; h++) { ObjectManager.Objects[i].Mesh.Faces[k].Vertices[h].Normal = Object.States[s].Object.Mesh.Faces[k].Vertices[h].Normal; } for (int h = 0; h < Object.States[s].Object.Mesh.Faces[k].Vertices.Length; h++) { if (!Object.States[s].Object.Mesh.Faces[k].Vertices[h].Normal.IsZero()) { if (rotateX) { World.Rotate(ref ObjectManager.Objects[i].Mesh.Faces[k].Vertices[h].Normal.X, ref ObjectManager.Objects[i].Mesh.Faces[k].Vertices[h].Normal.Y, ref ObjectManager.Objects[i].Mesh.Faces[k].Vertices[h].Normal.Z, Object.RotateXDirection.X, Object.RotateXDirection.Y, Object.RotateXDirection.Z, cosX, sinX); } if (rotateY) { World.Rotate(ref ObjectManager.Objects[i].Mesh.Faces[k].Vertices[h].Normal.X, ref ObjectManager.Objects[i].Mesh.Faces[k].Vertices[h].Normal.Y, ref ObjectManager.Objects[i].Mesh.Faces[k].Vertices[h].Normal.Z, Object.RotateYDirection.X, Object.RotateYDirection.Y, Object.RotateYDirection.Z, cosY, sinY); } if (rotateZ) { World.Rotate(ref ObjectManager.Objects[i].Mesh.Faces[k].Vertices[h].Normal.X, ref ObjectManager.Objects[i].Mesh.Faces[k].Vertices[h].Normal.Y, ref ObjectManager.Objects[i].Mesh.Faces[k].Vertices[h].Normal.Z, Object.RotateZDirection.X, Object.RotateZDirection.Y, Object.RotateZDirection.Z, cosZ, sinZ); } World.Rotate(ref ObjectManager.Objects[i].Mesh.Faces[k].Vertices[h].Normal.X, ref ObjectManager.Objects[i].Mesh.Faces[k].Vertices[h].Normal.Y, ref ObjectManager.Objects[i].Mesh.Faces[k].Vertices[h].Normal.Z, Direction.X, Direction.Y, Direction.Z, Up.X, Up.Y, Up.Z, Side.X, Side.Y, Side.Z); } } // visibility changed if (Show) { if (Overlay) { Renderer.ShowObject(i, Renderer.ObjectType.Overlay); } else { Renderer.ShowObject(i, Renderer.ObjectType.Dynamic); } } else { Renderer.HideObject(i); } } }
// get distance factor private static double GetDistanceFactor(World.Vertex[] Vertices, ref World.MeshFace Face, ushort GlowAttenuationData, double CameraX, double CameraY, double CameraZ) { if (Face.Vertices.Length != 0) { World.GlowAttenuationMode mode; double halfdistance; World.SplitGlowAttenuationData(GlowAttenuationData, out mode, out halfdistance); int i = (int)Face.Vertices[0].Index; double dx = Vertices[i].Coordinates.X - CameraX; double dy = Vertices[i].Coordinates.Y - CameraY; double dz = Vertices[i].Coordinates.Z - CameraZ; switch (mode) { case World.GlowAttenuationMode.DivisionExponent2: { double t = dx * dx + dy * dy + dz * dz; return t / (t + halfdistance * halfdistance); } case World.GlowAttenuationMode.DivisionExponent4: { double t = dx * dx + dy * dy + dz * dz; t *= t; halfdistance *= halfdistance; return t / (t + halfdistance * halfdistance); } default: return 1.0; } } else { return 1.0; } }
internal static int RegisterTexture(string FileName, World.ColorRGB TransparentColor, byte TransparentColorUsed, TextureLoadMode LoadMode, TextureWrapMode WrapModeX, TextureWrapMode WrapModeY, bool DontAllowUnload, int ClipLeft, int ClipTop, int ClipWidth, int ClipHeight) { if (FileName == null) { //Need to find out why the object parser sometimes decides to pass a null filename, but this works around it return -1; } int i = FindTexture(FileName, TransparentColor, TransparentColorUsed, LoadMode, WrapModeX, WrapModeY, ClipLeft, ClipTop, ClipWidth, ClipHeight); if (i >= 0) { return i; } else { i = GetFreeTexture(); Textures[i] = new Texture { Queried = false, Loaded = false, FileName = FileName, TransparentColor = TransparentColor, TransparentColorUsed = TransparentColorUsed, LoadMode = LoadMode, WrapModeX = WrapModeX, WrapModeY = WrapModeY, ClipLeft = ClipLeft, ClipTop = ClipTop, ClipWidth = ClipWidth, ClipHeight = ClipHeight, DontAllowUnload = DontAllowUnload, LoadImmediately = false, OpenGlTextureIndex = 0 }; bool alpha = false; switch (System.IO.Path.GetExtension(Textures[i].FileName).ToLowerInvariant()) { case ".gif": case ".png": alpha = true; Textures[i].LoadImmediately = true; break; } if (alpha) { Textures[i].Transparency = TextureTransparencyMode.Alpha; } else if (TransparentColorUsed != 0) { Textures[i].Transparency = TextureTransparencyMode.TransparentColor; } else { Textures[i].Transparency = TextureTransparencyMode.None; } Textures[i].IsRGBA = Textures[i].Transparency != TextureTransparencyMode.None | LoadMode != TextureLoadMode.Normal; return i; } }
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); }
// find texture private static int FindTexture(string FileName, World.ColorRGB TransparentColor, byte TransparentColorUsed, TextureLoadMode LoadMode, TextureWrapMode WrapModeX, TextureWrapMode WrapModeY, int ClipLeft, int ClipTop, int ClipWidth, int ClipHeight) { for (int i = 1; i < Textures.Length; i++) { if (Textures[i] != null && Textures[i].FileName != null) { if (string.Compare(Textures[i].FileName, FileName, StringComparison.OrdinalIgnoreCase) == 0) { if (Textures[i].LoadMode == LoadMode & Textures[i].WrapModeX == WrapModeX & Textures[i].WrapModeY == WrapModeY) { if (Textures[i].ClipLeft == ClipLeft & Textures[i].ClipTop == ClipTop & Textures[i].ClipWidth == ClipWidth & Textures[i].ClipHeight == ClipHeight) { if (TransparentColorUsed == 0) { if (Textures[i].TransparentColorUsed == 0) { return i; } } else { if (Textures[i].TransparentColorUsed != 0) { if (Textures[i].TransparentColor.R == TransparentColor.R & Textures[i].TransparentColor.G == TransparentColor.G & Textures[i].TransparentColor.B == TransparentColor.B) { return i; } } } } } } } } return -1; }
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 int CreateAnimatedWorldObject(AnimatedObject Prototype, Vector3 Position, World.Transformation BaseTransformation, World.Transformation AuxTransformation, int SectionIndex, double TrackPosition, double Brightness) { int a = AnimatedWorldObjectsUsed; if (a >= AnimatedWorldObjects.Length) { Array.Resize<AnimatedWorldObject>(ref AnimatedWorldObjects, AnimatedWorldObjects.Length << 1); } World.Transformation FinalTransformation = new World.Transformation(BaseTransformation, AuxTransformation); AnimatedWorldObjects[a] = new AnimatedWorldObject(); AnimatedWorldObjects[a].Position = Position; AnimatedWorldObjects[a].Direction = FinalTransformation.Z; AnimatedWorldObjects[a].Up = FinalTransformation.Y; AnimatedWorldObjects[a].Side = FinalTransformation.X; AnimatedWorldObjects[a].Object = Prototype.Clone(); AnimatedWorldObjects[a].Object.ObjectIndex = CreateDynamicObject(); AnimatedWorldObjects[a].SectionIndex = SectionIndex; AnimatedWorldObjects[a].TrackPosition = TrackPosition; for (int i = 0; i < AnimatedWorldObjects[a].Object.States.Length; i++) { if (AnimatedWorldObjects[a].Object.States[i].Object == null) { AnimatedWorldObjects[a].Object.States[i].Object = new StaticObject(); AnimatedWorldObjects[a].Object.States[i].Object.Mesh.Faces = new World.MeshFace[] { }; AnimatedWorldObjects[a].Object.States[i].Object.Mesh.Materials = new World.MeshMaterial[] { }; AnimatedWorldObjects[a].Object.States[i].Object.Mesh.Vertices = new World.Vertex[] { }; AnimatedWorldObjects[a].Object.States[i].Object.RendererIndex = -1; } } double r = 0.0; for (int i = 0; i < AnimatedWorldObjects[a].Object.States.Length; i++) { for (int j = 0; j < AnimatedWorldObjects[a].Object.States[i].Object.Mesh.Materials.Length; j++) { AnimatedWorldObjects[a].Object.States[i].Object.Mesh.Materials[j].Color.R = (byte)Math.Round((double)Prototype.States[i].Object.Mesh.Materials[j].Color.R * Brightness); AnimatedWorldObjects[a].Object.States[i].Object.Mesh.Materials[j].Color.G = (byte)Math.Round((double)Prototype.States[i].Object.Mesh.Materials[j].Color.G * Brightness); AnimatedWorldObjects[a].Object.States[i].Object.Mesh.Materials[j].Color.B = (byte)Math.Round((double)Prototype.States[i].Object.Mesh.Materials[j].Color.B * Brightness); } for (int j = 0; j < AnimatedWorldObjects[a].Object.States[i].Object.Mesh.Vertices.Length; j++) { double x = Prototype.States[i].Object.Mesh.Vertices[j].Coordinates.X; double y = Prototype.States[i].Object.Mesh.Vertices[j].Coordinates.Y; double z = Prototype.States[i].Object.Mesh.Vertices[j].Coordinates.Z; double t = x * x + y * y + z * z; if (t > r) r = t; } } AnimatedWorldObjects[a].Radius = Math.Sqrt(r); AnimatedWorldObjects[a].Visible = false; InitializeAnimatedObject(ref AnimatedWorldObjects[a].Object, 0, false, false); AnimatedWorldObjectsUsed++; return a; }
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); }
// create object internal static void CreateObject(UnifiedObject Prototype, Vector3 Position, World.Transformation BaseTransformation, World.Transformation AuxTransformation, bool AccurateObjectDisposal, double StartingDistance, double EndingDistance, double BlockLength, double TrackPosition) { CreateObject(Prototype, Position, BaseTransformation, AuxTransformation, -1, AccurateObjectDisposal, StartingDistance, EndingDistance, BlockLength, TrackPosition, 1.0, false); }
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); }
// create static object internal static int CreateStaticObject(StaticObject Prototype, Vector3 Position, World.Transformation BaseTransformation, World.Transformation AuxTransformation, bool AccurateObjectDisposal, double StartingDistance, double EndingDistance, double BlockLength, double TrackPosition) { return CreateStaticObject(Prototype, Position, BaseTransformation, AuxTransformation, AccurateObjectDisposal, 0.0, StartingDistance, EndingDistance, BlockLength, TrackPosition, 1.0, false); }
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 SoundSource(); 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 ApplyStaticObjectData(ref StaticObject Object, StaticObject Prototype, Vector3 Position, World.Transformation BaseTransformation, World.Transformation AuxTransformation, bool AccurateObjectDisposal, double AccurateObjectDisposalZOffset, double StartingDistance, double EndingDistance, double BlockLength, double TrackPosition, double Brightness, bool DuplicateMaterials) { Object = new StaticObject(); Object.StartingDistance = float.MaxValue; Object.EndingDistance = float.MinValue; bool brightnesschange = Brightness != 1.0; // vertices Object.Mesh.Vertices = new World.Vertex[Prototype.Mesh.Vertices.Length]; for (int j = 0; j < Prototype.Mesh.Vertices.Length; j++) { Object.Mesh.Vertices[j] = Prototype.Mesh.Vertices[j]; if (AccurateObjectDisposal) { World.Rotate(ref Object.Mesh.Vertices[j].Coordinates.X, ref Object.Mesh.Vertices[j].Coordinates.Y, ref Object.Mesh.Vertices[j].Coordinates.Z, AuxTransformation); if (Object.Mesh.Vertices[j].Coordinates.Z < Object.StartingDistance) { Object.StartingDistance = (float)Object.Mesh.Vertices[j].Coordinates.Z; } if (Object.Mesh.Vertices[j].Coordinates.Z > Object.EndingDistance) { Object.EndingDistance = (float)Object.Mesh.Vertices[j].Coordinates.Z; } Object.Mesh.Vertices[j].Coordinates = Prototype.Mesh.Vertices[j].Coordinates; } World.Rotate(ref Object.Mesh.Vertices[j].Coordinates.X, ref Object.Mesh.Vertices[j].Coordinates.Y, ref Object.Mesh.Vertices[j].Coordinates.Z, AuxTransformation); World.Rotate(ref Object.Mesh.Vertices[j].Coordinates.X, ref Object.Mesh.Vertices[j].Coordinates.Y, ref Object.Mesh.Vertices[j].Coordinates.Z, BaseTransformation); Object.Mesh.Vertices[j].Coordinates.X += Position.X; Object.Mesh.Vertices[j].Coordinates.Y += Position.Y; Object.Mesh.Vertices[j].Coordinates.Z += Position.Z; } if (AccurateObjectDisposal) { Object.StartingDistance += (float)AccurateObjectDisposalZOffset; Object.EndingDistance += (float)AccurateObjectDisposalZOffset; } // faces Object.Mesh.Faces = new World.MeshFace[Prototype.Mesh.Faces.Length]; for (int j = 0; j < Prototype.Mesh.Faces.Length; j++) { Object.Mesh.Faces[j].Flags = Prototype.Mesh.Faces[j].Flags; Object.Mesh.Faces[j].Material = Prototype.Mesh.Faces[j].Material; Object.Mesh.Faces[j].Vertices = new World.MeshFaceVertex[Prototype.Mesh.Faces[j].Vertices.Length]; for (int k = 0; k < Prototype.Mesh.Faces[j].Vertices.Length; k++) { Object.Mesh.Faces[j].Vertices[k] = Prototype.Mesh.Faces[j].Vertices[k]; double nx = Object.Mesh.Faces[j].Vertices[k].Normal.X; double ny = Object.Mesh.Faces[j].Vertices[k].Normal.Y; double nz = Object.Mesh.Faces[j].Vertices[k].Normal.Z; if (nx * nx + ny * ny + nz * nz != 0.0) { World.Rotate(ref Object.Mesh.Faces[j].Vertices[k].Normal.X, ref Object.Mesh.Faces[j].Vertices[k].Normal.Y, ref Object.Mesh.Faces[j].Vertices[k].Normal.Z, AuxTransformation); World.Rotate(ref Object.Mesh.Faces[j].Vertices[k].Normal.X, ref Object.Mesh.Faces[j].Vertices[k].Normal.Y, ref Object.Mesh.Faces[j].Vertices[k].Normal.Z, BaseTransformation); } } } // materials Object.Mesh.Materials = new World.MeshMaterial[Prototype.Mesh.Materials.Length]; for (int j = 0; j < Prototype.Mesh.Materials.Length; j++) { Object.Mesh.Materials[j] = Prototype.Mesh.Materials[j]; Object.Mesh.Materials[j].Color.R = (byte)Math.Round((double)Prototype.Mesh.Materials[j].Color.R * Brightness); Object.Mesh.Materials[j].Color.G = (byte)Math.Round((double)Prototype.Mesh.Materials[j].Color.G * Brightness); Object.Mesh.Materials[j].Color.B = (byte)Math.Round((double)Prototype.Mesh.Materials[j].Color.B * Brightness); } const double minBlockLength = 20.0; if (BlockLength < minBlockLength) { BlockLength = BlockLength * Math.Ceiling(minBlockLength / BlockLength); } if (AccurateObjectDisposal) { Object.StartingDistance += (float)TrackPosition; Object.EndingDistance += (float)TrackPosition; double z = BlockLength * Math.Floor(TrackPosition / BlockLength); StartingDistance = Math.Min(z - BlockLength, (double)Object.StartingDistance); EndingDistance = Math.Max(z + 2.0 * BlockLength, (double)Object.EndingDistance); Object.StartingDistance = (float)(BlockLength * Math.Floor(StartingDistance / BlockLength)); Object.EndingDistance = (float)(BlockLength * Math.Ceiling(EndingDistance / BlockLength)); } else { Object.StartingDistance = (float)StartingDistance; Object.EndingDistance = (float)EndingDistance; } if (BlockLength != 0.0) { checked { Object.GroupIndex = (short)Mod(Math.Floor(Object.StartingDistance / BlockLength), Math.Ceiling(Interface.CurrentOptions.ViewingDistance / BlockLength)); } } }
internal static void ApplyStaticObjectData(ref StaticObject Object, StaticObject Prototype, World.Vector3D Position, World.Transformation BaseTransformation, World.Transformation AuxTransformation, bool AccurateObjectDisposal, double AccurateObjectDisposalZOffset, double StartingDistance, double EndingDistance, double TrackPosition, double Brightness, bool DuplicateMaterials) { Object = new StaticObject(); Object.StartingDistance = float.MaxValue; Object.EndingDistance = float.MinValue; bool brightnesschange = Brightness != 1.0; // vertices Object.Mesh.Vertices = new World.Vertex[Prototype.Mesh.Vertices.Length]; for (int j = 0; j < Prototype.Mesh.Vertices.Length; j++) { Object.Mesh.Vertices[j] = Prototype.Mesh.Vertices[j]; if (AccurateObjectDisposal) { World.Rotate(ref Object.Mesh.Vertices[j].Coordinates.X, ref Object.Mesh.Vertices[j].Coordinates.Y, ref Object.Mesh.Vertices[j].Coordinates.Z, AuxTransformation); if (Object.Mesh.Vertices[j].Coordinates.Z < Object.StartingDistance) { Object.StartingDistance = (float)Object.Mesh.Vertices[j].Coordinates.Z; } if (Object.Mesh.Vertices[j].Coordinates.Z > Object.EndingDistance) { Object.EndingDistance = (float)Object.Mesh.Vertices[j].Coordinates.Z; } Object.Mesh.Vertices[j].Coordinates = Prototype.Mesh.Vertices[j].Coordinates; } World.Rotate(ref Object.Mesh.Vertices[j].Coordinates.X, ref Object.Mesh.Vertices[j].Coordinates.Y, ref Object.Mesh.Vertices[j].Coordinates.Z, AuxTransformation); World.Rotate(ref Object.Mesh.Vertices[j].Coordinates.X, ref Object.Mesh.Vertices[j].Coordinates.Y, ref Object.Mesh.Vertices[j].Coordinates.Z, BaseTransformation); Object.Mesh.Vertices[j].Coordinates.X += Position.X; Object.Mesh.Vertices[j].Coordinates.Y += Position.Y; Object.Mesh.Vertices[j].Coordinates.Z += Position.Z; } if (AccurateObjectDisposal) { Object.StartingDistance += (float)AccurateObjectDisposalZOffset; Object.EndingDistance += (float)AccurateObjectDisposalZOffset; } // faces Object.Mesh.Faces = new World.MeshFace[Prototype.Mesh.Faces.Length]; for (int j = 0; j < Prototype.Mesh.Faces.Length; j++) { Object.Mesh.Faces[j].Flags = Prototype.Mesh.Faces[j].Flags; Object.Mesh.Faces[j].Material = Prototype.Mesh.Faces[j].Material; Object.Mesh.Faces[j].Vertices = new World.MeshFaceVertex[Prototype.Mesh.Faces[j].Vertices.Length]; for (int k = 0; k < Prototype.Mesh.Faces[j].Vertices.Length; k++) { Object.Mesh.Faces[j].Vertices[k] = Prototype.Mesh.Faces[j].Vertices[k]; double nx = Object.Mesh.Faces[j].Vertices[k].Normal.X; double ny = Object.Mesh.Faces[j].Vertices[k].Normal.Y; double nz = Object.Mesh.Faces[j].Vertices[k].Normal.Z; if (nx * nx + ny * ny + nz * nz != 0.0) { World.Rotate(ref Object.Mesh.Faces[j].Vertices[k].Normal.X, ref Object.Mesh.Faces[j].Vertices[k].Normal.Y, ref Object.Mesh.Faces[j].Vertices[k].Normal.Z, AuxTransformation); World.Rotate(ref Object.Mesh.Faces[j].Vertices[k].Normal.X, ref Object.Mesh.Faces[j].Vertices[k].Normal.Y, ref Object.Mesh.Faces[j].Vertices[k].Normal.Z, BaseTransformation); } } } // materials Object.Mesh.Materials = new World.MeshMaterial[Prototype.Mesh.Materials.Length]; for (int j = 0; j < Prototype.Mesh.Materials.Length; j++) { Object.Mesh.Materials[j] = Prototype.Mesh.Materials[j]; Object.Mesh.Materials[j].Color.R = (byte)Math.Round((double)Prototype.Mesh.Materials[j].Color.R * Brightness); Object.Mesh.Materials[j].Color.G = (byte)Math.Round((double)Prototype.Mesh.Materials[j].Color.G * Brightness); Object.Mesh.Materials[j].Color.B = (byte)Math.Round((double)Prototype.Mesh.Materials[j].Color.B * Brightness); } if (AccurateObjectDisposal) { Object.StartingDistance += (float)TrackPosition; Object.EndingDistance += (float)TrackPosition; } else { Object.StartingDistance = (float)StartingDistance; Object.EndingDistance = (float)EndingDistance; } }
// execute function script private static void ExecuteFunctionScript(FunctionScript Function, TrainManager.Train Train, int CarIndex, World.Vector3D Position, double TrackPosition, int SectionIndex, bool IsPartOfTrain, double TimeElapsed) { int s = 0, c = 0; for (int i = 0; i < Function.Instructions.Length; i++) { switch (Function.Instructions[i]) { // system case Instructions.SystemHalt: i = Function.Instructions.Length; break; case Instructions.SystemConstant: Function.Stack[s] = Function.Constants[c]; s++; c++; break; case Instructions.SystemConstantArray: { int n = (int)Function.Instructions[i + 1]; for (int j = 0; j < n; j++) { Function.Stack[s + j] = Function.Constants[c + j]; } s += n; c += n; i++; } break; case Instructions.SystemValue: Function.Stack[s] = Function.LastResult; s++; break; case Instructions.SystemDelta: Function.Stack[s] = TimeElapsed; s++; break; // stack case Instructions.StackCopy: Function.Stack[s] = Function.Stack[s - 1]; s++; break; case Instructions.StackSwap: { double a = Function.Stack[s - 1]; Function.Stack[s - 1] = Function.Stack[s - 2]; Function.Stack[s - 2] = a; } break; // math case Instructions.MathPlus: Function.Stack[s - 2] += Function.Stack[s - 1]; s--; break; case Instructions.MathSubtract: Function.Stack[s - 2] -= Function.Stack[s - 1]; s--; break; case Instructions.MathMinus: Function.Stack[s - 1] = -Function.Stack[s - 1]; break; case Instructions.MathTimes: Function.Stack[s - 2] *= Function.Stack[s - 1]; s--; break; case Instructions.MathDivide: Function.Stack[s - 2] = Function.Stack[s - 1] == 0.0 ? 0.0 : Function.Stack[s - 2] / Function.Stack[s - 1]; s--; break; case Instructions.MathReciprocal: Function.Stack[s - 1] = Function.Stack[s - 1] == 0.0 ? 0.0 : 1.0 / Function.Stack[s - 1]; break; case Instructions.MathPower: { double a = Function.Stack[s - 2]; double b = Function.Stack[s - 1]; if (b == 2.0) { Function.Stack[s - 2] = a * a; } else if (b == 3.0) { Function.Stack[s - 2] = a * a * a; } else if (b == 4.0) { double t = a * a; Function.Stack[s - 2] = t * t; } else if (b == 5.0) { double t = a * a; Function.Stack[s - 2] = t * t * a; } else if (b == 6.0) { double t = a * a * a; Function.Stack[s - 2] = t * t; } else if (b == 7.0) { double t = a * a * a; Function.Stack[s - 2] = t * t * a; } else if (b == 8.0) { double t = a * a; t *= t; Function.Stack[s - 2] = t * t; } else if (b == 0.0) { Function.Stack[s - 2] = 1.0; } else if (b < 0.0) { Function.Stack[s - 2] = 0.0; } else { Function.Stack[s - 2] = Math.Pow(a, b); } s--; break; } case Instructions.MathIncrement: Function.Stack[s - 1] += 1.0; break; case Instructions.MathDecrement: Function.Stack[s - 1] -= 1.0; break; case Instructions.MathFusedMultiplyAdd: Function.Stack[s - 3] = Function.Stack[s - 3] * Function.Stack[s - 2] + Function.Stack[s - 1]; s -= 2; break; case Instructions.MathQuotient: Function.Stack[s - 2] = Function.Stack[s - 1] == 0.0 ? 0.0 : Math.Floor(Function.Stack[s - 2] / Function.Stack[s - 1]); s--; break; case Instructions.MathMod: Function.Stack[s - 2] = Function.Stack[s - 1] == 0.0 ? 0.0 : Function.Stack[s - 2] - Function.Stack[s - 1] * Math.Floor(Function.Stack[s - 2] / Function.Stack[s - 1]); s--; break; case Instructions.MathFloor: Function.Stack[s - 1] = Math.Floor(Function.Stack[s - 1]); break; case Instructions.MathCeiling: Function.Stack[s - 1] = Math.Ceiling(Function.Stack[s - 1]); break; case Instructions.MathRound: Function.Stack[s - 1] = Math.Round(Function.Stack[s - 1]); break; case Instructions.MathMin: Function.Stack[s - 2] = Function.Stack[s - 2] < Function.Stack[s - 1] ? Function.Stack[s - 2] : Function.Stack[s - 1]; s--; break; case Instructions.MathMax: Function.Stack[s - 2] = Function.Stack[s - 2] > Function.Stack[s - 1] ? Function.Stack[s - 2] : Function.Stack[s - 1]; s--; break; case Instructions.MathAbs: Function.Stack[s - 1] = Math.Abs(Function.Stack[s - 1]); break; case Instructions.MathSign: Function.Stack[s - 1] = Math.Sign(Function.Stack[s - 1]); break; case Instructions.MathExp: Function.Stack[s - 1] = Math.Exp(Function.Stack[s - 1]); break; case Instructions.MathLog: Function.Stack[s - 1] = Log(Function.Stack[s - 1]); break; case Instructions.MathSqrt: Function.Stack[s - 1] = Sqrt(Function.Stack[s - 1]); break; case Instructions.MathSin: Function.Stack[s - 1] = Math.Sin(Function.Stack[s - 1]); break; case Instructions.MathCos: Function.Stack[s - 1] = Math.Cos(Function.Stack[s - 1]); break; case Instructions.MathTan: Function.Stack[s - 1] = Tan(Function.Stack[s - 1]); break; case Instructions.MathArcTan: Function.Stack[s - 1] = Math.Atan(Function.Stack[s - 1]); break; // comparisons case Instructions.CompareEqual: Function.Stack[s - 2] = Function.Stack[s - 2] == Function.Stack[s - 1] ? 1.0 : 0.0; s--; break; case Instructions.CompareUnequal: Function.Stack[s - 2] = Function.Stack[s - 2] != Function.Stack[s - 1] ? 1.0 : 0.0; s--; break; case Instructions.CompareLess: Function.Stack[s - 2] = Function.Stack[s - 2] < Function.Stack[s - 1] ? 1.0 : 0.0; s--; break; case Instructions.CompareGreater: Function.Stack[s - 2] = Function.Stack[s - 2] > Function.Stack[s - 1] ? 1.0 : 0.0; s--; break; case Instructions.CompareLessEqual: Function.Stack[s - 2] = Function.Stack[s - 2] <= Function.Stack[s - 1] ? 1.0 : 0.0; s--; break; case Instructions.CompareGreaterEqual: Function.Stack[s - 2] = Function.Stack[s - 2] >= Function.Stack[s - 1] ? 1.0 : 0.0; s--; break; case Instructions.CompareConditional: Function.Stack[s - 3] = Function.Stack[s - 3] != 0.0 ? Function.Stack[s - 2] : Function.Stack[s - 1]; s -= 2; break; // logical case Instructions.LogicalNot: Function.Stack[s - 1] = Function.Stack[s - 1] != 0.0 ? 0.0 : 1.0; break; case Instructions.LogicalAnd: Function.Stack[s - 2] = Function.Stack[s - 2] != 0.0 & Function.Stack[s - 1] != 0.0 ? 1.0 : 0.0; s--; break; case Instructions.LogicalOr: Function.Stack[s - 2] = Function.Stack[s - 2] != 0.0 | Function.Stack[s - 1] != 0.0 ? 1.0 : 0.0; s--; break; case Instructions.LogicalNand: Function.Stack[s - 2] = Function.Stack[s - 2] != 0.0 & Function.Stack[s - 1] != 0.0 ? 0.0 : 1.0; s--; break; case Instructions.LogicalNor: Function.Stack[s - 2] = Function.Stack[s - 2] != 0.0 | Function.Stack[s - 1] != 0.0 ? 0.0 : 1.0; s--; break; case Instructions.LogicalXor: Function.Stack[s - 2] = Function.Stack[s - 2] != 0.0 ^ Function.Stack[s - 1] != 0.0 ? 1.0 : 0.0; s--; break; // time/camera case Instructions.TimeSecondsSinceMidnight: Function.Stack[s] = Game.SecondsSinceMidnight; s++; break; case Instructions.CameraDistance: { double dx = World.AbsoluteCameraPosition.X - Position.X; double dy = World.AbsoluteCameraPosition.Y - Position.Y; double dz = World.AbsoluteCameraPosition.Z - Position.Z; Function.Stack[s] = Math.Sqrt(dx * dx + dy * dy + dz * dz); s++; } break; // train case Instructions.TrainCars: if (Train != null) { Function.Stack[s] = (double)Train.Cars.Length; } else { Function.Stack[s] = 0.0; } s++; break; case Instructions.TrainSpeed: if (Train != null) { Function.Stack[s] = Train.Cars[CarIndex].Specs.CurrentSpeed; } else { Function.Stack[s] = 0.0; } s++; break; case Instructions.TrainSpeedOfCar: if (Train != null) { int j = (int)Math.Round(Function.Stack[s - 1]); if (j < 0) j += Train.Cars.Length; if (j >= 0 & j < Train.Cars.Length) { Function.Stack[s - 1] = Train.Cars[j].Specs.CurrentSpeed; } else { Function.Stack[s - 1] = 0.0; } } else { Function.Stack[s - 1] = 0.0; } break; case Instructions.TrainSpeedometer: if (Train != null) { Function.Stack[s] = Train.Cars[CarIndex].Specs.CurrentPerceivedSpeed; } else { Function.Stack[s] = 0.0; } s++; break; case Instructions.TrainSpeedometerOfCar: if (Train != null) { int j = (int)Math.Round(Function.Stack[s - 1]); if (j < 0) j += Train.Cars.Length; if (j >= 0 & j < Train.Cars.Length) { Function.Stack[s - 1] = Train.Cars[j].Specs.CurrentPerceivedSpeed; } else { Function.Stack[s - 1] = 0.0; } } else { Function.Stack[s - 1] = 0.0; } break; case Instructions.TrainAcceleration: if (Train != null) { Function.Stack[s] = Train.Cars[CarIndex].Specs.CurrentAcceleration; } else { Function.Stack[s] = 0.0; } s++; break; case Instructions.TrainAccelerationOfCar: if (Train != null) { int j = (int)Math.Round(Function.Stack[s - 1]); if (j < 0) j += Train.Cars.Length; if (j >= 0 & j < Train.Cars.Length) { Function.Stack[s - 1] = Train.Cars[j].Specs.CurrentAcceleration; } else { Function.Stack[s - 1] = 0.0; } } else { Function.Stack[s - 1] = 0.0; } break; case Instructions.TrainAccelerationMotor: if (Train != null) { Function.Stack[s] = 0.0; for (int j = 0; j < Train.Cars.Length; j++) { if (Train.Cars[j].Specs.IsMotorCar) { // hack: CurrentAccelerationOutput does not distinguish between forward/backward if (Train.Cars[j].Specs.CurrentAccelerationOutput < 0.0) { Function.Stack[s] = Train.Cars[j].Specs.CurrentAccelerationOutput * (double)Math.Sign(Train.Cars[j].Specs.CurrentSpeed); } else if (Train.Cars[j].Specs.CurrentAccelerationOutput > 0.0) { Function.Stack[s] = Train.Cars[j].Specs.CurrentAccelerationOutput * (double)Train.Specs.CurrentReverser.Actual; } else { Function.Stack[s] = 0.0; } break; } } } else { Function.Stack[s] = 0.0; } s++; break; case Instructions.TrainAccelerationMotorOfCar: if (Train != null) { int j = (int)Math.Round(Function.Stack[s - 1]); if (j < 0) j += Train.Cars.Length; if (j >= 0 & j < Train.Cars.Length) { // hack: CurrentAccelerationOutput does not distinguish between forward/backward if (Train.Cars[j].Specs.CurrentAccelerationOutput < 0.0) { Function.Stack[s - 1] = Train.Cars[j].Specs.CurrentAccelerationOutput * (double)Math.Sign(Train.Cars[j].Specs.CurrentSpeed); } else if (Train.Cars[j].Specs.CurrentAccelerationOutput > 0.0) { Function.Stack[s - 1] = Train.Cars[j].Specs.CurrentAccelerationOutput * (double)Train.Specs.CurrentReverser.Actual; } else { Function.Stack[s - 1] = 0.0; } } else { Function.Stack[s - 1] = 0.0; } } else { Function.Stack[s - 1] = 0.0; } break; case Instructions.TrainDistance: if (Train != null) { double dist = double.MaxValue; for (int j = 0; j < Train.Cars.Length; j++) { double fx = Train.Cars[j].FrontAxle.Follower.WorldPosition.X - Position.X; double fy = Train.Cars[j].FrontAxle.Follower.WorldPosition.Y - Position.Y; double fz = Train.Cars[j].FrontAxle.Follower.WorldPosition.Z - Position.Z; double f = fx * fx + fy * fy + fz * fz; if (f < dist) dist = f; double rx = Train.Cars[j].RearAxle.Follower.WorldPosition.X - Position.X; double ry = Train.Cars[j].RearAxle.Follower.WorldPosition.Y - Position.Y; double rz = Train.Cars[j].RearAxle.Follower.WorldPosition.Z - Position.Z; double r = rx * rx + ry * ry + rz * rz; if (r < dist) dist = r; } Function.Stack[s] = Math.Sqrt(dist); } else { Function.Stack[s] = 0.0; } s++; break; case Instructions.TrainDistanceToCar: if (Train != null) { int j = (int)Math.Round(Function.Stack[s - 1]); if (j < 0) j += Train.Cars.Length; if (j >= 0 & j < Train.Cars.Length) { double x = 0.5 * (Train.Cars[j].FrontAxle.Follower.WorldPosition.X + Train.Cars[j].RearAxle.Follower.WorldPosition.X) - Position.X; double y = 0.5 * (Train.Cars[j].FrontAxle.Follower.WorldPosition.Y + Train.Cars[j].RearAxle.Follower.WorldPosition.Y) - Position.Y; double z = 0.5 * (Train.Cars[j].FrontAxle.Follower.WorldPosition.Z + Train.Cars[j].RearAxle.Follower.WorldPosition.Z) - Position.Z; Function.Stack[s - 1] = Math.Sqrt(x * x + y * y + z * z); } else { Function.Stack[s - 1] = 0.0; } } else { Function.Stack[s - 1] = 0.0; } break; case Instructions.TrainTrackDistance: if (Train != null) { int r = Train.Cars.Length - 1; double t0 = Train.Cars[0].FrontAxle.Follower.TrackPosition - Train.Cars[0].FrontAxlePosition + 0.5 * Train.Cars[0].Length; double t1 = Train.Cars[r].RearAxle.Follower.TrackPosition - Train.Cars[r].RearAxlePosition - 0.5 * Train.Cars[r].Length; Function.Stack[s] = TrackPosition > t0 ? TrackPosition - t0 : TrackPosition < t1 ? TrackPosition - t1 : 0.0; } else { Function.Stack[s] = 0.0; } s++; break; case Instructions.TrainTrackDistanceToCar: if (Train != null) { int j = (int)Math.Round(Function.Stack[s - 1]); if (j < 0) j += Train.Cars.Length; if (j >= 0 & j < Train.Cars.Length) { double p = 0.5 * (Train.Cars[j].FrontAxle.Follower.TrackPosition + Train.Cars[j].RearAxle.Follower.TrackPosition); Function.Stack[s - 1] = TrackPosition - p; } else { Function.Stack[s - 1] = 0.0; } } else { Function.Stack[s - 1] = 0.0; } break; // door case Instructions.Doors: if (Train != null) { double a = 0.0; for (int j = 0; j < Train.Cars.Length; j++) { for (int k = 0; k < Train.Cars[j].Specs.Doors.Length; k++) { if (Train.Cars[j].Specs.Doors[k].State > a) { a = Train.Cars[j].Specs.Doors[k].State; } } } Function.Stack[s] = a; } else { Function.Stack[s] = 0.0; } s++; break; case Instructions.DoorsIndex: if (Train != null) { double a = 0.0; int j = (int)Math.Round(Function.Stack[s - 1]); if (j < 0) j += Train.Cars.Length; if (j >= 0 & j < Train.Cars.Length) { for (int k = 0; k < Train.Cars[j].Specs.Doors.Length; k++) { if (Train.Cars[j].Specs.Doors[k].State > a) { a = Train.Cars[j].Specs.Doors[k].State; } } } Function.Stack[s - 1] = a; } else { Function.Stack[s - 1] = 0.0; } break; case Instructions.LeftDoors: if (Train != null) { double a = 0.0; for (int j = 0; j < Train.Cars.Length; j++) { for (int k = 0; k < Train.Cars[j].Specs.Doors.Length; k++) { if (Train.Cars[j].Specs.Doors[k].Direction == -1 & Train.Cars[j].Specs.Doors[k].State > a) { a = Train.Cars[j].Specs.Doors[k].State; } } } Function.Stack[s] = a; } else { Function.Stack[s] = 0.0; } s++; break; case Instructions.LeftDoorsIndex: if (Train != null) { double a = 0.0; int j = (int)Math.Round(Function.Stack[s - 1]); if (j < 0) j += Train.Cars.Length; if (j >= 0 & j < Train.Cars.Length) { for (int k = 0; k < Train.Cars[j].Specs.Doors.Length; k++) { if (Train.Cars[j].Specs.Doors[k].Direction == -1 & Train.Cars[j].Specs.Doors[k].State > a) { a = Train.Cars[j].Specs.Doors[k].State; } } } Function.Stack[s - 1] = a; } else { Function.Stack[s - 1] = 0.0; } break; case Instructions.RightDoors: if (Train != null) { double a = 0.0; for (int j = 0; j < Train.Cars.Length; j++) { for (int k = 0; k < Train.Cars[j].Specs.Doors.Length; k++) { if (Train.Cars[j].Specs.Doors[k].Direction == 1 & Train.Cars[j].Specs.Doors[k].State > a) { a = Train.Cars[j].Specs.Doors[k].State; } } } Function.Stack[s] = a; } else { Function.Stack[s] = 0.0; } s++; break; case Instructions.RightDoorsIndex: if (Train != null) { double a = 0.0; int j = (int)Math.Round(Function.Stack[s - 1]); if (j < 0) j += Train.Cars.Length; if (j >= 0 & j < Train.Cars.Length) { for (int k = 0; k < Train.Cars[j].Specs.Doors.Length; k++) { if (Train.Cars[j].Specs.Doors[k].Direction == 1 & Train.Cars[j].Specs.Doors[k].State > a) { a = Train.Cars[j].Specs.Doors[k].State; } } } Function.Stack[s - 1] = a; } else { Function.Stack[s - 1] = 0.0; } break; case Instructions.LeftDoorsTarget: if (Train != null) { bool q = false; for (int j = 0; j < Train.Cars.Length; j++) { if (Train.Cars[j].Specs.AnticipatedLeftDoorsOpened) { q = true; break; } } Function.Stack[s] = q ? 1.0 : 0.0; } else { Function.Stack[s] = 0.0; } s++; break; case Instructions.LeftDoorsTargetIndex: if (Train != null) { bool q = false; int j = (int)Math.Round(Function.Stack[s - 1]); if (j < 0) j += Train.Cars.Length; if (j >= 0 & j < Train.Cars.Length) { for (int k = 0; k < Train.Cars[j].Specs.Doors.Length; k++) { if (Train.Cars[j].Specs.AnticipatedLeftDoorsOpened) { q = true; break; } } } Function.Stack[s] = q ? 1.0 : 0.0; } else { Function.Stack[s - 1] = 0.0; } break; case Instructions.RightDoorsTarget: if (Train != null) { bool q = false; for (int j = 0; j < Train.Cars.Length; j++) { if (Train.Cars[j].Specs.AnticipatedRightDoorsOpened) { q = true; break; } } Function.Stack[s] = q ? 1.0 : 0.0; } else { Function.Stack[s] = 0.0; } s++; break; case Instructions.RightDoorsTargetIndex: if (Train != null) { bool q = false; int j = (int)Math.Round(Function.Stack[s - 1]); if (j < 0) j += Train.Cars.Length; if (j >= 0 & j < Train.Cars.Length) { for (int k = 0; k < Train.Cars[j].Specs.Doors.Length; k++) { if (Train.Cars[j].Specs.AnticipatedRightDoorsOpened) { q = true; break; } } } Function.Stack[s] = q ? 1.0 : 0.0; } else { Function.Stack[s - 1] = 0.0; } break; // handles case Instructions.ReverserNotch: if (Train != null) { Function.Stack[s] = (double)Train.Specs.CurrentReverser.Driver; } else { Function.Stack[s] = 0.0; } s++; break; case Instructions.PowerNotch: if (Train != null) { Function.Stack[s] = (double)Train.Specs.CurrentPowerNotch.Driver; } else { Function.Stack[s] = 0.0; } s++; break; case Instructions.PowerNotches: if (Train != null) { Function.Stack[s] = (double)Train.Specs.MaximumPowerNotch; } else { Function.Stack[s] = 0.0; } s++; break; case Instructions.BrakeNotch: if (Train != null) { if (Train.Cars[Train.DriverCar].Specs.BrakeType == TrainManager.CarBrakeType.AutomaticAirBrake) { Function.Stack[s] = (double)Train.Specs.AirBrake.Handle.Driver; } else { Function.Stack[s] = (double)Train.Specs.CurrentBrakeNotch.Driver; } } else { Function.Stack[s] = 0.0; } s++; break; case Instructions.BrakeNotches: if (Train != null) { if (Train.Cars[Train.DriverCar].Specs.BrakeType == TrainManager.CarBrakeType.AutomaticAirBrake) { Function.Stack[s] = 2.0; } else { Function.Stack[s] = (double)Train.Specs.MaximumBrakeNotch; } } else { Function.Stack[s] = 0.0; } s++; break; case Instructions.BrakeNotchLinear: if (Train != null) { if (Train.Cars[Train.DriverCar].Specs.BrakeType == TrainManager.CarBrakeType.AutomaticAirBrake) { if (Train.Specs.CurrentEmergencyBrake.Driver) { Function.Stack[s] = 3.0; } else { Function.Stack[s] = (double)Train.Specs.AirBrake.Handle.Driver; } } else if (Train.Specs.HasHoldBrake) { if (Train.Specs.CurrentEmergencyBrake.Driver) { Function.Stack[s] = (double)Train.Specs.MaximumBrakeNotch + 2.0; } else if (Train.Specs.CurrentBrakeNotch.Driver > 0) { Function.Stack[s] = (double)Train.Specs.CurrentBrakeNotch.Driver + 1.0; } else { Function.Stack[s] = Train.Specs.CurrentHoldBrake.Driver ? 1.0 : 0.0; } } else { if (Train.Specs.CurrentEmergencyBrake.Driver) { Function.Stack[s] = (double)Train.Specs.MaximumBrakeNotch + 1.0; } else { Function.Stack[s] = (double)Train.Specs.CurrentBrakeNotch.Driver; } } } else { Function.Stack[s] = 0.0; } s++; break; case Instructions.BrakeNotchesLinear: if (Train != null) { if (Train.Cars[Train.DriverCar].Specs.BrakeType == TrainManager.CarBrakeType.AutomaticAirBrake) { Function.Stack[s] = 3.0; } else if (Train.Specs.HasHoldBrake) { Function.Stack[s] = Train.Specs.MaximumBrakeNotch + 2.0; } else { Function.Stack[s] = Train.Specs.MaximumBrakeNotch + 1.0; } } else { Function.Stack[s] = 0.0; } s++; break; case Instructions.EmergencyBrake: if (Train != null) { Function.Stack[s] = Train.Specs.CurrentEmergencyBrake.Driver ? 1.0 : 0.0; } else { Function.Stack[s] = 0.0; } s++; break; case Instructions.HasAirBrake: if (Train != null) { Function.Stack[s] = Train.Cars[Train.DriverCar].Specs.BrakeType == TrainManager.CarBrakeType.AutomaticAirBrake ? 1.0 : 0.0; } else { Function.Stack[s] = 0.0; } s++; break; case Instructions.HoldBrake: if (Train != null) { Function.Stack[s] = Train.Specs.CurrentHoldBrake.Driver ? 1.0 : 0.0; } else { Function.Stack[s] = 0.0; } s++; break; case Instructions.HasHoldBrake: if (Train != null) { Function.Stack[s] = Train.Specs.HasHoldBrake ? 1.0 : 0.0; } else { Function.Stack[s] = 0.0; } s++; break; case Instructions.ConstSpeed: if (Train != null) { Function.Stack[s] = Train.Specs.CurrentConstSpeed ? 1.0 : 0.0; } else { Function.Stack[s] = 0.0; } s++; break; case Instructions.HasConstSpeed: if (Train != null) { Function.Stack[s] = Train.Specs.HasConstSpeed ? 1.0 : 0.0; } else { Function.Stack[s] = 0.0; } s++; break; // brake case Instructions.BrakeMainReservoir: if (Train != null) { Function.Stack[s] = Train.Cars[CarIndex].Specs.AirBrake.MainReservoirCurrentPressure; } else { Function.Stack[s] = 0.0; } s++; break; case Instructions.BrakeMainReservoirOfCar: if (Train == null) { Function.Stack[s - 1] = 0.0; } else { int j = (int)Math.Round(Function.Stack[s - 1]); if (j < 0) j += Train.Cars.Length; if (j >= 0 & j < Train.Cars.Length) { Function.Stack[s - 1] = Train.Cars[j].Specs.AirBrake.MainReservoirCurrentPressure; } else { Function.Stack[s - 1] = 0.0; } } break; case Instructions.BrakeEqualizingReservoir: if (Train != null) { Function.Stack[s] = Train.Cars[CarIndex].Specs.AirBrake.EqualizingReservoirCurrentPressure; } else { Function.Stack[s] = 0.0; } s++; break; case Instructions.BrakeEqualizingReservoirOfCar: if (Train == null) { Function.Stack[s - 1] = 0.0; } else { int j = (int)Math.Round(Function.Stack[s - 1]); if (j < 0) j += Train.Cars.Length; if (j >= 0 & j < Train.Cars.Length) { Function.Stack[s - 1] = Train.Cars[j].Specs.AirBrake.EqualizingReservoirCurrentPressure; } else { Function.Stack[s - 1] = 0.0; } } break; case Instructions.BrakeBrakePipe: if (Train != null) { Function.Stack[s] = Train.Cars[CarIndex].Specs.AirBrake.BrakePipeCurrentPressure; } else { Function.Stack[s] = 0.0; } s++; break; case Instructions.BrakeBrakePipeOfCar: if (Train == null) { Function.Stack[s - 1] = 0.0; } else { int j = (int)Math.Round(Function.Stack[s - 1]); if (j < 0) j += Train.Cars.Length; if (j >= 0 & j < Train.Cars.Length) { Function.Stack[s - 1] = Train.Cars[j].Specs.AirBrake.BrakePipeCurrentPressure; } else { Function.Stack[s - 1] = 0.0; } } break; case Instructions.BrakeBrakeCylinder: if (Train != null) { Function.Stack[s] = Train.Cars[CarIndex].Specs.AirBrake.BrakeCylinderCurrentPressure; } else { Function.Stack[s] = 0.0; } s++; break; case Instructions.BrakeBrakeCylinderOfCar: if (Train == null) { Function.Stack[s - 1] = 0.0; } else { int j = (int)Math.Round(Function.Stack[s - 1]); if (j < 0) j += Train.Cars.Length; if (j >= 0 & j < Train.Cars.Length) { Function.Stack[s - 1] = Train.Cars[j].Specs.AirBrake.BrakeCylinderCurrentPressure; } else { Function.Stack[s - 1] = 0.0; } } break; case Instructions.BrakeStraightAirPipe: if (Train != null) { Function.Stack[s] = Train.Cars[CarIndex].Specs.AirBrake.StraightAirPipeCurrentPressure; } else { Function.Stack[s] = 0.0; } s++; break; case Instructions.BrakeStraightAirPipeOfCar: if (Train == null) { Function.Stack[s - 1] = 0.0; } else { int j = (int)Math.Round(Function.Stack[s - 1]); if (j < 0) j += Train.Cars.Length; if (j >= 0 & j < Train.Cars.Length) { Function.Stack[s - 1] = Train.Cars[j].Specs.AirBrake.StraightAirPipeCurrentPressure; } else { Function.Stack[s - 1] = 0.0; } } break; // safety case Instructions.SafetyPluginAvailable: if (Train == TrainManager.PlayerTrain) { Function.Stack[s] = TrainManager.PlayerTrain.Specs.Safety.Mode == TrainManager.SafetySystem.Plugin ? 1.0 : 0.0; } else { Function.Stack[s] = 0.0; } s++; break; case Instructions.SafetyPluginState: if (Train == null) { Function.Stack[s - 1] = 0.0; } else { int n = (int)Math.Round(Function.Stack[s - 1]); if (Train.Specs.Safety.Mode == TrainManager.SafetySystem.Plugin) { if (n >= 0 & n < PluginManager.CurrentPlugin.Panel.Length) { Function.Stack[s - 1] = (double)PluginManager.CurrentPlugin.Panel[n]; } else { Function.Stack[s - 1] = 0.0; } } else { Function.Stack[s - 1] = 0.0; switch(n) { case 256: // ATS if (Train.Specs.Safety.Mode == TrainManager.SafetySystem.AtsSn) { if (Train.Specs.Safety.State == TrainManager.SafetyState.Normal | Train.Specs.Safety.State == TrainManager.SafetyState.Initialization) { Function.Stack[s - 1] = 1.0; } } break; case 257: // ATS RUN (separate flashing) if (Train.Specs.Safety.Mode == TrainManager.SafetySystem.AtsSn) { if (Train.Specs.Safety.State == TrainManager.SafetyState.Ringing) { Function.Stack[s - 1] = 1.0; } else if (Train.Specs.Safety.State == TrainManager.SafetyState.Emergency | Train.Specs.Safety.State == TrainManager.SafetyState.Pattern | Train.Specs.Safety.State == TrainManager.SafetyState.Service) { Function.Stack[s - 1] = 2.0; } } break; case 258: // ATS RUN (integrated flashing) if (Train.Specs.Safety.Mode == TrainManager.SafetySystem.AtsSn) { if (Train.Specs.Safety.State == TrainManager.SafetyState.Ringing) { Function.Stack[s - 1] = 1.0; } else if (Train.Specs.Safety.State == TrainManager.SafetyState.Emergency | Train.Specs.Safety.State == TrainManager.SafetyState.Pattern | Train.Specs.Safety.State == TrainManager.SafetyState.Service) { if (((int)Math.Floor(2.0 * Game.SecondsSinceMidnight) & 1) == 0) { Function.Stack[s - 1] = 1.0; } else { Function.Stack[s - 1] = 0.0; } } } break; case 259: // P POWER if ((Train.Specs.Safety.Mode == TrainManager.SafetySystem.AtsSn | Train.Specs.Safety.Mode == TrainManager.SafetySystem.AtsP) & Train.Specs.Safety.Ats.AtsPAvailable) { Function.Stack[s - 1] = 1.0; } break; case 260: // PATTERN APPROACH if (Train.Specs.Safety.Mode == TrainManager.SafetySystem.AtsP) { if (Train.Specs.Safety.State == TrainManager.SafetyState.Pattern | Train.Specs.Safety.State == TrainManager.SafetyState.Service) { Function.Stack[s - 1] = 1.0; } } break; case 261: // BRAKE RELEASE if (Train.Specs.Safety.Mode == TrainManager.SafetySystem.AtsP) { if (Train.Specs.Safety.Ats.AtsPOverride) { Function.Stack[s - 1] = 1.0; } } break; case 262: // BRAKE OPERATION if (Train.Specs.Safety.Mode == TrainManager.SafetySystem.AtsP) { if (Train.Specs.Safety.State == TrainManager.SafetyState.Service & !Train.Specs.Safety.Ats.AtsPOverride) { Function.Stack[s - 1] = 1.0; } } break; case 263: // ATS-P if (Train.Specs.Safety.Mode == TrainManager.SafetySystem.AtsP) { Function.Stack[s - 1] = 1.0; } break; case 264: // FAILURE if (Train.Specs.Safety.Mode != TrainManager.SafetySystem.None) { if (Train.Specs.Safety.State == TrainManager.SafetyState.Initialization) { Function.Stack[s - 1] = 1.0; } else if (Train.Specs.Safety.Mode == TrainManager.SafetySystem.AtsP) { if (Train.Specs.Safety.State == TrainManager.SafetyState.Ringing | Train.Specs.Safety.State == TrainManager.SafetyState.Emergency) { Function.Stack[s - 1] = 1.0; } } } break; case 265: // ATC if (Train.Specs.Safety.Mode == TrainManager.SafetySystem.Atc) { Function.Stack[s - 1] = 1.0; } break; case 266: // ATC POWER if ((Train.Specs.Safety.Mode == TrainManager.SafetySystem.Atc | Train.Specs.Safety.Mode != TrainManager.SafetySystem.None & Train.Specs.Safety.Atc.AutomaticSwitch)) { Function.Stack[s - 1] = 1.0; } break; case 267: // ATC SERVICE if (Train.Specs.Safety.Mode == TrainManager.SafetySystem.Atc) { if (Train.Specs.Safety.State == TrainManager.SafetyState.Service) { Function.Stack[s - 1] = 1.0; } } break; case 268: // ATC EMERGENCY if (Train.Specs.Safety.Mode == TrainManager.SafetySystem.Atc) { if (!Train.Specs.Safety.Atc.Transmitting) { Function.Stack[s - 1] = 1.0; } } break; case 269: // EB if (Train.Specs.Safety.Mode != TrainManager.SafetySystem.None) { if (Train.Specs.Safety.Eb.BellState == TrainManager.SafetyState.Ringing) { Function.Stack[s - 1] = 1.0; } } break; case 270: // CONST SPEED if (Train.Specs.HasConstSpeed) { if (Train.Specs.CurrentConstSpeed) { Function.Stack[s - 1] = 1.0; } } break; case 271: // atc speedometer state if (Train.Specs.Safety.Mode == TrainManager.SafetySystem.Atc) { if (!Train.Specs.Safety.Atc.Transmitting) { Function.Stack[s - 1] = 0.0; } else { if (Train.Specs.Safety.Atc.SpeedRestriction < 4.1666) { Function.Stack[s - 1] = 1.0; } else if (Train.Specs.Safety.Atc.SpeedRestriction < 6.9443) { Function.Stack[s - 1] = 2.0; } else if (Train.Specs.Safety.Atc.SpeedRestriction < 12.4999) { Function.Stack[s - 1] = 3.0; } else if (Train.Specs.Safety.Atc.SpeedRestriction < 15.2777) { Function.Stack[s - 1] = 4.0; } else if (Train.Specs.Safety.Atc.SpeedRestriction < 18.0555) { Function.Stack[s - 1] = 5.0; } else if (Train.Specs.Safety.Atc.SpeedRestriction < 20.8333) { Function.Stack[s - 1] = 6.0; } else if (Train.Specs.Safety.Atc.SpeedRestriction < 24.9999) { Function.Stack[s - 1] = 7.0; } else if (Train.Specs.Safety.Atc.SpeedRestriction < 27.7777) { Function.Stack[s - 1] = 8.0; } else if (Train.Specs.Safety.Atc.SpeedRestriction < 30.5555) { Function.Stack[s - 1] = 9.0; } else if (Train.Specs.Safety.Atc.SpeedRestriction < 33.3333) { Function.Stack[s - 1] = 10.0; } else { Function.Stack[s - 1] = 11.0; } } } else { Function.Stack[s - 1] = 12.0; } break; } } } break; // timetable case Instructions.TimetableVisible: Function.Stack[s] = Timetable.CurrentTimetable == Timetable.TimetableState.Custom & Timetable.CustomTimetableAvailable ? 0.0 : -1.0; s++; break; // sections case Instructions.SectionAspectNumber: if (IsPartOfTrain) { int nextSectionIndex = Train.CurrentSectionIndex + 1; if (nextSectionIndex >= 0 & nextSectionIndex < Game.Sections.Length) { int a = Game.Sections[nextSectionIndex].CurrentAspect; if (a >= 0 & a < Game.Sections[nextSectionIndex].Aspects.Length) { Function.Stack[s] = (double)Game.Sections[nextSectionIndex].Aspects[a].Number; } else { Function.Stack[s] = 0; } } } else if (SectionIndex >= 0 & SectionIndex < Game.Sections.Length) { int a = Game.Sections[SectionIndex].CurrentAspect; if (a >= 0 & a < Game.Sections[SectionIndex].Aspects.Length) { Function.Stack[s] = (double)Game.Sections[SectionIndex].Aspects[a].Number; } else { Function.Stack[s] = 0; } } else { Function.Stack[s] = 0; } s++; break; // default default: throw new System.InvalidOperationException("The unknown instruction " + Function.Instructions[i].ToString() + " was encountered in ExecuteFunctionScript."); } } Function.LastResult = Function.Stack[s - 1]; }
/// <summary>Changes to or from fullscreen mode.</summary> internal static void ToggleFullscreen() { Fullscreen = !Fullscreen; // begin HACK // Renderer.ClearDisplayLists(); GL.Disable(EnableCap.Fog); GL.Disable(EnableCap.Lighting); Renderer.LightingEnabled = false; if (Fullscreen) { IList <DisplayResolution> resolutions = OpenTK.DisplayDevice.Default.AvailableResolutions; for (int i = 0; i < resolutions.Count; i++) { //Test each resolution if (resolutions[i].Width == Interface.CurrentOptions.FullscreenWidth && resolutions[i].Height == Interface.CurrentOptions.FullscreenHeight && resolutions[i].BitsPerPixel == Interface.CurrentOptions.FullscreenBits) { OpenTK.DisplayDevice.Default.ChangeResolution(resolutions[i]); Program.currentGameWindow.Width = resolutions[i].Width; Program.currentGameWindow.Height = resolutions[i].Height; Screen.Width = Interface.CurrentOptions.FullscreenWidth; Screen.Height = Interface.CurrentOptions.FullscreenHeight; Program.currentGameWindow.WindowState = WindowState.Fullscreen; break; } } System.Threading.Thread.Sleep(20); if (Program.currentGameWindow.WindowState != WindowState.Fullscreen) { MessageBox.Show(Translations.GetInterfaceString("errors_fullscreen_switch1") + System.Environment.NewLine + Translations.GetInterfaceString("errors_fullscreen_switch2"), Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Hand); Fullscreen = false; } } else { OpenTK.DisplayDevice.Default.RestoreResolution(); Program.currentGameWindow.WindowState = WindowState.Normal; Program.currentGameWindow.Width = Interface.CurrentOptions.WindowWidth; Program.currentGameWindow.Height = Interface.CurrentOptions.WindowHeight; Screen.Width = Interface.CurrentOptions.WindowWidth; Screen.Height = Interface.CurrentOptions.WindowHeight; } Renderer.InitializeLighting(); Renderer.UpdateViewport(Renderer.ViewPortChangeMode.NoChange); Renderer.InitializeMotionBlur(); lock (Illustrations.Locker) { Timetable.CreateTimetable(); } Timetable.UpdateCustomTimetable(null, null); World.InitializeCameraRestriction(); if (Renderer.OptionBackfaceCulling) { GL.Enable(EnableCap.CullFace); } else { GL.Disable(EnableCap.CullFace); } Renderer.ReAddObjects(); // end HACK // //Reset the camera when switching between fullscreen and windowed mode //Otherwise, if the aspect ratio changes distortion will occur until the view is changed or the camera reset if (World.CameraMode == CameraViewMode.Interior | World.CameraMode == CameraViewMode.InteriorLookAhead) { World.CameraCurrentAlignment.Position = new OpenBveApi.Math.Vector3(0.0, 0.0, 0.0); } World.CameraCurrentAlignment.Yaw = 0.0; World.CameraCurrentAlignment.Pitch = 0.0; World.CameraCurrentAlignment.Roll = 0.0; }