17cupsofcoffee / tetra

🎮 A simple 2D game framework written in Rust
MIT License
907 stars 63 forks source link

Integrate ImGui (imgui-rs) into Tetra as a early GUI solution #310

Open Nekomaru-PKU opened 2 years ago

Nekomaru-PKU commented 2 years ago

Summary

After a few days' work, I've successfully integrated ImGui (imgui-rust) into Tetra without breaking API changes. All changes are under a cargo feature called experimental_imgui, except that glow, a dependency of Tetra, must be downgraded from 0.11.0 to 0.10.0, since glow 0.11.0 introduced API changes that break the latest imgui-rs glow renderer.

I prefer to keep my changes on a separate branch (maybe experimental-imgui) if they are accepted into the main repo.After such a branch is created for me, I will raise a pull request.

Motivation/Examples

Motivations

At the present, game developers using Tetra have to struggle wih their own in-game GUI solutions, since Tetra doesn't provide one, and this is especially troublesome when an in-game editor or debug dashboard is strongly needed before further development.

Immediate Mode GUI library Dear ImGui has been widely used as a simple and strong GUI solution for in-game developer tools in the game industry. As is described in the ImGui repo (https://github.com/ocornut/imgui):

Dear ImGui is a bloat-free graphical user interface library for C++. It outputs optimized vertex buffers that you can render anytime in your 3D-pipeline enabled application. It is fast, portable, renderer agnostic and self-contained (no external dependencies).

Dear ImGui is designed to enable fast iterations and to empower programmers to create content creation tools and visualization / debug tools (as opposed to UI for the average end-user). It favors simplicity and productivity toward this goal, and lacks certain features normally found in more high-level libraries.

Dear ImGui is particularly suited to integration in games engine (for tooling), real-time 3D applications, fullscreen applications, embedded applications, or any applications on consoles platforms where operating system features are non-standard.

Examples

This example is based on Tetra keyboard example, and a slider is added to control the size of the player sprite like this: image

The ImGui part is like this (diff with original keyboard example)

@@ -6,6 +6,8 @@
 struct GameState {
     texture: Texture,
     position: Vec2<f32>,
+    player_name: String,
+    player_size: f32,
 }

 impl GameState {
@@ -13,6 +15,8 @@
         Ok(GameState {
             texture: Texture::new(ctx, "./examples/resources/player.png")?,
             position: Vec2::new(32.0, 32.0),
+            player_name: String::from("player"),
+            player_size: 2.0,
         })
     }
 }
@@ -62,16 +66,33 @@
             DrawParams::new()
                 .position(self.position)
                 .origin(Vec2::new(8.0, 8.0))
-                .scale(Vec2::new(2.0, 2.0)),
+                .scale(Vec2::new(self.player_size, self.player_size)),
         );

         Ok(())
     }
+
+    fn draw_imgui(&mut self, ui: &mut tetra::imgui::Ui) -> Result<(), tetra::TetraError> {
+        let mut b = true;
+        let w = ui
+            .window("Slider examples")
+            .opened(&mut b)
+            .position([30.0, 240.0], tetra::imgui::Condition::Appearing)
+            .size([360.0, 120.0], tetra::imgui::Condition::Appearing)
+            .resizable(false);
+        w.build(|| {
+            ui.input_text("Player name", &mut self.player_name).build();
+            ui.slider("Player size", 1f32, 16f32, &mut self.player_size);
+        });
+        Ok(())
+    }
 }

 fn main() -> tetra::Result {
     ContextBuilder::new("Keyboard Input", 640, 480)
         .quit_on_escape(true)
+        .show_mouse(true)
         .build()?
         .run(GameState::new)
 }

Alternatives Considered

Implementing our own GUI solution means a lot of hard work, and on the other hand, ImGui has been considered as a de facto standard in game industry.