fix mesh allocation bug and public mesh api improvements (#768)

This commit is contained in:
Carter Anderson 2020-11-02 13:15:07 -08:00 committed by GitHub
parent a04e67d9dd
commit 44b3e24e32
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 155 additions and 145 deletions

View File

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

View File

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

View File

@ -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 {

View File

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

View File

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

View File

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

View File

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