-
Notifications
You must be signed in to change notification settings - Fork 30
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Feature request: drawing images #57
Comments
Yes, I think that's about right! I have never used images myself but it would indeed be great if we could support those, so thank you for opening this ticket. This should not be a particularly complicated feature, but it would require a good amount of testing, adding texture management to each of the renderers we currently support, and additions to the render loop API. For this reason I'm hesitant to schedule this feature for the upcoming 0.3.0 release, but it will definitely happen at some point! |
I actually tried to cheat at this by importing an image as a bunch of raw bytes, then doing a |
That's clever 😅 But long term I think implementing an API around textures is definitely more desirable. |
I've gotten it working in OpenGL by finding the function addresses of the draw functions needed for OpenGL to upload the texture to the GPU, then just called them and add_image. Might release source soon, probably won't add support for anything but OpenGL though as I have zero experience with other renderers. Reference for this: /~https://github.com/ocornut/imgui/wiki/Image-Loading-and-Displaying-Examples#example-for-opengl-users |
Alright, so here's the code, you'll need the Windows and image crate for it to work. Getting module symbol function: /// Gets the address to a function inside of a module.
pub fn get_module_symbol_address(module: &str, symbol: &str) -> Option<usize> {
let module_utf16_bytes = module
.encode_utf16()
.chain(std::iter::once(0))
.collect::<Vec<u16>>();
let w_module = PCWSTR(module_utf16_bytes.as_ptr());
let c_symbol = CString::new(symbol).unwrap();
let w_symbol = PCSTR(c_symbol.as_ptr() as _);
unsafe {
let handle = GetModuleHandleW(w_module).expect("Failed getting module handle!");
GetProcAddress(handle, w_symbol).map(|result| result as usize)
}
} Load image function: /// OpenGL Only: Uploads the specified image to the GPU, then returns the pointer to that
/// image, which you may use with ImGui using a TextureId.
pub fn ogl_load_image(path: &str) -> u32 {
let image = image::open(path).expect("Failed loading desired image!");
let image_data = image.to_rgba8().into_raw();
let mut texture_id = 0;
unsafe {
// Constants needed for uploading an image to the GPU.
const TEXTURE_MAG_FILTER: u32 = 10240;
const TEXTURE_MIN_FILTER: u32 = 10241;
const TEXTURE_WRAP_S: u32 = 10242;
const TEXTURE_WRAP_T: u32 = 10243;
const CLAMP_TO_EDGE: u32 = 33071;
const UNSIGNED_BYTE: u32 = 5121;
const TEXTURE_2D: u32 = 3553;
const LINEAR: u32 = 9729;
const RGBA: u32 = 6408;
// OnceLock for each function we'll be using.
// Since they're static, they are only assigned once and remain alive until the end of
// the process.
static GEN_TEXTURES: OnceLock<usize> = OnceLock::new();
static BIND_TEXTURE: OnceLock<usize> = OnceLock::new();
static TEX_PARAMETER_I: OnceLock<usize> = OnceLock::new();
static TEX_IMAGE_2D: OnceLock<usize> = OnceLock::new();
static FLUSH: OnceLock<usize> = OnceLock::new();
// Find the functions needed, crash otherwise.
let gen_textures = *GEN_TEXTURES.get_or_init(|| {
WinUtils::get_module_symbol_address("opengl32.dll", "glGenTextures").expect("glGenTextures not found!")
});
let bind_texture = *BIND_TEXTURE.get_or_init(|| {
WinUtils::get_module_symbol_address("opengl32.dll", "glBindTexture").expect("glBindTexture not found!")
});
let tex_parameter_i = *TEX_PARAMETER_I.get_or_init(|| {
WinUtils::get_module_symbol_address("opengl32.dll", "glTexParameteri").expect("glTexParameteri not found!")
});
let tex_image_2d = *TEX_IMAGE_2D.get_or_init(|| {
WinUtils::get_module_symbol_address("opengl32.dll", "glTexImage2D").expect("glTexImage2D not found!")
});
let flush = *FLUSH.get_or_init(|| {
WinUtils::get_module_symbol_address("opengl32.dll", "glFlush").expect("glFlush not found!")
});
// Transmute functions so we can use them.
let gen_textures: fn(i32, *mut u32) = std::mem::transmute(gen_textures);
let bind_texture: fn(u32, u32) = std::mem::transmute(bind_texture);
let tex_parameter_i: fn(u32, u32, i32) = std::mem::transmute(tex_parameter_i);
let tex_image_2d: fn(u32, i32, i32, i32, i32, i32, u32, u32, *const c_void) =
std::mem::transmute(tex_image_2d);
let flush: fn() = std::mem::transmute(flush);
// Upload the texture to the GPU.
gen_textures(1, &mut texture_id);
bind_texture(TEXTURE_2D, texture_id);
tex_parameter_i(TEXTURE_2D, TEXTURE_MIN_FILTER, LINEAR as i32);
tex_parameter_i(TEXTURE_2D, TEXTURE_MAG_FILTER, LINEAR as i32);
tex_parameter_i(TEXTURE_2D, TEXTURE_WRAP_S, CLAMP_TO_EDGE as i32);
tex_parameter_i(TEXTURE_2D, TEXTURE_WRAP_T, CLAMP_TO_EDGE as i32);
tex_image_2d(
TEXTURE_2D,
0,
RGBA as i32,
image.width() as i32,
image.height() as i32,
0,
RGBA,
UNSIGNED_BYTE,
image_data.as_ptr() as _,
);
// Flush just in case we have unused data.
flush();
}
texture_id
} The load image function gives you the pointer to pass into TextureId, after that it'll "just work". Video showcasing it where I cached a bunch of frames extracted from a GIF, then iterated through them: |
Awesome, thank you! I see there are other snippets in imgui's repo for the other renderers, might end up supporting those as well. Hopefully I'll resume maintenance of this pretty soon. |
Yeah most of the work is just making it be suited for the other renderers. I was considering doing DirectX, but after I saw the chaos of the DX12 sample, I just closed it and moved on until I'm just that bored to fix it. |
#141 could make this (and a bunch of other stuff) pretty simple. |
2024-01-30_105822.mp4 |
To draw images using ImGui from what I can tell you need to load textures before you can do
draw_bg.add_image(texture_id, p_min, p_max)
.To accomplish this, from what I can understand, you would basically need to do what's happening in
create_font_texture
but for an image file or array of bytes, is that correct?The text was updated successfully, but these errors were encountered: