/// <summary> /// C'tor for TextLine /// </summary> /// <param name="parent">The UIGridElement owner.</param> /// <param name="text">The text to display.</param> /// <param name="Font">The function to get the current font.</param> /// <param name="checkbox">Should this line have a checkbox at the beginning?</param> public TextLine(UIGridElement parent, string text, UI2D.Shared.GetFont Font, bool checkbox) { this.parent = parent; this.text = TextHelper.FilterInvalidCharacters(text); this.Font = Font; this.checkbox = checkbox; } // end of TextLine c'tor
public PieRecipeItem(Object item, Texture2D texture, List <PieRecipeItem> subList, UI2D.Shared.GetFont font, string label) { this.menuItem = item; this.texture = texture; this.subList = subList; this.font = font; this.label = label; }
private void GetWH(out int w, out int h) { UI2D.Shared.GetFont entryFont = UI2D.Shared.GetGameFont18Bold; w = 512; // Note: the Count + (numColumns - 1) is there to ensure we get the right height // when the count is not an exact multiple of numColumns. h = 76 + (entryFont().LineSpacing + 4) * ((list.Count + (numColumns - 1)) / numColumns); }
/// <summary> /// c'tor for normal keys. /// </summary> /// <param name="parent"></param> /// <param name="position" /// <param name="size" /// <param name="label"></param> /// <param name="Font"></param> /// <param name="keyCapColor"></param> /// <param name="value"></param> public Key(KeySet parent, Vector2 position, Vector2 size, string label, UI2D.Shared.GetFont Font, Color labelColor, Color keyCapColor, string value) { this.parent = parent; this.position = position; this.size = size; this.label = label; this.Font = Font; this.labelColor = labelColor; this.keyCapColor = keyCapColor; this.value = value; }
/// <summary> /// c'tor for keys which cause a transition. Transition can be to another KeySet /// or to deactivate the virtual keyboard. /// </summary> /// <param name="parent"></param> /// <param name="position" /// <param name="size" /// <param name="label"></param> /// <param name="Font"></param> /// <param name="keyCapColor"></param> /// <param name="OnKey"></param> public Key(KeySet parent, Vector2 position, Vector2 size, string label, UI2D.Shared.GetFont Font, Color labelColor, Color keyCapColor, OnKeyDelegate OnKey) { this.parent = parent; this.position = position; this.size = size; this.label = label; this.Font = Font; this.labelColor = labelColor; this.keyCapColor = keyCapColor; this.OnKey = OnKey; }
public Button(string label, Color color, GetTexture getTexture, UI2D.Shared.GetFont Font) { this.label = label; this.color = color; this.renderColor = color; this.getTexture = getTexture; this.Font = Font; this.state = ButtonState.Released; this.box = new AABB2D(); this.labelOffset = new Vector2(); }
} // end of Hide() public void Update() { if (texture == null) { GraphicsDevice device = BokuGame.bokuGame.GraphicsDevice; RenderTarget2D rt = UI2D.Shared.RenderTarget128_128; InGame.SetRenderTarget(rt); InGame.Clear(Color.Transparent); // Background. ScreenSpaceQuad quad = ScreenSpaceQuad.GetInstance(); Texture2D background = BokuGame.Load <Texture2D>(BokuGame.Settings.MediaPath + @"Textures\GridElements\BlackSquare"); quad.Render(background, Vector2.Zero, new Vector2(rt.Width, rt.Height), "TexturedRegularAlpha"); // Y button Vector2 size = new Vector2(64, 64); quad.Render(ButtonTextures.BButton, new Vector2(44, 24), size, "TexturedRegularAlpha"); // Text. Color color = Color.Yellow; SpriteBatch batch = UI2D.Shared.SpriteBatch; UI2D.Shared.GetFont Font = UI2D.Shared.GetGameFont24Bold; Vector2 position = new Vector2(0, 120 - Font().LineSpacing); position.X = 64 - 0.5f * Font().MeasureString(Strings.Localize("editObjectParams.back")).X; batch.Begin(); TextHelper.DrawString(Font, Strings.Localize("editObjectParams.back"), position, color); batch.End(); InGame.RestoreRenderTarget(); texture = new Texture2D(device, 128, 128, false, SurfaceFormat.Color); // Copy rendertarget result into texture. int[] data = new int[128 * 128]; rt.GetData <int>(data); texture.SetData <int>(data); } double now = Time.WallClockTotalSeconds; if (now - showTime < delayTime || hide) { // Still in delay. alpha = 0.0f; } else { // Either in fade or in full view. float t = (float)(now - showTime - delayTime) / fadeTime; alpha = Math.Min(t, 1.0f); } } // end of Update()
// constructor // @params: item icon, optional text public PieMenuSlice(Object menuItem, Texture2D iconTexture, UI2D.Shared.GetFont font, string displayText) { int textWidth = 80; Debug.Assert(iconTexture != null || font != null); this.menuItem = menuItem; this.texture = iconTexture; this.font = font; this.label = displayText; this.textBlob = new TextBlob(font, displayText, textWidth); this.sliceType = PieSelector.SliceType.single; }
public PieMenuSlice(PieRecipeItem recipe) { this.menuItem = recipe.menuItem; this.texture = recipe.texture; this.font = recipe.font; this.label = recipe.label; if (recipe.subList == null || recipe.subList.Count == 0) { this.sliceType = PieSelector.SliceType.single; } else { this.sliceType = PieSelector.SliceType.group; } }
} // end of Shared c'tor /// <summary> /// Given a font, text string and a pixel position, returns the index /// of the character nearest the pixel position when the text string /// is laid out for rendering. /// </summary> /// <param name="font">Font to be used for measuring</param> /// <param name="str">Text string</param> /// <param name="pixelPos">Position in pixels</param> /// <returns></returns> public int FindCharAtWidth(UI2D.Shared.GetFont Font, string str, int pixelPos) { int charPos = 0; for (int i = 0; i < str.Length; i++) { int x = (int)Font().MeasureString(str.Substring(0, i)).X; if (x >= pixelPos) { break; } ++charPos; } return(charPos); } // end of FindCharAtWidth()
} // end of RefreshRT() /// <summary> /// Renders the buttons label onto the button textures. /// /// </summary> /// <param name="buttonIndex"></param> /// <returns>True if label fits, false if it's too big.</returns> static bool RenderLabelButton(int buttonIndex) { bool fits = true; string line1 = buttons[buttonIndex].Label; string line2 = null; UI2D.Shared.GetFont Font = UI2D.Shared.GetGameFont24; int margin = 8; int width = 128 - 2 * margin; Vector2 size1 = Font().MeasureString(line1); Vector2 size2 = Vector2.Zero; // Need to split into 2 lines? if (size1.X > width * splitThreshold) { SplitString(Font, buttons[buttonIndex].Label, out line1, out line2); if (line2 != null) { size1 = Font().MeasureString(line1); size2 = Font().MeasureString(line2); } } // Calc position. This assumes a single line. Vector2 pos = new Vector2(margin + buttonIndex * GUIButton.DefaultSize.X, (int)((GUIButton.DefaultSize.Y - size1.Y) / 2.0f)); // Adjust if we've got 2 lines. if (line2 != null) { pos.Y -= (int)(Font().LineSpacing / 2.0f); } SysFont.StartBatch(null); { fits &= RenderLine(Font, pos, line1, size1, width); if (line2 != null) { pos.Y += Font().LineSpacing; fits &= RenderLine(Font, pos, line2, size2, width); } } SysFont.EndBatch(); return(fits); } // end of LabelButton()
} // end of PreGameDesc Render() #endregion #region Internal protected override void Activate() { // Pause the game clock. // Instead of fully pausing the clock just let it run extremely slow. This still // lets updates happen as expected and results in objects appearing when they // should and the camera moving to where it needs to be. //Time.Paused = true; Time.ClockRatio = 0.0001f; base.Activate(); HelpOverlay.Push(@"PreGameDescription"); UI2D.Shared.GetFont Font = BokuGame.bokuGame.GraphicsDevice.Viewport.Height < 720 ? UI2D.Shared.GetGameFont18Bold : UI2D.Shared.GetGameFont24Bold; blob = new TextBlob(Font, Terrain.Current.XmlWorldData.name + "\n\n" + Terrain.Current.XmlWorldData.description, (int)(BokuGame.bokuGame.GraphicsDevice.Viewport.Width / 2)); blob.Justification = Terrain.Current.XmlWorldData.descJustification; } // end of PreGameDesc Activate()
} // end of RenderLine() /// <summary> /// Tries to split the input string into 2 strings as balanced as possible. /// In this case "balanced" means trying to make each substring as close as /// possible to the same length. /// </summary> /// <param name="Font"></param> /// <param name="input"></param> /// <param name="line1">First substring.</param> /// <param name="line2">Second substring. May be null.</param> static void SplitString(UI2D.Shared.GetFont Font, string input, out string line1, out string line2) { input = input.Trim(); // Clean off whitespace since it can throw off calculations. line1 = input; line2 = null; int bestIndex = 0; float bestRatio = float.MaxValue; // Ratio of substring lengths. Always flipped so ration >= 1.0. Lower values are better. int index = -1; while (true) { index = input.IndexOf(' ', index + 1); if (index == -1) { // No more spaces found. break; } // Split the line base on the space at i. line1 = input.Substring(0, index); line2 = input.Substring(index + 1); float ratio = Font().MeasureString(line1).X / Font().MeasureString(line2).X; if (ratio < 1) { ratio = 1 / ratio; } if (ratio < bestRatio) { bestRatio = ratio; bestIndex = index; } } if (bestIndex != -1) { // Split the string based on the best index. line1 = input.Substring(0, bestIndex); line2 = input.Substring(bestIndex + 1); } } // end of SplitString()
public ItemScroller(Vector2 pos, Vector2 size, Color baseColor, GetTexture getTexture, UI2D.Shared.GetFont Font) { this.scrollItems = new List <ScrollContainer>(); this.color_bg = baseColor.ToVector4(); this.renderColor = baseColor.ToVector4(); this.getTexture = getTexture; this.Font = Font; this.state = ButtonState.Released; this.FixedSize = size; this.relativePosition = pos; GraphicsDevice device = BokuGame.bokuGame.GraphicsDevice; this.originalDeviceViewport = device.Viewport; // Since we're rendering to a 1280*720 rendertarget. this.uiCamera.Resolution = new Point(1280, 720); }
} // end of ActorMenuItem c'tor public override void Render(Camera camera) { base.Render(camera); // Add a text label if it exists and we're not getting the texture from cardspace. if (name != null && !TextureIsFromCardSpace) { UI2D.Shared.GetFont Font = UI2D.Shared.GetCardLabel; SpriteBatch batch = UI2D.Shared.SpriteBatch; Point pixelPos = camera.WorldToScreenCoords(worldMatrix.Translation); Vector2 pos = new Vector2(pixelPos.X, pixelPos.Y); name = TextHelper.FilterInvalidCharacters(name); pos.X -= (int)Font().MeasureString(name).X / 2; pos.Y += 42; Color newBlack = new Color(20, 20, 20); batch.Begin(); TextHelper.DrawString(Font, name, pos, newBlack); batch.End(); } // Show the Y button. if (DisplayHelpButton) { Vector3 loc = MyMath.Lerp(worldMatrix.Translation, pieCenter, 0.4f); Point pixelPos = camera.WorldToScreenCoords(loc); Vector2 pos = new Vector2(pixelPos.X, pixelPos.Y); Vector2 size = new Vector2(BokuGame.bokuGame.GraphicsDevice.Viewport.Height / 12.0f); // Center button. pos -= size * (40.0f / 64.0f) / 2.0f; ScreenSpaceQuad ssquad = ScreenSpaceQuad.GetInstance(); ssquad.Render(ButtonTextures.YButton, pos, size, "TexturedRegularAlpha"); DisplayHelpButton = false; } } // end of ActorMenuItem Render()
} // end of LabelButton() /// <summary> /// Returns true if line fits with reasonable compression. False if compressed too much. /// </summary> /// <param name="Font"></param> /// <param name="pos"></param> /// <param name="line"></param> /// <param name="size"></param> /// <param name="width"></param> /// <returns></returns> static bool RenderLine(UI2D.Shared.GetFont Font, Vector2 pos, string line, Vector2 size, int width) { Vector2 scale = Vector2.One; if (size.X > width) { // Need to compress. scale.X = width / size.X; } else { // No compression, just center. pos.X += (int)((width - size.X) / 2.0f); } RectangleF rect = new RectangleF(pos.X, pos.Y, width, 96); SysFont.DrawString(line, pos, rect, Font().systemFont, Color.Black, scale, outlineColor: Color.White, outlineWidth: 1.5f); pos.Y += GUIButton.DefaultSize.Y; rect.Y += GUIButton.DefaultSize.Y; SysFont.DrawString(line, pos, rect, Font().systemFont, Color.Black, scale, outlineColor: Color.White, outlineWidth: 1.5f); return(scale.X > 0.5f); } // end of RenderLine()
// Add a simple slice to the main pie public void AddSlice(Object menuItem, Texture2D iconTexture, UI2D.Shared.GetFont font, string displaytext) { PieMenuSlice slice = new PieMenuSlice(menuItem, iconTexture, font, displaytext); this.rootDisk.AddSlice(slice); }
/// <summary> /// Long for c'tor for use with a drop shadow. /// </summary> /// <param name="width"></param> /// <param name="height"></param> /// <param name="edgeSize"></param> /// <param name="normalMapName"></param> /// <param name="baseColor"></param> /// <param name="label"></param> /// <param name="justify"></param> /// <param name="textColor"></param> /// <param name="dropShadowColor"></param> /// <param name="invertDropShadow"></param> public UIGrid2DTextElement(float width, float height, float edgeSize, string normalMapName, Color baseColor, string label, UI2D.Shared.GetFont Font, Justification justify, Color textColor, Color dropShadowColor, bool invertDropShadow) { this.width = width; this.height = height; this.edgeSize = edgeSize; this.baseColor = baseColor.ToVector4(); this.normalMapName = normalMapName; this.Font = Font; this.label = TextHelper.FilterInvalidCharacters(label); this.justify = justify; this.textColor = textColor; this.dropShadowColor = dropShadowColor; useDropShadow = true; this.invertDropShadow = invertDropShadow; }
} // end of Clear() private static void RefreshTexture() { bool lores = BokuGame.ScreenSize.Y <= 480; UI2D.Shared.GetFont Font = UI2D.Shared.GetGameFont24Bold; if (lores) { Font = UI2D.Shared.GetGameFont30Bold; } blob.Font = Font; ScreenSpaceQuad ssquad = ScreenSpaceQuad.GetInstance(); RenderTarget2D rt = UI2D.Shared.RenderTarget512_302; InGame.SetRenderTarget(rt); InGame.Clear(Color.Transparent); ssquad.Render(background, Vector2.Zero, new Vector2(512, 302), "TexturedRegularAlpha"); // Tile name. SpriteBatch batch = UI2D.Shared.SpriteBatch; Vector2 pos = new Vector2(margin, margin); /* * batch.Begin(); * TextHelper.DrawString(Font, curTip, pos, Color.Yellow); * batch.End(); */ string desc = blob.RawText; // Save string we're displaying. blob.RawText = curTip; if (blob.HasRtoL) { blob.Justification = Boku.UI2D.UIGridElement.Justification.Right; } blob.RenderWithButtons(pos, Color.Yellow); blob.RawText = desc; // Restore // We need to special case groups since they don't have any data. For groups // we just display a string that says "press <a> for more..." if (curTip == Strings.Localize("toolTips.group")) { blob = new TextBlob(Font, Strings.Localize("toolTips.groupDesc"), 512 - margin * 2); blob.Justification = Boku.UI2D.UIGridElement.Justification.Center; pos = new Vector2(0, (302 - Font().LineSpacing) / 2); blob.RenderWithButtons(pos, Color.White); } else { // Normal ToolTip. // Text description. if (blob != null) { int maxLines = showButtons ? (lores ? 3 : 4) : (lores ? 4 : 6); // Modify final line to end with ellipsis. blob.AddEllipsisToLine(maxLines - 1); // Move down to account for title. pos.Y += Font().LineSpacing; // If less than maxLines of text, center on texture. int spareLines = maxLines - blob.NumLines - 1; if (spareLines > 0) { pos.Y += spareLines * 0.5f * Font().LineSpacing; } // Right justify if RtoL if (blob.HasRtoL) { blob.Justification = Boku.UI2D.UIGridElement.Justification.Right; } blob.RenderWithButtons(pos, Color.White, maxLines: maxLines); } // Buttons @ bottom if (showButtons) { string aText = useAdd ? Strings.Localize("toolTips.add") : Strings.Localize("toolTips.change"); int buttonWidth = 40; // For spacing. Vector2 buttonSize = new Vector2(64, 64); // For rendering. pos.Y = 302 - margin - Font().LineSpacing; int aTextWidth = (int)Font().MeasureString(aText).X; int yTextWidth = (int)Font().MeasureString(Strings.Localize("toolTips.examples")).X; int width = 3 * buttonWidth + aTextWidth + yTextWidth; pos.X = (512 - width) / 2; batch.Begin(); ssquad.Render(ButtonTextures.AButton, pos, buttonSize, "TexturedRegularAlpha"); pos.X += buttonWidth; TextHelper.DrawString(Font, aText, pos, Color.White); pos.X += buttonWidth + aTextWidth; ssquad.Render(ButtonTextures.YButton, pos, buttonSize, "TexturedRegularAlpha"); pos.X += buttonWidth; TextHelper.DrawString(Font, Strings.Localize("toolTips.examples"), pos, Color.White); batch.End(); } } InGame.RestoreRenderTarget(); // // Copy result to local texture. // int[] data = new int[512 * 302]; rt.GetData <int>(data); texture.SetData <int>(data); // Scale size to 1/4 screen height. int w = (int)BokuGame.ScreenSize.X; int h = (int)BokuGame.ScreenSize.Y; float scale = h / 4.0f / 302.0f; size = new Vector2(512, 302); size *= scale; // Check position to keep on screen within 10% safe area. // Horizontal int safe = (int)(w * 0.05f); if (pendingPosition.X < safe) { pendingPosition.X = safe; } else if (pendingPosition.X > w - safe - size.X) { pendingPosition.X = w - safe - size.X; } // Vertical safe = (int)(h * 0.05f); if (pendingPosition.Y < safe) { pendingPosition.Y = safe; } else if (pendingPosition.Y > h - safe - size.Y) { pendingPosition.Y = h - safe - size.Y; } dirty = false; } // end of RefreshTexture()
public override void Render(Camera camera) { GraphicsDevice device = BokuGame.bokuGame.GraphicsDevice; RenderTarget2D rtFull = UI2D.Shared.RenderTargetDepthStencil1280_720; // Rendertarget we render whole display into. RenderTarget2D rt1k = UI2D.Shared.RenderTargetDepthStencil1024_768; Vector2 screenSize = BokuGame.ScreenSize; Vector2 rtSize = new Vector2(rtFull.Width, rtFull.Height); CameraSpaceQuad csquad = CameraSpaceQuad.GetInstance(); ScreenSpaceQuad ssquad = ScreenSpaceQuad.GetInstance(); Color greyTextColor = new Color(127, 127, 127); Color shadowTextColor = new Color(0, 0, 0, 20); Color greenTextColor = new Color(0, 255, 12); Color whiteTextColor = new Color(255, 255, 255); Vector2 shadowOffset = new Vector2(0, 6); // Render the description text and examples into the 1k rendertarget. InGame.SetRenderTarget(rt1k); InGame.Clear(Color.Transparent); SpriteBatch batch = UI2D.Shared.SpriteBatch; UI2D.Shared.GetFont FontHuge = UI2D.Shared.GetGameFont20; // Set up params for rendering UI with this camera. Fx.ShaderGlobals.SetCamera(shared.camera1k); // // Render the samples grid. // bool noExamples = shared.examplesGrid == null || shared.examplesGrid.ActualDimensions == Point.Zero; if (!noExamples) { // Clear the stencil buffer. device.Clear(ClearOptions.Stencil, Color.Transparent, 1.0f, 0); // Render the new stencil mask. Magic numbers from Photoshop. ssquad.RenderStencil(Vector4.One, new Vector2(100, 300), new Vector2(820, 400)); // Turn off stencil writing while rendering the grid. device.DepthStencilState = depthStencilStateNoWrite; shared.examplesGrid.Render(shared.camera1k); // Restore default. device.DepthStencilState = DepthStencilState.Default; } // Render the scene to our rendertarget. InGame.SetRenderTarget(rtFull); // Set up params for rendering UI with this camera. Fx.ShaderGlobals.SetCamera(shared.camera); InGame.Clear(Color.Transparent); // Set up effect for rendering tiles. effect.CurrentTechnique = effect.Techniques["NormalMappedNoTexture"]; effect.Parameters["Alpha"].SetValue(1.0f); effect.Parameters["SpecularColor"].SetValue(Vector4.Zero); effect.Parameters["SpecularPower"].SetValue(16.0f); effect.Parameters["NormalMap"].SetValue(normalMap); // Render tiles. Matrix world = Matrix.Identity; world.Translation = new Vector3(-3.4f, 2.5f, 0.0f); effect.Parameters["WorldMatrix"].SetValue(world); effect.Parameters["WorldViewProjMatrix"].SetValue(world * shared.camera.ViewProjectionMatrix); effect.Parameters["DiffuseColor"].SetValue(new Vector4(1.0f, 1.0f, 1.0f, 0.2f)); glassTile.Render(effect); world.Translation = new Vector3(1.15f, 2.5f, 0.0f); effect.Parameters["WorldMatrix"].SetValue(world); effect.Parameters["WorldViewProjMatrix"].SetValue(world * shared.camera.ViewProjectionMatrix); effect.Parameters["DiffuseColor"].SetValue(new Vector4(1.0f, 1.0f, 1.0f, 1.0f)); descTile.Render(effect); world.Translation = new Vector3(0.0f, -1.1f, 0.0f); effect.Parameters["WorldMatrix"].SetValue(world); effect.Parameters["WorldViewProjMatrix"].SetValue(world * shared.camera.ViewProjectionMatrix); effect.Parameters["DiffuseColor"].SetValue(new Vector4(0.0f, 0.0f, 0.0f, 1.0f)); examplesTile.Render(effect); // Render highlights on tiles. CameraSpaceQuad quad = CameraSpaceQuad.GetInstance(); device.BlendState = UI2D.Shared.BlendStateColorWriteRGB; // Glass tile. quad.Render(shared.camera, glassTileHighlight, Vector4.One, 1.0f, new Vector2(-3.4f, 2.9f), new Vector2(2.02f, 1.25f), "TexturedRegularAlpha"); // Desc tile. quad.Render(shared.camera, whiteHighlight, new Vector4(0.6f, 1.0f, 0.8f, 0.2f), 1.0f, new Vector2(1.15f, 1.85f), new Vector2(6.52f, 0.7f), "TexturedRegularAlpha"); // Examples tile. quad.Render(shared.camera, blackHighlight, Vector4.One, 1.0f, new Vector2(0.0f, 0.3f), new Vector2(8.82f, 2.0f), "TexturedRegularAlpha"); device.BlendState = BlendState.AlphaBlend; // Actor Icon. if (shared.actorHelp.upid != null) { Texture2D actorImage = CardSpace.Cards.CardFaceTexture(shared.actorHelp.upid); if (actorImage != null) { quad.Render(shared.camera, actorImage, new Vector2(-3.4f, 2.5f), new Vector2(1.8f, 1.8f), @"TexturedRegularAlpha"); } } // Stick Icons. ssquad.Render(leftStickTexture, new Vector2(181, 560), new Vector2(leftStickTexture.Width, leftStickTexture.Height), @"TexturedRegularAlpha"); Vector2 min = new Vector2(181, 560); Vector2 max = min + new Vector2(leftStickTexture.Width, leftStickTexture.Height); shared.leftStickBox.Set(min, max); if (shared.descBlob.NumLines > 3) { ssquad.Render(rightStickTexture, new Vector2(1036, 70), new Vector2(rightStickTexture.Width, rightStickTexture.Height), @"TexturedRegularAlpha"); min = new Vector2(1036, 70); max = min + new Vector2(rightStickTexture.Width, rightStickTexture.Height); shared.rightStickBox.Set(min, max); } // A button ssquad.Render(ButtonTextures.AButton, new Vector2(1000, 245), new Vector2(80, 80), "TexturedRegularAlpha"); shared.chooseBox.Set(new Vector2(990 - UI2D.Shared.GetGameFont24().MeasureString(Strings.Localize("helpCard.choose")).X, 245), new Vector2(1060, 245 + 55)); // Text labels. // Actor description // Render the new stencil mask. Magic numbers from Photoshop. ssquad.RenderStencil(Vector4.One, new Vector2(310, 75), new Vector2(590, 140)); device.DepthStencilState = depthStencilState; // Description. if (shared.descBlob != null) { Vector2 pos = new Vector2(shared.descMargin, shared.descTop + shared.descOffset); pos.X = 450; shared.descBlob.RenderWithButtons(pos, greyTextColor, maxLines: 3); } // Restore DepthStencilState to default. device.DepthStencilState = DepthStencilState.Default; batch.Begin(); // Actor name TextHelper.DrawString(UI2D.Shared.GetGameFont30Bold, shared.curActorName, new Vector2(450, 30) + shadowOffset, shadowTextColor); TextHelper.DrawString(UI2D.Shared.GetGameFont30Bold, shared.curActorName, new Vector2(450, 30), greyTextColor); // Create TextHelper.DrawString(UI2D.Shared.GetGameFont24Bold, Strings.Localize("helpCard.create"), new Vector2(268, 250), whiteTextColor); // Choose TextHelper.DrawString(UI2D.Shared.GetGameFont24, Strings.Localize("helpCard.choose"), new Vector2(990 - UI2D.Shared.GetGameFont24().MeasureString(Strings.Localize("helpCard.choose")).X, 250), greyTextColor); batch.End(); // Now render the contents of the rt1k texture but with the edges blended using the mask. Vector4 limits = new Vector4(0.4f, 0.41f, 0.857f, 0.93f); ssquad.RenderWithYLimits(rt1k, limits, new Vector2((rtFull.Width - rt1k.Width) / 2, 0), new Vector2(rt1k.Width, rtFull.Height), @"TexturedPreMultAlpha"); // Restore rt for final rendering. InGame.RestoreRenderTarget(); device.Clear(ClearOptions.DepthBuffer, Color.Pink, 1.0f, 0); // Start by using the blurred version of the scene as a backdrop. if (!shared.thumbnail.GraphicsDevice.IsDisposed) { //InGame.Clear(Color.Transparent); ssquad.Render(shared.thumbnail, Vector2.Zero, new Vector2(device.Viewport.Width, device.Viewport.Height), @"TexturedNoAlpha"); } else { Color backgroundColor = new Color(16, 66, 52); // 1/4 strength turquoise. InGame.Clear(backgroundColor); } // Copy the rendered scene to the rendertarget. float rtAspect = rtSize.X / rtSize.Y; Vector2 position = Vector2.Zero; Vector2 newSize = screenSize; newSize.X = rtAspect * newSize.Y; position.X = (screenSize.X - newSize.X) / 2.0f; ssquad.Render(rtFull, position + BokuGame.ScreenPosition, newSize, @"TexturedRegularAlpha"); } // end of AddItemHelpCard RenderObj Render()
} // end of OnExitTutorial() public static void PreRender() { // Decide which font to use based on screen width. UI2D.Shared.GetFont prevFont = font; font = BokuGame.ScreenSize.X > 1280 ? UI2D.Shared.GetGameFont24Bold : UI2D.Shared.GetGameFont18Bold; // Did the font or window size change? If so, reallocate the rendertarget. if (font != prevFont || rt == null || BokuGame.ScreenSize.X > rt.Width) { InGame.RelRT("TutorialRT", rt); BokuGame.Release(ref rt); CreateRenderTarget(); } if (backdrop == null || rt == null) { return; } ScreenSpaceQuad quad = ScreenSpaceQuad.GetInstance(); InGame.SetRenderTarget(rt); // Clear and add highlight. quad.Render(backdrop, Vector2.Zero, new Vector2(rt.Width, rt.Height), "TexturedRegularAlpha"); if (Active) { int indent = 10; // Lazy allocation. if (titleBlob == null) { titleBlob = new TextBlob(font, "test", (int)(rt.Width - 2.0f * indent)); //titleBlob.ProgrammingTileBackdrop = true; } if (instructionBlob == null) { instructionBlob = new TextBlob(font, "test", (int)(rt.Width - 2.0f * indent)); //instructionBlob.ProgrammingTileBackdrop = true; } // Font may have changed, keep the blobs up to date. titleBlob.Font = font; instructionBlob.Font = font; // Raw strings to put into blobs. string titleStr = null; string instructionStr = null; // We only care about the non-modal text if there's no modal display. // TODO We could think about displaying this under the modal display but we'd have to // add a drop shadow first to avoid cluttering things up. if (!modalDisplay.Active) { // We should only display text when the tutorial mode is fully open. bool display = targetPositionY > 1 && BokuGame.ScreenPosition.Y > targetPositionY - 2.0f; if (display) { if (curCrumb != null || targetModeReached) { // First line should be the goal of this section of the tutorial. High level. titleStr = curStep.GoalText; // Second line is either from the crumb telling us where to go OR from the step telling us what to do now that we're here. if (curCrumb == null) { if (GamePadInput.ActiveMode == GamePadInput.InputMode.KeyboardMouse) { instructionStr = curStep.MouseText; } else if (GamePadInput.ActiveMode == GamePadInput.InputMode.Touch) { instructionStr = curStep.TouchText; } else // gamepad { instructionStr = curStep.GamepadText; } } else { if (GamePadInput.ActiveMode == GamePadInput.InputMode.KeyboardMouse) { instructionStr = curCrumb.MouseText; } else if (GamePadInput.ActiveMode == GamePadInput.InputMode.Touch) { instructionStr = curCrumb.TouchText; } else // gamepad { instructionStr = curCrumb.GamepadText; } } #if DEBUG // Add in some debug info. //instructionStr += "\nCurMode = " + curGameMode.ToString() + " curTargetMode = " + curStep.TargetMode.ToString(); #endif } else { if (DebugMode) { // We've got no crumb. Need to add one! instructionStr = "Missing Crumb!"; // Add in some debug info. instructionStr += "\nCurMode = " + curGameMode.ToString() + " HelpOverlay = " + HelpOverlay.Peek() + "\nUpdateMode = " + InGame.inGame.CurrentUpdateMode.ToString(); if (curStep != null) { instructionStr += "\nTargetMode = " + curStep.TargetMode; } } } // Render text blob. // TODO Center text vertically and if fewer lines, increase the spacing a bit. titleBlob.RawText = titleStr; instructionBlob.RawText = instructionStr; //Color titleColor = new Color(50, 255, 50); // Same green as the hover text color we user elsewhere. Color titleColor = new Color(20, 20, 20); // Not quite black. //Color titleColor = new Color(250, 190, 50); // Amber. Color shadowColor = new Color(0, 0, 0, 40); Color lightGrey = new Color(200, 200, 200); Color darkGrey = new Color(100, 100, 100); Color textColor = darkGrey; if (DebugMode && curGameMode == GameMode.Unknown) { textColor = Color.Red; } titleBlob.RenderWithButtons(new Vector2(indent, 0), titleColor, shadowColor, new Vector2(0, 2), maxLines: 4); // Vertically center the instruction text. int yOffset = 0; if (instructionBlob.NumLines == 1) { yOffset = instructionBlob.TotalSpacing; } else if (instructionBlob.NumLines == 2) { yOffset = (int)(instructionBlob.TotalSpacing / 2.0f); } instructionBlob.RenderWithButtons(new Vector2(indent, titleBlob.TotalSpacing + yOffset - 2), textColor, shadowColor, new Vector2(0, 2), maxLines: 4); } // end if display true } // end if not modal active } // end if tutorial mode active InGame.RestoreRenderTarget(); } // end of PreRender()
} // end of UIGridModularRadioBoxElement Update() public void RefreshTexture() { if (dirty || diffuse.IsContentLost) { InGame.SetRenderTarget(diffuse); InGame.Clear(Color.White); int w = diffuse.Width; int h = diffuse.Height; ScreenSpaceQuad quad = ScreenSpaceQuad.GetInstance(); // Render the white background. Vector2 position = Vector2.Zero; Vector2 size = new Vector2(w, radioWhite.Height); quad.Render(radioWhite, position, size, "TexturedNoAlpha"); // And the black parts. position.Y = 70; size.Y = h - 70; quad.Render(middleBlack, position, size, "TexturedRegularAlpha"); position.Y = 64; size.Y = radioBlack.Height; quad.Render(radioBlack, position, size, "TexturedRegularAlpha"); // Disable writing to alpha channel. // This prevents transparent fringing around the text. GraphicsDevice device = BokuGame.bokuGame.GraphicsDevice; device.BlendState = UI2D.Shared.BlendStateColorWriteRGB; // Render the label and value text into the texture. int margin = 0; position.X = 0; position.Y = (int)((64 - Font().LineSpacing) / 2.0f); int textWidth = (int)(Font().MeasureString(label).X); justify = Justification.Center; position.X = TextHelper.CalcJustificationOffset(margin, w, textWidth, justify); Color labelColor = new Color(127, 127, 127); Color valueColor = new Color(140, 200, 63); Color shadowColor = new Color(0, 0, 0, 20); Vector2 shadowOffset = new Vector2(0, 6); Color entryColor = new Color(200, 200, 200); Color selectedColor = new Color(0, 255, 12); SpriteBatch batch = UI2D.Shared.SpriteBatch; batch.Begin(); // Title. TextHelper.DrawString(Font, label, position + shadowOffset, shadowColor); TextHelper.DrawString(Font, label, position, labelColor); // Entries. UI2D.Shared.GetFont entryFont = UI2D.Shared.GetGameFont18Bold; if (numColumns == 1) { position.Y = 70; Vector2 min = Vector2.Zero; Vector2 max = Vector2.One; for (int i = 0; i < list.Count; i++) { position.X = (512 - entryFont().MeasureString(list[i].Text).X) / 2; TextHelper.DrawString(entryFont, list[i].Text, position, curIndex == i ? selectedColor : entryColor); if (showIndicators) { int vert = 5; if (curIndex == i) { quad.Render(indicatorLit, new Vector2(30, position.Y + vert), new Vector2(indicatorLit.Width, indicatorLit.Height), "TexturedRegularAlpha"); quad.Render(indicatorLit, new Vector2(512 - 30 - indicatorLit.Width, position.Y + vert), new Vector2(indicatorLit.Width, indicatorLit.Height), "TexturedRegularAlpha"); } else { quad.Render(indicatorUnlit, new Vector2(30, position.Y + vert), new Vector2(indicatorUnlit.Width, indicatorUnlit.Height), "TexturedRegularAlpha"); quad.Render(indicatorUnlit, new Vector2(512 - 30 - indicatorLit.Width, position.Y + vert), new Vector2(indicatorUnlit.Width, indicatorUnlit.Height), "TexturedRegularAlpha"); } } min.Y = position.Y / h; position.Y += entryFont().LineSpacing + 4; max.Y = position.Y / h; if (list[i].Box == null) { list[i].Box = new AABB2D(min, max); } else { list[i].Box.Set(min, max); } } } else if (numColumns == 2) { // Probably not as general as we'd like but I think this only // get used for the language options so just do what we need // to get all the languages to fit. // For column 0, left justify. // For column 1, right justify. for (int column = 0; column < numColumns; column++) { position.Y = 70; int width = 512 / numColumns; int center = width / 2 + column * width; int itemsPerColumn = (list.Count + (numColumns - 1)) / numColumns; int minIndex = column * itemsPerColumn; int maxIndex = Math.Min(list.Count, (column + 1) * itemsPerColumn); // Min/max values ine 0..1 range across rt. Vector2 min = new Vector2((center - width / 2.0f) / w, 0); Vector2 max = new Vector2((center + width / 2.0f) / w, 1); for (int i = minIndex; i < maxIndex; i++) { position.X = (int)(center - (entryFont().MeasureString(list[i].Text).X) / 2); int edgeMargin = 8; if (column == 0) { position.X = edgeMargin; } else { position.X = (int)(512 - edgeMargin - entryFont().MeasureString(list[i].Text).X); } TextHelper.DrawString(entryFont, list[i].Text, position, curIndex == i ? selectedColor : entryColor); min.Y = position.Y / h; position.Y += entryFont().LineSpacing + 4; max.Y = position.Y / h; if (list[i].Box == null) { list[i].Box = new AABB2D(min, max); } else { list[i].Box.Set(min, max); } } } } else { Debug.Assert(false, "numColumns must be 1 or 2, nothing else is supported."); } batch.End(); // Restore default blend state. device.BlendState = BlendState.AlphaBlend; // Restore backbuffer. InGame.RestoreRenderTarget(); dirty = false; } } // end of UIGridModularRadioBoxElement RefreshTexture()
private static void RefreshTexture() { RenderTarget2D rt = UI2D.Shared.RenderTargetDepthStencil1280_720; ScreenSpaceQuad quad = ScreenSpaceQuad.GetInstance(); InGame.SetRenderTarget(rt); InGame.Clear(Color.Transparent); bool showTeam = (ActiveTeam != Classification.Colors.NotApplicable); bool showPlayer = ActivePlayer != GamePadSensor.PlayerId.Dynamic; if (showTeam || showPlayer) { // Main graphic. Vector2 size = new Vector2(textureWinner.Width, textureWinner.Height); Vector2 pos = new Vector2((rt.Width - size.X) / 2.0f, 0.0f); quad.Render(textureWinner, pos, size, "TexturedPreMultAlpha"); // Team or Player. size = new Vector2(textureTeam.Width, textureTeam.Height); pos = new Vector2((rt.Width - size.X) / 2.0f, 354); quad.Render(textureTeam, pos, size, "TexturedPreMultAlpha"); string label = String.Empty; if (showTeam) { label = Strings.Localize("gameOver.team") + " "; } if (showPlayer) { // Nothing to add here. } // Get correct color for team. Texture2D glyph = null; switch (ActivePlayer) { case GamePadSensor.PlayerId.One: glyph = CardSpace.Cards.CardFaceTexture("filter.player1"); label += CardSpace.Cards.GetLabel("filter.player1"); break; case GamePadSensor.PlayerId.Two: glyph = CardSpace.Cards.CardFaceTexture("filter.player2"); label += CardSpace.Cards.GetLabel("filter.player2"); break; case GamePadSensor.PlayerId.Three: glyph = CardSpace.Cards.CardFaceTexture("filter.player3"); label += CardSpace.Cards.GetLabel("filter.player3"); break; case GamePadSensor.PlayerId.Four: glyph = CardSpace.Cards.CardFaceTexture("filter.player4"); label += CardSpace.Cards.GetLabel("filter.player4"); break; default: // Do nothing... break; } switch (ActiveTeam) { case Classification.Colors.White: glyph = CardSpace.Cards.CardFaceTexture("filter.white"); label += Strings.Localize("colorNames.white"); break; case Classification.Colors.Black: glyph = CardSpace.Cards.CardFaceTexture("filter.Black"); label += Strings.Localize("colorNames.black"); break; case Classification.Colors.Grey: glyph = CardSpace.Cards.CardFaceTexture("filter.Grey"); label += Strings.Localize("colorNames.grey"); break; case Classification.Colors.Red: glyph = CardSpace.Cards.CardFaceTexture("filter.red"); label += Strings.Localize("colorNames.red"); break; case Classification.Colors.Green: glyph = CardSpace.Cards.CardFaceTexture("filter.green"); label += Strings.Localize("colorNames.green"); break; case Classification.Colors.Blue: glyph = CardSpace.Cards.CardFaceTexture("filter.blue"); label += Strings.Localize("colorNames.blue"); break; case Classification.Colors.Orange: glyph = CardSpace.Cards.CardFaceTexture("filter.orange"); label += Strings.Localize("colorNames.orange"); break; case Classification.Colors.Yellow: glyph = CardSpace.Cards.CardFaceTexture("filter.yellow"); label += Strings.Localize("colorNames.yellow"); break; case Classification.Colors.Purple: glyph = CardSpace.Cards.CardFaceTexture("filter.purple"); label += Strings.Localize("colorNames.purple"); break; case Classification.Colors.Pink: glyph = CardSpace.Cards.CardFaceTexture("filter.pink"); label += Strings.Localize("colorNames.pink"); break; case Classification.Colors.Brown: glyph = CardSpace.Cards.CardFaceTexture("filter.brown"); label += Strings.Localize("colorNames.brown"); break; default: break; } // Grabbing the glyph from CardSpace may have changed rendertargets // since we now create them somewhat on demand. InGame.SetRenderTarget(rt); if (glyph != null) { size = new Vector2(90, 90); pos += new Vector2(7, 10); quad.Render(glyph, pos, size, "TexturedPreMultAlpha"); } // Options. if (GamePadInput.ActiveMode == GamePadInput.InputMode.GamePad) { size = new Vector2(textureOptions.Width, textureOptions.Height); pos = new Vector2((rt.Width - size.X) / 2.0f, 470); quad.Render(textureOptions, pos, size, "TexturedPreMultAlpha"); } else { size = new Vector2(textureOptionsKey.Width, textureOptionsKey.Height); pos = new Vector2((rt.Width - size.X) / 2.0f, 470); quad.Render(textureOptionsKey, pos, size, "TexturedPreMultAlpha"); // Add key face icons. Color color = new Color(20, 20, 20); TextBlob blob = new TextBlob(UI2D.Shared.GetGameFont20, "[home]", 100); blob.Justification = Boku.UI2D.UIGridElement.Justification.Center; pos.Y += 16; blob.RenderWithButtons(pos, color); homeHitBox.Set(pos, pos + new Vector2(100, blob.TotalSpacing)); blob.RawText = "[esc]"; pos.Y += 50; blob.RenderWithButtons(pos, color); editHitBox.Set(pos, pos + new Vector2(100, blob.TotalSpacing)); blob.RawText = "[enter]"; pos.Y += 50; blob.RenderWithButtons(pos, color); restartHitBox.Set(pos, pos + new Vector2(100, blob.TotalSpacing)); } // Add button labels. SpriteBatch batch = UI2D.Shared.SpriteBatch; UI2D.Shared.GetFont Font = UI2D.Shared.GetGameFont24Bold; //Color fontColor = new Color(10, 75, 108); Color fontColor = new Color(127, 127, 127); Color shadowColor = new Color(0, 0, 0, 20); Vector2 shadowOffset = new Vector2(0, 6); // Disable writing to alpha channel. // This prevents transparent fringing around the text. GraphicsDevice device = BokuGame.bokuGame.GraphicsDevice; device.BlendState = UI2D.Shared.BlendStateColorWriteRGB; if (label != null) { // Center the team name. int len = (int)Font().MeasureString(label).X; pos = new Vector2(565, 386); pos.X += (textureTeam.Width - textureTeam.Height - len) / 2; TextHelper.DrawStringNoBatch(Font, label, pos + shadowOffset, shadowColor); TextHelper.DrawStringNoBatch(Font, label, pos, fontColor); } pos = new Vector2(572, 482); TextHelper.DrawStringNoBatch(Font, Strings.Localize("gameOver.browse"), pos + shadowOffset, shadowColor); TextHelper.DrawStringNoBatch(Font, Strings.Localize("gameOver.browse"), pos, fontColor); pos.Y += 51; TextHelper.DrawStringNoBatch(Font, Strings.Localize("gameOver.edit"), pos + shadowOffset, shadowColor); TextHelper.DrawStringNoBatch(Font, Strings.Localize("gameOver.edit"), pos, fontColor); pos.Y += 51; TextHelper.DrawStringNoBatch(Font, Strings.Localize("gameOver.restart"), pos + shadowOffset, shadowColor); TextHelper.DrawStringNoBatch(Font, Strings.Localize("gameOver.restart"), pos, fontColor); // Restore default blend state. device.BlendState = BlendState.AlphaBlend; } if (ActiveWinner) { // Main graphic. Vector2 size = new Vector2(textureWinner.Width, textureWinner.Height); Vector2 pos = new Vector2((rt.Width - size.X) / 2.0f, 0.0f); quad.Render(textureWinner, pos, size, "TexturedPreMultAlpha"); // Options. if (GamePadInput.ActiveMode == GamePadInput.InputMode.GamePad) { size = new Vector2(textureOptions.Width, textureOptions.Height); pos = new Vector2((rt.Width - size.X) / 2.0f, 470); quad.Render(textureOptions, pos, size, "TexturedPreMultAlpha"); } else { size = new Vector2(textureOptionsKey.Width, textureOptionsKey.Height); pos = new Vector2((rt.Width - size.X) / 2.0f, 470); quad.Render(textureOptionsKey, pos, size, "TexturedPreMultAlpha"); // Add key face icons. Color color = new Color(20, 20, 20); TextBlob blob = new TextBlob(UI2D.Shared.GetGameFont20, "[home]", 100); blob.Justification = Boku.UI2D.UIGridElement.Justification.Center; pos.Y += 16; blob.RenderWithButtons(pos, color); homeHitBox.Set(pos, pos + new Vector2(100, blob.TotalSpacing)); blob.RawText = "[esc]"; pos.Y += 50; blob.RenderWithButtons(pos, color); editHitBox.Set(pos, pos + new Vector2(100, blob.TotalSpacing)); blob.RawText = "[enter]"; pos.Y += 50; blob.RenderWithButtons(pos, color); restartHitBox.Set(pos, pos + new Vector2(100, blob.TotalSpacing)); } // Add button labels. SpriteBatch batch = UI2D.Shared.SpriteBatch; UI2D.Shared.GetFont Font = UI2D.Shared.GetGameFont24Bold; Color fontColor = new Color(10, 75, 108); pos = new Vector2(572, 482); TextHelper.DrawStringNoBatch(Font, Strings.Localize("gameOver.browse"), pos, fontColor); pos.Y += 51; TextHelper.DrawStringNoBatch(Font, Strings.Localize("gameOver.edit"), pos, fontColor); pos.Y += 51; TextHelper.DrawStringNoBatch(Font, Strings.Localize("gameOver.restart"), pos, fontColor); } if (ActiveGameOver) { // Main graphic. Vector2 size = new Vector2(textureGameOver.Width, textureGameOver.Height); Vector2 pos = new Vector2((rt.Width - size.X) / 2.0f, 0.0f); quad.Render(textureGameOver, pos, size, "TexturedPreMultAlpha"); // Options. if (GamePadInput.ActiveMode == GamePadInput.InputMode.GamePad) { size = new Vector2(textureOptions.Width, textureOptions.Height); pos = new Vector2((rt.Width - size.X) / 2.0f, 470); quad.Render(textureOptions, pos, size, "TexturedPreMultAlpha"); } else { size = new Vector2(textureOptionsKey.Width, textureOptionsKey.Height); pos = new Vector2((rt.Width - size.X) / 2.0f, 470); quad.Render(textureOptionsKey, pos, size, "TexturedPreMultAlpha"); // Add key face icons. Color color = new Color(20, 20, 20); TextBlob blob = new TextBlob(UI2D.Shared.GetGameFont20, "[home]", 100); blob.Justification = Boku.UI2D.UIGridElement.Justification.Center; pos.Y += 16; blob.RenderWithButtons(pos, color); homeHitBox.Set(pos, pos + new Vector2(100, blob.TotalSpacing)); blob.RawText = "[esc]"; pos.Y += 50; blob.RenderWithButtons(pos, color); editHitBox.Set(pos, pos + new Vector2(100, blob.TotalSpacing)); blob.RawText = "[enter]"; pos.Y += 50; blob.RenderWithButtons(pos, color); restartHitBox.Set(pos, pos + new Vector2(100, blob.TotalSpacing)); } // Add button labels. SpriteBatch batch = UI2D.Shared.SpriteBatch; UI2D.Shared.GetFont Font = UI2D.Shared.GetGameFont24Bold; Color fontColor = new Color(10, 75, 108); pos = new Vector2(572, 482); TextHelper.DrawStringNoBatch(Font, Strings.Localize("gameOver.browse"), pos, fontColor); pos.Y += 51; TextHelper.DrawStringNoBatch(Font, Strings.Localize("gameOver.edit"), pos, fontColor); pos.Y += 51; TextHelper.DrawStringNoBatch(Font, Strings.Localize("gameOver.restart"), pos, fontColor); } InGame.RestoreRenderTarget(); dirty = false; } // end of RefreshTexture()
} // end of Clear() private static void RefreshTexture() { // TODO (****) *** Does this make sense any more since we require a min height of 600? bool lores = BokuGame.ScreenSize.Y <= 480; UI2D.Shared.GetFont Font = UI2D.Shared.GetGameFont24Bold; if (lores) { Font = UI2D.Shared.GetGameFont30Bold; } blob.Font = Font; ScreenSpaceQuad ssquad = ScreenSpaceQuad.GetInstance(); RenderTarget2D rt = UI2D.Shared.RenderTarget512_302; InGame.SetRenderTarget(rt); InGame.Clear(Color.Transparent); ssquad.Render(background, Vector2.Zero, new Vector2(512, 302), "TexturedRegularAlpha"); // Text description. if (blob != null) { Vector2 pos = new Vector2(margin, margin); int maxLines = showYButton ? (lores ? 3 : 4) : (lores ? 4 : 6); // Modify final line to end with ellipsis. blob.AddEllipsisToLine(maxLines - 1); // If less than maxLines of text, center on texture. int spareLines = maxLines - blob.NumLines - 1; if (spareLines > 0) { pos.Y += spareLines * 0.5f * Font().LineSpacing; } blob.RenderWithButtons(pos, Color.Yellow, maxLines: maxLines); } InGame.RestoreRenderTarget(); // // Copy result to local texture. // int[] data = new int[512 * 302]; rt.GetData <int>(data); texture.SetData <int>(data); // Scale size to 1/4 screen height. int w = (int)BokuGame.ScreenSize.X; int h = (int)BokuGame.ScreenSize.Y; float scale = h / 4.0f / 302.0f; size = new Vector2(512, 302); size *= scale; // Position in lower right hand corner. targetPosition = new Vector2(w, h); targetPosition -= size; dirty = false; } // end of RefreshTexture()
// c'tor public Shared(MainMenu parent) { // Set up the options menu. optionsMenu = new OptionsMenu(); liveFeed = new LiveFeedDisplay(); if (BokuGame.bMarsMode) { boku = ActorManager.GetActor("RoverGreeter").CreateNewInstance() as BokuGreeter; } else { boku = ActorManager.GetActor("BokuGreeter").CreateNewInstance() as BokuGreeter; } boku.SetColor(Classification.Colors.White); bokuCamera.NearClip = 0.1f; bokuCamera.FarClip = 20.0f; // These are the values for the model when its translation off the ground has been thrown away (and added back via constant) bokuCamera.From = 1.3f * new Vector3(1.5f, 0.3f, 0.5f); bokuCamera.At = new Vector3(0.0f, -0.5f, 0.0f); // These are the values for a "correct" model - that is raised off the ground in Max and whose translation is intact // bokuCamera.From = new Vector3(1.5f, 0.3f, 1.4f); // bokuCamera.At = new Vector3(0.0f, -0.5f, 0.7f); // Move camera to look at menu from an angle. //camera.From = 0.9f * camera.From; camera.At = new Vector3(-0.6f, 0, 0); Matrix foo = Matrix.CreateRotationY(-0.3f) * Matrix.CreateTranslation(new Vector3(1.0f, 0.0f, -2.0f)); camera.At = Vector3.Transform(camera.At, foo); camera.From = Vector3.Transform(camera.From, foo); // We'll be using a 1280x720 rendertarget for all rendering. camera.Resolution = new Point(1280, 720); bokuCamera.Resolution = new Point(1280, 720); timer = new Boku.Base.GameTimer(Boku.Base.GameTimer.ClockType.WallClock, 3.1415927); timer.TimerElapsed += ChangeExpression; // Create text elements. // Start with a blob of common parameters. UIGridElement.ParamBlob blob = new UIGridElement.ParamBlob(); blob.width = 3.4f; blob.height = 0.5f; blob.edgeSize = 0.06f; blob.Font = UI2D.Shared.GetGameFont24Bold; blob.textColor = Color.White; blob.dropShadowColor = Color.Black; blob.useDropShadow = true; blob.invertDropShadow = true; blob.unselectedColor = new Color(new Vector3(4, 100, 90) / 255.0f); blob.selectedColor = new Color(new Vector3(5, 180, 160) / 255.0f); blob.normalMapName = @"Slant0Smoothed5NormalMap"; blob.justify = UIGrid2DTextElement.Justification.Left; menu = new ModularMenu(blob, null /*Strings.Localize("mainMenu.mainMenu")*/); menu.OnSelect = parent.OnSelect; menu.OnCancel = parent.OnCancel; menu.UseRtCoords = true; menu.AddText(Strings.Localize("mainMenu.new")); menu.AddText(Strings.Localize("mainMenu.play")); #if NETFX_CORE menu.AddText(Strings.Localize("mainMenu.import")); #else if (WinStoreHelpers.RunningAsUWP) { menu.AddText(Strings.Localize("mainMenu.import")); } #endif menu.AddText(Strings.Localize("mainMenu.community")); menu.AddText(Strings.Localize("mainMenu.options")); menu.AddText(Strings.Localize("mainMenu.help")); #if !NETFX_CORE // Once you run an app in Win8, you are never allowed to kill it. // Only the system can kill it. menu.AddText(Strings.Localize("mainMenu.exit")); #endif // And then remove what we don't want. if (!Program2.SiteOptions.CommunityEnabled) { menu.DeleteText(Strings.Localize("mainMenu.community")); } menu.WorldMatrix = Matrix.CreateScale(0.9f, 1.0f, 1.0f); string signOutStr = Strings.Localize("textDialog.signOut"); signOutButton = new Button(signOutStr, Color.White, null, UI2D.Shared.GetGameFont20); //Because this button has no texture and we can't set the width of the texture passed in explicitly. Just use the fixed size based on text size. UI2D.Shared.GetFont Font = UI2D.Shared.GetGameFont20; Vector2 size = (null != Font) ? Font().MeasureString(signOutStr) : new Vector2(60.0f, 20.0f); signOutButton.FixedSize = size; signOutButton.UseFixedSize = true; textBlob = new TextBlob(UI2D.Shared.GetGameFont24, "", 340); } // end of Shared c'tor
public override void Render(Camera camera) { GraphicsDevice device = BokuGame.bokuGame.GraphicsDevice; HelpOverlay.RefreshTexture(); RenderTarget2D rt = UI2D.Shared.RenderTargetDepthStencil1280_720; Vector2 screenSize = BokuGame.ScreenSize; Vector2 rtSize = new Vector2(rt.Width, rt.Height); if (skipFrames > 0 || shared.waitingForStorage) { InGame.Clear(Color.Black); --skipFrames; return; } shared.liveFeed.FeedSize = shared.liveFeed.ResetScrollBoxSize; InGame.SetRenderTarget(rt); // Clear the screen & z-buffer. InGame.Clear(Color.Black); // Apply the background. ScreenSpaceQuad quad = ScreenSpaceQuad.GetInstance(); Vector2 position = Vector2.Zero; quad.Render(shared.backgroundTexture, position, rtSize, @"TexturedNoAlpha"); Color textColor = new Color(21, 125, 178); if (parent.newWorldDialog.Active) { // Hide the dialog if auth UI is active. Just keeps things cleaner. if (!AuthUI.IsModalActive) { // If options menu is active, render instead of main menu. parent.newWorldDialog.Render(new Vector2(rt.Width, rt.Height)); } } else if (shared.optionsMenu.Active) { // Hide the menu if auth UI is active. Just keeps things cleaner. if (!AuthUI.IsModalActive) { // If options menu is active, render instead of main menu. shared.optionsMenu.Render(); } } else { // Render url SpriteBatch batch = UI2D.Shared.SpriteBatch; UI2D.Shared.GetFont Font = UI2D.Shared.GetGameFont24; Vector2 size = Font().MeasureString(shared.screenUrl); Vector2 pos = new Vector2(rt.Width / 2 - size.X / 2, 586); batch.Begin(); TextHelper.DrawString(Font, shared.screenUrl, pos, textColor); batch.End(); shared.urlBox.Set(pos, pos + size); // Hide the menu if auth UI is active. Just keeps things cleaner. if (!AuthUI.IsModalActive) { // Render menu using local cameras. ShaderGlobals.SetCamera(shared.camera); shared.menu.WorldMatrix = Matrix.CreateTranslation(0.0f, -0.3f, 0.0f); shared.menu.Render(shared.camera); } // Render Boku. ShaderGlobals.SetCamera(shared.bokuCamera); string oldRig = BokuGame.bokuGame.shaderGlobals.PushLightRig(ShaderGlobals.GreeterRigName); // TODO (****) How to temporarily disable point lights??? // Do we really need to? //Luz.SetToEffect(true); // disable scene point lights if (BokuGame.bMarsMode) { shared.boku.Movement.Position = new Vector3(-0.0f, 0.25f, -0.5f); shared.boku.ReScale = 0.50f; //quad = ScreenSpaceQuad.GetInstance(); //float wid=shared.jplTexture.Width/2; //position = new Vector2(1250-(wid), 20); //quad.Render(shared.jplTexture, position, new Vector2(wid, shared.jplTexture.Height/2), @"TexturedRegularAlpha"); } else { shared.boku.Movement.Position = new Vector3(0.0f, 0.0f, 0.0f); } fVal += 0.01f; // Be sure to set the right camera so the env map looks correct. ShaderGlobals.SetCamera(shared.bokuCamera); shared.boku.RenderObject.Render(shared.bokuCamera); // TODO (****) How to temporarily disable point lights??? //Luz.SetToEffect(false); // re-enable scene point lights BokuGame.bokuGame.shaderGlobals.PopLightRig(oldRig); } InGame.RestoreRenderTarget(); InGame.Clear(new Color(20, 20, 20)); InGame.SetViewportToScreen(); // Copy the rendered scene to the backbuffer. { ScreenWarp.FitRtToScreen(rtSize); quad.Render(rt, ScreenWarp.RenderPosition, ScreenWarp.RenderSize, @"TexturedNoAlpha"); } // Render news feed. if (!shared.optionsMenu.Active) { shared.liveFeed.Render(); } // Hide overlay if auth UI is active. if (!AuthUI.IsModalActive) { HelpOverlay.Render(); } // Render text dialogs if being shown by OptionsMenu. // TODO (****) Need to get rid of rendering to RTs where possible. // TODO (****) Need to split OptionsMenu from MainMenu. if (shared.optionsMenu.Active) { InGame.inGame.shared.smallTextDisplay.Render(); InGame.inGame.shared.scrollableTextDisplay.Render(); } MainMenu.Instance.prevSessionCrashedMessage.Render(); MainMenu.Instance.noCommunityMessage.Render(); MainMenu.Instance.noSharingMessage.Render(); } // end of Render()
} // end of Render() #endregion #region Internal /// <summary> /// If the text being displayed has changed, we need to refresh the texture. /// Note this requires changing the rendertarget so this should no be called /// during the normal rendering loop. /// </summary> private void RefreshTexture() { // This needs to be refactored. The problem is that when the buttons change color // (for hover for instance) the changing state of thier color needs to set the dirty // flag. For now, just always set it so we always have the right behavior. dirty = true; if (dirty) { GraphicsDevice device = BokuGame.bokuGame.GraphicsDevice; LoadContent(true); diffuse = UI2D.Shared.RenderTarget512_302; if (diffuse == null) { // Not ready yet, remain dirty. return; } SpriteBatch batch = UI2D.Shared.SpriteBatch; UI2D.Shared.GetFont Font20 = UI2D.Shared.GetGameFont20; UI2D.Shared.GetFont Font24 = UI2D.Shared.GetGameFont24; InGame.SetRenderTarget(diffuse); InGame.Clear(Color.Transparent); // Render the backdrop. ScreenSpaceQuad quad = ScreenSpaceQuad.GetInstance(); quad.Render(background, Vector2.Zero, new Vector2(512, 302), @"TexturedPreMultAlpha"); // // Render the text message. // Vector2 pos = new Vector2(margin, 0.0f); // Calc vertical center of display. pos.Y = (int)((height - blackHeight - 1.5f * textBlob.TotalSpacing) / 2.0f); // Offset based on number of lines. pos.Y -= (int)(textBlob.TotalSpacing * (textBlob.NumLines - 1) / 2.0f); textBlob.RenderWithButtons(pos + shadowOffset, shadowColor); textBlob.RenderWithButtons(pos, textColor); // // Render any active buttons and the text that goes with them. // batch.Begin(); // We need to calc the width of each active button and it's label // so we can center the whole set at the bottom of the dialog. // TODO Set this up so we can also right/left justify? Vector2 position = Vector2.Zero; position.X = width / 2.0f; position.Y = height - margin - 40.0f; int gap = Button.Margin; int totalWidth = 0; if (aButton != null) { totalWidth += (int)aButton.GetSize().X; totalWidth += gap; } if (bButton != null) { totalWidth += (int)bButton.GetSize().X; totalWidth += gap; } if (xButton != null) { totalWidth += (int)xButton.GetSize().X; totalWidth += gap; } if (yButton != null) { totalWidth += (int)yButton.GetSize().X; totalWidth += gap; } totalWidth -= gap; // Remove the extra one... position.X -= (int)(totalWidth / 2); if (aButton != null) { aButton.Render(position); position.X += aButton.GetSize().X + gap; } if (bButton != null) { bButton.Render(position); position.X += bButton.GetSize().X + gap; } if (xButton != null) { xButton.Render(position); position.X += xButton.GetSize().X + gap; } if (yButton != null) { yButton.Render(position); position.X += yButton.GetSize().X + gap; } batch.End(); // Restore backbuffer. InGame.RestoreRenderTarget(); dirty = false; } } // end of ModularMessageDialog RefreshTexture()
} // end of UIGridMaterialElement Render() /// <summary> /// Draw a numeric label under each cube, identifying it by its UI slot. /// Might be cool to have the letters spin as the cube spins. Might not. /// </summary> /// <param name="camera"></param> /// <param name="world"></param> private void RenderLabel(Camera camera, Matrix world) { GraphicsDevice device = BokuGame.bokuGame.GraphicsDevice; UI2D.Shared.GetFont Font = UI2D.Shared.GetGameFont18Bold; SpriteBatch batch = UI2D.Shared.SpriteBatch; // Handle small screens. if (BokuGame.ScreenSize.Y < 720) { Font = UI2D.Shared.GetGameFont15_75; } /// Find a placement sort of lower cube Matrix center = Matrix.Identity; center.Translation = new Vector3(0.5f, 0.5f, 0.0f); Matrix worldViewProj = center * world * camera.ViewProjectionMatrix; /// Find the screen position Vector4 screenPos = new Vector4(0, 0, 0, 1.0f); screenPos = Vector4.Transform(screenPos, worldViewProj); screenPos.X /= screenPos.W; screenPos.Y /= screenPos.W; /// Translate to pixel coords. Note the flip Y. int x = (int)((screenPos.X * 0.5f + 0.5f) * BokuGame.ScreenSize.X + 0.5f); int y = (int)((screenPos.Y * -0.5f + 0.5f) * BokuGame.ScreenSize.Y + 0.5f); /// Center the string /// Compute how centered the cube is as a var [0..1]. float centerness = Math.Abs(x - BokuGame.ScreenSize.X * 0.5f); centerness /= BokuGame.ScreenSize.X * 0.5f; centerness = (0.75f - centerness) / 0.75f; centerness = MathHelper.Clamp(centerness, 0.0f, 1.0f); centerness = MyMath.SmoothStep(0.0f, 1.0f, centerness); /// Translate centeredness into opacity, fading out in either extreme. float kMinAlpha = 64.0f; byte byteAlpha = (byte)(kMinAlpha + centerness * (255.9f - kMinAlpha)); byteAlpha = 255; /// Centeredness into scale. Note that this keeps the numbers from /// overlapping when the cubes are very close together. float kMinScale = 0.5f; float kMaxScale = 1.0f; float scale = kMinScale + centerness * (kMaxScale - kMinScale); int label = Terrain.MaterialIndexToLabel(Terrain.UISlotToMatIndex(uiSlot)); string uiSlotString = (label).ToString(); Vector2 strSize = Font().MeasureString(uiSlotString); x = (int)(x - strSize.X * scale * 0.5f + 0.5f); /// Shadow and text colors, with appropriate opacity. Color darkGrey = new Color(10, 10, 10, byteAlpha); Color transWhite = new Color(255, 255, 255, byteAlpha); // Finally, just do it. Note that we can't put the batching any // higher up the food chain, because the generic grid doesn't know // whether it's going to be rendering text. Although if perf is an // issue, it might be worth looking at moving the batch.begin()/end() // up to the BasePicker.Render(). // Note this no longer uses 'scale' to shrink the text to match the cubes. // Do we really care? // Note this uses SpriteFont rendering since there are so many labels (numbers). batch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend); { batch.DrawString(Font().spriteFont, uiSlotString, new Vector2(x + 1, y + 1), darkGrey); batch.DrawString(Font().spriteFont, uiSlotString, new Vector2(x, y), transWhite); } batch.End(); }
} // end of UIGridModularMenu Update() public void RefreshTexture() { if (dirty || diffuse.IsContentLost) { int w, h; GetWH(out w, out h); // If the number of elements has changed, we need a new rendertarget. InitDeviceResources(BokuGame.bokuGame.GraphicsDevice); GraphicsDevice device = BokuGame.bokuGame.GraphicsDevice; InGame.SetRenderTarget(diffuse); InGame.Clear(Color.Transparent); // The thin margin around the highlight where the normal color shows through. int highlightMargin = 5; ScreenSpaceQuad quad = ScreenSpaceQuad.GetInstance(); // Render the white background. Alpha on normal map is used to round corners. Vector2 position = Vector2.Zero; Vector2 size = new Vector2(w, h); if (title != null) { quad.Render(Vector4.One, position, size); position.Y = 70; } // And the black parts. size.Y = whiteTop.Height; quad.Render(whiteTop, new Vector4(0, 0, 0, 1), position, size, "TexturedRegularAlpha"); position.Y += 16; size.Y = h - position.Y; quad.Render(new Vector4(0, 0, 0, 1), position, size); // Disable writing to alpha channel. // This prevents transparent fringing around the text. device.BlendState = UI2D.Shared.BlendStateColorWriteRGB; // Add the highlight/shadow onto the white region. if (title != null) { position.Y = 25; size.Y = 48; quad.Render(whiteHighlight, new Vector4(0.6f, 1.0f, 0.8f, 0.2f), position + new Vector2(highlightMargin, 0), size + new Vector2(-2 * highlightMargin, -highlightMargin), "TexturedRegularAlpha"); } // Render the label and value text into the texture. SpriteBatch batch = UI2D.Shared.SpriteBatch; batch.Begin(); // Title. UI2D.Shared.GetFont Font = UI2D.Shared.GetGameFont24Bold; if (title != null) { position.X = TextHelper.CalcJustificationOffset(margin.X, w, (int)Font().MeasureString(title).X, justify); position.Y = (int)((64 - Font().LineSpacing) / 2.0f) + 4; TextHelper.DrawString(Font, title, position + shadowOffset, shadowColor); TextHelper.DrawString(Font, title, position, titleTextColor); } // Entries. Font = UI2D.Shared.GetGameFont18Bold; position.Y = 8 + (title != null ? 70 : 0); Vector2 min = Vector2.Zero; Vector2 max = Vector2.One; for (int i = 0; i < itemList.Count; i++) { // Render bar. Vector4 barColor = active ? new Vector4(1, 1, 1, itemList[i].BarAlpha) : new Vector4(1, 0.5f, 1, itemList[i].BarAlpha); quad.Render(greenBar, barColor, new Vector2(8, position.Y - additionalLineSpacing / 3), new Vector2(w - 16, Font().LineSpacing + additionalLineSpacing), "TexturedRegularAlpha"); // Render text. position.X = TextHelper.CalcJustificationOffset(margin.X, w, (int)Font().MeasureString(itemList[i].Text).X, justify); TextHelper.DrawString(Font, itemList[i].Text, position, itemList[i].TextColor); min.Y = position.Y / h; position.Y += Font().LineSpacing + additionalLineSpacing; max.Y = position.Y / h; itemList[i].UVBoundingBox.Set(min, max); } batch.End(); // Add the highlight to the black region. position = new Vector2(highlightMargin, 1 + (title != null ? 70 : 0)); size.X = w - 2 * highlightMargin; size.Y = 60; quad.Render(blackHighlight, new Vector4(1, 1, 1, 0.2f), position, size, "AdditiveBlendWithAlpha"); // Restore write channels. device.BlendState = BlendState.NonPremultiplied; // Restore backbuffer. InGame.RestoreRenderTarget(); dirty = false; } } // end of UIGridModularMenu RefreshTexture()
} // end of UpdateTextColor() /// <summary> /// Render our UI to the screen, but only if now is appropriate. /// </summary> public static void Render() { // In mouse mode, don't render undo/redo icons if pickers are active. bool mouseEdit = inGame.CurrentUpdateMode == UpdateMode.MouseEdit && !InGame.inGame.touchEditUpdateObj.PickersActive; if ((inGame.CurrentUpdateMode == UpdateMode.ToolMenu || mouseEdit) && HaveAnything) { GraphicsDevice device = BokuGame.bokuGame.GraphicsDevice; // Calc position for undo/redo text. int x = 0; int y = (int)(BokuGame.ScreenSize.Y * 0.66f); int buttonSize = 40; UI2D.Shared.GetFont Font = UI2D.Shared.GetGameFont18Bold; SpriteBatch batch = UI2D.Shared.SpriteBatch; // Handle small screens. if (BokuGame.ScreenSize.Y < 720) { Font = UI2D.Shared.GetGameFont15_75; buttonSize = (int)(buttonSize * 0.8f); } if (HaveReDo) { ScreenSpaceQuad quad = ScreenSpaceQuad.GetInstance(); Texture2D texture = GamePadInput.ActiveMode == GamePadInput.InputMode.GamePad ? ButtonTextures.YButton : ButtonTextures.Redo; quad.Render(texture, Vector4.One, new Vector2(x, y), new Vector2(buttonSize), @"TexturedRegularAlpha"); redoHitBox.Set(new Vector2(x, y), new Vector2(x, y) + new Vector2(buttonSize - 12)); } else { redoHitBox.Set(Vector2.Zero, Vector2.Zero); } if (HaveUnDo) { ScreenSpaceQuad quad = ScreenSpaceQuad.GetInstance(); Texture2D texture = GamePadInput.ActiveMode == GamePadInput.InputMode.GamePad ? ButtonTextures.XButton : ButtonTextures.Undo; quad.Render(texture, Vector4.One, new Vector2(x, y + buttonSize - 12), new Vector2(buttonSize), @"TexturedRegularAlpha"); undoHitBox.Set(new Vector2(x, y + buttonSize - 12), new Vector2(x, y + buttonSize - 12) + new Vector2(buttonSize - 12)); } else { undoHitBox.Set(Vector2.Zero, Vector2.Zero); } Color darkGrey = new Color(10, 10, 10); #if NETFX_CORE batch.Begin(); if (HaveReDo) { string str = Strings.Localize("undoStack.redo") + "(" + NumReDo.ToString() + ")"; TextHelper.DrawStringWithShadow(Font, batch, x + buttonSize - 12, y - 4, str, redoTextColor, darkGrey, false); Vector2 max = redoHitBox.Max; max.X += Font().MeasureString(str).X; redoHitBox.Set(redoHitBox.Min, max); } if (HaveUnDo) { string str = Strings.Localize("undoStack.undo") + "(" + NumUnDo.ToString() + ")"; TextHelper.DrawStringWithShadow(Font, batch, x + buttonSize - 12, y + buttonSize - 16, str, undoTextColor, darkGrey, false); Vector2 max = undoHitBox.Max; max.X += Font().MeasureString(str).X; undoHitBox.Set(undoHitBox.Min, max); } batch.End(); #else SysFont.StartBatch(null); if (HaveReDo) { string str = Strings.Localize("undoStack.redo") + "(" + NumReDo.ToString() + ")"; SysFont.DrawString(str, new Vector2(x + buttonSize - 12, y - 4), new RectangleF(), Font().systemFont, redoTextColor, outlineColor: Color.Black, outlineWidth: 1.5f); Vector2 max = redoHitBox.Max; max.X += Font().MeasureString(str).X; redoHitBox.Set(redoHitBox.Min, max); } if (HaveUnDo) { string str = Strings.Localize("undoStack.undo") + "(" + NumUnDo.ToString() + ")"; SysFont.DrawString(str, new Vector2(x + buttonSize - 12, y + buttonSize - 16), new RectangleF(), Font().systemFont, undoTextColor, outlineColor: Color.Black, outlineWidth: 1.5f); Vector2 max = undoHitBox.Max; max.X += Font().MeasureString(str).X; undoHitBox.Set(undoHitBox.Min, max); } SysFont.EndBatch(); #endif } }