Web builds? #24
Replies: 10 comments 4 replies
-
Hey, SDL2 web builds are possible with Emscripten. However, I really do not know what the current state of compiling C# for the web is. You'd need to both build the native C Platform library with Emscripten and then also compile the C# code with Blazor or something, and have them link up nicely. |
Beta Was this translation helpful? Give feedback.
-
Theoretically, it may be possible. Something similar was done with Raylib-cs. Keep in mind, it is uncharted territory so documentation/examples are likely to be sparse. I'd be extremely interested in any attempts to make it work, though. |
Beta Was this translation helpful? Give feedback.
-
I did a quick experiment based on the Raylib-cs example. I got the C# running, but for whatever reason I could not get it to P/Invoke into the native DLL I built with emscripten - it always resulted in an error Definitely seems possible though! But would likely require some fixes / changes. |
Beta Was this translation helpful? Give feedback.
-
I got a little further with this today, but there's definitely a lot of weird issues. I may create a branch to experiment in. Things I've found so far:
|
Beta Was this translation helpful? Give feedback.
-
I tried it too, but with no luck. However, you guys may interested in some things I found during the discovery. #ifdef __EMSCRIPTEN__
#include <emscripten.h>
#endif And should use mkdir build
cd build
emcmake cmake ..
emmake make -j4 Also in Second, according to ASP.NET Core Doc
Which I find is 3.1.34 in dotnet-8.0. NOTE: emscripten 3.1.34 use it's own version of SDL2 (which is 2.24) to build the library, and that version of SDL don't support |
Beta Was this translation helpful? Give feedback.
-
I'm finding that the net 5 guide (that uses Uno Wasm Bootstrap instead of the newer NativeAOT) for fna is actually addressing a lot of these issues:
So hypothetically you could also try shipping your own SDL2 which is implied to work? The library lib prefix removing thing is also mentioned so I guess it's not actually new with nativeaot. I believe Uno actually logs the full emscripten cli in debug, so I may potentially see if I have any old screenshots of the expected emcc flags, I'm not sure if |
Beta Was this translation helpful? Give feedback.
-
Not sure if these are doing anything different, but here are two more recently updated .NET 7/8 C# raylib wasm repos: |
Beta Was this translation helpful? Give feedback.
-
I've also just refactored this today, so besides logging functions this should be much more straightforward now. |
Beta Was this translation helpful? Give feedback.
-
Alright I got this working but it took a fair amount of wrangling: Brief list of things I had to do to get it working: Getting SDL2 to work:
Getting Foster to work:
[UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvCdecl) })]
private static void HandleLog(IntPtr msg, int type)
{
switch (type)
{
case 0: Log.Info(msg); break;
case 1: Log.Warning(msg); break;
case 2: Log.Error(msg); break;
default: Log.Info(msg); break;
}
}
static unsafe Platform()
{
delegate* unmanaged[Cdecl]<IntPtr, int, void> fn = &HandleLog;
FosterSetLogCallback((IntPtr)fn, 0);
}
[DllImport(DLL)]
public static extern void FosterSetLogCallback(IntPtr logFn, int level); The main loop doesn't work nicely in // in Platform.cs, link to `emscripten_set_main_loop`:
[DllImport(DLL)]
public static extern void emscripten_set_main_loop(IntPtr action, int fps, bool simulateInfiniteLoop);
// in App.cs, comment out `while (!Exiting)` and everything after, and replace with this:
unsafe
{
delegate* unmanaged[Cdecl]<void> fn = &Tick;
Platform.emscripten_set_main_loop(new IntPtr(fn), 60, true);
}
// this does mean the app will never shutdown, but that can be resolved more
// gracefully with a way to end the emscripten main loop, but I didn't do it for this test.
// the Tick() method also needs this attribute added:
[UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvCdecl) })]
private static void Tick() GLSL shaders had to be slightly adjusted to work with v300, which just meant changing the first line in the vertex/fragment shaders to: #version 300 es
precision mediump float; Finally, the resulting dll must be named Creating a Wrapper ApplicationThis project linked above is a really good example of how to set up the project. I changed a few things but mostly it's the same as what they did. I changed the main game to a <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<RuntimeIdentifier>browser-wasm</RuntimeIdentifier>
<WasmMainJSPath>main.js</WasmMainJSPath>
<OutputType>Exe</OutputType>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<RunAOTCompilation>true</RunAOTCompilation>
<WasmBuildNative>true</WasmBuildNative>
<RootNamespace>FosterWasm</RootNamespace>
<WasmNativeStrip>true</WasmNativeStrip>
<EnableAggressiveTrimming>true</EnableAggressiveTrimming>
<PublishTrimmed>true</PublishTrimmed>
<TrimMode>full</TrimMode>
<!-- This is to basically disable globalization to exclude icudt.dat (1.5MB) and reduce size of dotnet.wasm -->
<InvariantGlobalization>true</InvariantGlobalization>
<ValidateExecutableReferencesMatchSelfContained>false</ValidateExecutableReferencesMatchSelfContained>
</PropertyGroup>
<Choose>
<When Condition=" $(Configuration) == 'Debug' ">
<PropertyGroup>
<WasmEmitSymbolMap>true</WasmEmitSymbolMap>
<EmccFlags>-sVERBOSE=1 -sMIN_WEBGL_VERSION=2 -Wbad-function-cast -Wcast-function-type -O2 -g3 -sINITIAL_MEMORY=128MB -sMAXIMUM_MEMORY=2048MB -sALLOW_MEMORY_GROWTH=1 -sASYNCIFY_STACK_SIZE=10000000</EmccFlags>
</PropertyGroup>
</When>
<When Condition=" $(Configuration) == 'Release' ">
<PropertyGroup>
<EmccFlags>-sMIN_WEBGL_VERSION=2 -Wbad-function-cast -Wcast-function-type -O3 -g3 -sINITIAL_MEMORY=128MB -sMAXIMUM_MEMORY=2048MB -sALLOW_MEMORY_GROWTH=1 -sASYNCIFY_STACK_SIZE=10000000</EmccFlags>
</PropertyGroup>
</When>
</Choose>
<ItemGroup>
<WasmExtraFilesToDeploy Include="index.html" />
<WasmExtraFilesToDeploy Include="main.js" />
<NativeFileReference Include="FosterPlatform.a" />
<NativeFileReference Include="SDL2.a" />
<WasmFilesToIncludeInFileSystem Include="$(ProjectDir)..\Assets\**\*.*" TargetPath="Assets\%(RecursiveDir)\%(Filename)%(Extension)" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Source\Source.csproj" />
</ItemGroup>
</Project> ThoughtsAll told this wasn't too bad, and I think we could support it, likely with a separate example project that has a custom wrapper like I described above and pre-build SDL2 and FosterFramework libraries. I don't have much time this month to iterate on this but as a proof of concept it's cool! |
Beta Was this translation helpful? Give feedback.
-
So |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
-
Are web builds supported by SDL2, or easy to compile to? Coming from Unity, I’d like to tinker with Foster for a game jam and publish on itch.io.
Beta Was this translation helpful? Give feedback.
All reactions