// MonoGame - Copyright (C) The MonoGame Team // This file is subject to the terms and conditions defined in // file 'LICENSE.txt', which is part of this source code package. using System; using Microsoft.Xna.Framework.Graphics; namespace Microsoft.Xna.Framework.Content.Pipeline.Graphics { /// /// Provides properties and methods for creating and maintaining a bitmap resource. /// public abstract class BitmapContent : ContentItem { int height; int width; /// /// Gets or sets the height of the bitmap, in pixels. /// public int Height { get { return height; } protected set { if (value <= 0) throw new ArgumentOutOfRangeException("height"); height = value; } } /// /// Gets or sets the width of the bitmap, in pixels. /// public int Width { get { return width; } protected set { if (value <= 0) throw new ArgumentOutOfRangeException("width"); width = value; } } /// /// Initializes a new instance of BitmapContent. /// protected BitmapContent() { } /// /// Initializes a new instance of BitmapContent with the specified width or height. /// /// Width, in pixels, of the bitmap resource. /// Height, in pixels, of the bitmap resource. protected BitmapContent(int width, int height) { // Write to properties so validation is run. Width = width; Height = height; } /// /// Copies one bitmap into another. /// The destination bitmap can be in any format and size. If the destination is larger or smaller, the source bitmap is scaled accordingly. /// /// BitmapContent being copied. /// BitmapContent being overwritten. public static void Copy(BitmapContent sourceBitmap, BitmapContent destinationBitmap) { if (sourceBitmap == null) throw new ArgumentNullException("sourceBitmap"); if (destinationBitmap == null) throw new ArgumentNullException("destinationBitmap"); var sourceRegion = new Rectangle(0, 0, sourceBitmap.Width, sourceBitmap.Height); var destinationRegion = new Rectangle(0, 0, destinationBitmap.Width, destinationBitmap.Height); Copy(sourceBitmap, sourceRegion, destinationBitmap, destinationRegion); } /// /// Copies one bitmap into another. /// The destination bitmap can be in any format and size. If the destination is larger or smaller, the source bitmap is scaled accordingly. /// /// BitmapContent being copied. /// Region of sourceBitmap. /// BitmapContent being overwritten. /// Region of bitmap to be overwritten. public static void Copy(BitmapContent sourceBitmap, Rectangle sourceRegion, BitmapContent destinationBitmap, Rectangle destinationRegion) { ValidateCopyArguments(sourceBitmap, sourceRegion, destinationBitmap, destinationRegion); SurfaceFormat sourceFormat; if (!sourceBitmap.TryGetFormat(out sourceFormat)) throw new InvalidOperationException("Could not retrieve surface format of source bitmap"); SurfaceFormat destinationFormat; if (!destinationBitmap.TryGetFormat(out destinationFormat)) throw new InvalidOperationException("Could not retrieve surface format of destination bitmap"); // If the formats are the same and the regions are the full bounds of the bitmaps and they are the same size, do a simpler copy if (sourceFormat == destinationFormat && sourceRegion == destinationRegion && sourceRegion == new Rectangle(0, 0, sourceBitmap.Width, sourceBitmap.Height) && destinationRegion == new Rectangle(0, 0, destinationBitmap.Width, destinationBitmap.Height)) { destinationBitmap.SetPixelData(sourceBitmap.GetPixelData()); return; } // The basic process is // 1. Copy from source bitmap region to a new PixelBitmapContent using sourceBitmap.TryCopyTo() // 2. If source and destination regions are a different size, resize Vector4 version // 3. Copy from Vector4 to destination region using destinationBitmap.TryCopyFrom() // Copy from the source to the intermediate Vector4 format var intermediate = new PixelBitmapContent(sourceRegion.Width, sourceRegion.Height); var intermediateRegion = new Rectangle(0, 0, intermediate.Width, intermediate.Height); if (sourceBitmap.TryCopyTo(intermediate, sourceRegion, intermediateRegion)) { // Resize the intermediate if required if (intermediate.Width != destinationRegion.Width || intermediate.Height != destinationRegion.Height) intermediate = intermediate.Resize(destinationRegion.Width, destinationRegion.Height) as PixelBitmapContent; // Copy from the intermediate to the destination if (destinationBitmap.TryCopyFrom(intermediate, new Rectangle(0, 0, intermediate.Width, intermediate.Height), destinationRegion)) return; } // If we got here, one of the above steps didn't work throw new InvalidOperationException("Could not copy between " + sourceFormat + " and " + destinationFormat); } /// /// Reads encoded bitmap content. /// /// Array containing encoded bitmap data. public abstract byte[] GetPixelData(); /// /// Writes encoded bitmap content. /// /// Array containing encoded bitmap data to be set. public abstract void SetPixelData(byte[] sourceData); /// /// Returns a string description of the bitmap resource. /// /// Description of the bitmap. public override string ToString() { return string.Format("{0}, {1}x{2}", GetType().Name, Width, Height); } /// /// Attempts to copy a region from a specified bitmap. /// /// BitmapContent being copied. /// Location of sourceBitmap. /// Region of destination bitmap to be overwritten. /// true if region copy is supported; false otherwise. protected abstract bool TryCopyFrom(BitmapContent sourceBitmap, Rectangle sourceRegion, Rectangle destinationRegion); /// /// Attempts to copy a region of the specified bitmap onto another. /// /// BitmapContent being overwritten. /// Location of the source bitmap. /// Region of destination bitmap to be overwritten. /// true if region copy is supported; false otherwise. protected abstract bool TryCopyTo(BitmapContent destinationBitmap, Rectangle sourceRegion, Rectangle destinationRegion); /// /// Gets the corresponding GPU texture format for the specified bitmap type. /// /// Format being retrieved. /// The GPU texture format of the bitmap type. public abstract bool TryGetFormat(out SurfaceFormat format); /// /// Validates the arguments to the Copy function. /// /// BitmapContent being copied. /// Location of sourceBitmap. /// BitmapContent being overwritten. /// Region of bitmap to be overwritten. protected static void ValidateCopyArguments(BitmapContent sourceBitmap, Rectangle sourceRegion, BitmapContent destinationBitmap, Rectangle destinationRegion) { if (sourceBitmap == null) throw new ArgumentNullException("sourceBitmap"); if (destinationBitmap == null) throw new ArgumentNullException("destinationBitmap"); // Make sure regions are within the bounds of the bitmaps if (sourceRegion.Left < 0 || sourceRegion.Top < 0 || sourceRegion.Width <= 0 || sourceRegion.Height <= 0 || sourceRegion.Right > sourceBitmap.Width || sourceRegion.Bottom > sourceBitmap.Height) throw new ArgumentOutOfRangeException("sourceRegion"); if (destinationRegion.Left < 0 || destinationRegion.Top < 0 || destinationRegion.Width <= 0 || destinationRegion.Height <= 0 || destinationRegion.Right > destinationBitmap.Width || destinationRegion.Bottom > destinationBitmap.Height) throw new ArgumentOutOfRangeException("destinationRegion"); } } }