Added triangle test

This commit is contained in:
Joshua Barretto 2019-01-07 21:10:31 +00:00
parent 6f358fc762
commit 5d6ec363a5
14 changed files with 472 additions and 121 deletions

View File

@ -4,14 +4,25 @@ version = "0.1.0"
authors = ["Joshua Barretto <joshua.s.barretto@gmail.com>"] authors = ["Joshua Barretto <joshua.s.barretto@gmail.com>"]
edition = "2018" edition = "2018"
[features]
empty = ["rendy/empty"]
dx12 = ["rendy/dx12"]
metal = ["rendy/metal"]
vulkan = ["rendy/vulkan"]
default = ["empty"]
[dependencies] [dependencies]
common = { path = "../common" } common = { path = "../common" }
# Graphics # Graphics
gfx = "0.17.1" winit = "0.18"
gfx_device_gl = "0.15.0" rendy = { git = "https://github.com/omni-viral/rendy" }
gfx_window_glutin = "0.25.0"
glutin = "0.17.0"
# Mathematics # Mathematics
vek = "0.9" vek = "0.9"
# Utility
glsl-include = "0.2"
failure = "0.1"
lazy_static = "1.1"

View File

@ -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;
}

View File

@ -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);
}

34
voxygen/src/consts.rs Normal file
View File

@ -0,0 +1,34 @@
// Library
use gfx::{
handle::Buffer,
traits::{FactoryExt, Pod},
};
// Crate
use crate::render_ctx::{RenderCtx, Resources};
type ConstBuffer<T> = Buffer<Resources, T>;
#[derive(Clone)]
pub struct ConstHandle<T: Copy + Pod> {
buffer: ConstBuffer<T>,
}
impl<T: Copy + Pod> ConstHandle<T> {
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<T> { &self.buffer }
}

View File

@ -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",
}
}

View File

@ -1,16 +1,26 @@
mod menu; mod menu;
mod render_ctx; mod render;
mod window; mod window;
// Standard // Standard
use std::mem; use std::mem;
// Library
use winit;
use failure;
// Crate // Crate
use crate::{ use crate::{
menu::title::TitleState, menu::title::TitleState,
window::Window, 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 // A type used to store state that is shared between all play states
pub struct GlobalState { pub struct GlobalState {
window: Window, 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, // 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 // 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, Close,
/// Push a new play state onto the play state stack
Push(Box<dyn PlayState>), Push(Box<dyn PlayState>),
/// Switch the current play state with a new play state
Switch(Box<dyn PlayState>), Switch(Box<dyn PlayState>),
} }
pub trait PlayState { pub trait PlayState {
fn play(&mut self, global_state: &mut GlobalState) -> StateResult; fn play(&mut self, global_state: &mut GlobalState) -> PlayStateResult;
} }
fn main() { fn main() {
let mut states: Vec<Box<dyn PlayState>> = vec![Box::new(TitleState::new())]; let mut states: Vec<Box<dyn PlayState>> = vec![Box::new(TitleState::new())];
let mut global_state = GlobalState { 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)){ while let Some(state_result) = states.last_mut().map(|last| last.play(&mut global_state)){
// Implement state transfer logic // Implement state transfer logic
match state_result { match state_result {
StateResult::Close => { PlayStateResult::Shutdown => while states.last().is_some() {
states.pop(); states.pop();
}, },
StateResult::Push(new_state) => { PlayStateResult::Close => {
states.pop();
},
PlayStateResult::Push(new_state) => {
states.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)); states.last_mut().map(|old_state| mem::swap(old_state, &mut new_state));
}, },
} }

View File

@ -4,7 +4,7 @@ use vek::*;
// Crate // Crate
use crate::{ use crate::{
PlayState, PlayState,
StateResult, PlayStateResult,
GlobalState, GlobalState,
window::Event, window::Event,
}; };
@ -18,23 +18,23 @@ impl TitleState {
} }
impl PlayState for TitleState { impl PlayState for TitleState {
fn play(&mut self, global_state: &mut GlobalState) -> StateResult { fn play(&mut self, global_state: &mut GlobalState) -> PlayStateResult {
let mut running = true; 'eventloop: loop {
while running { // Process window events
global_state.window.poll_events(|event| match event { for event in global_state.window.fetch_events() {
Event::Close => running = false, 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.0,
0.3, 0.3,
1.0, 1.0,
1.0, 1.0,
)); ));
global_state.window.render_ctx_mut().flush_and_cleanup(); global_state.window.renderer_mut().flush();
global_state.window.swap_buffers(); global_state.window.display();
} }
StateResult::Close
} }
} }

View File

@ -0,0 +1,21 @@
// Local
use super::Pipeline;
/// Used to store vertex data on the CPU
pub struct Mesh<P: Pipeline> {
verts: Vec<P::Vertex>,
}
impl<P: Pipeline> Mesh<P> {
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);
}
}

36
voxygen/src/render/mod.rs Normal file
View File

@ -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;
}

View File

@ -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<P: Pipeline> {
phantom: PhantomData<P>,
}
impl<P: Pipeline> Model<P> {
pub fn new() -> Self {
Self {
phantom: PhantomData,
}
}
}

View File

@ -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<B: hal::Backend> {
vertex: Option<Buffer<B>>,
}
impl<B: hal::Backend, T: ?Sized> RenderPass<B, T> for TriangleRenderPass<B> {
fn name() -> &'static str { "triangle" }
fn vertices() -> Vec<(
Vec<hal::pso::Element<hal::format::Format>>,
hal::pso::ElemStride,
)> { vec![rendy::mesh::PosColor::VERTEX.gfx_vertex_input_desc()] }
fn load_shader_sets<'a>(
storage: &'a mut Vec<B::ShaderModule>,
factory: &mut Factory<B>,
_aux: &mut T,
) -> Vec<hal::pso::GraphicsShaderSet<'a, B>> {
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<B>,
_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<B>, _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<B>, _aux: &mut T) {}
}
pub struct Renderer {
//surface: Surface<Backend>,
graph: Graph<Backend, ()>,
factory: Factory<Backend>,
}
impl Renderer {
pub fn new(
window: winit::Window,
) -> Result<Self, VoxygenErr> {
let config: Config = Config::default();
let mut factory = Factory::<Backend>::new(config)
.map_err(|err| VoxygenErr::Other(err))?;
let surface = factory.create_surface(window);
let mut graph_builder = GraphBuilder::<Backend, ()>::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<f32>) {
}
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();
}
}

View File

@ -0,0 +1,23 @@
// Standard
use std::marker::PhantomData;
// Local
use super::{
Pipeline,
RenderErr
};
pub struct ShaderSet<P: Pipeline> {
phantom: PhantomData<P>,
}
impl<P: Pipeline> ShaderSet<P> {
pub fn new(
vs: &[u8],
fs: &[u8],
) -> Result<Self, RenderErr> {
Ok(Self {
phantom: PhantomData,
})
}
}

View File

@ -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<Resources, gfx::format::Srgba8>;
type TgtDepthView = DepthStencilView<Resources, gfx::format::DepthStencil>;
pub struct RenderCtx {
device: Device,
encoder: Encoder<Resources, CommandBuffer>,
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<f32>) {
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();
}
}

View File

@ -1,77 +1,53 @@
// External // Library
use gfx_window_glutin; use winit;
use glutin::{
Api::OpenGl,
dpi::LogicalSize,
ContextBuilder,
EventsLoop,
GlContext,
GlRequest,
GlWindow,
WindowBuilder,
};
// Crate // Crate
use crate::render_ctx::RenderCtx; use crate::{
VoxygenErr,
render::Renderer,
};
pub struct Window { pub struct Window {
events_loop: EventsLoop, events_loop: winit::EventsLoop,
gl_window: GlWindow, renderer: Renderer,
render_ctx: RenderCtx,
} }
impl Window { impl Window {
pub fn new() -> Window { pub fn new() -> Result<Window, VoxygenErr> {
let events_loop = EventsLoop::new(); let events_loop = winit::EventsLoop::new();
let ( let window = winit::WindowBuilder::new()
gl_window, .with_title("Veloren (Voxygen)")
device, .with_dimensions(winit::dpi::LogicalSize::new(800.0, 500.0))
factory, .with_maximized(false)
tgt_color_view, .build(&events_loop)
tgt_depth_view, .map_err(|err| VoxygenErr::WinitCreationErr(err))?;
) = 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,
);
Self { let tmp = Ok(Self {
events_loop, events_loop,
gl_window, renderer: Renderer::new(window)?,
render_ctx: RenderCtx::new( });
device, tmp
factory,
tgt_color_view,
tgt_depth_view,
),
}
} }
pub fn render_ctx(&self) -> &RenderCtx { &self.render_ctx } pub fn renderer(&self) -> &Renderer { &self.renderer }
pub fn render_ctx_mut(&mut self) -> &mut RenderCtx { &mut self.render_ctx } pub fn renderer_mut(&mut self) -> &mut Renderer { &mut self.renderer }
pub fn poll_events<F: FnMut(Event)>(&mut self, mut f: F) { pub fn fetch_events(&mut self) -> Vec<Event> {
let mut events = vec![];
self.events_loop.poll_events(|event| match event { self.events_loop.poll_events(|event| match event {
glutin::Event::WindowEvent { event, .. } => match event { winit::Event::WindowEvent { event, .. } => match event {
glutin::WindowEvent::CloseRequested => f(Event::Close), winit::WindowEvent::CloseRequested => events.push(Event::Close),
_ => {}, _ => {},
}, },
_ => {}, _ => {},
}); });
events
} }
pub fn swap_buffers(&self) { pub fn display(&self) {
self.gl_window // TODO
.swap_buffers()
.expect("Failed to swap window buffers");
} }
} }