/// <summary>Renders a string to the screen.</summary> /// <param name="font">The font to use.</param> /// <param name="text">The string to render.</param> /// <param name="location">The location.</param> /// <param name="alignment">The alignment.</param> /// <param name="color">The color.</param> /// <param name="shadow">Whether to draw a shadow.</param> /// <remarks>This function sets the OpenGL blend function to glBlendFunc(Gl.GL_SRC_ALPHA, Gl.GL_ONE_MINUS_SRC_ALPHA).</remarks> public static void DrawString(OpenGlFont font, string text, Point location, TextAlignment alignment, Color128 color, bool shadow) { if (shadow) { DrawString(font, text, new Point(location.X - 1, location.Y + 1), alignment, new Color128(0.0f, 0.0f, 0.0f, 0.5f * color.A)); DrawString(font, text, location, alignment, color); } else { DrawString(font, text, location, alignment, color); } }
/// <summary>Draws a key overlay to the screen</summary> /// <param name="Left">The left co-ordinate of the top key</param> /// <param name="Top">The top co-ordinate of the top key</param> /// <param name="Width">The width of the key overlay</param> /// <param name="Font">The font to draw</param> /// <param name="Keys">The key names</param> public static void RenderKeys(int Left, int Top, int Width, OpenGlFont Font, string[][] Keys) { int py = Top; for (int y = 0; y < Keys.Length; y++) { int px = Left; for (int x = 0; x < Keys[y].Length; x++) { if (Keys[y][x] != null) { DrawRectangle(null, new Point(px - 1, py - 1), new Size(Width + 1, 17), new Color128(0.25f, 0.25f, 0.25f, 0.5f)); DrawRectangle(null, new Point(px - 1, py - 1), new Size(Width - 1, 15), new Color128(0.75f, 0.75f, 0.75f, 0.5f)); DrawRectangle(null, new Point(px, py), new Size(Width, 16), new Color128(0.5f, 0.5f, 0.5f, 0.5f)); DrawString(Font, Keys[y][x], new Point(px - 1 + Width / 2, py + 7), TextAlignment.CenterMiddle, Color128.White); } px += Width + 4; } py += 20; } }
/// <summary>Renders a string to the screen.</summary> /// <param name="font">The font to use.</param> /// <param name="text">The string to render.</param> /// <param name="location">The location.</param> /// <param name="alignment">The alignment.</param> /// <param name="color">The color.</param> /// <remarks>This function sets the OpenGL blend function to glBlendFunc(Gl.GL_SRC_ALPHA, Gl.GL_ONE_MINUS_SRC_ALPHA).</remarks> public static void DrawString(OpenGlFont font, string text, Point location, TextAlignment alignment, Color128 color) { if (text == null || font == null) { return; } /* * Prepare the top-left coordinates for rendering, incorporating the * orientation of the string in relation to the specified location. * */ int left; if ((alignment & TextAlignment.Left) == 0) { int width = 0; for (int i = 0; i < text.Length; i++) { Texture texture; OpenGlFontChar data; i += font.GetCharacterData(text, i, out texture, out data) - 1; width += data.TypographicSize.Width; } if ((alignment & TextAlignment.Right) != 0) { left = location.X - width; } else { left = location.X - width / 2; } } else { left = location.X; } int top; if ((alignment & TextAlignment.Top) == 0) { int height = 0; for (int i = 0; i < text.Length; i++) { Texture texture; OpenGlFontChar data; i += font.GetCharacterData(text, i, out texture, out data) - 1; if (data.TypographicSize.Height > height) { height = data.TypographicSize.Height; } } if ((alignment & TextAlignment.Bottom) != 0) { top = location.Y - height; } else { top = location.Y - height / 2; } } else { top = location.Y; } /* * Render the string. * */ GL.Enable(EnableCap.Texture2D); for (int i = 0; i < text.Length; i++) { Texture texture; OpenGlFontChar data; i += font.GetCharacterData(text, i, out texture, out data) - 1; if (currentHost.LoadTexture(texture, OpenGlTextureWrapMode.ClampClamp)) { GL.BindTexture(TextureTarget.Texture2D, texture.OpenGlTextures[(int)OpenGlTextureWrapMode.ClampClamp].Name); int x = left - (data.PhysicalSize.Width - data.TypographicSize.Width) / 2; int y = top - (data.PhysicalSize.Height - data.TypographicSize.Height) / 2; /* * In the first pass, mask off the background with pure black. * */ GL.BlendFunc(BlendingFactor.Zero, BlendingFactor.OneMinusSrcColor); GL.Begin(PrimitiveType.Polygon); GL.Color4(color.A, color.A, color.A, 1.0f); GL.TexCoord2(data.TextureCoordinates.Left, data.TextureCoordinates.Top); GL.Vertex2(x, y); GL.Color4(color.A, color.A, color.A, 1.0f); GL.TexCoord2(data.TextureCoordinates.Right, data.TextureCoordinates.Top); GL.Vertex2(x + data.PhysicalSize.Width, y); GL.Color4(color.A, color.A, color.A, 1.0f); GL.TexCoord2(data.TextureCoordinates.Right, data.TextureCoordinates.Bottom); GL.Vertex2(x + data.PhysicalSize.Width, y + data.PhysicalSize.Height); GL.Color4(color.A, color.A, color.A, 1.0f); GL.TexCoord2(data.TextureCoordinates.Left, data.TextureCoordinates.Bottom); GL.Vertex2(x, y + data.PhysicalSize.Height); GL.End(); /* * In the second pass, add the character onto the background. * */ GL.BlendFunc(BlendingFactor.SrcAlpha, BlendingFactor.One); GL.Begin(PrimitiveType.Polygon); GL.Color4(color.R, color.G, color.B, color.A); GL.TexCoord2(data.TextureCoordinates.Left, data.TextureCoordinates.Top); GL.Vertex2(x, y); GL.Color4(color.R, color.G, color.B, color.A); GL.TexCoord2(data.TextureCoordinates.Right, data.TextureCoordinates.Top); GL.Vertex2(x + data.PhysicalSize.Width, y); GL.Color4(color.R, color.G, color.B, color.A); GL.TexCoord2(data.TextureCoordinates.Right, data.TextureCoordinates.Bottom); GL.Vertex2(x + data.PhysicalSize.Width, y + data.PhysicalSize.Height); GL.Color4(color.R, color.G, color.B, color.A); GL.TexCoord2(data.TextureCoordinates.Left, data.TextureCoordinates.Bottom); GL.Vertex2(x, y + data.PhysicalSize.Height); GL.End(); } left += data.TypographicSize.Width; } GL.BlendFunc(BlendingFactor.SrcAlpha, BlendingFactor.OneMinusSrcAlpha); // HACK // }
// // DRAW LOADING SCREEN // /// <summary>Draws on OpenGL canvas the route/train loading screen</summary> public static void DrawLoadingScreen(OpenGlFont Font, double RouteProgress, double TrainProgress) { // begin HACK // if (!Renderer.BlendEnabled) { GL.Enable(EnableCap.Blend); GL.BlendFunc(BlendingFactor.SrcAlpha, BlendingFactor.OneMinusSrcAlpha); Renderer.BlendEnabled = true; } if (Renderer.LightingEnabled) { GL.Disable(EnableCap.Lighting); Renderer.LightingEnabled = false; } GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit); GL.PushMatrix(); // fill the screen with background colour GL.Color4(bkgR, bkgG, bkgB, bkgA); Renderer.RenderOverlaySolid(0.0, 0.0, (double)Screen.Width, (double)Screen.Height); GL.Color4(1.0f, 1.0f, 1.0f, 1.0f); // BACKGROUND IMAGE int fontHeight = (int)Font.FontSize; int logoBottom; // int versionTop; int halfWidth = Screen.Width / 2; if (TextureLoadingBkg != null) { int bkgHeight, bkgWidth; // stretch the background image to fit at least one screen dimension double ratio = (double)TextureLoadingBkg.Width / (double)TextureLoadingBkg.Height; if (Screen.Width / ratio > Screen.Height) // if screen ratio is shorter than bkg... { bkgHeight = Screen.Height; // set height to screen height bkgWidth = (int)(Screen.Height * ratio); // and scale width proprtionally } else // if screen ratio is wider than bkg... { bkgWidth = Screen.Width; // set width to screen width bkgHeight = (int)(Screen.Width / ratio); // and scale height accordingly } // draw the background image down from the top screen edge Renderer.DrawRectangle(TextureLoadingBkg, new Point((Screen.Width - bkgWidth) / 2, 0), new Size(bkgWidth, bkgHeight), Color128.White); } // if the route has no custom loading image, add the openBVE logo // (the route custom image is loaded in OldParsers/CsvRwRouteParser.cs) if (!customLoadScreen) { if (TextureLogo != null) { // place the centre of the logo at from the screen top int logoTop = (int)(Screen.Height * logoCentreYFactor - TextureLogo.Height / 2.0); logoBottom = logoTop + TextureLogo.Height; Renderer.DrawRectangle(TextureLogo, new Point((Screen.Width - TextureLogo.Width) / 2, logoTop), new Size(TextureLogo.Width, TextureLogo.Height), Color128.White); } } else { // if custom route image, no logo and leave a conventional black area below the potential logo } logoBottom = Screen.Height / 2; // take the height remaining below the logo and divide in 3 horiz. parts int blankHeight = (Screen.Height - logoBottom) / 3; // VERSION NUMBER // place the version above the first division int versionTop = logoBottom + blankHeight - fontHeight; Renderer.DrawString(Font, "Version " + ProgramVersion, new Point(halfWidth, versionTop), TextAlignment.TopMiddle, Color128.White); // for the moment, do not show any URL; would go right below the first division // DrawString(Fonts.SmallFont, "https://sites.google.com/site/openbvesim/home", // new Point(halfWidth, versionTop + fontHeight+2), // TextAlignment.TopMiddle, Color128.White); // PROGRESS MESSAGE AND BAR // place progress bar right below the second division int progressTop = Screen.Height - blankHeight; int progressWidth = Screen.Width - progrMargin * 2; double routeProgress = Math.Max(0.0, Math.Min(1.0, RouteProgress)); double trainProgress = Math.Max(0.0, Math.Min(1.0, TrainProgress)); // draw progress message right above the second division string text = Translations.GetInterfaceString( routeProgress < 1.0 ? "loading_loading_route" : (trainProgress < 1.0 ? "loading_loading_train" : "message_loading")); Renderer.DrawString(Font, text, new Point(halfWidth, progressTop - fontHeight - 6), TextAlignment.TopMiddle, Color128.White); // sum of route progress and train progress arrives up to 2.0: // => times 50.0 to convert to % double percent = 50.0 * (routeProgress + trainProgress); string percStr = percent.ToString("0") + "%"; // progress frame Renderer.DrawRectangle(null, new Point(progrMargin - progrBorder, progressTop - progrBorder), new Size(progressWidth + progrBorder * 2, fontHeight + 6), Color128.White); // progress bar Renderer.DrawRectangle(null, new Point(progrMargin, progressTop), new Size(progressWidth * (int)percent / 100, fontHeight + 4), ColourProgressBar); // progress percent Renderer.DrawString(Font, percStr, new Point(halfWidth, progressTop), TextAlignment.TopMiddle, Color128.Black); GL.PopMatrix(); }