Skip to content

Commit ee3b8cf

Browse files
committed
Initial
0 parents  commit ee3b8cf

8 files changed

+2735
-0
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
/target/

Cargo.lock

+2,325
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
[package]
2+
name = "amethyst-imgui"
3+
version = "0.1.0"
4+
5+
[dependencies]
6+
amethyst = "0.8.0"
7+
gfx = "0.17.1"
8+
glsl-layout = "0.1.1"
9+
10+
glium = { version = "0.22", default-features = true }
11+
imgui = { git = "https://github.com/Gekkio/imgui-rs" }
12+
imgui-gfx-renderer = { git = "https://github.com/Gekkio/imgui-rs" }

README.md

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# Usage:
2+
1. Add `.with_pass(amethyst_imgui::DrawUi::new())` to your Stage
3+
1. Add this to your `handle_event`: ```rust
4+
let imgui_state: &mut Option<amethyst_imgui::ImguiState> = &mut data.world.write_resource::<Option<amethyst_imgui::ImguiState>>();
5+
if let Some(ref mut imgui_state) = imgui_state {
6+
amethyst_imgui::handle_imgui_events(imgui_state, &event);
7+
}
8+
```
9+
1. Add this to your main `update`: ```rust
10+
let imgui_state: &mut Option<amethyst_imgui::ImguiState> = &mut state.world.write_resource::<Option<amethyst_imgui::ImguiState>>();
11+
if let Some(ref mut imgui_state) = imgui_state {
12+
imgui_state.run_ui = Some(Box::new(move |ui: &mut imgui::Ui<'_>| {
13+
ui.show_demo_window(&mut true);
14+
ui.window(im_str!("TEST WINDOW WOOO")).build(|| {
15+
ui.text(im_str!("{}", seconds));
16+
});
17+
}));
18+
}
19+
```

mplus-1p-regular.ttf

1.66 MB
Binary file not shown.

src/lib.rs

+340
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,340 @@
1+
pub extern crate imgui;
2+
extern crate amethyst;
3+
extern crate gfx;
4+
#[macro_use] extern crate glsl_layout;
5+
extern crate imgui_gfx_renderer;
6+
7+
use amethyst::{
8+
core::{cgmath, specs::prelude::*},
9+
renderer::{
10+
error::Result,
11+
pipe::{
12+
pass::{Pass, PassData},
13+
Effect,
14+
NewEffect,
15+
},
16+
Encoder,
17+
Mesh,
18+
PosTex,
19+
Resources,
20+
VertexFormat,
21+
},
22+
};
23+
use gfx::{memory::Typed, preset::blend, pso::buffer::ElemStride, state::ColorMask};
24+
use gfx::traits::Factory;
25+
use glsl_layout::{vec2, vec4, Uniform};
26+
use imgui::{FontGlyphRange, FrameSize, ImFontConfig, ImGui, ImVec4};
27+
use imgui_gfx_renderer::{Renderer as ImguiRenderer, Shaders};
28+
29+
const VERT_SRC: &[u8] = include_bytes!("shaders/vertex.glsl");
30+
const FRAG_SRC: &[u8] = include_bytes!("shaders/frag.glsl");
31+
32+
#[derive(Copy, Clone, Debug, Uniform)]
33+
#[allow(dead_code)] // This is used by the shaders
34+
#[repr(C)]
35+
struct VertexArgs {
36+
proj_vec: vec4,
37+
coord: vec2,
38+
dimension: vec2,
39+
}
40+
41+
struct RendererThing {
42+
renderer: ImguiRenderer<Resources>,
43+
texture: gfx::handle::Texture<Resources, gfx::format::R8_G8_B8_A8>,
44+
shader_resource_view: gfx::handle::ShaderResourceView<Resources, [f32; 4]>,
45+
mesh: Mesh,
46+
}
47+
48+
#[derive(Default)]
49+
pub struct DrawUi {
50+
imgui: Option<ImGui>,
51+
renderer: Option<RendererThing>,
52+
}
53+
54+
impl DrawUi {
55+
pub fn new() -> Self {
56+
Self::default()
57+
}
58+
}
59+
60+
pub struct ImguiState {
61+
pub run_ui: Option<Box<dyn Fn(&mut imgui::Ui<'_>) + Sync + Send>>,
62+
imgui: ImGui,
63+
mouse_state: MouseState,
64+
size: (u16, u16),
65+
}
66+
67+
type UiPassData<'pass_data> = (
68+
ReadExpect<'pass_data, amethyst::renderer::ScreenDimensions>,
69+
Read<'pass_data, amethyst::core::timing::Time>,
70+
Write<'pass_data, Option<ImguiState>>,
71+
);
72+
73+
impl<'pass_data> PassData<'pass_data> for DrawUi {
74+
type Data = UiPassData<'pass_data>;
75+
}
76+
77+
type FormattedT = (gfx::format::R8_G8_B8_A8, gfx::format::Unorm);
78+
79+
impl Pass for DrawUi {
80+
fn compile(&mut self, mut effect: NewEffect<'_>) -> Result<Effect> {
81+
let mut imgui = ImGui::init();
82+
{
83+
// Fix incorrect colors with sRGB framebuffer
84+
fn imgui_gamma_to_linear(col: ImVec4) -> ImVec4 {
85+
let x = col.x.powf(2.2);
86+
let y = col.y.powf(2.2);
87+
let z = col.z.powf(2.2);
88+
let w = 1.0 - (1.0 - col.w).powf(2.2);
89+
ImVec4::new(x, y, z, w)
90+
}
91+
92+
let style = imgui.style_mut();
93+
for col in 0..style.colors.len() {
94+
style.colors[col] = imgui_gamma_to_linear(style.colors[col]);
95+
}
96+
}
97+
imgui.set_ini_filename(None);
98+
99+
let font_size = 13.;
100+
101+
let _ = imgui.fonts().add_font_with_config(
102+
include_bytes!("../mplus-1p-regular.ttf"),
103+
ImFontConfig::new()
104+
.oversample_h(1)
105+
.pixel_snap_h(true)
106+
.size_pixels(font_size)
107+
.rasterizer_multiply(1.75),
108+
&FontGlyphRange::japanese(),
109+
);
110+
111+
let _ = imgui.fonts().add_default_font_with_config(
112+
ImFontConfig::new()
113+
.merge_mode(true)
114+
.oversample_h(1)
115+
.pixel_snap_h(true)
116+
.size_pixels(font_size),
117+
);
118+
119+
{
120+
macro_rules! set_keys {
121+
($($key:ident => $id:expr),+$(,)*) => {
122+
$(imgui.set_imgui_key(imgui::ImGuiKey::$key, $id);)+
123+
};
124+
}
125+
126+
set_keys![
127+
Tab => 0,
128+
LeftArrow => 1,
129+
RightArrow => 2,
130+
UpArrow => 3,
131+
DownArrow => 4,
132+
PageUp => 5,
133+
PageDown => 6,
134+
Home => 7,
135+
End => 8,
136+
Delete => 9,
137+
Backspace => 10,
138+
Enter => 11,
139+
Escape => 12,
140+
A => 13,
141+
C => 14,
142+
V => 15,
143+
X => 16,
144+
Y => 17,
145+
Z => 18,
146+
];
147+
}
148+
149+
let data = vec![
150+
PosTex {
151+
position: [0., 1., 0.],
152+
tex_coord: [0., 0.],
153+
},
154+
PosTex {
155+
position: [1., 1., 0.],
156+
tex_coord: [1., 0.],
157+
},
158+
PosTex {
159+
position: [1., 0., 0.],
160+
tex_coord: [1., 1.],
161+
},
162+
PosTex {
163+
position: [0., 1., 0.],
164+
tex_coord: [0., 0.],
165+
},
166+
PosTex {
167+
position: [1., 0., 0.],
168+
tex_coord: [1., 1.],
169+
},
170+
PosTex {
171+
position: [0., 0., 0.],
172+
tex_coord: [0., 1.],
173+
},
174+
];
175+
176+
let (texture, shader_resource_view, target) = effect.factory.create_render_target::<FormattedT>(1024, 1024).unwrap();
177+
let renderer = ImguiRenderer::init(&mut imgui, effect.factory, Shaders::GlSl130, target).unwrap();
178+
self.renderer = Some(RendererThing {
179+
renderer,
180+
texture,
181+
shader_resource_view,
182+
mesh: Mesh::build(data).build(&mut effect.factory)?,
183+
});
184+
self.imgui = Some(imgui);
185+
186+
effect
187+
.simple(VERT_SRC, FRAG_SRC)
188+
.with_raw_constant_buffer("VertexArgs", std::mem::size_of::<<VertexArgs as Uniform>::Std140>(), 1)
189+
.with_raw_vertex_buffer(PosTex::ATTRIBUTES, PosTex::size() as ElemStride, 0)
190+
.with_texture("albedo")
191+
.with_blended_output("color", ColorMask::all(), blend::ALPHA, None)
192+
.build()
193+
}
194+
195+
fn apply<'ui, 'pass_data: 'ui>(
196+
&'ui mut self,
197+
encoder: &mut Encoder,
198+
effect: &mut Effect,
199+
mut factory: amethyst::renderer::Factory,
200+
(screen_dimensions, time, mut imgui_state): UiPassData<'pass_data>,
201+
) {
202+
let imgui_state = imgui_state.get_or_insert_with(|| ImguiState {
203+
imgui: self.imgui.take().unwrap(),
204+
mouse_state: MouseState::default(),
205+
run_ui: None,
206+
size: (1024, 1024),
207+
});
208+
let imgui = &mut imgui_state.imgui;
209+
210+
let (width, height) = (screen_dimensions.width(), screen_dimensions.height());
211+
let renderer_thing = self.renderer.as_mut().unwrap();
212+
213+
let vertex_args = VertexArgs {
214+
proj_vec: cgmath::vec4(2. / width, -2. / height, 0., 1.).into(),
215+
coord: [0., 0.].into(),
216+
dimension: [width, height].into(),
217+
};
218+
219+
if imgui_state.size.0 != width as u16 || imgui_state.size.1 != height as u16 {
220+
let (texture, shader_resource_view, target) = factory.create_render_target::<FormattedT>(width as u16, height as u16).unwrap();
221+
renderer_thing.renderer.update_render_target(target);
222+
renderer_thing.shader_resource_view = shader_resource_view;
223+
renderer_thing.texture = texture;
224+
}
225+
226+
encoder.clear(
227+
&factory
228+
.view_texture_as_render_target::<FormattedT>(&renderer_thing.texture, 0, None)
229+
.unwrap(),
230+
[0., 0., 0., 0.],
231+
);
232+
{
233+
if let Some(ref run_ui) = imgui_state.run_ui {
234+
let mut ui = imgui.frame(FrameSize::new(f64::from(width), f64::from(height), 1.), time.delta_seconds());
235+
run_ui(&mut ui);
236+
renderer_thing.renderer.render(ui, &mut factory, encoder).unwrap();
237+
}
238+
}
239+
240+
{
241+
use gfx::texture::{FilterMethod, SamplerInfo, WrapMode};
242+
let sampler = factory.create_sampler(SamplerInfo::new(FilterMethod::Trilinear, WrapMode::Clamp));
243+
effect.data.samplers.push(sampler);
244+
}
245+
246+
effect.update_constant_buffer("VertexArgs", &vertex_args.std140(), encoder);
247+
effect.data.textures.push(renderer_thing.shader_resource_view.raw().clone());
248+
effect
249+
.data
250+
.vertex_bufs
251+
.push(renderer_thing.mesh.buffer(PosTex::ATTRIBUTES).unwrap().clone());
252+
253+
effect.draw(renderer_thing.mesh.slice(), encoder);
254+
255+
effect.data.textures.clear();
256+
effect.data.samplers.clear();
257+
}
258+
}
259+
260+
#[derive(Copy, Clone, PartialEq, Debug, Default)]
261+
struct MouseState {
262+
pos: (i32, i32),
263+
pressed: (bool, bool, bool),
264+
wheel: f32,
265+
}
266+
267+
pub fn handle_imgui_events(imgui_state: &mut ImguiState, event: &amethyst::renderer::Event) {
268+
use amethyst::{
269+
renderer::{
270+
ElementState,
271+
Event,
272+
MouseButton,
273+
VirtualKeyCode as VK,
274+
WindowEvent::{self, ReceivedCharacter},
275+
},
276+
winit::{MouseScrollDelta, TouchPhase},
277+
};
278+
279+
let imgui = &mut imgui_state.imgui;
280+
let mouse_state = &mut imgui_state.mouse_state;
281+
282+
if let Event::WindowEvent { event, .. } = event {
283+
match event {
284+
WindowEvent::KeyboardInput { input, .. } => {
285+
let pressed = input.state == ElementState::Pressed;
286+
match input.virtual_keycode {
287+
Some(VK::Tab) => imgui.set_key(0, pressed),
288+
Some(VK::Left) => imgui.set_key(1, pressed),
289+
Some(VK::Right) => imgui.set_key(2, pressed),
290+
Some(VK::Up) => imgui.set_key(3, pressed),
291+
Some(VK::Down) => imgui.set_key(4, pressed),
292+
Some(VK::PageUp) => imgui.set_key(5, pressed),
293+
Some(VK::PageDown) => imgui.set_key(6, pressed),
294+
Some(VK::Home) => imgui.set_key(7, pressed),
295+
Some(VK::End) => imgui.set_key(8, pressed),
296+
Some(VK::Delete) => imgui.set_key(9, pressed),
297+
Some(VK::Back) => imgui.set_key(10, pressed),
298+
Some(VK::Return) => imgui.set_key(11, pressed),
299+
Some(VK::Escape) => imgui.set_key(12, pressed),
300+
Some(VK::A) => imgui.set_key(13, pressed),
301+
Some(VK::C) => imgui.set_key(14, pressed),
302+
Some(VK::V) => imgui.set_key(15, pressed),
303+
Some(VK::X) => imgui.set_key(16, pressed),
304+
Some(VK::Y) => imgui.set_key(17, pressed),
305+
Some(VK::Z) => imgui.set_key(18, pressed),
306+
Some(VK::LControl) | Some(VK::RControl) => imgui.set_key_ctrl(pressed),
307+
Some(VK::LShift) | Some(VK::RShift) => imgui.set_key_shift(pressed),
308+
Some(VK::LAlt) | Some(VK::RAlt) => imgui.set_key_alt(pressed),
309+
Some(VK::LWin) | Some(VK::RWin) => imgui.set_key_super(pressed),
310+
_ => {},
311+
}
312+
},
313+
WindowEvent::CursorMoved { position: pos, .. } => {
314+
mouse_state.pos = (pos.0 as i32, pos.1 as i32);
315+
},
316+
WindowEvent::MouseInput { state, button, .. } => match button {
317+
MouseButton::Left => mouse_state.pressed.0 = *state == ElementState::Pressed,
318+
MouseButton::Right => mouse_state.pressed.1 = *state == ElementState::Pressed,
319+
MouseButton::Middle => mouse_state.pressed.2 = *state == ElementState::Pressed,
320+
_ => {},
321+
},
322+
WindowEvent::MouseWheel {
323+
delta: MouseScrollDelta::LineDelta(_, y),
324+
phase: TouchPhase::Moved,
325+
..
326+
} | WindowEvent::MouseWheel {
327+
delta: MouseScrollDelta::PixelDelta(_, y),
328+
phase: TouchPhase::Moved,
329+
..
330+
} => mouse_state.wheel = *y,
331+
ReceivedCharacter(c) => imgui.add_input_character(*c),
332+
_ => (),
333+
}
334+
}
335+
336+
imgui.set_mouse_pos(mouse_state.pos.0 as f32, mouse_state.pos.1 as f32);
337+
imgui.set_mouse_down([mouse_state.pressed.0, mouse_state.pressed.1, mouse_state.pressed.2, false, false]);
338+
imgui.set_mouse_wheel(mouse_state.wheel);
339+
mouse_state.wheel = 0.0;
340+
}

src/shaders/frag.glsl

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
#version 150
2+
3+
uniform sampler2D albedo;
4+
5+
in vec2 f_uv;
6+
in vec4 f_color;
7+
8+
out vec4 color;
9+
10+
void main() {
11+
color = texture(albedo, f_uv.st);
12+
}

0 commit comments

Comments
 (0)