From 8b2a724d9046d7eb9cb20c18e6c5ec433c5c3379 Mon Sep 17 00:00:00 2001 From: Pascal Thomet Date: Wed, 19 Feb 2025 20:12:51 +0100 Subject: [PATCH] Python backends: add an example using wgpu (WebGPU for Python) https://github.com/pygfx/wgpu-py provides a nice way to run imgui apps using Python + WebGPU. --- .../demos_cpp/demo_immapp_launcher.cpp | 6 +- .../demos_python/demo_immapp_launcher.py | 5 ++ .../examples/example_python_backend_wgpu.py | 89 +++++++++++++++++++ 3 files changed, 99 insertions(+), 1 deletion(-) create mode 100644 bindings/imgui_bundle/python_backends/examples/example_python_backend_wgpu.py diff --git a/bindings/imgui_bundle/demos_cpp/demo_immapp_launcher.cpp b/bindings/imgui_bundle/demos_cpp/demo_immapp_launcher.cpp index e27e049b..fb1271ac 100644 --- a/bindings/imgui_bundle/demos_cpp/demo_immapp_launcher.cpp +++ b/bindings/imgui_bundle/demos_cpp/demo_immapp_launcher.cpp @@ -70,7 +70,11 @@ std::function makeGui() "Python: how to use ImGui with pyglet using a *full python* backend", true }, - + DemoApp{ + "example_python_backend_wgpu", + "Python: how to use ImGui with wgpu (WebGPU for Python)", + true, + }, }; std::string demoPythonBackendFolder = DemoPythonFolder() + + "/../python_backends/examples"; DemoAppTable demoAppTable( diff --git a/bindings/imgui_bundle/demos_python/demo_immapp_launcher.py b/bindings/imgui_bundle/demos_python/demo_immapp_launcher.py index 1150ec2b..60347754 100644 --- a/bindings/imgui_bundle/demos_python/demo_immapp_launcher.py +++ b/bindings/imgui_bundle/demos_python/demo_immapp_launcher.py @@ -90,6 +90,11 @@ def make_gui() -> GuiFunction: "Python: how to use ImGui with pyglet using a *full python* backend", is_python_backend_demo=True, ), + DemoApp( + "example_python_backend_wgpu", + "Python: how to use ImGui with wgpu (WebGPU for Python)", + is_python_backend_demo=True, + ), ] this_dir = os.path.dirname(__file__) diff --git a/bindings/imgui_bundle/python_backends/examples/example_python_backend_wgpu.py b/bindings/imgui_bundle/python_backends/examples/example_python_backend_wgpu.py new file mode 100644 index 00000000..586f144b --- /dev/null +++ b/bindings/imgui_bundle/python_backends/examples/example_python_backend_wgpu.py @@ -0,0 +1,89 @@ +# wgpu (see https://github.com/pygfx/wgpu-py and https://wgpu-py.readthedocs.io/en/stable/) +# provides a Python implementation of WebGPU together with +# an easy-to-use interface to Dear ImGui Bundle! +# +# See more examples in the wgpu-py repository here: +# https://github.com/pygfx/wgpu-py/tree/main/examples +# (look for examples whose name starts with "imgui_") +# +# Requirements: install wgpu with `pip install wgpu` + +import wgpu +import sys +from imgui_bundle import imgui, imgui_ctx +from wgpu.gui.auto import WgpuCanvas, run +from wgpu.utils.imgui import ImguiRenderer + + +# Create a canvas to render to +canvas = WgpuCanvas(title="imgui", size=(640, 480)) + +# Create a wgpu device +adapter = wgpu.gpu.request_adapter_sync(power_preference="high-performance") +device = adapter.request_device_sync() + +app_state = {"text": "Hello, World\nLorem ipsum, etc.\netc."} +imgui_renderer = ImguiRenderer(device, canvas) + + +def update_gui(): + imgui.new_frame() + if imgui.begin_main_menu_bar(): + if imgui.begin_menu("File", True): + clicked_quit, _ = imgui.menu_item("Quit", "Cmd+Q", False, True) + if clicked_quit: + sys.exit(0) + + imgui.end_menu() + imgui.end_main_menu_bar() + + imgui.set_next_window_size((300, 0), imgui.Cond_.appearing) + imgui.set_next_window_pos((0, 20), imgui.Cond_.appearing) + + imgui.begin("Custom window", None) + imgui.text("Example Text") + + if imgui.button("Hello"): + print("World") + + _, app_state["text"] = imgui.input_text_multiline( + "Edit", app_state["text"], imgui.ImVec2(200, 200) + ) + io = imgui.get_io() + imgui.text( + f""" + Keyboard modifiers: + {io.key_ctrl=} + {io.key_alt=} + {io.key_shift=} + {io.key_super=}""" + ) + + if imgui.button("Open popup"): + imgui.open_popup("my popup") + with imgui_ctx.begin_popup_modal("my popup") as popup: + if popup.visible: + imgui.text("Hello from popup!") + if imgui.button("Close popup"): + imgui.close_current_popup() + + imgui.end() + + imgui.end_frame() + imgui.render() + + return imgui.get_draw_data() + + +# set the GUI update function that gets called to return the draw data +imgui_renderer.set_gui(update_gui) + + +def draw_frame(): + imgui_renderer.render() + canvas.request_draw() + + +if __name__ == "__main__": + canvas.request_draw(draw_frame) + run()