RoundToPowerOfTwo() static private method

static private RoundToPowerOfTwo ( int Value ) : int
Value int
return int
示例#1
0
        // 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);
        }
示例#2
0
 // 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;
     }
 }
示例#3
0
 // 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);
            }
        }
示例#5
0
        // 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();
                }
            }
        }