From 8683f8b5659b16e00fe5113ae84b6d45d16b1077 Mon Sep 17 00:00:00 2001 From: alphafetus Date: Tue, 25 Aug 2026 10:31:36 -0400 Subject: [PATCH] feat: additional implementation of renderer --- src/app.rs | 119 ++++++++++++++++--------------------- src/common/camera.rs | 56 ++++++++--------- src/common/instance.rs | 31 ++++++---- src/common/material.rs | 4 +- src/common/mesh.rs | 15 +++-- src/common/mod.rs | 8 +-- src/common/render_batch.rs | 31 +++++----- src/common/scene.rs | 17 +++--- src/gpu/camera.rs | 2 +- src/gpu/mod.rs | 2 +- src/gpu/vertex3.rs | 8 +-- src/loaders/gltf_loader.rs | 8 +-- src/loaders/mesh_loader.rs | 30 ++++++---- src/loaders/mod.rs | 2 +- src/loaders/obj_loader.rs | 11 ++-- test_scene.scene | 48 ++++++++------- 16 files changed, 197 insertions(+), 195 deletions(-) diff --git a/src/app.rs b/src/app.rs index 5f8bfc4..e1c726e 100644 --- a/src/app.rs +++ b/src/app.rs @@ -1,4 +1,9 @@ +use crate::common::camera::{Camera, CameraResources}; +use crate::common::instance::InstanceRegistry; use crate::common::mesh::MeshRegistry; +use crate::common::render_batch::RenderBatch; +use crate::common::scene::Scene; +use crate::gpu::instance::GpuInstance; use crate::gpu::vertex3::Vertex3; use crate::triangle; use std::error::Error; @@ -15,35 +20,33 @@ use vulkano::device::physical::{PhysicalDevice, PhysicalDeviceType}; use vulkano::device::{ Device, DeviceCreateInfo, DeviceExtensions, Queue, QueueCreateInfo, QueueFlags, }; +use vulkano::format::Format; use vulkano::image::view::ImageView; use vulkano::image::{Image, ImageCreateInfo, ImageType, ImageUsage}; use vulkano::instance::{Instance, InstanceCreateFlags, InstanceCreateInfo, InstanceExtensions}; use vulkano::memory::allocator::{AllocationCreateInfo, MemoryAllocator, StandardMemoryAllocator}; use vulkano::pipeline::graphics::GraphicsPipelineCreateInfo; use vulkano::pipeline::graphics::color_blend::{ColorBlendAttachmentState, ColorBlendState}; +use vulkano::pipeline::graphics::depth_stencil::{DepthState, DepthStencilState}; use vulkano::pipeline::graphics::input_assembly::InputAssemblyState; use vulkano::pipeline::graphics::multisample::MultisampleState; use vulkano::pipeline::graphics::rasterization::RasterizationState; use vulkano::pipeline::graphics::vertex_input::{Vertex, VertexDefinition}; use vulkano::pipeline::graphics::viewport::{Viewport, ViewportState}; use vulkano::pipeline::layout::PipelineDescriptorSetLayoutCreateInfo; -use vulkano::pipeline::{DynamicState, GraphicsPipeline, Pipeline, PipelineBindPoint, PipelineLayout, PipelineShaderStageCreateInfo}; +use vulkano::pipeline::{ + DynamicState, GraphicsPipeline, Pipeline, PipelineBindPoint, PipelineLayout, + PipelineShaderStageCreateInfo, +}; use vulkano::render_pass::{Framebuffer, FramebufferCreateInfo, RenderPass, Subpass}; use vulkano::shader::ShaderModule; use vulkano::swapchain::{Surface, Swapchain, SwapchainCreateInfo, SwapchainPresentInfo}; use vulkano::sync::GpuFuture; use vulkano::{Validated, VulkanError, VulkanLibrary, swapchain, sync}; -use vulkano::format::Format; -use vulkano::pipeline::graphics::depth_stencil::{DepthState, DepthStencilState}; use winit::application::ApplicationHandler; use winit::event::WindowEvent; use winit::event_loop::ActiveEventLoop; use winit::window::{Window, WindowAttributes, WindowId}; -use crate::common::camera::{Camera, CameraResources}; -use crate::common::instance::InstanceRegistry; -use crate::common::render_batch::RenderBatch; -use crate::common::scene::Scene; -use crate::gpu::instance::GpuInstance; struct VulkanContext { window: Arc, @@ -165,23 +168,14 @@ impl VulkanContext { let frag_shader = triangle::load_fragment(device.clone()) .map_err(|e| format!("Failed to load fragment shader: {e}"))?; - let framebuffers = Self::create_framebuffers( - mem_allocator.clone(), - &images, - &render_pass - )?; + let framebuffers = Self::create_framebuffers(mem_allocator.clone(), &images, &render_pass)?; let image_extents = swapchain.image_extent(); // Create the camera. let camera = Camera::new(image_extents); - let pipeline = Self::create_pipeline( - &device, - &vert_shader, - &frag_shader, - &render_pass, - )?; + let pipeline = Self::create_pipeline(&device, &vert_shader, &frag_shader, &render_pass)?; // Get descriptor set layout let pipeline_layout = pipeline.layout().clone(); @@ -191,17 +185,12 @@ impl VulkanContext { let camera_resources = CameraResources::new( mem_allocator.clone(), desc_allocator.clone(), - desc_set_layout + desc_set_layout, ); let scene = Scene::from_file_json("./test_scene.scene"); - let mesh_registry = Arc::new(MeshRegistry::from_scene( - &scene, - mem_allocator.clone() - )); - let instance_registry = Arc::new(InstanceRegistry::from_scene( - &scene - )); + let mesh_registry = Arc::new(MeshRegistry::from_scene(&scene, mem_allocator.clone())); + let instance_registry = Arc::new(InstanceRegistry::from_scene(&scene)); Ok(Self { window, @@ -220,7 +209,7 @@ impl VulkanContext { mesh_registry, instance_registry, camera, - camera_resources + camera_resources, }) } @@ -260,16 +249,13 @@ impl VulkanContext { RenderBatch::build_batches( self.mem_allocator.clone(), self.mesh_registry.clone(), - self.instance_registry.clone() - ) + self.instance_registry.clone(), + ), )?; let future = sync::now(self.device.clone()) .join(acquire_future) - .then_execute( - self.queue.clone(), - cmd_buffer.clone(), - )? + .then_execute(self.queue.clone(), cmd_buffer.clone())? .then_swapchain_present( self.queue.clone(), SwapchainPresentInfo::swapchain_image_index(self.swapchain.clone(), image_idx), @@ -339,19 +325,17 @@ impl VulkanContext { images: &Vec>, render_pass: &Arc, ) -> Result>, Box> { - let depth_buffer = ImageView::new_default( - Image::new( - alloc.clone(), - ImageCreateInfo { - image_type: ImageType::Dim2d, - format: Format::D16_UNORM, - extent: images[0].extent(), - usage: ImageUsage::DEPTH_STENCIL_ATTACHMENT | ImageUsage::TRANSIENT_ATTACHMENT, - ..Default::default() - }, - AllocationCreateInfo::default() - )? - )?; + let depth_buffer = ImageView::new_default(Image::new( + alloc.clone(), + ImageCreateInfo { + image_type: ImageType::Dim2d, + format: Format::D16_UNORM, + extent: images[0].extent(), + usage: ImageUsage::DEPTH_STENCIL_ATTACHMENT | ImageUsage::TRANSIENT_ATTACHMENT, + ..Default::default() + }, + AllocationCreateInfo::default(), + )?)?; let framebuffers = images .iter() @@ -388,8 +372,8 @@ impl VulkanContext { .entry_point("main") .ok_or("Failed to find fragment shader entry point")?; - let vertex_input_state = [Vertex3::per_vertex(), GpuInstance::per_instance()] - .definition(&vs)?; + let vertex_input_state = + [Vertex3::per_vertex(), GpuInstance::per_instance()].definition(&vs)?; let stages = vec![ PipelineShaderStageCreateInfo::new(vs), @@ -453,15 +437,12 @@ impl VulkanContext { queue.queue_family_index(), CommandBufferUsage::OneTimeSubmit, ) - .expect("Couldn't create command buffer builder"); + .expect("Couldn't create command buffer builder"); builder .begin_render_pass( RenderPassBeginInfo { - clear_values: vec![ - Some([0.1, 0.1, 0.1, 0.5].into()), - Some(1f32.into()), - ], + clear_values: vec![Some([0.1, 0.1, 0.1, 0.5].into()), Some(1f32.into())], ..RenderPassBeginInfo::framebuffer(framebuffer.clone()) }, SubpassBeginInfo { @@ -469,10 +450,7 @@ impl VulkanContext { ..Default::default() }, )? - .set_viewport( - 0, - [camera.viewport()].into_iter().collect() - )? + .set_viewport(0, [camera.viewport()].into_iter().collect())? .bind_descriptor_sets( PipelineBindPoint::Graphics, pipeline.layout().clone(), @@ -486,13 +464,20 @@ impl VulkanContext { unsafe { render_batches.iter().for_each(|batch| { // Grab mesh information - let mesh = mesh_registry.get(&batch.mesh_id) + let mesh = mesh_registry + .get(&batch.mesh_id) .expect("Mesh does not exist in registry"); builder .bind_vertex_buffers(1, batch.instance_buffer.clone()) .unwrap() - .draw_indexed(mesh.index_count as u32, batch.instance_count, mesh.index_loc as u32, mesh.vertex_loc as i32, 0) + .draw_indexed( + mesh.index_count as u32, + batch.instance_count, + mesh.index_loc as u32, + mesh.vertex_loc as i32, + 0, + ) .unwrap(); }); } @@ -524,12 +509,11 @@ impl VulkanContext { self.swapchain_images = new_images; // Recreate the framebuffers, which depend on the swapchain. - let new_framebuffers = - Self::create_framebuffers( - self.mem_allocator.clone(), - &self.swapchain_images, - &self.render_pass - )?; + let new_framebuffers = Self::create_framebuffers( + self.mem_allocator.clone(), + &self.swapchain_images, + &self.render_pass, + )?; self.framebuffers = new_framebuffers; @@ -541,7 +525,8 @@ impl VulkanContext { &self.render_pass, )?; - self.camera.extents([image_extents.width, image_extents.height]); + self.camera + .extents([image_extents.width, image_extents.height]); self.pipeline = new_pipeline; } diff --git a/src/common/camera.rs b/src/common/camera.rs index f71863b..d10ebe2 100644 --- a/src/common/camera.rs +++ b/src/common/camera.rs @@ -1,13 +1,13 @@ +use crate::gpu::camera::CameraUniform; +use nalgebra::{Matrix4, Point3, Vector2, Vector3}; use std::f32::consts::PI; use std::sync::Arc; -use nalgebra::{Matrix4, Point3, Vector2, Vector3}; use vulkano::buffer::{Buffer, BufferCreateInfo, BufferUsage, Subbuffer}; use vulkano::descriptor_set::allocator::DescriptorSetAllocator; -use vulkano::descriptor_set::{DescriptorSet, WriteDescriptorSet}; use vulkano::descriptor_set::layout::DescriptorSetLayout; +use vulkano::descriptor_set::{DescriptorSet, WriteDescriptorSet}; use vulkano::memory::allocator::{AllocationCreateInfo, MemoryAllocator, MemoryTypeFilter}; use vulkano::pipeline::graphics::viewport::Viewport; -use crate::gpu::camera::CameraUniform; /// A camera set within 3D space. pub struct Camera { @@ -28,9 +28,7 @@ pub struct Camera { impl Camera { /// Creates a new camera. This default camera is positioned at (1, 1, 1) and is looking at /// (0, 0, 0), and a default FOV of 70 degrees. - pub fn new( - extents: impl Into> - ) -> Self { + pub fn new(extents: impl Into>) -> Self { let extents = extents.into(); let position = Vector3::new(-7.0, 7.0, -7.0); let target = Vector3::zeros(); @@ -84,7 +82,7 @@ impl Camera { Matrix4::look_at_rh( &Point3::from(self.position), &Point3::from(self.forward - self.position), - &self.up + &self.up, ) } @@ -92,12 +90,7 @@ impl Camera { pub fn get_projection(&self) -> Matrix4 { let aspect = self.extents.x as f32 / self.extents.y as f32; - let mut proj = Matrix4::new_perspective( - aspect, - self.fov, - 1.0, - 10000.0 - ); + let mut proj = Matrix4::new_perspective(aspect, self.fov, 1.0, 10000.0); // Flip the y-axis, since Vulkan uses a different coordinate system. proj[(1, 1)] *= -1.0; @@ -133,30 +126,34 @@ impl CameraResources { desc_layout: Arc, ) -> Arc { // Allocate the buffer - let buffer = Arc::new(Buffer::new_sized::( - alloc.clone(), - BufferCreateInfo { - usage: BufferUsage::UNIFORM_BUFFER, - ..Default::default() - }, - AllocationCreateInfo { - memory_type_filter: MemoryTypeFilter::PREFER_HOST | - MemoryTypeFilter::HOST_SEQUENTIAL_WRITE, - ..Default::default() - } - ).expect("Couldn't allocate the camera uniform buffer")); + let buffer = Arc::new( + Buffer::new_sized::( + alloc.clone(), + BufferCreateInfo { + usage: BufferUsage::UNIFORM_BUFFER, + ..Default::default() + }, + AllocationCreateInfo { + memory_type_filter: MemoryTypeFilter::PREFER_HOST + | MemoryTypeFilter::HOST_SEQUENTIAL_WRITE, + ..Default::default() + }, + ) + .expect("Couldn't allocate the camera uniform buffer"), + ); // Create the descriptor set let descriptor_set = DescriptorSet::new( desc_alloc.clone(), desc_layout, [WriteDescriptorSet::buffer(0, buffer.as_ref().clone())], - [] - ).expect("Couldn't create camera descriptor set"); + [], + ) + .expect("Couldn't create camera descriptor set"); Arc::new(Self { buffer, - descriptor_set + descriptor_set, }) } @@ -166,8 +163,7 @@ impl CameraResources { let view = camera.get_view(); let proj = camera.get_projection(); - let mut buffer_data = self.buffer.write() - .unwrap(); + let mut buffer_data = self.buffer.write().unwrap(); buffer_data.proj = proj.into(); buffer_data.view = view.into(); } diff --git a/src/common/instance.rs b/src/common/instance.rs index 523d998..48956cd 100644 --- a/src/common/instance.rs +++ b/src/common/instance.rs @@ -1,6 +1,6 @@ -use std::collections::HashMap; use crate::common::scene::{Scene, SceneInstance}; use nalgebra::{Matrix4, Vector3, Vector4}; +use std::collections::HashMap; /// Contains all information about an instance of a mesh, specifically its translation, rotation, /// and scale. Note that the rotation is a [`Vector4`], and not a `Quaternion`. @@ -44,7 +44,13 @@ impl From for MeshInstance { } impl From<&SceneInstance> for MeshInstance { - fn from(SceneInstance { translation, rotation, scale }: &SceneInstance) -> Self { + fn from( + SceneInstance { + translation, + rotation, + scale, + }: &SceneInstance, + ) -> Self { Self { translation: Vector3::from(*translation).to_homogeneous(), rotation: Vector3::from(*rotation).to_homogeneous(), @@ -61,17 +67,18 @@ pub struct InstanceRegistry { impl InstanceRegistry { pub fn from_scene(scene: &Scene) -> Self { // Read information about the instances from the scene. - let instances: HashMap> = scene.instances.iter() - .fold(HashMap::new(), |mut map, (mesh_id, instance)| { - map.entry(mesh_id.clone()) - .and_modify(|v| v.push(instance.into())) - .or_insert(vec![instance.into()]); - map - }); + let instances: HashMap> = + scene + .instances + .iter() + .fold(HashMap::new(), |mut map, (mesh_id, instance)| { + map.entry(mesh_id.clone()) + .and_modify(|v| v.push(instance.into())) + .or_insert(vec![instance.into()]); + map + }); - Self { - instances - } + Self { instances } } pub fn get_instances_for(&self, mesh_id: &String) -> Vec { diff --git a/src/common/material.rs b/src/common/material.rs index 70ad37c..8cae542 100644 --- a/src/common/material.rs +++ b/src/common/material.rs @@ -1,13 +1,13 @@ use std::collections::HashMap; pub struct MaterialRegistry { - materials: HashMap + materials: HashMap, } impl MaterialRegistry { pub fn new() -> Self { Self { - materials: HashMap::new() + materials: HashMap::new(), } } diff --git a/src/common/mesh.rs b/src/common/mesh.rs index bbd8963..2e92ace 100644 --- a/src/common/mesh.rs +++ b/src/common/mesh.rs @@ -1,11 +1,11 @@ use crate::common::scene::Scene; use crate::gpu::vertex3::Vertex3; +use crate::loaders::mesh_loader::{MeshInfo, MeshLoader}; use std::collections::HashMap; use std::sync::Arc; use vulkano::buffer::{Buffer, BufferCreateInfo, BufferUsage, Subbuffer}; use vulkano::memory::allocator::{AllocationCreateInfo, MemoryAllocator, MemoryTypeFilter}; use wavefront::Obj; -use crate::loaders::mesh_loader::{MeshInfo, MeshLoader}; /// This struct is slightly misleading - it doesn't actually contain the mesh information, but /// the locations of the mesh's information in the overall application's vertex buffer, index buffer, @@ -56,7 +56,9 @@ impl MeshRegistry { .map(|(id, path)| { ( id.clone(), - mesh_loader.load_mesh(path).expect("Couldn't read wavefront file"), + mesh_loader + .load_mesh(path) + .expect("Couldn't read wavefront file"), ) }) .collect::>(); @@ -71,7 +73,9 @@ impl MeshRegistry { let all_verts = obj.vertices; let all_norms = obj.normals; let obj_num_verts = all_verts.len(); - all_verts.iter().zip(all_norms.iter()) + all_verts + .iter() + .zip(all_norms.iter()) .zip(obj.uvs.iter()) .for_each(|((pos, norm), uv)| { buf_verts.push(Vertex3::new(*pos, *norm, *uv)); @@ -81,7 +85,10 @@ impl MeshRegistry { let obj_num_idx = obj.indices.len(); buf_indices.extend(obj.indices); - println!("Loaded mesh \"{}\" with {} vertices and {} indices", id, obj_num_verts, obj_num_idx); + println!( + "Loaded mesh \"{}\" with {} vertices and {} indices", + id, obj_num_verts, obj_num_idx + ); // TODO Create bounding boxes for each mesh and associate them with the struct. mesh_list.insert( diff --git a/src/common/mod.rs b/src/common/mod.rs index 439b6b2..769b9e3 100644 --- a/src/common/mod.rs +++ b/src/common/mod.rs @@ -1,6 +1,6 @@ -pub mod instance; -pub mod mesh; -pub mod scene; -pub mod render_batch; pub mod camera; +pub mod instance; mod material; +pub mod mesh; +pub mod render_batch; +pub mod scene; diff --git a/src/common/render_batch.rs b/src/common/render_batch.rs index 199145b..d732f1f 100644 --- a/src/common/render_batch.rs +++ b/src/common/render_batch.rs @@ -1,9 +1,9 @@ -use std::sync::Arc; -use vulkano::buffer::{Buffer, BufferCreateInfo, BufferUsage, Subbuffer}; -use vulkano::memory::allocator::{AllocationCreateInfo, MemoryAllocator, MemoryTypeFilter}; use crate::common::instance::InstanceRegistry; use crate::common::mesh::MeshRegistry; use crate::gpu::instance::GpuInstance; +use std::sync::Arc; +use vulkano::buffer::{Buffer, BufferCreateInfo, BufferUsage, Subbuffer}; +use vulkano::memory::allocator::{AllocationCreateInfo, MemoryAllocator, MemoryTypeFilter}; #[derive(Debug, Clone)] pub struct RenderBatch { @@ -18,9 +18,11 @@ impl RenderBatch { pub fn build_batches( allocator: Arc, mesh_registry: Arc, - instance_registry: Arc + instance_registry: Arc, ) -> Vec { - mesh_registry.meshes.iter() + mesh_registry + .meshes + .iter() .filter_map(|(id, mesh)| { let instances = instance_registry.get_instances_for(id); @@ -29,11 +31,10 @@ impl RenderBatch { return None; } - let gpu_instances = instances.iter() + let gpu_instances = instances + .iter() .cloned() - .map(|instance| { - instance.into() - }) + .map(|instance| instance.into()) .collect::>(); // Build instances into a RenderBatch @@ -44,18 +45,20 @@ impl RenderBatch { ..Default::default() }, AllocationCreateInfo { - memory_type_filter: MemoryTypeFilter::PREFER_DEVICE | - MemoryTypeFilter::HOST_SEQUENTIAL_WRITE, + memory_type_filter: MemoryTypeFilter::PREFER_DEVICE + | MemoryTypeFilter::HOST_SEQUENTIAL_WRITE, ..Default::default() }, - gpu_instances - ).expect("Couldn't allocate instance buffer"); + gpu_instances, + ) + .expect("Couldn't allocate instance buffer"); Some(Self { mesh_id: id.clone(), instance_buffer, instance_count: instances.len() as u32, }) - }).collect() + }) + .collect() } } diff --git a/src/common/scene.rs b/src/common/scene.rs index eeb74d2..b0f9574 100644 --- a/src/common/scene.rs +++ b/src/common/scene.rs @@ -89,24 +89,23 @@ pub struct SceneInstance { #[cfg(test)] pub mod create_files { + pub use super::*; use std::error::Error; use std::io::Write; - pub use super::*; #[test] pub fn create_test_scene() -> Result<(), Box> { let scene = Scene { name: "Testing Scene".to_string(), - mesh_paths: HashMap::from([ - ("venator".to_string(), "Venator.obj".to_string()) - ]), - instances: HashMap::from([ - ("venator".to_string(), SceneInstance { + mesh_paths: HashMap::from([("venator".to_string(), "Venator.obj".to_string())]), + instances: HashMap::from([( + "venator".to_string(), + SceneInstance { translation: [0.0, 0.0, 0.0], rotation: [0.0, 0.0, 0.0], - scale: [1.0, 1.0, 1.0] - }) - ]) + scale: [1.0, 1.0, 1.0], + }, + )]), }; let json = serde_json::to_string_pretty(&scene)?; diff --git a/src/gpu/camera.rs b/src/gpu/camera.rs index e8d8edd..93f1055 100644 --- a/src/gpu/camera.rs +++ b/src/gpu/camera.rs @@ -1,5 +1,5 @@ -use vulkano::buffer::BufferContents; use crate::common::camera::Camera; +use vulkano::buffer::BufferContents; #[derive(BufferContents)] #[repr(C)] diff --git a/src/gpu/mod.rs b/src/gpu/mod.rs index f34f871..7b47098 100644 --- a/src/gpu/mod.rs +++ b/src/gpu/mod.rs @@ -1,3 +1,3 @@ +pub mod camera; pub mod instance; pub mod vertex3; -pub mod camera; diff --git a/src/gpu/vertex3.rs b/src/gpu/vertex3.rs index 78c60d9..709f90b 100644 --- a/src/gpu/vertex3.rs +++ b/src/gpu/vertex3.rs @@ -13,15 +13,11 @@ pub struct Vertex3 { } impl Vertex3 { - pub fn new( - position: [f32; 3], - normal: [f32; 3], - uv: [f32; 3], - ) -> Self { + pub fn new(position: [f32; 3], normal: [f32; 3], uv: [f32; 3]) -> Self { Self { position, normal, - uv + uv, } } } diff --git a/src/loaders/gltf_loader.rs b/src/loaders/gltf_loader.rs index 9354bc1..c2d724f 100644 --- a/src/loaders/gltf_loader.rs +++ b/src/loaders/gltf_loader.rs @@ -1,6 +1,6 @@ -use std::path::Path; -use anyhow::Result; use crate::loaders::mesh_loader::{MeshFileLoader, MeshInfo}; +use anyhow::Result; +use std::path::Path; pub struct GltfLoader; @@ -51,7 +51,7 @@ impl MeshFileLoader for GltfLoader { vertices, indices, normals, - uvs + uvs, }) } -} \ No newline at end of file +} diff --git a/src/loaders/mesh_loader.rs b/src/loaders/mesh_loader.rs index e676d5d..e04d7f1 100644 --- a/src/loaders/mesh_loader.rs +++ b/src/loaders/mesh_loader.rs @@ -1,9 +1,9 @@ +use super::gltf_loader::*; +use crate::loaders::obj_loader::ObjLoader; +use anyhow::Result; use std::collections::HashMap; use std::path::Path; -use anyhow::Result; use thiserror::Error; -use crate::loaders::obj_loader::ObjLoader; -use super::gltf_loader::*; pub struct MeshInfo { /// The mesh's vertices. @@ -21,7 +21,7 @@ pub trait MeshFileLoader { } pub struct MeshLoader { - loaders: HashMap> + loaders: HashMap>, } #[derive(Error, Debug)] @@ -29,29 +29,37 @@ pub enum MeshLoaderError { #[error("file extension is missing")] MissingExtension, #[error("extension {0} is not supported")] - ExtensionNotSupported(String) + ExtensionNotSupported(String), } impl MeshLoader { pub fn new() -> Self { let mut loaders = HashMap::new(); - loaders.insert("gltf".into(), Box::new(GltfLoader) as Box); + loaders.insert( + "gltf".into(), + Box::new(GltfLoader) as Box, + ); + loaders.insert( + "glb".into(), + Box::new(GltfLoader) as Box, + ); loaders.insert("obj".into(), Box::new(ObjLoader)); - Self { - loaders - } + Self { loaders } } /// Loads a mesh and returns a `Result` containing the information. pub fn load_mesh>(&self, path: &P) -> Result { - let ext = path.as_ref().extension() + let ext = path + .as_ref() + .extension() .and_then(|ext| ext.to_str()) .ok_or(MeshLoaderError::MissingExtension)?; println!("Found extension {}, continuing with loading", ext); - self.loaders.get(ext) + self.loaders + .get(ext) .ok_or(MeshLoaderError::ExtensionNotSupported(ext.to_string()))? .load_mesh(path.as_ref()) } diff --git a/src/loaders/mod.rs b/src/loaders/mod.rs index 5d9dca3..a29e1a2 100644 --- a/src/loaders/mod.rs +++ b/src/loaders/mod.rs @@ -1,3 +1,3 @@ pub mod gltf_loader; pub mod mesh_loader; -mod obj_loader; \ No newline at end of file +mod obj_loader; diff --git a/src/loaders/obj_loader.rs b/src/loaders/obj_loader.rs index ad4ab6a..d9a1683 100644 --- a/src/loaders/obj_loader.rs +++ b/src/loaders/obj_loader.rs @@ -1,14 +1,13 @@ -use std::path::Path; -use wavefront::Obj; use crate::gpu::vertex3::Vertex3; use crate::loaders::mesh_loader::{MeshFileLoader, MeshInfo}; +use std::path::Path; +use wavefront::Obj; pub struct ObjLoader; impl MeshFileLoader for ObjLoader { fn load_mesh(&self, path: &Path) -> anyhow::Result { - let obj_info = Obj::from_file(path) - .expect("Couldn't read wavefront file"); + let obj_info = Obj::from_file(path).expect("Couldn't read wavefront file"); let index_list = obj_info .triangles() @@ -23,7 +22,7 @@ impl MeshFileLoader for ObjLoader { vertices: obj_info.positions().to_vec(), normals: obj_info.normals().to_vec(), indices: index_list, - uvs: obj_info.uvs().to_vec() + uvs: obj_info.uvs().to_vec(), }) } -} \ No newline at end of file +} diff --git a/test_scene.scene b/test_scene.scene index 0598906..2608faa 100644 --- a/test_scene.scene +++ b/test_scene.scene @@ -1,26 +1,28 @@ { - "name": "Testing Scene", - "mesh_paths": { - "gunship": "meshes/laat_gunship/scene.obj", - "trooper": "meshes/clone_trooper/scene.gltf" - }, - "instances": { - "trooper": { - "translation": [ - 0.0, - 0.0, - 0.0 - ], - "rotation": [ - 0.0, - 0.0, - 0.0 - ], - "scale": [ - 1.0, - 1.0, - 1.0 - ] + "name": "Testing Scene", + "mesh_paths": { + "gunship": "meshes/laat_gunship/scene.obj", + "trooper": "meshes/clone_trooper/scene.gltf", + "destroyer": "../meshes/sw_isd.glb", + "interceptor": "../meshes/sw_tie_interceptor.glb" + }, + "instances": { + "interceptor": { + "translation": [ + 0.0, + 0.0, + 0.0 + ], + "rotation": [ + 0.0, + 0.0, + 0.0 + ], + "scale": [ + 1.0, + 1.0, + 1.0 + ] + } } - } }