Bladeren bron

Examples: (Again, but better) made SDL+GL and GLFW+GL examples build with Emscripten. (#2492, #2494, #3699, #3705)

ocornut 2 jaren geleden
bovenliggende
commit
ea39841fcd

+ 2 - 1
docs/CHANGELOG.txt

@@ -98,7 +98,8 @@ All changes:
 - Backends: WebGPU: Fix building for latest WebGPU specs (remove implicit layout generation).
   (#6117, #4116, #3632) [@tonygrue, @bfierz]
 - Examples: refactored SDL+GL and GLFW+GL examples to compile with Emscripten.
-  (the dedicated example_emscripten_opengl3/ has been removed) (#2492, #2494, #3699, #3705)
+  (#2492, #2494, #3699, #3705) [@ocornut, @nicolasnoble]
+  The dedicated example_emscripten_opengl3/ has been removed.
 - Examples: Win32: Fixed examples using RegisterClassW() since 1.89 to also call
   DefWindowProcW() instead of DefWindowProc() so that title text are correctly converted
   when application is compiled without /DUNICODE. (#5725, #5961, #5975) [@markreidvfx]

+ 16 - 0
examples/example_glfw_opengl3/main.cpp

@@ -20,6 +20,11 @@
 #pragma comment(lib, "legacy_stdio_definitions")
 #endif
 
+// This example can also compile and run with Emscripten! See 'Makefile.emscripten' for details.
+#ifdef __EMSCRIPTEN__
+#include "../libs/emscripten/emscripten_mainloop_stub.h"
+#endif
+
 static void glfw_error_callback(int error, const char* description)
 {
     fprintf(stderr, "GLFW Error %d: %s\n", error, description);
@@ -85,6 +90,7 @@ int main(int, char**)
     // - Use '#define IMGUI_ENABLE_FREETYPE' in your imconfig file to use Freetype for higher quality font rendering.
     // - Read 'docs/FONTS.md' for more instructions and details.
     // - Remember that in C/C++ if you want to include a backslash \ in a string literal you need to write a double backslash \\ !
+    // - Our Emscripten build process allows embedding fonts to be accessible at runtime from the "fonts/" folder. See Makefile.emscripten for details.
     //io.Fonts->AddFontDefault();
     //io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\segoeui.ttf", 18.0f);
     //io.Fonts->AddFontFromFileTTF("../../misc/fonts/DroidSans.ttf", 16.0f);
@@ -99,7 +105,14 @@ int main(int, char**)
     ImVec4 clear_color = ImVec4(0.45f, 0.55f, 0.60f, 1.00f);
 
     // Main loop
+#ifdef __EMSCRIPTEN__
+    // For an Emscripten build we are disabling file-system access, so let's not attempt to do a fopen() of the imgui.ini file.
+    // You may manually call LoadIniSettingsFromMemory() to load settings from your own storage.
+    io.IniFilename = NULL;
+    EMSCRIPTEN_MAINLOOP_BEGIN
+#else
     while (!glfwWindowShouldClose(window))
+#endif
     {
         // Poll and handle events (inputs, window resize, etc.)
         // You can read the io.WantCaptureMouse, io.WantCaptureKeyboard flags to tell if dear imgui wants to use your inputs.
@@ -161,6 +174,9 @@ int main(int, char**)
 
         glfwSwapBuffers(window);
     }
+#ifdef __EMSCRIPTEN__
+    EMSCRIPTEN_MAINLOOP_END;
+#endif
 
     // Cleanup
     ImGui_ImplOpenGL3_Shutdown();

+ 16 - 0
examples/example_sdl_opengl3/main.cpp

@@ -14,6 +14,11 @@
 #include <SDL_opengl.h>
 #endif
 
+// This example can also compile and run with Emscripten! See 'Makefile.emscripten' for details.
+#ifdef __EMSCRIPTEN__
+#include "../libs/emscripten/emscripten_mainloop_stub.h"
+#endif
+
 // Main code
 int main(int, char**)
 {
@@ -81,6 +86,7 @@ int main(int, char**)
     // - Use '#define IMGUI_ENABLE_FREETYPE' in your imconfig file to use Freetype for higher quality font rendering.
     // - Read 'docs/FONTS.md' for more instructions and details.
     // - Remember that in C/C++ if you want to include a backslash \ in a string literal you need to write a double backslash \\ !
+    // - Our Emscripten build process allows embedding fonts to be accessible at runtime from the "fonts/" folder. See Makefile.emscripten for details.
     //io.Fonts->AddFontDefault();
     //io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\segoeui.ttf", 18.0f);
     //io.Fonts->AddFontFromFileTTF("../../misc/fonts/DroidSans.ttf", 16.0f);
@@ -96,7 +102,14 @@ int main(int, char**)
 
     // Main loop
     bool done = false;
+#ifdef __EMSCRIPTEN__
+    // For an Emscripten build we are disabling file-system access, so let's not attempt to do a fopen() of the imgui.ini file.
+    // You may manually call LoadIniSettingsFromMemory() to load settings from your own storage.
+    io.IniFilename = NULL;
+    EMSCRIPTEN_MAINLOOP_BEGIN
+#else
     while (!done)
+#endif
     {
         // Poll and handle events (inputs, window resize, etc.)
         // You can read the io.WantCaptureMouse, io.WantCaptureKeyboard flags to tell if dear imgui wants to use your inputs.
@@ -163,6 +176,9 @@ int main(int, char**)
         ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
         SDL_GL_SwapWindow(window);
     }
+#ifdef __EMSCRIPTEN__
+    EMSCRIPTEN_MAINLOOP_END;
+#endif
 
     // Cleanup
     ImGui_ImplOpenGL3_Shutdown();

+ 37 - 0
examples/libs/emscripten/emscripten_mainloop_stub.h

@@ -0,0 +1,37 @@
+// What does this file solves?
+// - Since Dear ImGui 1.00 we took pride that most of our examples applications had their entire
+//   main-loop inside the main() function. That's because:
+//   - It makes the examples easier to read, keeping the code sequential.
+//   - It permit the use of local variables, making it easier to try things and perform quick
+//     changes when someone needs to quickly test something (vs having to structure the example
+//     in order to pass data around). This is very important because people use those examples
+//     to craft easy-to-past repro when they want to discuss features or report issues.
+//   - It conveys at a glance that this is a no-BS framework, it won't take your main loop away from you.
+//   - It is generally nice and elegant.
+// - However, comes Emscripten... it is a wonderful and magical tech but it requires a "main loop" function.
+// - Only some of our examples would run on Emscripten. Typically the ones rendering with GL or WGPU ones.
+// - I tried to refactor those examples but felt it was problematic that other examples didn't follow the
+//   same layout. Why would the SDL+GL example be structured one way and the SGL+DX11 be structured differently?
+//   Especially as we are trying hard to convey that using a Dear ImGui backend in an *existing application*
+//   should requires only a few dozens lines of code, and this should be consistent and symmetrical for all backends.
+// - So the next logical step was to refactor all examples to follow that layout of using a "main loop" function.
+//   This worked, but it made us lose all the nice things we had...
+
+// Since only about 3 examples really need to run with Emscripten, here's our solution:
+// - Use some weird macros and capturing lambda to turn a loop in main() into a function.
+// - Hide all that crap in this file so it doesn't make our examples unusually ugly.
+//   As a stance and principle of Dear ImGui development we don't use C++ headers and we don't
+//   want to suggest to the newcomer that we would ever use C++ headers as this would affect
+//   the initial judgment of many of our target audience.
+// - Technique is based on this idea: https://github.com/ocornut/imgui/pull/2492/
+#ifdef __EMSCRIPTEN__
+#include <emscripten.h>
+#include <functional>
+static std::function<void()>            MainLoopForEmscriptenP;
+static void MainLoopForEmscripten()     { MainLoopForEmscriptenP(); }
+#define EMSCRIPTEN_MAINLOOP_BEGIN       MainLoopForEmscriptenP = [&]()
+#define EMSCRIPTEN_MAINLOOP_END         ; emscripten_set_main_loop(MainLoopForEmscripten, 0, true)
+#else
+#define EMSCRIPTEN_MAINLOOP_BEGIN
+#define EMSCRIPTEN_MAINLOOP_END
+#endif