#[cfg(feature = "opengl3-renderer")]
use std::ffi::CString;
use std::ffi::c_void;
use dear_imgui_rs::Context;
#[cfg(any(feature = "opengl3-renderer", feature = "sdlrenderer3-renderer"))]
use dear_imgui_rs::{TextureData, render::DrawData};
#[cfg(any(feature = "opengl3-renderer", feature = "sdlrenderer3-renderer"))]
use dear_imgui_sys as sys;
#[cfg(feature = "opengl3-renderer")]
use dear_imgui_sys::backend_shim::opengl3 as opengl3_backend;
#[cfg(feature = "sdlrenderer3-renderer")]
use dear_imgui_sys::backend_shim::sdlrenderer3 as sdlrenderer3_backend;
#[cfg(feature = "sdlrenderer3-renderer")]
use sdl3::render::WindowCanvas;
use sdl3::video::{GLContext, Window};
use sdl3_sys::events::SDL_Event;
mod ffi {
use super::*;
unsafe extern "C" {
pub fn ImGui_ImplSDL3_InitForOpenGL_Rust(
window: *mut sdl3_sys::video::SDL_Window,
sdl_gl_context: *mut c_void,
) -> bool;
pub fn ImGui_ImplSDL3_InitForVulkan_Rust(window: *mut sdl3_sys::video::SDL_Window) -> bool;
pub fn ImGui_ImplSDL3_InitForD3D_Rust(window: *mut sdl3_sys::video::SDL_Window) -> bool;
pub fn ImGui_ImplSDL3_InitForMetal_Rust(window: *mut sdl3_sys::video::SDL_Window) -> bool;
pub fn ImGui_ImplSDL3_InitForSDLRenderer_Rust(
window: *mut sdl3_sys::video::SDL_Window,
renderer: *mut sdl3_sys::render::SDL_Renderer,
) -> bool;
pub fn ImGui_ImplSDL3_InitForSDLGPU_Rust(window: *mut sdl3_sys::video::SDL_Window) -> bool;
pub fn ImGui_ImplSDL3_InitForOther_Rust(window: *mut sdl3_sys::video::SDL_Window) -> bool;
pub fn ImGui_ImplSDL3_Shutdown_Rust();
pub fn ImGui_ImplSDL3_NewFrame_Rust();
pub fn ImGui_ImplSDL3_ProcessEvent_Rust(event: *const SDL_Event) -> bool;
pub fn ImGui_ImplSDL3_SetGamepadMode_AutoFirst_Rust();
pub fn ImGui_ImplSDL3_SetGamepadMode_AutoAll_Rust();
pub fn ImGui_ImplSDL3_SetGamepadMode_Manual_Rust(
manual_gamepads_array: *const *mut sdl3_sys::gamepad::SDL_Gamepad,
manual_gamepads_count: i32,
);
}
}
#[derive(Debug, thiserror::Error)]
pub enum Sdl3BackendError {
#[error("ImGui_ImplSDL3_InitForOpenGL returned false")]
Sdl3InitFailed,
#[error("ImGui_ImplOpenGL3_Init returned false")]
OpenGlInitFailed,
#[error("Invalid GLSL version string")]
InvalidGlslVersion,
#[error("ImGui_ImplSDLRenderer3_Init returned false")]
Renderer3InitFailed,
}
#[derive(Copy, Clone, Debug)]
pub enum GamepadMode {
AutoFirst,
AutoAll,
}
pub fn set_gamepad_mode(mode: GamepadMode) {
unsafe {
match mode {
GamepadMode::AutoFirst => ffi::ImGui_ImplSDL3_SetGamepadMode_AutoFirst_Rust(),
GamepadMode::AutoAll => ffi::ImGui_ImplSDL3_SetGamepadMode_AutoAll_Rust(),
}
}
}
pub unsafe fn set_gamepad_mode_manual(gamepads: &[*mut sdl3_sys::gamepad::SDL_Gamepad]) {
unsafe {
ffi::ImGui_ImplSDL3_SetGamepadMode_Manual_Rust(gamepads.as_ptr(), gamepads.len() as i32);
}
}
pub fn enable_native_ime_ui() {
let _ = sdl3::hint::set("SDL_HINT_IME_SHOW_UI", "1");
}
#[cfg(feature = "opengl3-renderer")]
pub fn init_for_opengl(
_imgui: &mut Context,
window: &Window,
gl_context: &GLContext,
glsl_version: &str,
) -> Result<(), Sdl3BackendError> {
let glsl = CString::new(glsl_version).map_err(|_| Sdl3BackendError::InvalidGlslVersion)?;
let sdl_window = window.raw();
let sdl_gl = unsafe { gl_context.raw() };
unsafe {
if !ffi::ImGui_ImplSDL3_InitForOpenGL_Rust(sdl_window, sdl_gl as *mut c_void) {
return Err(Sdl3BackendError::Sdl3InitFailed);
}
if !opengl3_backend::dear_imgui_backend_opengl3_init(glsl.as_ptr()) {
return Err(Sdl3BackendError::OpenGlInitFailed);
}
}
Ok(())
}
#[cfg(feature = "opengl3-renderer")]
pub fn init_for_opengl_default(
_imgui: &mut Context,
window: &Window,
gl_context: &GLContext,
) -> Result<(), Sdl3BackendError> {
let sdl_window = window.raw();
let sdl_gl = unsafe { gl_context.raw() };
unsafe {
if !ffi::ImGui_ImplSDL3_InitForOpenGL_Rust(sdl_window, sdl_gl as *mut c_void) {
return Err(Sdl3BackendError::Sdl3InitFailed);
}
if !opengl3_backend::dear_imgui_backend_opengl3_init(std::ptr::null()) {
return Err(Sdl3BackendError::OpenGlInitFailed);
}
}
Ok(())
}
pub fn init_platform_for_opengl(
_imgui: &mut Context,
window: &Window,
gl_context: &GLContext,
) -> Result<(), Sdl3BackendError> {
let sdl_window = window.raw();
let sdl_gl = unsafe { gl_context.raw() };
unsafe {
if !ffi::ImGui_ImplSDL3_InitForOpenGL_Rust(sdl_window, sdl_gl as *mut c_void) {
return Err(Sdl3BackendError::Sdl3InitFailed);
}
}
Ok(())
}
pub fn init_for_other(_imgui: &mut Context, window: &Window) -> Result<(), Sdl3BackendError> {
let sdl_window = window.raw();
unsafe {
if !ffi::ImGui_ImplSDL3_InitForOther_Rust(sdl_window) {
return Err(Sdl3BackendError::Sdl3InitFailed);
}
}
Ok(())
}
pub fn init_for_vulkan(_imgui: &mut Context, window: &Window) -> Result<(), Sdl3BackendError> {
let sdl_window = window.raw();
unsafe {
if !ffi::ImGui_ImplSDL3_InitForVulkan_Rust(sdl_window) {
return Err(Sdl3BackendError::Sdl3InitFailed);
}
}
Ok(())
}
pub fn init_for_d3d(_imgui: &mut Context, window: &Window) -> Result<(), Sdl3BackendError> {
let sdl_window = window.raw();
unsafe {
if !ffi::ImGui_ImplSDL3_InitForD3D_Rust(sdl_window) {
return Err(Sdl3BackendError::Sdl3InitFailed);
}
}
Ok(())
}
pub fn init_for_metal(_imgui: &mut Context, window: &Window) -> Result<(), Sdl3BackendError> {
let sdl_window = window.raw();
unsafe {
if !ffi::ImGui_ImplSDL3_InitForMetal_Rust(sdl_window) {
return Err(Sdl3BackendError::Sdl3InitFailed);
}
}
Ok(())
}
pub unsafe fn init_for_sdl_renderer(
_imgui: &mut Context,
window: &Window,
renderer: *mut sdl3_sys::render::SDL_Renderer,
) -> Result<(), Sdl3BackendError> {
let sdl_window = window.raw();
unsafe {
if !ffi::ImGui_ImplSDL3_InitForSDLRenderer_Rust(sdl_window, renderer) {
return Err(Sdl3BackendError::Sdl3InitFailed);
}
}
Ok(())
}
pub fn init_for_sdl_gpu(_imgui: &mut Context, window: &Window) -> Result<(), Sdl3BackendError> {
let sdl_window = window.raw();
unsafe {
if !ffi::ImGui_ImplSDL3_InitForSDLGPU_Rust(sdl_window) {
return Err(Sdl3BackendError::Sdl3InitFailed);
}
}
Ok(())
}
#[cfg(feature = "sdlrenderer3-renderer")]
pub fn init_for_canvas(
_imgui: &mut Context,
window: &Window,
canvas: &WindowCanvas,
) -> Result<(), Sdl3BackendError> {
let sdl_window = window.raw();
let sdl_renderer = canvas.raw();
unsafe {
if !ffi::ImGui_ImplSDL3_InitForSDLRenderer_Rust(sdl_window, sdl_renderer) {
return Err(Sdl3BackendError::Sdl3InitFailed);
}
if !sdlrenderer3_backend::dear_imgui_backend_sdlrenderer3_init(
sdl_renderer as *mut std::ffi::c_void,
) {
return Err(Sdl3BackendError::Renderer3InitFailed);
}
}
Ok(())
}
#[cfg(feature = "opengl3-renderer")]
pub fn shutdown_for_opengl(_imgui: &mut Context) {
unsafe {
opengl3_backend::dear_imgui_backend_opengl3_shutdown();
ffi::ImGui_ImplSDL3_Shutdown_Rust();
}
}
pub fn shutdown(_imgui: &mut Context) {
unsafe {
ffi::ImGui_ImplSDL3_Shutdown_Rust();
}
}
#[cfg(feature = "sdlrenderer3-renderer")]
pub fn shutdown_for_canvas(_imgui: &mut Context) {
unsafe {
sdlrenderer3_backend::dear_imgui_backend_sdlrenderer3_shutdown();
ffi::ImGui_ImplSDL3_Shutdown_Rust();
}
}
#[cfg(feature = "opengl3-renderer")]
pub fn new_frame(_imgui: &mut Context) {
unsafe {
opengl3_backend::dear_imgui_backend_opengl3_new_frame();
ffi::ImGui_ImplSDL3_NewFrame_Rust();
}
}
pub fn sdl3_new_frame(_imgui: &mut Context) {
unsafe {
ffi::ImGui_ImplSDL3_NewFrame_Rust();
}
}
#[cfg(feature = "sdlrenderer3-renderer")]
pub fn canvas_new_frame(_imgui: &mut Context) {
unsafe {
sdlrenderer3_backend::dear_imgui_backend_sdlrenderer3_new_frame();
ffi::ImGui_ImplSDL3_NewFrame_Rust();
}
}
pub fn sdl3_poll_event_ll() -> Option<SDL_Event> {
let mut raw = std::mem::MaybeUninit::<SDL_Event>::uninit();
let has_event = unsafe { sdl3_sys::events::SDL_PollEvent(raw.as_mut_ptr()) };
if has_event {
Some(unsafe { raw.assume_init() })
} else {
None
}
}
pub fn process_sys_event(event: &SDL_Event) -> bool {
unsafe { ffi::ImGui_ImplSDL3_ProcessEvent_Rust(event) }
}
#[cfg(feature = "opengl3-renderer")]
pub fn render(draw_data: &DrawData) {
unsafe {
let raw = draw_data as *const DrawData as *const sys::ImDrawData;
opengl3_backend::dear_imgui_backend_opengl3_render_draw_data(raw);
}
}
#[cfg(feature = "sdlrenderer3-renderer")]
pub fn canvas_render(draw_data: &DrawData, canvas: &WindowCanvas) {
let sdl_renderer = canvas.raw();
unsafe {
let raw = draw_data as *const DrawData as *const sys::ImDrawData;
sdlrenderer3_backend::dear_imgui_backend_sdlrenderer3_render_draw_data(
raw,
sdl_renderer as *mut std::ffi::c_void,
);
}
}
#[cfg(feature = "opengl3-renderer")]
pub fn update_texture(tex: &mut TextureData) {
unsafe {
opengl3_backend::dear_imgui_backend_opengl3_update_texture(tex.as_raw_mut());
}
}
#[cfg(feature = "sdlrenderer3-renderer")]
pub fn canvas_update_texture(tex: &mut TextureData) {
unsafe {
sdlrenderer3_backend::dear_imgui_backend_sdlrenderer3_update_texture(tex.as_raw_mut());
}
}
#[cfg(feature = "opengl3-renderer")]
pub fn create_device_objects() -> bool {
unsafe { opengl3_backend::dear_imgui_backend_opengl3_create_device_objects() }
}
#[cfg(feature = "opengl3-renderer")]
pub fn destroy_device_objects() {
unsafe {
opengl3_backend::dear_imgui_backend_opengl3_destroy_device_objects();
}
}
#[cfg(feature = "sdlrenderer3-renderer")]
pub fn canvas_create_device_objects() {
unsafe { sdlrenderer3_backend::dear_imgui_backend_sdlrenderer3_create_device_objects() }
}
#[cfg(feature = "sdlrenderer3-renderer")]
pub fn canvas_destroy_device_objects() {
unsafe {
sdlrenderer3_backend::dear_imgui_backend_sdlrenderer3_destroy_device_objects();
}
}