using DotSDL.Interop.Core; using SdlPixels = DotSDL.Interop.Core.Pixels; using System; namespace DotSDL.Graphics { /// /// A representation of the contents of the SDL window, with a number of /// helper routines. /// public class Canvas { private int _width, _height; /// /// true if this has an SDL texture associated with it, otherwise false. /// protected bool HasTexture { get; set; } /// /// The scaling type that should be used to draw this . This field should not be /// manipulated directly--use instead. /// protected ScalingQuality ScalingQualityValue; /// /// The SDL_Texture that this maintains. /// internal IntPtr Renderer; internal IntPtr Texture; /// /// The raw pixels in the . /// public Color[] Pixels; /// /// Gets an that points to what should be displayed on the window's background. This is /// useful if you're maintaining your own ARGB framebuffer and don't plan to use DotSDL's /// object. You usually do not need to override this method. /// /// If an invalid is generated by this method, your application may /// crash with a segmentation fault. When in doubt, override instead! /// An containing the contents of the window's background. public Func GetCanvasPointer; /// /// Gets or sets the width of the texture. /// public int Width { get => _width; set { if(value <= 0) throw new ArgumentException("Width must be greater than 0."); _width = value; Resize(); } } /// /// Gets or sets the height of the texture. /// public int Height { get => _height; set { if(value <= 0) throw new ArgumentException("Height must be greater than 0."); _height = value; Resize(); } } /// /// Determines the method that will be used to scale this sprite when it is plotted to the /// screen. /// public virtual ScalingQuality ScalingQuality { get => ScalingQualityValue; set { ScalingQualityValue = value; if(HasTexture) CreateTexture(); } } /// /// Sets the section of the that should be drawn. If the size values are set to 0, the /// will fill as much of its containing object as possible. /// public Rectangle Clipping { get; set; } /// /// Initializes a new . /// /// The width of the . /// The height of the . internal Canvas(int textureWidth, int textureHeight) : this(textureWidth, textureHeight, new Rectangle(0, 0, textureWidth, textureHeight)) { } /// /// Initializes a new . /// /// The width of the . /// The height of the . /// The clipping for the . internal Canvas(int textureWidth, int textureHeight, Rectangle clipping) { _width = textureWidth; _height = textureHeight; Clipping = clipping; GetCanvasPointer = () => { unsafe { fixed(void* pixelPtr = Pixels) { return (IntPtr)pixelPtr; } } }; Resize(); } /// /// Creates a texture or recreates it if it already exists. /// internal virtual void CreateTexture() { CreateTexture(Render.TextureAccess.Streaming); } /// /// Creates a texture or recreates it if it already exists. /// /// The access mode for this texture. internal void CreateTexture(Render.TextureAccess textureAccess) { if(Renderer == IntPtr.Zero) return; DestroyTexture(); Hints.SetHint(Hints.RenderScaleQuality, ScalingQuality.ToString()); Texture = Render.CreateTexture(Renderer, SdlPixels.PixelFormatArgb8888, textureAccess, Width, Height); HasTexture = true; } /// /// Destroys the texture associated with this . /// internal void DestroyTexture() { if(!HasTexture) return; Render.DestroyTexture(Texture); HasTexture = false; } /// /// Retrieves an array index on the . /// /// The Y coordinate of the desired location on the . /// The Y coordinate of the desired location on the . /// The array index for the given point. public int GetIndex(int x, int y) { return (Width * y) + x; } /// /// Retrieves an array index on the . /// /// A representing the desired location on the . /// The array index for the given point. public int GetIndex(Point point) { return (Width * point.Y) + point.X; } /// /// Resizes the . Please note that this will also clear the canvas of /// its existing contents. /// protected void Resize() { Pixels = new Color[Width * Height]; if(HasTexture) CreateTexture(); } /// /// Updates the texture associated with this . This function must be called when the /// array is changed. /// /// true if the texture was successfully updated, otherwise false. This will return false if this hasn't been added to the sprite list. internal bool UpdateTexture() { if(!HasTexture) return false; Render.UpdateTexture(Texture, IntPtr.Zero, GetCanvasPointer(), Width * 4); return true; } } }