render: add RenderPass queries. move ui to its own pass
This commit is contained in:
parent
bd8e979de8
commit
2929197d9b
@ -1,6 +1,7 @@
|
||||
use crate::ArchetypeAccess;
|
||||
use hecs::{
|
||||
Archetype, Component, ComponentError, Entity, Fetch, Query as HecsQuery, Ref, RefMut, World,
|
||||
Archetype, Component, ComponentError, Entity, Fetch, Query as HecsQuery, QueryOne, Ref, RefMut,
|
||||
World,
|
||||
};
|
||||
use std::marker::PhantomData;
|
||||
|
||||
@ -11,10 +12,11 @@ pub struct Query<'a, Q: HecsQuery> {
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum QueryComponentError {
|
||||
pub enum QueryError {
|
||||
CannotReadArchetype,
|
||||
CannotWriteArchetype,
|
||||
ComponentError(ComponentError),
|
||||
NoSuchEntity,
|
||||
}
|
||||
|
||||
impl<'a, Q: HecsQuery> Query<'a, Q> {
|
||||
@ -34,7 +36,7 @@ impl<'a, Q: HecsQuery> Query<'a, Q> {
|
||||
|
||||
/// Gets a reference to the entity's component of the given type. This will fail if the entity does not have
|
||||
/// the given component type or if the given component type does not match this query.
|
||||
pub fn get<T: Component>(&self, entity: Entity) -> Result<Ref<'_, T>, QueryComponentError> {
|
||||
pub fn get<T: Component>(&self, entity: Entity) -> Result<Ref<'_, T>, QueryError> {
|
||||
if let Some(location) = self.world.get_entity_location(entity) {
|
||||
if self
|
||||
.archetype_access
|
||||
@ -47,23 +49,38 @@ impl<'a, Q: HecsQuery> Query<'a, Q> {
|
||||
{
|
||||
self.world
|
||||
.get(entity)
|
||||
.map_err(|err| QueryComponentError::ComponentError(err))
|
||||
.map_err(|err| QueryError::ComponentError(err))
|
||||
} else {
|
||||
Err(QueryComponentError::CannotReadArchetype)
|
||||
Err(QueryError::CannotReadArchetype)
|
||||
}
|
||||
} else {
|
||||
Err(QueryComponentError::ComponentError(
|
||||
ComponentError::NoSuchEntity,
|
||||
))
|
||||
Err(QueryError::ComponentError(ComponentError::NoSuchEntity))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn entity(&self, entity: Entity) -> Result<QueryOne<'_, Q>, QueryError> {
|
||||
if let Some(location) = self.world.get_entity_location(entity) {
|
||||
if self
|
||||
.archetype_access
|
||||
.immutable
|
||||
.contains(location.archetype as usize)
|
||||
|| self
|
||||
.archetype_access
|
||||
.mutable
|
||||
.contains(location.archetype as usize)
|
||||
{
|
||||
Ok(self.world.query_one(entity).unwrap())
|
||||
} else {
|
||||
Err(QueryError::CannotReadArchetype)
|
||||
}
|
||||
} else {
|
||||
Err(QueryError::NoSuchEntity)
|
||||
}
|
||||
}
|
||||
|
||||
/// Gets a mutable reference to the entity's component of the given type. This will fail if the entity does not have
|
||||
/// the given component type or if the given component type does not match this query.
|
||||
pub fn get_mut<T: Component>(
|
||||
&self,
|
||||
entity: Entity,
|
||||
) -> Result<RefMut<'_, T>, QueryComponentError> {
|
||||
pub fn get_mut<T: Component>(&self, entity: Entity) -> Result<RefMut<'_, T>, QueryError> {
|
||||
if let Some(location) = self.world.get_entity_location(entity) {
|
||||
if self
|
||||
.archetype_access
|
||||
@ -72,14 +89,12 @@ impl<'a, Q: HecsQuery> Query<'a, Q> {
|
||||
{
|
||||
self.world
|
||||
.get_mut(entity)
|
||||
.map_err(|err| QueryComponentError::ComponentError(err))
|
||||
.map_err(|err| QueryError::ComponentError(err))
|
||||
} else {
|
||||
Err(QueryComponentError::CannotWriteArchetype)
|
||||
Err(QueryError::CannotWriteArchetype)
|
||||
}
|
||||
} else {
|
||||
Err(QueryComponentError::ComponentError(
|
||||
ComponentError::NoSuchEntity,
|
||||
))
|
||||
Err(QueryError::ComponentError(ComponentError::NoSuchEntity))
|
||||
}
|
||||
}
|
||||
|
||||
@ -89,11 +104,7 @@ impl<'a, Q: HecsQuery> Query<'a, Q> {
|
||||
|
||||
/// Sets the entity's component to the given value. This will fail if the entity does not already have
|
||||
/// the given component type or if the given component type does not match this query.
|
||||
pub fn set<T: Component>(
|
||||
&self,
|
||||
entity: Entity,
|
||||
component: T,
|
||||
) -> Result<(), QueryComponentError> {
|
||||
pub fn set<T: Component>(&self, entity: Entity, component: T) -> Result<(), QueryError> {
|
||||
let mut current = self.get_mut::<T>(entity)?;
|
||||
*current = component;
|
||||
Ok(())
|
||||
|
@ -4,7 +4,7 @@ use bevy_ecs::Bundle;
|
||||
use bevy_render::{
|
||||
draw::Draw,
|
||||
mesh::Mesh,
|
||||
pipeline::{DynamicBinding, PipelineSpecialization, RenderPipeline, RenderPipelines},
|
||||
pipeline::{DynamicBinding, PipelineSpecialization, RenderPipeline, RenderPipelines}, prelude::MainPass,
|
||||
};
|
||||
use bevy_transform::prelude::{Rotation, Scale, Transform, Translation};
|
||||
|
||||
@ -12,6 +12,7 @@ use bevy_transform::prelude::{Rotation, Scale, Transform, Translation};
|
||||
pub struct PbrComponents {
|
||||
pub mesh: Handle<Mesh>,
|
||||
pub material: Handle<StandardMaterial>,
|
||||
pub main_pass: MainPass,
|
||||
pub draw: Draw,
|
||||
pub render_pipelines: RenderPipelines,
|
||||
pub transform: Transform,
|
||||
@ -43,6 +44,7 @@ impl Default for PbrComponents {
|
||||
)]),
|
||||
mesh: Default::default(),
|
||||
material: Default::default(),
|
||||
main_pass: Default::default(),
|
||||
draw: Default::default(),
|
||||
transform: Default::default(),
|
||||
translation: Default::default(),
|
||||
|
@ -8,11 +8,15 @@ use bevy_asset::Handle;
|
||||
use bevy_ecs::Bundle;
|
||||
use bevy_transform::components::{Rotation, Scale, Transform, Translation};
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct MainPass;
|
||||
|
||||
#[derive(Bundle, Default)]
|
||||
pub struct MeshComponents {
|
||||
pub mesh: Handle<Mesh>,
|
||||
pub draw: Draw,
|
||||
pub render_pipelines: RenderPipelines,
|
||||
pub main_pass: MainPass,
|
||||
pub transform: Transform,
|
||||
pub translation: Translation,
|
||||
pub rotation: Rotation,
|
||||
|
@ -7,6 +7,7 @@ use crate::{
|
||||
LoadOp, Operations, PassDescriptor, RenderPassColorAttachmentDescriptor,
|
||||
RenderPassDepthStencilAttachmentDescriptor, TextureAttachment,
|
||||
},
|
||||
prelude::MainPass,
|
||||
texture::{Extent3d, TextureDescriptor, TextureDimension, TextureFormat, TextureUsage},
|
||||
Color,
|
||||
};
|
||||
@ -89,7 +90,7 @@ impl BaseRenderGraphBuilder for RenderGraph {
|
||||
}
|
||||
|
||||
if config.add_main_pass {
|
||||
let mut main_pass_node = PassNode::new(PassDescriptor {
|
||||
let mut main_pass_node = PassNode::<&MainPass>::new(PassDescriptor {
|
||||
color_attachments: vec![RenderPassColorAttachmentDescriptor {
|
||||
attachment: TextureAttachment::Input("color".to_string()),
|
||||
resolve_target: None,
|
||||
|
@ -11,14 +11,15 @@ use crate::{
|
||||
},
|
||||
};
|
||||
use bevy_asset::{Assets, Handle};
|
||||
use bevy_ecs::{Resources, World};
|
||||
use bevy_ecs::{Resources, World, HecsQuery};
|
||||
use std::marker::PhantomData;
|
||||
|
||||
struct CameraInfo {
|
||||
name: String,
|
||||
bind_group_id: Option<BindGroupId>,
|
||||
}
|
||||
|
||||
pub struct PassNode {
|
||||
pub struct PassNode<Q: HecsQuery> {
|
||||
descriptor: PassDescriptor,
|
||||
inputs: Vec<ResourceSlotInfo>,
|
||||
cameras: Vec<CameraInfo>,
|
||||
@ -26,9 +27,10 @@ pub struct PassNode {
|
||||
depth_stencil_attachment_input_index: Option<usize>,
|
||||
default_clear_color_inputs: Vec<usize>,
|
||||
camera_bind_group_descriptor: BindGroupDescriptor,
|
||||
_marker: PhantomData<Q>,
|
||||
}
|
||||
|
||||
impl PassNode {
|
||||
impl<Q: HecsQuery> PassNode<Q> {
|
||||
pub fn new(descriptor: PassDescriptor) -> Self {
|
||||
let mut inputs = Vec::new();
|
||||
let mut color_attachment_input_indices = Vec::new();
|
||||
@ -75,6 +77,7 @@ impl PassNode {
|
||||
depth_stencil_attachment_input_index,
|
||||
default_clear_color_inputs: Vec::new(),
|
||||
camera_bind_group_descriptor,
|
||||
_marker: PhantomData::default(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -90,7 +93,7 @@ impl PassNode {
|
||||
}
|
||||
}
|
||||
|
||||
impl Node for PassNode {
|
||||
impl<Q: HecsQuery + Send + Sync + 'static> Node for PassNode<Q> {
|
||||
fn input(&self) -> &[ResourceSlotInfo] {
|
||||
&self.inputs
|
||||
}
|
||||
@ -167,6 +170,13 @@ impl Node for PassNode {
|
||||
// attempt to draw each visible entity
|
||||
let mut draw_state = DrawState::default();
|
||||
for visible_entity in visible_entities.iter() {
|
||||
if let Ok(mut query_one) = world.query_one::<Q>(visible_entity.entity) {
|
||||
if query_one.get().is_none() {
|
||||
// visible entity does not match the Pass query
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
let draw = if let Ok(draw) = world.get::<Draw>(visible_entity.entity) {
|
||||
draw
|
||||
} else {
|
||||
|
@ -7,7 +7,7 @@ use bevy_ecs::Bundle;
|
||||
use bevy_render::{
|
||||
mesh::Mesh,
|
||||
pipeline::{DynamicBinding, PipelineSpecialization, RenderPipeline, RenderPipelines},
|
||||
prelude::Draw,
|
||||
prelude::{Draw, MainPass},
|
||||
};
|
||||
use bevy_transform::prelude::{Rotation, Scale, Transform, Translation};
|
||||
|
||||
@ -16,6 +16,7 @@ pub struct SpriteComponents {
|
||||
pub sprite: Sprite,
|
||||
pub mesh: Handle<Mesh>, // TODO: maybe abstract this out
|
||||
pub material: Handle<ColorMaterial>,
|
||||
pub main_pass: MainPass,
|
||||
pub draw: Draw,
|
||||
pub render_pipelines: RenderPipelines,
|
||||
pub transform: Transform,
|
||||
@ -51,6 +52,7 @@ impl Default for SpriteComponents {
|
||||
..Default::default()
|
||||
},
|
||||
sprite: Default::default(),
|
||||
main_pass: MainPass,
|
||||
material: Default::default(),
|
||||
transform: Default::default(),
|
||||
translation: Default::default(),
|
||||
@ -66,6 +68,7 @@ pub struct SpriteSheetComponents {
|
||||
pub texture_atlas: Handle<TextureAtlas>,
|
||||
pub draw: Draw,
|
||||
pub render_pipelines: RenderPipelines,
|
||||
pub main_pass: MainPass,
|
||||
pub mesh: Handle<Mesh>, // TODO: maybe abstract this out
|
||||
pub transform: Transform,
|
||||
pub translation: Translation,
|
||||
@ -99,6 +102,7 @@ impl Default for SpriteSheetComponents {
|
||||
..Default::default()
|
||||
},
|
||||
mesh: QUAD_HANDLE,
|
||||
main_pass: MainPass,
|
||||
sprite: Default::default(),
|
||||
texture_atlas: Default::default(),
|
||||
transform: Default::default(),
|
||||
|
@ -4,9 +4,9 @@ use bevy_ecs::Resources;
|
||||
use bevy_render::{
|
||||
camera::ActiveCameras,
|
||||
pipeline::*,
|
||||
render_graph::{base, CameraNode, PassNode, RenderGraph, RenderResourcesNode},
|
||||
render_graph::{base, CameraNode, PassNode, RenderGraph, RenderResourcesNode, WindowSwapChainNode, WindowTextureNode},
|
||||
shader::{Shader, ShaderStage, ShaderStages},
|
||||
texture::TextureFormat,
|
||||
texture::TextureFormat, prelude::{Color, MainPass}, pass::{RenderPassColorAttachmentDescriptor, PassDescriptor, TextureAttachment, LoadOp, Operations, RenderPassDepthStencilAttachmentDescriptor},
|
||||
};
|
||||
|
||||
pub const UI_PIPELINE_HANDLE: Handle<PipelineDescriptor> =
|
||||
@ -60,6 +60,7 @@ pub fn build_ui_pipeline(shaders: &mut Assets<Shader>) -> PipelineDescriptor {
|
||||
pub mod node {
|
||||
pub const UI_CAMERA: &'static str = "ui_camera";
|
||||
pub const NODE: &'static str = "node";
|
||||
pub const UI_PASS: &'static str = "ui_pass";
|
||||
}
|
||||
|
||||
pub mod camera {
|
||||
@ -76,16 +77,56 @@ impl UiRenderGraphBuilder for RenderGraph {
|
||||
let mut shaders = resources.get_mut::<Assets<Shader>>().unwrap();
|
||||
pipelines.set(UI_PIPELINE_HANDLE, build_ui_pipeline(&mut shaders));
|
||||
|
||||
let mut ui_pass_node = PassNode::<&Node>::new(PassDescriptor {
|
||||
color_attachments: vec![RenderPassColorAttachmentDescriptor {
|
||||
attachment: TextureAttachment::Input("color".to_string()),
|
||||
resolve_target: None,
|
||||
ops: Operations {
|
||||
load: LoadOp::Load,
|
||||
store: true,
|
||||
},
|
||||
}],
|
||||
depth_stencil_attachment: Some(RenderPassDepthStencilAttachmentDescriptor {
|
||||
attachment: TextureAttachment::Input("depth".to_string()),
|
||||
depth_ops: Some(Operations {
|
||||
load: LoadOp::Clear(1.0),
|
||||
store: true,
|
||||
}),
|
||||
stencil_ops: None,
|
||||
}),
|
||||
sample_count: 1,
|
||||
});
|
||||
ui_pass_node.add_camera(camera::UI_CAMERA);
|
||||
self.add_node(node::UI_PASS, ui_pass_node);
|
||||
|
||||
self.add_slot_edge(
|
||||
base::node::PRIMARY_SWAP_CHAIN,
|
||||
WindowSwapChainNode::OUT_TEXTURE,
|
||||
node::UI_PASS,
|
||||
"color",
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
self.add_slot_edge(
|
||||
base::node::MAIN_DEPTH_TEXTURE,
|
||||
WindowTextureNode::OUT_TEXTURE,
|
||||
node::UI_PASS,
|
||||
"depth",
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
// ensure ui pass runs after main pass
|
||||
self.add_node_edge(base::node::MAIN_PASS, node::UI_PASS)
|
||||
.unwrap();
|
||||
|
||||
// setup ui camera
|
||||
self.add_system_node(node::UI_CAMERA, CameraNode::new(camera::UI_CAMERA));
|
||||
self.add_node_edge(node::UI_CAMERA, base::node::MAIN_PASS)
|
||||
self.add_node_edge(node::UI_CAMERA, node::UI_PASS)
|
||||
.unwrap();
|
||||
self.add_system_node(node::NODE, RenderResourcesNode::<Node>::new(true));
|
||||
self.add_node_edge(node::NODE, base::node::MAIN_PASS)
|
||||
self.add_node_edge(node::NODE, node::UI_PASS)
|
||||
.unwrap();
|
||||
let mut active_cameras = resources.get_mut::<ActiveCameras>().unwrap();
|
||||
let main_pass_node: &mut PassNode = self.get_node_mut(base::node::MAIN_PASS).unwrap();
|
||||
main_pass_node.add_camera(camera::UI_CAMERA);
|
||||
active_cameras.add(camera::UI_CAMERA);
|
||||
self
|
||||
}
|
||||
|
@ -63,7 +63,7 @@ fn setup(
|
||||
render_graph.add_system_node("secondary_camera", CameraNode::new("Secondary"));
|
||||
|
||||
// add a new render pass for our new camera
|
||||
let mut second_window_pass = PassNode::new(PassDescriptor {
|
||||
let mut second_window_pass = PassNode::<&MainPass>::new(PassDescriptor {
|
||||
color_attachments: vec![RenderPassColorAttachmentDescriptor {
|
||||
attachment: TextureAttachment::Input("color".to_string()),
|
||||
resolve_target: None,
|
||||
|
Loading…
Reference in New Issue
Block a user