use std::collections::HashMap;
use std::sync::atomic::{AtomicU64, Ordering};
use bevy_ecs::prelude::*;
use wgpu::{Buffer, RenderPipeline, BindGroup, IndexFormat};
use crate::renderer::RenderDevice;
use crate::renderer::buffer::{Vertex, create_vertex_buffer, create_index_buffer, create_index_buffer_u32};
static NEXT_HANDLE_ID: AtomicU64 = AtomicU64::new(1);
fn next_id() -> u64 {
NEXT_HANDLE_ID.fetch_add(1, Ordering::Relaxed)
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Component)]
pub struct MeshHandle(pub u64);
impl MeshHandle {
pub fn index(&self) -> u64 { self.0 }
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Component)]
pub struct MaterialHandle(pub u64);
impl MaterialHandle {
pub fn index(&self) -> u64 { self.0 }
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct PipelineHandle(pub u64);
pub struct GpuMesh {
pub vertex_buffer: Buffer,
pub index_buffer: Buffer,
pub index_count: u32,
pub index_format: IndexFormat,
}
pub struct GpuMaterial {
pub pipeline_handle: PipelineHandle,
pub bind_group: BindGroup,
}
#[derive(Resource, Default)]
pub struct RenderAssets {
meshes: HashMap<MeshHandle, GpuMesh>,
materials: HashMap<MaterialHandle, GpuMaterial>,
pipelines: HashMap<PipelineHandle, RenderPipeline>,
}
impl RenderAssets {
pub fn upload_mesh<V: Vertex>(
&mut self,
device: &RenderDevice,
vertices: &[V],
indices: &[u16],
label: &str,
) -> MeshHandle {
let vertex_buffer = create_vertex_buffer(device, &format!("{} VB", label), vertices);
let index_buffer = create_index_buffer(device, &format!("{} IB", label), indices);
let handle = MeshHandle(next_id());
self.meshes.insert(handle, GpuMesh {
vertex_buffer,
index_buffer,
index_count: indices.len() as u32,
index_format: IndexFormat::Uint16,
});
handle
}
pub fn upload_mesh_u32<V: Vertex>(
&mut self,
device: &RenderDevice,
vertices: &[V],
indices: &[u32],
label: &str,
) -> MeshHandle {
let vertex_buffer = create_vertex_buffer(device, &format!("{} VB", label), vertices);
let index_buffer = create_index_buffer_u32(device, &format!("{} IB", label), indices);
let handle = MeshHandle(next_id());
self.meshes.insert(handle, GpuMesh {
vertex_buffer,
index_buffer,
index_count: indices.len() as u32,
index_format: IndexFormat::Uint32,
});
handle
}
pub fn register_pipeline(&mut self, pipeline: RenderPipeline) -> PipelineHandle {
let handle = PipelineHandle(next_id());
self.pipelines.insert(handle, pipeline);
handle
}
pub fn create_material_with_pipeline(
&mut self,
pipeline_handle: PipelineHandle,
bind_group: BindGroup,
) -> MaterialHandle {
let handle = MaterialHandle(next_id());
self.materials.insert(handle, GpuMaterial {
pipeline_handle,
bind_group,
});
handle
}
pub fn create_material(
&mut self,
pipeline: RenderPipeline,
bind_group: BindGroup,
) -> MaterialHandle {
let pipeline_handle = self.register_pipeline(pipeline);
self.create_material_with_pipeline(pipeline_handle, bind_group)
}
pub fn get_mesh(&self, handle: &MeshHandle) -> Option<&GpuMesh> {
self.meshes.get(handle)
}
pub fn get_material(&self, handle: &MaterialHandle) -> Option<&GpuMaterial> {
self.materials.get(handle)
}
pub fn get_pipeline(&self, handle: &PipelineHandle) -> Option<&RenderPipeline> {
self.pipelines.get(handle)
}
pub fn remove_mesh(&mut self, handle: &MeshHandle) -> bool {
self.meshes.remove(handle).is_some()
}
pub fn remove_material(&mut self, handle: &MaterialHandle) -> bool {
self.materials.remove(handle).is_some()
}
pub fn remove_pipeline(&mut self, handle: &PipelineHandle) -> bool {
self.pipelines.remove(handle).is_some()
}
pub fn mesh_count(&self) -> usize {
self.meshes.len()
}
pub fn material_count(&self) -> usize {
self.materials.len()
}
pub fn pipeline_count(&self) -> usize {
self.pipelines.len()
}
}