Example #1
0
        // Writes a block compressed monochromatic font texture.
        static unsafe Graphics.Image GetCompressedMono(Bitmap bitmap, SpriteFontAsset options)
        {
            if ((bitmap.Width & 3) != 0 ||
                (bitmap.Height & 3) != 0)
            {
                throw new ArgumentException("Block compression requires texture size to be a multiple of 4.");
            }

            var image       = Graphics.Image.New2D(bitmap.Width, bitmap.Height, 1, Graphics.PixelFormat.BC2_UNorm);
            var pixelBuffer = (BC2Pixel *)image.PixelBuffer[0].DataPointer;

            using (var bitmapData = new BitmapUtils.PixelAccessor(bitmap, ImageLockMode.ReadOnly))
            {
                for (int y = 0; y < bitmap.Height; y += 4)
                {
                    for (int x = 0; x < bitmap.Width; x += 4)
                    {
                        BC2Pixel bc2Pixel;
                        CompressBlock(bitmapData, x, y, options, out bc2Pixel);
                        *pixelBuffer = bc2Pixel;
                        pixelBuffer++;
                    }
                }
            }
            return(image);
        }
Example #2
0
        // Searches a 2D bitmap for characters that are surrounded by a marker pink color.
        static IEnumerable <Rectangle> FindGlyphs(Bitmap bitmap)
        {
            using (var bitmapData = new BitmapUtils.PixelAccessor(bitmap, ImageLockMode.ReadOnly))
            {
                for (int y = 1; y < bitmap.Height; y++)
                {
                    for (int x = 1; x < bitmap.Width; x++)
                    {
                        // Look for the top left corner of a character (a pixel that is not pink, but was pink immediately to the left and above it)
                        if (!IsMarkerColor(bitmapData[x, y]) &&
                            IsMarkerColor(bitmapData[x - 1, y]) &&
                            IsMarkerColor(bitmapData[x, y - 1]))
                        {
                            // Measure the size of this character.
                            int w = 1, h = 1;

                            while ((x + w < bitmap.Width) && !IsMarkerColor(bitmapData[x + w, y]))
                            {
                                w++;
                            }

                            while ((y + h < bitmap.Height) && !IsMarkerColor(bitmapData[x, y + h]))
                            {
                                h++;
                            }

                            yield return(new Rectangle(x, y, w, h));
                        }
                    }
                }
            }
        }
Example #3
0
        // Writes an uncompressed 32 bit font texture.
        static Graphics.Image GetImageRgba32(Bitmap bitmap)
        {
            var image       = Graphics.Image.New2D(bitmap.Width, bitmap.Height, 1, Graphics.PixelFormat.R8G8B8A8_UNorm);
            var pixelBuffer = image.PixelBuffer[0];

            using (var bitmapData = new BitmapUtils.PixelAccessor(bitmap, ImageLockMode.ReadOnly))
            {
                for (int y = 0; y < bitmap.Height; y++)
                {
                    for (int x = 0; x < bitmap.Width; x++)
                    {
                        var color = bitmapData[x, y];
                        pixelBuffer.SetPixel(x, y, new Core.Mathematics.Color(color.R, color.G, color.B, color.A));
                    }
                }
            }
            return(image);
        }
Example #4
0
        // We want to compress our font textures, because, like, smaller is better,
        // right? But a standard DXT compressor doesn't do a great job with fonts that
        // are in premultiplied alpha format. Our font data is greyscale, so all of the
        // RGBA channels have the same value. If one channel is compressed differently
        // to another, this causes an ugly variation in brightness of the rendered text.
        // Also, fonts are mostly either black or white, with grey values only used for
        // antialiasing along their edges. It is very important that the black and white
        // areas be accurately represented, while the precise value of grey is less
        // important.
        //
        // Trouble is, your average DXT compressor knows nothing about these
        // requirements. It will optimize to minimize a generic error metric such as
        // RMS, but this will often sacrifice crisp black and white in exchange for
        // needless accuracy of the antialiasing pixels, or encode RGB differently to
        // alpha. UGLY!
        //
        // Fortunately, encoding monochrome fonts turns out to be trivial. Using DXT3,
        // we can fix the end colors as black and white, which gives guaranteed exact
        // encoding of the font inside and outside, plus two fractional values for edge
        // antialiasing. Also, these RGB values (0, 1/3, 2/3, 1) map exactly to four of
        // the possible 16 alpha values available in DXT3, so we can ensure the RGB and
        // alpha channels always exactly match.

        static void CompressBlock(BitmapUtils.PixelAccessor bitmapData, int blockX, int blockY, SpriteFontAsset options, out BC2Pixel bc2Pixel)
        {
            long alphaBits = 0;
            int  rgbBits   = 0;

            int pixelCount = 0;

            for (int y = 0; y < 4; y++)
            {
                for (int x = 0; x < 4; x++)
                {
                    long alpha;
                    int  rgb;

                    int value = bitmapData[blockX + x, blockY + y].A;

                    if (options.NoPremultiply)
                    {
                        // If we are not pre-multiplied, RGB is always white and we have 4 bit alpha.
                        alpha = value >> 4;
                        rgb   = 0;
                    }
                    else
                    {
                        // For pre-multiplied encoding, quantize the source value to 2 bit precision.
                        if (value < 256 / 6)
                        {
                            alpha = 0;
                            rgb   = 1;
                        }
                        else if (value < 256 / 2)
                        {
                            alpha = 5;
                            rgb   = 3;
                        }
                        else if (value < 256 * 5 / 6)
                        {
                            alpha = 10;
                            rgb   = 2;
                        }
                        else
                        {
                            alpha = 15;
                            rgb   = 0;
                        }
                    }

                    // Add this pixel to the alpha and RGB bit masks.
                    alphaBits |= alpha << (pixelCount * 4);
                    rgbBits   |= rgb << (pixelCount * 2);

                    pixelCount++;
                }
            }

            // Output the alpha bit mask.
            bc2Pixel.AlphaBits = alphaBits;

            // Output the two endpoint colors (black and white in 5.6.5 format).
            bc2Pixel.EndPoint = 0x0000FFFF;

            // Output the RGB bit mask.
            bc2Pixel.RgbBits = rgbBits;
        }
Example #5
0
        // Searches a 2D bitmap for characters that are surrounded by a marker pink color.
        static IEnumerable<Rectangle> FindGlyphs(Bitmap bitmap)
        {
            using (var bitmapData = new BitmapUtils.PixelAccessor(bitmap, ImageLockMode.ReadOnly))
            {
                for (int y = 1; y < bitmap.Height; y++)
                {
                    for (int x = 1; x < bitmap.Width; x++)
                    {
                        // Look for the top left corner of a character (a pixel that is not pink, but was pink immediately to the left and above it)
                        if (!IsMarkerColor(bitmapData[x, y]) &&
                             IsMarkerColor(bitmapData[x - 1, y]) &&
                             IsMarkerColor(bitmapData[x, y - 1]))
                        {
                            // Measure the size of this character.
                            int w = 1, h = 1;

                            while ((x + w < bitmap.Width) && !IsMarkerColor(bitmapData[x + w, y]))
                            {
                                w++;
                            }

                            while ((y + h < bitmap.Height) && !IsMarkerColor(bitmapData[x, y + h]))
                            {
                                h++;
                            }

                            yield return new Rectangle(x, y, w, h);
                        }
                    }
                }
            }
        }
        // Writes a block compressed monochromatic font texture.
        static unsafe Graphics.Image GetCompressedMono(Bitmap bitmap, SpriteFontAsset options)
        {
            if ((bitmap.Width & 3) != 0 ||
                (bitmap.Height & 3) != 0)
            {
                throw new ArgumentException("Block compression requires texture size to be a multiple of 4.");
            }

            var image = Graphics.Image.New2D(bitmap.Width, bitmap.Height, 1, Graphics.PixelFormat.BC2_UNorm);
            var pixelBuffer = (BC2Pixel*)image.PixelBuffer[0].DataPointer;
            using (var bitmapData = new BitmapUtils.PixelAccessor(bitmap, ImageLockMode.ReadOnly))
            {
                for (int y = 0; y < bitmap.Height; y += 4)
                {
                    for (int x = 0; x < bitmap.Width; x += 4)
                    {
                        BC2Pixel bc2Pixel;
                        CompressBlock( bitmapData, x, y, options, out bc2Pixel);
                        *pixelBuffer = bc2Pixel;
                        pixelBuffer++;
                    }
                }
            }
            return image;
        }
 // Writes an uncompressed 32 bit font texture.
 static Graphics.Image GetImageRgba32(Bitmap bitmap)
 {
     var image = Graphics.Image.New2D(bitmap.Width, bitmap.Height, 1, Graphics.PixelFormat.R8G8B8A8_UNorm);
     var pixelBuffer = image.PixelBuffer[0];
     using (var bitmapData = new BitmapUtils.PixelAccessor(bitmap, ImageLockMode.ReadOnly))
     {
         for (int y = 0; y < bitmap.Height; y++)
         {
             for (int x = 0; x < bitmap.Width; x++)
             {
                 var color = bitmapData[x, y];
                 pixelBuffer.SetPixel(x, y, new Core.Mathematics.Color(color.R, color.G, color.B, color.A));
             }
         }
     }
     return image;
 }