hephae_render/
lib.rs

1#![allow(internal_features)]
2#![cfg_attr(any(docsrs, docsrs_dep), feature(rustdoc_internals))]
3#![doc = include_str!("../README.md")]
4#![cfg_attr(doc, deny(missing_docs))]
5
6pub mod attribute;
7pub mod drawer;
8pub mod image_bind;
9pub mod pipeline;
10pub mod vertex;
11
12use bevy_app::{PluginGroupBuilder, prelude::*};
13use bevy_asset::prelude::*;
14use bevy_ecs::prelude::*;
15use bevy_render::{
16    Render, RenderApp, RenderSet,
17    prelude::*,
18    render_phase::AddRenderCommand,
19    render_resource::SpecializedRenderPipelines,
20    sync_component::SyncComponentPlugin,
21    view::{ExtractedView, VisibilitySystems},
22};
23pub use bytemuck;
24use hephae_utils::prelude::*;
25
26use crate::{
27    drawer::{Drawer, HasDrawer, extract_drawers, queue_drawers},
28    image_bind::{ImageAssetEvents, ImageBindGroups, extract_image_events, validate_image_bind_groups},
29    pipeline::{
30        DrawBuffers, DrawRequests, VertexPipeline, ViewBatches, ViewIndexBuffer, VisibleDrawers, extract_shader,
31        load_shader, prepare_indices, prepare_view_bind_groups, queue_vertices,
32    },
33    prelude::Vertex,
34    vertex::{DrawItems, VertexDrawers, check_visibilities},
35};
36
37/// Common imports for [`hephae_render`](crate).
38pub mod prelude {
39    pub use ::bytemuck::{self, NoUninit, Pod, Zeroable};
40
41    pub use crate::{
42        HephaeRenderSystems,
43        attribute::{IsVertexAttribute, LinearRgbaExt as _, Nor, VertexLayout},
44        drawer::{Drawer, DrawerExtract, HasDrawer, VertexQueuer},
45        image_bind::ImageBindGroups,
46        pipeline::{VertexPipeline, ViewBatches},
47        vertex::Vertex,
48    };
49}
50
51plugin_conf! {
52    /// [`Vertex`]s you can pass to [`RendererPlugin`] to conveniently configure them in one go.
53    pub trait VertexConf for Vertex, T => VertexPlugin::<T>::default()
54}
55
56plugin_conf! {
57    /// [`Drawer`]s you can pass to [`RendererPlugin`] to conveniently configure them in one go.
58    pub trait DrawerConf for Drawer, T => DrawerPlugin::<T>::default()
59}
60
61plugin_def! {
62    /// Vertex renderer driver, generic over `T`.
63    ///
64    /// Adds the core functionality of Hephae through the
65    /// [`Vertex`] `impl` of `T`. Note that with this alone you can't start drawing yet; refer to
66    /// [`drawer`] for more.
67    pub struct VertexPlugin<T: Vertex>;
68    fn build(&self, app: &mut App) {
69        app.init_resource::<VertexDrawers<T>>()
70            .add_systems(Startup, load_shader::<T>)
71            .add_systems(PostUpdate, check_visibilities::<T>.in_set(VisibilitySystems::CheckVisibility));
72
73        if let Some(render_app) = app.get_sub_app_mut(RenderApp) {
74            let world = render_app
75                .init_resource::<SpecializedRenderPipelines<VertexPipeline<T>>>()
76                .add_render_command::<T::Item, DrawRequests<T>>()
77                .add_systems(ExtractSchedule, extract_shader::<T>)
78                .add_systems(Render, queue_vertices::<T>.in_set(HephaeRenderSystems::QueueVertices))
79                .world_mut();
80
81            world.register_required_components::<ExtractedView, ViewBatches<T>>();
82            world.register_required_components::<ExtractedView, ViewIndexBuffer<T>>();
83            world.register_required_components::<ExtractedView, VisibleDrawers<T>>();
84        }
85    }
86
87    fn finish(&self, app: &mut App) {
88        if let Some(render_app) = app.get_sub_app_mut(RenderApp) {
89            render_app
90                .init_resource::<DrawBuffers<T>>()
91                .init_resource::<VertexPipeline<T>>()
92                .add_systems(
93                    Render,
94                    (
95                        prepare_indices::<T>.in_set(HephaeRenderSystems::PrepareIndices),
96                        prepare_view_bind_groups::<T>.in_set(HephaeRenderSystems::PrepareBindGroups),
97                    ),
98                );
99        }
100
101        T::setup(app);
102    }
103}
104
105plugin_def! {
106    /// Vertex specialized drawer driver, generic over `T`.
107    ///
108    /// Integrates [`Drawer`] into your application for entities to render into the Hephae rendering
109    /// pipeline.
110    pub struct DrawerPlugin<T: Drawer>;
111    fn build(&self, app: &mut App) {
112        app.add_plugins(SyncComponentPlugin::<HasDrawer<T>>::default())
113            .register_type::<HasDrawer<T>>()
114            .world_mut()
115            .resource_scope::<VertexDrawers<T::Vertex>, ()>(|world, mut drawers| drawers.add::<T>(world));
116
117        if let Some(render_app) = app.get_sub_app_mut(RenderApp) {
118            render_app
119                .add_systems(ExtractSchedule, extract_drawers::<T>)
120                .add_systems(Render, queue_drawers::<T>.in_set(HephaeRenderSystems::QueueDrawers))
121                .world_mut()
122                .register_required_components::<T, DrawItems<T::Vertex>>();
123        }
124    }
125}
126
127plugin_def! {
128    /// The entry point of Hephae. See [`vertex`] and [`drawer`] for more information.
129    #[plugin_group]
130    pub struct RendererPlugin<V: VertexConf = (), D: DrawerConf = ()>;
131    fn build(self) -> PluginGroupBuilder {
132        let mut builder = PluginGroupBuilder::start::<Self>().add(|app: &mut App| {
133            app.world_mut().resource_mut::<Assets<Shader>>().insert(
134                &HEPHAE_VIEW_BINDINGS_HANDLE,
135                Shader::from_wgsl(include_str!("view_bindings.wgsl"), "hephae/view_bindings.wgsl"),
136            );
137
138            if let Some(render_app) = app.get_sub_app_mut(RenderApp) {
139                render_app
140                    .configure_sets(
141                        Render,
142                        (
143                            (
144                                HephaeRenderSystems::ClearBatches,
145                                HephaeRenderSystems::QueueDrawers,
146                                HephaeRenderSystems::QueueVertices,
147                            )
148                                .in_set(RenderSet::Queue),
149                            HephaeRenderSystems::QueueDrawers.before(HephaeRenderSystems::QueueVertices),
150                            HephaeRenderSystems::PrepareIndices.in_set(RenderSet::PrepareResources),
151                            HephaeRenderSystems::PrepareBindGroups.in_set(RenderSet::PrepareBindGroups),
152                        ),
153                    )
154                    .init_resource::<ImageAssetEvents>()
155                    .init_resource::<ImageBindGroups>()
156                    .add_systems(ExtractSchedule, extract_image_events)
157                    .add_systems(
158                        Render,
159                        validate_image_bind_groups.before(HephaeRenderSystems::PrepareBindGroups),
160                    );
161            }
162        });
163
164        builder = V::build(builder);
165        D::build(builder)
166    }
167}
168
169/// Global handle to the global shader containing bind groups defining view uniform and tonemapping
170/// LUTs.
171pub const HEPHAE_VIEW_BINDINGS_HANDLE: Handle<Shader> = Handle::weak_from_u128(278527494526026980866063021704582553601);
172
173/// Labels assigned to Hephae systems that are added to [`Render`].
174#[derive(SystemSet, Debug, Copy, Clone, PartialEq, Eq, Hash)]
175pub enum HephaeRenderSystems {
176    /// Label for clearing batches, in [`RenderSet::Queue`].
177    ClearBatches,
178    /// Label for queueing drawers, in [`RenderSet::Queue`].
179    QueueDrawers,
180    /// Label for queueing vertices, in [`RenderSet::Queue`].
181    QueueVertices,
182    /// Label for preparing indices based on sorted render items, in
183    /// [`RenderSet::PrepareResources`].
184    PrepareIndices,
185    /// Label for preparing batches and view bind groups, in [`RenderSet::PrepareBindGroups`].
186    PrepareBindGroups,
187}