.NET's built-in interop is P/Invoke ([DllImport]). Delegates marshal to C
function pointers automatically, so the six callbacks are just methods.
Keep the delegates alive. The library stores the function pointers and calls
them later. If the managed delegate objects get garbage-collected, those
pointers dangle and the engine crashes. Here we store the whole Callbacks
struct (which holds the delegates) in a static field, which roots them for the
program's lifetime.
- Build
libdoomgeneric(seebindings/README.md). - Make the native library loadable. Easiest options:
- copy it next to the built binary (
bin/Release/net8.0/), or - macOS:
export DYLD_LIBRARY_PATH=/path/to/lib - Linux:
export LD_LIBRARY_PATH=/path/to/lib
- copy it next to the built binary (
- Build and run:
It writes
dotnet run -c Release -- -iwad /path/to/doom1.wad
frame.ppmat frame 100.
[DllImport("doomgeneric")] resolves to libdoomgeneric.so / .dylib /
doomgeneric.dll per OS automatically.
string[] argvmarshals to C'schar**, so engine flags like-iwadwork. We prepend a fakeargv[0]("doomdemo") because C programs expect it.dg_screen_buffer()returns anIntPtr;Marshal.Copypulls the pixels into anint[](each0x00RRGGBB) with nounsafecode.- Real input: return
1fromOnGetKeyand setpressed/doomKey(a DOOM key code) from events your UI framework delivers.