/*
 * This file is part of Afterwarp Framework (http://afterwarp.io).
 * Copyright (c) 2015 - 2025 Dr. Yuriy Kotsarenko. All rights reserved.
 *
 * This example source code is licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of the License at
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software distributed under the License is
 * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and limitations under the License.
 */

// This example illustrates the following features:
//  * Drawing normal and curved text using different fonts, color gradients, outlines and effects.

namespace FontsDemo
{
  using System.Numerics;
  using System.Windows.Forms;
  using Afterwarp;
  using TextRenderer = Afterwarp.TextRenderer;
  using Application = System.Windows.Forms.Application;

  public partial class MainForm : Form
  {
    private Device device;
    private SwapChain swapChain;
    private Canvas canvas;
    private TextRenderer textRenderer;
    private TextModeller textModeller;
    private Vector2 displaySize;

    public MainForm()
    {
      InitializeComponent();
    }

    private void MainForm_Load(object sender, EventArgs e)
    {
      displaySize = new Vector2(ClientSize.Width, ClientSize.Height);
      try
      {
        device = new Device(DeviceTechnology.Direct3D);
        swapChain = new SwapChain(device, Handle, null, PixelFormat.Unknown, PixelFormat.Unknown, 8);
        canvas = new Canvas(device);
        textRenderer = new TextRenderer(canvas, new Point(512, 512), PixelFormat.LA8);
        textModeller = new TextModeller(device);
      }
      catch (Exception ex)
      {
        MessageBox.Show(ex.Message, "Initialization failed", MessageBoxButtons.OK, MessageBoxIcon.Error);
        Application.Exit();
      }
      SetStyle(ControlStyles.Opaque, true);
      SetStyle(ControlStyles.UserPaint, true);
      SetStyle(ControlStyles.AllPaintingInWmPaint, true);
      SetStyle(ControlStyles.DoubleBuffer, false);
    }

    private void MainForm_FormClosed(object sender, FormClosedEventArgs e)
    {
      textModeller?.Dispose();
      textRenderer?.Dispose();
      canvas?.Dispose();
      swapChain?.Dispose();
      device?.Dispose();
    }

    private void MainForm_Resize(object sender, EventArgs e)
    {
      if (WindowState != FormWindowState.Minimized && device is not null)
      {
        displaySize = new Vector2(ClientSize.Width, ClientSize.Height);
        swapChain.Resize(new Point(displaySize));
        Invalidate();
      }
    }

    private void MainForm_Paint(object sender, PaintEventArgs e)
    {
      float scale = DeviceDpi / 96.0f;

      swapChain.Begin();
      try
      {
        device.Clear(DeviceClear.Color, new FloatColor(0xFFE1E2E6u));

        canvas.Begin();
        try
        {
          // Draw dark background on bottom part of the form.
          canvas.Attributes = 0;
          canvas.ContextState = CanvasContextState.FlatScene;

          canvas.FillRect(0.0f, displaySize.Y * 0.5f, displaySize.X, displaySize.Y * 0.5f,
            new ColorRect(0xFF40444Cu), BlendingEffect.Copy);

          Vector2 position = new(displaySize.X * 0.5f, displaySize.Y * 0.15f);

          // For curved text, we have to use vector-based text renderer, which also required multisampled
          // render target to enable proper anti-aliasing.
          textModeller.SetFontParameters(new FontParameters("Cambria", 16.0f * scale, FontWeight.Bold));

          textModeller.DrawCurved(canvas, position, "The framework also supports rendering curved text " +
            "to better accomodate for existing content.", 1000.0f, float.NaN,
            new ColorPair(0xFF000040u, 0xFF0040A0u));

          // Prepare canvas for text output.
          canvas.ContextState = CanvasContextState.FlatText;
          canvas.SamplerState = default;
          { // Arial Semi-Bold 16px.
            FontParameters parameters = new("Arial", 16.0f * scale, FontWeight.SemiBold);
            parameters.Effect.BorderType = FontBorder.Normal;
            parameters.Effect.ShadowOpacity = 1.0f;
            textRenderer.Parameters = parameters;

            TextRenderModifiers modifiers = default;
            // Extend further on a 2x HiDPI screen for demo purposes.
            modifiers.Interleave = scale >= 2.0f ? 8.0f : 1.0f;

            textRenderer.DrawCentered(position, "欢迎使用演示不同文本字体和视觉效果的应用程序。",
              new ColorPair(0xFF00E0FFu, 0xFF0000FFu), 1.0f, true, modifiers);
          }
          position.Y += 32.0f * scale;

          // Tahoma 14px.
          textRenderer.Parameters = new FontParameters("Tahoma", 14.0f * scale);
          textRenderer.DrawCentered(position, "C'è il pieno supporto per le lingue straniere nel formato " +
            "unicode UTF8.", new ColorPair(0xFF008000u, 0xFFFF0000u));

          position.Y += 32.0f * scale;
          { // Arial Regular 16px.
            FontParameters parameters = new("Arial", 16.0f * scale);
            parameters.Effect.BorderType = FontBorder.Normal;
            parameters.Effect.ShadowOpacity = 1.0f;
            textRenderer.Parameters = parameters;

            textRenderer.DrawCentered(position, "Arial Regular 16px with Border, Shadow and Gradient.",
              new ColorPair(0xFF00FF00u, 0xFFFFFFFFu));
          }
          position.Y += 32.0f * scale;

          // Arial Regular 14px, Black.
          textRenderer.Parameters = new FontParameters("Arial", 14.0f * scale);
          textRenderer.DrawCentered(position, "Arial Regular 14px without effects, black",
            new ColorPair(0xFF000000u));

          position.Y += 28.0f * scale;

          { // Segoe UI SemiBold 16px, Inverted with Border and Shadow.
            FontParameters parameters = new("Segoe UI", 16.0f * scale, FontWeight.SemiBold);
            parameters.Effect.BorderType = FontBorder.SemiHeavy;
            parameters.Effect.BorderBrightness = 0.75f;
            parameters.Effect.FillBrightness = 0.0f;
            parameters.Effect.ShadowBrightness = 0.5f;
            parameters.Effect.ShadowOpacity = 1.0f;
            textRenderer.Parameters = parameters;

            textRenderer.DrawCentered(position, "Segoe UI SemiBold 16px inverted with Border and Shadow.",
              new ColorPair(0xFFFFFFFFu));
          }
          position.Y += 32.0f * scale;

          // Consolas 12px.
          textRenderer.Parameters = new FontParameters("Consolas", 12.0f * scale);
          textRenderer.DrawCentered(position, "Consolas (monofont) Regular 12px with Gradient.",
            new ColorPair(0xFF0000FFu, 0xFFA00000u));

          position.Y += 32.0f * scale;

          { // Verdana Bold 20px + Border + Shadow + Gradient
            FontParameters parameters = new("Verdana", 20.0f * scale, FontWeight.Bold);
            parameters.Effect.BorderType = FontBorder.Normal;
            parameters.Effect.ShadowOpacity = 1.0f;
            textRenderer.Parameters = parameters;

            textRenderer.DrawAligned(position, "Verdana 20px aligned to left.",
              new ColorPair(0xFF0000FFu, 0xFFFF00FFu), TextAlignment.Start);
          }
          { // Cambria Bold Italic 18px + Border + Shadow + Gradient
            FontParameters parameters = new("Cambria", 18.0f * scale, FontWeight.Bold, FontStretch.Normal,
              FontSlant.Italic);
            parameters.Effect.BorderType = FontBorder.Normal;
            parameters.Effect.ShadowOpacity = 1.0f;
            textRenderer.Parameters = parameters;

            textRenderer.DrawAligned(position, "Cambria Italic 18px aligned to right.",
              new ColorPair(0xFF0000FFu, 0xFF00FFFFu), TextAlignment.End);
          }

          canvas.Attributes = Canvas.Attribute.Transform;
          canvas.Transform = Matrix3x2.CreateRotation(MathF.PI * -0.5f) *
            Matrix3x2.CreateTranslation(displaySize.X - 8.0f * scale, displaySize.Y * 0.25f);

          { // Cambria UI 16px + Border + Shadow + Gradient, Vertical (with correct shadow)
            FontParameters parameters = new("Cambria", 16.0f * scale);
            parameters.Effect.BorderType = FontBorder.Normal;
            parameters.Effect.ShadowOpacity = 1.0f;
            parameters.Effect.ShadowDistance = new Vector2(-2.0f, 2.0f);
            textRenderer.Parameters = parameters;

            textRenderer.DrawAligned(Vector2.Zero, "Vertical text is also possible.",
              new ColorPair(0xFFFF0080u, 0xFFFFFFFFu), TextAlignment.Middle, TextAlignment.End);
          }

          canvas.Transform = Matrix3x2.CreateRotation(MathF.PI * 0.5f) *
            Matrix3x2.CreateTranslation(8.0f * scale, displaySize.Y * 0.75f);

          { // Calibri UI 16px + Border + Shadow + Gradient, Vertical (with correct shadow)
            FontParameters parameters = new("Calibri", 16.0f * scale);
            parameters.Effect.BorderType = FontBorder.Normal;
            parameters.Effect.ShadowOpacity = 1.0f;
            parameters.Effect.ShadowDistance = new Vector2(2.0f, -2.0f);
            textRenderer.Parameters = parameters;

            textRenderer.DrawAligned(Vector2.Zero, "Text in a different orientation.",
              new ColorPair(0xFFA0A0A0u, 0xFFFFFFFFu), TextAlignment.Middle, TextAlignment.End);
          }

          canvas.Attributes = 0;
          position = new Vector2(displaySize.X * 0.5f, displaySize.Y * 0.6f);

          { // Tahoma Regular 16px + Border + Shadow + Gradient
            FontParameters parameters = new("Tahoma", 18.0f * scale);
            parameters.Effect.BorderType = FontBorder.Normal;
            parameters.Effect.ShadowOpacity = 1.0f;
            textRenderer.Parameters = parameters;

            textRenderer.DrawCentered(position,
              "このアプリケーションは、異なる言語で書かれたテキストを完全にサポートしています。",
              new ColorPair(0xFFC65D7Bu, 0xFFE0FCBFu));
          }
          position.Y += 40.0f * scale;

          { // Cambria SemiBold 18px + Border + Shadow + Gradient
            FontParameters parameters = new("Cambria", 18.0f * scale, FontWeight.SemiBold);
            parameters.Effect.BorderType = FontBorder.Normal;
            parameters.Effect.ShadowOpacity = 1.0f;
            textRenderer.Parameters = parameters;

            textRenderer.DrawCentered(position,
              "Some Cambria 18px sample text with Gradient, Border and Shadow.",
              new ColorPair(0xFFE6CFFFu, 0xFFE06E98u));
          }
          position.Y += 32.0f * scale;

          { // Calibri 16px + Border + Shadow + Gradient
            FontParameters parameters = new("Calibri", 16.0f * scale, FontWeight.SemiBold);
            parameters.Effect.BorderType = FontBorder.Normal;
            parameters.Effect.ShadowOpacity = 1.0f;
            textRenderer.Parameters = parameters;

            textRenderer.DrawCentered(position,
              "Calibri Regular 16px with Border, Shadow and Gradient.",
              new ColorPair(0xFFFF0000u, 0xFFFFE000u));
          }
          position.Y += 32.0f * scale;

          { // Segoe UI SemiBold 16px, Inverted with Border and Shadow.
            FontParameters parameters = new("Segoe UI", 16.0f * scale, FontWeight.SemiBold);
            parameters.Effect.BorderType = FontBorder.Heavy;
            parameters.Effect.BorderBrightness = 1.0f;
            parameters.Effect.FillBrightness = 0.0f;
            parameters.Effect.ShadowBrightness = 0.75f;
            parameters.Effect.ShadowOpacity = 1.0f;
            textRenderer.Parameters = parameters;

            textRenderer.DrawCentered(position, "Segoe UI SemiBold 16px inverted with Border and Shadow.",
              new ColorPair(0xFFFFFFFFu));
          }
          position.Y += 32.0f * scale;

          // Arial 14px.
          textRenderer.Parameters = new FontParameters("Arial", 14.0f * scale);
          textRenderer.DrawCentered(position, "Καλώς ορίσατε στον έλεγχο γραμματοσειρών του πλαισίου.",
            new ColorPair(0xFF00FF00u, 0xFFFFFFFFu));

          // Set canvas state for vector-based text rendering.
          canvas.ContextState = CanvasContextState.FlatScene;

          textModeller.SetFontParameters(new FontParameters("Calibri", 16.0f * scale,
            FontWeight.SemiBold));

          textModeller.DrawCurved(canvas, position, "El framework es capaz de rasterizar texto en curva " +
            "en cualquier orientación y con la transformación del canvas.", -1000.0f, float.NaN,
            new ColorPair(0xFF00E0FFu, 0xFF0000FFu));

          { // Draw technology string.
            FontParameters parameters = new("Segoe UI", 16.0f * scale, FontWeight.SemiBold);
            parameters.Effect.BorderType = FontBorder.SemiHeavy;
            parameters.Effect.BorderBrightness = 1.0f;
            parameters.Effect.FillBrightness = 0.0f;
            parameters.Effect.ShadowBrightness = 0.75f;
            parameters.Effect.ShadowOpacity = 1.0f;
            textRenderer.Parameters = parameters;

            textRenderer.Draw(new Vector2(8.0f * scale, 4.0f * scale),
              string.Format("Direct3D ({0}.{1}), features: {2}.{3}",
              device.TechVersion >> 8, (device.TechVersion >> 4) & 0xF,
              device.TechFeatureVersion >> 8, (device.TechFeatureVersion >> 4) & 0xF),
              new ColorPair(0xA0FFFFFFu));
          }
        }
        finally
        {
          canvas.End();
        }
      }
      finally
      {
        swapChain.End();
      }
    }
  }
}