diff --git a/imgui-examples/Cargo.lock b/imgui-examples/Cargo.lock index fd5b1d6..83d6189 100644 --- a/imgui-examples/Cargo.lock +++ b/imgui-examples/Cargo.lock @@ -1,3 +1,5 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. [[package]] name = "andrew" version = "0.1.4" @@ -193,6 +195,16 @@ dependencies = [ "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "gfx_device_dx11" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "gfx_core 0.8.3 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "gfx_device_gl" version = "0.15.4" @@ -211,6 +223,18 @@ dependencies = [ "gl_generator 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "gfx_window_dxgi" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "gfx_core 0.8.3 (registry+https://github.com/rust-lang/crates.io-index)", + "gfx_device_dx11 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "winit 0.18.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "gfx_window_glutin" version = "0.28.0" @@ -273,35 +297,37 @@ dependencies = [ [[package]] name = "imgui" -version = "0.0.22-pre" +version = "0.0.23-pre" dependencies = [ - "imgui-sys 0.0.22-pre", + "imgui-sys 0.0.23-pre", ] [[package]] name = "imgui-examples" -version = "0.0.22-pre" +version = "0.0.23-pre" dependencies = [ "gfx 0.17.1 (registry+https://github.com/rust-lang/crates.io-index)", + "gfx_window_dxgi 0.17.0 (registry+https://github.com/rust-lang/crates.io-index)", "gfx_window_glutin 0.28.0 (registry+https://github.com/rust-lang/crates.io-index)", "glutin 0.19.0 (registry+https://github.com/rust-lang/crates.io-index)", - "imgui 0.0.22-pre", - "imgui-gfx-renderer 0.0.22-pre", - "imgui-winit-support 0.0.22-pre", + "imgui 0.0.23-pre", + "imgui-gfx-renderer 0.0.23-pre", + "imgui-winit-support 0.0.23-pre", ] [[package]] name = "imgui-gfx-renderer" -version = "0.0.22-pre" +version = "0.0.23-pre" dependencies = [ "gfx 0.17.1 (registry+https://github.com/rust-lang/crates.io-index)", - "imgui 0.0.22-pre", - "imgui-sys 0.0.22-pre", + "imgui 0.0.23-pre", + "imgui-sys 0.0.23-pre", + "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "imgui-sys" -version = "0.0.22-pre" +version = "0.0.23-pre" dependencies = [ "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", "cc 1.0.28 (registry+https://github.com/rust-lang/crates.io-index)", @@ -311,9 +337,9 @@ dependencies = [ [[package]] name = "imgui-winit-support" -version = "0.0.22-pre" +version = "0.0.23-pre" dependencies = [ - "imgui 0.0.22-pre", + "imgui 0.0.23-pre", "winit 0.18.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -870,8 +896,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" "checksum gfx 0.17.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7d7ce0c1f747245342a73453fdb098ea0764c430421fbc4d98cdc8ef8ede4834" "checksum gfx_core 0.8.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c74932837e61f20956c3da1a47471513707dde300274812bba94373ab51830ae" +"checksum gfx_device_dx11 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b918e22cc5747deaba469c5e04bc7f2bb63a4a0b6baaf93427d1f794236383ff" "checksum gfx_device_gl 0.15.4 (registry+https://github.com/rust-lang/crates.io-index)" = "eb0cf0ff6a14427022856f608c167cd93ef01ead97ff2eff4ff0287130e80d0f" "checksum gfx_gl 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3e8a920f8f6c1025a7ddf9dd25502bf059506fd3cd765dfbe8dba0b56b7eeecb" +"checksum gfx_window_dxgi 0.17.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8365e2133ea9cd77c4a2ef600977e28596da6098d5a36c541a0f8310ad4c675c" "checksum gfx_window_glutin 0.28.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9762740a3aa4d2c0dc61fca23a4271e4c26586d90d7e904c00e2dd97d775db7f" "checksum gl_generator 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a0ffaf173cf76c73a73e080366bf556b4776ece104b06961766ff11449f38604" "checksum gl_generator 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a795170cbd85b5a7baa58d6d7525cae6a03e486859860c220f7ebbbdd379d0a" diff --git a/imgui-examples/Cargo.toml b/imgui-examples/Cargo.toml index d6cbd5b..62aed38 100644 --- a/imgui-examples/Cargo.toml +++ b/imgui-examples/Cargo.toml @@ -16,3 +16,6 @@ glutin = "0.19" imgui = { version = "0.0.23-pre", path = "../" } imgui-gfx-renderer = { version = "0.0.23-pre", path = "../imgui-gfx-renderer" } imgui-winit-support = { version = "0.0.23-pre", path = "../imgui-winit-support" } + +[target.'cfg(windows)'.dev-dependencies] +gfx_window_dxgi = "0.17" \ No newline at end of file diff --git a/imgui-examples/examples/hello_gfx.rs b/imgui-examples/examples/hello_gfx.rs index 162f32d..449856b 100644 --- a/imgui-examples/examples/hello_gfx.rs +++ b/imgui-examples/examples/hello_gfx.rs @@ -5,7 +5,7 @@ mod support_gfx; const CLEAR_COLOR: [f32; 4] = [1.0, 1.0, 1.0, 1.0]; fn main() { - support_gfx::run("hello_gfx.rs".to_owned(), CLEAR_COLOR, hello_world); + support_gfx::run_dx11("hello_gfx.rs".to_owned(), CLEAR_COLOR, hello_world); } fn hello_world<'a>(ui: &Ui<'a>) -> bool { diff --git a/imgui-examples/examples/support_gfx/mod.rs b/imgui-examples/examples/support_gfx/mod.rs index d59cec6..960ada9 100644 --- a/imgui-examples/examples/support_gfx/mod.rs +++ b/imgui-examples/examples/support_gfx/mod.rs @@ -145,3 +145,131 @@ pub fn run bool>(title: String, clear_color: [f32; 4], mut run_ device.cleanup(); } } + +// #[cfg(windows)] +pub fn run_dx11 bool>(title: String, clear_color: [f32; 4], mut run_ui: F) { + use gfx::{self, Device}; + use gfx_window_dxgi; + use glutin; + + type ColorFormat = gfx::format::Rgba8; + type DepthFormat = gfx::format::DepthStencil; + + let mut events_loop = glutin::EventsLoop::new(); + let window = glutin::WindowBuilder::new() + .with_title(title) + .with_dimensions(glutin::dpi::LogicalSize::new(1024f64, 768f64)); + let (window, mut device, mut factory, mut main_color) = + gfx_window_dxgi::init::(window, &events_loop) + .expect("Failed to initalize graphics"); + let mut encoder: gfx::Encoder<_, _> = factory.create_command_buffer().into(); + + let mut imgui = ImGui::init(); + { + // Fix incorrect colors with sRGB framebuffer + fn imgui_gamma_to_linear(col: ImVec4) -> ImVec4 { + let x = col.x.powf(2.2); + let y = col.y.powf(2.2); + let z = col.z.powf(2.2); + let w = 1.0 - (1.0 - col.w).powf(2.2); + ImVec4::new(x, y, z, w) + } + + let style = imgui.style_mut(); + for col in 0..style.colors.len() { + style.colors[col] = imgui_gamma_to_linear(style.colors[col]); + } + } + imgui.set_ini_filename(None); + + // In the examples we only use integer DPI factors, because the UI can get very blurry + // otherwise. This might or might not be what you want in a real application. + let hidpi_factor = window.inner.get_hidpi_factor().round(); + + let font_size = (13.0 * hidpi_factor) as f32; + + imgui.fonts().add_default_font_with_config( + ImFontConfig::new() + .oversample_h(1) + .pixel_snap_h(true) + .size_pixels(font_size), + ); + + imgui.fonts().add_font_with_config( + include_bytes!("../../../resources/mplus-1p-regular.ttf"), + ImFontConfig::new() + .merge_mode(true) + .oversample_h(1) + .pixel_snap_h(true) + .size_pixels(font_size) + .rasterizer_multiply(1.75), + &FontGlyphRange::japanese(), + ); + + imgui.set_font_global_scale((1.0 / hidpi_factor) as f32); + + let mut renderer = Renderer::init( + &mut imgui, + &mut factory, + Shaders::HlslSm40, + main_color.clone(), + ) + .expect("Failed to initialize renderer"); + + imgui_winit_support::configure_keys(&mut imgui); + + let mut last_frame = Instant::now(); + let mut quit = false; + + loop { + events_loop.poll_events(|event| { + use glutin::{ + Event, + WindowEvent::{CloseRequested, Resized}, + }; + + imgui_winit_support::handle_event( + &mut imgui, + &event, + window.inner.get_hidpi_factor(), + hidpi_factor, + ); + + if let Event::WindowEvent { event, .. } = event { + match event { + Resized(size) => { + // gfx_window_dxgi::update_views(&window, &mut factory, &mut device, ); + renderer.update_render_target(main_color.clone()); + } + CloseRequested => quit = true, + _ => (), + } + } + }); + if quit { + break; + } + + let now = Instant::now(); + let delta = now - last_frame; + let delta_s = delta.as_secs() as f32 + delta.subsec_nanos() as f32 / 1_000_000_000.0; + last_frame = now; + + imgui_winit_support::update_mouse_cursor(&imgui, &window.inner); + + let frame_size = imgui_winit_support::get_frame_size(&window.inner, hidpi_factor).unwrap(); + + let ui = imgui.frame(frame_size, delta_s); + if !run_ui(&ui) { + break; + } + + encoder.clear(&main_color, clear_color); + renderer + .render(ui, &mut factory, &mut encoder) + .expect("Rendering failed"); + encoder.flush(&mut device); + window.swap_buffers(1); + device.cleanup(); + } +} diff --git a/imgui-gfx-renderer/Cargo.toml b/imgui-gfx-renderer/Cargo.toml index 08812a7..27bfd94 100644 --- a/imgui-gfx-renderer/Cargo.toml +++ b/imgui-gfx-renderer/Cargo.toml @@ -16,3 +16,6 @@ travis-ci = { repository = "Gekkio/imgui-rs" } gfx = "0.17" imgui = { version = "0.0.23-pre", path = "../" } imgui-sys = { version = "0.0.23-pre", path = "../imgui-sys", features = ["gfx"] } + +[target.'cfg(windows)'.build-dependencies] +winapi = { version = "0.3", features = ["d3dcompiler"] } \ No newline at end of file diff --git a/imgui-gfx-renderer/build.rs b/imgui-gfx-renderer/build.rs new file mode 100644 index 0000000..128dc27 --- /dev/null +++ b/imgui-gfx-renderer/build.rs @@ -0,0 +1,109 @@ +fn main() { + #[cfg(windows)] + hlsl_build::compile_hlsl_shaders(); +} + +#[cfg(windows)] +mod hlsl_build { + use std::env; + use std::ffi::CStr; + use std::ffi::CString; + use std::fs; + use std::path::Path; + use std::path::PathBuf; + use std::ptr; + use std::slice; + use std::str; + + pub fn compile_hlsl_shaders() { + let source_path = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap()) + .join("src") + .join("shader") + .join("sm_40.hlsl"); + + let src_data = fs::read_to_string(&source_path).unwrap(); + + let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap()); + + fs::write( + out_dir.join("hlsl_vertex_shader_bytecode"), + compile_shader(&src_data, &source_path, "VertexMain", "vs_4_0").unwrap_or_else( + |error_message| { + eprintln!("{}", error_message); + panic!("Vertex shader failed to compile"); + }, + ), + ) + .unwrap(); + + fs::write( + out_dir.join("hlsl_pixel_shader_bytecode"), + compile_shader(&src_data, &source_path, "PixelMain", "ps_4_0").unwrap_or_else( + |error_message| { + eprintln!("{}", error_message); + panic!("Pixel shader failed to compile"); + }, + ), + ) + .unwrap(); + } + + fn compile_shader( + src_data: &str, + source_path: &Path, + entry_point: &str, + target: &str, + ) -> Result, String> { + use winapi::shared::minwindef::LPCVOID; + use winapi::um::d3dcommon::ID3DBlob; + use winapi::um::d3dcompiler; + + unsafe { + let mut code: *mut ID3DBlob = ptr::null_mut(); + let mut error_msgs: *mut ID3DBlob = ptr::null_mut(); + + let hr = d3dcompiler::D3DCompile( + src_data.as_bytes().as_ptr() as LPCVOID, + src_data.as_bytes().len(), + CString::new(source_path.to_string_lossy().to_string()) + .unwrap() + .as_ptr(), + ptr::null(), + ptr::null_mut(), + CString::new(entry_point).unwrap().as_ptr(), + CString::new(target).unwrap().as_ptr(), + 0, + 0, + &mut code, + &mut error_msgs, + ); + + if hr < 0 { + if !error_msgs.is_null() { + let error_msgs = error_msgs.as_ref().unwrap(); + + let error_msgs = str::from_utf8(slice::from_raw_parts( + error_msgs.GetBufferPointer() as *const u8, + error_msgs.GetBufferSize(), + )) + .expect("error messages from D3DCompile not valid UTF-8"); + + Err(error_msgs.to_string()) + } else { + Err(format!("hresult: {}", hr)) + } + } else { + let code = code + .as_ref() + .expect("null code blob returned from D3DCompile"); + + Ok(slice::from_raw_parts( + code.GetBufferPointer() as *const u8, + code.GetBufferSize(), + ) + .to_vec()) + } + } + } + +} diff --git a/imgui-gfx-renderer/src/lib.rs b/imgui-gfx-renderer/src/lib.rs index bbfb794..0049e85 100644 --- a/imgui-gfx-renderer/src/lib.rs +++ b/imgui-gfx-renderer/src/lib.rs @@ -76,6 +76,7 @@ macro_rules! extended_defines { } } +#[cfg(not(windows))] extended_defines! { pipeline pipe { vertex_buffer: gfx::VertexBuffer = (), @@ -90,6 +91,22 @@ extended_defines! { } } +// TODO need constant buffer support +#[cfg(windows)] +extended_defines! { + pipeline pipe { + vertex_buffer: gfx::VertexBuffer = (), + matrix: gfx::Global<[[f32; 4]; 4]> = "transform", + tex: gfx::TextureSampler<[f32; 4]> = "tex", + out: gfx::BlendTarget = ( + "Target0", + gfx::state::ColorMask::all(), + gfx::preset::blend::ALPHA, + ), + scissor: gfx::Scissor = (), + } +} + #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub enum Shaders { GlSl400, // OpenGL 4.0+ @@ -98,6 +115,7 @@ pub enum Shaders { GlSl110, // OpenGL 2.0+ GlSlEs300, // OpenGL ES 3.0+ GlSlEs100, // OpenGL ES 2.0+ + HlslSm40, // HLSL Shader Model 4.0+ } impl Shaders { @@ -128,6 +146,21 @@ impl Shaders { include_bytes!("shader/glsles_100.vert"), include_bytes!("shader/glsles_100.frag"), ), + HlslSm40 => { + #[cfg(not(windows))] + { + // panic instead? + (&[0], &[0]) + } + + #[cfg(windows)] + { + ( + include_bytes!(concat!(env!("OUT_DIR"), "/hlsl_vertex_shader_bytecode")), + include_bytes!(concat!(env!("OUT_DIR"), "/hlsl_pixel_shader_bytecode")), + ) + } + } } } } diff --git a/imgui-gfx-renderer/src/shader/sm_40.hlsl b/imgui-gfx-renderer/src/shader/sm_40.hlsl new file mode 100644 index 0000000..d18d01f --- /dev/null +++ b/imgui-gfx-renderer/src/shader/sm_40.hlsl @@ -0,0 +1,41 @@ +cbuffer Constants : register(b0) { + float4x4 transform; +} + +Texture2D tex; + +// Should be trilinear clamp +SamplerState linear_clamp_sampler +{ + Filter = MIN_MAG_MIP_LINEAR; + AddressU = Clamp; + AddressV = Clamp; +}; + +struct VIn { + float2 position : pos; + float2 uv : uv; + float4 color : col; +}; + +struct VOut +{ + float4 position : SV_POSITION; + float2 uv : TEXCOORD0; + float4 color : COLOR; +}; + +VOut VertexMain(VIn vertex) +{ + VOut output; + output.position = mul(transform, float4(vertex.position, 0.0, 1.0)); + output.uv = vertex.uv; + output.color = vertex.color; + + return output; +} + +float4 PixelMain(VOut vout) : SV_TARGET +{ + return vout.color * tex.Sample(linear_clamp_sampler, vout.uv); +} \ No newline at end of file