021: boxes

This commit is contained in:
zawz 2024-08-02 09:10:28 +02:00
parent 483be0c669
commit 40eeea224b
8 changed files with 663 additions and 80 deletions

View file

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

View file

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

View file

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

View file

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

View file

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