021: boxes
This commit is contained in:
parent
483be0c669
commit
40eeea224b
8 changed files with 663 additions and 80 deletions
|
|
@ -1,13 +1,12 @@
|
|||
#version 450
|
||||
|
||||
layout(location = 0) in vec4 position;
|
||||
layout(location = 1) in float size;
|
||||
layout(location = 2) in vec4 colour;
|
||||
layout(location = 0) in vec3 position;
|
||||
layout(location = 1) in vec3 position_offset;
|
||||
layout(location = 2) in vec3 colour;
|
||||
|
||||
layout(location = 0) out vec4 colourdata_for_the_fragmentshader;
|
||||
|
||||
void main() {
|
||||
gl_PointSize = size;
|
||||
gl_Position = position;
|
||||
colourdata_for_the_fragmentshader = colour;
|
||||
gl_Position = vec4(position + position_offset, 1.0);
|
||||
colourdata_for_the_fragmentshader = vec4(colour, 1.0);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
use ash::vk;
|
||||
|
||||
use crate::instance::buffer::BufferError;
|
||||
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
pub enum EngineError {
|
||||
#[error(transparent)]
|
||||
|
|
@ -13,5 +15,5 @@ pub enum EngineError {
|
|||
#[error(transparent)]
|
||||
RWHError(#[from] winit::raw_window_handle::HandleError),
|
||||
#[error(transparent)]
|
||||
AllocationError(#[from] gpu_allocator::AllocationError),
|
||||
BufferError(#[from] BufferError),
|
||||
}
|
||||
|
|
@ -6,8 +6,6 @@ use gpu_allocator::vulkan::Allocator as GpuAllocator;
|
|||
use gpu_allocator::vulkan::AllocatorCreateDesc;
|
||||
use gpu_allocator::MemoryLocation;
|
||||
|
||||
use super::EngineError;
|
||||
|
||||
pub struct BufferAllocator {
|
||||
pub allocator: GpuAllocator,
|
||||
}
|
||||
|
|
@ -15,6 +13,21 @@ pub struct BufferAllocator {
|
|||
pub struct Buffer {
|
||||
pub allocation: Option<GpuAllocation>,
|
||||
pub buffer: vk::Buffer,
|
||||
pub size: u64,
|
||||
pub flags: vk::BufferUsageFlags,
|
||||
pub location: MemoryLocation,
|
||||
}
|
||||
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
pub enum BufferError {
|
||||
#[error(transparent)]
|
||||
AllocationError(#[from] gpu_allocator::AllocationError),
|
||||
#[error("buffer memory is not visible to host")]
|
||||
NonVisibleMemory,
|
||||
#[error("data is larger than buffer")]
|
||||
BufferOverflow,
|
||||
#[error("buffer was unexpectedly unallocated")]
|
||||
UnexpectedUnallocatedBuffer,
|
||||
}
|
||||
|
||||
impl BufferAllocator {
|
||||
|
|
@ -22,7 +35,7 @@ impl BufferAllocator {
|
|||
ash_instance: &ash::Instance,
|
||||
physical_device: vk::PhysicalDevice,
|
||||
device: &ash::Device,
|
||||
) -> Result<Self, EngineError> {
|
||||
) -> Result<Self, BufferError> {
|
||||
let allocator = GpuAllocator::new(&AllocatorCreateDesc {
|
||||
instance: ash_instance.clone(),
|
||||
device: device.clone(),
|
||||
|
|
@ -40,7 +53,7 @@ impl BufferAllocator {
|
|||
size: u64,
|
||||
flags: vk::BufferUsageFlags,
|
||||
location: MemoryLocation,
|
||||
) -> Result<Buffer, EngineError> {
|
||||
) -> Result<Buffer, BufferError> {
|
||||
let vk_info = vk::BufferCreateInfo::default().size(size).usage(flags);
|
||||
|
||||
let buffer = unsafe { device.create_buffer(&vk_info, None) }.unwrap();
|
||||
|
|
@ -63,13 +76,24 @@ impl BufferAllocator {
|
|||
Ok(Buffer {
|
||||
allocation: Some(allocation),
|
||||
buffer,
|
||||
size,
|
||||
flags,
|
||||
location,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn free_buffer_allocation(&mut self, device: &ash::Device, buffer: &mut Buffer) {
|
||||
let allocation = buffer.allocation.take();
|
||||
self.allocator.free(allocation.unwrap()).unwrap();
|
||||
pub fn free_buffer_allocation(
|
||||
&mut self,
|
||||
device: &ash::Device,
|
||||
buffer: &mut Buffer,
|
||||
) -> Result<(), BufferError> {
|
||||
let allocation = buffer
|
||||
.allocation
|
||||
.take()
|
||||
.ok_or(BufferError::UnexpectedUnallocatedBuffer)?;
|
||||
self.allocator.free(allocation)?;
|
||||
unsafe { device.destroy_buffer(buffer.buffer, None) };
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -82,9 +106,54 @@ impl Buffer {
|
|||
}
|
||||
}
|
||||
|
||||
pub unsafe fn fill<T: Sized>(&mut self, data: &[T]) {
|
||||
let slice = self.mapped_slice_mut().unwrap();
|
||||
pub fn resize(
|
||||
&mut self,
|
||||
allocator: &mut BufferAllocator,
|
||||
device: &ash::Device,
|
||||
size: u64,
|
||||
) -> Result<(), BufferError> {
|
||||
allocator.free_buffer_allocation(device, self)?;
|
||||
let newbuffer = allocator.create_buffer(device, size, self.flags, self.location)?;
|
||||
*self = newbuffer;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Same as resize() but only if it's bigger
|
||||
pub fn grow(
|
||||
&mut self,
|
||||
allocator: &mut BufferAllocator,
|
||||
device: &ash::Device,
|
||||
size: u64,
|
||||
) -> Result<(), BufferError> {
|
||||
if size > self.size {
|
||||
self.resize(allocator, device, size)
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Try to grow the buffer if necessary, then fill
|
||||
pub fn grow_fill<T: Sized>(
|
||||
&mut self,
|
||||
allocator: &mut BufferAllocator,
|
||||
device: &ash::Device,
|
||||
data: &[T],
|
||||
) -> Result<(), BufferError> {
|
||||
let bytes_to_write = data.len() * std::mem::size_of::<T>();
|
||||
self.grow(allocator, device, bytes_to_write as u64)?;
|
||||
self.fill(data)
|
||||
}
|
||||
|
||||
pub fn fill<T: Sized>(&mut self, data: &[T]) -> Result<(), BufferError> {
|
||||
let bytes_to_write = data.len() * std::mem::size_of::<T>();
|
||||
if bytes_to_write as u64 > self.size {
|
||||
return Err(BufferError::BufferOverflow);
|
||||
}
|
||||
let slice = self
|
||||
.mapped_slice_mut()
|
||||
.ok_or(BufferError::NonVisibleMemory)?;
|
||||
let inner_buffer = slice.as_ptr() as *mut T;
|
||||
inner_buffer.copy_from_nonoverlapping(data.as_ptr(), data.len());
|
||||
unsafe { inner_buffer.copy_from_nonoverlapping(data.as_ptr(), data.len()) };
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,11 +1,10 @@
|
|||
use std::ffi::{c_char, CString};
|
||||
|
||||
use ash::vk;
|
||||
use buffer::{Buffer, BufferAllocator};
|
||||
use buffer::BufferAllocator;
|
||||
|
||||
pub mod buffer;
|
||||
pub mod debug;
|
||||
pub mod error;
|
||||
pub mod pipeline;
|
||||
pub mod pools;
|
||||
pub mod queue;
|
||||
|
|
@ -13,7 +12,13 @@ pub mod surface;
|
|||
pub mod swapchain;
|
||||
pub mod window;
|
||||
|
||||
pub use error::EngineError;
|
||||
use crate::{
|
||||
model::{
|
||||
cube::{self, Cube},
|
||||
Model,
|
||||
},
|
||||
EngineError,
|
||||
};
|
||||
|
||||
pub use debug::DebugInstance;
|
||||
pub use pipeline::Pipeline;
|
||||
|
|
@ -46,7 +51,7 @@ pub struct EngineInstance {
|
|||
pub pools: Pools,
|
||||
pub commandbuffers: Vec<vk::CommandBuffer>,
|
||||
pub allocator: std::mem::ManuallyDrop<BufferAllocator>,
|
||||
pub buffers: Vec<Buffer>,
|
||||
pub models: Vec<cube::Cube>,
|
||||
pub framecount: FrameCounter,
|
||||
}
|
||||
|
||||
|
|
@ -118,70 +123,40 @@ impl EngineInstance {
|
|||
let renderpass = Self::init_renderpass(&device, surface_format.format)?;
|
||||
swapchain.create_framebuffers(&device, renderpass)?;
|
||||
|
||||
let pbuflen1: u32 = 16;
|
||||
let pbuflen2: u32 = 20;
|
||||
let nvertex: u32 = 6;
|
||||
let ninstance: u32 = 1;
|
||||
|
||||
log::debug!("Create allocator");
|
||||
let mut allocator = BufferAllocator::init(&ash_instance, physical_device, &device)?;
|
||||
let mut buffer1 = allocator.create_buffer(
|
||||
&device,
|
||||
pbuflen1 as u64 * nvertex as u64,
|
||||
vk::BufferUsageFlags::VERTEX_BUFFER,
|
||||
gpu_allocator::MemoryLocation::CpuToGpu,
|
||||
)?;
|
||||
unsafe {
|
||||
buffer1.fill(&[
|
||||
0.5f32, 0.0f32, 0.0f32, 1.0f32, 0.0f32, 0.2f32, 0.0f32, 1.0f32, -0.5f32, 0.0f32,
|
||||
0.0f32, 1.0f32, -0.9f32, -0.9f32, 0.0f32, 1.0f32, 0.3f32, -0.8f32, 0.0f32, 1.0f32,
|
||||
0.0f32, -0.6f32, 0.0f32, 1.0f32,
|
||||
])
|
||||
};
|
||||
let mut buffer2 = allocator.create_buffer(
|
||||
&device,
|
||||
pbuflen2 as u64 * nvertex as u64,
|
||||
vk::BufferUsageFlags::VERTEX_BUFFER,
|
||||
gpu_allocator::MemoryLocation::CpuToGpu,
|
||||
)?;
|
||||
unsafe {
|
||||
buffer2.fill(&[
|
||||
1.0f32, 0.0f32, 1.0f32, 0.0f32, 1.0f32, 1.0f32, 0.0f32, 1.0f32, 0.0f32, 1.0f32,
|
||||
1.0f32, 0.0f32, 1.0f32, 0.0f32, 1.0f32, 1.0f32, 0.8f32, 0.7f32, 0.0f32, 1.0f32,
|
||||
1.0f32, 1.0f32, 0.0f32, 0.0f32, 1.0f32, 1.0f32, 0.0f32, 0.0f32, 1.0f32, 1.0f32,
|
||||
])
|
||||
};
|
||||
let mut allocator: BufferAllocator =
|
||||
BufferAllocator::init(&ash_instance, physical_device, &device)?;
|
||||
|
||||
let vertex_attrib_descs = [
|
||||
vk::VertexInputAttributeDescription {
|
||||
binding: 0,
|
||||
location: 0,
|
||||
offset: 0,
|
||||
format: vk::Format::R32G32B32A32_SFLOAT,
|
||||
format: vk::Format::R32G32B32_SFLOAT,
|
||||
},
|
||||
vk::VertexInputAttributeDescription {
|
||||
binding: 1,
|
||||
location: 1,
|
||||
offset: 0,
|
||||
format: vk::Format::R32_SFLOAT,
|
||||
format: vk::Format::R32G32B32_SFLOAT,
|
||||
},
|
||||
vk::VertexInputAttributeDescription {
|
||||
binding: 1,
|
||||
location: 2,
|
||||
offset: 4,
|
||||
format: vk::Format::R32G32B32A32_SFLOAT,
|
||||
offset: 12,
|
||||
format: vk::Format::R32G32B32_SFLOAT,
|
||||
},
|
||||
];
|
||||
let vertex_binding_descs = [
|
||||
vk::VertexInputBindingDescription {
|
||||
binding: 0,
|
||||
stride: pbuflen1,
|
||||
stride: 12,
|
||||
input_rate: vk::VertexInputRate::VERTEX,
|
||||
},
|
||||
vk::VertexInputBindingDescription {
|
||||
binding: 1,
|
||||
stride: pbuflen2,
|
||||
input_rate: vk::VertexInputRate::VERTEX,
|
||||
stride: 24,
|
||||
input_rate: vk::VertexInputRate::INSTANCE,
|
||||
},
|
||||
];
|
||||
|
||||
|
|
@ -201,6 +176,23 @@ impl EngineInstance {
|
|||
|
||||
log::debug!("Create command buffers");
|
||||
let commandbuffers = pools.create_commandbuffers(&device, swapchain.framebuffers.len())?;
|
||||
|
||||
let mut cube = cube::Cube::cube();
|
||||
cube.insert_visibly(cube::InstanceData {
|
||||
position: [0.0, -0.25, 0.0],
|
||||
colour: [1.0, 0.0, 0.0],
|
||||
});
|
||||
cube.insert_visibly(cube::InstanceData {
|
||||
position: [0.0, 0.0, 0.0],
|
||||
colour: [0.6, 0.5, 0.0],
|
||||
});
|
||||
cube.insert_visibly(cube::InstanceData {
|
||||
position: [0.0, 0.25, 0.0],
|
||||
colour: [0.0, 0.5, 0.0],
|
||||
});
|
||||
cube.update_vertexbuffer(&mut allocator, &device)?;
|
||||
cube.update_instancebuffer(&mut allocator, &device)?;
|
||||
let models = vec![cube];
|
||||
for (i, &commandbuffer) in commandbuffers.iter().enumerate() {
|
||||
Self::fill_commandbuffer(
|
||||
&device,
|
||||
|
|
@ -209,10 +201,7 @@ impl EngineInstance {
|
|||
&swapchain,
|
||||
i,
|
||||
&pipeline,
|
||||
buffer1.buffer,
|
||||
buffer2.buffer,
|
||||
nvertex,
|
||||
ninstance,
|
||||
&models,
|
||||
)?;
|
||||
}
|
||||
|
||||
|
|
@ -234,7 +223,7 @@ impl EngineInstance {
|
|||
pools,
|
||||
commandbuffers,
|
||||
allocator: std::mem::ManuallyDrop::new(allocator),
|
||||
buffers: vec![buffer1, buffer2],
|
||||
models,
|
||||
framecount: FrameCounter::new(),
|
||||
})
|
||||
}
|
||||
|
|
@ -247,8 +236,9 @@ impl EngineInstance {
|
|||
self.pools.cleanup(&self.device);
|
||||
self.pipeline.cleanup(&self.device);
|
||||
|
||||
for buffer in &mut self.buffers {
|
||||
self.allocator.free_buffer_allocation(&self.device, buffer);
|
||||
for m in &mut self.models {
|
||||
m.cleanup_buffers(&mut self.allocator, &self.device)
|
||||
.unwrap();
|
||||
}
|
||||
std::mem::ManuallyDrop::drop(&mut self.allocator);
|
||||
|
||||
|
|
@ -423,24 +413,19 @@ impl EngineInstance {
|
|||
Ok(renderpass)
|
||||
}
|
||||
|
||||
fn fill_commandbuffer(
|
||||
fn fill_commandbuffer<V, T>(
|
||||
device: &ash::Device,
|
||||
commandbuffer: vk::CommandBuffer,
|
||||
renderpass: vk::RenderPass,
|
||||
swapchain: &Swapchain,
|
||||
framebuffer_index: usize,
|
||||
pipeline: &Pipeline,
|
||||
// buffers: &[vk::Buffer],
|
||||
buffer1: vk::Buffer,
|
||||
buffer2: vk::Buffer,
|
||||
vertex_count: u32,
|
||||
instance_count: u32,
|
||||
models: &[Model<V, T>],
|
||||
) -> Result<(), vk::Result> {
|
||||
let commandbuffer_begininfo = vk::CommandBufferBeginInfo::default();
|
||||
unsafe {
|
||||
device.begin_command_buffer(commandbuffer, &commandbuffer_begininfo)?;
|
||||
}
|
||||
|
||||
let clearvalues = [vk::ClearValue {
|
||||
color: vk::ClearColorValue {
|
||||
float32: [0.0, 0.0, 0.08, 1.0],
|
||||
|
|
@ -466,9 +451,9 @@ impl EngineInstance {
|
|||
vk::PipelineBindPoint::GRAPHICS,
|
||||
pipeline.pipeline,
|
||||
);
|
||||
device.cmd_bind_vertex_buffers(commandbuffer, 0, &[buffer1], &[0]);
|
||||
device.cmd_bind_vertex_buffers(commandbuffer, 1, &[buffer2], &[0]);
|
||||
device.cmd_draw(commandbuffer, vertex_count, instance_count, 0, 0);
|
||||
for m in models {
|
||||
m.draw(device, commandbuffer);
|
||||
}
|
||||
device.cmd_end_render_pass(commandbuffer);
|
||||
device.end_command_buffer(commandbuffer)?;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,14 +1,16 @@
|
|||
pub mod error;
|
||||
pub mod frame_counter;
|
||||
pub mod instance;
|
||||
pub mod model;
|
||||
pub mod render;
|
||||
|
||||
pub mod frame_counter;
|
||||
|
||||
pub use error::EngineError;
|
||||
pub use instance::EngineInstance;
|
||||
use instance::{window::Resolution, Window};
|
||||
|
||||
use ash::vk;
|
||||
|
||||
pub const WINDOW_WIDTH: u32 = 800;
|
||||
pub const WINDOW_WIDTH: u32 = 600;
|
||||
pub const WINDOW_HEIGHT: u32 = 600;
|
||||
|
||||
pub const DEFAULT_RES: Resolution = Resolution {
|
||||
|
|
|
|||
39
src/model/cube.rs
Normal file
39
src/model/cube.rs
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
use super::Model;
|
||||
|
||||
#[repr(C)]
|
||||
pub struct InstanceData {
|
||||
pub position: [f32; 3],
|
||||
pub colour: [f32; 3],
|
||||
}
|
||||
|
||||
pub type Cube = Model<[f32; 3], InstanceData>;
|
||||
|
||||
impl Cube {
|
||||
pub fn cube() -> Self {
|
||||
let lbf = [-0.1, 0.1, 0.0]; //lbf: left-bottom-front
|
||||
let lbb = [-0.1, 0.1, 0.1];
|
||||
let ltf = [-0.1, -0.1, 0.0];
|
||||
let ltb = [-0.1, -0.1, 0.1];
|
||||
let rbf = [0.1, 0.1, 0.0];
|
||||
let rbb = [0.1, 0.1, 0.1];
|
||||
let rtf = [0.1, -0.1, 0.0];
|
||||
let rtb = [0.1, -0.1, 0.1];
|
||||
Model {
|
||||
vertexdata: vec![
|
||||
lbf, lbb, rbb, lbf, rbb, rbf, //bottom
|
||||
ltf, rtb, ltb, ltf, rtf, rtb, //top
|
||||
lbf, rtf, ltf, lbf, rbf, rtf, //front
|
||||
lbb, ltb, rtb, lbb, rtb, rbb, //back
|
||||
lbf, ltf, lbb, lbb, ltf, ltb, //left
|
||||
rbf, rbb, rtf, rbb, rtb, rtf, //right
|
||||
],
|
||||
handle_to_index: std::collections::HashMap::new(),
|
||||
handles: Vec::new(),
|
||||
instances: Vec::new(),
|
||||
first_invisible: 0,
|
||||
next_handle: 0,
|
||||
vertexbuffer: None,
|
||||
instancebuffer: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
232
src/model/mod.rs
Normal file
232
src/model/mod.rs
Normal file
|
|
@ -0,0 +1,232 @@
|
|||
use ash::vk;
|
||||
|
||||
pub mod cube;
|
||||
|
||||
use crate::{
|
||||
instance::buffer::{Buffer, BufferAllocator, BufferError},
|
||||
EngineError,
|
||||
};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct InvalidHandle;
|
||||
impl std::fmt::Display for InvalidHandle {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
write!(f, "invalid handle")
|
||||
}
|
||||
}
|
||||
impl std::error::Error for InvalidHandle {
|
||||
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Model<V, I> {
|
||||
vertexdata: Vec<V>,
|
||||
handle_to_index: std::collections::HashMap<usize, usize>,
|
||||
handles: Vec<usize>,
|
||||
instances: Vec<I>,
|
||||
first_invisible: usize,
|
||||
next_handle: usize,
|
||||
vertexbuffer: Option<Buffer>,
|
||||
instancebuffer: Option<Buffer>,
|
||||
}
|
||||
|
||||
impl<V, I> Model<V, I> {
|
||||
pub fn get(&self, handle: usize) -> Option<&I> {
|
||||
if let Some(&index) = self.handle_to_index.get(&handle) {
|
||||
self.instances.get(index)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
pub fn get_mut(&mut self, handle: usize) -> Option<&mut I> {
|
||||
if let Some(&index) = self.handle_to_index.get(&handle) {
|
||||
self.instances.get_mut(index)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn swap_by_handle(&mut self, handle1: usize, handle2: usize) -> Result<(), InvalidHandle> {
|
||||
if handle1 == handle2 {
|
||||
return Ok(());
|
||||
}
|
||||
if let (Some(&index1), Some(&index2)) = (
|
||||
self.handle_to_index.get(&handle1),
|
||||
self.handle_to_index.get(&handle2),
|
||||
) {
|
||||
self.handles.swap(index1, index2);
|
||||
self.instances.swap(index1, index2);
|
||||
self.handle_to_index.insert(index1, handle2);
|
||||
self.handle_to_index.insert(index2, handle1);
|
||||
Ok(())
|
||||
} else {
|
||||
Err(InvalidHandle)
|
||||
}
|
||||
}
|
||||
fn swap_by_index(&mut self, index1: usize, index2: usize) {
|
||||
if index1 == index2 {
|
||||
return;
|
||||
}
|
||||
let handle1 = self.handles[index1];
|
||||
let handle2 = self.handles[index2];
|
||||
self.handles.swap(index1, index2);
|
||||
self.instances.swap(index1, index2);
|
||||
self.handle_to_index.insert(index1, handle2);
|
||||
self.handle_to_index.insert(index2, handle1);
|
||||
}
|
||||
|
||||
pub fn is_visible(&self, handle: usize) -> Result<bool, InvalidHandle> {
|
||||
if let Some(index) = self.handle_to_index.get(&handle) {
|
||||
Ok(index < &self.first_invisible)
|
||||
} else {
|
||||
Err(InvalidHandle)
|
||||
}
|
||||
}
|
||||
pub fn make_visible(&mut self, handle: usize) -> Result<(), InvalidHandle> {
|
||||
//if already visible: do nothing
|
||||
if let Some(&index) = self.handle_to_index.get(&handle) {
|
||||
if index < self.first_invisible {
|
||||
return Ok(());
|
||||
}
|
||||
//else: move to position first_invisible and increase value of first_invisible
|
||||
self.swap_by_index(index, self.first_invisible);
|
||||
self.first_invisible += 1;
|
||||
Ok(())
|
||||
} else {
|
||||
Err(InvalidHandle)
|
||||
}
|
||||
}
|
||||
pub fn make_invisible(&mut self, handle: usize) -> Result<(), InvalidHandle> {
|
||||
//if already invisible: do nothing
|
||||
if let Some(&index) = self.handle_to_index.get(&handle) {
|
||||
if index >= self.first_invisible {
|
||||
return Ok(());
|
||||
}
|
||||
//else: move to position before first_invisible and decrease value of first_invisible
|
||||
self.swap_by_index(index, self.first_invisible - 1);
|
||||
self.first_invisible -= 1;
|
||||
Ok(())
|
||||
} else {
|
||||
Err(InvalidHandle)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn insert(&mut self, element: I) -> usize {
|
||||
let handle = self.next_handle;
|
||||
self.next_handle += 1;
|
||||
let index = self.instances.len();
|
||||
self.instances.push(element);
|
||||
self.handles.push(handle);
|
||||
self.handle_to_index.insert(handle, index);
|
||||
handle
|
||||
}
|
||||
pub fn insert_visibly(&mut self, element: I) -> usize {
|
||||
let new_handle = self.insert(element);
|
||||
self.make_visible(new_handle).ok(); //can't go wrong, see previous line
|
||||
new_handle
|
||||
}
|
||||
pub fn remove(&mut self, handle: usize) -> Result<I, InvalidHandle> {
|
||||
if let Some(&index) = self.handle_to_index.get(&handle) {
|
||||
if index < self.first_invisible {
|
||||
self.swap_by_index(index, self.first_invisible - 1);
|
||||
self.first_invisible -= 1;
|
||||
}
|
||||
self.swap_by_index(self.first_invisible, self.instances.len() - 1);
|
||||
self.handles.pop();
|
||||
self.handle_to_index.remove(&handle);
|
||||
//must be Some(), otherwise we couldn't have found an index
|
||||
Ok(self.instances.pop().unwrap())
|
||||
} else {
|
||||
Err(InvalidHandle)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn update_vertexbuffer(
|
||||
&mut self,
|
||||
allocator: &mut BufferAllocator,
|
||||
device: &ash::Device,
|
||||
) -> Result<(), BufferError> {
|
||||
if let Some(buffer) = &mut self.vertexbuffer {
|
||||
buffer.grow_fill(allocator, device, &self.vertexdata)?;
|
||||
Ok(())
|
||||
} else {
|
||||
let bytes = (self.vertexdata.len() * std::mem::size_of::<V>()) as u64;
|
||||
let mut buffer = allocator.create_buffer(
|
||||
device,
|
||||
bytes,
|
||||
vk::BufferUsageFlags::VERTEX_BUFFER,
|
||||
gpu_allocator::MemoryLocation::CpuToGpu,
|
||||
)?;
|
||||
buffer.grow_fill(allocator, device, &self.vertexdata)?;
|
||||
self.vertexbuffer = Some(buffer);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn update_instancebuffer(
|
||||
&mut self,
|
||||
allocator: &mut BufferAllocator,
|
||||
device: &ash::Device,
|
||||
) -> Result<(), EngineError> {
|
||||
if let Some(buffer) = &mut self.instancebuffer {
|
||||
buffer.grow_fill(allocator, device, &self.instances[0..self.first_invisible])?;
|
||||
Ok(())
|
||||
} else {
|
||||
let bytes = (self.first_invisible * std::mem::size_of::<I>()) as u64;
|
||||
let mut buffer = allocator.create_buffer(
|
||||
device,
|
||||
bytes,
|
||||
vk::BufferUsageFlags::VERTEX_BUFFER,
|
||||
gpu_allocator::MemoryLocation::CpuToGpu,
|
||||
)?;
|
||||
buffer.grow_fill(allocator, device, &self.instances[0..self.first_invisible])?;
|
||||
self.instancebuffer = Some(buffer);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn draw(&self, logical_device: &ash::Device, commandbuffer: vk::CommandBuffer) {
|
||||
if let Some(vertexbuffer) = &self.vertexbuffer {
|
||||
if let Some(instancebuffer) = &self.instancebuffer {
|
||||
if self.first_invisible > 0 {
|
||||
unsafe {
|
||||
logical_device.cmd_bind_vertex_buffers(
|
||||
commandbuffer,
|
||||
0,
|
||||
&[vertexbuffer.buffer],
|
||||
&[0],
|
||||
);
|
||||
logical_device.cmd_bind_vertex_buffers(
|
||||
commandbuffer,
|
||||
1,
|
||||
&[instancebuffer.buffer],
|
||||
&[0],
|
||||
);
|
||||
logical_device.cmd_draw(
|
||||
commandbuffer,
|
||||
self.vertexdata.len() as u32,
|
||||
self.first_invisible as u32,
|
||||
0,
|
||||
0,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn cleanup_buffers(
|
||||
&mut self,
|
||||
allocator: &mut BufferAllocator,
|
||||
device: &ash::Device,
|
||||
) -> Result<(), BufferError> {
|
||||
if let Some(b) = &mut self.vertexbuffer {
|
||||
allocator.free_buffer_allocation(device, b)?;
|
||||
}
|
||||
if let Some(b) = &mut self.instancebuffer {
|
||||
allocator.free_buffer_allocation(device, b)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
255
src/model/model.rs
Normal file
255
src/model/model.rs
Normal file
|
|
@ -0,0 +1,255 @@
|
|||
use ash::vk;
|
||||
|
||||
use crate::{
|
||||
instance::buffer::{Buffer, BufferAllocator, BufferError},
|
||||
EngineError,
|
||||
};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct InvalidHandle;
|
||||
impl std::fmt::Display for InvalidHandle {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
write!(f, "invalid handle")
|
||||
}
|
||||
}
|
||||
impl std::error::Error for InvalidHandle {
|
||||
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Model<V, I> {
|
||||
vertexdata: Vec<V>,
|
||||
handle_to_index: std::collections::HashMap<usize, usize>,
|
||||
handles: Vec<usize>,
|
||||
instances: Vec<I>,
|
||||
first_invisible: usize,
|
||||
next_handle: usize,
|
||||
vertexbuffer: Option<Buffer>,
|
||||
instancebuffer: Option<Buffer>,
|
||||
}
|
||||
|
||||
impl<V, I> Model<V, I> {
|
||||
pub fn get(&self, handle: usize) -> Option<&I> {
|
||||
if let Some(&index) = self.handle_to_index.get(&handle) {
|
||||
self.instances.get(index)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
pub fn get_mut(&mut self, handle: usize) -> Option<&mut I> {
|
||||
if let Some(&index) = self.handle_to_index.get(&handle) {
|
||||
self.instances.get_mut(index)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn swap_by_handle(&mut self, handle1: usize, handle2: usize) -> Result<(), InvalidHandle> {
|
||||
if handle1 == handle2 {
|
||||
return Ok(());
|
||||
}
|
||||
if let (Some(&index1), Some(&index2)) = (
|
||||
self.handle_to_index.get(&handle1),
|
||||
self.handle_to_index.get(&handle2),
|
||||
) {
|
||||
self.handles.swap(index1, index2);
|
||||
self.instances.swap(index1, index2);
|
||||
self.handle_to_index.insert(index1, handle2);
|
||||
self.handle_to_index.insert(index2, handle1);
|
||||
Ok(())
|
||||
} else {
|
||||
Err(InvalidHandle)
|
||||
}
|
||||
}
|
||||
fn swap_by_index(&mut self, index1: usize, index2: usize) {
|
||||
if index1 == index2 {
|
||||
return;
|
||||
}
|
||||
let handle1 = self.handles[index1];
|
||||
let handle2 = self.handles[index2];
|
||||
self.handles.swap(index1, index2);
|
||||
self.instances.swap(index1, index2);
|
||||
self.handle_to_index.insert(index1, handle2);
|
||||
self.handle_to_index.insert(index2, handle1);
|
||||
}
|
||||
|
||||
pub fn is_visible(&self, handle: usize) -> Result<bool, InvalidHandle> {
|
||||
if let Some(index) = self.handle_to_index.get(&handle) {
|
||||
Ok(index < &self.first_invisible)
|
||||
} else {
|
||||
Err(InvalidHandle)
|
||||
}
|
||||
}
|
||||
pub fn make_visible(&mut self, handle: usize) -> Result<(), InvalidHandle> {
|
||||
//if already visible: do nothing
|
||||
if let Some(&index) = self.handle_to_index.get(&handle) {
|
||||
if index < self.first_invisible {
|
||||
return Ok(());
|
||||
}
|
||||
//else: move to position first_invisible and increase value of first_invisible
|
||||
self.swap_by_index(index, self.first_invisible);
|
||||
self.first_invisible += 1;
|
||||
Ok(())
|
||||
} else {
|
||||
Err(InvalidHandle)
|
||||
}
|
||||
}
|
||||
pub fn make_invisible(&mut self, handle: usize) -> Result<(), InvalidHandle> {
|
||||
//if already invisible: do nothing
|
||||
if let Some(&index) = self.handle_to_index.get(&handle) {
|
||||
if index >= self.first_invisible {
|
||||
return Ok(());
|
||||
}
|
||||
//else: move to position before first_invisible and decrease value of first_invisible
|
||||
self.swap_by_index(index, self.first_invisible - 1);
|
||||
self.first_invisible -= 1;
|
||||
Ok(())
|
||||
} else {
|
||||
Err(InvalidHandle)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn insert(&mut self, element: I) -> usize {
|
||||
let handle = self.next_handle;
|
||||
self.next_handle += 1;
|
||||
let index = self.instances.len();
|
||||
self.instances.push(element);
|
||||
self.handles.push(handle);
|
||||
self.handle_to_index.insert(handle, index);
|
||||
handle
|
||||
}
|
||||
pub fn insert_visibly(&mut self, element: I) -> usize {
|
||||
let new_handle = self.insert(element);
|
||||
self.make_visible(new_handle).ok(); //can't go wrong, see previous line
|
||||
new_handle
|
||||
}
|
||||
pub fn remove(&mut self, handle: usize) -> Result<I, InvalidHandle> {
|
||||
if let Some(&index) = self.handle_to_index.get(&handle) {
|
||||
if index < self.first_invisible {
|
||||
self.swap_by_index(index, self.first_invisible - 1);
|
||||
self.first_invisible -= 1;
|
||||
}
|
||||
self.swap_by_index(self.first_invisible, self.instances.len() - 1);
|
||||
self.handles.pop();
|
||||
self.handle_to_index.remove(&handle);
|
||||
//must be Some(), otherwise we couldn't have found an index
|
||||
Ok(self.instances.pop().unwrap())
|
||||
} else {
|
||||
Err(InvalidHandle)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn update_vertexbuffer(
|
||||
&mut self,
|
||||
allocator: &mut BufferAllocator,
|
||||
device: &ash::Device,
|
||||
) -> Result<(), BufferError> {
|
||||
if let Some(buffer) = &mut self.vertexbuffer {
|
||||
buffer.grow_fill(allocator, device, &self.vertexdata)?;
|
||||
Ok(())
|
||||
} else {
|
||||
let bytes = (self.vertexdata.len() * std::mem::size_of::<V>()) as u64;
|
||||
let mut buffer = allocator.create_buffer(
|
||||
device,
|
||||
bytes,
|
||||
vk::BufferUsageFlags::VERTEX_BUFFER,
|
||||
gpu_allocator::MemoryLocation::CpuToGpu,
|
||||
)?;
|
||||
buffer.grow_fill(allocator, device, &self.vertexdata)?;
|
||||
self.vertexbuffer = Some(buffer);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn update_instancebuffer(
|
||||
&mut self,
|
||||
allocator: &mut BufferAllocator,
|
||||
device: &ash::Device,
|
||||
) -> Result<(), EngineError> {
|
||||
if let Some(buffer) = &mut self.instancebuffer {
|
||||
buffer.grow_fill(allocator, device, &self.instances[0..self.first_invisible])?;
|
||||
Ok(())
|
||||
} else {
|
||||
let bytes = (self.first_invisible * std::mem::size_of::<I>()) as u64;
|
||||
let mut buffer = allocator.create_buffer(
|
||||
device,
|
||||
bytes,
|
||||
vk::BufferUsageFlags::VERTEX_BUFFER,
|
||||
gpu_allocator::MemoryLocation::CpuToGpu,
|
||||
)?;
|
||||
buffer.grow_fill(allocator, device, &self.instances[0..self.first_invisible])?;
|
||||
self.instancebuffer = Some(buffer);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn draw(&self, logical_device: &ash::Device, commandbuffer: vk::CommandBuffer) {
|
||||
if let Some(vertexbuffer) = &self.vertexbuffer {
|
||||
if let Some(instancebuffer) = &self.instancebuffer {
|
||||
if self.first_invisible > 0 {
|
||||
unsafe {
|
||||
logical_device.cmd_bind_vertex_buffers(
|
||||
commandbuffer,
|
||||
0,
|
||||
&[vertexbuffer.buffer],
|
||||
&[0],
|
||||
);
|
||||
logical_device.cmd_bind_vertex_buffers(
|
||||
commandbuffer,
|
||||
1,
|
||||
&[instancebuffer.buffer],
|
||||
&[0],
|
||||
);
|
||||
logical_device.cmd_draw(
|
||||
commandbuffer,
|
||||
self.vertexdata.len() as u32,
|
||||
self.first_invisible as u32,
|
||||
0,
|
||||
0,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn cleanup_buffers(&mut self, allocator: &mut BufferAllocator, device: &ash::Device) {
|
||||
if let Some(b) = &mut self.vertexbuffer {
|
||||
allocator.free_buffer_allocation(device, b);
|
||||
}
|
||||
if let Some(b) = &mut self.instancebuffer {
|
||||
allocator.free_buffer_allocation(device, b);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Model<[f32; 3], [f32; 6]> {
|
||||
pub fn cube() -> Model<[f32; 3], [f32; 6]> {
|
||||
let lbf = [-0.1, 0.1, 0.0]; //lbf: left-bottom-front
|
||||
let lbb = [-0.1, 0.1, 0.1];
|
||||
let ltf = [-0.1, -0.1, 0.0];
|
||||
let ltb = [-0.1, -0.1, 0.1];
|
||||
let rbf = [0.1, 0.1, 0.0];
|
||||
let rbb = [0.1, 0.1, 0.1];
|
||||
let rtf = [0.1, -0.1, 0.0];
|
||||
let rtb = [0.1, -0.1, 0.1];
|
||||
Model {
|
||||
vertexdata: vec![
|
||||
lbf, lbb, rbb, lbf, rbb, rbf, //bottom
|
||||
ltf, rtb, ltb, ltf, rtf, rtb, //top
|
||||
lbf, rtf, ltf, lbf, rbf, rtf, //front
|
||||
lbb, ltb, rtb, lbb, rtb, rbb, //back
|
||||
lbf, ltf, lbb, lbb, ltf, ltb, //left
|
||||
rbf, rbb, rtf, rbb, rtb, rtf, //right
|
||||
],
|
||||
handle_to_index: std::collections::HashMap::new(),
|
||||
handles: Vec::new(),
|
||||
instances: Vec::new(),
|
||||
first_invisible: 0,
|
||||
next_handle: 0,
|
||||
vertexbuffer: None,
|
||||
instancebuffer: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue