commit ad10dff1cf1cbcf7dd97346f8778157d5119cde4 Author: Joonas Javanainen Date: Sat Aug 15 15:47:51 2015 +0300 Initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4ea67ad --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +*~ +*.swp +/target +/Cargo.lock diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..bcd9c2a --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "third-party/cimgui"] + path = third-party/cimgui + url = https://github.com/Extrawurst/cimgui.git diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..239937a --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,24 @@ +[package] +name = "imgui-rs" +version = "0.0.1" +authors = ["Joonas Javanainen "] +build = "build.rs" + +[lib] +name = "imgui" + +[dependencies] +bitflags = "0.3" +libc = "0.1" + +[dependencies.glium] +version = "0.8" +default-features = false +optional = true + +[dependencies.sdl2] +version = "0.7" +optional = true + +[build-dependencies] +gcc = "0.3" diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..9fbbdf3 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2015 Joonas Javanainen + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.markdown b/README.markdown new file mode 100644 index 0000000..8171d7a --- /dev/null +++ b/README.markdown @@ -0,0 +1,9 @@ +# imgui-rs: Rust bindings for (ImGui) + +**Ultra hyper turbo cyber mega extra über experimental!!!** + +## License + +imgui-rs is licensed under the MIT license. + +Uses [ImGui](https://github.com/ocornut/imgui) and [cimgui](https://github.com/Extrawurst/cimgui). diff --git a/build.rs b/build.rs new file mode 100644 index 0000000..78818c8 --- /dev/null +++ b/build.rs @@ -0,0 +1,13 @@ +extern crate gcc; + +fn main() { + gcc::Config::new() + .cpp(true) + .file("third-party/cimgui/cimgui/cimgui.cpp") + .file("third-party/cimgui/cimgui/fontAtlas.cpp") + .file("third-party/cimgui/cimgui/drawList.cpp") + .file("third-party/cimgui/imgui/imgui.cpp") + .file("third-party/cimgui/imgui/imgui_demo.cpp") + .file("third-party/cimgui/imgui/imgui_draw.cpp") + .compile("libcimgui.a"); +} diff --git a/src/ffi.rs b/src/ffi.rs new file mode 100644 index 0000000..9f4fa72 --- /dev/null +++ b/src/ffi.rs @@ -0,0 +1,1008 @@ +#![allow(non_upper_case_globals)] + +use libc::*; +use std::mem; +use std::slice; + +pub type ImU32 = c_uint; +pub type ImWchar = c_ushort; +pub type ImTextureID = *mut c_void; +pub type ImGuiID = ImU32; + +#[repr(C)] +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub enum ImGuiCol { + Text, + TextDisabled, + WindowBg, + ChildWindowBg, + Border, + BorderShadow, + FrameBg, + FrameBgHovered, + FrameBgActive, + TitleBg, + TitleBgCollapsed, + TitleBgActive, + MenuBarBg, + ScrollbarBg, + ScrollbarGrab, + ScrollbarGrabHovered, + ScrollbarGrabActive, + ComboBg, + CheckMark, + SliderGrab, + SliderGrabActive, + Button, + ButtonHovered, + ButtonActive, + Header, + HeaderHovered, + HeaderActive, + Column, + ColumnHovered, + ColumnActive, + ResizeGrip, + ResizeGripHovered, + ResizeGripActive, + CloseButton, + CloseButtonHovered, + CloseButtonActive, + PlotLines, + PlotLinesHovered, + PlotHistogram, + PlotHistogramHovered, + TextSelectedBg, + TooltipBg, + ModalWindowDarkening +} +pub const ImGuiCol_COUNT: usize = 43; + +#[repr(C)] +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub enum ImGuiStyleVar { + Alpha, + WindowPadding, + WindowRounding, + WindowMinSize, + ChildWindowRounding, + FramePadding, + FrameRounding, + ItemSpacing, + ItemInnerSpacing, + IndentSpacing, + GrabMinSize +} + +#[repr(C)] +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub enum ImGuiKey { + Tab, + LeftArrow, + RightArrow, + UpArrow, + DownArrow, + PageUp, + PageDown, + Home, + End, + Delete, + Backspace, + Enter, + Escape, + A, + C, + V, + X, + Y, + Z +} +pub const ImGuiKey_COUNT: usize = 19; + +bitflags!( + #[repr(C)] + flags ImGuiAlign: c_int { + const ImGuiAlign_Left = 1 << 0, + const ImGuiAlign_Center = 1 << 1, + const ImGuiAlign_Right = 1 << 2, + const ImGuiAlign_Top = 1 << 3, + const ImGuiAlign_VCenter = 1 << 4, + const ImGuiAlign_Default = ImGuiAlign_Left.bits | ImGuiAlign_Top.bits + } +); + +#[repr(C)] +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub enum ImGuiColorEditMode { + UserSelect, + UserSelectShowButton, + RGB, + HSV, + HEX +} + +#[repr(C)] +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub enum ImGuiMouseCursor { + Arrow, + TextInput, + Move, + ResizeNS, + ResizeEW, + ResizeNESW, + ResizeNWSE +} + +pub const ImGuiMouseCursor_COUNT: usize = 7; + +bitflags!( + #[repr(C)] + flags ImGuiWindowFlags: c_int { + const ImGuiWindowFlags_NoTitleBar = 1 << 0, + const ImGuiWindowFlags_NoResize = 1 << 1, + const ImGuiWindowFlags_NoMove = 1 << 2, + const ImGuiWindowFlags_NoScrollbar = 1 << 3, + const ImGuiWindowFlags_NoScrollWithMouse = 1 << 4, + const ImGuiWindowFlags_NoCollapse = 1 << 5, + const ImGuiWindowFlags_AlwaysAutoResize = 1 << 6, + const ImGuiWindowFlags_ShowBorders = 1 << 7, + const ImGuiWindowFlags_NoSavedSettings = 1 << 8, + const ImGuiWindowFlags_NoInputs = 1 << 9, + const ImGuiWindowFlags_MenuBar = 1 << 10, + + const ImGuiWindowFlags_ChildWindow = 1 << 20, + const ImGuiWindowFlags_ChildWindowAutoFitX = 1 << 21, + const ImGuiWindowFlags_ChildWindowAutoFitY = 1 << 22, + const ImGuiWindowFlags_ComboBox = 1 << 23, + const ImGuiWindowFlags_Tooltip = 1 << 24, + const ImGuiWindowFlags_Popup = 1 << 25, + const ImGuiWindowFlags_Modal = 1 << 26, + const ImGuiWindowFlags_ChildMenu = 1 << 27 + } +); + +bitflags!( + #[repr(C)] + flags ImGuiSetCond: c_int { + const ImGuiSetCond_Always = 1 << 0, + const ImGuiSetCond_Once = 1 << 1, + const ImGuiSetCond_FirstUseEver = 1 << 2, + const ImGuiSetCond_Appearing = 1 << 3 + } +); + +bitflags!( + #[repr(C)] + flags ImGuiInputTextFlags: c_int { + const ImGuiInputTextFlags_CharsDecimal = 1 << 0, + const ImGuiInputTextFlags_CharsHexadecimal = 1 << 1, + const ImGuiInputTextFlags_CharsUppercase = 1 << 2, + const ImGuiInputTextFlags_CharsNoBlank = 1 << 3, + const ImGuiInputTextFlags_AutoSelectAll = 1 << 4, + const ImGuiInputTextFlags_EnterReturnsTrue = 1 << 5, + const ImGuiInputTextFlags_CallbackCompletion = 1 << 6, + const ImGuiInputTextFlags_CallbackHistory = 1 << 7, + const ImGuiInputTextFlags_CallbackAlways = 1 << 8, + const ImGuiInputTextFlags_CallbackCharFilter = 1 << 9, + const ImGuiInputTextFlags_AllowTabInput = 1 << 10, + const ImGuiInputTextFlags_CtrlEnterForNewLine = 1 << 11, + const ImGuiInputTextFlags_NoHorizontalScroll = 1 << 12, + const ImGuiInputTextFlags_AlwaysInsertMode = 1 << 13, + + const ImGuiInputTextFlags_Multiline = 1 << 20, + } +); + +bitflags!( + #[repr(C)] + flags ImGuiSelectableFlags: c_int { + const ImGuiSelectableFlags_DontClosePopups = 1 << 0, + const ImGuiSelectableFlags_SpanAllColumns = 1 << 1 + } +); + +pub type ImGuiTextEditCallback = + Option c_int>; + +#[repr(C)] +#[derive(Copy, Clone, Debug, Default)] +pub struct ImVec2 { + pub x: c_float, + pub y: c_float +} + +#[repr(C)] +#[derive(Copy, Clone, Debug, Default)] +pub struct ImVec4 { + pub x: c_float, + pub y: c_float, + pub z: c_float, + pub w: c_float +} + +#[repr(C)] +pub struct ImGuiStyle { + pub alpha: c_float, + pub window_padding: ImVec2, + pub window_min_size: ImVec2, + pub window_rounding: c_float, + pub window_title_align: ImGuiAlign, + pub child_window_rounding: c_float, + pub frame_padding: ImVec2, + pub frame_rouding: c_float, + pub item_spacing: ImVec2, + pub item_inner_spacing: ImVec2, + pub touch_extra_padding: ImVec2, + pub window_fill_alpha_default: c_float, + pub indent_spacing: c_float, + pub columns_min_spacing: c_float, + pub scrollbar_width: c_float, + pub scrollbar_rounding: c_float, + pub grab_min_size: c_float, + pub grab_rounding: c_float, + pub display_window_padding: ImVec2, + pub display_safe_area_padding: ImVec2, + pub anti_aliased_lines: bool, + pub anti_aliased_shapes: bool, + pub colors: [ImVec4; ImGuiCol_COUNT] +} + +#[repr(C)] +pub struct ImGuiIO { + pub display_size: ImVec2, + pub delta_time: c_float, + pub ini_saving_rate: c_float, + pub ini_filename: *const c_char, + pub log_filename: *const c_char, + pub mouse_double_click_time: c_float, + pub mouse_double_click_max_dist: c_float, + pub mouse_drag_threshold: c_float, + pub key_map: [c_int; ImGuiKey_COUNT], + pub key_repeat_delay: c_float, + pub key_repeat_rate: c_float, + pub user_data: *mut c_void, + pub fonts: *mut ImFontAtlas, + pub font_global_scale: c_float, + pub font_allow_user_scaling: bool, + pub display_visible_min: ImVec2, + pub display_visible_max: ImVec2, + + pub render_draw_lists_fn: Option, + pub get_clipboard_text_fn: Option *const c_char>, + pub set_clipboard_text_fn: Option, + pub mem_alloc_fn: Option *mut c_void>, + pub mem_free_fn: Option, + pub ime_set_input_screen_pos_fn: Option, + + pub ime_window_handle: *mut c_void, + + pub mouse_pos: ImVec2, + pub mouse_down: [bool; 5], + pub mouse_wheel: c_float, + pub mouse_draw_cursor: bool, + pub key_ctrl: bool, + pub key_shift: bool, + pub key_alt: bool, + pub keys_down: [bool; 512], + pub input_characters: [ImWchar; 16+1], + + pub want_capture_mouse: bool, + pub want_capture_keyboard: bool, + pub framerate: c_float, + pub metrics_allocs: c_int, + pub metrics_render_vertices: c_int, + pub metrics_render_indices: c_int, + pub metrics_active_windows: c_int, + + pub mouse_pos_prev: ImVec2, + pub mouse_delta: ImVec2, + pub mouse_clicked: [bool; 5], + pub mouse_clicked_pos: [ImVec2; 5], + pub mouse_clicked_time: [c_float; 5], + pub mouse_double_clicked: [bool; 5], + pub mouse_released: [bool; 5], + pub mouse_down_owned: [bool; 5], + pub mouse_down_duration: [c_float; 5], + pub mouse_down_duration_prev: [c_float; 5], + pub mouse_drag_max_distance_sqr: [c_float; 5], + pub keys_down_duration: [c_float; 512], + pub keys_down_duration_prev: [c_float; 512] +} + +#[repr(C)] +pub struct ImVector { + pub size: c_int, + pub capacity: c_int, + pub data: *mut T +} + +impl ImVector { + pub unsafe fn as_slice(&self) -> &[T] { + slice::from_raw_parts(self.data, self.size as usize) + } +} + +#[repr(C)] +pub struct TextRange { + pub begin: *const c_char, + pub end: *const c_char +} + +#[repr(C)] +pub struct ImGuiTextFilter { + pub input_buf: [c_char; 256], + pub filters: ImVector, + pub count_grep: c_int +} + +#[repr(C)] +pub struct ImGuiTextBuffer { + pub buf: ImVector +} + +#[repr(C)] +pub struct Pair { + pub key: ImGuiID, + pub data: *mut c_void +} + +#[repr(C)] +pub struct ImGuiStorage { + pub data: ImVector +} + +#[repr(C)] +pub struct ImGuiTextEditCallbackData { + pub event_flag: ImGuiInputTextFlags, + pub flags: ImGuiInputTextFlags, + pub user_data: *mut c_void, + pub event_char: ImWchar, + pub event_key: ImGuiKey, + pub buf: *mut c_char, + pub buf_size: c_int, + pub buf_dirty: bool, + pub cursor_pos: c_int, + pub selection_start: c_int, + pub selection_end: c_int +} + +#[repr(C)] +#[derive(Copy, Clone, Debug, Default)] +pub struct ImColor { + pub value: ImVec4 +} + +#[repr(C)] +#[derive(Copy, Clone, Debug, Default)] +pub struct ImGuiListClipper { + pub items_height: c_float, + pub items_count: c_int, + pub display_start: c_int, + pub display_end: c_int +} + +pub type ImDrawCallback = + Option; + +#[repr(C)] +pub struct ImDrawCmd { + pub elem_count: c_uint, + pub clip_rect: ImVec4, + pub texture_id: ImTextureID, + pub user_callback: ImDrawCallback, + pub user_callback_data: *mut c_void +} + +pub type ImDrawIdx = c_ushort; + +#[repr(C)] +#[derive(Copy, Clone, Debug, Default)] +pub struct ImDrawVert { + pub pos: ImVec2, + pub uv: ImVec2, + pub col: ImU32 +} + +#[repr(C)] +pub struct ImDrawChannel { + pub cmd_buffer: ImVector, + pub idx_buffer: ImVector +} + +#[repr(C)] +pub struct ImDrawList { + pub cmd_buffer: ImVector, + pub idx_buffer: ImVector, + pub vtx_buffer: ImVector, + + owner_name: *const c_char, + vtx_current_idx: c_uint, + vtx_write_ptr: *mut ImDrawVert, + idx_write_ptr: *mut ImDrawIdx, + clip_rect_stack: ImVector, + texture_id_stack: ImVector, + path: ImVector, + channel_current: c_int, + channels: ImVector +} + +#[repr(C)] +pub struct ImDrawData { + pub cmd_lists: *mut *mut ImDrawList, + pub cmd_lists_count: c_int, + pub total_vtx_count: c_int, + pub total_idx_count: c_int +} + +impl ImDrawData { + pub unsafe fn cmd_lists(&self) -> &[*const ImDrawList] { + let cmd_lists: *const *const ImDrawList = mem::transmute(self.cmd_lists); + slice::from_raw_parts(cmd_lists, self.cmd_lists_count as usize) + } +} + +#[repr(C)] +pub struct ImFontConfig { + pub font_data: *mut c_void, + pub font_data_size: c_int, + pub font_data_owned_by_atlas: bool, + pub font_no: c_int, + pub size_pixels: c_float, + pub oversample_h: c_int, + pub oversample_v: c_int, + pub pixel_snap_h: bool, + pub glyph_extra_spacing: ImVec2, + pub glyph_ranges: *const ImWchar, + pub merge_mode: bool, + pub merge_glyph_center_v: bool, + + name: [c_char; 32], + dst_font: *mut ImFont +} + +#[repr(C)] +pub struct ImFontAtlas { + pub tex_id: *mut c_void, + pub tex_pixels_alpha8: *mut c_uchar, + pub tex_pixels_rgba32: *mut c_uint, + pub tex_width: c_int, + pub tex_height: c_int, + pub tex_uv_white_pixel: ImVec2, + pub fonts: ImVector<*mut ImFont>, + + config_data: ImVector +} + +#[repr(C)] +#[derive(Copy, Clone, Debug, Default)] +pub struct Glyph { + codepoint: ImWchar, + x_advance: c_float, + x0: c_float, y0: c_float, + x1: c_float, y1: c_float, + u0: c_float, v0: c_float, + u1: c_float, v1: c_float +} + +#[repr(C)] +pub struct ImFont { + font_size: c_float, + scale: c_float, + display_offset: ImVec2, + fallback_char: ImWchar, + config_data: *mut ImFontConfig, + config_data_count: c_int, + ascent: c_float, + descent: c_float, + container_atlas: *mut ImFontAtlas, + glyphs: ImVector, + fallback_glyph: *const Glyph, + fallback_x_advance: c_float, + index_x_advance: ImVector, + index_lookup: ImVector +} + +extern "C" { + pub fn igGetIO() -> *mut ImGuiIO; + pub fn igGetStyle() -> *mut ImGuiStyle; + pub fn igNewFrame(); + pub fn igRender(); + pub fn igShutdown(); + pub fn igShowUserGuide(); + pub fn igShowStyleEditor(style: *mut ImGuiStyle); + pub fn igShowTestWindow(opened: *mut bool); + pub fn igShowMetricsWindow(opened: *mut bool); +} + +// Window +extern "C" { + pub fn igBegin(name: *const c_char, opened: *mut bool, flags: ImGuiWindowFlags) -> bool; + pub fn igBegin2(name: *const c_char, opened: *mut bool, size_on_first_use: ImVec2, + bg_alpha: c_float, flags: ImGuiWindowFlags) -> bool; + pub fn igEnd(); + pub fn igBeginChild(str_id: *const char, size: ImVec2, border: bool, + extra_flags: ImGuiWindowFlags) -> bool; + pub fn igBeginChildEx(id: ImGuiID, size: ImVec2, border: bool, + extra_flags: ImGuiWindowFlags) -> bool; + pub fn igEndChild(); + pub fn igGetContentRegionMax(out: *mut ImVec2); + pub fn igGetContentRegionAvail(out: *mut ImVec2); + pub fn igGetWindowContentRegionMin(out: *mut ImVec2); + pub fn igGetWindowContentRegionMax(out: *mut ImVec2); + pub fn igGetWindowDrawList() -> *mut ImDrawList; + pub fn igGetWindowFont() -> *mut ImFont; + pub fn igGetWindowFontSize() -> c_float; + pub fn igSetWindowFontScale(scale: c_float); + pub fn igGetWindowPos(out: *mut ImVec2); + pub fn igGetWindowSize(out: *mut ImVec2); + pub fn igGetWindowWidth() -> c_float; + pub fn igIsWindowCollapsed() -> bool; + + pub fn igSetNextWindowPos(pos: ImVec2, cond: ImGuiSetCond); + pub fn igSetNextWindowPosCenter(cond: ImGuiSetCond); + pub fn igSetNextWindowSize(size: ImVec2, cond: ImGuiSetCond); + pub fn igSetNextWindowCollapsed(collapsed: bool, cond: ImGuiSetCond); + pub fn igSetNextWindowFocus(); + pub fn igSetWindowPos(pos: ImVec2, cond: ImGuiSetCond); + pub fn igSetWindowSize(size: ImVec2, cond: ImGuiSetCond); + pub fn igSetWindowCollapsed(collapsed: bool, cond: ImGuiSetCond); + pub fn igSetWindowFocus(); + pub fn igSetWindowPosByName(name: *const c_char, pos: ImVec2, cond: ImGuiSetCond); + pub fn igSetWindowSize2(name: *const c_char, size: ImVec2, cond: ImGuiSetCond); + pub fn igSetWindowCollapsed2(name: *const c_char, collapsed: bool, cond: ImGuiSetCond); + pub fn igSetWindowFocus2(name: *const c_char); + + pub fn igGetScrollY() -> c_float; + pub fn igGetScrollMaxY() -> c_float; + pub fn igSetScrollY(scroll_y: c_float); + pub fn igSetScrollHere(center_y_ratio: c_float); + pub fn igSetScrollFromPosY(pos_y: c_float, center_y_ratio: c_float); + pub fn igSetKeyboardFocusHere(offset: c_int); + pub fn igSetStateStorage(tree: *mut ImGuiStorage); + pub fn igGetStateStorage() -> *mut ImGuiStorage; +} + +// Parameter stack (shared) +extern "C" { + pub fn igPushFont(font: *mut ImFont); + pub fn igPopFont(); + pub fn igPushStyleColor(idx: ImGuiCol, col: ImVec4); + pub fn igPopStyleColor(count: c_int); + pub fn igPushStyleVar(idx: ImGuiStyleVar, val: c_float); + pub fn igPushStyleVavrVec(idx: ImGuiStyleVar, val: ImVec2); + pub fn igPopStyleVar(count: c_int); +} + +// Parameter stack (current window) +extern "C" { + pub fn igPushItemWidth(item_width: c_float); + pub fn igPopitemWidth(); + pub fn igCalcItemWidth() -> c_float; + pub fn igPushAllowKeyboardFocus(v: bool); + pub fn igPopAllowKeyboardFocus(); + pub fn igPushTextWrapPos(wrap_pos_x: c_float); + pub fn igPopTextWrapPos(); + pub fn igPushButtonRepeat(repeat: bool); + pub fn igPopButtonRepeat(); +} + +// Layout +extern "C" { + pub fn igBeginGroup(); + pub fn igEndGroup(); + pub fn igSeparator(); + pub fn igSameLine(pos_x: c_float, spacing_w: c_float); + pub fn igSpacing(); + pub fn igDummy(size: *const ImVec2); + pub fn igIndent(); + pub fn igUnindent(); + pub fn igColumns(count: c_int, id: *const c_char, border: bool); + pub fn igNextColumn(); + pub fn igGetColumnIndex() -> c_int; + pub fn igGetColumnOffset(column_index: c_int) -> c_float; + pub fn igSetColumnOffset(column_index: c_int, offset_x: c_float); + pub fn igGetColumnWidth(column_index: c_int) -> c_float; + pub fn igGetColumnsCount() -> c_int; + pub fn igGetCursorPos(out: *mut ImVec2); + pub fn igGetCursorPosX() -> c_float; + pub fn igGetCursorPosY() -> c_float; + pub fn igSetCursorPos(pos: ImVec2); + pub fn igSetCursorPosX(x: c_float); + pub fn igSetCursorPosY(y: c_float); + pub fn igGetCursorStartPos(out: *mut ImVec2); + pub fn igGetCursorScreenPos(out: *mut ImVec2); + pub fn igSetCursorScreenPos(pos: ImVec2); + pub fn igAlignFirstTextHeightToWidgets(); + pub fn igGetTextLineHeight() -> c_float; + pub fn igGetTextLineHeightWithSpacing() -> c_float; + pub fn igGetItemsLineHeightWithSpacing() -> c_float; +} + +// ID scopes +extern "C" { + pub fn igPushIdStr(str_id: *const c_char); + pub fn igPushIdStrRange(str_begin: *const c_char, str_end: *const c_char); + pub fn igPushIdPtr(ptr_id: *const c_void); + pub fn igPushIdInt(int_id: c_int); + pub fn igPopId(); + pub fn igGetIdStr(str_id: *const c_char) -> ImGuiID; + pub fn igGetIdstrRange(str_begin: *const c_char, str_end: *const c_char) -> ImGuiID; + pub fn igGetIdPtr(ptr_id: *const c_void) -> ImGuiID; +} + +// Widgets +extern "C" { + pub fn igText(fmt: *const c_char, ...); + // pub fn igTextV(fmt: *const c_char, args: va_list); + pub fn igTextColored(col: ImVec4, fmt: *const char, ...); + // pub fn igTextColoredV(col: ImVec4, fmt: *const char, args: va_list); + pub fn igTextDisabled(fmt: *const c_char, ...); + // pub fn igTextDisabledV(fmt: *const c_char, args: va_list); + pub fn igTextWrapped(fmt: *const c_char, ...); + // pub fn igTextWrappedV(fmt: *const c_char, args: va_list); + pub fn igTextUnformatted(text: *const c_char, text_end: *const c_char); + pub fn igLabelText(label: *const c_char, fmt: *const c_char, ...); + // pub fn igLabelTextV(label: *const c_char, fmt: *const c_char, args: va_list); + pub fn igBullet(); + pub fn igBulletText(fmt: *const c_char, ...); + // pub fn igBulletTextV(fmt: *const c_char, args: va_list); + pub fn igButton(label: *const c_char, size: ImVec2) -> bool; + pub fn igSmallButton(label: *const c_char) -> bool; + pub fn igInvisibleButton(str_id: *const c_char, size: ImVec2) -> bool; + pub fn igImage(user_texture_id: ImTextureID, size: ImVec2, + uv0: ImVec2, uv1: ImVec2, + tint_col: ImVec4, border_col: ImVec4); + pub fn igImageButton(user_texture_id: ImTextureID, size: ImVec2, + uv0: ImVec2, uv1: ImVec2, + frame_padding: c_int, bg_col: ImVec4, + tint_col: ImVec4) -> bool; + pub fn igCollapsingHeader(label: *const c_char, str_id: *const c_char, + display_frame: bool, default_open: bool) -> bool; + pub fn igCheckbox(label: *const c_char, v: *mut bool) -> bool; + pub fn igCheckboxFlags(label: *const c_char, + flags: *mut c_uint, flags_value: c_uint) -> bool; + pub fn igRadioButtonBool(label: *const c_char, active: bool) -> bool; + pub fn igRadioButton(label: *const c_char, v: *mut c_int, + v_button: c_int) -> bool; + pub fn igCombo(label: *const c_char, current_item: *mut c_int, + items: *mut *const c_char, items_count: c_int, height_in_items: c_int) -> bool; + pub fn igCombo2(label: *const c_char, current_item: *mut c_int, + items_separated_by_zeros: *const c_char, height_in_items: c_int) -> bool; + pub fn igCombo3(label: *const c_char, current_item: *mut c_int, + items_getter: extern "C" fn(data: *mut c_void, + idx: c_int, + out_text: *mut *const c_char) -> bool, + data: *mut c_void, items_count: c_int, + height_in_items: c_int) -> bool; + pub fn igColorButton(col: ImVec4, small_height: bool, outline_border: bool) -> bool; + pub fn igColorEdit3(label: *const c_char, col: [c_float; 3]) -> bool; + pub fn igColorEdit4(label: *const c_char, col: [c_float; 4], show_alpha: bool) -> bool; + pub fn igColorEditMode(mode: ImGuiColorEditMode); + pub fn igPlotLines(label: *const c_char, + values: *const c_float, values_count: c_int, values_offset: c_int, + overlay_text: *const c_char, + scale_min: c_float, scale_max: c_float, + graph_size: ImVec2, stride: c_int); + pub fn igPlotLines2(label: *const c_char, + values_getter: extern "C" fn(data: *mut c_void, + idx: c_int) -> c_float, + data: *mut c_void, + values_count: c_int, values_offset: c_int, + overlay_text: *const c_char, + scale_min: c_float, scale_max: c_float, graph_size: ImVec2); + pub fn igPlotHistogram(label: *const c_char, + values: *const c_float, values_count: c_int, values_offset: c_int, + overlay_text: *const c_char, + scale_min: c_float, scale_max: c_float, + graph_size: ImVec2, stride: c_int); + pub fn igPlotHistogram2(label: *const c_char, + values_getter: extern "C" fn(data: *mut c_void, + idx: c_int) -> c_float, + data: *mut c_void, + values_count: c_int, values_offset: c_int, + overlay_text: *const c_char, + scale_min: c_float, scale_max: c_float, + graph_size: ImVec2); +} + +// Widgets: Sliders +extern "C" { + pub fn igSliderFloat(label: *const c_char, v: *mut c_float, + v_min: c_float, v_max: c_float, + display_format: *const c_char, power: c_float) -> bool; + pub fn igSliderFloat2(label: *const c_char, v: *mut c_float, + v_min: c_float, v_max: c_float, + display_format: *const c_char, power: c_float) -> bool; + pub fn igSliderFloat3(label: *const c_char, v: *mut c_float, + v_min: c_float, v_max: c_float, + display_format: *const c_char, power: c_float) -> bool; + pub fn igSliderFloat4(label: *const c_char, v: *mut c_float, + v_min: c_float, v_max: c_float, + display_format: *const c_char, power: c_float) -> bool; + pub fn igSliderAngle(label: *const c_char, v_rad: *mut c_float, + v_degrees_min: c_float, v_degrees_max: c_float) -> bool; + pub fn igSliderInt(label: *const c_char, v: *mut c_int, + v_min: c_int, v_max: c_int, + display_format: *const c_char) -> bool; + pub fn igSliderInt2(label: *const c_char, v: *mut c_int, + v_min: c_int, v_max: c_int, + display_format: *const c_char) -> bool; + pub fn igSliderInt3(label: *const c_char, v: *mut c_int, + v_min: c_int, v_max: c_int, + display_format: *const c_char) -> bool; + pub fn igSliderInt4(label: *const c_char, v: *mut c_int, + v_min: c_int, v_max: c_int, + display_format: *const c_char) -> bool; + pub fn igVSliderFloat(label: *const c_char, size: ImVec2, v: *mut c_float, + v_min: c_float, v_max: c_float, + display_format: *const c_char, power: c_float) -> bool; + pub fn igVSliderInt(label: *const c_char, size: ImVec2, v: *mut c_int, + v_min: c_int, v_max: c_int, display_format: *const c_char) -> bool; +} + +// Widgets: Drags +extern "C" { + pub fn igDragFloat(label: *const c_char, v: *mut c_float, + v_speed: c_float, v_min: c_float, v_max: c_float, + display_format: *const c_char, power: c_float) -> bool; + pub fn igDragFloat2(label: *const c_char, v: *mut c_float, + v_speed: c_float, v_min: c_float, v_max: c_float, + display_format: *const c_char, power: c_float) -> bool; + pub fn igDragFloat3(label: *const c_char, v: *mut c_float, + v_speed: c_float, v_min: c_float, v_max: c_float, + display_format: *const c_char, power: c_float) -> bool; + pub fn igDragFloat4(label: *const c_char, v: *mut c_float, + v_speed: c_float, v_min: c_float, v_max: c_float, + display_format: *const c_char, power: c_float) -> bool; + pub fn igDragFloatRange2(label: *const c_char, + v_current_min: *mut c_float, v_current_max: *mut c_float, + v_speed: c_float, v_min: c_float, v_max: c_float, + display_format: *const c_char, display_format_max: *const c_char, + power: c_float) -> bool; + pub fn igDragInt(label: *const c_char, v: *mut c_int, + v_speed: c_float, v_min: c_int, v_max: c_int, + display_format: *const c_char) -> bool; + pub fn igDragInt2(label: *const c_char, v: *mut c_int, + v_speed: c_float, v_min: c_int, v_max: c_int, + display_format: *const c_char) -> bool; + pub fn igDragInt3(label: *const c_char, v: *mut c_int, + v_speed: c_float, v_min: c_int, v_max: c_int, + display_format: *const c_char) -> bool; + pub fn igDragInt4(label: *const c_char, v: *mut c_int, + v_speed: c_float, v_min: c_int, v_max: c_int, + display_format: *const c_char) -> bool; + pub fn igDragIntRange2(label: *const c_char, + v_current_min: *mut c_int, v_current_max: *mut c_int, + v_speed: c_float, v_min: c_int, v_max: c_int, + display_format: *const c_char, + display_format_max: *const c_char) -> bool; +} + +// Widgets: Input +extern "C" { + pub fn igInputText(label: *const c_char, buf: *mut c_char, + buf_size: size_t, flags: ImGuiInputTextFlags, + callback: ImGuiTextEditCallback, user_data: *mut c_void) -> bool; + pub fn igInputTextMultiline(label: *const c_char, + buf: *mut c_char, buf_size: size_t, + size: ImVec2, flags: ImGuiInputTextFlags, + callback: ImGuiTextEditCallback, user_data: *mut c_void) -> bool; + pub fn igInputFloat(label: *const c_char, v: *mut c_float, + step: c_float, step_fast: c_float, decimal_precision: c_int, + extra_flags: ImGuiInputTextFlags) -> bool; + pub fn igInputFloat2(label: *const c_char, v: *mut c_float, decimal_precision: c_int, + extra_flags: ImGuiInputTextFlags) -> bool; + pub fn igInputFloat3(label: *const c_char, v: *mut c_float, decimal_precision: c_int, + extra_flags: ImGuiInputTextFlags) -> bool; + pub fn igInputFloat4(label: *const c_char, v: *mut c_float, decimal_precision: c_int, + extra_flags: ImGuiInputTextFlags) -> bool; + pub fn igInputInt(label: *const c_char, v: *mut c_int, step: c_int, step_fast: c_int, + extra_flags: ImGuiInputTextFlags) -> bool; + pub fn igInputInt2(label: *const c_char, v: *mut c_int, + extra_flags: ImGuiInputTextFlags) -> bool; + pub fn igInputInt3(label: *const c_char, v: *mut c_int, + extra_flags: ImGuiInputTextFlags) -> bool; + pub fn igInputInt4(label: *const c_char, v: *mut c_int, + extra_flags: ImGuiInputTextFlags) -> bool; +} + +// Widgets: Trees +extern "C" { + pub fn igTreeNode(str_label_id: *const c_char) -> bool; + pub fn igTreeNodeStr(str_id: *const c_char, fmt: *const c_char, ...) -> bool; + pub fn igTreeNodePtr(ptr_id: *const c_void, fmt: *const c_char, ...) -> bool; + // pub fn igTreeNodeStrV(str_id: *const c_char, fmt: *const c_char, args: va_list) -> bool; + // pub fn igTreeNodePtrV(ptr_id: *const c_void, fmt: *const c_char, args: va_list) -> bool; + pub fn igTreePushStr(str_id: *const c_char); + pub fn igTreePushPtr(ptr_id: *const c_void); + pub fn igTreePop(); + pub fn igSetNextTreeNodeOpened(opened: bool, cond: ImGuiSetCond); +} + +// Widgets: Selectable / Lists +extern "C" { + pub fn igSelectable(label: *const c_char, selected: bool, + flags: ImGuiSelectableFlags, size: ImVec2) -> bool; + pub fn igSelectableEx(label: *const c_char, p_selected: *mut bool, + flags: ImGuiSelectableFlags, size: ImVec2) -> bool; + pub fn igListBox(label: *const c_char, current_item: *mut c_int, + items: *mut *const c_char, items_count: c_int, + height_in_items: c_int) -> bool; + pub fn igListBox2(label: *const c_char, current_item: *mut c_int, + items_getter: extern "C" fn(data: *mut c_void, + idx: c_int, + out_text: *mut *const c_char) -> bool, + data: *mut c_void, items_count: c_int, height_in_items: c_int) -> bool; + pub fn igListBoxHeader(label: *const c_char, size: ImVec2) -> bool; + pub fn igListBoxHeader2(label: *const c_char, items_count: c_int, + height_in_items: c_int) -> bool; + pub fn igListBoxFooter(); +} + +// Widgets: Value() Helpers +extern "C" { + pub fn igValueBool(prefix: *const c_char, b: bool); + pub fn igValueInt(prefix: *const c_char, v: c_int); + pub fn igValueUInt(prefix: *const c_char, v: c_uint); + pub fn igValueFloat(prefix: *const c_char, v: c_float, float_format: *const c_char); + pub fn igColor(prefix: *const c_char, v: ImVec4); + pub fn igColor2(prefix: *const c_char, v: c_uint); +} + +// Tooltip +extern "C" { + pub fn igSetTooltip(fmt: *const c_char, ...); + // pub fn igSetTooltipV(fmt: *const c_char, args: va_list); + pub fn igBeginTooltip(); + pub fn igEndTooltip(); +} + +// Widgets: Menus +extern "C" { + pub fn igBeginMainMenuBar() -> bool; + pub fn igEndMainMenuBar(); + pub fn igBeginMenuBar() -> bool; + pub fn igEndMenuBar(); + pub fn igBeginMenu(label: *const c_char, enabled: bool) -> bool; + pub fn igEndMenu(); + pub fn igMenuItem(label: *const c_char, shortcut: *const c_char, selected: bool, + enabled: bool) -> bool; + pub fn igMenuItemPtr(label: *const c_char, shortcut: *const c_char, p_selected: *mut bool, + enabled: bool) -> bool; +} + +// Popup +extern "C" { + pub fn igOpenPopup(str_id: *const c_char); + pub fn igBeginPopup(str_id: *const c_char) -> bool; + pub fn igBeginPopupModal(name: *const c_char, p_opened: *mut bool, + extra_flags: ImGuiWindowFlags) -> bool; + pub fn igBeginPopupContextItem(str_id: *const c_char, mouse_button: c_int) -> bool; + pub fn igBeginPopupContextWindow(also_over_items: bool, + str_id: *const c_char, mouse_button: c_int) -> bool; + pub fn igBeginPopupContextVoid(str_id: *const c_char, mouse_button: c_int) -> bool; + pub fn igEndPopup(); + pub fn igCloseCurrentPopup(); +} + +// Logging +extern "C" { + pub fn igLogToTTY(max_depth: c_int); + pub fn igLogToFile(max_depth: c_int, filename: *const c_char); + pub fn igLogToClipboard(max_depth: c_int); + pub fn igLogFinish(); + pub fn igLogButtons(); + pub fn igLogText(fmt: *const c_char, ...); +} + +// Utilities +extern "C" { + pub fn igIsItemHovered() -> bool; + pub fn igIsItemHoveredRect() -> bool; + pub fn igIsItemActive() -> bool; + pub fn igIsItemVisible() -> bool; + pub fn igIsAnyItemHovered() -> bool; + pub fn igIsAnyItemActive() -> bool; + pub fn igGetItemRectMin(out: *mut ImVec2); + pub fn igGetItemRectMax(out: *mut ImVec2); + pub fn igGetItemRectSize(out: *mut ImVec2); + pub fn igIsWindowHovered() -> bool; + pub fn igIsWindowFocused() -> bool; + pub fn igIsRootWindowFocused() -> bool; + pub fn igIsRootWindowOrAnyChildFocused() -> bool; + pub fn igIsRectVisible(pos: ImVec2) -> bool; + pub fn igGetTime() -> c_float; + pub fn igGetFrameCount() -> c_int; + pub fn igGetStyleColName(idx: ImGuiCol) -> *const c_char; + pub fn igCalcItemRectClosestPoint(out: *mut ImVec2, pos: ImVec2, + on_edge: bool, outward: c_float); + pub fn igCalcTextSize(out: *mut ImVec2, text: *const c_char, text_end: *const c_char, + hide_text_after_double_hash: bool, wrap_width: c_float); + pub fn igCalcListClipping(items_count: c_int, items_height: c_float, + out_items_display_start: *mut c_int, + out_items_display_end: *mut c_int); + + pub fn igBeginChildFrame(id: ImGuiID, size: ImVec2) -> bool; + pub fn igEndChildFrame(); + + pub fn igColorConvertFloat4ToU32(color: ImVec4) -> ImU32; + pub fn igColorConvertRGBtoHSV(r: c_float, g: c_float, b: c_float, + out_h: *mut c_float, out_s: *mut c_float, out_v: *mut c_float); + pub fn igColorConvertHSVtoRGB(h: c_float, s: c_float, v: c_float, + out_r: *mut c_float, out_g: *mut c_float, out_b: *mut c_float); + + pub fn igIsKeyDown(key_index: c_int) -> bool; + pub fn igIsKeyPressed(key_index: c_int, repeat: bool) -> bool; + pub fn igIsKeyReleased(key_index: c_int) -> bool; + pub fn igIsMouseDown(button: c_int) -> bool; + pub fn igIsMouseClicked(button: c_int, repeat: bool) -> bool; + pub fn igIsMouseDoubleClicked(button: c_int) -> bool; + pub fn igIsMouseReleased(button: c_int) -> bool; + pub fn igIsMouseHoveringWindow() -> bool; + pub fn igIsMouseHoveringAnyWindow() -> bool; + pub fn igIsMouseHoveringRect(rect_min: ImVec2, rect_max: ImVec2) -> bool; + pub fn igIsMouseDragging(button: c_int, lock_threshold: c_float) -> bool; + pub fn igGetMousePos(out: *mut ImVec2); + pub fn igGetMouseDragDelta(out: *mut ImVec2, button: c_int, lock_threshold: c_float); + pub fn igResetMouseDragDelta(button: c_int); + pub fn igGetMouseCursor() -> ImGuiMouseCursor; + pub fn igSetMouseCursor(cursor: ImGuiMouseCursor); +} + +// Internal state access +extern "C" { + pub fn igGetVersion() -> *const c_char; + pub fn igGetInternalState() -> *mut c_void; + pub fn igGetInternalStateSize() -> size_t; + pub fn igSetInternalState(state: *mut c_void, construct: bool); +} + +extern "C" { + pub fn ImFontAtlas_GetTexDataAsRGBA32(atlas: *mut ImFontAtlas, + out_pixels: *mut *mut c_uchar, + out_width: *mut c_int, out_height: *mut c_int, + out_bytes_per_pixel: *mut c_int); + pub fn ImFontAtlas_GetTexDataAsAlpha8(atlas: *mut ImFontAtlas, + out_pixels: *mut *mut c_uchar, + out_width: *mut c_int, out_height: *mut c_int, + out_bytes_per_pixel: *mut c_int); + pub fn ImFontAtlas_SetTexID(atlas: *mut ImFontAtlas, tex: *mut c_void); + pub fn ImFontAtlas_AddFont(atlas: *mut ImFontAtlas, + font_cfg: *const ImFontConfig) -> *mut ImFont; + pub fn ImFontAtlas_AddFontDefault(atlas: *mut ImFontAtlas, + font_cfg: *const ImFontConfig) -> *mut ImFont; + pub fn ImFontAtlas_AddFontFromFileTTF(atlas: *mut ImFontAtlas, + filename: *const c_char, + size_pixels: c_float, + font_cfg: *const ImFontConfig, + glyph_ranges: *const ImWchar) -> *mut ImFont; + pub fn ImFontAtlas_AddFontFromMemoryTTF(atlas: *mut ImFontAtlas, + ttf_data: *mut c_void, + ttf_size: c_int, + size_pixels: c_float, + font_cfg: *const ImFontConfig, + glyph_ranges: *const ImWchar) -> *mut ImFont; + pub fn ImFontAtlas_AddFontFromMemoryCompressedTTF(atlas: *mut ImFontAtlas, + compressed_ttf_data: *const c_void, + compressed_ttf_size: c_int, + size_pixels: c_float, + font_cfg: *const ImFontConfig, + glyph_ranges: *const ImWchar) -> *mut ImFont; + pub fn ImFontAtlas_AddFontFromMemoryCompressedBase85TTF( + atlas: *mut ImFontAtlas, + compressed_ttf_data_base85: *const c_char, + size_pixels: c_float, + font_cfg: *const ImFontConfig, + glyph_ranges: *const ImWchar) -> *mut ImFont; + pub fn ImFontAtlas_ClearTexData(atlas: *mut ImFontAtlas); + pub fn ImFontAtlas_Clear(atlas: *mut ImFontAtlas); + pub fn ImGuiIO_AddInputCharacter(c: c_ushort); + pub fn ImGuiIO_AddInputCharactersUTF8(utf8_chars: *const c_char); + pub fn ImDrawList_GetVertexBufferSize(list: *mut ImDrawList) -> c_int; + pub fn ImDrawList_GetVertexPtr(list: *mut ImDrawList, n: c_int) -> *mut ImDrawVert; + pub fn ImDrawList_GetIndexBufferSize(list: *mut ImDrawList) -> c_int; + pub fn ImDrawList_GetIndexPtr(list: *mut ImDrawList, n: c_int) -> *mut ImDrawIdx; + pub fn ImDrawList_GetCmdSize(list: *mut ImDrawList) -> c_int; + pub fn ImDrawList_GetCmdPtr(list: *mut ImDrawList, n: c_int) -> *mut ImDrawCmd; + pub fn ImDrawData_DeIndexAllBuffers(drawData: *mut ImDrawData); +} diff --git a/src/glium_renderer.rs b/src/glium_renderer.rs new file mode 100644 index 0000000..8288cf5 --- /dev/null +++ b/src/glium_renderer.rs @@ -0,0 +1,209 @@ +use glium::{ + index, program, texture, vertex, + DrawError, DrawParameters, IndexBuffer, Program, Rect, Surface, Texture2d, VertexBuffer +}; +use glium::backend::{Context, Facade}; +use glium::draw_parameters::{BlendingFunction, LinearBlendingFactor}; +use glium::index::PrimitiveType; +use glium::texture::{ClientFormat, RawImage2d}; +use glium::vertex::{Attribute, AttributeType, Vertex, VertexFormat}; +use libc::c_float; +use std::borrow::Cow; +use std::mem; +use std::rc::Rc; + +use super::{DrawList, Frame, ImDrawIdx, ImDrawVert, ImGui, ImVec2, ImVec4}; + +pub type RendererResult = Result; + +pub enum RendererError { + Vertex(vertex::BufferCreationError), + Index(index::BufferCreationError), + Program(program::ProgramCreationError), + Texture(texture::TextureCreationError), + Draw(DrawError) +} + +impl From for RendererError { + fn from(e: vertex::BufferCreationError) -> RendererError { + RendererError::Vertex(e) + } +} + +impl From for RendererError { + fn from(e: index::BufferCreationError) -> RendererError { + RendererError::Index(e) + } +} + +impl From for RendererError { + fn from(e: program::ProgramCreationError) -> RendererError { + RendererError::Program(e) + } +} + +impl From for RendererError { + fn from(e: texture::TextureCreationError) -> RendererError { + RendererError::Texture(e) + } +} + +impl From for RendererError { + fn from(e: DrawError) -> RendererError { + RendererError::Draw(e) + } +} + +unsafe impl Attribute for ImVec2 { + fn get_type() -> AttributeType { <(c_float, c_float) as Attribute>::get_type() } +} + +unsafe impl Attribute for ImVec4 { + fn get_type() -> AttributeType { + <(c_float, c_float, c_float, c_float) as Attribute>::get_type() + } +} + +impl Vertex for ImDrawVert { + fn build_bindings() -> VertexFormat { + unsafe { + let dummy: &ImDrawVert = mem::transmute(0usize); + Cow::Owned(vec![ + ("pos".into(), mem::transmute(&dummy.pos), ::get_type()), + ("uv".into(), mem::transmute(&dummy.uv), ::get_type()), + ("col".into(), mem::transmute(&dummy.col), AttributeType::U8U8U8U8) + ]) + } + } +} + +pub struct Renderer { + ctx: Rc, + device_objects: DeviceObjects +} + +impl Renderer { + pub fn init(imgui: &mut ImGui, ctx: &F) -> RendererResult { + let device_objects = try!(DeviceObjects::init(imgui, ctx)); + Ok(Renderer { + ctx: ctx.get_context().clone(), + device_objects: device_objects + }) + } + pub fn render<'a, S: Surface>(&mut self, surface: &mut S, + frame: Frame<'a>) -> RendererResult<()> { + frame.render(|draw_list| self.render_draw_list(surface, draw_list)) + } + fn render_draw_list<'a, S: Surface>(&mut self, surface: &mut S, + draw_list: DrawList<'a>) -> RendererResult<()> { + try!(self.device_objects.upload_vertex_buffer(&self.ctx, draw_list.vtx_buffer)); + try!(self.device_objects.upload_index_buffer(&self.ctx, draw_list.idx_buffer)); + + let (width, height) = surface.get_dimensions(); + + let mut idx_start = 0; + for cmd in draw_list.cmd_buffer { + let matrix = [ + [ 2.0 / (width as f32), 0.0, 0.0, 0.0 ], + [ 0.0, 2.0 / -(height as f32), 0.0, 0.0 ], + [ 0.0, 0.0, -1.0, 0.0 ], + [ -1.0, 1.0, 0.0, 1.0 ] + ]; + let uniforms = uniform! { + matrix: matrix, + texture: self.device_objects.texture.sampled() + }; + let draw_params = DrawParameters { + blending_function: Some(BlendingFunction::Addition { + source: LinearBlendingFactor::SourceAlpha, + destination: LinearBlendingFactor::OneMinusSourceAlpha + }), + scissor: Some(Rect { + left: cmd.clip_rect.x as u32, + bottom: (height as f32 - cmd.clip_rect.w) as u32, + width: (cmd.clip_rect.z - cmd.clip_rect.x) as u32, + height: (cmd.clip_rect.w - cmd.clip_rect.y) as u32 + }), + .. Default::default() + }; + let idx_end = idx_start + cmd.elem_count as usize; + try!(surface.draw(&self.device_objects.vertex_buffer, + &self.device_objects.index_buffer.slice(idx_start ..idx_end) + .expect("Invalid index buffer range"), + &self.device_objects.program, + &uniforms, + &draw_params)); + idx_start = idx_end; + } + Ok(()) + } +} + +pub struct DeviceObjects { + vertex_buffer: VertexBuffer, + index_buffer: IndexBuffer, + program: Program, + texture: Texture2d +} + +fn compile_default_program(ctx: &F) -> Result { + program!( + ctx, + 140 => { + vertex: include_str!("shader/vert_140.glsl"), + fragment: include_str!("shader/frag_140.glsl"), + outputs_srgb: true + }, + 110 => { + vertex: include_str!("shader/vert_110.glsl"), + fragment: include_str!("shader/frag_110.glsl"), + outputs_srgb: true + } + ) +} + +impl DeviceObjects { + pub fn init(im_gui: &mut ImGui, ctx: &F) -> RendererResult { + let vertex_buffer = try!(VertexBuffer::empty_dynamic(ctx, 0)); + let index_buffer = try!(IndexBuffer::empty_dynamic(ctx, PrimitiveType::TrianglesList, 0)); + + let program = try!(compile_default_program(ctx)); + let texture = try!(im_gui.prepare_texture(|handle| { + let data = RawImage2d { + data: Cow::Borrowed(handle.pixels), + width: handle.width, + height: handle.height, + format: ClientFormat::U8U8U8U8 + }; + Texture2d::new(ctx, data) + })); + + Ok(DeviceObjects { + vertex_buffer: vertex_buffer, + index_buffer: index_buffer, + program: program, + texture: texture + }) + } + pub fn upload_vertex_buffer(&mut self, ctx: &F, + vtx_buffer: &[ImDrawVert]) -> RendererResult<()> { + self.vertex_buffer.invalidate(); + if let Some(slice) = self.vertex_buffer.slice_mut(0 .. vtx_buffer.len()) { + slice.write(vtx_buffer); + return Ok(()); + } + self.vertex_buffer = try!(VertexBuffer::dynamic(ctx, vtx_buffer)); + Ok(()) + } + pub fn upload_index_buffer(&mut self, ctx: &F, + idx_buffer: &[ImDrawIdx]) -> RendererResult<()> { + self.index_buffer.invalidate(); + if let Some(slice) = self.index_buffer.slice_mut(0 .. idx_buffer.len()) { + slice.write(idx_buffer); + return Ok(()); + } + self.index_buffer = + try!(IndexBuffer::dynamic(ctx, PrimitiveType::TrianglesList, idx_buffer)); + Ok(()) + } +} diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..d8e1367 --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,147 @@ +#[macro_use] +extern crate bitflags; + +#[cfg(feature = "glium")] +#[macro_use] +extern crate glium; + +extern crate libc; + +#[cfg(feature = "sdl2")] +extern crate sdl2; + +use libc::{c_float, c_int, c_uchar}; +use std::marker::PhantomData; +use std::mem; +use std::ptr; +use std::slice; + +pub use ffi::{ImDrawIdx, ImDrawVert, ImVec2, ImVec4}; + +pub mod ffi; + +#[cfg(feature = "glium")] +pub mod glium_renderer; + +pub struct ImGui; + +pub struct TextureHandle<'a> { + pub width: u32, + pub height: u32, + pub pixels: &'a [c_uchar] +} + +impl ImGui { + pub fn init() -> ImGui { + let io: &mut ffi::ImGuiIO = unsafe { mem::transmute(ffi::igGetIO()) }; + io.render_draw_lists_fn = Some(render_draw_lists); + + ImGui + } + pub fn prepare_texture<'a, F, T>(&mut self, f: F) -> T where F: FnOnce(TextureHandle<'a>) -> T { + let io: &mut ffi::ImGuiIO = unsafe { mem::transmute(ffi::igGetIO()) }; + let mut pixels: *mut c_uchar = ptr::null_mut(); + let mut width: c_int = 0; + let mut height: c_int = 0; + let mut bytes_per_pixel: c_int = 0; + unsafe { + ffi::ImFontAtlas_GetTexDataAsRGBA32(io.fonts, &mut pixels, &mut width, &mut height, &mut bytes_per_pixel); + f(TextureHandle { + width: width as u32, + height: height as u32, + pixels: slice::from_raw_parts(pixels, (width * height * bytes_per_pixel) as usize) + }) + } + } + pub fn draw_mouse_cursor(&mut self, value: bool) { + let io: &mut ffi::ImGuiIO = unsafe { mem::transmute(ffi::igGetIO()) }; + io.mouse_draw_cursor = value; + } + #[cfg(feature = "sdl2")] + pub fn update_mouse(&mut self, mouse: &::sdl2::mouse::MouseUtil) { + let (mouse_state, mouse_x, mouse_y) = mouse.get_mouse_state(); + let io: &mut ffi::ImGuiIO = unsafe { mem::transmute(ffi::igGetIO()) }; + io.mouse_pos.x = mouse_x as f32; + io.mouse_pos.y = mouse_y as f32; + io.mouse_down = [ + mouse_state.left(), + mouse_state.right(), + mouse_state.middle(), + mouse_state.x1(), + mouse_state.x2() + ]; + } + pub fn frame<'a>(&'a mut self, width: u32, height: u32, delta_time: f32) -> Frame<'a> { + unsafe { + let io: &mut ffi::ImGuiIO = mem::transmute(ffi::igGetIO()); + io.display_size.x = width as c_float; + io.display_size.y = height as c_float; + io.delta_time = delta_time; + + ffi::igNewFrame(); + } + Frame { + _phantom: PhantomData + } + } +} + +impl Drop for ImGui { + fn drop(&mut self) { + unsafe { + ffi::igShutdown(); + } + } +} + +pub struct DrawList<'a> { + pub cmd_buffer: &'a [ffi::ImDrawCmd], + pub idx_buffer: &'a [ffi::ImDrawIdx], + pub vtx_buffer: &'a [ffi::ImDrawVert] +} + +pub struct Frame<'a> { + _phantom: PhantomData<&'a ImGui> +} + +impl<'a> Frame<'a> { + pub fn show_test_window(&mut self) -> bool { + let mut opened = true; + unsafe { + ffi::igShowTestWindow(&mut opened); + } + opened + } + pub fn render(self, mut f: F) -> Result<(), E> + where F: FnMut(DrawList<'a>) -> Result<(), E> { + unsafe { + let mut im_draw_data = mem::zeroed(); + RENDER_DRAW_LISTS_STATE.0 = &mut im_draw_data; + ffi::igRender(); + RENDER_DRAW_LISTS_STATE.0 = 0 as *mut ffi::ImDrawData; + + for &cmd_list in im_draw_data.cmd_lists() { + let draw_list = + DrawList { + cmd_buffer: (*cmd_list).cmd_buffer.as_slice(), + idx_buffer: (*cmd_list).idx_buffer.as_slice(), + vtx_buffer: (*cmd_list).vtx_buffer.as_slice() + }; + try!(f(draw_list)); + } + } + Ok(()) + } +} + +struct RenderDrawListsState(*mut ffi::ImDrawData); +unsafe impl Sync for RenderDrawListsState {} + +static mut RENDER_DRAW_LISTS_STATE: RenderDrawListsState = + RenderDrawListsState(0 as *mut ffi::ImDrawData); + +extern "C" fn render_draw_lists(data: *mut ffi::ImDrawData) { + unsafe { + ptr::copy_nonoverlapping(data, RENDER_DRAW_LISTS_STATE.0, 1); + } +} diff --git a/src/shader/frag_110.glsl b/src/shader/frag_110.glsl new file mode 100644 index 0000000..8bdec78 --- /dev/null +++ b/src/shader/frag_110.glsl @@ -0,0 +1,10 @@ +#version 110 + +uniform sampler2D tex; + +varying vec2 f_uv; +varying vec4 f_color; + +void main() { + gl_FragColor = f_color * texture2D(tex, f_uv.st); +} diff --git a/src/shader/frag_140.glsl b/src/shader/frag_140.glsl new file mode 100644 index 0000000..c28c2d8 --- /dev/null +++ b/src/shader/frag_140.glsl @@ -0,0 +1,12 @@ +#version 140 + +uniform sampler2D tex; + +in vec2 f_uv; +in vec4 f_color; + +out vec4 out_color; + +void main() { + out_color = f_color * texture(tex, f_uv.st); +} diff --git a/src/shader/vert_110.glsl b/src/shader/vert_110.glsl new file mode 100644 index 0000000..156ad93 --- /dev/null +++ b/src/shader/vert_110.glsl @@ -0,0 +1,16 @@ +#version 110 + +uniform mat4 matrix; + +attribute vec2 pos; +attribute vec2 uv; +attribute vec4 col; + +varying vec2 f_uv; +varying vec4 f_color; + +void main() { + f_uv = uv; + f_color = col / 255.0; + gl_Position = matrix * vec4(pos.xy, 0, 1); +} diff --git a/src/shader/vert_140.glsl b/src/shader/vert_140.glsl new file mode 100644 index 0000000..8bb556a --- /dev/null +++ b/src/shader/vert_140.glsl @@ -0,0 +1,16 @@ +#version 140 + +uniform mat4 matrix; + +in vec2 pos; +in vec2 uv; +in vec4 col; + +out vec2 f_uv; +out vec4 f_color; + +void main() { + f_uv = uv; + f_color = col / 255.0; + gl_Position = matrix * vec4(pos.xy, 0, 1); +} diff --git a/third-party/cimgui b/third-party/cimgui new file mode 160000 index 0000000..5d061e7 --- /dev/null +++ b/third-party/cimgui @@ -0,0 +1 @@ +Subproject commit 5d061e7db70f85caa8fa2d6c96263ebe724eff88