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;
}
}
}