Merge pull request #801 from rtfeldman/editor_refactor

editor: refactoring orthographic projection
This commit is contained in:
Richard Feldman 2020-12-14 22:19:00 -05:00 committed by GitHub
commit 44e91bbfda
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 130 additions and 91 deletions

View file

@ -11,12 +11,10 @@
use crate::buffer::create_rect_buffers; use crate::buffer::create_rect_buffers;
use crate::text::{build_glyph_brush, Text}; use crate::text::{build_glyph_brush, Text};
use crate::vertex::Vertex; use crate::vertex::Vertex;
use cgmath::Ortho; use ortho::{init_ortho, update_ortho_buffer, OrthoResources};
use std::error::Error; use std::error::Error;
use std::io; use std::io;
use std::path::Path; use std::path::Path;
use wgpu::util::DeviceExt;
use wgpu::{BindGroup, BindGroupLayoutDescriptor, BindGroupLayoutEntry, Buffer, ShaderStage};
use winit::event; use winit::event;
use winit::event::{Event, ModifiersState}; use winit::event::{Event, ModifiersState};
use winit::event_loop::ControlFlow; use winit::event_loop::ControlFlow;
@ -25,6 +23,7 @@ pub mod ast;
mod buffer; mod buffer;
pub mod file; pub mod file;
mod keyboard_input; mod keyboard_input;
mod ortho;
pub mod pool; pub mod pool;
mod rect; mod rect;
pub mod text; pub mod text;
@ -41,31 +40,6 @@ pub fn launch(_filepaths: &[&Path]) -> io::Result<()> {
Ok(()) Ok(())
} }
#[repr(C)]
#[derive(Debug, Copy, Clone, bytemuck::Pod, bytemuck::Zeroable)]
struct Uniforms {
// We can't use cgmath with bytemuck directly so we'll have
// to convert the Matrix4 into a 4x4 f32 array
ortho: [[f32; 4]; 4],
}
impl Uniforms {
fn new(w: u32, h: u32) -> Self {
let ortho: cgmath::Matrix4<f32> = Ortho::<f32> {
left: 0.0,
right: w as f32,
bottom: h as f32,
top: 0.0,
near: -1.0,
far: 1.0,
}
.into();
Self {
ortho: ortho.into(),
}
}
}
fn run_event_loop() -> Result<(), Box<dyn Error>> { fn run_event_loop() -> Result<(), Box<dyn Error>> {
env_logger::init(); env_logger::init();
@ -123,8 +97,7 @@ fn run_event_loop() -> Result<(), Box<dyn Error>> {
let mut swap_chain = gpu_device.create_swap_chain(&surface, &swap_chain_descr); let mut swap_chain = gpu_device.create_swap_chain(&surface, &swap_chain_descr);
let (rect_pipeline, ortho_bind_group, ortho_buffer) = let (rect_pipeline, ortho) = make_rect_pipeline(&gpu_device, &swap_chain_descr);
make_rect_pipeline(&gpu_device, &swap_chain_descr);
let mut glyph_brush = build_glyph_brush(&gpu_device, render_format)?; let mut glyph_brush = build_glyph_brush(&gpu_device, render_format)?;
@ -169,33 +142,13 @@ fn run_event_loop() -> Result<(), Box<dyn Error>> {
}, },
); );
// update orthographic buffer according to new window size update_ortho_buffer(
let new_uniforms = Uniforms::new(size.width, size.height); size.width,
size.height,
let new_ortho_buffer = &gpu_device,
gpu_device.create_buffer_init(&wgpu::util::BufferInitDescriptor { &ortho.buffer,
label: Some("Ortho uniform buffer"), &cmd_queue,
contents: bytemuck::cast_slice(&[new_uniforms]),
usage: wgpu::BufferUsage::UNIFORM | wgpu::BufferUsage::COPY_SRC,
});
// get a command encoder for the current frame
let mut encoder =
gpu_device.create_command_encoder(&wgpu::CommandEncoderDescriptor {
label: Some("Resize"),
});
// overwrite the new buffer over the old one
encoder.copy_buffer_to_buffer(
&new_ortho_buffer,
0,
&ortho_buffer,
0,
(std::mem::size_of::<Uniforms>() * vec![new_uniforms].as_slice().len())
as wgpu::BufferAddress,
); );
cmd_queue.submit(Some(encoder.finish()));
} }
//Received Character //Received Character
Event::WindowEvent { Event::WindowEvent {
@ -250,7 +203,7 @@ fn run_event_loop() -> Result<(), Box<dyn Error>> {
if rect_buffers.num_rects > 0 { if rect_buffers.num_rects > 0 {
render_pass.set_pipeline(&rect_pipeline); render_pass.set_pipeline(&rect_pipeline);
render_pass.set_bind_group(0, &ortho_bind_group, &[]); render_pass.set_bind_group(0, &ortho.bind_group, &[]);
render_pass.set_vertex_buffer(0, rect_buffers.vertex_buffer.slice(..)); render_pass.set_vertex_buffer(0, rect_buffers.vertex_buffer.slice(..));
render_pass.set_index_buffer(rect_buffers.index_buffer.slice(..)); render_pass.set_index_buffer(rect_buffers.index_buffer.slice(..));
render_pass.draw_indexed(0..rect_buffers.num_rects, 0, 0..1); render_pass.draw_indexed(0..rect_buffers.num_rects, 0, 0..1);
@ -290,41 +243,11 @@ fn run_event_loop() -> Result<(), Box<dyn Error>> {
fn make_rect_pipeline( fn make_rect_pipeline(
gpu_device: &wgpu::Device, gpu_device: &wgpu::Device,
swap_chain_descr: &wgpu::SwapChainDescriptor, swap_chain_descr: &wgpu::SwapChainDescriptor,
) -> (wgpu::RenderPipeline, BindGroup, Buffer) { ) -> (wgpu::RenderPipeline, OrthoResources) {
let uniforms = Uniforms::new(swap_chain_descr.width, swap_chain_descr.height); let ortho = init_ortho(swap_chain_descr.width, swap_chain_descr.height, gpu_device);
// orthographic projection is used to transfrom pixel coords to the coordinate system used by wgpu
let ortho_buffer = gpu_device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
label: Some("Ortho uniform buffer"),
contents: bytemuck::cast_slice(&[uniforms]),
usage: wgpu::BufferUsage::UNIFORM | wgpu::BufferUsage::COPY_DST,
});
// bind groups consist of extra resources that are provided to the shaders
let ortho_bind_group_layout = gpu_device.create_bind_group_layout(&BindGroupLayoutDescriptor {
entries: &[BindGroupLayoutEntry {
binding: 0,
visibility: ShaderStage::VERTEX,
ty: wgpu::BindingType::UniformBuffer {
dynamic: false,
min_binding_size: None,
},
count: None,
}],
label: Some("Ortho bind group layout"),
});
let ortho_bind_group = gpu_device.create_bind_group(&wgpu::BindGroupDescriptor {
layout: &ortho_bind_group_layout,
entries: &[wgpu::BindGroupEntry {
binding: 0,
resource: wgpu::BindingResource::Buffer(ortho_buffer.slice(..)),
}],
label: Some("Ortho bind group"),
});
let pipeline_layout = gpu_device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { let pipeline_layout = gpu_device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
bind_group_layouts: &[&ortho_bind_group_layout], bind_group_layouts: &[&ortho.bind_group_layout],
push_constant_ranges: &[], push_constant_ranges: &[],
label: Some("Rectangle pipeline layout"), label: Some("Rectangle pipeline layout"),
}); });
@ -337,7 +260,7 @@ fn make_rect_pipeline(
wgpu::include_spirv!("shaders/rect.frag.spv"), wgpu::include_spirv!("shaders/rect.frag.spv"),
); );
(pipeline, ortho_bind_group, ortho_buffer) (pipeline, ortho)
} }
fn create_render_pipeline( fn create_render_pipeline(

116
editor/src/ortho.rs Normal file
View file

@ -0,0 +1,116 @@
use cgmath::{Matrix4, Ortho};
use wgpu::util::DeviceExt;
use wgpu::{
BindGroup, BindGroupLayout, BindGroupLayoutDescriptor, BindGroupLayoutEntry, Buffer,
ShaderStage,
};
// orthographic projection is used to transfrom pixel coords to the coordinate system used by wgpu
#[repr(C)]
#[derive(Debug, Copy, Clone, bytemuck::Pod, bytemuck::Zeroable)]
struct Uniforms {
// We can't use cgmath with bytemuck directly so we'll have
// to convert the Matrix4 into a 4x4 f32 array
ortho: [[f32; 4]; 4],
}
impl Uniforms {
fn new(w: u32, h: u32) -> Self {
let ortho: Matrix4<f32> = Ortho::<f32> {
left: 0.0,
right: w as f32,
bottom: h as f32,
top: 0.0,
near: -1.0,
far: 1.0,
}
.into();
Self {
ortho: ortho.into(),
}
}
}
// update orthographic buffer according to new window size
pub fn update_ortho_buffer(
inner_width: u32,
inner_height: u32,
gpu_device: &wgpu::Device,
ortho_buffer: &Buffer,
cmd_queue: &wgpu::Queue,
) {
let new_uniforms = Uniforms::new(inner_width, inner_height);
let new_ortho_buffer = gpu_device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
label: Some("Ortho uniform buffer"),
contents: bytemuck::cast_slice(&[new_uniforms]),
usage: wgpu::BufferUsage::UNIFORM | wgpu::BufferUsage::COPY_SRC,
});
// get a command encoder for the current frame
let mut encoder = gpu_device.create_command_encoder(&wgpu::CommandEncoderDescriptor {
label: Some("Resize"),
});
// overwrite the new buffer over the old one
encoder.copy_buffer_to_buffer(
&new_ortho_buffer,
0,
ortho_buffer,
0,
(std::mem::size_of::<Uniforms>() * vec![new_uniforms].as_slice().len())
as wgpu::BufferAddress,
);
cmd_queue.submit(Some(encoder.finish()));
}
pub struct OrthoResources {
pub buffer: Buffer,
pub bind_group_layout: BindGroupLayout,
pub bind_group: BindGroup,
}
pub fn init_ortho(
inner_width: u32,
inner_height: u32,
gpu_device: &wgpu::Device,
) -> OrthoResources {
let uniforms = Uniforms::new(inner_width, inner_height);
let ortho_buffer = gpu_device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
label: Some("Ortho uniform buffer"),
contents: bytemuck::cast_slice(&[uniforms]),
usage: wgpu::BufferUsage::UNIFORM | wgpu::BufferUsage::COPY_DST,
});
// bind groups consist of extra resources that are provided to the shaders
let ortho_bind_group_layout = gpu_device.create_bind_group_layout(&BindGroupLayoutDescriptor {
entries: &[BindGroupLayoutEntry {
binding: 0,
visibility: ShaderStage::VERTEX,
ty: wgpu::BindingType::UniformBuffer {
dynamic: false,
min_binding_size: None,
},
count: None,
}],
label: Some("Ortho bind group layout"),
});
let ortho_bind_group = gpu_device.create_bind_group(&wgpu::BindGroupDescriptor {
layout: &ortho_bind_group_layout,
entries: &[wgpu::BindGroupEntry {
binding: 0,
resource: wgpu::BindingResource::Buffer(ortho_buffer.slice(..)),
}],
label: Some("Ortho bind group"),
});
OrthoResources {
buffer: ortho_buffer,
bind_group_layout: ortho_bind_group_layout,
bind_group: ortho_bind_group,
}
}