1use imgui_sys::*;
2
3use crate::gfx::Heap;
4use crate::os;
5use crate::os::App;
6use crate::os::Window;
7use crate::os::NativeHandle;
8
9use crate::gfx;
10use crate::gfx::Buffer;
11use crate::gfx::CmdBuf;
12use crate::gfx::Device;
13use crate::gfx::SwapChain;
14use crate::gfx::Texture;
15
16use std::ffi::CStr;
17use std::ffi::CString;
18
19use maths_rs::Vec4f;
20
21use std::ptr::addr_of;
22use std::ptr::addr_of_mut;
23
24macro_rules! static_ref_mut{
25 ($place:expr) => {
26 &mut *addr_of_mut!($place)
27 }
28}
29
30fn to_im_vec4(v: Vec4f) -> ImVec4 {
31 unsafe {
32 std::mem::transmute(v)
33 }
34}
35
36const DEFAULT_VB_SIZE: i32 = 5000;
37const DEFAULT_IB_SIZE: i32 = 10000;
38const MAX_RANGES: usize = 32;
39
40const MAIN_DOCKSPACE_FLAGS : u32 = ImGuiWindowFlags_NoTitleBar |
41 ImGuiWindowFlags_NoCollapse |
42 ImGuiWindowFlags_NoResize |
43 ImGuiWindowFlags_NoMove |
44 ImGuiWindowFlags_NoBringToFrontOnFocus |
45 ImGuiWindowFlags_NoNavFocus |
46 ImGuiWindowFlags_MenuBar |
47 ImGuiWindowFlags_NoScrollbar;
48
49const IMVEC2_ZERO : ImVec2 = ImVec2 {x: 0.0, y: 0.0 };
50const MAIN_DOCK_NAME : *const i8 = "main_dock\0".as_ptr() as *const i8;
51const STATUS_BAR_NAME : *const i8 = "status_bar\0".as_ptr() as *const i8;
52
53pub struct FontInfo {
55 pub filepath: String,
57 pub glyph_ranges: Option<Vec<[u32; 2]>>
59}
60
61pub struct ImGuiInfo<'stack, D: Device, A: App> {
63 pub device: &'stack mut D,
64 pub swap_chain: &'stack mut D::SwapChain,
65 pub main_window: &'stack A::Window,
66 pub fonts: Vec<FontInfo>,
67}
68
69pub struct ImGui<D: Device, A: App> {
71 _native_handle: A::NativeHandle,
72 _font_texture: D::Texture,
73 pipeline: D::RenderPipeline,
74 buffers: Vec<RenderBuffers<D>>,
75 last_cursor: os::Cursor
76}
77
78#[derive(Clone)]
79struct RenderBuffers<D: Device> {
80 vb: D::Buffer,
81 ib: D::Buffer,
82 vb_size: i32,
83 ib_size: i32,
84}
85
86struct ViewportData<D: Device, A: App> {
87 main_viewport: bool,
89 window: Vec<A::Window>,
90 swap_chain: Vec<D::SwapChain>,
91 cmd: Vec<D::CmdBuf>,
92 buffers: Vec<RenderBuffers<D>>,
93}
94
95struct UserData<'a, D: Device, A: App> {
96 app: &'a mut A,
97 device: &'a mut D,
98 main_window: &'a mut A::Window,
99 pipeline: &'a D::RenderPipeline,
100 image_heaps: &'a Vec<&'a D::Heap>
101}
102
103pub trait UserInterface<D: gfx::Device, A: os::App> {
105 fn show_ui(&mut self, imgui: &mut ImGui<D, A>, open: bool) -> bool;
106}
107
108bitflags! {
109 pub struct WindowFlags : i32 {
110 const NONE = 0;
111 const NO_TITLE_BAR = 1 << 0;
112 const NO_RESIZE = 1 << 1;
113 const NO_MOVE = 1 << 2;
114 const NO_SCROLLBAR = 1 << 3;
115 const NO_SCROLL_WITH_MOUSE = 1 << 4;
116 const NO_COLLAPSE = 1 << 5;
117 const ALWAYS_AUTO_RESIZE = 1 << 6;
118 const NO_BACKGROUND = 1 << 7;
119 const NO_SAVED_SETTINGS = 1 << 8;
120 const NO_MOUSE_INPUTS = 1 << 9;
121 const MENU_BAR = 1 << 10;
122 const HORIZONTAL_SCROLLBAR = 1 << 11;
123 const NO_FOCUS_ON_APPEARING = 1 << 12;
124 const NO_BRING_TO_FRONT_ON_FOCUS = 1 << 13;
125 const ALWAYS_VERTICAL_SCROLLBAR = 1 << 14;
126 const ALWAYS_HORIZONTAL_SCROLLBAR = 1 << 15;
127 const ALWAYS_USE_WINDOW_PADDING = 1 << 16;
128 const NO_NAV_INPUTS = 1 << 18;
129 const NO_NAV_FOCUS = 1 << 19;
130 const UNSAVED_DOCUMENT = 1 << 20;
131 const NO_DOCKING = 1 << 21;
132 const NO_NAV = (1 << 18 | 1 << 19);
133 const NO_DECORATION = (1 << 0 | 1 << 1 | 1 << 3 | 1 << 5);
134 const NO_INPUTS = (1 << 9 | 1 << 18 | 1 << 19);
135 }
136}
137
138impl From<WindowFlags> for i32 {
139 fn from(mask: WindowFlags) -> i32 {
140 mask.bits
141 }
142}
143
144fn new_viewport_data<D: Device, A: App>() -> *mut ViewportData<D, A> {
145 unsafe {
146 let layout =
147 std::alloc::Layout::from_size_align(std::mem::size_of::<ViewportData<D, A>>(), 8).unwrap();
148 std::alloc::alloc_zeroed(layout) as *mut ViewportData<D, A>
149 }
150}
151
152fn new_native_handle<A: App>(handle: A::NativeHandle) -> *mut A::NativeHandle {
153 unsafe {
154 let layout = std::alloc::Layout::from_size_align(
155 std::mem::size_of::<A::NativeHandle>(),
156 8,
157 )
158 .unwrap();
159 let nh = std::alloc::alloc_zeroed(layout) as *mut A::NativeHandle;
160 *nh = handle;
161 nh
162 }
163}
164
165fn new_monitors(monitors: &Vec<ImGuiPlatformMonitor>) -> *mut ImGuiPlatformMonitor {
166 unsafe {
167 let size_bytes = std::mem::size_of::<ImGuiPlatformMonitor>() * monitors.len();
168 let layout = std::alloc::Layout::from_size_align(size_bytes, 8).unwrap();
169 let ptr = std::alloc::alloc_zeroed(layout) as *mut ImGuiPlatformMonitor;
170 std::ptr::copy_nonoverlapping(monitors.as_ptr(), ptr, monitors.len());
171 ptr
172 }
173}
174
175fn new_ranges() -> *mut [u32; (MAX_RANGES * 2) + 1] {
176 unsafe {
177 let layout = std::alloc::Layout::from_size_align(std::mem::size_of::<[u32; (MAX_RANGES * 2) + 1]>(), 8).unwrap();
178 std::alloc::alloc_zeroed(layout) as *mut [u32; (MAX_RANGES * 2) + 1]
179 }
180}
181
182fn to_imgui_texture_id<D: Device>(tex: &D::Texture) -> ImTextureID {
183 unsafe {
184 let srv = tex.get_srv_index().unwrap() as u64;
185 let heap_id = tex.get_shader_heap_id().unwrap() as u64;
186
187 let mask = 0x0000ffffffffffff;
192 let combined = (srv & mask) | ((heap_id << 48) & !mask);
193 let tex_id : *mut cty::c_void = std::ptr::null_mut();
194 tex_id.add(combined as usize)
195 }
196}
197
198fn to_srv_heap_id(tex_id: *mut cty::c_void) -> (usize, u16) {
199 let mask = 0x0000ffffffffffff;
200 let srv_id = (tex_id as u64) & mask;
201 let heap_id = ((tex_id as u64) & !mask) >> 48;
202 (srv_id as usize, heap_id as u16)
203}
204
205fn create_fonts_texture<D: Device>(
206 device: &mut D,
207) -> Result<D::Texture, super::Error> {
208 unsafe {
209 let io = &*igGetIO();
210 let mut out_pixels: *mut u8 = std::ptr::null_mut();
211 let mut out_width = 0;
212 let mut out_height = 0;
213 let mut out_bytes_per_pixel = 0;
214 ImFontAtlas_GetTexDataAsRGBA32(
215 io.Fonts,
216 &mut out_pixels,
217 &mut out_width,
218 &mut out_height,
219 &mut out_bytes_per_pixel,
220 );
221
222 let data_size = out_bytes_per_pixel * out_width * out_height;
223 let data_slice = std::slice::from_raw_parts(out_pixels, data_size as usize);
224
225 let tex_info = gfx::TextureInfo {
226 format: gfx::Format::RGBA8n,
227 tex_type: gfx::TextureType::Texture2D,
228 width: out_width as u64,
229 height: out_height as u64,
230 depth: 1,
231 array_layers: 1,
232 mip_levels: 1,
233 samples: 1,
234 usage: gfx::TextureUsage::SHADER_RESOURCE,
235 initial_state: gfx::ResourceState::ShaderResource,
236 };
237
238 device.create_texture(&tex_info, Some(data_slice))
239 }
240}
241
242fn create_render_pipeline<D: Device, A: App>(info: &ImGuiInfo<D, A>) -> Result<D::RenderPipeline, super::Error> {
243 let device = &info.device;
244 let swap_chain = &info.swap_chain;
245
246 let src = "
248 cbuffer vertexBuffer : register(b0)
249 {
250 float4x4 ProjectionMatrix;
251 };
252 struct VS_INPUT
253 {
254 float2 pos : POSITION;
255 float4 col : COLOR0;
256 float2 uv : TEXCOORD0;
257 };
258
259 struct PS_INPUT
260 {
261 float4 pos : SV_POSITION;
262 float4 col : COLOR0;
263 float2 uv : TEXCOORD0;
264 };
265
266 PS_INPUT VSMain(VS_INPUT input)
267 {
268 PS_INPUT output;
269 output.pos = mul(ProjectionMatrix, float4(input.pos.xy, 0.0, 1.0));
270 output.col = input.col;
271 output.uv = input.uv;
272 return output;
273 }
274
275 SamplerState sampler0 : register(s0);
276 Texture2D texture0 : register(t0);
277
278 float4 PSMain(PS_INPUT input) : SV_Target
279 {
280 float4 out_col = input.col * texture0.Sample(sampler0, input.uv);
281 return out_col;
282 }";
283
284 let vs_info = gfx::ShaderInfo {
285 shader_type: gfx::ShaderType::Vertex,
286 compile_info: Some(gfx::ShaderCompileInfo {
287 entry_point: String::from("VSMain"),
288 target: String::from("vs_5_0"),
289 flags: gfx::ShaderCompileFlags::NONE,
290 }),
291 };
292
293 let fs_info = gfx::ShaderInfo {
294 shader_type: gfx::ShaderType::Fragment,
295 compile_info: Some(gfx::ShaderCompileInfo {
296 entry_point: String::from("PSMain"),
297 target: String::from("ps_5_0"),
298 flags: gfx::ShaderCompileFlags::NONE,
299 }),
300 };
301
302 let vs = device.create_shader(&vs_info, src.as_bytes())?;
303 let fs = device.create_shader(&fs_info, src.as_bytes())?;
304
305 device.create_render_pipeline(&gfx::RenderPipelineInfo {
306 vs: Some(&vs),
307 fs: Some(&fs),
308 input_layout: vec![
309 gfx::InputElementInfo {
310 semantic: String::from("POSITION"),
311 index: 0,
312 format: gfx::Format::RG32f,
313 input_slot: 0,
314 aligned_byte_offset: 0,
315 input_slot_class: gfx::InputSlotClass::PerVertex,
316 step_rate: 0,
317 },
318 gfx::InputElementInfo {
319 semantic: String::from("TEXCOORD"),
320 index: 0,
321 format: gfx::Format::RG32f,
322 input_slot: 0,
323 aligned_byte_offset: 8,
324 input_slot_class: gfx::InputSlotClass::PerVertex,
325 step_rate: 0,
326 },
327 gfx::InputElementInfo {
328 semantic: String::from("COLOR"),
329 index: 0,
330 format: gfx::Format::RGBA8n,
331 input_slot: 0,
332 aligned_byte_offset: 16,
333 input_slot_class: gfx::InputSlotClass::PerVertex,
334 step_rate: 0,
335 },
336 ],
337 pipeline_layout: gfx::PipelineLayout {
338 push_constants: Some(vec![gfx::PushConstantInfo {
339 visibility: gfx::ShaderVisibility::Vertex,
340 num_values: 16,
341 shader_register: 0,
342 register_space: 0,
343 }]),
344 bindings: Some(vec![gfx::DescriptorBinding {
345 visibility: gfx::ShaderVisibility::Fragment,
346 binding_type: gfx::DescriptorType::ShaderResource,
347 num_descriptors: Some(1),
348 shader_register: 0,
349 register_space: 0,
350 }]),
351 static_samplers: Some(vec![gfx::SamplerBinding {
352 visibility: gfx::ShaderVisibility::Fragment,
353 shader_register: 0,
354 register_space: 0,
355 sampler_info: gfx::SamplerInfo {
356 filter: gfx::SamplerFilter::Linear,
357 address_u: gfx::SamplerAddressMode::Wrap,
358 address_v: gfx::SamplerAddressMode::Wrap,
359 address_w: gfx::SamplerAddressMode::Wrap,
360 comparison: None,
361 border_colour: None,
362 mip_lod_bias: 0.0,
363 max_aniso: 0,
364 min_lod: -1.0,
365 max_lod: -1.0,
366 }}]),
367 },
368 blend_info: gfx::BlendInfo {
369 independent_blend_enabled: true,
370 render_target: vec![gfx::RenderTargetBlendInfo {
371 blend_enabled: true,
372 logic_op_enabled: false,
373 src_blend: gfx::BlendFactor::SrcAlpha,
374 dst_blend: gfx::BlendFactor::InvSrcAlpha,
375 blend_op: gfx::BlendOp::Add,
376 src_blend_alpha: gfx::BlendFactor::One,
377 dst_blend_alpha: gfx::BlendFactor::InvSrcAlpha,
378 blend_op_alpha: gfx::BlendOp::Add,
379 logic_op: gfx::LogicOp::Clear,
380 write_mask: gfx::WriteMask::ALL,
381 }],
382 ..Default::default()
383 },
384 topology: gfx::Topology::TriangleList,
385 pass: Some(swap_chain.get_backbuffer_pass()),
386 ..Default::default()
387 })
388}
389
390fn create_vertex_buffer<D: Device>(
391 device: &mut D,
392 size: i32,
393) -> Result<D::Buffer, super::Error> {
394 device.create_buffer::<u8>(
395 &gfx::BufferInfo {
396 usage: gfx::BufferUsage::VERTEX,
397 cpu_access: gfx::CpuAccessFlags::WRITE,
398 format: gfx::Format::Unknown,
399 stride: std::mem::size_of::<ImDrawVert>(),
400 num_elements: size as usize,
401 initial_state: gfx::ResourceState::VertexConstantBuffer
402 },
403 None,
404 )
405}
406
407fn create_index_buffer<D: Device>(
408 device: &mut D,
409 size: i32,
410) -> Result<D::Buffer, super::Error> {
411 device.create_buffer::<u8>(
412 &gfx::BufferInfo {
413 usage: gfx::BufferUsage::INDEX,
414 cpu_access: gfx::CpuAccessFlags::WRITE,
415 format: gfx::Format::R16u,
416 stride: std::mem::size_of::<ImDrawIdx>(),
417 num_elements: size as usize,
418 initial_state: gfx::ResourceState::IndexBuffer
419 },
420 None,
421 )
422}
423
424fn render_draw_data<D: Device>(
425 draw_data: &ImDrawData,
426 device: &mut D,
427 cmd: &mut D::CmdBuf,
428 image_heaps: &Vec<&D::Heap>,
429 buffers: &mut [RenderBuffers<D>],
430 pipeline: &D::RenderPipeline,
431) -> Result<(), super::Error> where D::RenderPipeline: gfx::Pipeline {
432 unsafe {
433 if draw_data.CmdListsCount > 0 && draw_data.TotalVtxCount > 0 {
434 let bb = cmd.get_backbuffer_index() as usize;
435
436 let buffers = &mut buffers[bb];
437
438 if draw_data.TotalVtxCount > buffers.vb_size {
440 buffers.vb = create_vertex_buffer::<D>(device, draw_data.TotalVtxCount)?;
441 buffers.vb_size = draw_data.TotalVtxCount;
442 }
443
444 if draw_data.TotalIdxCount > buffers.ib_size {
446 buffers.ib = create_index_buffer::<D>(device, draw_data.TotalIdxCount)?;
447 buffers.ib_size = draw_data.TotalIdxCount;
448 }
449
450 let imgui_cmd_lists =
452 std::slice::from_raw_parts(draw_data.CmdLists, draw_data.CmdListsCount as usize);
453 let mut vertex_write_offset = 0;
454 let mut index_write_offset = 0;
455
456 for imgui_cmd_list in imgui_cmd_lists {
457 let draw_vert = &(*(*imgui_cmd_list)).VtxBuffer;
459 let vb_size_bytes = draw_vert.Size as usize * std::mem::size_of::<ImDrawVert>();
460 let vb_slice = std::slice::from_raw_parts(draw_vert.Data, draw_vert.Size as usize);
461 buffers.vb.update(vertex_write_offset, vb_slice)?;
462 vertex_write_offset += vb_size_bytes;
463 let draw_index = &(*(*imgui_cmd_list)).IdxBuffer;
465 let ib_size_bytes = draw_index.Size as usize * std::mem::size_of::<ImDrawIdx>();
466 let ib_slice = std::slice::from_raw_parts(draw_index.Data, draw_index.Size as usize);
467 buffers.ib.update(index_write_offset, ib_slice)?;
468 index_write_offset += ib_size_bytes;
469 }
470
471 let l = draw_data.DisplayPos.x;
473 let r = draw_data.DisplayPos.x + draw_data.DisplaySize.x;
474 let t = draw_data.DisplayPos.y;
475 let b = draw_data.DisplayPos.y + draw_data.DisplaySize.y;
476
477 let mvp: [[f32; 4]; 4] = [
478 [2.0 / (r - l), 0.0, 0.0, 0.0],
479 [0.0, 2.0 / (t - b), 0.0, 0.0],
480 [0.0, 0.0, 0.5, 0.0],
481 [(r + l) / (l - r), (t + b) / (b - t), 0.0, 1.0],
482 ];
483
484 let viewport = gfx::Viewport {
485 x: 0.0,
486 y: 0.0,
487 width: draw_data.DisplaySize.x,
488 height: draw_data.DisplaySize.y,
489 min_depth: 0.0,
490 max_depth: 1.0,
491 };
492
493 cmd.begin_event(0xff1fb6c4, "imgui");
494 cmd.set_viewport(&viewport);
495 cmd.set_vertex_buffer(&buffers.vb, 0);
496 cmd.set_index_buffer(&buffers.ib);
497 cmd.set_render_pipeline(pipeline);
498 cmd.push_render_constants(0, 16, 0, &mvp);
499
500 let clip_off = draw_data.DisplayPos;
501 let mut global_vtx_offset = 0;
502 let mut global_idx_offset = 0;
503 for imgui_cmd_list in imgui_cmd_lists {
504 let imgui_cmd_buffer = (**imgui_cmd_list).CmdBuffer;
505 let imgui_cmd_data =
506 std::slice::from_raw_parts(imgui_cmd_buffer.Data, imgui_cmd_buffer.Size as usize);
507 let draw_vert = &(*(*imgui_cmd_list)).VtxBuffer;
508 let draw_index = &(*(*imgui_cmd_list)).IdxBuffer;
509 for cmd_data in imgui_cmd_data.iter().take(imgui_cmd_buffer.Size as usize) {
510 let imgui_cmd = &cmd_data;
511 if imgui_cmd.UserCallback.is_some() {
512 }
514 else {
515 let clip_min_x = imgui_cmd.ClipRect.x - clip_off.x;
516 let clip_min_y = imgui_cmd.ClipRect.y - clip_off.y;
517 let clip_max_x = imgui_cmd.ClipRect.z - clip_off.x;
518 let clip_max_y = imgui_cmd.ClipRect.w - clip_off.y;
519 if clip_max_x < clip_min_x || clip_max_y < clip_min_y {
520 continue;
521 }
522
523 let scissor = gfx::ScissorRect {
524 left: clip_min_x as i32,
525 top: clip_min_y as i32,
526 right: clip_max_x as i32,
527 bottom: clip_max_y as i32,
528 };
529
530 let (srv, heap_id) = to_srv_heap_id(imgui_cmd.TextureId);
531 if heap_id == device.get_shader_heap().get_heap_id() {
532 cmd.set_binding(pipeline, device.get_shader_heap(), 1, srv);
534 }
535 else {
536 for heap in image_heaps {
538 if heap.get_heap_id() == heap_id {
539 cmd.set_binding(pipeline, heap, 1, srv);
540 break;
541 }
542 }
543 }
544
545 cmd.set_scissor_rect(&scissor);
546 cmd.draw_indexed_instanced(
547 imgui_cmd.ElemCount,
548 1,
549 imgui_cmd.IdxOffset + global_idx_offset,
550 (imgui_cmd.VtxOffset + global_vtx_offset) as i32,
551 0,
552 );
553 }
554 }
555 global_idx_offset += draw_index.Size as u32;
556 global_vtx_offset += draw_vert.Size as u32;
557 }
558 cmd.end_event();
559 }
560 Ok(())
561 }
562}
563
564impl<D, A> ImGui<D, A> where D: Device, A: App, D::RenderPipeline: gfx::Pipeline {
565 fn style_colours_hotline() {
567 unsafe {
568 igStyleColorsDark(std::ptr::null_mut());
569
570 let style = &mut *igGetStyle();
571 style.Colors[ImGuiCol_WindowBg as usize].w = 1.0;
572 style.WindowRounding = 2.0;
573 style.TabRounding = 2.0;
574
575 let colors = &mut style.Colors;
576
577 let hl = [
578 ImVec4{x: 251.0/255.0, y: 211.0/255.0, z: 122.0/255.0, w: 1.0},
580 ImVec4{x: 191.0/255.0, y: 161.0/255.0, z: 93.0/255.0, w: 1.0},
581
582 ImVec4{x: 179.0/255.0, y: 85.0/255.0, z: 149.0/255.0, w: 1.0},
584 ImVec4{x: 131.0/255.0, y: 61.0/255.0, z: 109.0/255.0, w: 1.0},
585 ImVec4{x: 93.0/255.0, y: 50.0/255.0, z: 79.0/255.0, w: 1.0},
586
587 ImVec4{x: 251.0/255.0, y: 180.0/255.0, z: 93.0/255.0, w: 1.0},
589 ];
590
591 let bg = [
592 ImVec4{x: 0.31, y: 0.305, z: 0.30, w: 1.0},
594 ImVec4{x: 0.21, y: 0.205, z: 0.21, w: 1.0},
595 ImVec4{x: 0.15, y: 0.150, z: 0.15, w: 1.0},
596 ImVec4{x: 0.11, y: 0.105, z: 0.10, w: 1.0},
597 ];
598
599 colors[ImGuiCol_WindowBg as usize] = bg[3];
600 colors[ImGuiCol_Header as usize] = hl[3];
601 colors[ImGuiCol_HeaderActive as usize] = hl[1];
602 colors[ImGuiCol_Button as usize] = hl[4];
603 colors[ImGuiCol_ButtonHovered as usize] = hl[1];
604 colors[ImGuiCol_ButtonActive as usize] = hl[0];
605 colors[ImGuiCol_FrameBg as usize] = bg[1];
606 colors[ImGuiCol_FrameBgHovered as usize] = bg[0];
607 colors[ImGuiCol_FrameBgActive as usize] = bg[2];
608 colors[ImGuiCol_Tab as usize] = hl[3];
609 colors[ImGuiCol_TabHovered as usize] = hl[5];
610 colors[ImGuiCol_TabActive as usize] = hl[1];
611 colors[ImGuiCol_TabUnfocused as usize] = bg[2];
612 colors[ImGuiCol_TabUnfocusedActive as usize] = hl[3];
613 colors[ImGuiCol_TitleBg as usize] = bg[2];
614 colors[ImGuiCol_TitleBgActive as usize] = hl[4];
615 colors[ImGuiCol_TitleBgCollapsed as usize] = bg[2];
616
617 colors[ImGuiCol_CheckMark as usize] = hl[1];
619 colors[ImGuiCol_SliderGrab as usize] = hl[1];
620 colors[ImGuiCol_SliderGrabActive as usize] = hl[0];
621 colors[ImGuiCol_HeaderHovered as usize] = hl[1];
622 colors[ImGuiCol_ResizeGrip as usize] = bg[0];
623 colors[ImGuiCol_ResizeGripActive as usize] = hl[0];
624 colors[ImGuiCol_ResizeGripHovered as usize] = hl[1];
625 }
626 }
627
628 pub fn create(info: &mut ImGuiInfo<D, A>) -> Result<Self, super::Error> {
630 unsafe {
631 igCreateContext(std::ptr::null_mut());
632 let io = &mut *igGetIO();
633
634 io.ConfigFlags |= ImGuiConfigFlags_DockingEnable as i32;
635 io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable as i32;
636
637 let exe_path = std::env::current_exe().ok().unwrap();
639 if let Some(parent) = exe_path.parent() {
640 let ini_file = parent.join("imgui.ini");
642 static mut NULL_INI_FILE : Option<CString> = None;
643 NULL_INI_FILE = Some(CString::new(ini_file.to_str().unwrap().to_string()).unwrap());
644 if let Some(i) = &*addr_of!(NULL_INI_FILE) {
645 io.IniFilename = i.as_ptr() as _;
646 }
647 };
648
649 Self::style_colours_hotline();
650
651 let style = &mut *igGetStyle();
652 style.WindowRounding = 0.0;
653 style.Colors[imgui_sys::ImGuiCol_WindowBg as usize].w = 1.0;
654
655 let mut merge = false;
657
658 let mut font_ranges = Vec::new();
659 let mut font_ranges_alloc = Vec::new();
660 let mut font_names = Vec::new();
661
662 for font in &info.fonts {
663 let names_back = font_names.len();
664 font_names.push(CString::new(font.filepath.clone()).unwrap());
665
666 let config = ImFontConfig_ImFontConfig();
667 (*config).MergeMode = merge;
668
669 let null_term_ranges = new_ranges();
671 let mut itr = 0;
672
673 if let Some(ranges) = &font.glyph_ranges {
674 assert!(ranges.len() < MAX_RANGES);
677 for range in ranges {
678 (*null_term_ranges)[itr] = range[0];
679 (*null_term_ranges)[itr+1] = range[1];
680 itr += 2;
681 }
682 }
683 font_ranges.push(null_term_ranges);
684
685 let p_ranges = if font.glyph_ranges.is_some() {
687 null_term_ranges as *mut u32
688 }
689 else {
690 std::ptr::null_mut()
691 };
692 font_ranges_alloc.push(p_ranges);
693
694 ImFontAtlas_AddFontFromFileTTF(
695 io.Fonts,
696 font_names[names_back].as_ptr() as *const i8,
697 16.0,
698 config,
699 p_ranges
700 );
701
702 merge = true;
704 }
705
706 io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard as i32;
707 io.KeyMap[ImGuiKey_Tab as usize] = A::get_key_code(os::Key::Tab);
708 io.KeyMap[ImGuiKey_LeftArrow as usize] = A::get_key_code(os::Key::Left);
709 io.KeyMap[ImGuiKey_RightArrow as usize] =
710 A::get_key_code(os::Key::Right);
711 io.KeyMap[ImGuiKey_UpArrow as usize] = A::get_key_code(os::Key::Up);
712 io.KeyMap[ImGuiKey_DownArrow as usize] = A::get_key_code(os::Key::Down);
713 io.KeyMap[ImGuiKey_PageUp as usize] = A::get_key_code(os::Key::PageUp);
714 io.KeyMap[ImGuiKey_PageDown as usize] =
715 A::get_key_code(os::Key::PageDown);
716 io.KeyMap[ImGuiKey_Home as usize] = A::get_key_code(os::Key::Home);
717 io.KeyMap[ImGuiKey_End as usize] = A::get_key_code(os::Key::End);
718 io.KeyMap[ImGuiKey_Insert as usize] = A::get_key_code(os::Key::Insert);
719 io.KeyMap[ImGuiKey_Delete as usize] = A::get_key_code(os::Key::Delete);
720 io.KeyMap[ImGuiKey_Backspace as usize] =
721 A::get_key_code(os::Key::Backspace);
722 io.KeyMap[ImGuiKey_Space as usize] = A::get_key_code(os::Key::Space);
723 io.KeyMap[ImGuiKey_Enter as usize] = A::get_key_code(os::Key::Enter);
724 io.KeyMap[ImGuiKey_Escape as usize] = A::get_key_code(os::Key::Escape);
725 io.KeyMap[ImGuiKey_KeyPadEnter as usize] =
726 A::get_key_code(os::Key::KeyPadEnter);
727 io.KeyMap[ImGuiKey_A as usize] = 'A' as i32;
728 io.KeyMap[ImGuiKey_C as usize] = 'C' as i32;
729 io.KeyMap[ImGuiKey_V as usize] = 'V' as i32;
730 io.KeyMap[ImGuiKey_X as usize] = 'X' as i32;
731 io.KeyMap[ImGuiKey_Y as usize] = 'Y' as i32;
732 io.KeyMap[ImGuiKey_Z as usize] = 'Z' as i32;
733
734 io.BackendPlatformName = "imgui_impl_hotline".as_ptr() as *const i8;
736 io.BackendFlags |= ImGuiBackendFlags_HasMouseCursors as i32;
737 io.BackendFlags |= ImGuiBackendFlags_HasSetMousePos as i32;
738 io.BackendFlags |= ImGuiBackendFlags_PlatformHasViewports as i32;
739 io.BackendFlags |= ImGuiBackendFlags_HasMouseHoveredViewport as i32;
740
741 io.BackendRendererName = "imgui_impl_hotline".as_ptr() as *const i8;
743 io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset as i32;
744 io.BackendFlags |= ImGuiBackendFlags_RendererHasViewports as i32;
745
746 let mut buffers: Vec<RenderBuffers<D>> = Vec::new();
748 let num_buffers = (*info.swap_chain).get_num_buffers();
749
750 let font_tex = create_fonts_texture::<D>(info.device)?;
751
752 let font_tex_id = to_imgui_texture_id::<D>(&font_tex);
753 ImFontAtlas_SetTexID(io.Fonts, font_tex_id);
754
755 let pipeline = create_render_pipeline(info)?;
756
757 for _i in 0..num_buffers {
758 buffers.push(RenderBuffers {
759 vb: create_vertex_buffer::<D>(info.device, DEFAULT_VB_SIZE)?,
760 vb_size: DEFAULT_VB_SIZE,
761 ib: create_index_buffer::<D>(info.device, DEFAULT_IB_SIZE)?,
762 ib_size: DEFAULT_IB_SIZE,
763 })
764 }
765
766 let mut monitors: Vec<ImGuiPlatformMonitor> = Vec::new();
768
769 let platform_io = &mut *igGetPlatformIO();
770 let os_monitors = A::enumerate_display_monitors();
771 for monitor in os_monitors {
772 let ig_mon = ImGuiPlatformMonitor {
773 MainPos: ImVec2 {
774 x: monitor.rect.x as f32,
775 y: monitor.rect.y as f32,
776 },
777 MainSize: ImVec2 {
778 x: monitor.rect.width as f32,
779 y: monitor.rect.height as f32,
780 },
781 WorkPos: ImVec2 {
782 x: monitor.client_rect.x as f32,
783 y: monitor.client_rect.y as f32,
784 },
785 WorkSize: ImVec2 {
786 x: monitor.client_rect.width as f32,
787 y: monitor.client_rect.height as f32,
788 },
789 DpiScale: monitor.dpi_scale,
790 };
791 if monitor.primary {
792 monitors.push(ig_mon)
793 } else {
794 monitors.insert(0, ig_mon)
795 }
796 }
797
798 platform_io.Monitors.Size = monitors.len() as i32;
799 platform_io.Monitors.Capacity = monitors.len() as i32;
800 platform_io.Monitors.Data = new_monitors(&monitors);
801
802 let vps = &mut *igGetMainViewport();
803
804 let vp = new_viewport_data::<D, A>();
806 (*vp).main_viewport = true;
807 vps.PlatformUserData = vp as _;
808 vps.PlatformHandle = new_native_handle::<A>(info.main_window.get_native_handle()) as _;
809
810 let imgui = ImGui {
812 _native_handle: info.main_window.get_native_handle(),
813 _font_texture: font_tex,
814 pipeline,
815 buffers,
816 last_cursor: os::Cursor::None
817 };
818
819 if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable as i32) != 0 {
820 imgui.setup_platform_interface();
821 }
822
823 Ok(imgui)
824 }
825 }
826
827 fn setup_platform_interface(&self) {
828 unsafe {
829 let platform_io = &mut *igGetPlatformIO();
830 platform_io.Platform_CreateWindow = Some(platform_create_window::<D, A>);
832 platform_io.Platform_DestroyWindow = Some(platform_destroy_window::<D, A>);
833 platform_io.Platform_ShowWindow = Some(platform_show_window::<D, A>);
834 platform_io.Platform_SetWindowPos = Some(platform_set_window_pos::<D, A>);
835 platform_io.Platform_SetWindowSize = Some(platform_set_window_size::<D, A>);
836 platform_io.Platform_SetWindowFocus = Some(platform_set_window_focus::<D, A>);
837 platform_io.Platform_GetWindowFocus = Some(platform_get_window_focus::<D, A>);
838 platform_io.Platform_GetWindowMinimized = Some(platform_get_window_minimised::<D, A>);
839 platform_io.Platform_SetWindowTitle = Some(platform_set_window_title::<D, A>);
840 platform_io.Platform_GetWindowDpiScale = Some(platform_get_window_dpi_scale::<D, A>);
841 platform_io.Platform_UpdateWindow = Some(platform_update_window::<D, A>);
842
843 platform_io.Renderer_RenderWindow = Some(renderer_render_window::<D, A>);
845 platform_io.Renderer_SwapBuffers = Some(renderer_swap_buffers::<D, A>);
846
847 ImGuiPlatformIO_Set_Platform_GetWindowPos(platform_io, platform_get_window_pos::<D, A>);
849 ImGuiPlatformIO_Set_Platform_GetWindowSize(platform_io, platform_get_window_size::<D, A>)
850 }
851 }
852
853 pub fn new_frame(
855 &mut self,
856 app: &mut A,
857 main_window: &mut A::Window,
858 device: &mut D,
859 ) {
860 let size = main_window.get_size();
861 unsafe {
862 let io = &mut *igGetIO();
863
864 let mut ud = UserData {
866 device,
867 app,
868 main_window,
869 pipeline: &self.pipeline,
870 image_heaps: &Vec::new()
871 };
872 io.UserData = (&mut ud as *mut UserData<D, A>) as _;
873
874 io.DisplaySize = ImVec2 {
876 x: size.x as f32,
877 y: size.y as f32,
878 };
879
880 if io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable as i32 == 0 {
882 let client_mouse = main_window.get_mouse_client_pos(app.get_mouse_pos());
884 io.MousePos = ImVec2::from(client_mouse);
885 } else {
886 io.MousePos = ImVec2::from(app.get_mouse_pos());
888 }
889
890 let platform_io = &mut *igGetPlatformIO();
892 let num_vp = platform_io.Viewports.Size;
893
894 assert_ne!(platform_io.Viewports.Data, std::ptr::null_mut());
895
896 let viewports = std::slice::from_raw_parts(platform_io.Viewports.Data, num_vp as usize);
897
898 io.MouseHoveredViewport = 0;
900 for vp in viewports {
901 let p_vp = *vp;
902 let vp_ref = &*p_vp;
903 if !vp_ref.PlatformUserData.is_null() {
904 let win = get_viewport_window::<D, A>(p_vp);
905 if win.is_mouse_hovered() && (vp_ref.Flags & ImGuiViewportFlags_NoInputs as i32) == 0 {
906 io.MouseHoveredViewport = vp_ref.ID;
907 }
908 }
909 }
910
911 io.MouseWheel = app.get_mouse_wheel();
913 io.MouseWheelH = app.get_mouse_wheel();
914 io.MouseDown = app.get_mouse_buttons();
915
916 let utf16 = app.get_utf16_input();
918 for u in utf16 {
919 ImGuiIO_AddInputCharacterUTF16(io, u);
920 }
921
922 let keys_down = app.get_keys_down();
924 std::ptr::copy_nonoverlapping(
925 &keys_down as *const bool,
926 &mut io.KeysDown as *mut bool,
927 256,
928 );
929 io.KeyCtrl = app.is_sys_key_down(os::SysKey::Ctrl);
930 io.KeyShift = app.is_sys_key_down(os::SysKey::Shift);
931 io.KeyAlt = app.is_sys_key_down(os::SysKey::Alt);
932
933 let cursor = if io.MouseDrawCursor {
937 to_os_cursor(igGetMouseCursor())
938 } else {
939 os::Cursor::None
940 };
941
942 if self.last_cursor != cursor {
943 self.last_cursor = cursor;
944 app.set_cursor(&self.last_cursor);
945 }
946
947 igNewFrame();
948
949 io.UserData = std::ptr::null_mut();
950 }
951 }
952
953 pub fn add_main_dock(&mut self, status_bar_height: f32) {
956 unsafe {
957 let main_viewport = &*igGetMainViewport();
959
960 let size = ImVec2 {
961 x: main_viewport.Size.x,
962 y: main_viewport.Size.y - status_bar_height
963 };
964
965 igSetNextWindowPos(main_viewport.Pos, 0, IMVEC2_ZERO);
966 igSetNextWindowSize(size, 0);
967 igSetNextWindowViewport(main_viewport.ID);
968
969 igPushStyleVarFloat(ImGuiStyleVar_WindowRounding as i32, 0.0);
970 igPushStyleVarFloat(ImGuiStyleVar_WindowBorderSize as i32, 0.0);
971 igPushStyleVarVec2(ImGuiStyleVar_WindowPadding as i32, IMVEC2_ZERO);
972
973 let dockspace_name = "main_window_dockspace\0".as_ptr() as *const i8;
974
975 let mut open = true;
976 igBegin(dockspace_name, &mut open, MAIN_DOCKSPACE_FLAGS as i32);
977
978 let id = igGetIDStr(dockspace_name);
979
980 igDockSpace(id, ImVec2{x: 0.0, y: 0.0}, ImGuiDockNodeFlags_PassthruCentralNode as i32, std::ptr::null_mut());
981
982 igPopStyleVar(3);
983 igEnd();
984
985 igPushStyleVarFloat(ImGuiStyleVar_ChildRounding as i32, 0.0);
987 igPushStyleVarFloat(ImGuiStyleVar_ChildBorderSize as i32, 0.0);
988 igPushStyleVarFloat(ImGuiStyleVar_WindowRounding as i32, 0.0);
989 igPushStyleVarFloat(ImGuiStyleVar_WindowBorderSize as i32, 0.0);
990 igPushStyleVarVec2(ImGuiStyleVar_WindowPadding as i32, IMVEC2_ZERO);
991
992 let window_class = ImGuiWindowClass {
993 DockNodeFlagsOverrideSet: ImGuiDockNodeFlags_NoTabBar,
994 ..Default::default()
995 };
996
997 igSetNextWindowClass(&window_class);
998
999 igBegin(MAIN_DOCK_NAME, std::ptr::null_mut(), 0);
1000
1001 let mut avail = IMVEC2_ZERO;
1002 igGetContentRegionAvail(&mut avail);
1003
1004 igEnd();
1005 igPopStyleVar(5);
1006 }
1007 }
1008
1009 pub fn add_status_bar(&mut self, height: f32) -> f32 {
1013 unsafe {
1014 let status_bar_flags = ImGuiWindowFlags_NoDocking |
1015 ImGuiWindowFlags_NoResize |
1016 ImGuiWindowFlags_NoTitleBar |
1017 ImGuiWindowFlags_NoMove |
1018 ImGuiWindowFlags_NoScrollbar |
1019 ImGuiWindowFlags_NoSavedSettings;
1020
1021 let vp = &*igGetMainViewport();
1022 let style = &*igGetStyle();
1023
1024 igSetNextWindowPos(ImVec2 {x: vp.Pos.x, y: vp.Pos.y + vp.Size.y - height}, 0, IMVEC2_ZERO);
1025 igSetNextWindowSize(ImVec2 {x: vp.Size.x, y: height}, 0);
1026 igPushStyleVarFloat(ImGuiStyleVar_WindowRounding as i32, 0.0);
1027 igPushStyleVarFloat(ImGuiStyleVar_WindowBorderSize as i32, 0.0);
1028 igPushStyleColorVec4(ImGuiCol_WindowBg as i32, style.Colors[ImGuiCol_MenuBarBg as usize]);
1029
1030 igBegin(STATUS_BAR_NAME, std::ptr::null_mut(), status_bar_flags as i32);
1031 igPopStyleColor(1);
1032 igPopStyleVar(2);
1033
1034 let mut actual_size = IMVEC2_ZERO;
1035 igGetWindowSize(&mut actual_size);
1036 let actual_height = actual_size.y;
1037
1038 igEnd();
1039
1040 actual_height
1041 }
1042 }
1043
1044 pub fn get_main_dock_size(&self) -> (f32, f32) {
1046 unsafe {
1047 igBegin(MAIN_DOCK_NAME, std::ptr::null_mut(), 0);
1048 let mut avail = IMVEC2_ZERO;
1049 igGetContentRegionAvail(&mut avail);
1050 igEnd();
1051 (avail.x, avail.y)
1052 }
1053 }
1054
1055 pub fn render(
1058 &mut self,
1059 app: &mut A,
1060 main_window: &mut A::Window,
1061 device: &mut D,
1062 cmd: &mut D::CmdBuf,
1063 image_heaps: &Vec<&D::Heap>,
1064 ) {
1065 unsafe {
1066 let io = &mut *igGetIO();
1067 igRender();
1068
1069 render_draw_data::<D>(
1070 &*igGetDrawData(),
1071 device,
1072 cmd,
1073 image_heaps,
1074 &mut self.buffers,
1075 &self.pipeline,
1076 )
1077 .unwrap();
1078
1079 if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable as i32) != 0 {
1080 let mut ud = UserData {
1082 device,
1083 app,
1084 main_window,
1085 pipeline: &self.pipeline,
1086 image_heaps
1087 };
1088 io.UserData = (&mut ud as *mut UserData<D, A>) as _;
1089
1090 igUpdatePlatformWindows();
1091 igRenderPlatformWindowsDefault(std::ptr::null_mut(), std::ptr::null_mut());
1092
1093 io.UserData = std::ptr::null_mut();
1094 }
1095 }
1096 }
1097
1098 pub fn demo(&self) {
1100 unsafe {
1101 static mut SHOW_DEMO_WINDOW: bool = true;
1102 static mut SHOW_ANOTHER_WINDOW: bool = true;
1103 static mut CLEAR_COLOUR: [f32; 3] = [0.0, 0.0, 0.0];
1104
1105 let io = &mut *igGetIO();
1106
1107 if SHOW_DEMO_WINDOW {
1108 igShowDemoWindow(static_ref_mut!(SHOW_DEMO_WINDOW));
1109 }
1110
1111 {
1113 static mut SLIDER_FLOAT: f32 = 0.0;
1114 static mut COUNTER: i32 = 0;
1115
1116 let mut open = true;
1117
1118 igBegin(
1120 "Hello, world!\0".as_ptr() as *const i8,
1121 &mut open,
1122 ImGuiWindowFlags_None as i32,
1123 );
1124
1125 igText(
1126 "%s\0".as_ptr() as *const i8,
1127 "This is some useful text.\0".as_ptr() as *const i8,
1128 );
1129
1130 igCheckbox("Demo Window\0".as_ptr() as *const i8, static_ref_mut!(SHOW_DEMO_WINDOW));
1131 igCheckbox("Another Window\0".as_ptr() as *const i8, static_ref_mut!(SHOW_ANOTHER_WINDOW));
1132
1133 igText(
1134 "%f, %f : %f %f\0".as_ptr() as *const i8,
1135 io.MousePos.x as f64,
1136 io.MousePos.y as f64,
1137 io.DisplaySize.x as f64,
1138 io.DisplaySize.y as f64,
1139 );
1140
1141 igSliderFloat(
1142 "float\0".as_ptr() as _,
1143 static_ref_mut!(SLIDER_FLOAT),
1144 0.0,
1145 1.0,
1146 "%.3f\0".as_ptr() as _,
1147 0,
1148 );
1149
1150 if igButton("Button\0".as_ptr() as _, ImVec2 { x: 0.0, y: 0.0 }) {
1151 COUNTER += 1;
1152 }
1153
1154 igSameLine(0.0, -1.0);
1155
1156 igText(
1157 "counter = %i\0".as_ptr() as *const i8,
1158 "This is some useful text.\0".as_ptr() as *const i8,
1159 );
1160
1161 igColorEdit3("clear color\0".as_ptr() as _, CLEAR_COLOUR.as_mut_ptr(), 0); igText(
1164 "Application average %.3f ms/frame (%.1f FPS)\0".as_ptr() as _,
1165 1000.0 / io.Framerate as f64,
1166 io.Framerate as f64,
1167 );
1168
1169 igEnd();
1170 }
1171
1172 if SHOW_ANOTHER_WINDOW {
1174 igBegin(
1175 "Another Window\0".as_ptr() as *const i8,
1176 static_ref_mut!(SHOW_ANOTHER_WINDOW),
1177 ImGuiWindowFlags_None as i32,
1178 );
1179
1180 igText(
1181 "%s\0".as_ptr() as *const i8,
1182 "Hello from another window!\0".as_ptr() as *const i8,
1183 );
1184
1185 if igButton("Close Me\0".as_ptr() as _, ImVec2 { x: 0.0, y: 0.0 }) {
1186 SHOW_ANOTHER_WINDOW = false;
1187 }
1188
1189 igEnd();
1190 }
1191 }
1192 }
1193
1194 pub fn get_current_context(&self) ->*mut core::ffi::c_void {
1196 unsafe {
1197 igGetCurrentContext() as *mut core::ffi::c_void
1198 }
1199 }
1200
1201 pub fn set_current_context(&mut self, context: *mut core::ffi::c_void) {
1203 unsafe {
1204 igSetCurrentContext(context as *mut ImGuiContext);
1205 }
1206 }
1207
1208 pub fn begin(&mut self, title: &str, open: &mut bool, flags: WindowFlags) -> bool {
1210 unsafe {
1211 let null_title = CString::new(title).unwrap();
1212 igBegin(
1213 null_title.as_ptr() as *const i8,
1214 open as *mut bool,
1215 i32::from(flags),
1216 )
1217 }
1218 }
1219
1220 pub fn begin_window(&mut self, name: &str) -> bool {
1222 unsafe {
1223 let null_name = CString::new(name).unwrap();
1224 igBegin(
1225 null_name.as_ptr() as *const i8,
1226 std::ptr::null_mut(),
1227 0
1228 )
1229 }
1230 }
1231
1232 pub fn end(&mut self) {
1234 unsafe {
1235 igEnd();
1236 };
1237 }
1238
1239 pub fn text(&mut self, text: &str) {
1241 let null_term_text = CString::new(text).unwrap();
1242 unsafe {
1243 igText(null_term_text.as_ptr() as *const i8);
1244 }
1245 }
1246
1247 pub fn colour_text(&mut self, text: &str, col: Vec4f) {
1249 unsafe {
1250 igPushStyleColorVec4(ImGuiCol_Text as i32, to_im_vec4(col));
1251 self.text(text);
1252 igPopStyleColor(1);
1253 }
1254 }
1255
1256 pub fn push_style_colour(&mut self, flags: ImGuiStyleVar, col: Vec4f) {
1258 unsafe {
1259 igPushStyleColorVec4(flags, to_im_vec4(col))
1260 }
1261 }
1262
1263 pub fn pop_style_colour(&mut self) {
1265 unsafe {
1266 igPopStyleColor(1);
1267 }
1268 }
1269
1270 pub fn pop_style_colour_count(&mut self, count: i32) {
1272 unsafe {
1273 igPopStyleColor(count);
1274 }
1275 }
1276
1277 pub fn begin_main_menu_bar(&mut self) -> bool {
1279 unsafe {
1280 igBeginMainMenuBar()
1281 }
1282 }
1283
1284 pub fn end_main_menu_bar(&mut self) {
1286 unsafe {
1287 igEndMainMenuBar()
1288 }
1289 }
1290
1291 pub fn begin_menu(&mut self, label: &str) -> bool {
1293 let null_term_label = CString::new(label).unwrap();
1294 unsafe {
1295 igBeginMenu(null_term_label.as_ptr() as *const i8, true)
1296 }
1297 }
1298
1299 pub fn end_menu(&mut self) {
1301 unsafe {
1302 igEndMenu()
1303 }
1304 }
1305
1306 pub fn begin_combo(&mut self, label: &str, preview_item: &str, flags: ImGuiComboFlags) -> bool {
1308 unsafe {
1309 let null_term_label = CString::new(label).unwrap();
1310 let null_term_preview_item = CString::new(preview_item).unwrap();
1311 igBeginCombo(
1312 null_term_label.as_ptr() as *const i8,
1313 null_term_preview_item.as_ptr() as *const i8,
1314 flags
1315 )
1316 }
1317 }
1318
1319 pub fn end_combo(&mut self) {
1321 unsafe {
1322 igEndCombo()
1323 }
1324 }
1325
1326 pub fn selectable(&mut self, label: &str, selected: bool, flags: ImGuiSelectableFlags) -> bool {
1328 unsafe {
1329 let null_term_label = CString::new(label).unwrap();
1330 igSelectableBool(null_term_label.as_ptr() as *const i8, selected, flags, ImVec2 { x: 0.0, y: 0.0 })
1331 }
1332 }
1333
1334 pub fn combo_list(&mut self, label: &str, items: &Vec<String>, selected: &str) -> (bool, String) {
1336 let mut result = selected.to_string();
1337 if self.begin_combo(label, selected, ImGuiComboFlags_None as i32) {
1338 for item in items {
1339 if self.selectable(item, item == selected, ImGuiSelectableFlags_None as i32) {
1340 result = item.to_string();
1341 }
1342 }
1343 self.end_combo();
1344 (true, result)
1345 }
1346 else {
1347 (false, result)
1348 }
1349 }
1350
1351 pub fn menu_item(&mut self, label: &str) -> bool {
1353 let null_term_label = CString::new(label).unwrap();
1354 unsafe {
1355 igMenuItemBool(
1356 null_term_label.as_ptr() as *const i8,
1357 std::ptr::null(),
1358 false,
1359 true)
1360 }
1361 }
1362
1363 pub fn separator(&mut self) {
1365 unsafe {
1366 igSeparator()
1367 }
1368 }
1369
1370 pub fn spacing(&mut self) {
1372 unsafe {
1373 igSpacing()
1374 }
1375 }
1376
1377 pub fn same_line(&mut self) {
1379 unsafe {
1380 igSameLine(0.0, -1.0);
1381 };
1382 }
1383
1384 pub fn button(&mut self, label: &str) -> bool {
1386 unsafe {
1387 let null_label = CString::new(label).unwrap();
1388 igButton(null_label.as_ptr() as *const i8, ImVec2{x: 0.0, y: 0.0})
1389 }
1390 }
1391
1392 pub fn button_size(&mut self, label: &str, w: f32, h: f32) -> bool {
1394 unsafe {
1395 let null_label = CString::new(label).unwrap();
1396 igButton(null_label.as_ptr() as *const i8, ImVec2{x: w, y: h})
1397 }
1398 }
1399
1400 pub fn checkbox(&mut self, label: &str, v: &mut bool) -> bool {
1403 unsafe {
1404 let null_label = CString::new(label).unwrap();
1405 igCheckbox(null_label.as_ptr() as *const i8, v)
1406 }
1407 }
1408
1409 pub fn input_float(&mut self, label: &str, v: &mut f32) -> bool {
1411 unsafe {
1412 let null_label = CString::new(label).unwrap();
1413 let fmt = CString::new("%.3f").unwrap();
1414 igInputFloat(
1415 null_label.as_ptr() as *const i8, v, 0.0, 0.0, fmt.as_ptr() as *const i8, 0)
1416 }
1417 }
1418
1419 pub fn input_int(&mut self, label: &str, v: &mut i32) -> bool {
1421 unsafe {
1422 let null_label = CString::new(label).unwrap();
1423 igInputInt(
1424 null_label.as_ptr() as *const i8, v, 0, 0, 0)
1425 }
1426 }
1427
1428 pub fn slider_float(&mut self, label: &str, v: &mut f32, min: f32, max: f32) -> bool {
1430 unsafe {
1431 let null_label = CString::new(label).unwrap();
1432 let fmt = CString::new("%.3f").unwrap();
1433 igSliderFloat(
1434 null_label.as_ptr() as *const i8, v, min, max, fmt.as_ptr() as *const i8, 0)
1435 }
1436 }
1437
1438 pub fn dummy(&mut self, w: f32, h: f32) {
1440 unsafe {
1441 igDummy(ImVec2 {x: w, y: h})
1442 }
1443 }
1444
1445 pub fn hdummy(&mut self, size: f32) {
1447 unsafe {
1448 igDummy(ImVec2 {x: size, y: 0.0})
1449 }
1450 }
1451
1452 pub fn vdummy(&mut self, size: f32) {
1454 unsafe {
1455 igDummy(ImVec2 {x: 0.0, y: size})
1456 }
1457 }
1458
1459 pub fn image(&mut self, tex: &D::Texture, w: f32, h: f32) {
1461 unsafe {
1462 let id = to_imgui_texture_id::<D>(tex);
1463 igImage(
1464 id,
1465 ImVec2 {x: w, y: h},
1466 ImVec2 {x: 0.0, y: 0.0},
1467 ImVec2 {x: 1.0, y: 1.0},
1468 ImVec4 {x: 1.0, y: 1.0, z: 1.0, w: 1.0},
1469 ImVec4 {x: 0.0, y: 0.0, z: 0.0, w: 0.0},
1470 );
1471 }
1472 }
1473
1474 pub fn calc_text_size(&self, text: &str) -> (f32, f32) {
1476 let null_text = CString::new(text).unwrap();
1477 let mut size = IMVEC2_ZERO;
1478 unsafe {
1479 igCalcTextSize(&mut size, null_text.as_ptr() as *const i8, std::ptr::null(), false, -1.0);
1480 }
1481 (size.x, size.y)
1482 }
1483
1484 pub fn right_align(&mut self, offset: f32) {
1486 unsafe {
1487 let mut size = IMVEC2_ZERO;
1488 igGetWindowSize(&mut size);
1489 igSetCursorPosX(size.x - offset);
1490 }
1491 }
1492
1493 pub fn image_window(&mut self, label: &str, tex: &D::Texture) {
1495 unsafe {
1496 let null_label = CString::new(label).unwrap();
1497
1498 let (w, h) = self.get_main_dock_size();
1499
1500 let id = to_imgui_texture_id::<D>(tex);
1501
1502 igBegin(null_label.as_ptr() as *const i8, std::ptr::null_mut(), 0);
1503
1504 igImage(
1505 id,
1506 ImVec2 {x: w, y: h},
1507 ImVec2 {x: 0.0, y: 0.0},
1508 ImVec2 {x: 1.0, y: 1.0},
1509 ImVec4 {x: 1.0, y: 1.0, z: 1.0, w: 1.0},
1510 ImVec4 {x: 0.0, y: 0.0, z: 0.0, w: 0.0},
1511 );
1512
1513 igEnd();
1514 }
1515 }
1516
1517 pub fn set_next_item_width(&mut self, item_width: f32) {
1519 unsafe {
1520 igSetNextItemWidth(item_width);
1521 }
1522 }
1523
1524 pub fn main_dock_hovered(&self) -> bool {
1526 unsafe {
1527 igBegin(MAIN_DOCK_NAME, std::ptr::null_mut(), 0);
1528 let result = igIsWindowHovered(0);
1529 igEnd();
1530 result
1531 }
1532 }
1533
1534 pub fn want_capture_keyboard(&self) -> bool {
1536 unsafe {
1537 let io = &mut *igGetIO();
1538 io.WantCaptureKeyboard
1539 }
1540 }
1541
1542 pub fn want_capture_mouse(&self) -> bool {
1544 unsafe {
1545 let io = &mut *igGetIO();
1546 io.WantCaptureMouse
1547 }
1548 }
1549
1550 pub fn save_ini_settings(&self) {
1552 unsafe {
1553 let io = &mut *igGetIO();
1554 igSaveIniSettingsToDisk(io.IniFilename);
1555 }
1556 }
1557
1558 pub fn save_ini_settings_to_location(&self, path: &str) {
1560 unsafe {
1561 let null_term_filename = CString::new(format!("{}/imgui.ini", path)).unwrap();
1562 igSaveIniSettingsToDisk(null_term_filename.as_ptr() as *const i8);
1563 }
1564 }
1565}
1566
1567impl<D, A> Drop for ImGui<D, A> where D: Device, A: App {
1568 fn drop(&mut self) {
1569 unsafe {
1570 igDestroyPlatformWindows();
1571 let platform_io = &mut *igGetPlatformIO();
1572 std::ptr::drop_in_place(platform_io.Monitors.Data as *mut ImGuiPlatformMonitor);
1573 platform_io.Monitors.Data = std::ptr::null_mut();
1574 }
1575 }
1576}
1577
1578impl From<os::Point<i32>> for ImVec2 {
1579 fn from(point: os::Point<i32>) -> ImVec2 {
1580 ImVec2 {
1581 x: point.x as f32,
1582 y: point.y as f32,
1583 }
1584 }
1585}
1586
1587impl From<ImVec2> for os::Point<i32> {
1588 fn from(vec2: ImVec2) -> os::Point<i32> {
1589 os::Point {
1590 x: vec2.x as i32,
1591 y: vec2.y as i32,
1592 }
1593 }
1594}
1595
1596fn get_viewport_window<'a, D: Device, A: App>(vp: *mut ImGuiViewport) -> &'a mut A::Window {
1599 unsafe {
1600 let vp_ref = &mut *vp;
1601 let vd = &mut *(vp_ref.PlatformUserData as *mut ViewportData<D, A>);
1602 if vd.main_viewport {
1603 let io = &mut *igGetIO();
1604 let ud = &mut *(io.UserData as *mut UserData<D, A>);
1605 return ud.main_window;
1606 }
1607 &mut vd.window[0]
1608 }
1609}
1610
1611fn get_viewport_data<'a, D: Device, A: App>(vp: *mut ImGuiViewport) -> &'a mut ViewportData<D, A> {
1613 unsafe {
1614 let vp_ref = &mut *vp;
1615 &mut *(vp_ref.PlatformUserData as *mut ViewportData<D, A>)
1616 }
1617}
1618
1619fn get_user_data<'a, D: Device, A: App>() -> &'a mut UserData<'a, D, A> {
1621 unsafe {
1622 let io = &mut *igGetIO();
1623 &mut *(io.UserData as *mut UserData<D, A>)
1624 }
1625}
1626
1627unsafe extern "C" fn platform_create_window<D: Device, A: App>(vp: *mut ImGuiViewport) {
1628 let io = &mut *igGetIO();
1629 let ud = &mut *(io.UserData as *mut UserData<D, A>);
1630 let device = &mut ud.device;
1631 let vp_ref = &mut *vp;
1632
1633 let p_vd = new_viewport_data::<D, A>();
1635 let vd = &mut *p_vd;
1636
1637 let mut parent_handle = None;
1639 if vp_ref.ParentViewportId != 0 {
1640 let parent = &*igFindViewportByID(vp_ref.ParentViewportId);
1641 let nh = &*(parent.PlatformHandle as *mut A::NativeHandle);
1642 parent_handle = Some(nh.copy());
1643 }
1644
1645 vd.window = vec![ud.app.create_window(os::WindowInfo {
1647 title: String::from("Utitled"),
1648 rect: os::Rect {
1649 x: vp_ref.Pos.x as i32,
1650 y: vp_ref.Pos.y as i32,
1651 width: vp_ref.Size.x as i32,
1652 height: vp_ref.Size.y as i32,
1653 },
1654 style: os::WindowStyleFlags::from(vp_ref.Flags),
1655 parent_handle,
1656 })];
1657
1658 vd.cmd = vec![device.create_cmd_buf(2)];
1660
1661 let swap_chain_info = gfx::SwapChainInfo {
1663 num_buffers: 2,
1664 format: gfx::Format::RGBA8n,
1665 clear_colour: Some(gfx::ClearColour {
1666 r: 0.45,
1667 g: 0.55,
1668 b: 0.60,
1669 a: 1.00,
1670 }),
1671 };
1672 vd.swap_chain = vec![device.create_swap_chain::<A>(&swap_chain_info, &vd.window[0]).unwrap()];
1673
1674 let mut buffers: Vec<RenderBuffers<D>> = Vec::new();
1676 let num_buffers = vd.swap_chain[0].get_num_buffers();
1677 for _i in 0..num_buffers {
1678 buffers.push(RenderBuffers {
1679 vb: create_vertex_buffer::<D>(device, DEFAULT_VB_SIZE).unwrap(),
1680 vb_size: DEFAULT_VB_SIZE,
1681 ib: create_index_buffer::<D>(device, DEFAULT_IB_SIZE).unwrap(),
1682 ib_size: DEFAULT_IB_SIZE,
1683 })
1684 }
1685 vd.buffers = buffers;
1686
1687 vp_ref.PlatformUserData = p_vd as *mut _;
1689 vp_ref.PlatformRequestResize = false;
1690 vp_ref.PlatformHandle = new_native_handle::<A>(vd.window[0].get_native_handle()) as _;
1691}
1692
1693unsafe extern "C" fn platform_destroy_window<D: Device, A: App>(vp: *mut ImGuiViewport) {
1694 let vd = get_viewport_data::<D, A>(vp);
1695 let vp_ref = &mut *vp;
1696
1697 if !vd.swap_chain.is_empty() {
1698 vd.swap_chain[0].wait_for_last_frame();
1699 vd.cmd[0].reset(&vd.swap_chain[0]);
1700 }
1701
1702 let io = &mut *igGetIO();
1704 if !io.UserData.is_null() {
1705 get_user_data::<D, A>().app.destroy_window(&vd.window[0]);
1706 }
1707
1708 if !vd.swap_chain.is_empty() {
1709 vd.swap_chain.clear();
1710 }
1711
1712 if !vd.cmd.is_empty() {
1713 vd.cmd.clear();
1714 }
1715
1716 if !vd.buffers.is_empty() {
1717 vd.buffers.clear();
1718 }
1719
1720 if !vd.window.is_empty() {
1721 vd.window.clear();
1722 }
1723
1724 std::ptr::drop_in_place(vp_ref.PlatformUserData as *mut ViewportData<D, A>);
1726 vp_ref.PlatformUserData = std::ptr::null_mut();
1727 std::ptr::drop_in_place(vp_ref.PlatformHandle as *mut A::NativeHandle);
1728 vp_ref.PlatformHandle = std::ptr::null_mut();
1729}
1730
1731unsafe extern "C" fn platform_update_window<D: Device, A: App>(vp: *mut ImGuiViewport) {
1732 let window = get_viewport_window::<D, A>(vp);
1733 let vp_ref = &mut *vp;
1734 window.update(get_user_data::<D, A>().app);
1735 window.update_style(
1736 os::WindowStyleFlags::from(vp_ref.Flags),
1737 os::Rect {
1738 x: vp_ref.Pos.x as i32,
1739 y: vp_ref.Pos.y as i32,
1740 width: vp_ref.Size.x as i32,
1741 height: vp_ref.Size.y as i32,
1742 },
1743 );
1744 let events = window.get_events();
1745 if events.contains(os::WindowEventFlags::CLOSE) {
1746 vp_ref.PlatformRequestClose = true;
1747 }
1748 if events.contains(os::WindowEventFlags::MOVE) {
1749 vp_ref.PlatformRequestMove = true;
1750 }
1751 if events.contains(os::WindowEventFlags::SIZE) {
1752 vp_ref.PlatformRequestResize = true;
1753 }
1754 window.clear_events();
1755}
1756
1757unsafe extern "C" fn platform_get_window_pos<D: Device, A: App>(vp: *mut ImGuiViewport, out_pos: *mut ImVec2) {
1758 let window = get_viewport_window::<D, A>(vp);
1759 let pos = window.get_pos();
1760 (*out_pos).x = pos.x as f32;
1761 (*out_pos).y = pos.y as f32;
1762}
1763
1764unsafe extern "C" fn platform_get_window_size<D: Device, A: App>(vp: *mut ImGuiViewport, out_size: *mut ImVec2) {
1765 let window = get_viewport_window::<D, A>(vp);
1766 let size = window.get_size();
1767 (*out_size).x = size.x as f32;
1768 (*out_size).y = size.y as f32;
1769}
1770
1771unsafe extern "C" fn platform_show_window<D: Device, A: App>(vp: *mut ImGuiViewport) {
1772 let window = get_viewport_window::<D, A>(vp);
1773 let activate = (*vp).Flags & ImGuiViewportFlags_NoFocusOnAppearing as i32 == 0;
1774 window.show(true, activate);
1775}
1776
1777unsafe extern "C" fn platform_set_window_title<D: Device, A: App>(vp: *mut ImGuiViewport, str_: *const cty::c_char) {
1778 let win = get_viewport_window::<D, A>(vp);
1779 let cstr = CStr::from_ptr(str_);
1780 win.set_title(String::from(cstr.to_str().unwrap()));
1781}
1782
1783unsafe extern "C" fn platform_set_window_focus<D: Device, A: App>(vp: *mut ImGuiViewport) {
1784 let window = get_viewport_window::<D, A>(vp);
1785 window.set_focused();
1786}
1787
1788unsafe extern "C" fn platform_get_window_focus<D: Device, A: App>(vp: *mut ImGuiViewport) -> bool {
1789 let window = get_viewport_window::<D, A>(vp);
1790 window.is_focused()
1791}
1792
1793unsafe extern "C" fn platform_set_window_pos<D: Device, A: App>(vp: *mut ImGuiViewport, pos: ImVec2) {
1794 let window = get_viewport_window::<D, A>(vp);
1795 window.set_pos(os::Point::from(pos));
1796}
1797
1798unsafe extern "C" fn platform_set_window_size<D: Device, A: App>(vp: *mut ImGuiViewport, size: ImVec2) {
1799 let window = get_viewport_window::<D, A>(vp);
1800 window.set_size(os::Size::from(size));
1801}
1802
1803unsafe extern "C" fn platform_get_window_minimised<D: Device, A: App>(vp: *mut ImGuiViewport) -> bool {
1804 let window = get_viewport_window::<D, A>(vp);
1805 window.is_minimised()
1806}
1807
1808unsafe extern "C" fn platform_get_window_dpi_scale<D: Device, A: App>(vp: *mut ImGuiViewport) -> f32 {
1809 let window = get_viewport_window::<D, A>(vp);
1810 window.get_dpi_scale()
1811}
1812
1813unsafe extern "C" fn renderer_render_window<D: Device, A: App>(vp: *mut ImGuiViewport, _render_arg: *mut cty::c_void) where D::RenderPipeline: gfx::Pipeline {
1814 let ud = get_user_data::<D, A>();
1815 let vd = get_viewport_data::<D, A>(vp);
1816 let vp_ref = &*vp;
1817
1818 assert_ne!(vd.window.len(), 0);
1820 assert_ne!(vd.cmd.len(), 0);
1821 assert_ne!(vd.swap_chain.len(), 0);
1822
1823 let window = &mut vd.window[0];
1825 let cmd = &mut vd.cmd[0];
1826 let swap = &mut vd.swap_chain[0];
1827 let vp_rect = window.get_viewport_rect();
1828
1829 window.update(ud.app);
1831 swap.update::<A>(ud.device, window, cmd);
1832 cmd.reset(swap);
1833
1834 let viewport = gfx::Viewport::from(vp_rect);
1836 let scissor = gfx::ScissorRect::from(vp_rect);
1837
1838 cmd.transition_barrier(&gfx::TransitionBarrier {
1840 texture: Some(swap.get_backbuffer_texture()),
1841 buffer: None,
1842 state_before: gfx::ResourceState::Present,
1843 state_after: gfx::ResourceState::RenderTarget,
1844 });
1845
1846 let pass = swap.get_backbuffer_pass_mut();
1847 cmd.begin_render_pass(pass);
1848
1849 cmd.set_viewport(&viewport);
1850 cmd.set_scissor_rect(&scissor);
1851
1852 render_draw_data::<D>(
1853 &*vp_ref.DrawData,
1854 ud.device,
1855 cmd,
1856 ud.image_heaps,
1857 &mut vd.buffers,
1858 ud.pipeline,
1859 )
1860 .unwrap();
1861
1862 cmd.end_render_pass();
1863
1864 cmd.transition_barrier(&gfx::TransitionBarrier {
1866 texture: Some(swap.get_backbuffer_texture()),
1867 buffer: None,
1868 state_before: gfx::ResourceState::RenderTarget,
1869 state_after: gfx::ResourceState::Present,
1870 });
1871
1872 cmd.close().unwrap();
1873
1874 ud.device.execute(cmd);
1875}
1876
1877unsafe extern "C" fn renderer_swap_buffers<D: Device, A: App>(vp: *mut ImGuiViewport, _render_arg: *mut cty::c_void) {
1878 let ud = get_user_data::<D, A>();
1879 let vd = get_viewport_data::<D, A>(vp);
1880 assert_ne!(vd.swap_chain.len(), 0);
1881 vd.swap_chain[0].swap(ud.device);
1882}
1883
1884pub type WindowSizeCallback = unsafe extern "C" fn(vp: *mut ImGuiViewport, out_pos: *mut ImVec2);
1885
1886extern "C" {
1887 pub fn ImGuiPlatformIO_Set_Platform_GetWindowPos(
1888 platform_io: *mut ImGuiPlatformIO,
1889 function: WindowSizeCallback,
1890 );
1891
1892 pub fn ImGuiPlatformIO_Set_Platform_GetWindowSize(
1893 platform_io: *mut ImGuiPlatformIO,
1894 function: WindowSizeCallback,
1895 );
1896}
1897
1898impl From<ImGuiViewportFlags> for os::WindowStyleFlags {
1899 fn from(flags: ImGuiViewportFlags) -> os::WindowStyleFlags {
1900 let mut style = os::WindowStyleFlags::IMGUI;
1901 if (flags & ImGuiViewportFlags_NoDecoration as i32) != 0 {
1902 style |= os::WindowStyleFlags::POPUP;
1903 } else {
1904 style |= os::WindowStyleFlags::OVERLAPPED_WINDOW;
1905 }
1906 if (flags & ImGuiViewportFlags_NoTaskBarIcon as i32) != 0 {
1907 style |= os::WindowStyleFlags::TOOL_WINDOW;
1908 } else {
1909 style |= os::WindowStyleFlags::APP_WINDOW;
1910 }
1911 if (flags & ImGuiViewportFlags_TopMost as i32) != 0 {
1912 style |= os::WindowStyleFlags::TOPMOST;
1913 }
1914 style
1915 }
1916}
1917
1918#[allow(non_upper_case_globals)]
1919const fn to_os_cursor(cursor: ImGuiMouseCursor) -> os::Cursor {
1920 match cursor {
1921 ImGuiMouseCursor_Arrow => os::Cursor::Arrow,
1922 ImGuiMouseCursor_TextInput => os::Cursor::TextInput,
1923 ImGuiMouseCursor_ResizeAll => os::Cursor::ResizeAll,
1924 ImGuiMouseCursor_ResizeEW => os::Cursor::ResizeEW,
1925 ImGuiMouseCursor_ResizeNS => os::Cursor::ResizeNS,
1926 ImGuiMouseCursor_ResizeNESW => os::Cursor::ResizeNESW,
1927 ImGuiMouseCursor_ResizeNWSE => os::Cursor::ResizeNWSE,
1928 ImGuiMouseCursor_Hand => os::Cursor::Hand,
1929 ImGuiMouseCursor_NotAllowed => os::Cursor::NotAllowed,
1930 _ => os::Cursor::None,
1931 }
1932}