protected override bool TryCopyFrom(
            BitmapContent sourceBitmap, Rectangle sourceRegion, Rectangle destinationRegion)
        {
            if (!sourceBitmap.TryGetFormat(out SurfaceFormat sourceFormat))
            {
                return(false);
            }

            TryGetFormat(out SurfaceFormat format);

            // A shortcut for copying the entire bitmap to another bitmap of the same type and format
            if (format == sourceFormat &&
                sourceRegion == new Rectangle(0, 0, Width, Height) &&
                sourceRegion == destinationRegion)
            {
                SetPixelData(sourceBitmap.GetPixelData());
                return(true);
            }

            // Destination region copy is not yet supported
            if (destinationRegion != new Rectangle(0, 0, Width, Height))
            {
                return(false);
            }

            if (sourceBitmap is PixelBitmapContent <RgbaVector> &&
                sourceRegion.Width == destinationRegion.Width &&
                sourceRegion.Height == destinationRegion.Height)
            {
                ATICompressor.CompressionFormat targetFormat;
                switch (format)
                {
                case SurfaceFormat.RgbaAtcExplicitAlpha:
                    targetFormat = ATICompressor.CompressionFormat.AtcRgbaExplicitAlpha;
                    break;

                case SurfaceFormat.RgbaAtcInterpolatedAlpha:
                    targetFormat = ATICompressor.CompressionFormat.AtcRgbaInterpolatedAlpha;
                    break;

                default:
                    return(false);
                }

                var sourceData     = sourceBitmap.GetPixelData();
                var compressedData = ATICompressor.Compress(sourceData, Width, Height, targetFormat);
                SetPixelData(compressedData);
                return(true);
            }
            try
            {
                Copy(sourceBitmap, sourceRegion, this, destinationRegion);
                return(true);
            }
            catch (InvalidOperationException)
            {
                return(false);
            }
        }
Ejemplo n.º 2
0
 // Constructor.
 public Glyph(Rune character, BitmapContent bitmap, Rectangle?subrect = null)
 {
     Character = character;
     Bitmap    = bitmap;
     Subrect   = subrect.GetValueOrDefault(new Rectangle(0, 0, bitmap.Width, bitmap.Height));
     Width     = bitmap.Width;
     Height    = bitmap.Height;
 }
        protected override bool TryCopyFrom(BitmapContent sourceBitmap, Rectangle sourceRegion, Rectangle destinationRegion)
        {
            if (!sourceBitmap.TryGetFormat(out SurfaceFormat sourceFormat))
            {
                return(false);
            }

            // A shortcut for copying the entire bitmap to another bitmap of the same type and format
            if (SurfaceFormat.RgbEtc1 == sourceFormat && (sourceRegion == new Rectangle(0, 0, Width, Height)) && sourceRegion == destinationRegion)
            {
                SetPixelData(sourceBitmap.GetPixelData());
                return(true);
            }

            // Destination region copy is not yet supported
            if (destinationRegion != new Rectangle(0, 0, Width, Height))
            {
                return(false);
            }

            // If the source is not Vector4 or requires resizing, send it through BitmapContent.Copy
            if (sourceBitmap is PixelBitmapContent <RgbaVector> &&
                sourceRegion.Width == destinationRegion.Width &&
                sourceRegion.Height == destinationRegion.Height)
            {
                // Create the texture object in the PVR library
                var sourceData = sourceBitmap.GetPixelData();
                var rgba32F    = (PixelFormat)0x2020202061626772; // static const PixelType PVRStandard32PixelType = PixelType('r', 'g', 'b', 'a', 32, 32, 32, 32);
                using (var pvrTexture = PVRTexture.CreateTexture(sourceData, (uint)sourceBitmap.Width, (uint)sourceBitmap.Height, 1,
                                                                 rgba32F, true, VariableType.Float, ColourSpace.lRGB))
                {
                    // Resize the bitmap if needed
                    if ((sourceBitmap.Width != Width) || (sourceBitmap.Height != Height))
                    {
                        pvrTexture.Resize((uint)Width, (uint)Height, 1, ResizeMode.Cubic);
                    }
                    pvrTexture.Transcode(PixelFormat.ETC1, VariableType.UnsignedByte, ColourSpace.lRGB /*, CompressorQuality.ETCMediumPerceptual, true*/);
                    var texDataSize = pvrTexture.GetTextureDataSize(0);
                    var texData     = new byte[texDataSize];
                    pvrTexture.GetTextureData(texData, texDataSize);
                    SetPixelData(texData);
                }
                return(true);
            }
            try
            {
                Copy(sourceBitmap, sourceRegion, this, destinationRegion);
                return(true);
            }
            catch (InvalidOperationException)
            {
                return(false);
            }
        }
        protected override bool TryCopyTo(
            BitmapContent dstBitmap, Rectangle srcRegion, Rectangle dstRegion)
        {
            if (dstBitmap == null)
            {
                throw new ArgumentNullException(nameof(dstBitmap));
            }

            if (!dstBitmap.TryGetFormat(out SurfaceFormat destinationFormat))
            {
                return(false);
            }

            // A shortcut for copying the entire bitmap to another bitmap of the same type and format
            if (_format == destinationFormat &&
                srcRegion == new Rectangle(0, 0, Width, Height) &&
                srcRegion == dstRegion)
            {
                dstBitmap.SetPixelData(GetPixelData());
                return(true);
            }

            if (dstBitmap is PixelBitmapContent <RgbaVector> dst &&
                srcRegion.Width == dstRegion.Width &&
                srcRegion.Height == dstRegion.Height)
            {
                // TODO: use Image.ConvertPixels

                // Convert to a RgbaVector format
                for (int y = 0; y < srcRegion.Height; y++)
                {
                    var srcRow = GetRowSpan(srcRegion.Top + y);
                    var dstRow = dst.GetRowSpan(dstRegion.Top + y);
                    for (int x = 0; x < srcRegion.Width; x++)
                    {
                        dstRow[dstRegion.Left + x].FromScaledVector(
                            srcRow[srcRegion.Left + x].ToScaledVector4());
                    }
                }
                return(true);
            }

            try
            {
                Copy(this, srcRegion, dstBitmap, dstRegion);
                return(true);
            }
            catch (InvalidOperationException)
            {
                return(false);
            }
        }
        protected override bool TryCopyFrom(
            BitmapContent srcBitmap, Rectangle srcRegion, Rectangle dstRegion)
        {
            if (srcBitmap == null)
            {
                throw new ArgumentNullException(nameof(srcBitmap));
            }

            if (!srcBitmap.TryGetFormat(out SurfaceFormat sourceFormat))
            {
                return(false);
            }

            // A shortcut for copying the entire bitmap to another bitmap of the same type and format
            if (_format == sourceFormat &&
                srcRegion == new Rectangle(0, 0, Width, Height) &&
                srcRegion == dstRegion)
            {
                SetPixelData(srcBitmap.GetPixelData());
                return(true);
            }

            // If the source is RgbaVector and doesn't require resizing, just copy
            if (srcBitmap is PixelBitmapContent <RgbaVector> src &&
                srcRegion.Width == dstRegion.Width &&
                srcRegion.Height == dstRegion.Height)
            {
                // TODO: use Image.ConvertPixels

                for (int y = 0; y < srcRegion.Height; y++)
                {
                    var srcRow = src.GetRowSpan(srcRegion.Top + y);
                    var dstRow = GetRowSpan(dstRegion.Top + y);

                    for (int x = 0; x < srcRegion.Width; x++)
                    {
                        dstRow[dstRegion.X + x].FromScaledVector(srcRow[srcRegion.Left + x].ToScaledVector4());
                    }
                }
                return(true);
            }

            try
            {
                Copy(srcBitmap, srcRegion, this, dstRegion);
                return(true);
            }
            catch (InvalidOperationException)
            {
                return(false);
            }
        }
Ejemplo n.º 6
0
        /// <summary>
        /// Converts all bitmaps for this texture to a different format.
        /// </summary>
        /// <param name="newBitmapType">
        /// Type being converted to.
        /// The new type must be a subclass of BitmapContent,
        /// such as PixelBitmapContent or DxtBitmapContent.
        /// </param>
        public void ConvertBitmapType(Type newBitmapType)
        {
            if (newBitmapType == null)
            {
                throw new ArgumentNullException(nameof(newBitmapType));
            }

            if (!newBitmapType.IsSubclassOf(typeof(BitmapContent)))
            {
                throw new ArgumentException(
                          $"Type '{newBitmapType}' is not a subclass of BitmapContent.");
            }

            if (newBitmapType.IsAbstract)
            {
                throw new ArgumentException(
                          $"Type '{newBitmapType}' is abstract and cannot be allocated.");
            }

            if (newBitmapType.ContainsGenericParameters)
            {
                throw new ArgumentException(
                          $"Type '{newBitmapType}' contains generic parameters and cannot be allocated.");
            }

            if (newBitmapType.GetConstructor(new Type[2] {
                typeof(int), typeof(int)
            }) == null)
            {
                throw new ArgumentException(
                          $"Type '{newBitmapType} does not have a " +
                          $"constructor with signature (int, int) and cannot be allocated.");
            }

            foreach (var mipChain in Faces)
            {
                for (var i = 0; i < mipChain.Count; i++)
                {
                    var src = mipChain[i];
                    if (src.GetType() != newBitmapType)
                    {
                        var dst = (BitmapContent)Activator.CreateInstance(
                            newBitmapType, new object[] { src.Width, src.Height });

                        BitmapContent.Copy(src, dst);
                        mipChain[i] = dst;
                    }
                }
            }
        }
        protected override bool TryCopyTo(BitmapContent destinationBitmap, Rectangle sourceRegion, Rectangle destinationRegion)
        {
            if (!destinationBitmap.TryGetFormat(out SurfaceFormat destinationFormat))
            {
                return(false);
            }

            TryGetFormat(out SurfaceFormat format);

            // A shortcut for copying the entire bitmap to another bitmap of the same type and format
            if (format == destinationFormat && (sourceRegion == new Rectangle(0, 0, Width, Height)) && sourceRegion == destinationRegion)
            {
                destinationBitmap.SetPixelData(GetPixelData());
                return(true);
            }

            // No other support for copying from a PVR texture yet
            return(false);
        }
Ejemplo n.º 8
0
        // Once arranging is complete, copies each glyph to its chosen position in the single larger output bitmap.
        static PixelBitmapContent <Color> CopyGlyphsToOutput(
            List <ArrangedGlyph> glyphs, int width, int height)
        {
            var output = new PixelBitmapContent <Color>(width, height);

            foreach (var glyph in glyphs)
            {
                var sourceGlyph       = glyph.Source;
                var sourceRegion      = sourceGlyph.Subrect;
                var destinationRegion = new Rectangle(glyph.X + 1, glyph.Y + 1, sourceRegion.Width, sourceRegion.Height);

                BitmapContent.Copy(sourceGlyph.Bitmap, sourceRegion, output, destinationRegion);

                sourceGlyph.Bitmap  = output;
                sourceGlyph.Subrect = destinationRegion;
            }

            return(output);
        }
Ejemplo n.º 9
0
        /// <summary>
        /// Checks whether an area of a bitmap contains entirely the specified alpha value.
        /// </summary>
        /// <param name="expectedAlpha"></param>
        /// <param name="bitmap"></param>
        /// <param name="region"></param>
        /// <returns></returns>
        public static bool IsAlphaEntirely(byte expectedAlpha, BitmapContent bitmap, Rectangle?region = null)
        {
            var bitmapRegion = region ?? new Rectangle(0, 0, bitmap.Width, bitmap.Height);

            if (bitmap is PixelBitmapContent <Alpha8> alphaBmp)
            {
                for (int y = 0; y < bitmapRegion.Height; y++)
                {
                    var row = alphaBmp.GetRowSpan(bitmapRegion.Y + y);
                    for (int x = 0; x < bitmapRegion.Width; x++)
                    {
                        if (row[bitmapRegion.X + x].A != expectedAlpha)
                        {
                            return(false);
                        }
                    }
                }
                return(true);
            }
            else if (bitmap is PixelBitmapContent <Color> rgbaBmp)
            {
                for (int y = 0; y < bitmapRegion.Height; y++)
                {
                    var row = rgbaBmp.GetRowSpan(bitmapRegion.Y + y);
                    for (int x = 0; x < bitmapRegion.Width; x++)
                    {
                        if (row[bitmapRegion.X + x].A != expectedAlpha)
                        {
                            return(false);
                        }
                    }
                }
                return(true);
            }
            else
            {
                throw new ArgumentException(
                          "Expected PixelBitmapContent<Alpha8> or PixelBitmapContent<Rgba32> but got " +
                          bitmap.GetType().Name, nameof(bitmap));
            }
        }
Ejemplo n.º 10
0
        internal static PixelBitmapContent <RgbaVector> Resize(
            this BitmapContent bitmap, int newWidth, int newHeight)
        {
            BitmapContent src = bitmap;

            src.TryGetFormat(out SurfaceFormat format);
            if (format != SurfaceFormat.Vector4)
            {
                var v4 = new PixelBitmapContent <RgbaVector>(src.Width, src.Height);
                BitmapContent.Copy(src, v4);
                src = v4;
            }

            using (var image = Image.WrapMemory <RgbaVector>(src.GetPixelData(), new Size(src.Height, src.Width)))
                using (var resized = image.ProcessRows(x => x.Resize(new Size(newWidth, newHeight), 0)))
                {
                    var result = new PixelBitmapContent <RgbaVector>(newWidth, newHeight);
                    result.SetPixelData(resized.GetPixelSpan());
                    return(result);
                }
        }
Ejemplo n.º 11
0
        /// <summary>
        /// Generates a full set of mipmaps for the texture.
        /// </summary>
        /// <param name="overwriteExistingMipmaps">
        /// true if the existing mipmap set is replaced with the new set; false otherwise.
        /// </param>
        public virtual void GenerateMipmaps(bool overwriteExistingMipmaps)
        {
            // If we already have mipmaps and we're not supposed to overwrite
            // them then return without any generation.
            if (!overwriteExistingMipmaps && Faces.Any(f => f.Count > 1))
            {
                return;
            }

            // Generate the mips for each face.
            foreach (var face in Faces)
            {
                // Remove any existing mipmaps.
                var faceBitmap = face[0];
                face.Clear();
                face.Add(faceBitmap);
                var faceType = faceBitmap.GetType();
                int width    = faceBitmap.Width;
                int height   = faceBitmap.Height;

                while (width > 1 || height > 1)
                {
                    if (width > 1)
                    {
                        width /= 2;
                    }
                    if (height > 1)
                    {
                        height /= 2;
                    }

                    var mip = (BitmapContent)Activator.CreateInstance(
                        faceType, new object[] { width, height });

                    BitmapContent.Copy(faceBitmap, mip);
                    face.Add(mip);
                }
            }
        }
Ejemplo n.º 12
0
        /// <summary>
        /// Gets the alpha range in a set of pixels.
        /// </summary>
        /// <param name="bitmap">A bitmap of RGBA pixel data.</param>
        /// <returns>A member of the AlphaRange enum to describe the range of alpha in the pixel data.</returns>
        static AlphaRange CalculateAlphaRange(BitmapContent bitmap)
        {
            var result = AlphaRange.Opaque;

            if (bitmap is PixelBitmapContent <Color> rgbaBmp)
            {
                var pixels = rgbaBmp.GetPixelSpan();
                for (int i = 0; i < pixels.Length; ++i)
                {
                    Color pixel = pixels[i];
                    if (pixel.A == 0)
                    {
                        result = AlphaRange.Cutout;
                    }
                    else if (pixel.A < byte.MaxValue)
                    {
                        return(AlphaRange.Full);
                    }
                }
            }
            return(result);
        }
Ejemplo n.º 13
0
        protected override bool TryCopyFrom(BitmapContent sourceBitmap, Rectangle sourceRegion, Rectangle destinationRegion)
        {
            if (!sourceBitmap.TryGetFormat(out SurfaceFormat sourceFormat))
            {
                return(false);
            }

            TryGetFormat(out SurfaceFormat format);

            // A shortcut for copying the entire bitmap to another bitmap of the same type and format
            if (format == sourceFormat &&
                sourceRegion == new Rectangle(0, 0, Width, Height) &&
                sourceRegion == destinationRegion)
            {
                SetPixelData(sourceBitmap.GetPixelData());
                return(true);
            }

            // TODO: Add a XNA unit test to see what it does
            // my guess is that this is invalid for DXT.
            //
            // Destination region copy is not yet supported
            if (destinationRegion != new Rectangle(0, 0, Width, Height))
            {
                return(false);
            }

            if (sourceBitmap is PixelBitmapContent <RgbaVector> &&
                sourceRegion.Width == destinationRegion.Width &&
                sourceRegion.Height == destinationRegion.Height)
            {
                // NVTT wants 8bit data in BGRA format.
                var colorBitmap = new PixelBitmapContent <Bgra32>(sourceBitmap.Width, sourceBitmap.Height);
                Copy(sourceBitmap, colorBitmap);
                var sourceData = colorBitmap.GetPixelData();

                AlphaMode alphaMode;
                Format    outputFormat;
                bool      alphaDither = false;
                switch (format)
                {
                case SurfaceFormat.Dxt1:
                case SurfaceFormat.Dxt1SRgb:
                {
                    PrepareNVTT_DXT1(sourceData, out bool hasTransparency);
                    outputFormat = hasTransparency ? Format.DXT1a : Format.DXT1;
                    alphaMode    = hasTransparency ? AlphaMode.Transparency : AlphaMode.None;
                    alphaDither  = true;
                    break;
                }

                case SurfaceFormat.Dxt3:
                case SurfaceFormat.Dxt3SRgb:
                {
                    //PrepareNVTT(sourceData);
                    outputFormat = Format.DXT3;
                    alphaMode    = AlphaMode.Transparency;
                    break;
                }

                case SurfaceFormat.Dxt5:
                case SurfaceFormat.Dxt5SRgb:
                {
                    //PrepareNVTT(sourceData);
                    outputFormat = Format.DXT5;
                    alphaMode    = AlphaMode.Transparency;
                    break;
                }

                default:
                    throw new InvalidOperationException("Invalid DXT surface format!");
                }

                // Do all the calls to the NVTT wrapper within this handler
                // so we properly clean up if things blow up.
                var dataHandle = GCHandle.Alloc(sourceData, GCHandleType.Pinned);
                try
                {
                    var dataPtr = dataHandle.AddrOfPinnedObject();

                    var inputOptions = new InputOptions();
                    inputOptions.SetTextureLayout(TextureType.Texture2D, colorBitmap.Width, colorBitmap.Height, 1);
                    inputOptions.SetMipmapData(dataPtr, colorBitmap.Width, colorBitmap.Height, 1, 0, 0);
                    inputOptions.SetMipmapGeneration(false);
                    inputOptions.SetGamma(1.0f, 1.0f);
                    inputOptions.SetAlphaMode(alphaMode);

                    var compressionOptions = new CompressionOptions();
                    compressionOptions.SetFormat(outputFormat);
                    compressionOptions.SetQuality(Quality.Normal);

                    // TODO: This isn't working which keeps us from getting the
                    // same alpha dither behavior on DXT1 as XNA.
                    //
                    // See https://github.com/MonoGame/MonoGame/issues/6259
                    //
                    //if (alphaDither)
                    //compressionOptions.SetQuantization(false, false, true);

                    var outputOptions = new OutputOptions();
                    outputOptions.SetOutputHeader(false);
                    outputOptions.SetOutputOptionsOutputHandler(NvttBeginImage, NvttWriteImage, NvttEndImage);

                    var dxtCompressor = new Compressor();
                    dxtCompressor.Compress(inputOptions, compressionOptions, outputOptions);
                }
                finally
                {
                    dataHandle.Free();
                }
                return(true);
            }

            try
            {
                Copy(sourceBitmap, sourceRegion, this, destinationRegion);
                return(true);
            }
            catch (InvalidOperationException)
            {
                return(false);
            }
        }
Ejemplo n.º 14
0
        // Rasterizes a single character glyph.
        private Glyph ImportGlyph(Rune character, Face face)
        {
            uint glyphIndex = face.GetCharIndex((uint)character.Value);

            face.LoadGlyph(glyphIndex, LoadFlags.Default, LoadTarget.Normal);
            face.Glyph.RenderGlyph(RenderMode.Normal);

            // Render the character.
            BitmapContent glyphBitmap = null;

            if (face.Glyph.Bitmap.Width > 0 && face.Glyph.Bitmap.Rows > 0)
            {
                glyphBitmap = new PixelBitmapContent <Alpha8>(face.Glyph.Bitmap.Width, face.Glyph.Bitmap.Rows);
                byte[] gpixelAlphas = new byte[face.Glyph.Bitmap.Width * face.Glyph.Bitmap.Rows];

                //if the character bitmap has 1bpp we have to expand the buffer data to get the 8bpp pixel data
                //each byte in bitmap.bufferdata contains the value of to 8 pixels in the row
                //if bitmap is of width 10, each row has 2 bytes with 10 valid bits, and the last 6 bits of 2nd byte must be discarded
                if (face.Glyph.Bitmap.PixelMode == PixelMode.Mono)
                {
                    //variables needed for the expansion, amount of written data, length of the data to write
                    int written = 0, length = face.Glyph.Bitmap.Width * face.Glyph.Bitmap.Rows;
                    for (int i = 0; written < length; i++)
                    {
                        //width in pixels of each row
                        int width = face.Glyph.Bitmap.Width;
                        while (width > 0)
                        {
                            //valid data in the current byte
                            int stride = Math.Min(8, width);
                            //copy the valid bytes to pixeldata
                            //System.Array.Copy(ExpandByte(face.Glyph.Bitmap.BufferData[i]), 0, gpixelAlphas, written, stride);
                            ExpandByteAndCopy(face.Glyph.Bitmap.BufferData[i], stride, gpixelAlphas, written);
                            written += stride;
                            width   -= stride;
                            if (width > 0)
                            {
                                i++;
                            }
                        }
                    }
                }
                else
                {
                    Marshal.Copy(face.Glyph.Bitmap.Buffer, gpixelAlphas, 0, gpixelAlphas.Length);
                }
                glyphBitmap.SetPixelData(gpixelAlphas);
            }

            if (glyphBitmap == null)
            {
                var gHA = face.Glyph.Metrics.HorizontalAdvance >> 6;
                var gVA = face.Size.Metrics.Height >> 6;

                gHA = gHA > 0 ? gHA : gVA;
                gVA = gVA > 0 ? gVA : gHA;

                glyphBitmap = new PixelBitmapContent <Alpha8>(gHA, gVA);
            }

            // not sure about this at all
            var abc = new ABCFloat
            {
                A = face.Glyph.Metrics.HorizontalBearingX >> 6,
                B = face.Glyph.Metrics.Width >> 6
            };

            abc.C = (face.Glyph.Metrics.HorizontalAdvance >> 6) - (abc.A + abc.B);

            // Construct the output Glyph object.
            return(new Glyph(character, glyphBitmap)
            {
                XOffset = -(face.Glyph.Advance.X >> 6),
                XAdvance = face.Glyph.Metrics.HorizontalAdvance >> 6,
                YOffset = -(face.Glyph.Metrics.HorizontalBearingY >> 6),
                CharacterWidths = abc
            });
        }