mirror of
https://github.com/eliasstepanik/imgui-rs.git
synced 2026-01-11 21:48:36 +00:00
Initial commit
This commit is contained in:
commit
ad10dff1cf
4
.gitignore
vendored
Normal file
4
.gitignore
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
*~
|
||||
*.swp
|
||||
/target
|
||||
/Cargo.lock
|
||||
3
.gitmodules
vendored
Normal file
3
.gitmodules
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
[submodule "third-party/cimgui"]
|
||||
path = third-party/cimgui
|
||||
url = https://github.com/Extrawurst/cimgui.git
|
||||
24
Cargo.toml
Normal file
24
Cargo.toml
Normal file
@ -0,0 +1,24 @@
|
||||
[package]
|
||||
name = "imgui-rs"
|
||||
version = "0.0.1"
|
||||
authors = ["Joonas Javanainen <joonas.javanainen@gmail.com>"]
|
||||
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"
|
||||
21
LICENSE
Normal file
21
LICENSE
Normal file
@ -0,0 +1,21 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2015 Joonas Javanainen <joonas.javanainen@gmail.com>
|
||||
|
||||
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.
|
||||
9
README.markdown
Normal file
9
README.markdown
Normal file
@ -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).
|
||||
13
build.rs
Normal file
13
build.rs
Normal file
@ -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");
|
||||
}
|
||||
1008
src/ffi.rs
Normal file
1008
src/ffi.rs
Normal file
File diff suppressed because it is too large
Load Diff
209
src/glium_renderer.rs
Normal file
209
src/glium_renderer.rs
Normal file
@ -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<T> = Result<T, RendererError>;
|
||||
|
||||
pub enum RendererError {
|
||||
Vertex(vertex::BufferCreationError),
|
||||
Index(index::BufferCreationError),
|
||||
Program(program::ProgramCreationError),
|
||||
Texture(texture::TextureCreationError),
|
||||
Draw(DrawError)
|
||||
}
|
||||
|
||||
impl From<vertex::BufferCreationError> for RendererError {
|
||||
fn from(e: vertex::BufferCreationError) -> RendererError {
|
||||
RendererError::Vertex(e)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<index::BufferCreationError> for RendererError {
|
||||
fn from(e: index::BufferCreationError) -> RendererError {
|
||||
RendererError::Index(e)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<program::ProgramCreationError> for RendererError {
|
||||
fn from(e: program::ProgramCreationError) -> RendererError {
|
||||
RendererError::Program(e)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<texture::TextureCreationError> for RendererError {
|
||||
fn from(e: texture::TextureCreationError) -> RendererError {
|
||||
RendererError::Texture(e)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<DrawError> 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), <ImVec2 as Attribute>::get_type()),
|
||||
("uv".into(), mem::transmute(&dummy.uv), <ImVec2 as Attribute>::get_type()),
|
||||
("col".into(), mem::transmute(&dummy.col), AttributeType::U8U8U8U8)
|
||||
])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Renderer {
|
||||
ctx: Rc<Context>,
|
||||
device_objects: DeviceObjects
|
||||
}
|
||||
|
||||
impl Renderer {
|
||||
pub fn init<F: Facade>(imgui: &mut ImGui, ctx: &F) -> RendererResult<Renderer> {
|
||||
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<ImDrawVert>,
|
||||
index_buffer: IndexBuffer<ImDrawIdx>,
|
||||
program: Program,
|
||||
texture: Texture2d
|
||||
}
|
||||
|
||||
fn compile_default_program<F: Facade>(ctx: &F) -> Result<Program, program::ProgramCreationError> {
|
||||
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<F: Facade>(im_gui: &mut ImGui, ctx: &F) -> RendererResult<DeviceObjects> {
|
||||
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<F: Facade>(&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<F: Facade>(&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(())
|
||||
}
|
||||
}
|
||||
147
src/lib.rs
Normal file
147
src/lib.rs
Normal file
@ -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<F, E>(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);
|
||||
}
|
||||
}
|
||||
10
src/shader/frag_110.glsl
Normal file
10
src/shader/frag_110.glsl
Normal file
@ -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);
|
||||
}
|
||||
12
src/shader/frag_140.glsl
Normal file
12
src/shader/frag_140.glsl
Normal file
@ -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);
|
||||
}
|
||||
16
src/shader/vert_110.glsl
Normal file
16
src/shader/vert_110.glsl
Normal file
@ -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);
|
||||
}
|
||||
16
src/shader/vert_140.glsl
Normal file
16
src/shader/vert_140.glsl
Normal file
@ -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);
|
||||
}
|
||||
1
third-party/cimgui
vendored
Submodule
1
third-party/cimgui
vendored
Submodule
@ -0,0 +1 @@
|
||||
Subproject commit 5d061e7db70f85caa8fa2d6c96263ebe724eff88
|
||||
Loading…
x
Reference in New Issue
Block a user