From 7cd02a401e32289345be6b65de4fe6874176742a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20F=2E=20R=C3=B8dseth?= Date: Thu, 17 Oct 2024 14:14:16 +0200 Subject: [PATCH 1/3] Attempt to make the C# example work on macOS / aarch64 / M3 --- csharp/Makefile | 1 + csharp/main.cs | 158 +++++++++++++++++++++++++++++++++++++++--------- 2 files changed, 132 insertions(+), 27 deletions(-) diff --git a/csharp/Makefile b/csharp/Makefile index 9d1a513..0d508b9 100644 --- a/csharp/Makefile +++ b/csharp/Makefile @@ -30,6 +30,7 @@ run: msg main clean: rm -f main main.exe temp.* *crash*.json + rm -rf ./bin/ ./obj/ check-config: @if [ ! -f $(MACHINE_CONFIG) ]; then \ diff --git a/csharp/main.cs b/csharp/main.cs index 7831c06..5bdd953 100644 --- a/csharp/main.cs +++ b/csharp/main.cs @@ -1,11 +1,14 @@ using System; using System.Runtime.InteropServices; using System.Text; +using System.Diagnostics; public class HelloWorld { // From SDL.h + private const UInt32 SDL_INIT_TIMER = 0x00000001; private const UInt32 SDL_INIT_VIDEO = 0x00000020; + private const UInt32 SDL_INIT_EVENTS = 0x00004000; // From SDL_video.h private const Int32 SDL_WINDOWPOS_UNDEFINED = 0x1FFF0000; @@ -15,6 +18,32 @@ public class HelloWorld private const UInt32 SDL_RENDERER_ACCELERATED = 0x00000002; private const UInt32 SDL_RENDERER_PRESENTVSYNC = 0x00000004; + // From SDL_events.h + private const UInt32 SDL_QUIT = 0x100; + private const UInt32 SDL_KEYDOWN = 0x300; + + // From SDL_keycode.h + private const UInt32 SDLK_ESCAPE = 27; + + [StructLayout(LayoutKind.Sequential)] + public struct SDL_Event + { + public UInt32 type; + public UInt32 timestamp; + public UInt32 windowID; + public UInt32 eventState; + public SDL_Keysym key; + } + + [StructLayout(LayoutKind.Sequential)] + public struct SDL_Keysym + { + public UInt32 scancode; + public UInt32 sym; + public UInt32 mod; + public UInt32 unused; + } + [DllImport("SDL2")] private static extern unsafe Int32 SDL_Init(UInt32 flags); @@ -97,6 +126,12 @@ private static extern unsafe IntPtr SDL_RWFromFile( [DllImport("SDL2")] private static extern unsafe byte* SDL_GetError(); + [DllImport("SDL2")] + private static extern unsafe int SDL_PollEvent(out SDL_Event e); + + [DllImport("SDL2")] + private static extern unsafe UInt32 SDL_GetTicks(); + // Call SDL_GetError() and return the C string as a C# String private static unsafe string SDL_GetErrorString() { @@ -119,7 +154,10 @@ private static void PrintErr(string topic) public class SDLWindow : IDisposable { - public IntPtr Handle { get; private set; } + public IntPtr Handle { + get; + private set; + } public SDLWindow(string title, int x, int y, int w, int h, uint flags) { @@ -128,6 +166,7 @@ public SDLWindow(string title, int x, int y, int w, int h, uint flags) { throw new Exception("SDL_CreateWindow Error: " + SDL_GetErrorString()); } + Console.WriteLine("SDLWindow created successfully"); } public void Dispose() @@ -136,21 +175,31 @@ public void Dispose() { SDL_DestroyWindow(Handle); Handle = IntPtr.Zero; + Console.WriteLine("SDLWindow destroyed"); } } } public class SDLRenderer : IDisposable { - public IntPtr Handle { get; private set; } + public IntPtr Handle { + get; + private set; + } public SDLRenderer(SDLWindow window, int index, uint flags) { + if (window.Handle == IntPtr.Zero) + { + throw new Exception("Invalid window handle when creating renderer."); + } + Handle = SDL_CreateRenderer(window.Handle, index, flags); if (Handle == IntPtr.Zero) { throw new Exception("SDL_CreateRenderer Error: " + SDL_GetErrorString()); } + Console.WriteLine("SDLRenderer created successfully"); } public void Dispose() @@ -159,21 +208,31 @@ public void Dispose() { SDL_DestroyRenderer(Handle); Handle = IntPtr.Zero; + Console.WriteLine("SDLRenderer destroyed"); } } } public class SDLTexture : IDisposable { - public IntPtr Handle { get; private set; } + public IntPtr Handle { + get; + private set; + } public SDLTexture(SDLRenderer renderer, IntPtr surface) { + if (renderer.Handle == IntPtr.Zero) + { + throw new Exception("Renderer handle is null when creating texture."); + } + Handle = SDL_CreateTextureFromSurface(renderer.Handle, surface); if (Handle == IntPtr.Zero) { throw new Exception("SDL_CreateTextureFromSurface Error: " + SDL_GetErrorString()); } + Console.WriteLine("SDLTexture created successfully"); } public void Dispose() @@ -182,50 +241,95 @@ public void Dispose() { SDL_DestroyTexture(Handle); Handle = IntPtr.Zero; + Console.WriteLine("SDLTexture destroyed"); } } } public static int Main(string[] args) { - if (SDL_Init(SDL_INIT_VIDEO) != 0) + if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER | SDL_INIT_EVENTS) != 0) { PrintErr("SDL_Init"); return 1; } + Console.WriteLine("SDL Initialized successfully"); using (var window = new SDLWindow("Hello, World!", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 620, 387, SDL_WINDOW_SHOWN)) - using (var renderer = new SDLRenderer(window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC)) - { - IntPtr rwop = SDL_RWFromFile("../img/grumpy-cat.bmp", "rb"); - if (rwop == IntPtr.Zero) - { - PrintErr("SDL_RWFromFile"); - return 1; - } - - IntPtr bmp = SDL_LoadBMP_RW(rwop, 1); // this also frees rwop - if (bmp == IntPtr.Zero) + using (var renderer = new SDLRenderer(window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC)) { - PrintErr("SDL_LoadBMP_RW"); - return 1; - } + IntPtr rwop = SDL_RWFromFile("../img/grumpy-cat.bmp", "rb"); + if (rwop == IntPtr.Zero) + { + PrintErr("SDL_RWFromFile"); + return 1; + } + Console.WriteLine("Image file loaded successfully"); - using (var texture = new SDLTexture(renderer, bmp)) - { - SDL_FreeSurface(bmp); + IntPtr bmp = SDL_LoadBMP_RW(rwop, 1); // this also frees rwop + if (bmp == IntPtr.Zero) + { + PrintErr("SDL_LoadBMP_RW"); + return 1; + } + Console.WriteLine("BMP loaded successfully"); - for (int i = 0; i < 20; i++) + using (var texture = new SDLTexture(renderer, bmp)) { - SDL_RenderClear(renderer.Handle); - SDL_RenderCopy(renderer.Handle, texture.Handle, IntPtr.Zero, IntPtr.Zero); - SDL_RenderPresent(renderer.Handle); - System.Threading.Thread.Sleep(100); + SDL_FreeSurface(bmp); + Console.WriteLine("Surface freed successfully"); + + Debug.Assert(renderer.Handle != IntPtr.Zero, "Renderer handle is null!"); + Debug.Assert(texture.Handle != IntPtr.Zero, "Texture handle is null!"); + + if (renderer.Handle == IntPtr.Zero || texture.Handle == IntPtr.Zero) + { + PrintErr("Null reference in renderer or texture handle"); + return 1; + } + + SDL_Event e; + bool quit = false; + UInt32 startTime = SDL_GetTicks(); + + while (!quit) + { + // Poll for events + while (SDL_PollEvent(out e) != 0) + { + if (e.type == SDL_QUIT || (e.type == SDL_KEYDOWN && e.key.sym == SDLK_ESCAPE)) + { + quit = true; + } + } + + // Render loop + if (renderer.Handle != IntPtr.Zero && texture.Handle != IntPtr.Zero) + { + Console.WriteLine("Rendering frame"); + SDL_RenderClear(renderer.Handle); + SDL_RenderCopy(renderer.Handle, texture.Handle, IntPtr.Zero, IntPtr.Zero); + SDL_RenderPresent(renderer.Handle); + } + else + { + PrintErr("Renderer or texture handle became null during render loop"); + break; + } + + // Exit after 2000ms (2 seconds) + if (SDL_GetTicks() - startTime > 2000) + { + break; + } + + System.Threading.Thread.Sleep(100); // Delay to limit loop iteration + } } } - } SDL_Quit(); + Console.WriteLine("SDL Quit successfully"); return 0; } From 9c1f430abbcb82271b526dc9f69e7780438b810f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20F=2E=20R=C3=B8dseth?= Date: Thu, 14 Nov 2024 16:47:58 +0100 Subject: [PATCH 2/3] Use .NET 9 --- csharp/main.csproj | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/csharp/main.csproj b/csharp/main.csproj index 9f12e48..af64186 100644 --- a/csharp/main.csproj +++ b/csharp/main.csproj @@ -1,7 +1,7 @@ - + Exe - net8.0 + net9.0 enable enable true From 333a26f5a5d540ba294dbda45f88f8d538abaf2f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20F=2E=20R=C3=B8dseth?= Date: Thu, 14 Nov 2024 16:48:05 +0100 Subject: [PATCH 3/3] Add a simple run script, for testing on macOS --- csharp/run.sh | 1 + 1 file changed, 1 insertion(+) create mode 100755 csharp/run.sh diff --git a/csharp/run.sh b/csharp/run.sh new file mode 100755 index 0000000..72b4b4e --- /dev/null +++ b/csharp/run.sh @@ -0,0 +1 @@ +export DYLD_LIBRARY_PATH=/opt/homebrew/lib && dotnet run