From 5d6ec363a5f89dbd0b5c0241c724ff53ea582742 Mon Sep 17 00:00:00 2001 From: Joshua Barretto Date: Mon, 7 Jan 2019 21:10:31 +0000 Subject: [PATCH] Added triangle test --- voxygen/Cargo.toml | 19 ++- voxygen/shaders/test/shader.frag | 11 ++ voxygen/shaders/test/shader.vert | 11 ++ voxygen/src/consts.rs | 34 +++++ voxygen/src/global_consts.rs | 18 +++ voxygen/src/main.rs | 33 ++++- voxygen/src/menu/title.rs | 24 ++-- voxygen/src/render/mesh.rs | 21 +++ voxygen/src/render/mod.rs | 36 +++++ voxygen/src/render/model.rs | 18 +++ voxygen/src/render/renderer.rs | 218 +++++++++++++++++++++++++++++++ voxygen/src/render/shader_set.rs | 23 ++++ voxygen/src/render_ctx.rs | 45 ------- voxygen/src/window.rs | 82 ++++-------- 14 files changed, 472 insertions(+), 121 deletions(-) create mode 100644 voxygen/shaders/test/shader.frag create mode 100644 voxygen/shaders/test/shader.vert create mode 100644 voxygen/src/consts.rs create mode 100644 voxygen/src/global_consts.rs create mode 100644 voxygen/src/render/mesh.rs create mode 100644 voxygen/src/render/mod.rs create mode 100644 voxygen/src/render/model.rs create mode 100644 voxygen/src/render/renderer.rs create mode 100644 voxygen/src/render/shader_set.rs delete mode 100644 voxygen/src/render_ctx.rs diff --git a/voxygen/Cargo.toml b/voxygen/Cargo.toml index 4744287815..a31f5ee603 100644 --- a/voxygen/Cargo.toml +++ b/voxygen/Cargo.toml @@ -4,14 +4,25 @@ version = "0.1.0" authors = ["Joshua Barretto "] edition = "2018" +[features] +empty = ["rendy/empty"] +dx12 = ["rendy/dx12"] +metal = ["rendy/metal"] +vulkan = ["rendy/vulkan"] + +default = ["empty"] + [dependencies] common = { path = "../common" } # Graphics -gfx = "0.17.1" -gfx_device_gl = "0.15.0" -gfx_window_glutin = "0.25.0" -glutin = "0.17.0" +winit = "0.18" +rendy = { git = "https://github.com/omni-viral/rendy" } # Mathematics vek = "0.9" + +# Utility +glsl-include = "0.2" +failure = "0.1" +lazy_static = "1.1" diff --git a/voxygen/shaders/test/shader.frag b/voxygen/shaders/test/shader.frag new file mode 100644 index 0000000000..c1ceb77ce0 --- /dev/null +++ b/voxygen/shaders/test/shader.frag @@ -0,0 +1,11 @@ +#version 450 +#extension GL_ARB_separate_shader_objects : enable + +layout(early_fragment_tests) in; + +layout(location = 0) in vec4 frag_color; +layout(location = 0) out vec4 color; + +void main() { + color = frag_color; +} diff --git a/voxygen/shaders/test/shader.vert b/voxygen/shaders/test/shader.vert new file mode 100644 index 0000000000..1562324ae1 --- /dev/null +++ b/voxygen/shaders/test/shader.vert @@ -0,0 +1,11 @@ +#version 450 +#extension GL_ARB_separate_shader_objects : enable + +layout(location = 0) in vec3 pos; +layout(location = 1) in vec4 color; +layout(location = 0) out vec4 frag_color; + +void main() { + frag_color = color; + gl_Position = vec4(pos, 1.0); +} diff --git a/voxygen/src/consts.rs b/voxygen/src/consts.rs new file mode 100644 index 0000000000..95ec0a2564 --- /dev/null +++ b/voxygen/src/consts.rs @@ -0,0 +1,34 @@ +// Library +use gfx::{ + handle::Buffer, + traits::{FactoryExt, Pod}, +}; + +// Crate +use crate::render_ctx::{RenderCtx, Resources}; + +type ConstBuffer = Buffer; + +#[derive(Clone)] +pub struct ConstHandle { + buffer: ConstBuffer, +} + +impl ConstHandle { + pub fn new(render_ctx: &mut RenderCtx) -> Self { + Self { + buffer: render_ctx + .factory_mut() + .create_constant_buffer(1), + } + } + + pub fn update(&self, render_ctx: &mut RenderCtx, consts: T) { + render_ctx + .encoder_mut() + .update_buffer(&self.buffer, &[consts], 0) + .unwrap(); + } + + pub fn buffer(&self) -> &ConstBuffer { &self.buffer } +} diff --git a/voxygen/src/global_consts.rs b/voxygen/src/global_consts.rs new file mode 100644 index 0000000000..2045d35ef9 --- /dev/null +++ b/voxygen/src/global_consts.rs @@ -0,0 +1,18 @@ +// Library +use gfx::{ + // Urgh + gfx_defines, + gfx_constant_struct_meta, + gfx_impl_struct_meta, +}; + +gfx_defines! { + constant GlobalConsts { + view_mat: [[f32; 4]; 4] = "view_mat", + proj_mat: [[f32; 4]; 4] = "proj_mat", + cam_origin: [f32; 4] = "cam_origin", + play_origin: [f32; 4] = "play_origin", + view_distance: [f32; 4] = "view_distance", + time: [f32; 4] = "time", + } +} diff --git a/voxygen/src/main.rs b/voxygen/src/main.rs index 8e2cbab9a4..209bfbe69e 100644 --- a/voxygen/src/main.rs +++ b/voxygen/src/main.rs @@ -1,16 +1,26 @@ mod menu; -mod render_ctx; +mod render; mod window; // Standard use std::mem; +// Library +use winit; +use failure; + // Crate use crate::{ menu::title::TitleState, window::Window, }; +#[derive(Debug)] +pub enum VoxygenErr { + WinitCreationErr(winit::CreationError), + Other(failure::Error), +} + // A type used to store state that is shared between all play states pub struct GlobalState { window: Window, @@ -18,33 +28,42 @@ pub struct GlobalState { // States can either close (and revert to a previous state), push a new state on top of themselves, // or switch to a totally different state -pub enum StateResult { +pub enum PlayStateResult { + /// Pop all play states in reverse order and shut down the program + Shutdown, + /// Close the current play state Close, + /// Push a new play state onto the play state stack Push(Box), + /// Switch the current play state with a new play state Switch(Box), } pub trait PlayState { - fn play(&mut self, global_state: &mut GlobalState) -> StateResult; + fn play(&mut self, global_state: &mut GlobalState) -> PlayStateResult; } fn main() { let mut states: Vec> = vec![Box::new(TitleState::new())]; let mut global_state = GlobalState { - window: Window::new(), + window: Window::new() + .expect("Failed to create window"), }; while let Some(state_result) = states.last_mut().map(|last| last.play(&mut global_state)){ // Implement state transfer logic match state_result { - StateResult::Close => { + PlayStateResult::Shutdown => while states.last().is_some() { states.pop(); }, - StateResult::Push(new_state) => { + PlayStateResult::Close => { + states.pop(); + }, + PlayStateResult::Push(new_state) => { states.push(new_state); }, - StateResult::Switch(mut new_state) => { + PlayStateResult::Switch(mut new_state) => { states.last_mut().map(|old_state| mem::swap(old_state, &mut new_state)); }, } diff --git a/voxygen/src/menu/title.rs b/voxygen/src/menu/title.rs index bab4b3b183..ac4eb506ec 100644 --- a/voxygen/src/menu/title.rs +++ b/voxygen/src/menu/title.rs @@ -4,7 +4,7 @@ use vek::*; // Crate use crate::{ PlayState, - StateResult, + PlayStateResult, GlobalState, window::Event, }; @@ -18,23 +18,23 @@ impl TitleState { } impl PlayState for TitleState { - fn play(&mut self, global_state: &mut GlobalState) -> StateResult { - let mut running = true; - while running { - global_state.window.poll_events(|event| match event { - Event::Close => running = false, - }); + fn play(&mut self, global_state: &mut GlobalState) -> PlayStateResult { + 'eventloop: loop { + // Process window events + for event in global_state.window.fetch_events() { + match event { + Event::Close => break 'eventloop PlayStateResult::Shutdown, + } + } - global_state.window.render_ctx_mut().clear(Rgba::new( + global_state.window.renderer_mut().clear(Rgba::new( 0.0, 0.3, 1.0, 1.0, )); - global_state.window.render_ctx_mut().flush_and_cleanup(); - global_state.window.swap_buffers(); + global_state.window.renderer_mut().flush(); + global_state.window.display(); } - - StateResult::Close } } diff --git a/voxygen/src/render/mesh.rs b/voxygen/src/render/mesh.rs new file mode 100644 index 0000000000..352e1e92df --- /dev/null +++ b/voxygen/src/render/mesh.rs @@ -0,0 +1,21 @@ +// Local +use super::Pipeline; + +/// Used to store vertex data on the CPU +pub struct Mesh { + verts: Vec, +} + +impl Mesh

{ + pub fn empty() -> Self { + Self { verts: vec![] } + } + + pub fn verts(&self) -> &[P::Vertex] { + &self.verts + } + + pub fn push(&mut self, vert: P::Vertex) { + self.verts.push(vert); + } +} diff --git a/voxygen/src/render/mod.rs b/voxygen/src/render/mod.rs new file mode 100644 index 0000000000..db1f83f747 --- /dev/null +++ b/voxygen/src/render/mod.rs @@ -0,0 +1,36 @@ +mod mesh; +mod model; +mod renderer; +mod shader_set; + +// Reexports +pub use self::{ + mesh::Mesh, + model::Model, + shader_set::ShaderSet, + renderer::Renderer, +}; + +// Library +use rendy; + +#[cfg(not(any(feature = "dx12", feature = "metal", feature = "vulkan")))] +type Backend = rendy::empty::Backend; + +#[cfg(feature = "dx12")] +type Backend = rendy::dx12::Backend; + +#[cfg(feature = "metal")] +type Backend = rendy::metal::Backend; + +#[cfg(feature = "vulkan")] +type Backend = rendy::vulkan::Backend; + +/// Used to represent one of many possible errors that may be omitted by the rendering code +#[derive(Debug)] +pub enum RenderErr {} + +/// Used to represent a specific rendering configuration +pub trait Pipeline { + type Vertex; +} diff --git a/voxygen/src/render/model.rs b/voxygen/src/render/model.rs new file mode 100644 index 0000000000..b7aaf5d6f7 --- /dev/null +++ b/voxygen/src/render/model.rs @@ -0,0 +1,18 @@ +// Standard +use std::marker::PhantomData; + +// Local +use super::Pipeline; + +/// Represents a mesh that has been sent to the CPU +pub struct Model { + phantom: PhantomData

, +} + +impl Model

{ + pub fn new() -> Self { + Self { + phantom: PhantomData, + } + } +} diff --git a/voxygen/src/render/renderer.rs b/voxygen/src/render/renderer.rs new file mode 100644 index 0000000000..9c8b6cade5 --- /dev/null +++ b/voxygen/src/render/renderer.rs @@ -0,0 +1,218 @@ +// Library +use vek::*; +use winit; +use lazy_static::lazy_static; +use rendy::{ + hal, + command::RenderPassInlineEncoder, + wsi::Surface, + graph::{ + Graph, + GraphBuilder, + NodeBuffer, + NodeImage, + present::PresentNode, + render::RenderPass, + }, + factory::{Config, Factory}, + memory::MemoryUsageValue, + resource::buffer::Buffer, + mesh::AsVertex, + shader::{Shader, ShaderKind, SourceLanguage, StaticShaderInfo}, +}; + +// Crate +use crate::VoxygenErr; + +// Local +use super::{ + model::Model, + mesh::Mesh, + shader_set::ShaderSet, + Pipeline, + RenderErr, + Backend, +}; + +lazy_static! { + static ref VS: StaticShaderInfo = StaticShaderInfo::new( + concat!(env!("CARGO_MANIFEST_DIR"), "/shaders/test/shader.vert"), + ShaderKind::Vertex, + SourceLanguage::GLSL, + "main", + ); + + static ref FS: StaticShaderInfo = StaticShaderInfo::new( + concat!(env!("CARGO_MANIFEST_DIR"), "/shaders/test/shader.frag"), + ShaderKind::Fragment, + SourceLanguage::GLSL, + "main", + ); +} + +#[derive(Debug)] +struct TriangleRenderPass { + vertex: Option>, +} + +impl RenderPass for TriangleRenderPass { + fn name() -> &'static str { "triangle" } + + fn vertices() -> Vec<( + Vec>, + hal::pso::ElemStride, + )> { vec![rendy::mesh::PosColor::VERTEX.gfx_vertex_input_desc()] } + + fn load_shader_sets<'a>( + storage: &'a mut Vec, + factory: &mut Factory, + _aux: &mut T, + ) -> Vec> { + storage.clear(); + storage.push(VS.module(factory).unwrap()); + storage.push(FS.module(factory).unwrap()); + + vec![hal::pso::GraphicsShaderSet { + vertex: hal::pso::EntryPoint { + entry: "main", + module: &storage[0], + specialization: hal::pso::Specialization::default(), + }, + fragment: Some(hal::pso::EntryPoint { + entry: "main", + module: &storage[1], + specialization: hal::pso::Specialization::default(), + }), + hull: None, + domain: None, + geometry: None, + }] + } + + fn build<'a>( + _factory: &mut Factory, + _aux: &mut T, + buffers: &mut [NodeBuffer<'a, B>], + images: &mut [NodeImage<'a, B>], + sets: &[impl AsRef<[B::DescriptorSetLayout]>], + ) -> Self { + assert!(buffers.is_empty()); + assert!(images.is_empty()); + assert_eq!(sets.len(), 1); + assert!(sets[0].as_ref().is_empty()); + + Self { + vertex: None, + } + } + + fn prepare(&mut self, factory: &mut Factory, _aux: &T) -> bool { + if self.vertex.is_some() { + return false; + } else { + let mut vbuf = factory.create_buffer( + 512, + rendy::mesh::PosColor::VERTEX.stride as u64 * 3, + (hal::buffer::Usage::VERTEX, MemoryUsageValue::Dynamic) + ).unwrap(); + + unsafe { + factory.upload_visible_buffer(&mut vbuf, 0, &[ + rendy::mesh::PosColor { + position: [0.0, -1.0, 0.0].into(), + color: [1.0, 0.0, 0.0, 1.0].into(), + }, + rendy::mesh::PosColor { + position: [1.0, 1.0, 0.0].into(), + color: [0.0, 1.0, 0.0, 1.0].into(), + }, + rendy::mesh::PosColor { + position: [-1.0, 1.0, 0.0].into(), + color: [0.0, 0.0, 1.0, 1.0].into(), + }, + ]).unwrap(); + } + + self.vertex = Some(vbuf); + + true + } + } + + fn draw( + &mut self, + _layouts: &[B::PipelineLayout], + pipelines: &[B::GraphicsPipeline], + mut encoder: RenderPassInlineEncoder<'_, B>, + _index: usize, + _aux: &T, + ) { + let vbuf = self.vertex.as_ref().unwrap(); + encoder.bind_graphics_pipeline(&pipelines[0]); + encoder.bind_vertex_buffers(0, Some((vbuf.raw(), 0))); + encoder.draw(0..3, 0..1); + } + + fn dispose(self, _factory: &mut Factory, _aux: &mut T) {} +} + +pub struct Renderer { + //surface: Surface, + graph: Graph, + factory: Factory, +} + +impl Renderer { + pub fn new( + window: winit::Window, + ) -> Result { + let config: Config = Config::default(); + + let mut factory = Factory::::new(config) + .map_err(|err| VoxygenErr::Other(err))?; + + let surface = factory.create_surface(window); + + let mut graph_builder = GraphBuilder::::new(); + + let color_img = graph_builder.create_image( + surface.kind(), + 1, + hal::format::Format::Rgba8Unorm, + MemoryUsageValue::Data, + Some(hal::command::ClearValue::Color([1.0; 4].into())), + ); + + graph_builder.add_node( + TriangleRenderPass::builder() + .with_image(color_img) + ); + + graph_builder.add_node( + PresentNode::builder(surface) + .with_image(color_img) + ); + + let graph = graph_builder.build(&mut factory, &mut ()) + .map_err(|err| VoxygenErr::Other(err))?; + + Ok(Self { + graph, + factory, + }) + } + + pub fn clear(&mut self, col: Rgba) { + } + + pub fn flush(&mut self) { + self.graph.run(&mut self.factory, &mut ()); + } +} + +impl Drop for Renderer { + fn drop(&mut self) { + //self.graph.dispose(&mut self.factory, &mut ()); + //self.factory.dispose(); + } +} diff --git a/voxygen/src/render/shader_set.rs b/voxygen/src/render/shader_set.rs new file mode 100644 index 0000000000..d1e70d4cc4 --- /dev/null +++ b/voxygen/src/render/shader_set.rs @@ -0,0 +1,23 @@ +// Standard +use std::marker::PhantomData; + +// Local +use super::{ + Pipeline, + RenderErr +}; + +pub struct ShaderSet { + phantom: PhantomData

, +} + +impl ShaderSet

{ + pub fn new( + vs: &[u8], + fs: &[u8], + ) -> Result { + Ok(Self { + phantom: PhantomData, + }) + } +} diff --git a/voxygen/src/render_ctx.rs b/voxygen/src/render_ctx.rs deleted file mode 100644 index b4a1efe459..0000000000 --- a/voxygen/src/render_ctx.rs +++ /dev/null @@ -1,45 +0,0 @@ -// Library -use gfx_device_gl::{Device, Resources, Factory, CommandBuffer}; -use gfx::{ - handle::{RenderTargetView, DepthStencilView}, - Device as DeviceTrait, - Encoder, -}; -use vek::*; - -type TgtColorView = RenderTargetView; -type TgtDepthView = DepthStencilView; - -pub struct RenderCtx { - device: Device, - encoder: Encoder, - factory: Factory, - tgt_color_view: TgtColorView, - tgt_depth_view: TgtDepthView, -} - -impl RenderCtx { - pub fn new( - device: Device, - mut factory: Factory, - tgt_color_view: TgtColorView, - tgt_depth_view: TgtDepthView, - ) -> Self { - Self { - device, - encoder: Encoder::from(factory.create_command_buffer()), - factory, - tgt_color_view, - tgt_depth_view, - } - } - - pub fn clear(&mut self, col: Rgba) { - self.encoder.clear(&self.tgt_color_view, col.into_array()); - } - - pub fn flush_and_cleanup(&mut self) { - self.encoder.flush(&mut self.device); - self.device.cleanup(); - } -} diff --git a/voxygen/src/window.rs b/voxygen/src/window.rs index 365960c409..fcc36efaab 100644 --- a/voxygen/src/window.rs +++ b/voxygen/src/window.rs @@ -1,77 +1,53 @@ -// External -use gfx_window_glutin; -use glutin::{ - Api::OpenGl, - dpi::LogicalSize, - ContextBuilder, - EventsLoop, - GlContext, - GlRequest, - GlWindow, - WindowBuilder, -}; +// Library +use winit; // Crate -use crate::render_ctx::RenderCtx; +use crate::{ + VoxygenErr, + render::Renderer, +}; pub struct Window { - events_loop: EventsLoop, - gl_window: GlWindow, - render_ctx: RenderCtx, + events_loop: winit::EventsLoop, + renderer: Renderer, } impl Window { - pub fn new() -> Window { - let events_loop = EventsLoop::new(); + pub fn new() -> Result { + let events_loop = winit::EventsLoop::new(); - let ( - gl_window, - device, - factory, - tgt_color_view, - tgt_depth_view, - ) = gfx_window_glutin::init( - WindowBuilder::new() - .with_title("Veloren (Voxygen)") - .with_dimensions(LogicalSize::new(800.0, 500.0)) - .with_maximized(false), - ContextBuilder::new() - .with_gl(GlRequest::Specific(OpenGl, (3, 2))) - .with_multisampling(2) - .with_vsync(true), - &events_loop, - ); + let window = winit::WindowBuilder::new() + .with_title("Veloren (Voxygen)") + .with_dimensions(winit::dpi::LogicalSize::new(800.0, 500.0)) + .with_maximized(false) + .build(&events_loop) + .map_err(|err| VoxygenErr::WinitCreationErr(err))?; - Self { + let tmp = Ok(Self { events_loop, - gl_window, - render_ctx: RenderCtx::new( - device, - factory, - tgt_color_view, - tgt_depth_view, - ), - } + renderer: Renderer::new(window)?, + }); + tmp } - pub fn render_ctx(&self) -> &RenderCtx { &self.render_ctx } - pub fn render_ctx_mut(&mut self) -> &mut RenderCtx { &mut self.render_ctx } + pub fn renderer(&self) -> &Renderer { &self.renderer } + pub fn renderer_mut(&mut self) -> &mut Renderer { &mut self.renderer } - pub fn poll_events(&mut self, mut f: F) { + pub fn fetch_events(&mut self) -> Vec { + let mut events = vec![]; self.events_loop.poll_events(|event| match event { - glutin::Event::WindowEvent { event, .. } => match event { - glutin::WindowEvent::CloseRequested => f(Event::Close), + winit::Event::WindowEvent { event, .. } => match event { + winit::WindowEvent::CloseRequested => events.push(Event::Close), _ => {}, }, _ => {}, }); + events } - pub fn swap_buffers(&self) { - self.gl_window - .swap_buffers() - .expect("Failed to swap window buffers"); + pub fn display(&self) { + // TODO } }