// get opengl texture index internal static int GetTextureIndex(FontType FontType, int Codepoint) { int Font = (int)FontType; string t = char.ConvertFromUtf32(Codepoint); int i = char.ConvertToUtf32(t, 0); if (i >= Characters[Font].Length || Characters[Font][i].Texture == -1) { if (Characters[Font].Length == 0) { Characters[Font] = new Character[i + 1]; for (int j = 0; j <= i; j++) { Characters[Font][j].Texture = -1; } } while (i >= Characters[Font].Length) { int n = Characters[Font].Length; Array.Resize <Character>(ref Characters[Font], 2 * n); for (int j = n; j < 2 * n; j++) { Characters[Font][j].Texture = -1; } } float s1; switch (Font) { case 0: s1 = ExtraSmallFontSize; break; case 1: s1 = SmallFontSize; break; case 2: s1 = MediumFontSize; break; case 3: s1 = LargeFontSize; break; case 4: s1 = ExtraLargeFontSize; break; default: s1 = SmallFontSize; break; } int s0w = Interface.RoundToPowerOfTwo((int)Math.Ceiling((double)s1 * 1.25)); int s0h = s0w; FontStyle fs = Font == 0 ? FontStyle.Regular : FontStyle.Regular; Bitmap b = new Bitmap(s0w, s0h, System.Drawing.Imaging.PixelFormat.Format24bppRgb); Graphics g = Graphics.FromImage(b); g.Clear(Color.Black); g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.ClearTypeGridFit; Font f = new Font(FontFamily.GenericSansSerif, s1, fs, GraphicsUnit.Pixel); SizeF s = g.MeasureString(t, f, s0w, StringFormat.GenericTypographic); g.DrawString(t, f, Brushes.White, 0.0f, 0.0f); g.Dispose(); Characters[Font][i].Texture = TextureManager.RegisterTexture(b, false); Characters[Font][i].Width = s.Width <= 0.05f ? 4.0f : (float)Math.Ceiling((double)s.Width); Characters[Font][i].Height = s.Height <= 0.05f ? 4.0f : (float)Math.Ceiling((double)s.Height); b.Dispose(); } return(Characters[Font][i].Texture); }
// load texture rgb private static void LoadTextureRGBforData(Bitmap Bitmap, int TextureIndex) { try { // load bytes int Width, Height, Stride; byte[] Data; { // extract clip into power-of-two bitmap if (Textures[TextureIndex].ClipWidth == 0) { Textures[TextureIndex].ClipWidth = Bitmap.Width; } if (Textures[TextureIndex].ClipHeight == 0) { Textures[TextureIndex].ClipHeight = Bitmap.Height; } Width = Interface.RoundToPowerOfTwo(Textures[TextureIndex].ClipWidth); Height = Interface.RoundToPowerOfTwo(Textures[TextureIndex].ClipHeight); Bitmap c = new Bitmap(Width, Height, GDIPixelFormat.Format24bppRgb); Graphics g = Graphics.FromImage(c); Point[] p = new Point[] { new Point(0, 0), new Point(Width, 0), new Point(0, Height) }; g.DrawImage(Bitmap, p, new Rectangle(Textures[TextureIndex].ClipLeft, Textures[TextureIndex].ClipTop, Textures[TextureIndex].ClipWidth, Textures[TextureIndex].ClipHeight), 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(); } Textures[TextureIndex].Width = Width; Textures[TextureIndex].Height = Height; Textures[TextureIndex].Data = Data; } catch (Exception ex) { Interface.AddMessage(Interface.MessageType.Error, false, "Internal error in TextureManager.cs::LoadTextureRGBForData: " + ex.Message); throw; } }
// load texture rgba private static void LoadTextureRGBAforData(Bitmap Bitmap, Color24 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 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; //Check that our image is a valid power of two int tw, th; GetImageDimensions(FileName, out tw, out th); int w = Interface.RoundToPowerOfTwo(tw); int h = Interface.RoundToPowerOfTwo(th); if (w != tw) { Interface.AddMessage(Interface.MessageType.Information, false, "The Texture: " + FileName + " has a width of " + tw + " . This is not a valid power of two."); } if (h != th) { Interface.AddMessage(Interface.MessageType.Information, false, "The Texture: " + FileName + " has a height of " + th + " . This is not a valid power of two."); } return(i); } }
// render data private static void RenderData(ref Table Table) { // prepare timetable int w = 384, h = 192; int offsetx = 0; int actualheight = h; float descriptionwidth = 256; float descriptionheight = 16; float stationnamewidth = 16; for (int k = 0; k < 2; k++) { Bitmap b = new Bitmap(w, h); Graphics g = Graphics.FromImage(b); g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias; g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.ClearTypeGridFit; g.Clear(Color.Transparent); g.FillRectangle(Brushes.White, new RectangleF(offsetx, 0, w, actualheight)); Font f = new Font(FontFamily.GenericSansSerif, 13.0f, GraphicsUnit.Pixel); Font fs = new Font(FontFamily.GenericSansSerif, 11.0f, GraphicsUnit.Pixel); Font fss = new Font(FontFamily.GenericSansSerif, 9.0f, GraphicsUnit.Pixel); // draw timetable string t; SizeF s; // description float x0 = offsetx + 8; float y0 = 8; if (k == 1) { t = DefaultTimetableDescription; g.DrawString(t, f, Brushes.Black, new RectangleF(x0, 6, descriptionwidth, descriptionheight + 8)); y0 += descriptionheight + 2; } // highest speed t = Interface.GetInterfaceString("timetable_highestspeed"); s = g.MeasureString(t, fs); g.DrawString(t, fs, Brushes.Black, x0, y0); float y0a = y0 + s.Height + 2; float x1 = x0 + s.Width + 4; for (int i = 0; i < Table.Tracks.Length; i++) { float y = y0a + 18 * i; t = Table.Tracks[i].Speed; g.DrawString(t, f, Brushes.Black, x0, y); s = g.MeasureString(t, f); float x = x0 + s.Width + 4; if (x > x1) { x1 = x; } } g.DrawLine(Pens.LightGray, new PointF(x1 - 2, 4 + descriptionheight), new PointF(x1 - 2, y0a + 18 * Table.Tracks.Length - 1)); // driving time t = Interface.GetInterfaceString("timetable_drivingtime"); s = g.MeasureString(t, fs); g.DrawString(t, fs, Brushes.Black, x1, y0); float x2 = x1 + s.Width + 4; for (int i = 0; i < Table.Tracks.Length; i++) { float y = y0a + 18 * i; if (Table.Tracks[i].Time.Hour.Length != 0) { t = Table.Tracks[i].Time.Hour; g.DrawString(t, fss, Brushes.Black, x1, y + 2); } else { t = "0"; } s = g.MeasureString(t, fss, 9999, StringFormat.GenericTypographic); float x = x1 + s.Width - 1; if (Table.Tracks[i].Time.Minute.Length != 0) { t = Table.Tracks[i].Time.Minute; g.DrawString(t, fs, Brushes.Black, x, y + 2); } else { t = "00:"; } s = g.MeasureString(t, fs, 9999, StringFormat.GenericTypographic); x += s.Width + 1; t = Table.Tracks[i].Time.Second; g.DrawString(t, fss, Brushes.Black, x, y + 2); s = g.MeasureString(t, fss, 9999, StringFormat.GenericTypographic); x += s.Width + 8; if (x > x2) { x2 = x; } } for (int i = 0; i < Table.Tracks.Length; i++) { float y = y0a + 18 * i; g.DrawLine(Pens.LightGray, new PointF(offsetx + 4, y - 1), new PointF(x2 - 2, y - 1)); } g.DrawLine(Pens.LightGray, new PointF(x2 - 2, 4 + descriptionheight), new PointF(x2 - 2, y0a + 18 * Table.Tracks.Length - 1)); // station name float y2 = y0; t = Interface.GetInterfaceString("timetable_stationname"); s = g.MeasureString(t, f); g.DrawString(t, f, Brushes.Black, x2, y2); float x3 = x2 + s.Width + 4; for (int i = 0; i < Table.Stations.Length; i++) { float y = y0 + 18 * (i + 1) + 2; g.DrawLine(Pens.LightGray, new PointF(x2 - 2, y - 1), new PointF(w - 4, y - 1)); t = Table.Stations[i].Name; if (Table.Stations[i].NameJapanese & Table.Stations[i].Name.Length > 1) { float[] sizes = new float[t.Length]; float totalsize = 0.0f; for (int j = 0; j < t.Length; j++) { sizes[j] = g.MeasureString(new string(t[j], 1), f, 9999, StringFormat.GenericTypographic).Width; totalsize += sizes[j]; } float space = (stationnamewidth - totalsize) / (float)(t.Length - 1); float x = 0.0f; for (int j = 0; j < t.Length; j++) { g.DrawString(new string(t[j], 1), f, Brushes.Black, x2 + x, y); x += sizes[j] + space; } } else { g.DrawString(t, f, Brushes.Black, x2, y); } s = g.MeasureString(t, f); { float x = x2 + s.Width + 4; if (x > x3) { x3 = x; } } } g.DrawLine(Pens.LightGray, new PointF(x3 - 2, 4 + descriptionheight), new PointF(x3 - 2, y0 + 18 * (Table.Stations.Length + 1))); if (k == 0) { stationnamewidth = x3 - x2 - 6; } // arrival time t = Interface.GetInterfaceString("timetable_arrivaltime"); s = g.MeasureString(t, f); g.DrawString(t, f, Brushes.Black, x3, y2); float x4 = x3 + s.Width + 4; for (int i = 0; i < Table.Stations.Length; i++) { float y = y0 + 18 * (i + 1) + 2; if (Table.Stations[i].Pass) { t = "00"; s = g.MeasureString(t, fs); float x = x3 + s.Width; t = " ↓"; g.DrawString(t, f, Brushes.Black, x, y); s = g.MeasureString(t, f); x += +s.Width + 4; if (x > x4) { x4 = x; } } else { if (Table.Stations[i].Arrival.Hour.Length != 0) { t = Table.Stations[i].Arrival.Hour; g.DrawString(t, fs, Brushes.Black, x3, y); } else { t = "00"; } s = g.MeasureString(t, fs); float x = x3 + s.Width; if (Table.Stations[i].Arrival.Minute.Length != 0 & Table.Stations[i].Arrival.Second.Length != 0) { t = Table.Stations[i].Arrival.Minute + ":" + Table.Stations[i].Arrival.Second; } else { t = ""; } g.DrawString(t, f, Brushes.Black, x, y); s = g.MeasureString(t, f); x += s.Width + 4; if (x > x4) { x4 = x; } } } g.DrawLine(Pens.LightGray, new PointF(x4 - 2, 4 + descriptionheight), new PointF(x4 - 2, y0 + 18 * (Table.Stations.Length + 1))); // departure time t = Interface.GetInterfaceString("timetable_departuretime"); s = g.MeasureString(t, f); g.DrawString(t, f, Brushes.Black, x4, y2); float x5 = x4 + s.Width + 4; for (int i = 0; i < Table.Stations.Length; i++) { float y = y0 + 18 * (i + 1) + 2; if (Table.Stations[i].Terminal) { t = "00"; s = g.MeasureString(t, fs); float x = x4 + s.Width; const float c0 = 4; const float c1 = 32; g.DrawLine(Pens.Black, new PointF(x + c0, y + 6), new PointF(x + c1, y + 6)); g.DrawLine(Pens.Black, new PointF(x + c0, y + 10), new PointF(x + c1, y + 10)); x += c1 + 4; if (x > x5) { x5 = x; } } else { if (Table.Stations[i].Departure.Hour.Length != 0) { t = Table.Stations[i].Departure.Hour; g.DrawString(t, fs, Brushes.Black, x4, y); } else { t = "00"; } s = g.MeasureString(t, fs); float x = x4 + s.Width; if (Table.Stations[i].Departure.Minute.Length != 0 & Table.Stations[i].Departure.Second.Length != 0) { t = Table.Stations[i].Departure.Minute + ":" + Table.Stations[i].Departure.Second; } else { t = ""; } g.DrawString(t, f, Brushes.Black, x, y); s = g.MeasureString(t, f); x += s.Width + 4; if (x > x5) { x5 = x; } } } for (int i = 0; i < Table.Stations.Length; i++) { float y = y0 + 18 * (i + 1) + 2; g.DrawLine(Pens.LightGray, new PointF(x2 - 2, y - 1), new PointF(w - 4, y - 1)); } // border if (k == 1) { g.DrawLine(Pens.Black, new PointF(offsetx + 4, 4), new PointF(offsetx + 4, y0a + 18 * Table.Tracks.Length - 1)); g.DrawLine(Pens.Black, new PointF(offsetx + 4, y0a + 18 * Table.Tracks.Length - 1), new PointF(x2 - 2, y0a + 18 * Table.Tracks.Length - 1)); g.DrawLine(Pens.Black, new PointF(offsetx + 4, 4), new PointF(w - 4, 4)); g.DrawLine(Pens.Black, new PointF(offsetx + 4, 4 + descriptionheight), new PointF(w - 4, 4 + descriptionheight)); g.DrawLine(Pens.Black, new PointF(x2 - 2, y0 + 18 * (Table.Stations.Length + 1)), new PointF(w - 4, y0 + 18 * (Table.Stations.Length + 1))); g.DrawLine(Pens.Black, new PointF(w - 4, 4), new PointF(w - 4, y0 + 18 * (Table.Stations.Length + 1))); g.DrawLine(Pens.Black, new PointF(x2 - 2, y0a + 18 * Table.Tracks.Length - 1), new PointF(x2 - 2, y0 + 18 * (Table.Stations.Length + 1))); } // measure w = (int)Math.Ceiling((double)(x5 + 1)); h = (int)Math.Ceiling((double)(y0 + 18 * (Table.Stations.Length + 1) + 4)); // description if (k == 0) { t = DefaultTimetableDescription; s = g.MeasureString(t, f, w - 16); descriptionwidth = s.Width; descriptionheight = s.Height + 2; h += (int)Math.Ceiling((double)s.Height) + 4; } // finish if (k == 0) { // measures int nw = Interface.RoundToPowerOfTwo(w); offsetx = nw - w; w = nw; actualheight = h; h = Interface.RoundToPowerOfTwo(h); } else { // create texture g.Dispose(); DefaultTimetableTexture = TextureManager.RegisterTexture(b, true); b.Dispose(); } } }