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