diff --git a/Campari.csproj b/Campari.csproj
index 9d7b99d..dfa4d85 100644
--- a/Campari.csproj
+++ b/Campari.csproj
@@ -3,6 +3,7 @@
netstandard2.0
x64
+ true
diff --git a/Texture.cs b/Texture.cs
deleted file mode 100644
index 287d516..0000000
--- a/Texture.cs
+++ /dev/null
@@ -1,82 +0,0 @@
-using System;
-using RefreshCS;
-
-namespace Campari
-{
- public class Texture : IDisposable
- {
- public RefreshDevice Device { get; }
- public IntPtr Handle { get; }
- public uint Height { get; }
- public uint Width { get; }
-
- public bool IsDisposed { get; private set; }
-
- public static Texture Load(RefreshDevice device, string path)
- {
- var pixels = Refresh.Refresh_Image_Load(path, out var width, out var height, out var channels);
- IntPtr textureHandle = Refresh.Refresh_CreateTexture2D(
- device.Handle,
- Refresh.ColorFormat.R8G8B8A8,
- (uint) width,
- (uint) height,
- 1,
- (uint) Refresh.TextureUsageFlagBits.SamplerBit
- );
-
- Refresh.TextureSlice textureSlice;
- textureSlice.texture = textureHandle;
- textureSlice.rectangle.x = 0;
- textureSlice.rectangle.y = 0;
- textureSlice.rectangle.w = width;
- textureSlice.rectangle.h = height;
- textureSlice.level = 0;
- textureSlice.layer = 0;
- textureSlice.depth = 0;
-
- Refresh.Refresh_SetTextureData(
- device.Handle,
- ref textureSlice,
- pixels,
- (uint) (width * height * 4)
- );
-
- return new Texture(
- device,
- textureHandle,
- (uint) width,
- (uint) height
- );
- }
-
- public Texture(RefreshDevice device, IntPtr handle, uint width, uint height)
- {
- Device = device;
- Handle = handle;
- Width = width;
- Height = height;
- }
-
- protected virtual void Dispose(bool disposing)
- {
- if (!IsDisposed)
- {
- Refresh.Refresh_QueueDestroyTexture(Device.Handle, Handle);
- IsDisposed = true;
- }
- }
-
- ~Texture()
- {
- // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
- Dispose(disposing: false);
- }
-
- public void Dispose()
- {
- // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
- Dispose(disposing: true);
- GC.SuppressFinalize(this);
- }
- }
-}
diff --git a/lib/RefreshCS b/lib/RefreshCS
index c33e62b..c6fddad 160000
--- a/lib/RefreshCS
+++ b/lib/RefreshCS
@@ -1 +1 @@
-Subproject commit c33e62b9e46f9c86c40fffe56bce461739b71bf8
+Subproject commit c6fddad50aaf4a6d00ca8571fb8f94876d0fcbef
diff --git a/src/Bytecode.cs b/src/Bytecode.cs
new file mode 100644
index 0000000..8f33e7f
--- /dev/null
+++ b/src/Bytecode.cs
@@ -0,0 +1,33 @@
+using System.IO;
+
+namespace Campari
+{
+ public static class Bytecode
+ {
+ public static uint[] ReadBytecode(FileInfo fileInfo)
+ {
+ byte[] data;
+ int size;
+ using (FileStream stream = new FileStream(fileInfo.FullName, FileMode.Open, FileAccess.Read))
+ {
+ size = (int)stream.Length;
+ data = new byte[size];
+ stream.Read(data, 0, size);
+ }
+
+ uint[] uintData = new uint[size / 4];
+ using (var memoryStream = new MemoryStream(data))
+ {
+ using (var reader = new BinaryReader(memoryStream))
+ {
+ for (int i = 0; i < size / 4; i++)
+ {
+ uintData[i] = reader.ReadUInt32();
+ }
+ }
+ }
+
+ return uintData;
+ }
+ }
+}
diff --git a/src/GraphicsResource.cs b/src/GraphicsResource.cs
new file mode 100644
index 0000000..2c77ef5
--- /dev/null
+++ b/src/GraphicsResource.cs
@@ -0,0 +1,42 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Campari
+{
+ public abstract class GraphicsResource : IDisposable
+ {
+ public RefreshDevice Device { get; }
+ public IntPtr Handle { get; protected set; }
+
+ public bool IsDisposed { get; private set; }
+ protected abstract Action QueueDestroyFunction { get; }
+
+ public GraphicsResource(RefreshDevice device)
+ {
+ Device = device;
+ }
+
+ protected virtual void Dispose(bool disposing)
+ {
+ if (!IsDisposed)
+ {
+ QueueDestroyFunction(Device.Handle, Handle);
+ IsDisposed = true;
+ }
+ }
+
+ ~GraphicsResource()
+ {
+ // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
+ Dispose(disposing: false);
+ }
+
+ public void Dispose()
+ {
+ // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
+ Dispose(disposing: true);
+ GC.SuppressFinalize(this);
+ }
+ }
+}
diff --git a/RefreshDevice.cs b/src/RefreshDevice.cs
similarity index 100%
rename from RefreshDevice.cs
rename to src/RefreshDevice.cs
diff --git a/src/RenderPass.cs b/src/RenderPass.cs
new file mode 100644
index 0000000..ece64e7
--- /dev/null
+++ b/src/RenderPass.cs
@@ -0,0 +1,42 @@
+using System;
+using RefreshCS;
+
+namespace Campari
+{
+ public class RenderPass : GraphicsResource
+ {
+ protected override Action QueueDestroyFunction => Refresh.Refresh_QueueDestroyRenderPass;
+
+ public unsafe RenderPass(RefreshDevice device, params Refresh.ColorTargetDescription[] colorTargetDescriptions) : base(device)
+ {
+ fixed (Refresh.ColorTargetDescription* ptr = colorTargetDescriptions)
+ {
+ Refresh.RenderPassCreateInfo renderPassCreateInfo;
+ renderPassCreateInfo.colorTargetCount = (uint) colorTargetDescriptions.Length;
+ renderPassCreateInfo.colorTargetDescriptions = (IntPtr) ptr;
+ renderPassCreateInfo.depthStencilTargetDescription = IntPtr.Zero;
+
+ Handle = Refresh.Refresh_CreateRenderPass(device.Handle, ref renderPassCreateInfo);
+ }
+ }
+
+ public unsafe RenderPass(
+ RefreshDevice device,
+ Refresh.DepthStencilTargetDescription depthStencilTargetDescription,
+ params Refresh.ColorTargetDescription[] colorTargetDescriptions
+ ) : base(device)
+ {
+ Refresh.DepthStencilTargetDescription* depthStencilPtr = &depthStencilTargetDescription;
+
+ fixed (Refresh.ColorTargetDescription* colorPtr = colorTargetDescriptions)
+ {
+ Refresh.RenderPassCreateInfo renderPassCreateInfo;
+ renderPassCreateInfo.colorTargetCount = (uint)colorTargetDescriptions.Length;
+ renderPassCreateInfo.colorTargetDescriptions = (IntPtr)colorPtr;
+ renderPassCreateInfo.depthStencilTargetDescription = (IntPtr) depthStencilPtr;
+
+ Handle = Refresh.Refresh_CreateRenderPass(device.Handle, ref renderPassCreateInfo);
+ }
+ }
+ }
+}
diff --git a/src/ShaderModule.cs b/src/ShaderModule.cs
new file mode 100644
index 0000000..e932857
--- /dev/null
+++ b/src/ShaderModule.cs
@@ -0,0 +1,23 @@
+using RefreshCS;
+using System;
+using System.IO;
+
+namespace Campari
+{
+ public class ShaderModule : GraphicsResource
+ {
+ protected override Action QueueDestroyFunction => Refresh.Refresh_QueueDestroyShaderModule;
+
+ public unsafe ShaderModule(RefreshDevice device, FileInfo fileInfo) : base(device)
+ {
+ fixed (uint* ptr = Bytecode.ReadBytecode(fileInfo))
+ {
+ Refresh.ShaderModuleCreateInfo shaderModuleCreateInfo;
+ shaderModuleCreateInfo.codeSize = (UIntPtr) fileInfo.Length;
+ shaderModuleCreateInfo.byteCode = (IntPtr) ptr;
+
+ Handle = Refresh.Refresh_CreateShaderModule(device.Handle, ref shaderModuleCreateInfo);
+ }
+ }
+ }
+}
diff --git a/src/Texture.cs b/src/Texture.cs
new file mode 100644
index 0000000..5857f29
--- /dev/null
+++ b/src/Texture.cs
@@ -0,0 +1,55 @@
+using System;
+using System.IO;
+using RefreshCS;
+
+namespace Campari
+{
+ public class Texture : GraphicsResource
+ {
+ public uint Height { get; }
+ public uint Width { get; }
+
+ protected override Action QueueDestroyFunction => Refresh.Refresh_QueueDestroyTexture;
+
+ public Texture(RefreshDevice device, FileInfo fileInfo) : base(device)
+ {
+ var pixels = Refresh.Refresh_Image_Load(
+ fileInfo.FullName,
+ out var width,
+ out var height,
+ out var channels
+ );
+
+ IntPtr textureHandle = Refresh.Refresh_CreateTexture2D(
+ device.Handle,
+ Refresh.ColorFormat.R8G8B8A8,
+ (uint)width,
+ (uint)height,
+ 1,
+ (uint)Refresh.TextureUsageFlagBits.SamplerBit
+ );
+
+ Refresh.TextureSlice textureSlice;
+ textureSlice.texture = textureHandle;
+ textureSlice.rectangle.x = 0;
+ textureSlice.rectangle.y = 0;
+ textureSlice.rectangle.w = width;
+ textureSlice.rectangle.h = height;
+ textureSlice.level = 0;
+ textureSlice.layer = 0;
+ textureSlice.depth = 0;
+
+ Refresh.Refresh_SetTextureData(
+ device.Handle,
+ ref textureSlice,
+ pixels,
+ (uint)(width * height * 4)
+ );
+
+ Refresh.Refresh_Image_Free(pixels);
+
+ Width = (uint) width;
+ Height = (uint) height;
+ }
+ }
+}