Skip to content

Instantly share code, notes, and snippets.

@Sergiovan
Created February 16, 2024 13:46
Show Gist options
  • Save Sergiovan/8c6eaa8110440c31ff76f1d038ff4e9c to your computer and use it in GitHub Desktop.
Save Sergiovan/8c6eaa8110440c31ff76f1d038ff4e9c to your computer and use it in GitHub Desktop.
imgui-rs with raylib-rs
[package]
name = "imgui-raylib"
version = "0.1.0"
edition = "2021"
[dependencies]
imgui = "0.11.0"
copypasta = "0.8.2"
[dependencies.raylib]
version = "4.5.0"
git = "https://github.com/litten2up/raylib-rs"
branch = "4.5.0"
[dependencies.raylib-sys]
version = "4.5.0"
git = "https://github.com/litten2up/raylib-rs"
branch = "4.5.0"
// from https://github.com/imgui-rs/imgui-rs/blob/main/imgui-examples/examples/support/clipboard.rs
use copypasta::{ClipboardContext, ClipboardProvider};
use imgui::ClipboardBackend;
pub struct ClipboardSupport(pub ClipboardContext);
impl ClipboardSupport {
pub fn init() -> Option<ClipboardSupport> {
ClipboardContext::new().ok().map(ClipboardSupport)
}
}
impl ClipboardBackend for ClipboardSupport {
fn get(&mut self) -> Option<String> {
self.0.get_contents().ok()
}
fn set(&mut self, text: &str) {
// ignore errors?
let _ = self.0.set_contents(text.to_owned());
}
}
use imgui::Io;
mod clipboard;
mod platform;
mod renderer;
pub struct RaylibImguiSupport {
context: imgui::Context,
renderer: renderer::RaylibRenderer,
platform: platform::RaylibPlatform,
}
impl RaylibImguiSupport {
pub fn setup(
rl: &mut raylib::RaylibHandle,
thread: &raylib::RaylibThread,
) -> RaylibImguiSupport {
let mut context = imgui::Context::create();
context.set_ini_filename(None);
context.set_log_filename(None);
context
.fonts()
.add_font(&[imgui::FontSource::DefaultFontData { config: None }]);
if let Some(support) = clipboard::ClipboardSupport::init() {
context.set_clipboard_backend(support);
} else {
println!("Could not set clipboard backend");
}
let renderer = renderer::RaylibRenderer::init(rl, thread, &mut context);
let platform = platform::RaylibPlatform::init(rl, &mut context);
RaylibImguiSupport {
context,
renderer,
platform,
}
}
pub fn start_frame(&mut self, rl: &mut raylib::RaylibHandle) -> &mut imgui::Ui {
self.platform.new_frame(rl, &mut self.context);
self.platform.handle_events(rl, &mut self.context);
self.context.new_frame()
}
pub fn end_frame(&mut self, rl: &mut raylib::drawing::RaylibDrawHandle) {
let [fb_x, fb_y] = self.context.io_mut().display_framebuffer_scale;
let draw_data = self.context.render();
self.renderer.render(rl, draw_data, [fb_x, fb_y]);
}
pub fn io(&mut self) -> &mut Io {
self.context.io_mut()
}
}
// From https://github.com/raylib-extras/rlImGui/blob/main/rlImGui.cpp
use std::time::Instant;
use imgui::{BackendFlags, Context};
use raylib::prelude::*;
struct LastFrame {
pub focused: bool,
pub ctrl: bool,
pub shift: bool,
pub alt: bool,
pub super_key: bool,
}
pub struct RaylibPlatform {
last_frame: Instant,
cursor: Option<imgui::MouseCursor>,
last_frame_data: LastFrame,
}
fn translate_cursor(imgui_cursor: imgui::MouseCursor) -> MouseCursor {
match imgui_cursor {
imgui::MouseCursor::Arrow => MouseCursor::MOUSE_CURSOR_ARROW,
imgui::MouseCursor::TextInput => MouseCursor::MOUSE_CURSOR_IBEAM,
imgui::MouseCursor::ResizeAll => MouseCursor::MOUSE_CURSOR_RESIZE_ALL,
imgui::MouseCursor::ResizeNS => MouseCursor::MOUSE_CURSOR_RESIZE_NS,
imgui::MouseCursor::ResizeEW => MouseCursor::MOUSE_CURSOR_RESIZE_EW,
imgui::MouseCursor::ResizeNESW => MouseCursor::MOUSE_CURSOR_RESIZE_NESW,
imgui::MouseCursor::ResizeNWSE => MouseCursor::MOUSE_CURSOR_RESIZE_NWSE,
imgui::MouseCursor::Hand => MouseCursor::MOUSE_CURSOR_POINTING_HAND,
imgui::MouseCursor::NotAllowed => MouseCursor::MOUSE_CURSOR_NOT_ALLOWED,
}
}
fn translate_key(key: KeyboardKey) -> imgui::Key {
match key {
KeyboardKey::KEY_A => imgui::Key::A,
KeyboardKey::KEY_B => imgui::Key::B,
KeyboardKey::KEY_C => imgui::Key::C,
KeyboardKey::KEY_D => imgui::Key::D,
KeyboardKey::KEY_E => imgui::Key::E,
KeyboardKey::KEY_F => imgui::Key::F,
KeyboardKey::KEY_G => imgui::Key::G,
KeyboardKey::KEY_H => imgui::Key::H,
KeyboardKey::KEY_I => imgui::Key::I,
KeyboardKey::KEY_J => imgui::Key::J,
KeyboardKey::KEY_K => imgui::Key::K,
KeyboardKey::KEY_L => imgui::Key::L,
KeyboardKey::KEY_M => imgui::Key::M,
KeyboardKey::KEY_N => imgui::Key::N,
KeyboardKey::KEY_O => imgui::Key::O,
KeyboardKey::KEY_P => imgui::Key::P,
KeyboardKey::KEY_Q => imgui::Key::Q,
KeyboardKey::KEY_R => imgui::Key::R,
KeyboardKey::KEY_S => imgui::Key::S,
KeyboardKey::KEY_T => imgui::Key::T,
KeyboardKey::KEY_U => imgui::Key::U,
KeyboardKey::KEY_V => imgui::Key::V,
KeyboardKey::KEY_W => imgui::Key::W,
KeyboardKey::KEY_X => imgui::Key::X,
KeyboardKey::KEY_Y => imgui::Key::Y,
KeyboardKey::KEY_Z => imgui::Key::Z,
KeyboardKey::KEY_ONE => imgui::Key::Keypad1,
KeyboardKey::KEY_TWO => imgui::Key::Keypad2,
KeyboardKey::KEY_THREE => imgui::Key::Keypad3,
KeyboardKey::KEY_FOUR => imgui::Key::Keypad4,
KeyboardKey::KEY_FIVE => imgui::Key::Keypad5,
KeyboardKey::KEY_SIX => imgui::Key::Keypad6,
KeyboardKey::KEY_SEVEN => imgui::Key::Keypad7,
KeyboardKey::KEY_EIGHT => imgui::Key::Keypad8,
KeyboardKey::KEY_NINE => imgui::Key::Keypad9,
KeyboardKey::KEY_ZERO => imgui::Key::Keypad0,
KeyboardKey::KEY_ENTER => imgui::Key::Enter,
KeyboardKey::KEY_ESCAPE => imgui::Key::Escape,
KeyboardKey::KEY_BACKSPACE => imgui::Key::Backspace,
KeyboardKey::KEY_TAB => imgui::Key::Tab,
KeyboardKey::KEY_SPACE => imgui::Key::Space,
KeyboardKey::KEY_MINUS => imgui::Key::Minus,
KeyboardKey::KEY_EQUAL => imgui::Key::Equal,
KeyboardKey::KEY_LEFT_BRACKET => imgui::Key::LeftBracket,
KeyboardKey::KEY_RIGHT_BRACKET => imgui::Key::RightBracket,
KeyboardKey::KEY_BACKSLASH => imgui::Key::Backslash,
KeyboardKey::KEY_SEMICOLON => imgui::Key::Semicolon,
KeyboardKey::KEY_APOSTROPHE => imgui::Key::Apostrophe,
KeyboardKey::KEY_GRAVE => imgui::Key::GraveAccent,
KeyboardKey::KEY_COMMA => imgui::Key::Comma,
KeyboardKey::KEY_PERIOD => imgui::Key::Period,
KeyboardKey::KEY_SLASH => imgui::Key::Slash,
KeyboardKey::KEY_CAPS_LOCK => imgui::Key::CapsLock,
KeyboardKey::KEY_F1 => imgui::Key::F1,
KeyboardKey::KEY_F2 => imgui::Key::F2,
KeyboardKey::KEY_F3 => imgui::Key::F3,
KeyboardKey::KEY_F4 => imgui::Key::F4,
KeyboardKey::KEY_F5 => imgui::Key::F5,
KeyboardKey::KEY_F6 => imgui::Key::F6,
KeyboardKey::KEY_F7 => imgui::Key::F7,
KeyboardKey::KEY_F8 => imgui::Key::F8,
KeyboardKey::KEY_F9 => imgui::Key::F9,
KeyboardKey::KEY_F10 => imgui::Key::F10,
KeyboardKey::KEY_F11 => imgui::Key::F11,
KeyboardKey::KEY_F12 => imgui::Key::F12,
KeyboardKey::KEY_PRINT_SCREEN => imgui::Key::PrintScreen,
KeyboardKey::KEY_SCROLL_LOCK => imgui::Key::ScrollLock,
KeyboardKey::KEY_PAUSE => imgui::Key::Pause,
KeyboardKey::KEY_INSERT => imgui::Key::Insert,
KeyboardKey::KEY_HOME => imgui::Key::Home,
KeyboardKey::KEY_PAGE_UP => imgui::Key::PageUp,
KeyboardKey::KEY_DELETE => imgui::Key::Delete,
KeyboardKey::KEY_END => imgui::Key::End,
KeyboardKey::KEY_PAGE_DOWN => imgui::Key::PageDown,
KeyboardKey::KEY_RIGHT => imgui::Key::RightArrow,
KeyboardKey::KEY_LEFT => imgui::Key::LeftArrow,
KeyboardKey::KEY_DOWN => imgui::Key::DownArrow,
KeyboardKey::KEY_UP => imgui::Key::UpArrow,
KeyboardKey::KEY_KP_DIVIDE => imgui::Key::KeypadDivide,
KeyboardKey::KEY_KP_MULTIPLY => imgui::Key::KeypadMultiply,
KeyboardKey::KEY_KP_SUBTRACT => imgui::Key::KeypadSubtract,
KeyboardKey::KEY_KP_ADD => imgui::Key::KeypadAdd,
KeyboardKey::KEY_KP_ENTER => imgui::Key::KeypadEnter,
KeyboardKey::KEY_KP_1 => imgui::Key::Keypad1,
KeyboardKey::KEY_KP_2 => imgui::Key::Keypad2,
KeyboardKey::KEY_KP_3 => imgui::Key::Keypad3,
KeyboardKey::KEY_KP_4 => imgui::Key::Keypad4,
KeyboardKey::KEY_KP_5 => imgui::Key::Keypad5,
KeyboardKey::KEY_KP_6 => imgui::Key::Keypad6,
KeyboardKey::KEY_KP_7 => imgui::Key::Keypad7,
KeyboardKey::KEY_KP_8 => imgui::Key::Keypad8,
KeyboardKey::KEY_KP_9 => imgui::Key::Keypad9,
KeyboardKey::KEY_KP_0 => imgui::Key::Keypad0,
KeyboardKey::KEY_KP_DECIMAL => imgui::Key::KeypadDecimal,
KeyboardKey::KEY_KB_MENU => imgui::Key::Menu,
KeyboardKey::KEY_KP_EQUAL => imgui::Key::KeypadEqual,
KeyboardKey::KEY_LEFT_CONTROL => imgui::Key::LeftCtrl,
KeyboardKey::KEY_LEFT_SHIFT => imgui::Key::LeftShift,
KeyboardKey::KEY_LEFT_ALT => imgui::Key::LeftAlt,
KeyboardKey::KEY_LEFT_SUPER => imgui::Key::LeftSuper,
KeyboardKey::KEY_RIGHT_CONTROL => imgui::Key::RightCtrl,
KeyboardKey::KEY_RIGHT_SHIFT => imgui::Key::RightShift,
KeyboardKey::KEY_RIGHT_ALT => imgui::Key::RightAlt,
KeyboardKey::KEY_RIGHT_SUPER => imgui::Key::RightSuper,
_ => imgui::Key::Escape, // TODO Figure this one out
}
}
fn keyboard_key_from_u32(key: u32) -> KeyboardKey {
match key {
39 => KeyboardKey::KEY_APOSTROPHE,
44 => KeyboardKey::KEY_COMMA,
45 => KeyboardKey::KEY_MINUS,
46 => KeyboardKey::KEY_PERIOD,
47 => KeyboardKey::KEY_SLASH,
48 => KeyboardKey::KEY_ZERO,
49 => KeyboardKey::KEY_ONE,
50 => KeyboardKey::KEY_TWO,
51 => KeyboardKey::KEY_THREE,
52 => KeyboardKey::KEY_FOUR,
53 => KeyboardKey::KEY_FIVE,
54 => KeyboardKey::KEY_SIX,
55 => KeyboardKey::KEY_SEVEN,
56 => KeyboardKey::KEY_EIGHT,
57 => KeyboardKey::KEY_NINE,
59 => KeyboardKey::KEY_SEMICOLON,
61 => KeyboardKey::KEY_EQUAL,
65 => KeyboardKey::KEY_A,
66 => KeyboardKey::KEY_B,
67 => KeyboardKey::KEY_C,
68 => KeyboardKey::KEY_D,
69 => KeyboardKey::KEY_E,
70 => KeyboardKey::KEY_F,
71 => KeyboardKey::KEY_G,
72 => KeyboardKey::KEY_H,
73 => KeyboardKey::KEY_I,
74 => KeyboardKey::KEY_J,
75 => KeyboardKey::KEY_K,
76 => KeyboardKey::KEY_L,
77 => KeyboardKey::KEY_M,
78 => KeyboardKey::KEY_N,
79 => KeyboardKey::KEY_O,
80 => KeyboardKey::KEY_P,
81 => KeyboardKey::KEY_Q,
82 => KeyboardKey::KEY_R,
83 => KeyboardKey::KEY_S,
84 => KeyboardKey::KEY_T,
85 => KeyboardKey::KEY_U,
86 => KeyboardKey::KEY_V,
87 => KeyboardKey::KEY_W,
88 => KeyboardKey::KEY_X,
89 => KeyboardKey::KEY_Y,
90 => KeyboardKey::KEY_Z,
91 => KeyboardKey::KEY_LEFT_BRACKET,
92 => KeyboardKey::KEY_BACKSLASH,
93 => KeyboardKey::KEY_RIGHT_BRACKET,
96 => KeyboardKey::KEY_GRAVE,
32 => KeyboardKey::KEY_SPACE,
256 => KeyboardKey::KEY_ESCAPE,
257 => KeyboardKey::KEY_ENTER,
258 => KeyboardKey::KEY_TAB,
259 => KeyboardKey::KEY_BACKSPACE,
260 => KeyboardKey::KEY_INSERT,
261 => KeyboardKey::KEY_DELETE,
262 => KeyboardKey::KEY_RIGHT,
263 => KeyboardKey::KEY_LEFT,
264 => KeyboardKey::KEY_DOWN,
265 => KeyboardKey::KEY_UP,
266 => KeyboardKey::KEY_PAGE_UP,
267 => KeyboardKey::KEY_PAGE_DOWN,
268 => KeyboardKey::KEY_HOME,
269 => KeyboardKey::KEY_END,
280 => KeyboardKey::KEY_CAPS_LOCK,
281 => KeyboardKey::KEY_SCROLL_LOCK,
282 => KeyboardKey::KEY_NUM_LOCK,
283 => KeyboardKey::KEY_PRINT_SCREEN,
284 => KeyboardKey::KEY_PAUSE,
290 => KeyboardKey::KEY_F1,
291 => KeyboardKey::KEY_F2,
292 => KeyboardKey::KEY_F3,
293 => KeyboardKey::KEY_F4,
294 => KeyboardKey::KEY_F5,
295 => KeyboardKey::KEY_F6,
296 => KeyboardKey::KEY_F7,
297 => KeyboardKey::KEY_F8,
298 => KeyboardKey::KEY_F9,
299 => KeyboardKey::KEY_F10,
300 => KeyboardKey::KEY_F11,
301 => KeyboardKey::KEY_F12,
340 => KeyboardKey::KEY_LEFT_SHIFT,
341 => KeyboardKey::KEY_LEFT_CONTROL,
342 => KeyboardKey::KEY_LEFT_ALT,
343 => KeyboardKey::KEY_LEFT_SUPER,
344 => KeyboardKey::KEY_RIGHT_SHIFT,
345 => KeyboardKey::KEY_RIGHT_CONTROL,
346 => KeyboardKey::KEY_RIGHT_ALT,
347 => KeyboardKey::KEY_RIGHT_SUPER,
348 => KeyboardKey::KEY_KB_MENU,
320 => KeyboardKey::KEY_KP_0,
321 => KeyboardKey::KEY_KP_1,
322 => KeyboardKey::KEY_KP_2,
323 => KeyboardKey::KEY_KP_3,
324 => KeyboardKey::KEY_KP_4,
325 => KeyboardKey::KEY_KP_5,
326 => KeyboardKey::KEY_KP_6,
327 => KeyboardKey::KEY_KP_7,
328 => KeyboardKey::KEY_KP_8,
329 => KeyboardKey::KEY_KP_9,
330 => KeyboardKey::KEY_KP_DECIMAL,
331 => KeyboardKey::KEY_KP_DIVIDE,
332 => KeyboardKey::KEY_KP_MULTIPLY,
333 => KeyboardKey::KEY_KP_SUBTRACT,
334 => KeyboardKey::KEY_KP_ADD,
335 => KeyboardKey::KEY_KP_ENTER,
336 => KeyboardKey::KEY_KP_EQUAL,
4 => KeyboardKey::KEY_BACK,
24 => KeyboardKey::KEY_VOLUME_UP,
25 => KeyboardKey::KEY_VOLUME_DOWN,
_ => KeyboardKey::KEY_NULL,
}
}
fn translate_mouse_button(button: MouseButton) -> imgui::MouseButton {
match button {
MouseButton::MOUSE_BUTTON_LEFT => imgui::MouseButton::Left,
MouseButton::MOUSE_BUTTON_RIGHT => imgui::MouseButton::Right,
MouseButton::MOUSE_BUTTON_MIDDLE => imgui::MouseButton::Middle,
MouseButton::MOUSE_BUTTON_SIDE => imgui::MouseButton::Left,
MouseButton::MOUSE_BUTTON_EXTRA => imgui::MouseButton::Left,
MouseButton::MOUSE_BUTTON_FORWARD => imgui::MouseButton::Extra1,
MouseButton::MOUSE_BUTTON_BACK => imgui::MouseButton::Extra2,
}
}
fn mouse_button_from_u32(button: u32) -> MouseButton {
match button {
0 => MouseButton::MOUSE_BUTTON_LEFT,
1 => MouseButton::MOUSE_BUTTON_RIGHT,
2 => MouseButton::MOUSE_BUTTON_MIDDLE,
3 => MouseButton::MOUSE_BUTTON_SIDE,
4 => MouseButton::MOUSE_BUTTON_EXTRA,
5 => MouseButton::MOUSE_BUTTON_FORWARD,
6 => MouseButton::MOUSE_BUTTON_BACK,
_ => MouseButton::MOUSE_BUTTON_LEFT,
}
}
impl RaylibPlatform {
pub fn init(rl: &mut RaylibHandle, imgui: &mut Context) -> RaylibPlatform {
let io = imgui.io_mut();
io.backend_flags.insert(BackendFlags::HAS_MOUSE_CURSORS);
io.backend_flags.insert(BackendFlags::HAS_SET_MOUSE_POS);
imgui.set_platform_name(Some(String::from("imgui-raylib-support")));
imgui.style_mut().use_dark_colors();
RaylibPlatform {
last_frame: Instant::now(),
cursor: None,
last_frame_data: LastFrame {
focused: rl.is_window_focused(),
ctrl: false,
shift: false,
alt: false,
super_key: false,
},
}
}
pub fn new_frame(&mut self, rl: &mut raylib::RaylibHandle, context: &mut Context) {
let io = context.io_mut();
if rl.is_window_fullscreen() {
let monitor = raylib::window::get_current_monitor();
io.display_size[0] = raylib::window::get_monitor_width(monitor) as f32;
io.display_size[1] = raylib::window::get_monitor_height(monitor) as f32;
} else {
io.display_size[0] = rl.get_screen_width() as f32;
io.display_size[1] = rl.get_screen_height() as f32;
}
let [width, height] = io.display_size;
if width > 0.0 && height > 0.0 {
io.display_framebuffer_scale = [
width.floor() / io.display_size[0],
height.floor() / io.display_size[1],
];
} else {
io.display_framebuffer_scale = [1.0, 1.0];
}
let now = Instant::now();
let delta_time = now - self.last_frame;
self.last_frame = now;
io.delta_time = delta_time.as_secs_f32();
if io.want_set_mouse_pos {
rl.set_mouse_position(Vector2 {
x: io.mouse_pos[0],
y: io.mouse_pos[1],
});
} else {
io.mouse_pos[0] = rl.get_mouse_x() as f32;
io.mouse_pos[1] = rl.get_mouse_y() as f32;
}
io.mouse_down[0] = rl.is_mouse_button_down(consts::MouseButton::MOUSE_BUTTON_LEFT);
io.mouse_down[1] = rl.is_mouse_button_down(consts::MouseButton::MOUSE_BUTTON_RIGHT);
io.mouse_down[2] = rl.is_mouse_button_down(consts::MouseButton::MOUSE_BUTTON_MIDDLE);
let mouse_wheel = rl.get_mouse_wheel_move_v();
io.mouse_wheel += mouse_wheel.y;
io.mouse_wheel_h += mouse_wheel.x;
if !io
.config_flags
.contains(imgui::ConfigFlags::NO_MOUSE_CURSOR_CHANGE)
{
let imgui_cursor = context.mouse_cursor();
if imgui_cursor != self.cursor {
self.cursor = imgui_cursor;
if let Some(cursor) = imgui_cursor {
rl.show_cursor();
rl.set_mouse_cursor(translate_cursor(cursor));
} else {
rl.hide_cursor();
}
}
}
}
pub fn handle_events(&mut self, rl: &mut raylib::RaylibHandle, context: &mut Context) {
let io = context.io_mut();
let focused = rl.is_window_focused();
if focused != self.last_frame_data.focused {
self.last_frame_data.focused = focused;
}
let ctrl = rl.is_key_down(KeyboardKey::KEY_RIGHT_CONTROL)
|| rl.is_key_down(KeyboardKey::KEY_LEFT_CONTROL);
if ctrl != self.last_frame_data.ctrl {
self.last_frame_data.ctrl = ctrl;
io.add_key_event(imgui::Key::ModCtrl, ctrl);
}
let alt =
rl.is_key_down(KeyboardKey::KEY_RIGHT_ALT) || rl.is_key_down(KeyboardKey::KEY_LEFT_ALT);
if alt != self.last_frame_data.alt {
self.last_frame_data.alt = alt;
io.add_key_event(imgui::Key::ModAlt, alt);
}
let shift = rl.is_key_down(KeyboardKey::KEY_RIGHT_SHIFT)
|| rl.is_key_down(KeyboardKey::KEY_LEFT_SHIFT);
if shift != self.last_frame_data.shift {
self.last_frame_data.shift = shift;
io.add_key_event(imgui::Key::ModShift, shift);
}
let super_key = rl.is_key_down(KeyboardKey::KEY_RIGHT_SUPER)
|| rl.is_key_down(KeyboardKey::KEY_LEFT_SUPER);
if super_key != self.last_frame_data.super_key {
self.last_frame_data.super_key = super_key;
io.add_key_event(imgui::Key::ModSuper, super_key);
}
while let Some(key) = rl.get_key_pressed() {
io.add_key_event(translate_key(key), true);
}
for i in 0..io.keys_down.len() {
let key = keyboard_key_from_u32(i as u32);
if key == KeyboardKey::KEY_NULL {
continue;
}
if rl.is_key_released(key) {
io.add_key_event(translate_key(key), false);
}
}
while let Some(char) = rl.get_char_pressed() {
io.add_input_character(char);
}
for i in 0..imgui::MouseButton::COUNT {
let button = mouse_button_from_u32(i as u32);
if rl.is_mouse_button_pressed(button) {
io.add_mouse_button_event(translate_mouse_button(button), true);
}
if rl.is_mouse_button_released(button) {
io.add_mouse_button_event(translate_mouse_button(button), false);
}
}
}
}
// From https://github.com/raylib-extras/rlImGui/blob/main/rlImGui.cpp
use imgui::{self, internal::RawWrapper};
use raylib::prelude::*;
use raylib::ffi;
pub struct RaylibRenderer {
_font_texture: Texture2D,
}
impl RaylibRenderer {
pub fn init(
rl: &mut RaylibHandle,
thread: &RaylibThread,
imgui: &mut imgui::Context,
) -> RaylibRenderer {
let texture = imgui.fonts().build_rgba32_texture();
let image =
Image::gen_image_color(texture.width as i32, texture.height as i32, Color::BLANK);
let pixel_len = texture.width * texture.height * 4;
unsafe {
(image.data as *mut u8)
.copy_from_nonoverlapping(texture.data.as_ptr(), pixel_len as usize)
};
let texture = rl.load_texture_from_image(thread, &image).unwrap();
imgui.fonts().tex_id = (texture.id as usize).into();
RaylibRenderer {
_font_texture: texture,
}
}
pub fn render(
&mut self,
rl: &mut RaylibDrawHandle,
draw_data: &imgui::DrawData,
framebuffer_scale: [f32; 2],
) {
unsafe {
ffi::rlDrawRenderBatchActive();
ffi::rlDisableBackfaceCulling();
}
for list in draw_data.draw_lists() {
for command in list.commands() {
match command {
imgui::DrawCmd::Elements { count, cmd_params } => {
let [x, y, z, w] = cmd_params.clip_rect;
self.enable_scissor(
rl,
x - draw_data.display_pos[0],
y - draw_data.display_pos[1],
z - (x - draw_data.display_pos[0]),
w - (y - draw_data.display_pos[1]),
framebuffer_scale,
);
self.render_triangles(
count,
cmd_params.idx_offset,
list.idx_buffer(),
list.vtx_buffer(),
cmd_params.texture_id,
);
unsafe {
ffi::rlDrawRenderBatchActive();
}
}
imgui::DrawCmd::RawCallback { callback, raw_cmd } => {
let clip_rect = unsafe { *raw_cmd }.ClipRect;
self.enable_scissor(
rl,
clip_rect.x - draw_data.display_pos[0],
clip_rect.y - draw_data.display_pos[1],
clip_rect.z - (clip_rect.x - draw_data.display_pos[0]),
clip_rect.w - (clip_rect.y - draw_data.display_pos[1]),
framebuffer_scale,
);
unsafe { callback(list.raw(), raw_cmd) }
}
imgui::DrawCmd::ResetRenderState => (),
}
}
}
unsafe {
ffi::rlSetTexture(0);
ffi::rlDisableScissorTest();
ffi::rlEnableBackfaceCulling();
}
}
fn enable_scissor(
&self,
rl: &mut RaylibDrawHandle,
x: f32,
y: f32,
width: f32,
height: f32,
framebuffer_scale: [f32; 2],
) {
unsafe {
ffi::rlEnableScissorTest();
}
let [fb_x, fb_y] = framebuffer_scale;
let scissor_x = (x * fb_x) as i32;
let scissor_y = ((rl.get_screen_height() as f32 - (y + height)) * fb_y) as i32;
let scissor_width = (width * fb_x) as i32;
let scissor_height = (height * fb_y) as i32;
unsafe {
ffi::rlScissor(scissor_x, scissor_y, scissor_width, scissor_height);
}
}
fn render_triangles(
&self,
count: usize,
start: usize,
index_buffer: &[imgui::DrawIdx],
vertex_buffer: &[imgui::DrawVert],
texture: imgui::TextureId,
) {
if count < 3 {
return;
}
let texture_id = texture.id() as u32;
unsafe {
ffi::rlBegin(ffi::RL_TRIANGLES as i32);
ffi::rlSetTexture(texture_id);
}
for i in (0..count).step_by(3) {
unsafe {
if ffi::rlCheckRenderBatchLimit(3) {
ffi::rlBegin(ffi::RL_TRIANGLES as i32);
ffi::rlSetTexture(texture_id);
}
}
let idx1 = index_buffer[start + i];
let idx2 = index_buffer[start + i + 1];
let idx3 = index_buffer[start + i + 2];
let vert1 = &vertex_buffer[idx1 as usize];
let vert2 = &vertex_buffer[idx2 as usize];
let vert3 = &vertex_buffer[idx3 as usize];
self.triangle_vertex(vert1);
self.triangle_vertex(vert2);
self.triangle_vertex(vert3);
}
unsafe {
ffi::rlEnd();
}
}
fn triangle_vertex(&self, vertex: &imgui::DrawVert) {
let [r, g, b, a] = vertex.col;
unsafe {
ffi::rlColor4ub(r, g, b, a);
ffi::rlTexCoord2f(vertex.uv[0], vertex.uv[1]);
ffi::rlVertex2f(vertex.pos[0], vertex.pos[1]);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment