implement ui

This commit is contained in:
John Hunter
2023-01-24 23:21:05 +00:00
parent c455bc09b6
commit fc455c918c
2 changed files with 225 additions and 44 deletions
+50
View File
@@ -0,0 +1,50 @@
use egui::{Color32, Frame, Id, ScrollArea, TextEdit, TextStyle};
use egui_winit_vulkano::Gui;
fn sized_text(ui: &mut egui::Ui, text: impl Into<String>, size: f32) {
ui.label(egui::RichText::new(text).size(size));
}
const CODE: &str = r#"
# Some markup
```
let mut gui = Gui::new(&event_loop, renderer.surface(), renderer.queue());
```
Vulkan(o) is hard, that I know...
"#;
#[derive(Debug)]
pub struct GState {
pub cursor_sensitivity: f32,
pub move_speed: f32,
}
impl Default for GState {
fn default() -> Self {
Self {
cursor_sensitivity: 1.0,
move_speed: 1.0,
}
}
}
pub fn gui_up(gui: &mut Gui, state: &mut GState) {
let mut code = CODE.to_owned();
gui.immediate_ui(|gui| {
let ctx = gui.context();
egui::SidePanel::left(Id::new("main_left"))
.frame(Frame::default().fill(Color32::from_rgba_unmultiplied(100, 100, 100, 200)))
.show(&ctx, |ui| {
ui.vertical_centered(|ui| {
ui.add(egui::widgets::Label::new("Efficient Realtime Rendering of Complex Closed Form Implicit Surfaces Using Modern RTX Enabled GPUs"));
sized_text(ui, "Settings", 32.0);
});
ui.separator();
ui.vertical_centered(|ui| {
//ui.heading("Camera Control");
ui.add(egui::Slider::new(&mut state.cursor_sensitivity, 0.0..=2.0).text("Mouse Sensitivity"));
ui.add(egui::Slider::new(&mut state.move_speed, 0.0..=2.0).text("Movement Speed"));
});
});
});
}
+171 -40
View File
@@ -16,23 +16,24 @@
// and that you want to learn Vulkan. This means that for example it won't go into details about
// what a vertex or a shader is.
use bytemuck::{Pod, Zeroable};
use cgmath::{Matrix3, Matrix4, Point3, Rad, Vector3};
use cgmath::{
AbsDiffEq, Basis3, Deg, EuclideanSpace, Euler, Matrix3, Matrix4, Point3, Quaternion, Rad,
SquareMatrix, Transform, Vector3,
};
use obj::{LoadConfig, ObjData};
use rodio::{source::Source, Decoder, OutputStream};
use std::io::Cursor;
use std::{sync::Arc, time::Instant};
use vulkano::buffer::CpuBufferPool;
use vulkano::command_buffer::allocator::StandardCommandBufferAllocator;
use vulkano::descriptor_set::allocator::StandardDescriptorSetAllocator;
use vulkano::device::QueueFlags;
use vulkano::format::Format;
use vulkano::image::AttachmentImage;
use vulkano::memory::allocator::{MemoryAllocator, MemoryUsage, StandardMemoryAllocator};
use vulkano::memory::allocator::StandardMemoryAllocator;
use vulkano::pipeline::graphics::depth_stencil::DepthStencilState;
use vulkano::pipeline::graphics::rasterization::CullMode;
use vulkano::pipeline::graphics::rasterization::FrontFace::Clockwise;
use vulkano::swapchain::SwapchainPresentInfo;
use vulkano::{memory, VulkanLibrary};
use vulkano::swapchain::{PresentMode, SwapchainPresentInfo};
use vulkano::VulkanLibrary;
use winit::event::{DeviceEvent, DeviceId, ElementState, MouseButton, VirtualKeyCode};
use egui_winit_vulkano::Gui;
use vulkano::pipeline::StateMode::Fixed;
@@ -41,7 +42,6 @@ use vulkano::{
command_buffer::{
AutoCommandBufferBuilder, CommandBufferUsage, RenderPassBeginInfo, SubpassContents,
},
descriptor_set::{PersistentDescriptorSet, WriteDescriptorSet},
device::{
physical::PhysicalDeviceType, Device, DeviceCreateInfo, DeviceExtensions, QueueCreateInfo,
},
@@ -55,7 +55,7 @@ use vulkano::{
vertex_input::BuffersDefinition,
viewport::{Viewport, ViewportState},
},
GraphicsPipeline, Pipeline, PipelineBindPoint,
GraphicsPipeline, Pipeline,
},
render_pass::{Framebuffer, FramebufferCreateInfo, RenderPass, Subpass},
swapchain::{
@@ -70,6 +70,9 @@ use winit::{
window::{Window, WindowBuilder},
};
use crate::gui::*;
mod gui;
fn main() {
// The first step of any Vulkan program is to create an instance.
//
@@ -213,9 +216,6 @@ fn main() {
// iterator.
let queue = queues.next().expect("Unable to retrieve queues");
// Create an egui GUI
let mut gui = Gui::new(&event_loop, surface.clone(), None, queue.clone(), false);
// Before we can draw on the surface, we have to create what is called a swapchain. Creating
// a swapchain allocates the color buffers that will contain the image that will ultimately
// be visible on the screen. These images are returned alongside the swapchain.
@@ -276,6 +276,8 @@ fn main() {
.next()
.unwrap(),
present_mode: PresentMode::FifoRelaxed,
..Default::default()
},
)
@@ -393,7 +395,7 @@ fn main() {
// The next step is to create a *render pass*, which is an object that describes where the
// output of the graphics pipeline will go. It describes the layout of the images
// where the colors, depth and/or stencil information will be written.
let render_pass = vulkano::single_pass_renderpass!(
let render_pass = vulkano::ordered_passes_renderpass!(
device.clone(),
attachments: {
// `color` is a custom name we give to the first and only attachment.
@@ -421,12 +423,19 @@ fn main() {
samples: 1,
}
},
pass: {
passes: [{
// We use the attachment named `color` as the one and only color attachment.
color: [color],
// No depth-stencil attachment is indicated with empty brackets.
depth_stencil: {depth}
}
depth_stencil: {depth},
input: []
},{
// We use the attachment named `color` as the one and only color attachment.
color: [color],
// No depth-stencil attachment is indicated with empty brackets.
depth_stencil: {depth},
input: []
}]
)
.unwrap();
@@ -504,6 +513,7 @@ fn main() {
// that, we store the submission of the previous frame here.
let mut previous_frame_end = Some(sync::now(device.clone()).boxed());
/*
// Get a output stream handle to the default physical sound device
let (_stream, stream_handle) = OutputStream::try_default().unwrap();
// Load a sound from a file, using a path relative to Cargo.toml
@@ -512,24 +522,101 @@ fn main() {
let source = Decoder::new(freebird).unwrap().repeat_infinite();
// Play the sound directly on the device
stream_handle.play_raw(source.convert_samples()).unwrap();
*/
let rotation_start = Instant::now();
//let descriptor_set_allocator = StandardDescriptorSetAllocator::new(device.clone());
// Create an egui GUI
let mut gui = Gui::new_with_subpass(
&event_loop,
surface.clone(),
None,
queue.clone(),
Subpass::from(render_pass.clone(), 1).unwrap(),
);
let mut gstate = GState::default();
let mut campos = Point3 {
x: 0f32,
y: 0f32,
z: 3f32,
};
let mut camforward = Euler::new(Deg(0f32), Deg(0f32), Deg(0f32));
let mut looking = false;
struct Keys {
w: bool,
s: bool,
a: bool,
d: bool,
}
let mut keys = Keys {
w: false,
s: false,
a: false,
d: false,
};
event_loop.run(move |event, _, control_flow| {
match event {
Event::WindowEvent {
event: WindowEvent::CloseRequested,
..
} => {
if let Event::WindowEvent { event: we, .. } = &event {
if !gui.update(we) {
match &we {
WindowEvent::CloseRequested => {
*control_flow = ControlFlow::Exit;
}
Event::WindowEvent {
event: WindowEvent::Resized(_),
WindowEvent::Resized(_) => {
recreate_swapchain = true;
}
WindowEvent::ScaleFactorChanged { .. } => {
recreate_swapchain = true;
}
WindowEvent::DroppedFile(file) => {
todo!()
}
WindowEvent::MouseInput {
device_id: d,
state: s,
button: b,
..
} => {
recreate_swapchain = true;
println!("MOUSE {:?}, {:?}, {:?}", d, s, b);
if b == &MouseButton::Right {
looking = s == &ElementState::Pressed;
}
}
WindowEvent::KeyboardInput { input, .. } => match input.virtual_keycode {
Some(VirtualKeyCode::W) => {
keys.w = input.state == ElementState::Pressed;
}
Some(VirtualKeyCode::S) => {
keys.s = input.state == ElementState::Pressed;
}
Some(VirtualKeyCode::A) => {
keys.a = input.state == ElementState::Pressed;
}
Some(VirtualKeyCode::D) => {
keys.d = input.state == ElementState::Pressed;
}
_ => {}
},
_ => {}
}
}
}
match event {
Event::DeviceEvent {
event: DeviceEvent::MouseMotion { delta },
..
} => {
if looking {
camforward.x -= Deg(delta.1 as f32) * gstate.cursor_sensitivity;
camforward.y += Deg(delta.0 as f32) * gstate.cursor_sensitivity;
}
//println!("AXISM {:?}", delta);
}
Event::RedrawEventsCleared => {
// Do not draw frame when screen dimensions are zero.
@@ -575,11 +662,44 @@ fn main() {
recreate_swapchain = false;
}
//println!("{:?}", right);
let uniform_data = {
let elapsed = rotation_start.elapsed();
let rotation =
elapsed.as_secs() as f64 + elapsed.subsec_nanos() as f64 / 1_000_000_000.0;
let rotation = Matrix3::from_angle_y(Rad(rotation as f32));
if looking {
if keys.w {
campos -= Matrix3::from_angle_y(camforward.y)
* Matrix3::from_angle_x(camforward.x)
* Vector3::unit_z()
* 0.02
* gstate.move_speed;
}
if keys.s {
campos += Matrix3::from_angle_y(camforward.y)
* Matrix3::from_angle_x(camforward.x)
* Vector3::unit_z()
* 0.02
* gstate.move_speed;
}
if keys.a {
campos += Matrix3::from_angle_y(camforward.y)
* Matrix3::from_angle_x(camforward.x)
* Vector3::unit_x()
* 0.02
* gstate.move_speed;
}
if keys.d {
campos -= Matrix3::from_angle_y(camforward.y)
* Matrix3::from_angle_x(camforward.x)
* Vector3::unit_x()
* 0.02
* gstate.move_speed;
}
} else {
keys.w = false;
keys.s = false;
keys.a = false;
keys.d = false;
}
// note: this teapot was meant for OpenGL where the origin is at the lower left
// instead the origin is at the upper left in Vulkan, so we reverse the Y axis
@@ -591,25 +711,28 @@ fn main() {
0.01,
100.0,
);
let view = Matrix4::look_at_rh(
Point3::new(0.3, 0.3, 1.0),
Point3::new(0.0, 0.0, 0.0),
Vector3::new(0.0, -1.0, 0.0),
);
let scale = Matrix4::from_scale(0.01);
let scale = 0.01;
let view = Matrix4::from(camforward)
* Matrix4::from_angle_z(Deg(180f32))
* Matrix4::from_translation(Point3::origin() - campos)
* Matrix4::from_scale(scale);
//*Matrix4::from_angle_z(Deg(180f32));
vs::ty::PushConstantData {
world: Matrix4::from(rotation).into(),
view: (view * scale).into(),
let pc = vs::ty::PushConstantData {
world: Matrix4::identity().into(),
view: view.into(),
proj: proj.into(),
}
};
if looking {
/*println!(
"world: {:?} view: {:?} proj: {:?}",
uniform_data.world, uniform_data.view, uniform_data.proj
pc.world, pc.view, pc.proj
);*/
println!("campos: {:?} camforward: {:?}", campos, camforward);
}
//uniform_buffer.from_data(uniform_data).unwrap()
pc
};
//let layout = pipeline.layout().set_layouts().get(0).unwrap();
@@ -644,6 +767,8 @@ fn main() {
recreate_swapchain = true;
}
gui_up(&mut gui, &mut gstate);
// In order to draw, we have to build a *command buffer*. The command buffer object holds
// the list of commands that are going to be executed.
//
@@ -660,6 +785,8 @@ fn main() {
)
.unwrap();
let cb = gui.draw_on_subpass_image(dimensions.into());
builder
// Before we can draw, we have to *enter a render pass*.
.begin_render_pass(
@@ -702,6 +829,10 @@ fn main() {
.unwrap()
// We leave the render pass. Note that if we had multiple
// subpasses we could have called `next_subpass` to jump to the next subpass.
.next_subpass(SubpassContents::SecondaryCommandBuffers)
.unwrap()
.execute_commands(cb)
.unwrap()
.end_render_pass()
.unwrap();