Refactor texture loading
This commit is contained in:
parent
f91c0792b2
commit
a32cf6c747
19 changed files with 1499 additions and 337 deletions
10
Cargo.lock
generated
10
Cargo.lock
generated
|
@ -2090,6 +2090,7 @@ dependencies = [
|
||||||
"image",
|
"image",
|
||||||
"rand 0.9.1",
|
"rand 0.9.1",
|
||||||
"thiserror 2.0.12",
|
"thiserror 2.0.12",
|
||||||
|
"tobj",
|
||||||
"tracing",
|
"tracing",
|
||||||
"tracing-log",
|
"tracing-log",
|
||||||
"tracing-subscriber",
|
"tracing-subscriber",
|
||||||
|
@ -2466,6 +2467,15 @@ dependencies = [
|
||||||
"zerovec",
|
"zerovec",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tobj"
|
||||||
|
version = "4.0.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "04aca6092e5978e708ee784e8ab9b5cf3cdb598b28f99a2f257446e7081a7025"
|
||||||
|
dependencies = [
|
||||||
|
"ahash",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "toml"
|
name = "toml"
|
||||||
version = "0.8.22"
|
version = "0.8.22"
|
||||||
|
|
|
@ -28,3 +28,6 @@ tracing-tracy = "0.11"
|
||||||
|
|
||||||
# Random
|
# Random
|
||||||
rand = "0.9"
|
rand = "0.9"
|
||||||
|
|
||||||
|
# OBJ loader
|
||||||
|
tobj = "4.0"
|
||||||
|
|
BIN
res/objects/cube-diffuse.jpg
Normal file
BIN
res/objects/cube-diffuse.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 25 KiB |
BIN
res/objects/cube-normal.png
Normal file
BIN
res/objects/cube-normal.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 117 KiB |
1143
res/objects/cube.obj
Normal file
1143
res/objects/cube.obj
Normal file
File diff suppressed because it is too large
Load diff
|
@ -1,5 +1,5 @@
|
||||||
pub mod material_manager;
|
pub mod material_manager;
|
||||||
pub mod primitives;
|
pub mod primitives;
|
||||||
pub mod render_pass_manager;
|
pub mod render_pass_manager;
|
||||||
pub mod texture;
|
pub mod resources;
|
||||||
pub mod vulkan_context;
|
pub mod vulkan_context;
|
||||||
|
|
|
@ -14,10 +14,9 @@ mod command;
|
||||||
|
|
||||||
pub mod camera;
|
pub mod camera;
|
||||||
pub mod mvp;
|
pub mod mvp;
|
||||||
|
pub mod resource;
|
||||||
pub mod transform;
|
pub mod transform;
|
||||||
pub mod vertex;
|
pub mod vertex;
|
||||||
|
|
||||||
pub mod resource;
|
|
||||||
pub use buffer::{AsBindableBuffer, AsIndexBuffer, AsUniformBuffer, AsVertexBuffer};
|
pub use buffer::{AsBindableBuffer, AsIndexBuffer, AsUniformBuffer, AsVertexBuffer};
|
||||||
pub use command::{AsRecordable, AsRenderableMesh, AsRenderableMeshInstance};
|
pub use command::{AsRecordable, AsRenderableMesh, AsRenderableMeshInstance};
|
||||||
|
|
||||||
|
|
5
src/core/render/resources/meshes/mod.rs
Normal file
5
src/core/render/resources/meshes/mod.rs
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
mod square;
|
||||||
|
pub use square::SquareMesh;
|
||||||
|
|
||||||
|
mod obj;
|
||||||
|
pub use obj::ObjMesh;
|
76
src/core/render/resources/meshes/obj.rs
Normal file
76
src/core/render/resources/meshes/obj.rs
Normal file
|
@ -0,0 +1,76 @@
|
||||||
|
use std::{error::Error, path::PathBuf, sync::Arc};
|
||||||
|
|
||||||
|
use vulkano::{buffer::Subbuffer, memory::allocator::StandardMemoryAllocator};
|
||||||
|
|
||||||
|
use crate::core::render::primitives::{
|
||||||
|
AsIndexBuffer, AsRenderableMesh, AsVertexBuffer, vertex::Vertex3D,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub struct ObjMesh {
|
||||||
|
vertex_buffer: Subbuffer<[Vertex3D]>,
|
||||||
|
index_buffer: Subbuffer<[u32]>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ObjMesh {
|
||||||
|
pub fn new(
|
||||||
|
memory_allocator: &Arc<StandardMemoryAllocator>,
|
||||||
|
file_path: impl Into<PathBuf>,
|
||||||
|
) -> Result<Vec<Self>, Box<dyn Error>> {
|
||||||
|
let (models, _) = tobj::load_obj(
|
||||||
|
&file_path.into(),
|
||||||
|
&tobj::LoadOptions {
|
||||||
|
single_index: true,
|
||||||
|
triangulate: true,
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
)?;
|
||||||
|
|
||||||
|
let meshes = models
|
||||||
|
.into_iter()
|
||||||
|
.map(|model| {
|
||||||
|
let vertices = (0..model.mesh.positions.len() / 3)
|
||||||
|
.map(|i| Vertex3D {
|
||||||
|
position: [
|
||||||
|
model.mesh.positions[i * 3],
|
||||||
|
model.mesh.positions[i * 3 + 1],
|
||||||
|
model.mesh.positions[i * 3 + 2],
|
||||||
|
],
|
||||||
|
uv: [model.mesh.texcoords[i * 2], model.mesh.texcoords[i * 2 + 1]],
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
let indices = model.mesh.indices;
|
||||||
|
|
||||||
|
let vertex_buffer = Vertex3D::create_vertex_buffer(memory_allocator, &vertices)
|
||||||
|
.expect("Failed to create vertex buffer");
|
||||||
|
let index_buffer = u32::create_index_buffer(memory_allocator, &indices)
|
||||||
|
.expect("Failed to create index buffer");
|
||||||
|
|
||||||
|
Self {
|
||||||
|
vertex_buffer,
|
||||||
|
index_buffer,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
Ok(meshes)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AsRenderableMesh<Vertex3D, Subbuffer<[u32]>> for ObjMesh {
|
||||||
|
fn vertex_buffer(&self) -> &Subbuffer<[Vertex3D]> {
|
||||||
|
&self.vertex_buffer
|
||||||
|
}
|
||||||
|
|
||||||
|
fn index_buffer(&self) -> Option<&Subbuffer<[u32]>> {
|
||||||
|
Some(&self.index_buffer)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn vertex_count(&self) -> u32 {
|
||||||
|
self.vertex_buffer.len() as u32
|
||||||
|
}
|
||||||
|
|
||||||
|
fn index_count(&self) -> u32 {
|
||||||
|
self.index_buffer.len() as u32
|
||||||
|
}
|
||||||
|
}
|
|
@ -27,12 +27,12 @@ const VERTICES: [Vertex3D; 4] = [
|
||||||
|
|
||||||
const INDICES: [u32; 6] = [0, 2, 1, 2, 3, 1];
|
const INDICES: [u32; 6] = [0, 2, 1, 2, 3, 1];
|
||||||
|
|
||||||
pub struct Square {
|
pub struct SquareMesh {
|
||||||
vertex_buffer: Subbuffer<[Vertex3D]>,
|
vertex_buffer: Subbuffer<[Vertex3D]>,
|
||||||
index_buffer: Subbuffer<[u32]>,
|
index_buffer: Subbuffer<[u32]>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Square {
|
impl SquareMesh {
|
||||||
pub fn new(memory_allocator: &Arc<StandardMemoryAllocator>) -> Result<Self, Box<dyn Error>> {
|
pub fn new(memory_allocator: &Arc<StandardMemoryAllocator>) -> Result<Self, Box<dyn Error>> {
|
||||||
let vertex_buffer = Vertex3D::create_vertex_buffer(memory_allocator, &VERTICES)?;
|
let vertex_buffer = Vertex3D::create_vertex_buffer(memory_allocator, &VERTICES)?;
|
||||||
let index_buffer = u32::create_index_buffer(memory_allocator, &INDICES)?;
|
let index_buffer = u32::create_index_buffer(memory_allocator, &INDICES)?;
|
||||||
|
@ -44,7 +44,7 @@ impl Square {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AsRenderableMesh<Vertex3D, Subbuffer<[u32]>> for Square {
|
impl AsRenderableMesh<Vertex3D, Subbuffer<[u32]>> for SquareMesh {
|
||||||
fn vertex_buffer(&self) -> &Subbuffer<[Vertex3D]> {
|
fn vertex_buffer(&self) -> &Subbuffer<[Vertex3D]> {
|
||||||
&self.vertex_buffer
|
&self.vertex_buffer
|
||||||
}
|
}
|
2
src/core/render/resources/mod.rs
Normal file
2
src/core/render/resources/mod.rs
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
pub mod meshes;
|
||||||
|
pub mod texture;
|
127
src/core/render/resources/texture/loader.rs
Normal file
127
src/core/render/resources/texture/loader.rs
Normal file
|
@ -0,0 +1,127 @@
|
||||||
|
use std::{collections::HashMap, error::Error, sync::Arc};
|
||||||
|
|
||||||
|
use vulkano::{
|
||||||
|
command_buffer::{
|
||||||
|
AutoCommandBufferBuilder, CommandBufferUsage, PrimaryCommandBufferAbstract,
|
||||||
|
allocator::StandardCommandBufferAllocator,
|
||||||
|
},
|
||||||
|
device::{Device, Queue},
|
||||||
|
format::Format,
|
||||||
|
image::sampler::SamplerCreateInfo,
|
||||||
|
memory::allocator::StandardMemoryAllocator,
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::core::app::context::WindowContext;
|
||||||
|
|
||||||
|
use super::Texture;
|
||||||
|
|
||||||
|
pub enum TextureSourceKind {
|
||||||
|
File(String),
|
||||||
|
Buffer(Vec<u8>),
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct TextureLoadInfo {
|
||||||
|
pub source: TextureSourceKind,
|
||||||
|
pub sampler_create_info: SamplerCreateInfo,
|
||||||
|
pub image_format: Format,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct TextureLoader {
|
||||||
|
loaded_textures: HashMap<String, Texture>,
|
||||||
|
pending_textures: HashMap<String, TextureLoadInfo>,
|
||||||
|
device: Arc<Device>,
|
||||||
|
command_buffer_allocator: Arc<StandardCommandBufferAllocator>,
|
||||||
|
memory_allocator: Arc<StandardMemoryAllocator>,
|
||||||
|
queue: Arc<Queue>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TextureLoader {
|
||||||
|
pub fn new(app_context: &WindowContext) -> Self {
|
||||||
|
Self {
|
||||||
|
loaded_textures: HashMap::new(),
|
||||||
|
pending_textures: HashMap::new(),
|
||||||
|
device: app_context.device.clone(),
|
||||||
|
command_buffer_allocator: app_context.command_buffer_allocator.clone(),
|
||||||
|
memory_allocator: app_context.memory_allocator.clone(),
|
||||||
|
queue: Self::select_best_suitable_queue(app_context),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn select_best_suitable_queue(app_context: &WindowContext) -> Arc<Queue> {
|
||||||
|
app_context
|
||||||
|
.transfer_queue
|
||||||
|
.as_ref()
|
||||||
|
.map(|queue| {
|
||||||
|
tracing::trace!(
|
||||||
|
"Selected transfer queue for texture loading with family index: {:?}",
|
||||||
|
queue.queue_family_index()
|
||||||
|
);
|
||||||
|
queue.clone()
|
||||||
|
})
|
||||||
|
.or_else(|| {
|
||||||
|
tracing::trace!(
|
||||||
|
"Selected graphics queue for texture loading with family index: {:?}",
|
||||||
|
app_context.graphics_queue.queue_family_index()
|
||||||
|
);
|
||||||
|
Some(app_context.graphics_queue.clone())
|
||||||
|
})
|
||||||
|
.unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add_texture(&mut self, name: String, load_info: TextureLoadInfo) {
|
||||||
|
self.pending_textures.insert(name, load_info);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn load_pending_textures(&mut self) -> Result<(), Box<dyn Error>> {
|
||||||
|
let _span = tracing::info_span!("load_pending_textures");
|
||||||
|
let mut uploads = AutoCommandBufferBuilder::primary(
|
||||||
|
self.command_buffer_allocator.clone(),
|
||||||
|
self.queue.queue_family_index(),
|
||||||
|
CommandBufferUsage::OneTimeSubmit,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
let mut loading_textures = HashMap::new();
|
||||||
|
|
||||||
|
tracing::trace!("Pending textures count: {}", self.pending_textures.len());
|
||||||
|
|
||||||
|
for (name, info) in self.pending_textures.iter() {
|
||||||
|
let texture = match &info.source {
|
||||||
|
TextureSourceKind::File(path) => Texture::from_file(
|
||||||
|
&self.device,
|
||||||
|
&self.memory_allocator,
|
||||||
|
&mut uploads,
|
||||||
|
path.as_str(),
|
||||||
|
info,
|
||||||
|
)?,
|
||||||
|
TextureSourceKind::Buffer(buffer) => Texture::from_bytes(
|
||||||
|
&self.device,
|
||||||
|
&self.memory_allocator,
|
||||||
|
&mut uploads,
|
||||||
|
&buffer,
|
||||||
|
info,
|
||||||
|
)?,
|
||||||
|
};
|
||||||
|
|
||||||
|
loading_textures.insert(name.clone(), texture);
|
||||||
|
tracing::trace!("Loaded texture: {}", name);
|
||||||
|
}
|
||||||
|
|
||||||
|
let _ = uploads.build()?.execute(self.queue.clone())?;
|
||||||
|
|
||||||
|
self.loaded_textures.extend(loading_textures);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_texture(&self, name: &str) -> Option<&Texture> {
|
||||||
|
self.loaded_textures.get(name)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn pending_textures_count(&self) -> usize {
|
||||||
|
self.pending_textures.len()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn loaded_textures_count(&self) -> usize {
|
||||||
|
self.loaded_textures.len()
|
||||||
|
}
|
||||||
|
}
|
5
src/core/render/resources/texture/mod.rs
Normal file
5
src/core/render/resources/texture/mod.rs
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
mod texture;
|
||||||
|
pub use texture::Texture;
|
||||||
|
|
||||||
|
mod loader;
|
||||||
|
pub use loader::{TextureLoadInfo, TextureLoader, TextureSourceKind};
|
|
@ -7,22 +7,20 @@ use vulkano::{
|
||||||
command_buffer::{AutoCommandBufferBuilder, CopyBufferToImageInfo, PrimaryAutoCommandBuffer},
|
command_buffer::{AutoCommandBufferBuilder, CopyBufferToImageInfo, PrimaryAutoCommandBuffer},
|
||||||
descriptor_set::{
|
descriptor_set::{
|
||||||
DescriptorSet, WriteDescriptorSet,
|
DescriptorSet, WriteDescriptorSet,
|
||||||
allocator::{DescriptorSetAllocator, StandardDescriptorSetAllocator},
|
allocator::StandardDescriptorSetAllocator,
|
||||||
layout::{DescriptorSetLayout, DescriptorSetLayoutBinding, DescriptorType},
|
layout::{DescriptorSetLayout, DescriptorSetLayoutBinding, DescriptorType},
|
||||||
},
|
},
|
||||||
device::Device,
|
device::Device,
|
||||||
format::Format,
|
format::Format,
|
||||||
image::{
|
image::{Image, ImageCreateInfo, ImageType, ImageUsage, sampler::Sampler, view::ImageView},
|
||||||
Image, ImageCreateInfo, ImageType, ImageUsage,
|
|
||||||
sampler::{Filter, Sampler, SamplerAddressMode, SamplerCreateInfo},
|
|
||||||
view::ImageView,
|
|
||||||
},
|
|
||||||
memory::allocator::{AllocationCreateInfo, MemoryTypeFilter, StandardMemoryAllocator},
|
memory::allocator::{AllocationCreateInfo, MemoryTypeFilter, StandardMemoryAllocator},
|
||||||
shader::ShaderStages,
|
shader::ShaderStages,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::core::render::primitives::AsBindableDescriptorSet;
|
use crate::core::render::primitives::AsBindableDescriptorSet;
|
||||||
|
|
||||||
|
use super::TextureLoadInfo;
|
||||||
|
|
||||||
pub struct Texture {
|
pub struct Texture {
|
||||||
texture: Arc<ImageView>,
|
texture: Arc<ImageView>,
|
||||||
sampler: Arc<Sampler>,
|
sampler: Arc<Sampler>,
|
||||||
|
@ -33,37 +31,39 @@ impl Texture {
|
||||||
Self { texture, sampler }
|
Self { texture, sampler }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_file(
|
pub(super) fn from_file(
|
||||||
device: &Arc<Device>,
|
device: &Arc<Device>,
|
||||||
memory_allocator: &Arc<StandardMemoryAllocator>,
|
memory_allocator: &Arc<StandardMemoryAllocator>,
|
||||||
builder: &mut AutoCommandBufferBuilder<PrimaryAutoCommandBuffer>,
|
builder: &mut AutoCommandBufferBuilder<PrimaryAutoCommandBuffer>,
|
||||||
path: &str,
|
path: &str,
|
||||||
|
load_info: &TextureLoadInfo,
|
||||||
) -> Result<Self, Box<dyn Error>> {
|
) -> Result<Self, Box<dyn Error>> {
|
||||||
let _span = tracing::info_span!("texture_load_from_file", path = path);
|
|
||||||
|
|
||||||
let bytes = std::fs::read(path)?;
|
let bytes = std::fs::read(path)?;
|
||||||
Self::from_bytes(device, memory_allocator, builder, &bytes)
|
Self::from_bytes(device, memory_allocator, builder, &bytes, load_info)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_bytes(
|
pub(super) fn from_bytes(
|
||||||
device: &Arc<Device>,
|
device: &Arc<Device>,
|
||||||
memory_allocator: &Arc<StandardMemoryAllocator>,
|
memory_allocator: &Arc<StandardMemoryAllocator>,
|
||||||
builder: &mut AutoCommandBufferBuilder<PrimaryAutoCommandBuffer>,
|
builder: &mut AutoCommandBufferBuilder<PrimaryAutoCommandBuffer>,
|
||||||
bytes: &[u8],
|
bytes: &[u8],
|
||||||
|
load_info: &TextureLoadInfo,
|
||||||
) -> Result<Self, Box<dyn Error>> {
|
) -> Result<Self, Box<dyn Error>> {
|
||||||
let image = image::load_from_memory(bytes)?;
|
let image = image::load_from_memory(bytes)?;
|
||||||
Self::from_dynamic_image(device, memory_allocator, builder, image)
|
Self::from_dynamic_image(device, memory_allocator, builder, image, load_info)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_dynamic_image(
|
fn from_dynamic_image(
|
||||||
device: &Arc<Device>,
|
device: &Arc<Device>,
|
||||||
memory_allocator: &Arc<StandardMemoryAllocator>,
|
memory_allocator: &Arc<StandardMemoryAllocator>,
|
||||||
builder: &mut AutoCommandBufferBuilder<PrimaryAutoCommandBuffer>,
|
builder: &mut AutoCommandBufferBuilder<PrimaryAutoCommandBuffer>,
|
||||||
image: DynamicImage,
|
image: DynamicImage,
|
||||||
|
load_info: &TextureLoadInfo,
|
||||||
) -> Result<Self, Box<dyn Error>> {
|
) -> Result<Self, Box<dyn Error>> {
|
||||||
let _span = tracing::info_span!("texture_from_dynamic_image");
|
let image_data = match load_info.image_format {
|
||||||
|
Format::R8G8B8A8_SRGB => image.to_rgba8(),
|
||||||
let image_data = image.to_rgba8();
|
_ => return Err("Unsupported format".into()),
|
||||||
|
};
|
||||||
let image_dimensions = image_data.dimensions();
|
let image_dimensions = image_data.dimensions();
|
||||||
let image_data = image_data.into_raw();
|
let image_data = image_data.into_raw();
|
||||||
|
|
||||||
|
@ -90,7 +90,7 @@ impl Texture {
|
||||||
memory_allocator.clone(),
|
memory_allocator.clone(),
|
||||||
ImageCreateInfo {
|
ImageCreateInfo {
|
||||||
image_type: ImageType::Dim2d,
|
image_type: ImageType::Dim2d,
|
||||||
format: Format::R8G8B8A8_SRGB,
|
format: load_info.image_format,
|
||||||
extent: [image_dimensions.0, image_dimensions.1, 1],
|
extent: [image_dimensions.0, image_dimensions.1, 1],
|
||||||
array_layers: 1,
|
array_layers: 1,
|
||||||
usage: ImageUsage::TRANSFER_DST | ImageUsage::SAMPLED,
|
usage: ImageUsage::TRANSFER_DST | ImageUsage::SAMPLED,
|
||||||
|
@ -104,30 +104,12 @@ impl Texture {
|
||||||
image.clone(),
|
image.clone(),
|
||||||
))?;
|
))?;
|
||||||
|
|
||||||
let sampler = Sampler::new(
|
let sampler = Sampler::new(device.clone(), load_info.sampler_create_info.clone())?;
|
||||||
device.clone(),
|
|
||||||
SamplerCreateInfo {
|
|
||||||
mag_filter: Filter::Linear,
|
|
||||||
min_filter: Filter::Linear,
|
|
||||||
address_mode: [SamplerAddressMode::Repeat; 3],
|
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
)?;
|
|
||||||
|
|
||||||
let image_view = ImageView::new_default(image)?;
|
let image_view = ImageView::new_default(image)?;
|
||||||
|
|
||||||
tracing::trace!("Texture loaded with dimensions {:?}", image_dimensions);
|
|
||||||
|
|
||||||
Ok(Self::new(image_view, sampler))
|
Ok(Self::new(image_view, sampler))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_texture(&self) -> &Arc<ImageView> {
|
|
||||||
&self.texture
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_sampler(&self) -> &Arc<Sampler> {
|
|
||||||
&self.sampler
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AsBindableDescriptorSet<Texture> for Texture {
|
impl AsBindableDescriptorSet<Texture> for Texture {
|
|
@ -1 +0,0 @@
|
||||||
pub mod square;
|
|
|
@ -1,2 +1 @@
|
||||||
pub mod meshs;
|
|
||||||
pub mod pipelines;
|
pub mod pipelines;
|
||||||
|
|
|
@ -31,7 +31,7 @@ use crate::core::render::{
|
||||||
AsBindableDescriptorSet, AsRecordable, AsRenderableMesh, AsRenderableMeshInstance,
|
AsBindableDescriptorSet, AsRecordable, AsRenderableMesh, AsRenderableMeshInstance,
|
||||||
mvp::Mvp, transform::TransformRaw, vertex::Vertex3D,
|
mvp::Mvp, transform::TransformRaw, vertex::Vertex3D,
|
||||||
},
|
},
|
||||||
texture::Texture,
|
resources::texture::Texture,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub struct SimplePipelineRenderData<'a> {
|
pub struct SimplePipelineRenderData<'a> {
|
||||||
|
|
|
@ -1,255 +0,0 @@
|
||||||
use std::{error::Error, sync::Arc};
|
|
||||||
|
|
||||||
use vulkano::{
|
|
||||||
buffer::Subbuffer,
|
|
||||||
command_buffer::{AutoCommandBufferBuilder, PrimaryAutoCommandBuffer},
|
|
||||||
descriptor_set::{
|
|
||||||
DescriptorSet, allocator::StandardDescriptorSetAllocator,
|
|
||||||
layout::DescriptorSetLayoutCreateInfo,
|
|
||||||
},
|
|
||||||
device::Device,
|
|
||||||
format::Format,
|
|
||||||
memory::allocator::StandardMemoryAllocator,
|
|
||||||
pipeline::{
|
|
||||||
DynamicState, GraphicsPipeline, Pipeline, PipelineBindPoint, PipelineLayout,
|
|
||||||
PipelineShaderStageCreateInfo,
|
|
||||||
graphics::{
|
|
||||||
GraphicsPipelineCreateInfo,
|
|
||||||
color_blend::{ColorBlendAttachmentState, ColorBlendState},
|
|
||||||
depth_stencil::{DepthState, DepthStencilState},
|
|
||||||
input_assembly::InputAssemblyState,
|
|
||||||
multisample::MultisampleState,
|
|
||||||
rasterization::RasterizationState,
|
|
||||||
subpass::PipelineRenderingCreateInfo,
|
|
||||||
vertex_input::{Vertex, VertexDefinition},
|
|
||||||
viewport::ViewportState,
|
|
||||||
},
|
|
||||||
layout::{PipelineDescriptorSetLayoutCreateInfo, PipelineLayoutCreateFlags},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
use crate::core::render::{
|
|
||||||
primitives::{
|
|
||||||
AsBindableDescriptorSet, AsDrawable, AsIndexBuffer, AsRecordable, AsVertexBuffer, mvp::Mvp,
|
|
||||||
transform::TransformRaw, vertex::Vertex3D,
|
|
||||||
},
|
|
||||||
texture::Texture,
|
|
||||||
};
|
|
||||||
|
|
||||||
const VERTICES: [Vertex3D; 4] = [
|
|
||||||
Vertex3D {
|
|
||||||
position: [-0.5, -0.5, 0.0],
|
|
||||||
uv: [0.0, 0.0],
|
|
||||||
},
|
|
||||||
Vertex3D {
|
|
||||||
position: [-0.5, 0.5, 0.0],
|
|
||||||
uv: [0.0, 1.0],
|
|
||||||
},
|
|
||||||
Vertex3D {
|
|
||||||
position: [0.5, -0.5, 0.0],
|
|
||||||
uv: [1.0, 0.0],
|
|
||||||
},
|
|
||||||
Vertex3D {
|
|
||||||
position: [0.5, 0.5, 0.0],
|
|
||||||
uv: [1.0, 1.0],
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
const INDICES: [u32; 6] = [0, 2, 1, 2, 3, 1];
|
|
||||||
|
|
||||||
pub mod shaders {
|
|
||||||
pub mod vs {
|
|
||||||
vulkano_shaders::shader! {
|
|
||||||
ty: "vertex",
|
|
||||||
path: r"res/shaders/vertex.vert",
|
|
||||||
generate_structs: false,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub mod fs {
|
|
||||||
vulkano_shaders::shader! {
|
|
||||||
ty: "fragment",
|
|
||||||
path: r"res/shaders/vertex.frag",
|
|
||||||
generate_structs: false,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Square {
|
|
||||||
vertex_buffer: Subbuffer<[Vertex3D]>,
|
|
||||||
index_buffer: Subbuffer<[u32]>,
|
|
||||||
pipeline: Arc<GraphicsPipeline>,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Structure pour encapsuler les données de rendu du Square
|
|
||||||
pub struct SquareRenderData<'a> {
|
|
||||||
pub square: &'a Square,
|
|
||||||
pub mvp_uniform: &'a Subbuffer<[Mvp]>,
|
|
||||||
pub transform_uniform: &'a Subbuffer<[TransformRaw]>,
|
|
||||||
pub descriptor_sets: &'a [Arc<DescriptorSet>],
|
|
||||||
pub texture: &'a Texture,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Square {
|
|
||||||
pub fn new(
|
|
||||||
device: &Arc<Device>,
|
|
||||||
memory_allocator: &Arc<StandardMemoryAllocator>,
|
|
||||||
swapchain_format: Format,
|
|
||||||
depth_format: Format,
|
|
||||||
) -> Result<Self, Box<dyn Error>> {
|
|
||||||
let vertex_buffer = Vertex3D::create_vertex_buffer(memory_allocator, &VERTICES)?;
|
|
||||||
|
|
||||||
let index_buffer = u32::create_index_buffer(memory_allocator, &INDICES)?;
|
|
||||||
|
|
||||||
let vs = shaders::vs::load(device.clone())?
|
|
||||||
.entry_point("main")
|
|
||||||
.ok_or("Failed find main entry point of vertex shader".to_string())?;
|
|
||||||
|
|
||||||
let fs = shaders::fs::load(device.clone())?
|
|
||||||
.entry_point("main")
|
|
||||||
.ok_or("Failed find main entry point of fragment shader".to_string())?;
|
|
||||||
|
|
||||||
let vertex_input_state =
|
|
||||||
[Vertex3D::per_vertex(), TransformRaw::per_instance()].definition(&vs)?;
|
|
||||||
|
|
||||||
let stages = [
|
|
||||||
PipelineShaderStageCreateInfo::new(vs),
|
|
||||||
PipelineShaderStageCreateInfo::new(fs),
|
|
||||||
];
|
|
||||||
|
|
||||||
let vertex_bindings = Mvp::as_descriptor_set_layout_bindings();
|
|
||||||
let texture_bindings = Texture::as_descriptor_set_layout_bindings();
|
|
||||||
|
|
||||||
let vertex_descriptor_set_layout = DescriptorSetLayoutCreateInfo {
|
|
||||||
bindings: vertex_bindings,
|
|
||||||
..Default::default()
|
|
||||||
};
|
|
||||||
|
|
||||||
let fragment_descriptor_set_layout = DescriptorSetLayoutCreateInfo {
|
|
||||||
bindings: texture_bindings,
|
|
||||||
..Default::default()
|
|
||||||
};
|
|
||||||
|
|
||||||
let create_info = PipelineDescriptorSetLayoutCreateInfo {
|
|
||||||
set_layouts: vec![vertex_descriptor_set_layout, fragment_descriptor_set_layout],
|
|
||||||
flags: PipelineLayoutCreateFlags::default(),
|
|
||||||
push_constant_ranges: vec![],
|
|
||||||
}
|
|
||||||
.into_pipeline_layout_create_info(device.clone())?;
|
|
||||||
|
|
||||||
let layout = PipelineLayout::new(device.clone(), create_info)?;
|
|
||||||
|
|
||||||
let subpass = PipelineRenderingCreateInfo {
|
|
||||||
color_attachment_formats: vec![Some(swapchain_format)],
|
|
||||||
depth_attachment_format: Some(depth_format),
|
|
||||||
..Default::default()
|
|
||||||
};
|
|
||||||
|
|
||||||
let pipeline = GraphicsPipeline::new(
|
|
||||||
device.clone(),
|
|
||||||
None,
|
|
||||||
GraphicsPipelineCreateInfo {
|
|
||||||
stages: stages.into_iter().collect(),
|
|
||||||
vertex_input_state: Some(vertex_input_state),
|
|
||||||
input_assembly_state: Some(InputAssemblyState::default()),
|
|
||||||
viewport_state: Some(ViewportState::default()),
|
|
||||||
rasterization_state: Some(RasterizationState::default()),
|
|
||||||
multisample_state: Some(MultisampleState::default()),
|
|
||||||
color_blend_state: Some(ColorBlendState::with_attachment_states(
|
|
||||||
subpass.color_attachment_formats.len() as u32,
|
|
||||||
ColorBlendAttachmentState::default(),
|
|
||||||
)),
|
|
||||||
depth_stencil_state: Some(DepthStencilState {
|
|
||||||
depth: Some(DepthState::simple()),
|
|
||||||
..Default::default()
|
|
||||||
}),
|
|
||||||
dynamic_state: [DynamicState::Viewport].into_iter().collect(),
|
|
||||||
subpass: Some(subpass.into()),
|
|
||||||
..GraphicsPipelineCreateInfo::layout(layout)
|
|
||||||
},
|
|
||||||
)?;
|
|
||||||
|
|
||||||
Ok(Self {
|
|
||||||
vertex_buffer,
|
|
||||||
index_buffer,
|
|
||||||
pipeline,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn render(
|
|
||||||
&self,
|
|
||||||
command_buffer: &mut AutoCommandBufferBuilder<PrimaryAutoCommandBuffer>,
|
|
||||||
descriptor_set_allocator: &Arc<StandardDescriptorSetAllocator>,
|
|
||||||
mvp_uniform: &Subbuffer<[Mvp]>,
|
|
||||||
transform_uniform: &Subbuffer<[TransformRaw]>,
|
|
||||||
texture: &Texture,
|
|
||||||
) -> Result<(), Box<dyn Error>> {
|
|
||||||
let layouts = self.pipeline.layout().set_layouts();
|
|
||||||
|
|
||||||
let uniform_descriptor_set =
|
|
||||||
Mvp::as_descriptor_set(descriptor_set_allocator, &layouts[0], mvp_uniform)?;
|
|
||||||
|
|
||||||
let texture_descriptor_set =
|
|
||||||
Texture::as_descriptor_set(descriptor_set_allocator, &layouts[1], texture)?;
|
|
||||||
|
|
||||||
let render_data = SquareRenderData {
|
|
||||||
square: self,
|
|
||||||
mvp_uniform,
|
|
||||||
transform_uniform,
|
|
||||||
texture,
|
|
||||||
descriptor_sets: &[uniform_descriptor_set, texture_descriptor_set],
|
|
||||||
};
|
|
||||||
|
|
||||||
// Utiliser les nouveaux traits pour le rendu
|
|
||||||
Self::record_render_commands(command_buffer, &self.pipeline, &render_data)?;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> AsRecordable<SquareRenderData<'a>> for Square {
|
|
||||||
fn record_render_commands(
|
|
||||||
builder: &mut AutoCommandBufferBuilder<PrimaryAutoCommandBuffer>,
|
|
||||||
pipeline: &Arc<GraphicsPipeline>,
|
|
||||||
data: &SquareRenderData<'a>,
|
|
||||||
) -> Result<(), Box<dyn Error>> {
|
|
||||||
// Bind pipeline
|
|
||||||
builder.bind_pipeline_graphics(pipeline.clone())?;
|
|
||||||
|
|
||||||
// Bind descriptor sets
|
|
||||||
builder.bind_descriptor_sets(
|
|
||||||
PipelineBindPoint::Graphics,
|
|
||||||
pipeline.layout().clone(),
|
|
||||||
0,
|
|
||||||
data.descriptor_sets.iter().cloned().collect::<Vec<_>>(),
|
|
||||||
)?;
|
|
||||||
|
|
||||||
// Bind buffers
|
|
||||||
builder.bind_vertex_buffers(
|
|
||||||
0,
|
|
||||||
(
|
|
||||||
Self::vertex_buffer(data).clone(),
|
|
||||||
data.transform_uniform.clone(),
|
|
||||||
),
|
|
||||||
)?;
|
|
||||||
|
|
||||||
if let Some(index_buffer) = Self::index_buffer(data) {
|
|
||||||
builder.bind_index_buffer(index_buffer.clone())?;
|
|
||||||
unsafe {
|
|
||||||
builder.draw_indexed(
|
|
||||||
Self::index_count(data),
|
|
||||||
Self::instance_count(data),
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
)?;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
unsafe {
|
|
||||||
builder.draw(Self::vertex_count(data), Self::instance_count(data), 0, 0)?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -4,19 +4,22 @@ use super::settings_scene::SettingsScene;
|
||||||
use crate::core::app::DEPTH_IMAGE_ID;
|
use crate::core::app::DEPTH_IMAGE_ID;
|
||||||
use crate::core::app::context::WindowContext;
|
use crate::core::app::context::WindowContext;
|
||||||
use crate::core::app::user_event::UserEvent;
|
use crate::core::app::user_event::UserEvent;
|
||||||
|
use crate::core::render::primitives::AsRecordable;
|
||||||
use crate::core::render::primitives::camera::Camera3D;
|
use crate::core::render::primitives::camera::Camera3D;
|
||||||
use crate::core::render::primitives::mvp::Mvp;
|
|
||||||
use crate::core::render::primitives::transform::Transform;
|
use crate::core::render::primitives::transform::Transform;
|
||||||
use crate::core::render::primitives::{AsBindableDescriptorSet, AsRecordable};
|
|
||||||
use crate::core::render::render_pass_manager::{RenderPassConfig, RenderPassManager};
|
use crate::core::render::render_pass_manager::{RenderPassConfig, RenderPassManager};
|
||||||
use crate::core::render::texture::Texture;
|
use crate::core::render::resources::meshes::{ObjMesh, SquareMesh};
|
||||||
|
use crate::core::render::resources::texture::{
|
||||||
|
Texture, TextureLoadInfo, TextureLoader, TextureSourceKind,
|
||||||
|
};
|
||||||
use crate::core::scene::Scene;
|
use crate::core::scene::Scene;
|
||||||
use crate::game::assets::meshs::square::Square;
|
|
||||||
use crate::game::assets::pipelines::simple::{SimplePipeline, SimplePipelineRenderData};
|
use crate::game::assets::pipelines::simple::{SimplePipeline, SimplePipelineRenderData};
|
||||||
use egui_winit_vulkano::egui;
|
use egui_winit_vulkano::egui;
|
||||||
use glam::EulerRot;
|
use glam::EulerRot;
|
||||||
use glam::Quat;
|
use glam::Quat;
|
||||||
use glam::Vec3;
|
use glam::Vec3;
|
||||||
|
use vulkano::format::Format;
|
||||||
|
use vulkano::image::sampler::{Filter, SamplerAddressMode, SamplerCreateInfo};
|
||||||
use vulkano::{
|
use vulkano::{
|
||||||
command_buffer::{AutoCommandBufferBuilder, CommandBufferUsage, PrimaryCommandBufferAbstract},
|
command_buffer::{AutoCommandBufferBuilder, CommandBufferUsage, PrimaryCommandBufferAbstract},
|
||||||
sync::GpuFuture,
|
sync::GpuFuture,
|
||||||
|
@ -24,11 +27,13 @@ use vulkano::{
|
||||||
use winit::window::CursorGrabMode;
|
use winit::window::CursorGrabMode;
|
||||||
|
|
||||||
pub struct MainSceneState {
|
pub struct MainSceneState {
|
||||||
square: Square,
|
texture_loader: TextureLoader,
|
||||||
|
square: SquareMesh,
|
||||||
|
obj: ObjMesh,
|
||||||
simple_pipeline: SimplePipeline,
|
simple_pipeline: SimplePipeline,
|
||||||
instances: Vec<Transform>,
|
square_instances: Vec<Transform>,
|
||||||
|
obj_instances: Vec<Transform>,
|
||||||
camera: Camera3D,
|
camera: Camera3D,
|
||||||
texture: Texture,
|
|
||||||
speed: f32,
|
speed: f32,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -50,7 +55,41 @@ impl Scene for MainScene {
|
||||||
let swapchain_image_view =
|
let swapchain_image_view =
|
||||||
app_context.with_renderer(|renderer| renderer.swapchain_image_view().clone());
|
app_context.with_renderer(|renderer| renderer.swapchain_image_view().clone());
|
||||||
|
|
||||||
let square = Square::new(&app_context.memory_allocator)?;
|
let mut texture_loader = TextureLoader::new(app_context);
|
||||||
|
texture_loader.add_texture(
|
||||||
|
"wooden-crate".to_string(),
|
||||||
|
TextureLoadInfo {
|
||||||
|
source: TextureSourceKind::File("res/textures/wooden-crate.jpg".to_string()),
|
||||||
|
sampler_create_info: SamplerCreateInfo {
|
||||||
|
mag_filter: Filter::Linear,
|
||||||
|
min_filter: Filter::Linear,
|
||||||
|
address_mode: [SamplerAddressMode::Repeat; 3],
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
image_format: Format::R8G8B8A8_SRGB,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
texture_loader.add_texture(
|
||||||
|
"cube-diffuse".to_string(),
|
||||||
|
TextureLoadInfo {
|
||||||
|
source: TextureSourceKind::File("res/objects/cube-diffuse.jpg".to_string()),
|
||||||
|
sampler_create_info: SamplerCreateInfo {
|
||||||
|
mag_filter: Filter::Linear,
|
||||||
|
min_filter: Filter::Linear,
|
||||||
|
address_mode: [SamplerAddressMode::Repeat; 3],
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
image_format: Format::R8G8B8A8_SRGB,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
texture_loader.load_pending_textures()?;
|
||||||
|
|
||||||
|
let square = SquareMesh::new(&app_context.memory_allocator)?;
|
||||||
|
|
||||||
|
let obj = {
|
||||||
|
let obj = ObjMesh::new(&app_context.memory_allocator, "res/objects/cube.obj")?;
|
||||||
|
obj.into_iter().next().unwrap()
|
||||||
|
};
|
||||||
let simple_pipeline = SimplePipeline::new(
|
let simple_pipeline = SimplePipeline::new(
|
||||||
&app_context.device,
|
&app_context.device,
|
||||||
swapchain_image_view.format(),
|
swapchain_image_view.format(),
|
||||||
|
@ -61,7 +100,7 @@ impl Scene for MainScene {
|
||||||
let instance_size = 10.0;
|
let instance_size = 10.0;
|
||||||
let instance_spacing = 10.0;
|
let instance_spacing = 10.0;
|
||||||
let num_instances_per_row = (num_instances as f32 / instance_spacing).ceil() as u32;
|
let num_instances_per_row = (num_instances as f32 / instance_spacing).ceil() as u32;
|
||||||
let instances: Vec<Transform> = (0..num_instances)
|
let square_instances: Vec<Transform> = (0..num_instances)
|
||||||
.map(|i| {
|
.map(|i| {
|
||||||
Transform::new(
|
Transform::new(
|
||||||
Vec3::new(
|
Vec3::new(
|
||||||
|
@ -75,26 +114,26 @@ impl Scene for MainScene {
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
let texture = {
|
let obj_instances: Vec<Transform> = (0..num_instances)
|
||||||
let mut uploads = AutoCommandBufferBuilder::primary(
|
.map(|i| {
|
||||||
app_context.command_buffer_allocator.clone(),
|
Transform::new(
|
||||||
app_context.graphics_queue.queue_family_index(),
|
Vec3::new(
|
||||||
CommandBufferUsage::OneTimeSubmit,
|
(i % num_instances_per_row) as f32 * (instance_spacing + instance_size),
|
||||||
)?;
|
0.0,
|
||||||
|
(i / num_instances_per_row) as f32
|
||||||
let texture = Texture::from_file(
|
* (instance_spacing + instance_size)
|
||||||
&app_context.device,
|
* -1.0
|
||||||
&app_context.memory_allocator,
|
- instance_spacing * 2.0,
|
||||||
&mut uploads,
|
),
|
||||||
"res/textures/wooden-crate.jpg",
|
Quat::from_euler(EulerRot::XYZ, 0.0, rand::random_range(0.0..=360.0), 0.0),
|
||||||
)?;
|
Vec3::new(
|
||||||
|
instance_size * 0.5,
|
||||||
let _ = uploads
|
instance_size * 0.5,
|
||||||
.build()?
|
instance_size * 0.5,
|
||||||
.execute(app_context.graphics_queue.clone())?;
|
),
|
||||||
|
)
|
||||||
texture
|
})
|
||||||
};
|
.collect();
|
||||||
|
|
||||||
let camera = app_context.with_renderer(|renderer| {
|
let camera = app_context.with_renderer(|renderer| {
|
||||||
Camera3D::new(
|
Camera3D::new(
|
||||||
|
@ -107,11 +146,13 @@ impl Scene for MainScene {
|
||||||
|
|
||||||
self.state = Some(MainSceneState {
|
self.state = Some(MainSceneState {
|
||||||
square,
|
square,
|
||||||
|
obj,
|
||||||
simple_pipeline,
|
simple_pipeline,
|
||||||
instances,
|
square_instances,
|
||||||
|
obj_instances,
|
||||||
camera,
|
camera,
|
||||||
texture,
|
|
||||||
speed: 50.0,
|
speed: 50.0,
|
||||||
|
texture_loader,
|
||||||
});
|
});
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -132,7 +173,14 @@ impl Scene for MainScene {
|
||||||
});
|
});
|
||||||
|
|
||||||
let delta_time = app_context.get_delta_time();
|
let delta_time = app_context.get_delta_time();
|
||||||
for (i, instance) in state.instances.iter_mut().enumerate() {
|
for (i, instance) in state.square_instances.iter_mut().enumerate() {
|
||||||
|
let rotation_speed = (i % 10) as f32;
|
||||||
|
let rotation_delta = Quat::from_rotation_y(rotation_speed * delta_time);
|
||||||
|
|
||||||
|
instance.rotate(rotation_delta);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i, instance) in state.obj_instances.iter_mut().enumerate() {
|
||||||
let rotation_speed = (i % 10) as f32;
|
let rotation_speed = (i % 10) as f32;
|
||||||
let rotation_delta = Quat::from_rotation_y(rotation_speed * delta_time);
|
let rotation_delta = Quat::from_rotation_y(rotation_speed * delta_time);
|
||||||
|
|
||||||
|
@ -203,21 +251,40 @@ impl Scene for MainScene {
|
||||||
|
|
||||||
// Create camera uniform using the actual camera
|
// Create camera uniform using the actual camera
|
||||||
let camera_uniform = state.camera.create_buffer(&app_context.memory_allocator)?;
|
let camera_uniform = state.camera.create_buffer(&app_context.memory_allocator)?;
|
||||||
let transform_uniform =
|
let square_transform_uniform =
|
||||||
Transform::create_buffer(&app_context.memory_allocator, &state.instances)?;
|
Transform::create_buffer(&app_context.memory_allocator, &state.square_instances)?;
|
||||||
|
let obj_transform_uniform =
|
||||||
|
Transform::create_buffer(&app_context.memory_allocator, &state.obj_instances)?;
|
||||||
|
|
||||||
SimplePipeline::record_bind_commands(
|
SimplePipeline::record_bind_commands(
|
||||||
&mut builder,
|
&mut builder,
|
||||||
&app_context.descriptor_set_allocator,
|
&app_context.descriptor_set_allocator,
|
||||||
state.simple_pipeline.pipeline(),
|
state.simple_pipeline.pipeline(),
|
||||||
&state.square,
|
&state.square,
|
||||||
&transform_uniform,
|
&square_transform_uniform,
|
||||||
&SimplePipelineRenderData {
|
&SimplePipelineRenderData {
|
||||||
mvp_uniform: &camera_uniform,
|
mvp_uniform: &camera_uniform,
|
||||||
texture: &state.texture,
|
texture: &state.texture_loader.get_texture("wooden-crate").unwrap(),
|
||||||
},
|
},
|
||||||
)?;
|
)?;
|
||||||
SimplePipeline::record_draw_commands(&mut builder, &state.square, &transform_uniform)?;
|
SimplePipeline::record_draw_commands(
|
||||||
|
&mut builder,
|
||||||
|
&state.square,
|
||||||
|
&square_transform_uniform,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
SimplePipeline::record_bind_commands(
|
||||||
|
&mut builder,
|
||||||
|
&app_context.descriptor_set_allocator,
|
||||||
|
state.simple_pipeline.pipeline(),
|
||||||
|
&state.obj,
|
||||||
|
&obj_transform_uniform,
|
||||||
|
&SimplePipelineRenderData {
|
||||||
|
mvp_uniform: &camera_uniform,
|
||||||
|
texture: &state.texture_loader.get_texture("cube-diffuse").unwrap(),
|
||||||
|
},
|
||||||
|
)?;
|
||||||
|
SimplePipeline::record_draw_commands(&mut builder, &state.obj, &obj_transform_uniform)?;
|
||||||
|
|
||||||
RenderPassManager::end_rendering(&mut builder)?;
|
RenderPassManager::end_rendering(&mut builder)?;
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue