Compare commits

..

13 Commits

19 changed files with 187 additions and 66 deletions

View File

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<TargetFrameworks>net6.0;net7.0</TargetFrameworks>
<Platforms>x64</Platforms>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>

View File

@ -46,8 +46,8 @@ namespace MoonWorks.Audio
if (devices == 0)
{
Logger.LogError("No audio devices found!");
Handle = IntPtr.Zero;
FAudio.FAudio_Release(Handle);
Handle = IntPtr.Zero;
return;
}
@ -118,13 +118,13 @@ namespace MoonWorks.Audio
IntPtr chainPtr;
chainPtr = Marshal.AllocHGlobal(
sizeof(FAudio.FAudioEffectChain)
Marshal.SizeOf<FAudio.FAudioEffectChain>()
);
FAudio.FAudioEffectChain* reverbChain = (FAudio.FAudioEffectChain*) chainPtr;
reverbChain->EffectCount = 1;
reverbChain->pEffectDescriptors = Marshal.AllocHGlobal(
sizeof(FAudio.FAudioEffectDescriptor)
Marshal.SizeOf<FAudio.FAudioEffectDescriptor>()
);
FAudio.FAudioEffectDescriptor* reverbDescriptor =
@ -157,7 +157,7 @@ namespace MoonWorks.Audio
// Defaults based on FAUDIOFX_I3DL2_PRESET_GENERIC
IntPtr reverbParamsPtr = Marshal.AllocHGlobal(
sizeof(FAudio.FAudioFXReverbParameters)
Marshal.SizeOf<FAudio.FAudioFXReverbParameters>()
);
FAudio.FAudioFXReverbParameters* reverbParams = (FAudio.FAudioFXReverbParameters*) reverbParamsPtr;
@ -187,7 +187,7 @@ namespace MoonWorks.Audio
ReverbVoice,
0,
reverbParamsPtr,
(uint) sizeof(FAudio.FAudioFXReverbParameters),
(uint) Marshal.SizeOf<FAudio.FAudioFXReverbParameters>(),
0
);
Marshal.FreeHGlobal(reverbParamsPtr);
@ -198,7 +198,7 @@ namespace MoonWorks.Audio
{
SendCount = 2,
pSends = Marshal.AllocHGlobal(
2 * sizeof(FAudio.FAudioSendDescriptor)
2 * Marshal.SizeOf<FAudio.FAudioSendDescriptor>()
)
};
FAudio.FAudioSendDescriptor* sendDesc = (FAudio.FAudioSendDescriptor*) ReverbSends.pSends;

View File

@ -12,6 +12,7 @@ namespace MoonWorks.Collision.Fixed
private readonly Fix64 cellSize;
private readonly Dictionary<long, HashSet<T>> hashDictionary = new Dictionary<long, HashSet<T>>();
// FIXME: this ICollidable causes boxing which triggers garbage collection
private readonly Dictionary<T, (ICollidable, Transform2D, uint)> IDLookup = new Dictionary<T, (ICollidable, Transform2D, uint)>();
public int MinX { get; private set; } = 0;

View File

@ -12,6 +12,7 @@ namespace MoonWorks.Collision.Float
private readonly int cellSize;
private readonly Dictionary<long, HashSet<T>> hashDictionary = new Dictionary<long, HashSet<T>>();
// FIXME: this ICollidable causes boxing which triggers garbage collection
private readonly Dictionary<T, (ICollidable, Transform2D, uint)> IDLookup = new Dictionary<T, (ICollidable, Transform2D, uint)>();
public int MinX { get; private set; } = 0;

View File

@ -1,4 +1,5 @@
using System;
using System.Runtime.InteropServices;
using RefreshCS;
namespace MoonWorks.Graphics
@ -823,6 +824,11 @@ namespace MoonWorks.Graphics
{
#if DEBUG
AssertRenderPassActive();
if (scissor.X < 0 || scissor.Y < 0 || scissor.W <= 0 || scissor.H <= 0)
{
throw new System.ArgumentOutOfRangeException("Scissor position cannot be negative and dimensions must be positive!");
}
#endif
Refresh.Refresh_SetScissor(
@ -1421,7 +1427,7 @@ namespace MoonWorks.Graphics
Device.Handle,
Handle,
(IntPtr) uniformsPtr,
(uint) sizeof(T)
(uint) Marshal.SizeOf<T>()
);
}
}
@ -1448,7 +1454,7 @@ namespace MoonWorks.Graphics
Device.Handle,
Handle,
(IntPtr) uniformsPtr,
(uint) sizeof(T)
(uint) Marshal.SizeOf<T>()
);
}
}
@ -1476,7 +1482,7 @@ namespace MoonWorks.Graphics
Device.Handle,
Handle,
(IntPtr) uniformsPtr,
(uint) sizeof(T)
(uint) Marshal.SizeOf<T>()
);
}
}
@ -1632,17 +1638,18 @@ namespace MoonWorks.Graphics
/// Can return null if the swapchain is unavailable. The user should ALWAYS handle the case where this occurs.
/// If null is returned, presentation will not occur.
/// It is an error to acquire two swapchain textures from the same window in one command buffer.
/// It is an error to dispose the swapchain texture. If you do this your game WILL crash. DO NOT DO THIS.
/// </summary>
public Texture AcquireSwapchainTexture(
Window window
)
{
) {
#if DEBUG
if (!window.Claimed)
{
throw new System.InvalidOperationException("Cannot acquire swapchain texture, window has not been claimed!");
}
#endif
var texturePtr = Refresh.Refresh_AcquireSwapchainTexture(
Device.Handle,
Handle,
@ -1656,13 +1663,13 @@ namespace MoonWorks.Graphics
return null;
}
return new Texture(
Device,
texturePtr,
window.SwapchainFormat,
width,
height
);
// Override the texture properties to avoid allocating a new texture instance!
window.SwapchainTexture.Handle = texturePtr;
window.SwapchainTexture.Width = width;
window.SwapchainTexture.Height = height;
window.SwapchainTexture.Format = window.SwapchainFormat;
return window.SwapchainTexture;
}
/// <summary>
@ -1741,7 +1748,7 @@ namespace MoonWorks.Graphics
AssertRenderPassInactive("Cannot copy during render pass!");
#endif
var elementSize = sizeof(T);
var elementSize = Marshal.SizeOf<T>();
fixed (T* ptr = &data[startElement])
{
@ -1770,9 +1777,9 @@ namespace MoonWorks.Graphics
Device.Handle,
Handle,
buffer.Handle,
(uint) sizeof(T) * bufferOffsetInElements,
(uint) Marshal.SizeOf<T>() * bufferOffsetInElements,
dataPtr,
(uint) sizeof(T) * numElements
(uint) Marshal.SizeOf<T>() * numElements
);
}
@ -1972,10 +1979,13 @@ namespace MoonWorks.Graphics
}
}
var pipelineDepthFormat = graphicsPipeline.AttachmentInfo.DepthStencilFormat;
if (pipelineDepthFormat != depthStencilFormat)
if (graphicsPipeline.AttachmentInfo.HasDepthStencilAttachment)
{
throw new System.InvalidOperationException($"Depth texture format mismatch! Pipeline expects {pipelineDepthFormat}, render pass attachment is {depthStencilFormat}");
var pipelineDepthFormat = graphicsPipeline.AttachmentInfo.DepthStencilFormat;
if (pipelineDepthFormat != depthStencilFormat)
{
throw new System.InvalidOperationException($"Depth texture format mismatch! Pipeline expects {pipelineDepthFormat}, render pass attachment is {depthStencilFormat}");
}
}
}

View File

@ -28,8 +28,8 @@ namespace MoonWorks.Graphics.Font
{
fixed (FontRange *pFontRanges = &fontRanges[0])
{
var nativeSize = fontRanges.Length * sizeof(Wellspring.FontRange);
void* fontRangeMemory = NativeMemory.Alloc((nuint) fontRanges.Length, (nuint) sizeof(Wellspring.FontRange));
var nativeSize = fontRanges.Length * Marshal.SizeOf<Wellspring.FontRange>();
void* fontRangeMemory = NativeMemory.Alloc((nuint) fontRanges.Length, (nuint) Marshal.SizeOf<Wellspring.FontRange>());
System.Buffer.MemoryCopy(pFontRanges, fontRangeMemory, nativeSize, nativeSize);
var result = Wellspring.Wellspring_PackFontRanges(Handle, (IntPtr) fontRangeMemory, (uint) fontRanges.Length);

View File

@ -73,6 +73,10 @@ namespace MoonWorks.Graphics
{
window.Claimed = true;
window.SwapchainFormat = GetSwapchainFormat(window);
if (window.SwapchainTexture == null)
{
window.SwapchainTexture = new Texture(this, IntPtr.Zero, window.SwapchainFormat, 0, 0);
}
}
return success;
@ -101,6 +105,73 @@ namespace MoonWorks.Graphics
return new CommandBuffer(this, Refresh.Refresh_AcquireCommandBuffer(Handle, 0));
}
public unsafe void Submit(CommandBuffer commandBuffer)
{
var commandBufferPtrs = stackalloc IntPtr[1];
commandBufferPtrs[0] = commandBuffer.Handle;
Refresh.Refresh_Submit(
Handle,
1,
(IntPtr) commandBufferPtrs
);
}
public unsafe void Submit(
CommandBuffer commandBufferOne,
CommandBuffer commandBufferTwo
) {
var commandBufferPtrs = stackalloc IntPtr[2];
commandBufferPtrs[0] = commandBufferOne.Handle;
commandBufferPtrs[1] = commandBufferTwo.Handle;
Refresh.Refresh_Submit(
Handle,
2,
(IntPtr) commandBufferPtrs
);
}
public unsafe void Submit(
CommandBuffer commandBufferOne,
CommandBuffer commandBufferTwo,
CommandBuffer commandBufferThree
) {
var commandBufferPtrs = stackalloc IntPtr[3];
commandBufferPtrs[0] = commandBufferOne.Handle;
commandBufferPtrs[1] = commandBufferTwo.Handle;
commandBufferPtrs[2] = commandBufferThree.Handle;
Refresh.Refresh_Submit(
Handle,
3,
(IntPtr) commandBufferPtrs
);
}
public unsafe void Submit(
CommandBuffer commandBufferOne,
CommandBuffer commandBufferTwo,
CommandBuffer commandBufferThree,
CommandBuffer commandBufferFour
) {
var commandBufferPtrs = stackalloc IntPtr[4];
commandBufferPtrs[0] = commandBufferOne.Handle;
commandBufferPtrs[1] = commandBufferTwo.Handle;
commandBufferPtrs[2] = commandBufferThree.Handle;
commandBufferPtrs[3] = commandBufferFour.Handle;
Refresh.Refresh_Submit(
Handle,
4,
(IntPtr) commandBufferPtrs
);
}
public unsafe void Submit(params CommandBuffer[] commandBuffers)
{
var commandBufferPtrs = stackalloc IntPtr[commandBuffers.Length];

View File

@ -5,7 +5,7 @@ namespace MoonWorks.Graphics
public abstract class GraphicsResource : IDisposable
{
public GraphicsDevice Device { get; }
public IntPtr Handle { get; protected set; }
public IntPtr Handle { get; internal set; }
public bool IsDisposed { get; private set; }
protected abstract Action<IntPtr, IntPtr> QueueDestroyFunction { get; }

View File

@ -134,7 +134,7 @@ namespace MoonWorks.Graphics
{
Binding = 0,
InputRate = VertexInputRate.Vertex,
Stride = (uint) sizeof(T)
Stride = (uint) Marshal.SizeOf<T>()
};
}
}

View File

@ -1,4 +1,5 @@
using System;
using System.Runtime.InteropServices;
using RefreshCS;
namespace MoonWorks.Graphics
@ -32,7 +33,7 @@ namespace MoonWorks.Graphics
return new Buffer(
device,
usageFlags,
(uint) sizeof(T) * elementCount
(uint) Marshal.SizeOf<T>() * elementCount
);
}

View File

@ -9,14 +9,15 @@ namespace MoonWorks.Graphics
/// </summary>
public class Texture : GraphicsResource
{
public uint Width { get; }
public uint Height { get; }
public uint Width { get; internal set; }
public uint Height { get; internal set; }
public uint Depth { get; }
public TextureFormat Format { get; }
public TextureFormat Format { get; internal set; }
public bool IsCube { get; }
public uint LevelCount { get; }
public TextureUsageFlags UsageFlags { get; }
// FIXME: this allocates a delegate instance
protected override Action<IntPtr, IntPtr> QueueDestroyFunction => Refresh.Refresh_QueueDestroyTexture;
/// <summary>

View File

@ -24,7 +24,7 @@ namespace MoonWorks.Graphics
{
ShaderModule = shaderModule,
EntryPointName = entryPointName,
UniformBufferSize = (uint) sizeof(T),
UniformBufferSize = (uint) Marshal.SizeOf<T>(),
BufferBindingCount = bufferBindingCount,
ImageBindingCount = imageBindingCount
};

View File

@ -22,7 +22,7 @@ namespace MoonWorks.Graphics
{
ShaderModule = shaderModule,
EntryPointName = entryPointName,
UniformBufferSize = (uint) sizeof(T),
UniformBufferSize = (uint) Marshal.SizeOf<T>(),
SamplerBindingCount = samplerBindingCount
};
}

View File

@ -8,6 +8,8 @@
public bool IsHeld => ButtonStatus == ButtonStatus.Held;
public bool IsDown => ButtonStatus == ButtonStatus.Pressed || ButtonStatus == ButtonStatus.Held;
public bool IsReleased => ButtonStatus == ButtonStatus.Released;
public bool IsIdle => ButtonStatus == ButtonStatus.Idle;
public bool IsUp => ButtonStatus == ButtonStatus.Idle || ButtonStatus == ButtonStatus.Released;
public ButtonState(ButtonStatus buttonStatus)
{
@ -18,26 +20,34 @@
{
if (isPressed)
{
if (ButtonStatus == ButtonStatus.Pressed)
{
return new ButtonState(ButtonStatus.Held);
}
else if (ButtonStatus == ButtonStatus.Released)
if (IsUp)
{
return new ButtonState(ButtonStatus.Pressed);
}
else if (ButtonStatus == ButtonStatus.Held)
else
{
return new ButtonState(ButtonStatus.Held);
}
}
return new ButtonState(ButtonStatus.Released);
else
{
if (IsDown)
{
return new ButtonState(ButtonStatus.Released);
}
else
{
return new ButtonState(ButtonStatus.Idle);
}
}
}
/// <summary>
/// Combines two button states. Useful for alt controls or input buffering.
/// </summary>
public static ButtonState operator |(ButtonState a, ButtonState b)
{
if (a.ButtonStatus == ButtonStatus.Released)
if (a.ButtonStatus == ButtonStatus.Idle || a.ButtonStatus == ButtonStatus.Released)
{
return b;
}

View File

@ -3,15 +3,19 @@
public enum ButtonStatus
{
/// <summary>
/// Indicates that the input is not pressed.
/// Indicates that the button was not pressed last frame and is still not pressed.
/// </summary>
Idle,
/// <summary>
/// Indicates that the button was released this frame.
/// </summary>
Released,
/// <summary>
/// Indicates that the input was pressed this frame.
/// Indicates that the button was pressed this frame.
/// </summary>
Pressed,
/// <summary>
/// Indicates that the input has been held for multiple frames.
/// Indicates that the button has been held for multiple frames.
/// </summary>
Held
}

View File

@ -1,6 +1,5 @@
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using SDL2;
namespace MoonWorks.Input
@ -12,6 +11,7 @@ namespace MoonWorks.Input
public IntPtr State { get; private set; }
private KeyCode[] KeyCodes;
private KeyboardButton[] Keys { get; }
private int numKeys;
@ -41,8 +41,10 @@ namespace MoonWorks.Input
{
SDL.SDL_GetKeyboardState(out numKeys);
KeyCodes = Enum.GetValues<KeyCode>();
Keys = new KeyboardButton[numKeys];
foreach (KeyCode keycode in Enum.GetValues(typeof(KeyCode)))
foreach (KeyCode keycode in KeyCodes)
{
Keys[(int) keycode] = new KeyboardButton(this, keycode);
}
@ -54,18 +56,18 @@ namespace MoonWorks.Input
State = SDL.SDL_GetKeyboardState(out _);
foreach (int keycode in Enum.GetValues(typeof(KeyCode)))
foreach (KeyCode keycode in KeyCodes)
{
var button = Keys[keycode];
var button = Keys[(int) keycode];
button.Update();
if (button.IsPressed)
{
if (TextInputBindings.TryGetValue((KeyCode) keycode, out var textIndex))
if (TextInputBindings.TryGetValue(keycode, out var textIndex))
{
Inputs.OnTextInput(TextInputCharacters[(textIndex)]);
}
else if (IsDown(KeyCode.LeftControl) && (KeyCode) keycode == KeyCode.V)
else if (IsDown(KeyCode.LeftControl) && keycode == KeyCode.V)
{
Inputs.OnTextInput(TextInputCharacters[6]);
}
@ -76,11 +78,6 @@ namespace MoonWorks.Input
}
}
public bool IsDown(KeyCode keycode)
{
return Keys[(int) keycode].IsDown;
}
public bool IsPressed(KeyCode keycode)
{
return Keys[(int) keycode].IsPressed;
@ -91,11 +88,26 @@ namespace MoonWorks.Input
return Keys[(int) keycode].IsHeld;
}
public bool IsDown(KeyCode keycode)
{
return Keys[(int) keycode].IsDown;
}
public bool IsReleased(KeyCode keycode)
{
return Keys[(int) keycode].IsReleased;
}
public bool IsIdle(KeyCode keycode)
{
return Keys[(int) keycode].IsIdle;
}
public bool IsUp(KeyCode keycode)
{
return Keys[(int) keycode].IsUp;
}
public KeyboardButton Button(KeyCode keycode)
{
return Keys[(int) keycode];

View File

@ -43,8 +43,6 @@ namespace MoonWorks.Input
private readonly Dictionary<MouseButtonCode, MouseButton> CodeToButton;
private IEnumerable<MouseButton> Buttons => CodeToButton.Values;
public Mouse()
{
LeftButton = new MouseButton(this, MouseButtonCode.Left, SDL.SDL_BUTTON_LMASK);
@ -78,7 +76,7 @@ namespace MoonWorks.Input
Wheel = WheelRaw - previousWheelRaw;
previousWheelRaw = WheelRaw;
foreach (var button in Buttons)
foreach (var button in CodeToButton.Values)
{
button.Update();

View File

@ -5,9 +5,9 @@ namespace MoonWorks.Input
public ButtonState State { get; protected set; }
/// <summary>
/// True if the button is pressed or held.
/// True if the button was pressed this exact frame.
/// </summary>
public bool IsDown => State.IsDown;
public bool IsPressed => State.IsPressed;
/// <summary>
/// True if the button has been continuously held for more than one frame.
@ -15,15 +15,25 @@ namespace MoonWorks.Input
public bool IsHeld => State.IsHeld;
/// <summary>
/// True if the button was pressed this exact frame.
/// True if the button is pressed or held.
/// </summary>
public bool IsPressed => State.IsPressed;
public bool IsDown => State.IsDown;
/// <summary>
/// True if the button is not pressed.
/// True if the button was released this frame.
/// </summary>
public bool IsReleased => State.IsReleased;
/// <summary>
/// True if the button was not pressed the previous or current frame.
/// </summary>
public bool IsIdle => State.IsIdle;
/// <summary>
/// True if the button is idle or released.
/// </summary>
public bool IsUp => State.IsUp;
internal virtual void Update()
{
State = State.Update(CheckPressed());

View File

@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using MoonWorks.Graphics;
using SDL2;
namespace MoonWorks
@ -10,6 +11,7 @@ namespace MoonWorks
public ScreenMode ScreenMode { get; private set; }
public uint Width { get; private set; }
public uint Height { get; private set; }
internal Texture SwapchainTexture { get; set; } = null;
public bool Claimed { get; internal set; }
public MoonWorks.Graphics.TextureFormat SwapchainFormat { get; internal set; }