From 456258524ee93081b2d5044ff6a76413659f32bd Mon Sep 17 00:00:00 2001 From: Tad Hardesty Date: Mon, 10 Sep 2018 00:40:02 -0700 Subject: [PATCH] Add simplest possible image support for gfx renderer --- imgui-gfx-renderer/src/lib.rs | 32 +++++++++++-- src/image.rs | 90 +++++++++++++++++++++++++++++++++++ src/lib.rs | 12 +++++ 3 files changed, 130 insertions(+), 4 deletions(-) create mode 100644 src/image.rs diff --git a/imgui-gfx-renderer/src/lib.rs b/imgui-gfx-renderer/src/lib.rs index 0d7e74e..c6c135e 100644 --- a/imgui-gfx-renderer/src/lib.rs +++ b/imgui-gfx-renderer/src/lib.rs @@ -7,7 +7,9 @@ use gfx::memory::Bind; use gfx::texture::{FilterMethod, SamplerInfo, WrapMode}; use gfx::traits::FactoryExt; use gfx::{Bundle, CommandBuffer, Encoder, Factory, IntoIndexBuffer, Rect, Resources, Slice}; -use imgui::{DrawList, FrameSize, ImDrawIdx, ImDrawVert, ImGui, Ui}; +use imgui::{DrawList, FrameSize, ImDrawIdx, ImDrawVert, ImGui, Ui, ImTexture}; + +use std::collections::HashMap; pub type RendererResult = Result; @@ -94,9 +96,13 @@ impl Shaders { } } +pub type Texture = (gfx::handle::ShaderResourceView, gfx::handle::Sampler); + pub struct Renderer { bundle: Bundle>, index_buffer: Buffer, + textures: HashMap>, + next_texture: usize, } impl Renderer { @@ -131,9 +137,13 @@ impl Renderer { &[handle.pixels], ) })?; - // TODO: set texture id in imgui let sampler = factory.create_sampler(SamplerInfo::new(FilterMethod::Trilinear, WrapMode::Clamp)); + let pair = (texture, sampler); + let mut textures = HashMap::new(); + textures.insert(0, pair.clone()); + imgui.set_texture_id(0); + let data = pipe::Data { vertex_buffer: vertex_buffer, matrix: [ @@ -142,7 +152,7 @@ impl Renderer { [0.0, 0.0, -1.0, 0.0], [-1.0, 1.0, 0.0, 1.0], ], - tex: (texture, sampler), + tex: pair, out: out, scissor: Rect { x: 0, @@ -161,11 +171,22 @@ impl Renderer { Ok(Renderer { bundle: Bundle::new(slice, pso, data), index_buffer: index_buffer, + textures, + next_texture: 1, }) } + pub fn update_render_target(&mut self, out: RenderTargetView) { self.bundle.data.out = out; } + + pub fn add_texture(&mut self, texture: Texture) -> ImTexture { + let id = self.next_texture; + self.textures.insert(id, texture); + self.next_texture += 1; + id + } + pub fn render<'a, F: Factory, C: CommandBuffer>( &mut self, ui: Ui<'a>, @@ -214,7 +235,10 @@ impl Renderer { self.bundle.slice.start = 0; for cmd in draw_list.cmd_buffer { - // TODO: check cmd.texture_id + if let Some(tex) = self.textures.get(&(cmd.texture_id as usize)) { + // cloning handles is okay, since they're Arcs internally + self.bundle.data.tex = tex.clone(); + } self.bundle.slice.end = self.bundle.slice.start + cmd.elem_count; self.bundle.data.scissor = Rect { diff --git a/src/image.rs b/src/image.rs new file mode 100644 index 0000000..b8cf978 --- /dev/null +++ b/src/image.rs @@ -0,0 +1,90 @@ +use super::{ImVec2, ImVec4, Ui}; +use std::marker::PhantomData; +use std::os::raw::c_void; +use sys; + +pub type ImTexture = usize; + +/// Represent an image about to be drawn. +/// See [`Ui::image`]. +/// +/// Create your image using the builder pattern then [`Image::build`] it. +pub struct Image<'ui> { + /// we use Result to allow postponing any construction errors to the build call + texture_id: ImTexture, + size: ImVec2, + uv0: ImVec2, + uv1: ImVec2, + tint_col: ImVec4, + border_col: ImVec4, + _phantom: PhantomData<&'ui Ui<'ui>>, +} + +impl<'ui> Image<'ui> { + pub fn new(_: &Ui<'ui>, texture_id: usize, size: S) -> Self + where + S: Into, + { + const DEFAULT_UV0: ImVec2 = ImVec2 { x: 0.0, y: 0.0 }; + const DEFAULT_UV1: ImVec2 = ImVec2 { x: 1.0, y: 1.0 }; + const DEFAULT_TINT_COL: ImVec4 = ImVec4 { + x: 1.0, + y: 1.0, + z: 1.0, + w: 1.0, + }; + const DEFAULT_BORDER_COL: ImVec4 = ImVec4 { + x: 0.0, + y: 0.0, + z: 0.0, + w: 0.0, + }; + Image { + texture_id: texture_id, + size: size.into(), + uv0: DEFAULT_UV0, + uv1: DEFAULT_UV1, + tint_col: DEFAULT_TINT_COL, + border_col: DEFAULT_BORDER_COL, + _phantom: PhantomData, + } + } + /// Set size (default based on texture) + pub fn size>(mut self, size: T) -> Self { + self.size = size.into(); + self + } + /// Set uv0 (default `[0.0, 0.0]`) + pub fn uv0>(mut self, uv0: T) -> Self { + self.uv0 = uv0.into(); + self + } + /// Set uv1 (default `[1.0, 1.0]`) + pub fn uv1>(mut self, uv1: T) -> Self { + self.uv1 = uv1.into(); + self + } + /// Set tint color (default: no tint color) + pub fn tint_col>(mut self, tint_col: T) -> Self { + self.tint_col = tint_col.into(); + self + } + /// Set border color (default: no border) + pub fn border_col>(mut self, border_col: T) -> Self { + self.border_col = border_col.into(); + self + } + /// Draw image where the cursor currently is + pub fn build(self) { + unsafe { + sys::igImage( + self.texture_id as *mut c_void, + self.size, + self.uv0, + self.uv1, + self.tint_col, + self.border_col, + ); + } + } +} diff --git a/src/lib.rs b/src/lib.rs index e7887bc..4e9688f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -18,6 +18,7 @@ pub use drag::{ DragInt4, DragIntRange2, }; pub use fonts::{FontGlyphRange, ImFont, ImFontAtlas, ImFontConfig}; +pub use image::{ImTexture, Image}; pub use input::{ InputFloat, InputFloat2, InputFloat3, InputFloat4, InputInt, InputInt2, InputInt3, InputInt4, InputText, InputTextMultiline, @@ -45,6 +46,7 @@ mod child_frame; mod color_editors; mod drag; mod fonts; +mod image; mod input; mod menus; mod plothistogram; @@ -1301,6 +1303,16 @@ impl<'ui> Ui<'ui> { } } +// Image +impl<'ui> Ui<'ui> { + pub fn image(&self, texture: ImTexture, size: S) -> Image + where + S: Into, + { + Image::new(self, texture, size) + } +} + impl<'ui> Ui<'ui> { /// Calculate the size required for a given text string. ///