using System; using System.IO; using System.Runtime.InteropServices; using RefreshCS; namespace MoonWorks.Graphics { /// /// A container for pixel data. /// public class Texture : GraphicsResource { public uint Width { get; } public uint Height { get; } public TextureFormat Format { get; } protected override Action QueueDestroyFunction => Refresh.Refresh_QueueDestroyTexture; public static Texture LoadPNG(GraphicsDevice device, string filePath) { var pixels = Refresh.Refresh_Image_Load( filePath, out var width, out var height, out var channels ); TextureCreateInfo textureCreateInfo; textureCreateInfo.Width = (uint)width; textureCreateInfo.Height = (uint)height; textureCreateInfo.Depth = 1; textureCreateInfo.Format = TextureFormat.R8G8B8A8; textureCreateInfo.IsCube = false; textureCreateInfo.LevelCount = 1; textureCreateInfo.SampleCount = SampleCount.One; textureCreateInfo.UsageFlags = TextureUsageFlags.Sampler; var texture = new Texture(device, textureCreateInfo); texture.SetData(pixels, (uint)(width * height * 4)); Refresh.Refresh_Image_Free(pixels); return texture; } public unsafe static void SavePNG(string path, int width, int height, byte[] pixels) { fixed (byte* ptr = &pixels[0]) { Refresh.Refresh_Image_SavePNG(path, width, height, (IntPtr) ptr); } } /// /// Creates a 2D texture. /// /// An initialized GraphicsDevice. /// The width of the texture. /// The height of the texture. /// The format of the texture. /// Specifies how the texture will be used. /// Specifies the multisample count. /// Specifies the number of mip levels. public static Texture CreateTexture2D( GraphicsDevice device, uint width, uint height, TextureFormat format, TextureUsageFlags usageFlags, SampleCount sampleCount = SampleCount.One, uint levelCount = 1 ) { var textureCreateInfo = new TextureCreateInfo { Width = width, Height = height, Depth = 1, IsCube = false, SampleCount = sampleCount, LevelCount = levelCount, Format = format, UsageFlags = usageFlags }; return new Texture(device, textureCreateInfo); } /// /// Creates a 3D texture. /// /// An initialized GraphicsDevice. /// The width of the texture. /// The height of the texture. /// The depth of the texture. /// The format of the texture. /// Specifies how the texture will be used. /// Specifies the multisample count. /// Specifies the number of mip levels. public static Texture CreateTexture3D( GraphicsDevice device, uint width, uint height, uint depth, TextureFormat format, TextureUsageFlags usageFlags, SampleCount sampleCount = SampleCount.One, uint levelCount = 1 ) { var textureCreateInfo = new TextureCreateInfo { Width = width, Height = height, Depth = depth, IsCube = false, SampleCount = sampleCount, LevelCount = levelCount, Format = format, UsageFlags = usageFlags }; return new Texture(device, textureCreateInfo); } /// /// Creates a cube texture. /// /// An initialized GraphicsDevice. /// The length of one side of the cube. /// The format of the texture. /// Specifies how the texture will be used. /// Specifies the multisample count. /// Specifies the number of mip levels. public static Texture CreateTextureCube( GraphicsDevice device, uint size, TextureFormat format, TextureUsageFlags usageFlags, SampleCount sampleCount = SampleCount.One, uint levelCount = 1 ) { var textureCreateInfo = new TextureCreateInfo { Width = size, Height = size, Depth = 1, IsCube = true, SampleCount = sampleCount, LevelCount = levelCount, Format = format, UsageFlags = usageFlags }; return new Texture(device, textureCreateInfo); } /// /// Creates a new texture using a TextureCreateInfo struct. /// /// An initialized GraphicsDevice. /// The parameters to use when creating the texture. public Texture( GraphicsDevice device, in TextureCreateInfo textureCreateInfo ) : base(device) { Handle = Refresh.Refresh_CreateTexture( device.Handle, textureCreateInfo.ToRefreshTextureCreateInfo() ); Format = textureCreateInfo.Format; Width = textureCreateInfo.Width; Height = textureCreateInfo.Height; } /// /// Asynchronously copies data into the texture. /// /// The texture slice to copy into. /// A pointer to an array of data to copy from. /// The amount of data to copy from the array. public void SetData(in TextureSlice textureSlice, IntPtr dataPtr, uint dataLengthInBytes) { Refresh.Refresh_SetTextureData( Device.Handle, textureSlice.ToRefreshTextureSlice(), dataPtr, dataLengthInBytes ); } /// /// Asynchronously copies data into the texture. /// This variant copies into the entire texture. /// /// A pointer to an array of data to copy from. /// The amount of data to copy from the array. public void SetData(IntPtr dataPtr, uint dataLengthInBytes) { SetData(new TextureSlice(this), dataPtr, dataLengthInBytes); } /// /// Asynchronously copies data into the texture. /// /// The texture slice to copy into. /// An array of data to copy into the texture. public unsafe void SetData(in TextureSlice textureSlice, T[] data) where T : unmanaged { var size = Marshal.SizeOf(); fixed (T* ptr = &data[0]) { Refresh.Refresh_SetTextureData( Device.Handle, textureSlice.ToRefreshTextureSlice(), (IntPtr) ptr, (uint) (data.Length * size) ); } } /// /// Asynchronously copies data into the texture. /// This variant copies data into the entire texture. /// /// An array of data to copy into the texture. public unsafe void SetData(T[] data) where T : unmanaged { SetData(new TextureSlice(this), data); } } }