From 1a527828823be7261a252e94874e70a28056f818 Mon Sep 17 00:00:00 2001 From: Sergiusz Bazanski Date: Mon, 20 Jul 2020 21:16:29 +0200 Subject: [PATCH] engine/render: refactor mesh and materials into separate modules --- engine/BUILD | 2 + engine/src/main.rs | 8 +- engine/src/render/material.rs | 187 ++++++++++++++++++++++++ engine/src/render/mesh.rs | 67 +++++++++ engine/src/render/mod.rs | 2 + engine/src/render/renderable.rs | 244 +------------------------------- 6 files changed, 265 insertions(+), 245 deletions(-) create mode 100644 engine/src/render/material.rs create mode 100644 engine/src/render/mesh.rs diff --git a/engine/BUILD b/engine/BUILD index 6d60bce..7f8b4fc 100644 --- a/engine/BUILD +++ b/engine/BUILD @@ -13,6 +13,8 @@ rust_binary( "src/main.rs", "src/physics/mod.rs", "src/physics/color.rs", + "src/render/material.rs", + "src/render/mesh.rs", "src/render/mod.rs", "src/render/renderable.rs", "src/render/vulkan/data.rs", diff --git a/engine/src/main.rs b/engine/src/main.rs index 58516a9..8f9486a 100644 --- a/engine/src/main.rs +++ b/engine/src/main.rs @@ -10,7 +10,9 @@ mod util; mod physics; use render::vulkan::data; -use render::renderable::{Object, Renderable, ResourceManager, Mesh, Texture, PBRTextureSet}; +use render::material::{Texture, PBRMaterialBuilder}; +use render::mesh::Mesh; +use render::renderable::{Object, Renderable, ResourceManager}; use physics::color; fn main() { @@ -66,10 +68,10 @@ fn main() { rm.add_mesh(Mesh::new(vertices, indices)) }; - let material = PBRTextureSet { + let material = rm.add_material(PBRMaterialBuilder { diffuse: Texture::from_image(String::from("assets/test-128px.png")), roughness: Texture::from_color(color::LinearF32::new(1.0)), - }.build(&mut rm); + }.build()); let mut cubes: Vec> = vec![]; diff --git a/engine/src/render/material.rs b/engine/src/render/material.rs new file mode 100644 index 0000000..d9ffffd --- /dev/null +++ b/engine/src/render/material.rs @@ -0,0 +1,187 @@ +use std::sync::Arc; +use std::sync::Mutex; +use std::time; + +use image; +use image::GenericImageView; +use vulkano::device as vd; +use vulkano::format as vf; +use vulkano::image as vm; +use vulkano::sync::GpuFuture; + +use crate::physics::color; +use crate::render::vulkan::data; +use crate::util::file; + +pub trait ChannelLayout { + fn vulkan_from_image( + image: Arc, + graphics_queue: Arc, + ) -> Arc>; + + fn vulkan_from_value( + &self, + graphics_queue: Arc, + ) -> Arc>; +} + +impl ChannelLayout for color::XYZ { + fn vulkan_from_image( + image: Arc, + graphics_queue: Arc, + ) -> Arc> { + let (width, height) = (image.width(), image.height()); + let rgba = image.to_rgba(); + // TODO(q3k): RGB -> CIE XYZ + let (image_view, future) = vm::ImmutableImage::from_iter( + rgba.into_raw().iter().cloned(), + vm::Dimensions::Dim2d{ width, height }, + vf::Format::R8G8B8A8Unorm, + graphics_queue.clone(), + ).unwrap(); + + future.flush().unwrap(); + image_view + } + + fn vulkan_from_value( + &self, + graphics_queue: Arc, + ) -> Arc> { + let mut image = image::ImageBuffer::, Vec>::new(1, 1); + image.put_pixel(0, 0, image::Rgba([self.x, self.y, self.z, 0.0])); + + let (image_view, future) = vm::ImmutableImage::from_iter( + image.into_raw().iter().cloned(), + vm::Dimensions::Dim2d{ width: 1, height: 1 }, + vf::Format::R32G32B32A32Sfloat, + graphics_queue.clone(), + ).unwrap(); + future.flush().unwrap(); + image_view + } +} + +impl ChannelLayout for color::LinearF32 { + fn vulkan_from_image( + image: Arc, + graphics_queue: Arc, + ) -> Arc> { + let (width, height) = (image.width(), image.height()); + assert!(match image.color() { + image::ColorType::L8 => true, + image::ColorType::L16 => true, + _ => false, + }, "linearf32 texture must be 8-bit grayscale"); + let gray = image.to_luma(); + let (image_view, future) = vm::ImmutableImage::from_iter( + gray.into_raw().iter().cloned(), + vm::Dimensions::Dim2d{ width, height }, + vf::Format::R8G8B8A8Unorm, + graphics_queue.clone(), + ).unwrap(); + + future.flush().unwrap(); + image_view + } + + fn vulkan_from_value( + &self, + graphics_queue: Arc, + ) -> Arc> { + let mut image = image::ImageBuffer::, Vec>::new(1, 1); + image.put_pixel(0, 0, image::Luma([self.d])); + + let (image_view, future) = vm::ImmutableImage::from_iter( + image.into_raw().iter().cloned(), + vm::Dimensions::Dim2d{ width: 1, height: 1 }, + vf::Format::R32Sfloat, + graphics_queue.clone(), + ).unwrap(); + + future.flush().unwrap(); + image_view + } +} + +pub enum Texture { + Color(T), + ImageRef(String), +} + +impl Texture { + fn vulkan_image(&self, graphics_queue: Arc) -> Arc> { + match self { + Texture::::Color(c) => c.vulkan_from_value(graphics_queue), + Texture::::ImageRef(r) => { + let path = &file::resource_path(r.clone()); + let img = Arc::new(image::open(path).unwrap()); + T::vulkan_from_image(img, graphics_queue) + }, + } + } + + pub fn from_color(color: T) -> Self { + Texture::::Color(color) + } + + pub fn from_image(name: String) -> Self { + Texture::::ImageRef(name) + } +} + +pub struct Material { + diffuse: Texture, + roughness: Texture, + + pub id: u64, + // vulkan cache + vulkan: Mutex>, +} + +impl Material { + pub fn new( + diffuse: Texture, + roughness: Texture, + ) -> Self { + Self { + diffuse, + roughness, + + // TODO: use a better method + id: time::SystemTime::now().duration_since(time::UNIX_EPOCH).unwrap().as_nanos() as u64, + vulkan: Mutex::new(None), + } + } + + pub fn vulkan_textures( + &self, + graphics_queue: Arc, + ) -> data::Textures { + let mut cache = self.vulkan.lock().unwrap(); + match &mut *cache { + Some(data) => data.clone(), + None => { + let diffuse = self.diffuse.vulkan_image(graphics_queue.clone()); + let roughness = self.roughness.vulkan_image(graphics_queue.clone()); + let textures = data::Textures { + diffuse, roughness, + }; + *cache = Some(textures.clone()); + textures + }, + } + } +} + +pub struct PBRMaterialBuilder { + pub diffuse: Texture, + pub roughness: Texture, +} + +impl PBRMaterialBuilder { + pub fn build(self) -> Material { + Material::new(self.diffuse, self.roughness) + } +} + diff --git a/engine/src/render/mesh.rs b/engine/src/render/mesh.rs new file mode 100644 index 0000000..7969363 --- /dev/null +++ b/engine/src/render/mesh.rs @@ -0,0 +1,67 @@ +use std::sync::Arc; +use std::time; +use std::sync::Mutex; + +use vulkano::device as vd; +use vulkano::buffer as vb; +use vulkano::sync::GpuFuture; + +use crate::render::vulkan::data; + +pub struct Mesh { + vertices: Arc>, + indices: Arc>, + + pub id: u64, + // vulkan buffers cache + vulkan: Mutex>, +} + +impl Mesh { + pub fn new( + vertices: Arc>, + indices: Arc>, + ) -> Self { + Self { + vertices, indices, + // TODO: use a better method + id: time::SystemTime::now().duration_since(time::UNIX_EPOCH).unwrap().as_nanos() as u64, + vulkan: Mutex::new(None), + } + } + + pub fn vulkan_buffers( + &self, + graphics_queue: Arc, + ) -> ( + Arc>, + Arc>, + ) { + let mut cache = self.vulkan.lock().unwrap(); + match &mut *cache { + Some(data) => (data.vbuffer.clone(), data.ibuffer.clone()), + None => { + let (vbuffer, vfuture) = vb::immutable::ImmutableBuffer::from_iter( + self.vertices.iter().cloned(), + vb::BufferUsage::vertex_buffer(), + graphics_queue.clone(), + ).unwrap(); + let (ibuffer, ifuture) = vb::immutable::ImmutableBuffer::from_iter( + self.indices.iter().cloned(), + vb::BufferUsage::index_buffer(), + graphics_queue.clone(), + ).unwrap(); + vfuture.flush().unwrap(); + ifuture.flush().unwrap(); + + *cache = Some(data::VertexData { + vbuffer: vbuffer.clone(), + ibuffer: ibuffer.clone(), + }); + + (vbuffer.clone(), ibuffer.clone()) + }, + } + } +} + diff --git a/engine/src/render/mod.rs b/engine/src/render/mod.rs index 63a003a..031229a 100644 --- a/engine/src/render/mod.rs +++ b/engine/src/render/mod.rs @@ -16,6 +16,8 @@ use vulkano::instance as vi; use vulkano::swapchain as vs; pub mod vulkan; +pub mod material; +pub mod mesh; pub mod renderable; const WIDTH: u32 = 800; diff --git a/engine/src/render/renderable.rs b/engine/src/render/renderable.rs index 7b2651b..1609d2b 100644 --- a/engine/src/render/renderable.rs +++ b/engine/src/render/renderable.rs @@ -1,21 +1,10 @@ use std::collections::HashMap; use std::hash; -use std::sync::Arc; -use std::sync::Mutex; -use std::time; use cgmath as cgm; -use image; -use image::GenericImageView; -use vulkano::device as vd; -use vulkano::buffer as vb; -use vulkano::sync::GpuFuture; -use vulkano::format as vf; -use vulkano::image as vm; -use crate::render::vulkan::data; -use crate::physics::color; -use crate::util::file; +use crate::render::material::Material; +use crate::render::mesh::Mesh; pub struct ResourceManager { meshes: HashMap, @@ -88,118 +77,6 @@ impl<'a> ResourceManager { } } -pub struct PBRTextureSet { - pub diffuse: Texture, - pub roughness: Texture, -} - -impl PBRTextureSet { - pub fn build(self, rm: &mut ResourceManager) -> ResourceID { - rm.add_material(Material::new(self.diffuse, self.roughness)) - } -} - -pub struct Material { - diffuse: Texture, - roughness: Texture, - - id: u64, - // vulkan cache - vulkan: Mutex>, -} - -impl Material { - pub fn new( - diffuse: Texture, - roughness: Texture, - ) -> Self { - Self { - diffuse, - roughness, - - // TODO: use a better method - id: time::SystemTime::now().duration_since(time::UNIX_EPOCH).unwrap().as_nanos() as u64, - vulkan: Mutex::new(None), - } - } - - pub fn vulkan_textures( - &self, - graphics_queue: Arc, - ) -> data::Textures { - let mut cache = self.vulkan.lock().unwrap(); - match &mut *cache { - Some(data) => data.clone(), - None => { - let diffuse = self.diffuse.vulkan_image(graphics_queue.clone()); - let roughness = self.roughness.vulkan_image(graphics_queue.clone()); - let textures = data::Textures { - diffuse, roughness, - }; - *cache = Some(textures.clone()); - textures - }, - } - } -} - -pub struct Mesh { - vertices: Arc>, - indices: Arc>, - - id: u64, - // vulkan buffers cache - vulkan: Mutex>, -} - -impl Mesh { - pub fn new( - vertices: Arc>, - indices: Arc>, - ) -> Self { - Self { - vertices, indices, - // TODO: use a better method - id: time::SystemTime::now().duration_since(time::UNIX_EPOCH).unwrap().as_nanos() as u64, - vulkan: Mutex::new(None), - } - } - - pub fn vulkan_buffers( - &self, - graphics_queue: Arc, - ) -> ( - Arc>, - Arc>, - ) { - let mut cache = self.vulkan.lock().unwrap(); - match &mut *cache { - Some(data) => (data.vbuffer.clone(), data.ibuffer.clone()), - None => { - let (vbuffer, vfuture) = vb::immutable::ImmutableBuffer::from_iter( - self.vertices.iter().cloned(), - vb::BufferUsage::vertex_buffer(), - graphics_queue.clone(), - ).unwrap(); - let (ibuffer, ifuture) = vb::immutable::ImmutableBuffer::from_iter( - self.indices.iter().cloned(), - vb::BufferUsage::index_buffer(), - graphics_queue.clone(), - ).unwrap(); - vfuture.flush().unwrap(); - ifuture.flush().unwrap(); - - *cache = Some(data::VertexData { - vbuffer: vbuffer.clone(), - ibuffer: ibuffer.clone(), - }); - - (vbuffer.clone(), ibuffer.clone()) - }, - } - } -} - pub trait Renderable { fn render_data(&self) -> Option<(ResourceID, ResourceID, &cgm::Matrix4)> { None @@ -218,120 +95,3 @@ impl Renderable for Object { } } -pub trait ChannelLayout { - fn vulkan_from_image( - image: Arc, - graphics_queue: Arc, - ) -> Arc>; - - fn vulkan_from_value( - &self, - graphics_queue: Arc, - ) -> Arc>; -} - -impl ChannelLayout for color::XYZ { - fn vulkan_from_image( - image: Arc, - graphics_queue: Arc, - ) -> Arc> { - let (width, height) = (image.width(), image.height()); - let rgba = image.to_rgba(); - // TODO(q3k): RGB -> CIE XYZ - let (image_view, future) = vm::ImmutableImage::from_iter( - rgba.into_raw().iter().cloned(), - vm::Dimensions::Dim2d{ width, height }, - vf::Format::R8G8B8A8Unorm, - graphics_queue.clone(), - ).unwrap(); - - future.flush().unwrap(); - image_view - } - - fn vulkan_from_value( - &self, - graphics_queue: Arc, - ) -> Arc> { - let mut image = image::ImageBuffer::, Vec>::new(1, 1); - image.put_pixel(0, 0, image::Rgba([self.x, self.y, self.z, 0.0])); - - let (image_view, future) = vm::ImmutableImage::from_iter( - image.into_raw().iter().cloned(), - vm::Dimensions::Dim2d{ width: 1, height: 1 }, - vf::Format::R32G32B32A32Sfloat, - graphics_queue.clone(), - ).unwrap(); - future.flush().unwrap(); - image_view - } -} - -impl ChannelLayout for color::LinearF32 { - fn vulkan_from_image( - image: Arc, - graphics_queue: Arc, - ) -> Arc> { - let (width, height) = (image.width(), image.height()); - assert!(match image.color() { - image::ColorType::L8 => true, - image::ColorType::L16 => true, - _ => false, - }, "linearf32 texture must be 8-bit grayscale"); - let gray = image.to_luma(); - let (image_view, future) = vm::ImmutableImage::from_iter( - gray.into_raw().iter().cloned(), - vm::Dimensions::Dim2d{ width, height }, - vf::Format::R8G8B8A8Unorm, - graphics_queue.clone(), - ).unwrap(); - - future.flush().unwrap(); - image_view - } - - fn vulkan_from_value( - &self, - graphics_queue: Arc, - ) -> Arc> { - let mut image = image::ImageBuffer::, Vec>::new(1, 1); - image.put_pixel(0, 0, image::Luma([self.d])); - - let (image_view, future) = vm::ImmutableImage::from_iter( - image.into_raw().iter().cloned(), - vm::Dimensions::Dim2d{ width: 1, height: 1 }, - vf::Format::R32Sfloat, - graphics_queue.clone(), - ).unwrap(); - - future.flush().unwrap(); - image_view - } -} - -pub enum Texture { - Color(T), - ImageRef(String), -} - -impl Texture { - fn vulkan_image(&self, graphics_queue: Arc) -> Arc> { - match self { - Texture::::Color(c) => c.vulkan_from_value(graphics_queue), - Texture::::ImageRef(r) => { - let path = &file::resource_path(r.clone()); - let img = Arc::new(image::open(path).unwrap()); - T::vulkan_from_image(img, graphics_queue) - }, - } - } - - pub fn from_color(color: T) -> Self { - Texture::::Color(color) - } - - pub fn from_image(name: String) -> Self { - Texture::::ImageRef(name) - } -} -