Skip to content
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

Implementation of UI wrapper #7

Merged
merged 15 commits into from
Aug 21, 2019
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 38 additions & 17 deletions src/imgui_renderer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ use std::mem;
use imgui;
use imgui::internal::RawWrapper;
yanchith marked this conversation as resolved.
Show resolved Hide resolved

use crate::include_shader;

#[derive(Debug, Clone)]
pub enum ImguiRendererError {
BadTexture(imgui::TextureId),
Expand All @@ -19,8 +21,6 @@ pub struct ImguiRenderer {
}

impl ImguiRenderer {
const DRAW_VERT_SIZE: usize = mem::size_of::<imgui::DrawVert>();

pub fn new(
imgui: &mut imgui::Context,
device: &mut wgpu::Device,
Expand All @@ -29,15 +29,16 @@ impl ImguiRenderer {
) -> Result<ImguiRenderer, ImguiRendererError> {
// Link shaders

let vs_spv = include_bytes!(concat!(env!("OUT_DIR"), "/shaders/imgui.vert.spv"));
let fs_spv = include_bytes!(concat!(env!("OUT_DIR"), "/shaders/imgui.frag.spv"));
let vs_spv = include_shader!("imgui.vert.spv");
let fs_spv = include_shader!("imgui.frag.spv");
let vs_module = device.create_shader_module(vs_spv);
let fs_module = device.create_shader_module(fs_spv);

// Create ortho projection matrix uniform buffer, layout and bind group

let uniform_buffer_size = wgpu_size_of::<TransformUniforms>();
let uniform_buffer = device.create_buffer(&wgpu::BufferDescriptor {
size: UNIFORM_BUFFER_SIZE,
size: uniform_buffer_size,
// FIXME(yanchith): `TRANSFER_DST` is required because the
// only way to upload the buffer currently is by issueing
// the transfer command in `upload_buffer_immediate`. We
Expand All @@ -60,7 +61,7 @@ impl ImguiRenderer {
binding: 0,
resource: wgpu::BindingResource::Buffer {
buffer: &uniform_buffer,
range: 0..UNIFORM_BUFFER_SIZE,
range: 0..uniform_buffer_size,
},
}],
});
Expand Down Expand Up @@ -129,7 +130,8 @@ impl ImguiRenderer {
depth_stencil_state: None,
index_format: wgpu::IndexFormat::Uint16, // FIXME(yanchith): may need 32bit indices!
yanchith marked this conversation as resolved.
Show resolved Hide resolved
vertex_buffers: &[wgpu::VertexBufferDescriptor {
stride: u64::try_from(Self::DRAW_VERT_SIZE).unwrap(),
stride: u64::try_from(wgpu_size_of::<imgui::DrawVert>())
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Redundant try_from, wgpu_size_of already returns u64 (type aliased as wgpu::BufferAddress)

.expect("Should convert size of draw vert to u64"),
step_mode: wgpu::InputStepMode::Vertex,
attributes: &[
wgpu::VertexAttributeDescriptor {
Expand Down Expand Up @@ -167,7 +169,7 @@ impl ImguiRenderer {
sample_count: 1,
dimension: wgpu::TextureDimension::D2,
format: wgpu::TextureFormat::Rgba8Unorm,
usage: wgpu::TextureUsage::SAMPLED,
usage: wgpu::TextureUsage::SAMPLED | wgpu::TextureUsage::TRANSFER_DST,
});

upload_texture_immediate(
Expand Down Expand Up @@ -201,6 +203,8 @@ impl ImguiRenderer {
height: u32,
data: &[u8],
yanchith marked this conversation as resolved.
Show resolved Hide resolved
) -> imgui::TextureId {
assert_eq!(data.len() % 4, 0);

let texture = device.create_texture(&wgpu::TextureDescriptor {
size: wgpu::Extent3d {
width,
Expand All @@ -212,7 +216,7 @@ impl ImguiRenderer {
sample_count: 1,
dimension: wgpu::TextureDimension::D2,
format: wgpu::TextureFormat::Rgba8Unorm,
usage: wgpu::TextureUsage::SAMPLED,
usage: wgpu::TextureUsage::SAMPLED | wgpu::TextureUsage::TRANSFER_DST,
});

upload_texture_immediate(device, &texture, width, height, data);
Expand Down Expand Up @@ -270,7 +274,7 @@ impl ImguiRenderer {
upload_buffer_immediate(
device,
&self.uniform_buffer,
&[translate[0], translate[1], scale[0], scale[1]],
TransformUniforms { translate, scale },
);

// Will project scissor/clipping rectangles into framebuffer space
Expand Down Expand Up @@ -423,15 +427,26 @@ impl Texture {
}
}

fn upload_buffer_immediate(device: &mut wgpu::Device, buffer: &wgpu::Buffer, data: &[f32]) {
let count = data.len();
#[repr(C)]
#[derive(Debug, Clone, Copy)]
struct TransformUniforms {
translate: [f32; 2],
scale: [f32; 2],
}

fn upload_buffer_immediate(
device: &mut wgpu::Device,
buffer: &wgpu::Buffer,
transform_uniforms: TransformUniforms,
) {
let transform_uniforms_size = wgpu_size_of::<TransformUniforms>();
let source_buffer = device
.create_buffer_mapped(count, wgpu::BufferUsage::TRANSFER_SRC)
.fill_from_slice(data);
.create_buffer_mapped(1, wgpu::BufferUsage::TRANSFER_SRC)
.fill_from_slice(&[transform_uniforms]);

let mut encoder = device.create_command_encoder(&wgpu::CommandEncoderDescriptor { todo: 0 });

encoder.copy_buffer_to_buffer(&source_buffer, 0, buffer, 0, UNIFORM_BUFFER_SIZE);
encoder.copy_buffer_to_buffer(&source_buffer, 0, buffer, 0, transform_uniforms_size);

device.get_queue().submit(&[encoder.finish()]);
}
Expand All @@ -450,7 +465,9 @@ fn upload_texture_immediate(

let mut encoder = device.create_command_encoder(&wgpu::CommandEncoderDescriptor { todo: 0 });

let pixel_size = u32::try_from(count).unwrap() / width / height;
let count = u32::try_from(count).expect("Should convert texture data length to u32");
let pixel_size = count / width / height;

encoder.copy_buffer_to_texture(
wgpu::BufferCopyView {
buffer: &buffer,
Expand Down Expand Up @@ -492,4 +509,8 @@ fn create_sampler(device: &wgpu::Device) -> wgpu::Sampler {
})
}

const UNIFORM_BUFFER_SIZE: u64 = 16;
fn wgpu_size_of<T>() -> wgpu::BufferAddress {
let size = mem::size_of::<T>();
wgpu::BufferAddress::try_from(size)
.unwrap_or_else(|_| panic!("Size {} does not fit into wgpu BufferAddress", size))
}
1 change: 1 addition & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,6 @@ pub mod imgui_renderer;
pub mod importer;
pub mod input;
pub mod primitives;
pub mod shader;
pub mod ui;
pub mod viewport_renderer;
46 changes: 36 additions & 10 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use hurban_selector::imgui_renderer::ImguiRenderer;
use hurban_selector::importer::Importer;
use hurban_selector::input::InputManager;
use hurban_selector::primitives;
use hurban_selector::ui::{self, Ui};
use hurban_selector::ui;
use hurban_selector::viewport_renderer::{Geometry, ViewportRenderer};

const SWAP_CHAIN_FORMAT: wgpu::TextureFormat = wgpu::TextureFormat::Bgra8Unorm;
Expand Down Expand Up @@ -83,9 +83,9 @@ fn main() {

let mut dynamic_models = Vec::new();

let mut ui = Ui::new(&window);
let (mut imgui_context, mut winit_platform) = ui::init(&window);
let mut imgui_renderer = ImguiRenderer::new(
ui.context(),
&mut imgui_context,
&mut device,
wgpu::TextureFormat::Bgra8Unorm,
None,
Expand All @@ -105,14 +105,41 @@ fn main() {
let duration_running = now.duration_since(time_start);
time = now;

let duration_last_frame_s = duration_last_frame.as_secs() as f32
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can leave a FIXME here to change to https://doc.rust-lang.org/std/time/struct.Duration.html#method.as_secs_f32 when it stabilizes in 1.38.0

+ duration_last_frame.subsec_nanos() as f32 / 1_000_000_000.0;

imgui_context.io_mut().delta_time = duration_last_frame_s;

(duration_last_frame, duration_running)
};

input_manager.start_frame();
// Since input manager needs to process events separately after imgui
// handles them, this buffer with copies of events is needed.
let mut input_events = vec![];

event_loop.poll_events(|event| {
let (ui_captured_keyboard, ui_captured_mouse) = ui.process_event(&event);
input_manager.process_event(event, ui_captured_keyboard, ui_captured_mouse);
input_events.push(event.clone());
winit_platform.handle_event(imgui_context.io_mut(), &window, &event);
});

// Start UI and input manger frames
winit_platform
.prepare_frame(imgui_context.io_mut(), &window)
.expect("Failed to start imgui frame");
let imgui_ui = imgui_context.frame();
let imgui_ui_io = imgui_ui.io();

input_manager.start_frame();

// Imgui's IO is updated after current frame starts, else it'd contain
// outdated values.
let ui_captured_keyboard = imgui_ui_io.want_capture_keyboard;
let ui_captured_mouse = imgui_ui_io.want_capture_mouse;

for event in input_events {
input_manager.process_event(event, ui_captured_keyboard, ui_captured_mouse);
}

let input_state = input_manager.input_state();

let [pan_ground_x, pan_ground_y] = input_state.camera_pan_ground;
Expand Down Expand Up @@ -190,11 +217,10 @@ fn main() {
&camera.view_matrix(),
);

time = ui.update_delta_time(time);
ui::draw_fps_window(&imgui_ui);

let imgui_draw_data = ui.create(|imgui_ui| {
ui::draw_fps_window(imgui_ui);
});
winit_platform.prepare_render(&imgui_ui, &window);
let imgui_draw_data = imgui_ui.render();

let frame = swap_chain.get_next_texture();
let mut encoder =
Expand Down
6 changes: 6 additions & 0 deletions src/shader.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#[macro_export]
macro_rules! include_shader {
($name:expr) => {{
include_bytes!(concat!(env!("OUT_DIR"), "/shaders/", $name))
}};
}
12 changes: 6 additions & 6 deletions src/shaders/imgui.frag
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
#version 450

layout(set = 1, binding = 0) uniform texture2D u_Texture;
layout(set = 1, binding = 1) uniform sampler u_Sampler;
layout(set = 1, binding = 0) uniform texture2D u_texture;
layout(set = 1, binding = 1) uniform sampler u_sampler;

layout(location = 0) in vec2 v_UV;
layout(location = 1) in vec4 v_Color;
layout(location = 0) in vec2 v_tex_coords;
layout(location = 1) in vec4 v_color;

layout(location = 0) out vec4 o_Target;
layout(location = 0) out vec4 o_color;

void main() {
o_Target = v_Color * texture(sampler2D(u_Texture, u_Sampler), v_UV);
o_color = v_color * texture(sampler2D(u_texture, u_sampler), v_tex_coords);
}
26 changes: 13 additions & 13 deletions src/shaders/imgui.vert
Original file line number Diff line number Diff line change
@@ -1,22 +1,22 @@
#version 450

layout(set = 0, binding = 0) uniform Transform {
vec2 u_Translate;
vec2 u_Scale;
vec2 u_translate;
vec2 u_scale;
};

layout(location = 0) in vec2 a_Pos;
layout(location = 1) in vec2 a_UV;
layout(location = 2) in uint a_Color;
layout(location = 0) in vec2 a_pos;
layout(location = 1) in vec2 a_tex_coords;
layout(location = 2) in uint a_color;

layout(location = 0) out vec2 v_UV;
layout(location = 1) out vec4 v_Color;
layout(location = 0) out vec2 v_tex_coords;
layout(location = 1) out vec4 v_color;

void main() {
v_UV = a_UV;
v_Color = vec4(a_Color & 0xFF,
(a_Color >> 8) & 0xFF,
(a_Color >> 16) & 0xFF,
(a_Color >> 24) & 0xFF) / 255.0;
gl_Position = vec4(a_Pos.xy * u_Scale + u_Translate, 0.0, 1.0);
v_tex_coords = a_tex_coords;
v_color = vec4(a_color & 0xFF,
(a_color >> 8) & 0xFF,
(a_color >> 16) & 0xFF,
(a_color >> 24) & 0xFF) / 255.0;
gl_Position = vec4(a_pos.xy * u_scale + u_translate, 0.0, 1.0);
}
Loading