fix mesh allocation bug and public mesh api improvements (#768)
This commit is contained in:
parent
a04e67d9dd
commit
44b3e24e32
@ -20,7 +20,7 @@ use gltf::{
|
|||||||
Primitive,
|
Primitive,
|
||||||
};
|
};
|
||||||
use image::{GenericImageView, ImageFormat};
|
use image::{GenericImageView, ImageFormat};
|
||||||
use std::{borrow::Cow, path::Path};
|
use std::path::Path;
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
/// An error that occurs when loading a GLTF file
|
/// An error that occurs when loading a GLTF file
|
||||||
@ -90,28 +90,25 @@ async fn load_gltf<'a, 'b>(
|
|||||||
.read_positions()
|
.read_positions()
|
||||||
.map(|v| VertexAttributeValues::Float3(v.collect()))
|
.map(|v| VertexAttributeValues::Float3(v.collect()))
|
||||||
{
|
{
|
||||||
mesh.attributes
|
mesh.set_attribute(Mesh::ATTRIBUTE_POSITION, vertex_attribute);
|
||||||
.insert(Cow::Borrowed(Mesh::ATTRIBUTE_POSITION), vertex_attribute);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(vertex_attribute) = reader
|
if let Some(vertex_attribute) = reader
|
||||||
.read_normals()
|
.read_normals()
|
||||||
.map(|v| VertexAttributeValues::Float3(v.collect()))
|
.map(|v| VertexAttributeValues::Float3(v.collect()))
|
||||||
{
|
{
|
||||||
mesh.attributes
|
mesh.set_attribute(Mesh::ATTRIBUTE_NORMAL, vertex_attribute);
|
||||||
.insert(Cow::Borrowed(Mesh::ATTRIBUTE_NORMAL), vertex_attribute);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(vertex_attribute) = reader
|
if let Some(vertex_attribute) = reader
|
||||||
.read_tex_coords(0)
|
.read_tex_coords(0)
|
||||||
.map(|v| VertexAttributeValues::Float2(v.into_f32().collect()))
|
.map(|v| VertexAttributeValues::Float2(v.into_f32().collect()))
|
||||||
{
|
{
|
||||||
mesh.attributes
|
mesh.set_attribute(Mesh::ATTRIBUTE_UV_0, vertex_attribute);
|
||||||
.insert(Cow::Borrowed(Mesh::ATTRIBUTE_UV_0), vertex_attribute);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(indices) = reader.read_indices() {
|
if let Some(indices) = reader.read_indices() {
|
||||||
mesh.indices = Some(Indices::U32(indices.into_u32().collect()));
|
mesh.set_indices(Some(Indices::U32(indices.into_u32().collect())));
|
||||||
};
|
};
|
||||||
|
|
||||||
load_context.set_labeled_asset(&primitive_label, LoadedAsset::new(mesh));
|
load_context.set_labeled_asset(&primitive_label, LoadedAsset::new(mesh));
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
pipeline::{PrimitiveTopology, RenderPipelines, VertexFormat},
|
pipeline::{IndexFormat, PrimitiveTopology, RenderPipelines, VertexFormat},
|
||||||
renderer::{BufferInfo, BufferUsage, RenderResourceContext, RenderResourceId},
|
renderer::{BufferInfo, BufferUsage, RenderResourceContext, RenderResourceId},
|
||||||
};
|
};
|
||||||
use bevy_app::prelude::{EventReader, Events};
|
use bevy_app::prelude::{EventReader, Events};
|
||||||
use bevy_asset::{AssetEvent, Assets, Handle};
|
use bevy_asset::{AssetEvent, Assets, Handle};
|
||||||
use bevy_core::AsBytes;
|
use bevy_core::AsBytes;
|
||||||
use bevy_ecs::{Local, Query, Res, ResMut};
|
use bevy_ecs::{Local, Query, Res};
|
||||||
use bevy_math::*;
|
use bevy_math::*;
|
||||||
use bevy_type_registry::TypeUuid;
|
use bevy_type_registry::TypeUuid;
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
@ -89,18 +89,24 @@ pub enum Indices {
|
|||||||
U16(Vec<u16>),
|
U16(Vec<u16>),
|
||||||
U32(Vec<u32>),
|
U32(Vec<u32>),
|
||||||
}
|
}
|
||||||
// TODO: allow values to be unloaded after been submitting to the GPU to conserve memory
|
|
||||||
pub type VertexAttributesHashMap = HashMap<Cow<'static, str>, VertexAttributeValues>;
|
|
||||||
|
|
||||||
|
impl From<&Indices> for IndexFormat {
|
||||||
|
fn from(indices: &Indices) -> Self {
|
||||||
|
match indices {
|
||||||
|
Indices::U16(_) => IndexFormat::Uint16,
|
||||||
|
Indices::U32(_) => IndexFormat::Uint32,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: allow values to be unloaded after been submitting to the GPU to conserve memory
|
||||||
#[derive(Debug, TypeUuid)]
|
#[derive(Debug, TypeUuid)]
|
||||||
#[uuid = "8ecbac0f-f545-4473-ad43-e1f4243af51e"]
|
#[uuid = "8ecbac0f-f545-4473-ad43-e1f4243af51e"]
|
||||||
pub struct Mesh {
|
pub struct Mesh {
|
||||||
pub primitive_topology: PrimitiveTopology,
|
primitive_topology: PrimitiveTopology,
|
||||||
/// `bevy_utils::HashMap` with all defined vertex attributes (Positions, Normals, ...) for this mesh. Attribute name maps to attribute values.
|
/// `bevy_utils::HashMap` with all defined vertex attributes (Positions, Normals, ...) for this mesh. Attribute name maps to attribute values.
|
||||||
pub attributes: VertexAttributesHashMap,
|
attributes: HashMap<Cow<'static, str>, VertexAttributeValues>,
|
||||||
pub indices: Option<Indices>,
|
indices: Option<Indices>,
|
||||||
/// The layout of the attributes in the GPU buffer without `shader_location`. `None` will indicate that no data has been uploaded to the GPU yet.
|
|
||||||
pub attribute_buffer_descriptor_reference: Option<VertexBufferDescriptor>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Mesh {
|
impl Mesh {
|
||||||
@ -113,16 +119,107 @@ impl Mesh {
|
|||||||
primitive_topology,
|
primitive_topology,
|
||||||
attributes: Default::default(),
|
attributes: Default::default(),
|
||||||
indices: None,
|
indices: None,
|
||||||
attribute_buffer_descriptor_reference: Default::default(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn primitive_topology(&self) -> PrimitiveTopology {
|
||||||
|
self.primitive_topology
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_attribute(
|
||||||
|
&mut self,
|
||||||
|
name: impl Into<Cow<'static, str>>,
|
||||||
|
values: VertexAttributeValues,
|
||||||
|
) {
|
||||||
|
self.attributes.insert(name.into(), values);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn attribute(
|
||||||
|
&mut self,
|
||||||
|
name: impl Into<Cow<'static, str>>,
|
||||||
|
) -> Option<&VertexAttributeValues> {
|
||||||
|
self.attributes.get(&name.into())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_indices(&mut self, indices: Option<Indices>) {
|
||||||
|
self.indices = indices;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn indices(&self) -> Option<&Indices> {
|
||||||
|
self.indices.as_ref()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn get_index_buffer_bytes(&self) -> Option<Vec<u8>> {
|
pub fn get_index_buffer_bytes(&self) -> Option<Vec<u8>> {
|
||||||
self.indices.as_ref().map(|indices| match &indices {
|
self.indices.as_ref().map(|indices| match &indices {
|
||||||
Indices::U16(indices) => indices.as_slice().as_bytes().to_vec(),
|
Indices::U16(indices) => indices.as_slice().as_bytes().to_vec(),
|
||||||
Indices::U32(indices) => indices.as_slice().as_bytes().to_vec(),
|
Indices::U32(indices) => indices.as_slice().as_bytes().to_vec(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_vertex_buffer_descriptor(&self) -> VertexBufferDescriptor {
|
||||||
|
let mut attributes = Vec::new();
|
||||||
|
let mut accumulated_offset = 0;
|
||||||
|
for (attribute_name, attribute_values) in self.attributes.iter() {
|
||||||
|
let vertex_format = VertexFormat::from(attribute_values);
|
||||||
|
attributes.push(VertexAttributeDescriptor {
|
||||||
|
name: attribute_name.clone(),
|
||||||
|
offset: accumulated_offset,
|
||||||
|
format: vertex_format,
|
||||||
|
shader_location: 0,
|
||||||
|
});
|
||||||
|
accumulated_offset += vertex_format.get_size();
|
||||||
|
}
|
||||||
|
|
||||||
|
VertexBufferDescriptor {
|
||||||
|
name: Default::default(),
|
||||||
|
stride: accumulated_offset,
|
||||||
|
step_mode: InputStepMode::Vertex,
|
||||||
|
attributes,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn count_vertices(&self) -> usize {
|
||||||
|
let mut vertex_count: Option<usize> = None;
|
||||||
|
for (attribute_name, attribute_data) in self.attributes.iter() {
|
||||||
|
let attribute_len = attribute_data.len();
|
||||||
|
if let Some(previous_vertex_count) = vertex_count {
|
||||||
|
assert_eq!(previous_vertex_count, attribute_len,
|
||||||
|
"Attribute {} has a different vertex count ({}) than other attributes ({}) in this mesh.", attribute_name, attribute_len, previous_vertex_count);
|
||||||
|
}
|
||||||
|
vertex_count = Some(attribute_len);
|
||||||
|
}
|
||||||
|
|
||||||
|
vertex_count.unwrap_or(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_vertex_buffer_data(&self) -> Vec<u8> {
|
||||||
|
let mut vertex_size = 0;
|
||||||
|
for attribute_values in self.attributes.values() {
|
||||||
|
let vertex_format = VertexFormat::from(attribute_values);
|
||||||
|
vertex_size += vertex_format.get_size() as usize;
|
||||||
|
}
|
||||||
|
|
||||||
|
let vertex_count = self.count_vertices();
|
||||||
|
let mut attributes_interleaved_buffer = vec![0; vertex_count * vertex_size];
|
||||||
|
// bundle into interleaved buffers
|
||||||
|
let mut attribute_offset = 0;
|
||||||
|
for attribute_values in self.attributes.values() {
|
||||||
|
let vertex_format = VertexFormat::from(attribute_values);
|
||||||
|
let attribute_size = vertex_format.get_size() as usize;
|
||||||
|
let attributes_bytes = attribute_values.get_bytes();
|
||||||
|
for (vertex_index, attribute_bytes) in
|
||||||
|
attributes_bytes.chunks_exact(attribute_size).enumerate()
|
||||||
|
{
|
||||||
|
let offset = vertex_index * vertex_size + attribute_offset;
|
||||||
|
attributes_interleaved_buffer[offset..offset + attribute_size]
|
||||||
|
.copy_from_slice(attribute_bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
attribute_offset += attribute_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
attributes_interleaved_buffer
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Generation for some primitive shape meshes.
|
/// Generation for some primitive shape meshes.
|
||||||
@ -131,7 +228,6 @@ pub mod shape {
|
|||||||
use crate::pipeline::PrimitiveTopology;
|
use crate::pipeline::PrimitiveTopology;
|
||||||
use bevy_math::*;
|
use bevy_math::*;
|
||||||
use hexasphere::Hexasphere;
|
use hexasphere::Hexasphere;
|
||||||
use std::borrow::Cow;
|
|
||||||
|
|
||||||
/// A cube.
|
/// A cube.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@ -201,13 +297,10 @@ pub mod shape {
|
|||||||
]);
|
]);
|
||||||
|
|
||||||
let mut mesh = Mesh::new(PrimitiveTopology::TriangleList);
|
let mut mesh = Mesh::new(PrimitiveTopology::TriangleList);
|
||||||
mesh.attributes
|
mesh.set_attribute(Mesh::ATTRIBUTE_POSITION, positions.into());
|
||||||
.insert(Cow::Borrowed(Mesh::ATTRIBUTE_POSITION), positions.into());
|
mesh.set_attribute(Mesh::ATTRIBUTE_NORMAL, normals.into());
|
||||||
mesh.attributes
|
mesh.set_attribute(Mesh::ATTRIBUTE_UV_0, uvs.into());
|
||||||
.insert(Cow::Borrowed(Mesh::ATTRIBUTE_NORMAL), normals.into());
|
mesh.set_indices(Some(indices));
|
||||||
mesh.attributes
|
|
||||||
.insert(Cow::Borrowed(Mesh::ATTRIBUTE_UV_0), uvs.into());
|
|
||||||
mesh.indices = Some(indices);
|
|
||||||
mesh
|
mesh
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -300,13 +393,10 @@ pub mod shape {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let mut mesh = Mesh::new(PrimitiveTopology::TriangleList);
|
let mut mesh = Mesh::new(PrimitiveTopology::TriangleList);
|
||||||
mesh.indices = Some(indices);
|
mesh.set_indices(Some(indices));
|
||||||
mesh.attributes
|
mesh.set_attribute(Mesh::ATTRIBUTE_POSITION, positions.into());
|
||||||
.insert(Cow::Borrowed(Mesh::ATTRIBUTE_POSITION), positions.into());
|
mesh.set_attribute(Mesh::ATTRIBUTE_NORMAL, normals.into());
|
||||||
mesh.attributes
|
mesh.set_attribute(Mesh::ATTRIBUTE_UV_0, uvs.into());
|
||||||
.insert(Cow::Borrowed(Mesh::ATTRIBUTE_NORMAL), normals.into());
|
|
||||||
mesh.attributes
|
|
||||||
.insert(Cow::Borrowed(Mesh::ATTRIBUTE_UV_0), uvs.into());
|
|
||||||
mesh
|
mesh
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -341,13 +431,10 @@ pub mod shape {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let mut mesh = Mesh::new(PrimitiveTopology::TriangleList);
|
let mut mesh = Mesh::new(PrimitiveTopology::TriangleList);
|
||||||
mesh.indices = Some(indices);
|
mesh.set_indices(Some(indices));
|
||||||
mesh.attributes
|
mesh.set_attribute(Mesh::ATTRIBUTE_POSITION, positions.into());
|
||||||
.insert(Cow::Borrowed(Mesh::ATTRIBUTE_POSITION), positions.into());
|
mesh.set_attribute(Mesh::ATTRIBUTE_NORMAL, normals.into());
|
||||||
mesh.attributes
|
mesh.set_attribute(Mesh::ATTRIBUTE_UV_0, uvs.into());
|
||||||
.insert(Cow::Borrowed(Mesh::ATTRIBUTE_NORMAL), normals.into());
|
|
||||||
mesh.attributes
|
|
||||||
.insert(Cow::Borrowed(Mesh::ATTRIBUTE_UV_0), uvs.into());
|
|
||||||
mesh
|
mesh
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -415,13 +502,10 @@ pub mod shape {
|
|||||||
let indices = Indices::U32(indices);
|
let indices = Indices::U32(indices);
|
||||||
|
|
||||||
let mut mesh = Mesh::new(PrimitiveTopology::TriangleList);
|
let mut mesh = Mesh::new(PrimitiveTopology::TriangleList);
|
||||||
mesh.indices = Some(indices);
|
mesh.set_indices(Some(indices));
|
||||||
mesh.attributes
|
mesh.set_attribute(Mesh::ATTRIBUTE_POSITION, points.into());
|
||||||
.insert(Cow::Borrowed(Mesh::ATTRIBUTE_POSITION), points.into());
|
mesh.set_attribute(Mesh::ATTRIBUTE_NORMAL, normals.into());
|
||||||
mesh.attributes
|
mesh.set_attribute(Mesh::ATTRIBUTE_UV_0, uvs.into());
|
||||||
.insert(Cow::Borrowed(Mesh::ATTRIBUTE_NORMAL), normals.into());
|
|
||||||
mesh.attributes
|
|
||||||
.insert(Cow::Borrowed(Mesh::ATTRIBUTE_UV_0), uvs.into());
|
|
||||||
mesh
|
mesh
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -456,7 +540,7 @@ pub struct MeshResourceProviderState {
|
|||||||
pub fn mesh_resource_provider_system(
|
pub fn mesh_resource_provider_system(
|
||||||
mut state: Local<MeshResourceProviderState>,
|
mut state: Local<MeshResourceProviderState>,
|
||||||
render_resource_context: Res<Box<dyn RenderResourceContext>>,
|
render_resource_context: Res<Box<dyn RenderResourceContext>>,
|
||||||
mut meshes: ResMut<Assets<Mesh>>,
|
meshes: Res<Assets<Mesh>>,
|
||||||
mesh_events: Res<Events<AssetEvent<Mesh>>>,
|
mesh_events: Res<Events<AssetEvent<Mesh>>>,
|
||||||
mut query: Query<(&Handle<Mesh>, &mut RenderPipelines)>,
|
mut query: Query<(&Handle<Mesh>, &mut RenderPipelines)>,
|
||||||
) {
|
) {
|
||||||
@ -482,7 +566,7 @@ pub fn mesh_resource_provider_system(
|
|||||||
|
|
||||||
// update changed mesh data
|
// update changed mesh data
|
||||||
for changed_mesh_handle in changed_meshes.iter() {
|
for changed_mesh_handle in changed_meshes.iter() {
|
||||||
if let Some(mesh) = meshes.get_mut(changed_mesh_handle) {
|
if let Some(mesh) = meshes.get(changed_mesh_handle) {
|
||||||
// TODO: check for individual buffer changes in non-interleaved mode
|
// TODO: check for individual buffer changes in non-interleaved mode
|
||||||
let index_buffer = render_resource_context.create_buffer_with_data(
|
let index_buffer = render_resource_context.create_buffer_with_data(
|
||||||
BufferInfo {
|
BufferInfo {
|
||||||
@ -498,12 +582,8 @@ pub fn mesh_resource_provider_system(
|
|||||||
INDEX_BUFFER_ASSET_INDEX,
|
INDEX_BUFFER_ASSET_INDEX,
|
||||||
);
|
);
|
||||||
|
|
||||||
// Vertex buffer
|
let interleaved_buffer = mesh.get_vertex_buffer_data();
|
||||||
let vertex_count = attributes_count_vertices(&mesh.attributes).unwrap();
|
|
||||||
let interleaved_buffer =
|
|
||||||
attributes_to_vertex_buffer_data(&mesh.attributes, vertex_count);
|
|
||||||
|
|
||||||
mesh.attribute_buffer_descriptor_reference = Some(interleaved_buffer.1);
|
|
||||||
render_resource_context.set_asset_resource(
|
render_resource_context.set_asset_resource(
|
||||||
changed_mesh_handle,
|
changed_mesh_handle,
|
||||||
RenderResourceId::Buffer(render_resource_context.create_buffer_with_data(
|
RenderResourceId::Buffer(render_resource_context.create_buffer_with_data(
|
||||||
@ -511,7 +591,7 @@ pub fn mesh_resource_provider_system(
|
|||||||
buffer_usage: BufferUsage::VERTEX,
|
buffer_usage: BufferUsage::VERTEX,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
&interleaved_buffer.0,
|
&interleaved_buffer,
|
||||||
)),
|
)),
|
||||||
VERTEX_ATTRIBUTE_BUFFER_ID,
|
VERTEX_ATTRIBUTE_BUFFER_ID,
|
||||||
);
|
);
|
||||||
@ -525,7 +605,7 @@ pub fn mesh_resource_provider_system(
|
|||||||
buffer_usage: BufferUsage::VERTEX,
|
buffer_usage: BufferUsage::VERTEX,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
&vec![0; (vertex_count * VertexFormat::Float4.get_size() as u32) as usize],
|
&vec![0; mesh.count_vertices() * VertexFormat::Float4.get_size() as usize],
|
||||||
)),
|
)),
|
||||||
VERTEX_FALLBACK_BUFFER_ID,
|
VERTEX_FALLBACK_BUFFER_ID,
|
||||||
);
|
);
|
||||||
@ -533,11 +613,17 @@ pub fn mesh_resource_provider_system(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// handover buffers to pipeline
|
// handover buffers to pipeline
|
||||||
// TODO: remove this once batches are pipeline specific and deprecate assigned_meshes draw target
|
|
||||||
for (handle, mut render_pipelines) in query.iter_mut() {
|
for (handle, mut render_pipelines) in query.iter_mut() {
|
||||||
if let Some(mesh) = meshes.get(handle) {
|
if let Some(mesh) = meshes.get(handle) {
|
||||||
for render_pipeline in render_pipelines.pipelines.iter_mut() {
|
for render_pipeline in render_pipelines.pipelines.iter_mut() {
|
||||||
render_pipeline.specialization.primitive_topology = mesh.primitive_topology;
|
render_pipeline.specialization.primitive_topology = mesh.primitive_topology;
|
||||||
|
// TODO: don't allocate a new vertex buffer descriptor for every entity
|
||||||
|
render_pipeline.specialization.vertex_buffer_descriptor =
|
||||||
|
mesh.get_vertex_buffer_descriptor();
|
||||||
|
render_pipeline.specialization.index_format = mesh
|
||||||
|
.indices()
|
||||||
|
.map(|i| i.into())
|
||||||
|
.unwrap_or(IndexFormat::Uint32);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(RenderResourceId::Buffer(index_buffer_resource)) =
|
if let Some(RenderResourceId::Buffer(index_buffer_resource)) =
|
||||||
@ -566,65 +652,3 @@ pub fn mesh_resource_provider_system(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn attributes_count_vertices(attributes: &VertexAttributesHashMap) -> Option<u32> {
|
|
||||||
let mut vertex_count: Option<u32> = None;
|
|
||||||
for (attribute_name, attribute_data) in attributes {
|
|
||||||
let attribute_len = attribute_data.len();
|
|
||||||
if let Some(previous_vertex_count) = vertex_count {
|
|
||||||
assert_eq!(previous_vertex_count, attribute_len as u32,
|
|
||||||
"Attribute {} has a different vertex count ({}) than other attributes ({}) in this mesh.", attribute_name, attribute_len, previous_vertex_count);
|
|
||||||
}
|
|
||||||
vertex_count = Some(attribute_len as u32);
|
|
||||||
}
|
|
||||||
vertex_count
|
|
||||||
}
|
|
||||||
pub fn attributes_to_vertex_buffer_data(
|
|
||||||
attributes: &VertexAttributesHashMap,
|
|
||||||
vertex_count: u32,
|
|
||||||
) -> (Vec<u8>, VertexBufferDescriptor) {
|
|
||||||
// get existing attribute data as bytes and generate attribute descriptor
|
|
||||||
let mut attributes_gpu_ready = Vec::<(VertexAttributeDescriptor, &[u8])>::default();
|
|
||||||
let mut accumulated_offset = 0;
|
|
||||||
let mut attributes_sorted: Vec<_> = attributes.iter().collect();
|
|
||||||
attributes_sorted.sort_by(|a, b| a.0.cmp(b.0));
|
|
||||||
for attribute_data in attributes_sorted {
|
|
||||||
// TODO: allow for custom converter here
|
|
||||||
let vertex_format = VertexFormat::from(attribute_data.1);
|
|
||||||
attributes_gpu_ready.push((
|
|
||||||
// this serves as a reference and is not supposed to be used directly.
|
|
||||||
VertexAttributeDescriptor {
|
|
||||||
name: attribute_data.0.clone(),
|
|
||||||
offset: accumulated_offset,
|
|
||||||
format: vertex_format,
|
|
||||||
shader_location: 0,
|
|
||||||
},
|
|
||||||
attribute_data.1.get_bytes(),
|
|
||||||
));
|
|
||||||
accumulated_offset += vertex_format.get_size();
|
|
||||||
}
|
|
||||||
let mut attributes_interleaved_buffer = Vec::<u8>::default();
|
|
||||||
|
|
||||||
// bundle into interleaved buffers
|
|
||||||
for vertex_index in 0..vertex_count {
|
|
||||||
let vertex_index = vertex_index as usize;
|
|
||||||
for (attribute_descriptor, attributes_bytes) in &attributes_gpu_ready {
|
|
||||||
let stride = attribute_descriptor.format.get_size() as usize;
|
|
||||||
// insert one element
|
|
||||||
attributes_interleaved_buffer
|
|
||||||
.extend(&attributes_bytes[vertex_index * stride..vertex_index * stride + stride]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let vertex_buffer_descriptor_reference = VertexBufferDescriptor {
|
|
||||||
name: Default::default(),
|
|
||||||
stride: accumulated_offset,
|
|
||||||
step_mode: InputStepMode::Vertex,
|
|
||||||
attributes: attributes_gpu_ready.iter().map(|x| x.0.clone()).collect(),
|
|
||||||
};
|
|
||||||
|
|
||||||
(
|
|
||||||
attributes_interleaved_buffer,
|
|
||||||
vertex_buffer_descriptor_reference,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
@ -20,7 +20,7 @@ pub struct PipelineSpecialization {
|
|||||||
pub primitive_topology: PrimitiveTopology,
|
pub primitive_topology: PrimitiveTopology,
|
||||||
pub dynamic_bindings: Vec<DynamicBinding>,
|
pub dynamic_bindings: Vec<DynamicBinding>,
|
||||||
pub index_format: IndexFormat,
|
pub index_format: IndexFormat,
|
||||||
pub mesh_attribute_layout: VertexBufferDescriptor,
|
pub vertex_buffer_descriptor: VertexBufferDescriptor,
|
||||||
pub sample_count: u32,
|
pub sample_count: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -28,11 +28,11 @@ impl Default for PipelineSpecialization {
|
|||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
sample_count: 1,
|
sample_count: 1,
|
||||||
|
index_format: IndexFormat::Uint32,
|
||||||
shader_specialization: Default::default(),
|
shader_specialization: Default::default(),
|
||||||
primitive_topology: Default::default(),
|
primitive_topology: Default::default(),
|
||||||
dynamic_bindings: Default::default(),
|
dynamic_bindings: Default::default(),
|
||||||
index_format: IndexFormat::Uint32,
|
vertex_buffer_descriptor: Default::default(),
|
||||||
mesh_attribute_layout: Default::default(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -172,7 +172,7 @@ impl PipelineCompiler {
|
|||||||
// create a vertex layout that provides all attributes from either the specialized vertex buffers or a zero buffer
|
// create a vertex layout that provides all attributes from either the specialized vertex buffers or a zero buffer
|
||||||
let mut pipeline_layout = specialized_descriptor.layout.as_mut().unwrap();
|
let mut pipeline_layout = specialized_descriptor.layout.as_mut().unwrap();
|
||||||
// the vertex buffer descriptor of the mesh
|
// the vertex buffer descriptor of the mesh
|
||||||
let mesh_vertex_buffer_descriptor = pipeline_specialization.mesh_attribute_layout.clone();
|
let mesh_vertex_buffer_descriptor = &pipeline_specialization.vertex_buffer_descriptor;
|
||||||
|
|
||||||
// the vertex buffer descriptor that will be used for this pipeline
|
// the vertex buffer descriptor that will be used for this pipeline
|
||||||
let mut compiled_vertex_buffer_descriptor = VertexBufferDescriptor {
|
let mut compiled_vertex_buffer_descriptor = VertexBufferDescriptor {
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use super::{IndexFormat, PipelineDescriptor, PipelineSpecialization};
|
use super::{PipelineDescriptor, PipelineSpecialization};
|
||||||
use crate::{
|
use crate::{
|
||||||
draw::{Draw, DrawContext},
|
draw::{Draw, DrawContext},
|
||||||
mesh::{Indices, Mesh},
|
mesh::{Indices, Mesh},
|
||||||
@ -91,21 +91,16 @@ pub fn draw_render_pipelines_system(
|
|||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
|
|
||||||
let (index_range, index_format) = match mesh.indices.as_ref() {
|
let index_range = match mesh.indices() {
|
||||||
Some(Indices::U32(indices)) => (Some(0..indices.len() as u32), IndexFormat::Uint32),
|
Some(Indices::U32(indices)) => Some(0..indices.len() as u32),
|
||||||
Some(Indices::U16(indices)) => (Some(0..indices.len() as u32), IndexFormat::Uint16),
|
Some(Indices::U16(indices)) => Some(0..indices.len() as u32),
|
||||||
None => (None, IndexFormat::Uint32),
|
None => None,
|
||||||
};
|
};
|
||||||
|
|
||||||
let render_pipelines = &mut *render_pipelines;
|
let render_pipelines = &mut *render_pipelines;
|
||||||
for pipeline in render_pipelines.pipelines.iter_mut() {
|
for pipeline in render_pipelines.pipelines.iter_mut() {
|
||||||
pipeline.specialization.sample_count = msaa.samples;
|
pipeline.specialization.sample_count = msaa.samples;
|
||||||
pipeline.specialization.index_format = index_format;
|
// TODO: move these to mesh.rs?
|
||||||
pipeline.specialization.mesh_attribute_layout = mesh
|
|
||||||
.attribute_buffer_descriptor_reference
|
|
||||||
.as_ref()
|
|
||||||
.unwrap()
|
|
||||||
.clone();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for render_pipeline in render_pipelines.pipelines.iter() {
|
for render_pipeline in render_pipelines.pipelines.iter() {
|
||||||
|
@ -51,7 +51,7 @@ impl<'a> Drawable for DrawableText<'a> {
|
|||||||
&bevy_sprite::SPRITE_SHEET_PIPELINE_HANDLE,
|
&bevy_sprite::SPRITE_SHEET_PIPELINE_HANDLE,
|
||||||
&PipelineSpecialization {
|
&PipelineSpecialization {
|
||||||
sample_count: self.msaa.samples,
|
sample_count: self.msaa.samples,
|
||||||
mesh_attribute_layout: self.font_quad_vertex_descriptor.clone(),
|
vertex_buffer_descriptor: self.font_quad_vertex_descriptor.clone(),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
)?;
|
)?;
|
||||||
|
@ -100,14 +100,8 @@ pub fn draw_text_system(
|
|||||||
mut asset_render_resource_bindings: ResMut<AssetRenderResourceBindings>,
|
mut asset_render_resource_bindings: ResMut<AssetRenderResourceBindings>,
|
||||||
mut query: Query<(&mut Draw, &Text, &Node, &GlobalTransform)>,
|
mut query: Query<(&mut Draw, &Text, &Node, &GlobalTransform)>,
|
||||||
) {
|
) {
|
||||||
let font_quad_vertex_descriptor = {
|
|
||||||
let font_quad = meshes.get(&QUAD_HANDLE).unwrap();
|
let font_quad = meshes.get(&QUAD_HANDLE).unwrap();
|
||||||
font_quad
|
let vertex_buffer_descriptor = font_quad.get_vertex_buffer_descriptor();
|
||||||
.attribute_buffer_descriptor_reference
|
|
||||||
.as_ref()
|
|
||||||
.unwrap()
|
|
||||||
.clone()
|
|
||||||
};
|
|
||||||
|
|
||||||
for (mut draw, text, node, global_transform) in query.iter_mut() {
|
for (mut draw, text, node, global_transform) in query.iter_mut() {
|
||||||
if let Some(font) = fonts.get(&text.font) {
|
if let Some(font) = fonts.get(&text.font) {
|
||||||
@ -123,7 +117,7 @@ pub fn draw_text_system(
|
|||||||
style: &text.style,
|
style: &text.style,
|
||||||
text: &text.value,
|
text: &text.value,
|
||||||
container_size: node.size,
|
container_size: node.size,
|
||||||
font_quad_vertex_descriptor: &font_quad_vertex_descriptor,
|
font_quad_vertex_descriptor: &vertex_buffer_descriptor,
|
||||||
};
|
};
|
||||||
drawable_text.draw(&mut draw, &mut draw_context).unwrap();
|
drawable_text.draw(&mut draw, &mut draw_context).unwrap();
|
||||||
}
|
}
|
||||||
|
@ -23,7 +23,7 @@ fn setup(
|
|||||||
if let Some(sphere) = meshes.get(&sphere_handle) {
|
if let Some(sphere) = meshes.get(&sphere_handle) {
|
||||||
// You might notice that this doesn't run! This is because assets load in parallel without blocking.
|
// You might notice that this doesn't run! This is because assets load in parallel without blocking.
|
||||||
// When an asset has loaded, it will appear in relevant Assets<T> collection.
|
// When an asset has loaded, it will appear in relevant Assets<T> collection.
|
||||||
println!("{:?}", sphere.primitive_topology);
|
println!("{:?}", sphere.primitive_topology());
|
||||||
} else {
|
} else {
|
||||||
println!("sphere hasn't loaded yet");
|
println!("sphere hasn't loaded yet");
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user