bevy/crates/bevy_ui/src/ui_resource_provider.rs
2020-04-24 17:57:20 -07:00

121 lines
3.7 KiB
Rust

use bevy_core::ecs;
use bevy_derive::Uniforms;
use bevy_render::{
pipeline::VertexBufferDescriptors,
render_resource::{
resource_name, BufferArrayInfo, BufferInfo, BufferUsage, RenderResource,
RenderResourceAssignments, ResourceProvider,
},
renderer::Renderer,
shader::AsUniforms,
};
use bevy_transform::prelude::Parent;
use legion::prelude::*;
use zerocopy::{AsBytes, FromBytes};
#[repr(C)]
#[derive(Clone, Copy, Debug, AsBytes, FromBytes, Uniforms)]
#[uniform(bevy_path = "crate")]
pub struct Rect {
#[uniform(instance)]
pub position: [f32; 2],
#[uniform(instance)]
pub size: [f32; 2],
#[uniform(instance)]
pub color: [f32; 4],
#[uniform(instance)]
pub z_index: f32,
}
pub struct UiResourceProvider {
pub instance_buffer: Option<RenderResource>,
}
impl UiResourceProvider {
pub fn new() -> Self {
UiResourceProvider {
instance_buffer: None,
}
}
pub fn update(&mut self, renderer: &mut dyn Renderer, world: &World, resources: &Resources) {
let node_query = <Read<Node>>::query().filter(!component::<Parent>());
let mut data = Vec::new();
if node_query.iter(world).count() > 0 {
// TODO: this probably isn't the best way to handle z-ordering
let mut z = 0.9999;
{
let mut add_data: Box<dyn FnMut(&World, Entity, ()) -> Option<()>> =
Box::new(|world, entity, _| {
let node = world.get_component::<Node>(entity).unwrap();
data.push(Rect {
position: node.global_position.into(),
size: node.size.into(),
color: node.color.into(),
z_index: z,
});
z -= 0.0001;
Some(())
});
for entity in node_query
.iter_entities(world)
.map(|(entity, _)| entity)
.collect::<Vec<Entity>>()
{
ecs::run_on_hierarchy(world, entity, (), &mut add_data);
}
}
}
if data.len() == 0 {
return;
}
let size = std::mem::size_of::<Rect>();
let data_len = data.len();
if let Some(old_instance_buffer) = self.instance_buffer {
renderer.remove_buffer(old_instance_buffer);
}
let buffer = renderer.create_buffer_with_data(
BufferInfo {
size,
buffer_usage: BufferUsage::COPY_SRC | BufferUsage::VERTEX,
array_info: Some(BufferArrayInfo {
item_capacity: data_len,
item_count: data_len,
item_size: size,
..Default::default()
}),
..Default::default()
},
data.as_bytes(),
);
let mut render_resource_assignments =
resources.get_mut::<RenderResourceAssignments>().unwrap();
render_resource_assignments.set(resource_name::buffer::UI_INSTANCES, buffer);
self.instance_buffer = Some(buffer);
}
}
impl ResourceProvider for UiResourceProvider {
fn initialize(
&mut self,
_renderer: &mut dyn Renderer,
_world: &mut World,
resources: &Resources,
) {
let mut vertex_buffer_descriptors = resources.get_mut::<VertexBufferDescriptors>().unwrap();
vertex_buffer_descriptors.set(Rect::get_vertex_buffer_descriptor().cloned().unwrap());
}
fn update(&mut self, renderer: &mut dyn Renderer, world: &mut World, resources: &Resources) {
self.update(renderer, world, resources);
}
}