private void ConvertToI4(Bitmap imageToConvert)
        {
            SetupCoder(imageToConvert);
            /* We will need to add a grayscale check in the future also */
            if (UniqueColors.Count > 16)
            {
                WuQuantizer quantizer = new WuQuantizer();
                imageToConvert = new Bitmap(quantizer.QuantizeImage(imageToConvert, 0, 0, new Histogram(), 16));
                SetupCoder(imageToConvert);
            }

            /* Set type, I 4-bit */
            Format       = GBI.G_IM_FMT_I;
            Size         = GBI.G_IM_SIZ_4b;
            n64ImageType = N64ImageType.i4;
            /* Generate texture buffer */
            Data    = new byte[(imageToConvert.Width * imageToConvert.Height) / 2];
            Palette = null;

            /* Loop through pixels, convert to I 4-bit, write to texture buffer */
            for (int i = 0, j = 0; i < Raw.Length; i += 8, j++)
            {
                Data[j] = (byte)(((Raw[i] / 16) << 4) | ((Raw[i + 4] / 16) & 0xF));
            }
        }
        private void ConvertToCi4(Bitmap imageToConvert)
        {
            /* Convert to CI */
            if (UniqueColors.Count > 16)
            {
                WuQuantizer quantizer = new WuQuantizer();
                imageToConvert = new Bitmap(quantizer.QuantizeImage(imageToConvert, 0, 0, new Histogram(), 16));
                SetupCoder(imageToConvert);
            }
            /* Set type, CI 4-bit */
            Format       = GBI.G_IM_FMT_CI;
            Size         = GBI.G_IM_SIZ_4b;
            n64ImageType = N64ImageType.ci4;
            /* Generate texture buffer */
            Data = new byte[(imageToConvert.Width * imageToConvert.Height) / 2];

            /* Generate 16-color RGBA5551 palette */
            Palette = GeneratePalette(UniqueColors, 16);

            /* Loop through pixels, get palette indexes, write to texture buffer */
            for (int i = 0, j = 0; i < Raw.Length; i += 8, j++)
            {
                ushort RGBA5551_1 = ToRGBA5551(Raw[i + 2], Raw[i + 1], Raw[i], Raw[i + 3]);
                ushort RGBA5551_2 = ToRGBA5551(Raw[i + 6], Raw[i + 5], Raw[i + 4], Raw[i + 7]);
                byte   Value      = (byte)(
                    ((GetPaletteIndex(Palette, RGBA5551_1)) << 4) |
                    ((GetPaletteIndex(Palette, RGBA5551_2) & 0xF)));
                Data[j] = Value;
            }
        }
        private void ConvertToCi8(Bitmap imageToConvert)
        {
            if (UniqueColors.Count > 256)
            {
                WuQuantizer quantizer = new WuQuantizer();
                imageToConvert = new Bitmap(quantizer.QuantizeImage(imageToConvert, 0, 0, new Histogram(), 256));
                SetupCoder(imageToConvert);
            }

            /* Set type, CI 8-bit */
            Format       = GBI.G_IM_FMT_CI;
            Size         = GBI.G_IM_SIZ_8b;
            n64ImageType = N64ImageType.ci8;

            /* Generate texture buffer
             * NFL BLitz requires CI8 to be padded to 8 bytes */
            int dataSize = (imageToConvert.Width * imageToConvert.Height);

            while (dataSize % 8 != 0)
            {
                dataSize++;
            }
            Data = new byte[dataSize];

            /* Generate 256-color RGBA5551 palette */
            Palette = GeneratePalette(UniqueColors, 256);

            /* Loop through pixels, get palette indexes, write to texture buffer */
            for (int i = 0, j = 0; i < Raw.Length; i += 4, j++)
            {
                ushort RGBA5551 = ToRGBA5551(Raw[i + 2], Raw[i + 1], Raw[i], Raw[i + 3]);
                Data[j] = (byte)GetPaletteIndex(Palette, RGBA5551);
            }
        }
        private void ConvertToc16PlusI4(Bitmap imageToConvert)
        {
            //split image in half
            Bitmap c16, i4;

            c16 = i4 = new Bitmap(imageToConvert.Width, imageToConvert.Height / 2);
            Rectangle rect = new Rectangle(0, 0, imageToConvert.Width, imageToConvert.Height / 2);

            c16  = imageToConvert.Clone(rect, imageToConvert.PixelFormat);
            rect = new Rectangle(0, imageToConvert.Height / 2, imageToConvert.Width, imageToConvert.Height / 2);
            i4   = imageToConvert.Clone(rect, imageToConvert.PixelFormat);

            ImageCoder c16ImageCoder = new ImageCoder();

            c16ImageCoder = new N64ImageViewer.ImageCoder();
            c16ImageCoder.ConvertToC16(c16);
            ImageCoder i4ImageCoder = new ImageCoder();

            i4ImageCoder.ConvertToI4(i4);
            n64ImageType = N64ImageType.c16PlusI4;
            List <byte> tempData = new List <byte>();

            tempData.AddRange(c16ImageCoder.Data);
            tempData.AddRange(i4ImageCoder.Data);
            Data  = tempData.ToArray();
            Width = imageToConvert.Width;
            // Height is used for both the C16 and I4 so we need to split it in half, since each image makes up half
            Height   = imageToConvert.Height / 2;
            HasAlpha = c16ImageCoder.HasAlpha;
            return;
        }
        private void ConvertToia8(Bitmap imageToConvert)
        {
            /* Set type, IA 8-bit */
            Format       = GBI.G_IM_FMT_IA;
            Size         = GBI.G_IM_SIZ_8b;
            n64ImageType = N64ImageType.ia8;
            /* Generate texture buffer */
            Data    = new byte[imageToConvert.Width * imageToConvert.Height];
            Palette = null;

            /* Loop through pixels, convert to IA 8-bit, write to texture buffer */
            for (int i = 0, j = 0; i < Raw.Length; i += 4, j++)
            {
                Data[j] = (byte)(((Raw[i] / 16) << 4) | ((Raw[i + 3] / 16) & 0xF));
            }
        }
        private void ConvertToI8(Bitmap imageToConvert)
        {
            /* Set type, I 8-bit */
            Format       = GBI.G_IM_FMT_I;
            Size         = GBI.G_IM_SIZ_8b;
            n64ImageType = N64ImageType.notSupported; //NFL Blitz does not make use of I8 Images
                                                      /* Generate texture buffer */
            Data    = new byte[imageToConvert.Width * imageToConvert.Height];
            Palette = null;

            /* Loop through pixels, convert to I 8-bit, write to texture buffer */
            for (int i = 0, j = 0; i < Raw.Length; i += 4, j++)
            {
                Data[j] = Raw[i];
            }
        }
        private void ConvertToC16(Bitmap imageToConvert)
        {
            SetupCoder(imageToConvert);
            /* Set type, RGBA 16-bit */
            Format       = GBI.G_IM_FMT_RGBA;
            Size         = GBI.G_IM_SIZ_16b;
            n64ImageType = N64ImageType.c16;
            /* Generate texture buffer */
            Data    = new byte[imageToConvert.Width * imageToConvert.Height * 2];
            Palette = null;

            /* Loop through pixels, convert to RGBA5551, write to texture buffer */
            for (int i = 0, j = 0; i < Raw.Length; i += 4, j += 2)
            {
                ushort RGBA5551 = ToRGBA5551(Raw[i + 2], Raw[i + 1], Raw[i], Raw[i + 3]);
                Data[j]     = (byte)(RGBA5551 >> 8);
                Data[j + 1] = (byte)(RGBA5551 & 0xFF);
            }
        }
        public void ConvertTo(Bitmap imageToConvert, N64ImageType type)
        {
            SetupCoder(imageToConvert);
            switch (type)
            {
            case N64ImageType.c16:
            {
                ConvertToC16(imageToConvert);
                return;
            };

            case N64ImageType.ci8:
            {
                ConvertToCi8(imageToConvert);
                return;
            }

            case N64ImageType.c16PlusI4:
            {
                ConvertToc16PlusI4(imageToConvert);
                return;
            }
            }
        }
        /// <summary>
        /// Converts given ObjFile.imageToConvert into N64 texture
        /// </summary>
        /// <param name="imageToConvert">imageToConvert to convert</param>
        public void Convert(Bitmap imageToConvert, bool checkC16I4 = true)
        {
            // C16-I4 Check, Pretty hacky...
            if (checkC16I4 && imageToConvert.Height % 2 == 0)
            {
                //even height, split it in half
                Bitmap c16, i4;
                c16 = i4 = new Bitmap(imageToConvert.Width, imageToConvert.Height / 2);
                Rectangle rect = new Rectangle(0, 0, imageToConvert.Width, imageToConvert.Height / 2);
                c16  = imageToConvert.Clone(rect, imageToConvert.PixelFormat);
                rect = new Rectangle(0, imageToConvert.Height / 2, imageToConvert.Width, imageToConvert.Height / 2);
                i4   = imageToConvert.Clone(rect, imageToConvert.PixelFormat);

                ImageCoder c16ImageCoder = new ImageCoder();
                c16ImageCoder = new N64ImageViewer.ImageCoder();
                c16ImageCoder.Convert(c16, false);
                ImageCoder i4ImageCoder = new ImageCoder();
                i4ImageCoder.Convert(i4, false);
                if (c16ImageCoder.n64ImageType.Equals(N64ImageType.c16) && i4ImageCoder.n64ImageType.Equals(N64ImageType.i4))
                {
                    n64ImageType = N64ImageType.c16PlusI4;
                    List <byte> tempData = new List <byte>();
                    tempData.AddRange(c16ImageCoder.Data);
                    tempData.AddRange(i4ImageCoder.Data);
                    Data     = tempData.ToArray();
                    Width    = imageToConvert.Width;
                    Height   = imageToConvert.Height / 2; // Height is used for both the C16 and I4 so we need to split it in half, since each image makes up half
                    HasAlpha = c16ImageCoder.HasAlpha;
                    return;
                }
            }
            //End C16-I4 check
            try
            {
                SetupCoder(imageToConvert);
                if (IsGrayscale == true)
                {
                    if (HasAlpha == true)
                    {
                        /* Convert to IA */
                        if (UniqueColors.Count <= 16)
                        {
                            ConvertToia8(imageToConvert);
                        }
                    }
                    else
                    {
                        /* Convert to I */
                        if (UniqueColors.Count <= 16)
                        {
                            ConvertToI4(imageToConvert);
                        }
                        else if (UniqueColors.Count <= 256 && imageToConvert.Width * imageToConvert.Height <= 4096)
                        {
                            ConvertToI8(imageToConvert);
                        }
                        else
                        {
                            /* Uh-oh, too many grayshades OR invalid size! */
                            throw new Exception("Too many grayshades in texture OR invalid size");
                        }
                    }
                }
                else
                {
                    /* Convert to CI */
                    if (UniqueColors.Count <= 16)
                    {
                        ConvertToCi4(imageToConvert);
                    }
                    else if (UniqueColors.Count <= 256)
                    {
                        ConvertToCi8(imageToConvert);
                    }
                    else
                    {
                        ConvertToC16(imageToConvert);
                    }
                }
            }
            catch (Exception ex)
            {
                //   System.Windows.Forms.MessageBox.Show("imageToConvert '" + imageToConvert.DisplayName + "': " + ex.Message, "Exception", System.Windows.Forms.MessageBoxButtons.OK, System.Windows.Forms.MessageBoxIcon.Exclamation);
                //  SetInvalidTexture(imageToConvert);
            }

            /* Pack texture type */
            Type = (byte)((Format << 5) | (Size << 3));
        }