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