/*
 * 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:
//  * Creating and filling texture from system memory in real-time to produce a plasma-looking effect.
//  * Accurate time-based movement independent of rendering frame rate.

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

  public partial class MainForm : Form
  {
    private Device device;
    private SwapChain swapChain;
    private Canvas canvas;
    private TextRenderer textRenderer;
    private Timer timer;

    private Texture texturePlasma;
    private Texture textureScanline;

    private readonly uint[] plasmaArray = new uint[512 * 512];
    private readonly ushort[] lookupSin = new ushort[2048];
    private readonly ushort[] lookupCos = new ushort[2048];

    private Vector2 displaySize;
    private Point shift;
    private int paletteIndex;

    public MainForm()
    {
      InitializeComponent();
      Application.Idle += Application_Idle;
    }

    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);
        canvas = new Canvas(device);
        textRenderer = new TextRenderer(canvas, new Point(512, 512), PixelFormat.LA8);
        timer = new Timer();

        texturePlasma = new Texture(device, new TextureParameters(512, 512, 0, PixelFormat.RGBA8,
          TextureType.Surface, Texture.Attribute.Dynamic));
        textureScanline = new Texture(device, new TextureParameters(64, 64, 0, PixelFormat.L8));

        { // Generate scanline texture content.
          byte[] pixels = new byte[64 * 64];

          for (int i = 0; i < 64 * 64; ++i)
            pixels[i] = (byte)((i / 64) % 2 == 1 ? 174 : 255);

          // Update texture contents with the aforementioned values.
          textureScanline.Update(pixels);
        }
        // Create lookup tables.
        for (int i = 0; i < 2048; ++i)
        {
          lookupSin[i] = (ushort)((int)(Math.Truncate(Math.Sin(2.0 * Math.PI * i / 2048.0) * 1024.0) +
            1024) & 0x7FF);
          lookupCos[i] = (ushort)((int)(Math.Truncate(Math.Cos(2.0 * Math.PI * i / 2048.0) * 1024.0) +
            1024) & 0x7FF);
        }
      }
      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)
    {
      textureScanline?.Dispose();
      texturePlasma?.Dispose();
      timer?.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));
      }
    }

    private void MainForm_Paint(object sender, PaintEventArgs e)
    {
      float scale = DeviceDpi / 96.0f;
      { // Update plasma array and texture.
        int destIndex = 0;

        for (int j = 0; j < 512; ++j)
        {
          int addX = lookupSin[((j << 2) + shift.X) & 0x7FF];
          int addC = lookupCos[((j << 2) + shift.Y) & 0x7FF];

          for (int i = 0; i < 512; ++i)
          {
            int index = (lookupSin[((i << 2) + addX) & 0x7FF] + addC) & 0x7FF;
            if (index > 1023)
              index = 2047 - index;

//            plasmaArray[destIndex++] = Utility.MakeColorGray(127 + ((index * 255) / 0x7FF), 255);
            plasmaArray[destIndex++] = plasmaPalette[((index / 4) + paletteIndex) & 0x3FF];
          }
        }
        texturePlasma.Update(plasmaArray);
      }

      // Render on the form.
      swapChain.Begin();
      try
      {
        device.Clear(DeviceClear.Color, new FloatColor(0xFFE1E2E6u));

        canvas.Begin();
        try
        {
          canvas.ContextState = CanvasContextState.FlatScene;

          // Draw plasma texture tiled.
          for (int j = 0; j <= displaySize.Y / 512; ++j)
            for (int i = 0; i <= displaySize.X / 512; ++i)
              canvas.Quad(texturePlasma, new Quad(i * 512.0f, j * 512.0f, 512.0f, 512.0f), null, null,
                BlendingEffect.Copy);

          // Apply scanline effect.
          for (int j = 0; j <= displaySize.Y / 64; ++j)
            for (int i = 0; i <= displaySize.X / 64; ++i)
              canvas.Quad(textureScanline, new Quad(i * 64.0f, j * 64.0f, 64.0f, 64.0f), null, null,
                BlendingEffect.Multiply);

          // Render information text.
          canvas.ContextState = CanvasContextState.FlatText;
          {
            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),
              $"Frame Rate: {(int)MathF.Round(timer.FrameRate)}", new ColorPair(0xB0FFFFFFu));

            textRenderer.DrawAligned(new Vector2(displaySize.X - 8.0f * scale, displaySize.Y -
              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(0xB0FFFFFFu), TextAlignment.End, TextAlignment.End);
          }
        }
        finally
        {
          canvas.End();
        }
      }
      finally
      {
        swapChain.End();
      }
      timer.Update();

      // Extract fixed-rate processing tokens, if there are any.
      int tokens = timer.ExtractTokens;

      // Advance animation by a number of fixed-rate processing tokens.
      shift.X += tokens;
      shift.Y -= tokens;
      paletteIndex += tokens;
    }

    private void Application_Idle(object sender, EventArgs e)
    {
      if (WindowState != FormWindowState.Minimized)
        Invalidate(); // Continuously repaint the form.
    }

    private static readonly uint[] plasmaPalette = [
      0x000000, 0x000000, 0x000000, 0x010000, 0x010000, 0x020001, 0x020001, 0x030001, 0x040002, 0x050002,
      0x060003, 0x070004, 0x090004, 0x0A0005, 0x0C0006, 0x0D0007, 0x0F0007, 0x110008, 0x130009, 0x15000A,
      0x17000C, 0x1A000D, 0x1C000E, 0x1F000F, 0x210010, 0x240012, 0x270013, 0x290014, 0x2C0016, 0x2F0017,
      0x320019, 0x36001A, 0x39001C, 0x3C001E, 0x3F001F, 0x430021, 0x460023, 0x4A0024, 0x4D0026, 0x510028,
      0x55002A, 0x58002C, 0x5C002E, 0x60002F, 0x640031, 0x680033, 0x6B0035, 0x6F0037, 0x730039, 0x77003B,
      0x7B003D, 0x7F003F, 0x830041, 0x870043, 0x8B0045, 0x8F0046, 0x920048, 0x96004A, 0x9A004C, 0x9E004E,
      0xA20050, 0xA50052, 0xA90054, 0xAD0055, 0xB10057, 0xB40059, 0xB8005B, 0xBB005C, 0xBF005E, 0xC20060,
      0xC50061, 0xC80063, 0xCC0065, 0xCF0066, 0xD20068, 0xD50069, 0xD8006B, 0xDA006C, 0xDD006D, 0xE0006F,
      0xE20070, 0xE50071, 0xE70072, 0xE90073, 0xEB0074, 0xED0075, 0xEF0076, 0xF10077, 0xF30078, 0xF50079,
      0xF6007A, 0xF7007A, 0xF9007B, 0xFA007B, 0xFB007C, 0xFC007C, 0xFD007D, 0xFD007D, 0xFE007D, 0xFE007E,
      0xFF007E, 0xFF007E, 0xFF007E, 0xFF007E, 0xFF007E, 0xFF007E, 0xFF007E, 0xFF017F, 0xFF017F, 0xFF017F,
      0xFF027F, 0xFF0280, 0xFF0380, 0xFF0381, 0xFF0481, 0xFF0582, 0xFF0583, 0xFF0683, 0xFF0784, 0xFF0885,
      0xFF0986, 0xFF0A87, 0xFF0B87, 0xFF0C88, 0xFF0D89, 0xFF0E8A, 0xFF0F8B, 0xFF118D, 0xFF128E, 0xFF138F,
      0xFF1590, 0xFF1691, 0xFF1893, 0xFF1994, 0xFF1B95, 0xFF1C97, 0xFF1E98, 0xFF1F99, 0xFF219B, 0xFF239C,
      0xFF259E, 0xFF269F, 0xFF28A1, 0xFF2AA2, 0xFF2CA4, 0xFF2DA5, 0xFF2FA7, 0xFF31A9, 0xFF33AA, 0xFF35AC,
      0xFF37AD, 0xFF38AF, 0xFF3AB1, 0xFF3CB2, 0xFF3EB4, 0xFF40B6, 0xFF42B7, 0xFF44B9, 0xFF45BA, 0xFF47BC,
      0xFF49BE, 0xFF4BBF, 0xFF4DC1, 0xFF4FC2, 0xFF50C4, 0xFF52C5, 0xFF54C7, 0xFF56C8, 0xFF57CA, 0xFF59CB,
      0xFF5BCD, 0xFF5CCE, 0xFF5ED0, 0xFF5FD1, 0xFF61D2, 0xFF62D4, 0xFF64D5, 0xFF65D6, 0xFF67D7, 0xFF68D8,
      0xFF69DA, 0xFF6BDB, 0xFF6CDC, 0xFF6DDD, 0xFF6EDE, 0xFF6FDF, 0xFF70E0, 0xFF71E0, 0xFF72E1, 0xFF73E2,
      0xFF74E3, 0xFF75E3, 0xFF75E4, 0xFF76E5, 0xFF77E5, 0xFF77E6, 0xFF78E6, 0xFF78E7, 0xFF79E7, 0xFF79E7,
      0xFF79E7, 0xFF7AE8, 0xFF7AE8, 0xFF7AE8, 0xFF7AE8, 0xFF7AE8, 0xFF7AE8, 0xFF7AE8, 0xFF7AE8, 0xFF79E8,
      0xFF79E7, 0xFF79E7, 0xFF78E7, 0xFF78E6, 0xFF77E6, 0xFF77E5, 0xFF76E5, 0xFF76E4, 0xFF75E4, 0xFF74E3,
      0xFF73E2, 0xFF72E1, 0xFF71E1, 0xFF71E0, 0xFF6FDF, 0xFF6EDE, 0xFF6DDD, 0xFF6CDC, 0xFF6BDB, 0xFF6ADA,
      0xFF68D9, 0xFF67D8, 0xFF66D6, 0xFF64D5, 0xFF63D4, 0xFF61D3, 0xFF60D1, 0xFF5ED0, 0xFF5DCE, 0xFF5BCD,
      0xFF59CC, 0xFF58CA, 0xFF56C9, 0xFF54C7, 0xFF53C6, 0xFF51C4, 0xFF4FC3, 0xFF4DC1, 0xFF4BBF, 0xFF4ABE,
      0xFF48BC, 0xFF46BB, 0xFF44B9, 0xFF42B7, 0xFF40B6, 0xFF3EB4, 0xFF3DB3, 0xFF3BB1, 0xFF39AF, 0xFF37AE,
      0xFF35AC, 0xFF33AA, 0xFF31A9, 0xFF30A7, 0xFF2EA6, 0xFF2CA4, 0xFF2AA3, 0xFF28A1, 0xFF27A0, 0xFF259E,
      0xFF239D, 0xFF219B, 0xFF209A, 0xFF1E98, 0xFF1D97, 0xFF1B95, 0xFF1994, 0xFF1893, 0xFF1692, 0xFF1590,
      0xFF148F, 0xFF128E, 0xFF118D, 0xFF108C, 0xFF0E8B, 0xFF0D8A, 0xFF0C89, 0xFF0B88, 0xFF0A87, 0xFF0986,
      0xFF0885, 0xFF0784, 0xFF0683, 0xFF0583, 0xFF0582, 0xFF0481, 0xFF0381, 0xFF0380, 0xFF0280, 0xFF0280,
      0xFF017F, 0xFF017F, 0xFF017F, 0xFF007E, 0xFF007E, 0xFF007E, 0xFF007E, 0xFF007E, 0xFF007E, 0xFF007E,
      0xFF017E, 0xFF017F, 0xFF027F, 0xFF027F, 0xFF0380, 0xFF0480, 0xFF0581, 0xFF0681, 0xFF0782, 0xFF0982,
      0xFF0A83, 0xFF0C84, 0xFF0D85, 0xFF0F86, 0xFF1187, 0xFF1388, 0xFF1589, 0xFF188A, 0xFF1A8B, 0xFF1C8C,
      0xFF1F8E, 0xFF218F, 0xFF2490, 0xFF2792, 0xFF2A93, 0xFF2D95, 0xFF3096, 0xFF3398, 0xFF3699, 0xFF399B,
      0xFF3C9D, 0xFF409E, 0xFF43A0, 0xFF47A2, 0xFF4AA4, 0xFF4EA5, 0xFF51A7, 0xFF55A9, 0xFF59AB, 0xFF5DAD,
      0xFF60AF, 0xFF64B1, 0xFF68B3, 0xFF6CB5, 0xFF70B6, 0xFF74B8, 0xFF77BA, 0xFF7BBC, 0xFF7FBE, 0xFF83C0,
      0xFF87C2, 0xFF8BC4, 0xFF8FC6, 0xFF93C8, 0xFF97CA, 0xFF9BCC, 0xFF9ECE, 0xFFA2D0, 0xFFA6D2, 0xFFAAD4,
      0xFFADD6, 0xFFB1D7, 0xFFB4D9, 0xFFB8DB, 0xFFBBDD, 0xFFBFDF, 0xFFC2E0, 0xFFC6E2, 0xFFC9E4, 0xFFCCE5,
      0xFFCFE7, 0xFFD2E8, 0xFFD5EA, 0xFFD8EB, 0xFFDBED, 0xFFDDEE, 0xFFE0EF, 0xFFE2F1, 0xFFE5F2, 0xFFE7F3,
      0xFFE9F4, 0xFFECF5, 0xFFEEF6, 0xFFF0F7, 0xFFF1F8, 0xFFF3F9, 0xFFF5FA, 0xFFF6FB, 0xFFF8FB, 0xFFF9FC,
      0xFFFAFC, 0xFFFBFD, 0xFFFCFD, 0xFFFDFE, 0xFFFDFE, 0xFFFEFE, 0xFFFEFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF,
      0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFEFEFE, 0xFEFEFE, 0xFEFEFE, 0xFDFDFD, 0xFDFDFD, 0xFCFCFC,
      0xFCFCFC, 0xFBFBFB, 0xFAFAFA, 0xF9F9F9, 0xF8F8F8, 0xF8F8F8, 0xF7F7F7, 0xF6F6F6, 0xF4F4F4, 0xF3F3F3,
      0xF2F2F2, 0xF1F1F1, 0xF0F0F0, 0xEEEEEE, 0xEDEDED, 0xEBEBEB, 0xEAEAEA, 0xE8E8E8, 0xE6E6E6, 0xE5E5E5,
      0xE3E3E3, 0xE1E1E1, 0xDFDFDF, 0xDDDDDD, 0xDBDBDB, 0xD9D9D9, 0xD7D7D7, 0xD5D5D5, 0xD3D3D3, 0xD1D1D1,
      0xCFCFCF, 0xCCCCCC, 0xCACACA, 0xC7C7C7, 0xC5C5C5, 0xC2C2C2, 0xC0C0C0, 0xBDBDBD, 0xBBBBBB, 0xB8B8B8,
      0xB5B5B5, 0xB3B3B3, 0xB0B0B0, 0xADADAD, 0xAAAAAA, 0xA7A7A7, 0xA4A4A4, 0xA1A1A1, 0x9E9E9E, 0x9B9B9B,
      0x989898, 0x959595, 0x919191, 0x8E8E8E, 0x8B8B8B, 0x888888, 0x848484, 0x818181, 0x7D7D7D, 0x7A7A7A,
      0x777777, 0x737373, 0x707070, 0x6C6C6C, 0x696969, 0x656565, 0x616161, 0x5E5E5E, 0x5A5A5A, 0x565656,
      0x535353, 0x4F4F4F, 0x4B4B4B, 0x474747, 0x444444, 0x404040, 0x3C3C3C, 0x383838, 0x343434, 0x313131,
      0x2D2D2D, 0x292929, 0x252525, 0x212121, 0x1D1D1D, 0x191919, 0x161616, 0x121212, 0x0E0E0E, 0x0A0A0A,
      0x060606, 0x020202, 0x010000, 0x040000, 0x060000, 0x090000, 0x0C0000, 0x0E0000, 0x110000, 0x130001,
      0x160001, 0x180001, 0x1B0001, 0x1E0001, 0x200001, 0x230001, 0x250001, 0x280001, 0x2A0001, 0x2D0001,
      0x2F0001, 0x320001, 0x340002, 0x360002, 0x390002, 0x3B0002, 0x3E0002, 0x400002, 0x420002, 0x450002,
      0x470002, 0x4A0002, 0x4C0002, 0x4E0002, 0x500002, 0x530002, 0x550003, 0x570003, 0x590003, 0x5B0003,
      0x5E0003, 0x600003, 0x620003, 0x640003, 0x660003, 0x680003, 0x6A0003, 0x6C0003, 0x6E0003, 0x700003,
      0x720003, 0x740003, 0x760004, 0x770004, 0x790004, 0x7B0004, 0x7D0004, 0x7E0004, 0x800004, 0x820004,
      0x830004, 0x850004, 0x870004, 0x880004, 0x8A0004, 0x8B0004, 0x8C0004, 0x8E0004, 0x8F0004, 0x910004,
      0x920004, 0x930004, 0x940004, 0x960004, 0x970004, 0x980005, 0x990005, 0x9A0005, 0x9B0005, 0x9C0005,
      0x9D0005, 0x9E0005, 0x9F0005, 0xA00005, 0xA00005, 0xA10005, 0xA20005, 0xA20005, 0xA30005, 0xA40005,
      0xA40005, 0xA50005, 0xA50005, 0xA60005, 0xA60005, 0xA60005, 0xA70005, 0xA70005, 0xA70005, 0xA80005,
      0xA80005, 0xA80005, 0xA80005, 0xA80005, 0xA80005, 0xA70307, 0xA60509, 0xA5080B, 0xA30A0D, 0xA20D0E,
      0xA10F10, 0xA01212, 0x9F1414, 0x9E1716, 0x9D1917, 0x9C1C19, 0x9B1E1B, 0x9A211D, 0x99231F, 0x982620,
      0x962822, 0x952B24, 0x942D26, 0x933028, 0x92322A, 0x91352B, 0x90372D, 0x8F3A2F, 0x8E3C31, 0x8D3F33,
      0x8C4134, 0x8A4436, 0x894638, 0x88493A, 0x874B3C, 0x864E3D, 0x85503F, 0x845341, 0x835543, 0x825845,
      0x815A46, 0x805D48, 0x7F5F4A, 0x7D624C, 0x7C644E, 0x7B6750, 0x7A6951, 0x796C53, 0x786E55, 0x777157,
      0x767359, 0x75765A, 0x74785C, 0x737B5E, 0x727D60, 0x708062, 0x6F8263, 0x6E8565, 0x6D8767, 0x6C8A69,
      0x6B8C6B, 0x6A8F6C, 0x69916E, 0x689470, 0x679672, 0x669974, 0x659B75, 0x639E77, 0x62A079, 0x61A37B,
      0x60A57D, 0x5FA87F, 0x5EAA80, 0x5DAC82, 0x5CAF84, 0x5BB186, 0x5AB488, 0x59B689, 0x57B98B, 0x56BB8D,
      0x55BE8F, 0x54C091, 0x53C392, 0x52C594, 0x51C896, 0x50CA98, 0x4FCD9A, 0x4ECF9B, 0x4DD29D, 0x4CD49F,
      0x4AD7A1, 0x49D9A3, 0x48DCA5, 0x47DEA6, 0x46E1A8, 0x45E3AA, 0x44E6AC, 0x43E8AE, 0x42EBAF, 0x41EDB1,
      0x40F0B3, 0x3FF2B5, 0x3DF5B7, 0x3CF7B8, 0x3BFABA, 0x3AFCBC, 0x39FFBE, 0x39FFBE, 0x39FFBE, 0x39FFBE,
      0x39FFBE, 0x39FFBE, 0x39FFBF, 0x39FEBF, 0x39FEBF, 0x39FEBF, 0x39FEBF, 0x39FEC0, 0x39FDC0, 0x39FDC1,
      0x39FDC1, 0x39FCC1, 0x39FCC2, 0x39FBC2, 0x39FBC3, 0x39FBC3, 0x39FAC4, 0x39FAC4, 0x39F9C5, 0x39F9C6,
      0x39F8C6, 0x39F7C7, 0x39F7C8, 0x39F6C8, 0x39F6C9, 0x39F5CA, 0x39F4CB, 0x39F4CC, 0x39F3CC, 0x39F2CD,
      0x39F2CE, 0x39F1CF, 0x39F0D0, 0x39EFD1, 0x39EFD2, 0x39EED3, 0x39EDD3, 0x39ECD4, 0x39ECD5, 0x39EBD6,
      0x39EAD7, 0x39E9D8, 0x39E8D9, 0x39E8DA, 0x39E7DB, 0x39E6DC, 0x39E5DD, 0x39E4DE, 0x39E3DF, 0x39E3E0,
      0x39E2E1, 0x39E1E2, 0x39E0E3, 0x39DFE4, 0x39DEE5, 0x39DEE6, 0x39DDE7, 0x39DCE8, 0x39DBE9, 0x39DAEA,
      0x39DAEB, 0x39D9EC, 0x39D8ED, 0x39D7EE, 0x39D7EE, 0x39D6EF, 0x39D5F0, 0x39D5F1, 0x39D4F2, 0x39D3F3,
      0x39D3F3, 0x39D2F4, 0x39D1F5, 0x39D1F6, 0x39D0F6, 0x39D0F7, 0x39CFF8, 0x39CFF8, 0x39CEF9, 0x39CEF9,
      0x39CDFA, 0x39CDFA, 0x39CCFB, 0x39CCFB, 0x39CCFC, 0x39CBFC, 0x39CBFD, 0x39CBFD, 0x39CAFD, 0x39CAFE,
      0x39CAFE, 0x39CAFE, 0x39CAFE, 0x39C9FF, 0x39C9FF, 0x39C9FF, 0x39C9FF, 0x39C9FF, 0x39C9FF, 0x3AC9FF,
      0x3BCAFF, 0x3CCBFF, 0x3ECBFF, 0x3FCCFF, 0x40CDFF, 0x41CDFF, 0x43CEFF, 0x44CFFF, 0x45CFFF, 0x47D0FF,
      0x48D1FF, 0x49D1FF, 0x4AD2FF, 0x4CD3FF, 0x4DD3FF, 0x4ED4FF, 0x4FD5FF, 0x51D5FF, 0x52D6FF, 0x53D7FF,
      0x54D7FF, 0x56D8FF, 0x57D9FF, 0x58D9FF, 0x59DAFF, 0x5ADAFF, 0x5CDBFF, 0x5DDCFF, 0x5EDCFF, 0x5FDDFF,
      0x60DEFF, 0x61DEFF, 0x62DFFF, 0x64DFFF, 0x65E0FF, 0x66E0FF, 0x67E1FF, 0x68E2FF, 0x69E2FF, 0x6AE3FF,
      0x6BE3FF, 0x6CE4FF, 0x6DE4FF, 0x6EE5FF, 0x6FE5FF, 0x70E6FF, 0x71E6FF, 0x72E7FF, 0x73E7FF, 0x74E8FF,
      0x75E8FF, 0x76E9FF, 0x77E9FF, 0x77EAFF, 0x78EAFF, 0x79EBFF, 0x7AEBFF, 0x7BEBFF, 0x7CECFF, 0x7CECFF,
      0x7DEDFF, 0x7EEDFF, 0x7FEDFF, 0x7FEEFF, 0x80EEFF, 0x81EFFF, 0x81EFFF, 0x82EFFF, 0x83F0FF, 0x83F0FF,
      0x84F0FF, 0x84F1FF, 0x85F1FF, 0x86F1FF, 0x86F1FF, 0x87F2FF, 0x87F2FF, 0x87F2FF, 0x88F2FF, 0x88F3FF,
      0x89F3FF, 0x89F3FF, 0x8AF3FF, 0x8AF3FF, 0x8AF4FF, 0x8BF4FF, 0x8BF4FF, 0x8BF4FF, 0x8BF4FF, 0x8CF4FF,
      0x8CF4FF, 0x8CF5FF, 0x8CF5FF, 0x8CF5FF, 0x8DF5FF, 0x8DF5FF, 0x8DF5FF, 0x8DF5FF, 0x8DF5FF, 0x8DF5FF,
      0x8DF5FF, 0x8DF5FF, 0x8DF5FF, 0x8DF5FF, 0x8DF5FF, 0x8DF4FE, 0x8DF4FE, 0x8CF4FE, 0x8CF3FD, 0x8CF3FD,
      0x8CF3FC, 0x8BF2FC, 0x8BF1FB, 0x8AF1FA, 0x8AF0FA, 0x8AEFF9, 0x89EEF8, 0x89EDF7, 0x88ECF6, 0x87EBF5,
      0x87EAF4, 0x86E9F3, 0x86E8F1, 0x85E7F0, 0x84E5EF, 0x83E4ED, 0x82E3EC, 0x82E1EA, 0x81E0E9, 0x80DEE7,
      0x7FDDE6, 0x7EDBE4, 0x7DD9E2, 0x7CD7E0, 0x7BD6DE, 0x7AD4DC, 0x79D2DA, 0x78D0D8, 0x76CED6, 0x75CCD4,
      0x74CAD2, 0x73C8D0, 0x72C5CD, 0x70C3CB, 0x6FC1C9, 0x6EBEC6, 0x6CBCC4, 0x6BBAC1, 0x69B7BF, 0x68B5BC,
      0x66B2B9, 0x65AFB7, 0x63ADB4, 0x62AAB1, 0x60A7AE, 0x5FA5AB, 0x5DA2A8, 0x5C9FA6, 0x5A9CA3, 0x58999F,
      0x56969C, 0x559399, 0x539096, 0x518D93, 0x4F8A90, 0x4E878C, 0x4C8489, 0x4A8186, 0x487D83, 0x467A7F,
      0x44777C, 0x437478, 0x417075, 0x3F6D71, 0x3D6A6E, 0x3B666A, 0x396367, 0x375F63, 0x355C60, 0x33585C,
      0x315558, 0x2F5155, 0x2D4E51, 0x2B4A4D, 0x294649, 0x264346, 0x243F42, 0x223C3E, 0x20383A, 0x1E3436,
      0x1C3133, 0x1A2D2F, 0x18292B, 0x162527, 0x132223, 0x111E1F, 0x0F1A1B, 0x0D1717, 0x0B1314, 0x090F10,
      0x060B0C, 0x040808, 0x020404, 0x000000];
  }
}