add more doc comments and clean up some public exports

This commit is contained in:
Carter Anderson 2020-08-09 16:13:04 -07:00
parent f963cd41dc
commit 3d09459813
74 changed files with 360 additions and 163 deletions

View file

@ -1,6 +1,26 @@
use crate::app_builder::AppBuilder;
use bevy_ecs::{ParallelExecutor, Resources, Schedule, World};
/// Containers of app logic and data
///
/// App store the ECS World, Resources, Schedule, and Executor. They also store the "run" function of the App, which
/// by default executes the App schedule once. Apps are constructed using the builder pattern.
///
/// ## Example
/// Here is a simple "Hello World" Bevy app:
/// ```
///use bevy::prelude::*;
///
///fn main() {
/// App::build()
/// .add_system(hello_world_system.system())
/// .run();
///}
///
///fn hello_world_system() {
/// println!("hello world");
///}
/// ```
pub struct App {
pub world: World,
pub resources: Resources,

View file

@ -1,11 +1,12 @@
use crate::{
app::{App, AppExit},
event::Events,
plugin::{load_plugin, Plugin},
plugin::{dynamically_load_plugin, Plugin},
stage, startup_stage,
};
use bevy_ecs::{FromResources, IntoQuerySystem, Resources, System, World};
/// Configure [App]s using the builder pattern
pub struct AppBuilder {
pub app: App,
}
@ -220,7 +221,7 @@ impl AppBuilder {
}
pub fn load_plugin(&mut self, path: &str) -> &mut Self {
let (_lib, plugin) = load_plugin(path);
let (_lib, plugin) = dynamically_load_plugin(path);
log::debug!("loaded plugin: {}", plugin.name());
plugin.build(self);
self

View file

@ -82,6 +82,7 @@ fn map_instance_event<T>(event_instance: &EventInstance<T>) -> &T {
&event_instance.event
}
/// Reads events of type `T` in order and tracks which events have already been read.
pub struct EventReader<T> {
last_event_count: usize,
_marker: PhantomData<T>,

View file

@ -1,11 +1,13 @@
/// The names of the default App stages
pub mod stage;
/// The names of the default App startup stages
pub mod startup_stage;
mod app;
mod app_builder;
mod event;
mod plugin;
mod schedule_runner;
mod startup_stage;
pub use app::*;
pub use app_builder::*;
@ -13,7 +15,6 @@ pub use bevy_derive::DynamicPlugin;
pub use event::*;
pub use plugin::*;
pub use schedule_runner::*;
pub use startup_stage::*;
pub mod prelude {
pub use crate::{

View file

@ -2,6 +2,9 @@ use crate::AppBuilder;
use libloading::{Library, Symbol};
use std::any::Any;
/// A collection of Bevy App logic and configuration
///
/// Plugins use [AppBuilder] to configure an [App](crate::App). When an [App](crate::App) registers a plugin, the plugin's [Plugin::build] function is run.
pub trait Plugin: Any + Send + Sync {
fn build(&self, app: &mut AppBuilder);
fn name(&self) -> &str {
@ -11,7 +14,8 @@ pub trait Plugin: Any + Send + Sync {
pub type CreatePlugin = unsafe fn() -> *mut dyn Plugin;
pub fn load_plugin(path: &str) -> (Library, Box<dyn Plugin>) {
/// Dynamically links a plugin a the given path. The plugin must export the [CreatePlugin] function.
pub fn dynamically_load_plugin(path: &str) -> (Library, Box<dyn Plugin>) {
let lib = Library::new(path).unwrap();
unsafe {

View file

@ -6,6 +6,7 @@ use crate::{
};
use std::{thread, time::Duration};
/// Determines the method used to run an [App]'s `Schedule`
#[derive(Copy, Clone, Debug)]
pub enum RunMode {
Loop { wait: Option<Duration> },
@ -18,6 +19,7 @@ impl Default for RunMode {
}
}
/// Configures an App to run its [Schedule](bevy_ecs::Schedule) according to a given [RunMode]
#[derive(Default)]
pub struct ScheduleRunnerPlugin {
pub run_mode: RunMode,

View file

@ -14,7 +14,10 @@ use std::{
};
use thiserror::Error;
/// The type used for asset versioning
pub type AssetVersion = usize;
/// Errors that occur while loading assets with an AssetServer
#[derive(Error, Debug)]
pub enum AssetServerError {
#[error("Asset folder path is not a directory.")]
@ -39,13 +42,15 @@ struct LoaderThread {
requests: Arc<RwLock<Vec<LoadRequest>>>,
}
/// Info about a specific asset, such as its path and its current load state
#[derive(Clone, Debug)]
pub struct AssetInfo {
handle_id: HandleId,
path: PathBuf,
load_state: LoadState,
pub handle_id: HandleId,
pub path: PathBuf,
pub load_state: LoadState,
}
/// The load state of an asset
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum LoadState {
Loading(AssetVersion),
@ -63,6 +68,7 @@ impl LoadState {
}
}
/// Loads assets from the filesystem on background threads
pub struct AssetServer {
asset_folders: RwLock<Vec<PathBuf>>,
loader_threads: RwLock<Vec<LoaderThread>>,

View file

@ -7,12 +7,14 @@ use bevy_ecs::{FromResources, IntoQuerySystem, ResMut, Resource};
use bevy_type_registry::RegisterType;
use std::collections::HashMap;
/// Events that happen on assets of type `T`
pub enum AssetEvent<T: Resource> {
Created { handle: Handle<T> },
Modified { handle: Handle<T> },
Removed { handle: Handle<T> },
}
/// Stores Assets of a given type and tracks changes to them.
pub struct Assets<T: Resource> {
assets: HashMap<Handle<T>, T>,
events: Events<AssetEvent<T>>,
@ -108,6 +110,7 @@ impl<T: Resource> Assets<T> {
}
}
/// [AppBuilder] extension methods for adding new asset types
pub trait AddAsset {
fn add_asset<T>(&mut self) -> &mut Self
where

View file

@ -2,7 +2,7 @@ use crossbeam_channel::Receiver;
use notify::{Event, RecommendedWatcher, RecursiveMode, Result, Watcher};
use std::path::Path;
/// Watches for changes to assets on the filesystem and informs the `AssetServer` to reload them
/// Watches for changes to assets on the filesystem. This is used by the `AssetServer` to reload them
pub struct FilesystemWatcher {
pub watcher: RecommendedWatcher,
pub receiver: Receiver<Result<Event>>,

View file

@ -8,10 +8,13 @@ use serde::{Deserialize, Serialize};
use std::{any::TypeId, marker::PhantomData};
use uuid::Uuid;
/// The ID of the "default" asset
pub(crate) const DEFAULT_HANDLE_ID: HandleId =
HandleId(Uuid::from_u128(240940089166493627844978703213080810552));
/// A unique id that corresponds to a specific asset in the [Assets](crate::Assets) collection.
#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash, Serialize, Deserialize, Property)]
pub struct HandleId(pub Uuid);
pub const DEFAULT_HANDLE_ID: HandleId =
HandleId(Uuid::from_u128(240940089166493627844978703213080810552));
impl HandleId {
pub fn new() -> HandleId {
@ -19,6 +22,9 @@ impl HandleId {
}
}
/// A handle into a specific Asset of type `T`
///
/// Handles contain a unique id that corresponds to a specific asset in the [Assets](crate::Assets) collection.
#[derive(Properties)]
pub struct Handle<T>
where
@ -156,6 +162,9 @@ impl<T> Copy for Handle<T> {}
unsafe impl<T> Send for Handle<T> {}
unsafe impl<T> Sync for Handle<T> {}
/// A non-generic version of [Handle]
///
/// This allows handles to be mingled in a cross asset context. For example, storing `Handle<A>` and `Handle<B>` in the same `HashSet<HandleUntyped>`.
#[derive(Hash, Copy, Clone, Eq, PartialEq, Debug)]
pub struct HandleUntyped {
pub id: HandleId,

View file

@ -1,7 +1,7 @@
#[cfg(feature = "filesystem_watcher")]
mod filesystem_watcher;
mod asset_server;
mod assets;
#[cfg(feature = "filesystem_watcher")]
pub mod filesystem_watcher;
mod handle;
mod load_request;
mod loader;
@ -12,6 +12,7 @@ pub use handle::*;
pub use load_request::*;
pub use loader::*;
/// The names of asset stages in an App Schedule
pub mod stage {
pub const LOAD_ASSETS: &str = "load_assets";
pub const ASSET_EVENTS: &str = "asset_events";
@ -25,6 +26,8 @@ use bevy_app::{prelude::Plugin, AppBuilder};
use bevy_ecs::IntoQuerySystem;
use bevy_type_registry::RegisterType;
/// Adds support for Assets to an App. Assets are typed collections with change tracking, which are added as App Resources.
/// Examples of assets: textures, sounds, 3d models, maps, scenes
#[derive(Default)]
pub struct AssetPlugin;

View file

@ -5,6 +5,7 @@ use fs::File;
use io::Read;
use std::{fs, io, path::PathBuf};
/// A request from an [AssetServer](crate::AssetServer) to load an asset.
#[derive(Debug)]
pub struct LoadRequest {
pub path: PathBuf,
@ -13,12 +14,13 @@ pub struct LoadRequest {
pub version: AssetVersion,
}
/// Handles load requests from an AssetServer
pub trait AssetLoadRequestHandler: Send + Sync + 'static {
fn handle_request(&self, load_request: &LoadRequest);
fn extensions(&self) -> &[&str];
}
pub struct ChannelAssetHandler<TLoader, TAsset>
pub(crate) struct ChannelAssetHandler<TLoader, TAsset>
where
TLoader: AssetLoader<TAsset>,
TAsset: 'static,

View file

@ -10,6 +10,7 @@ use std::{
};
use thiserror::Error;
/// Errors that occur while loading assets
#[derive(Error, Debug)]
pub enum AssetLoadError {
#[error("Encountered an io error while loading asset.")]
@ -18,6 +19,7 @@ pub enum AssetLoadError {
LoaderError(#[from] anyhow::Error),
}
/// A loader for a given asset of type `T`
pub trait AssetLoader<T>: Send + Sync + 'static {
fn from_bytes(&self, asset_path: &Path, bytes: Vec<u8>) -> Result<T, anyhow::Error>;
fn extensions(&self) -> &[&str];
@ -30,6 +32,7 @@ pub trait AssetLoader<T>: Send + Sync + 'static {
}
}
/// The result of loading an asset of type `T`
pub struct AssetResult<T: 'static> {
pub result: Result<T, AssetLoadError>,
pub handle: Handle<T>,
@ -37,6 +40,7 @@ pub struct AssetResult<T: 'static> {
pub version: AssetVersion,
}
/// A channel to send and receive [AssetResult]s
pub struct AssetChannel<T: 'static> {
pub sender: Sender<AssetResult<T>>,
pub receiver: Receiver<AssetResult<T>>,
@ -49,6 +53,7 @@ impl<T> AssetChannel<T> {
}
}
/// Reads [AssetResult]s from an [AssetChannel] and updates the [Assets] collection and [LoadState] accordingly
pub fn update_asset_storage_system<T: Resource>(
asset_channel: Res<AssetChannel<T>>,
asset_server: Res<AssetServer>,

View file

@ -4,6 +4,7 @@ use bevy_ecs::Res;
use rodio::{Decoder, Device, Sink};
use std::{collections::VecDeque, io::Cursor, sync::RwLock};
/// Used to play audio on the current "audio device"
pub struct AudioOutput {
device: Device,
queue: RwLock<VecDeque<Handle<AudioSource>>>,
@ -46,7 +47,8 @@ impl AudioOutput {
}
}
pub fn play_queued_audio_system(
/// Plays audio currently queued in the [AudioOutput] resource
pub(crate) fn play_queued_audio_system(
audio_sources: Res<Assets<AudioSource>>,
audio_output: Res<AudioOutput>,
) {

View file

@ -2,6 +2,7 @@ use anyhow::Result;
use bevy_asset::AssetLoader;
use std::{path::Path, sync::Arc};
/// A source of audio data
#[derive(Clone)]
pub struct AudioSource {
pub bytes: Arc<Vec<u8>>,
@ -13,6 +14,7 @@ impl AsRef<[u8]> for AudioSource {
}
}
/// Loads mp3 files as [AudioSource] [Assets](bevy_asset::Assets)
#[derive(Default)]
pub struct Mp3Loader;

View file

@ -12,6 +12,7 @@ use bevy_app::prelude::*;
use bevy_asset::AddAsset;
use bevy_ecs::IntoQuerySystem;
/// Adds support for audio playback to an App
#[derive(Default)]
pub struct AudioPlugin;

View file

@ -2,11 +2,16 @@ use bevy_math::{Mat4, Vec2, Vec3, Vec4};
pub use bevy_derive::Bytes;
/// Converts the implementing type to bytes by writing them to a given buffer
pub trait Bytes {
/// Converts the implementing type to bytes by writing them to a given buffer
fn write_bytes(&self, buffer: &mut [u8]);
/// The number of bytes that will be written when calling `write_bytes`
fn byte_len(&self) -> usize;
}
/// A trait that indicates that it is safe to cast the type to a byte array reference.
pub unsafe trait Byteable
where
Self: Sized,
@ -27,11 +32,15 @@ where
}
}
/// Reads the implementing type as a byte array reference
pub trait AsBytes {
/// Reads the implementing type as a byte array reference
fn as_bytes(&self) -> &[u8];
}
/// Converts a byte array to `Self`
pub trait FromBytes {
/// Converts a byte array to `Self`
fn from_bytes(bytes: &[u8]) -> Self;
}

View file

@ -5,7 +5,9 @@ use std::{
ops::Neg,
};
// working around the famous "rust float ordering" problem
/// A wrapper type that enables ordering floats. This is a work around for the famous "rust float ordering" problem.
/// By using it, you acknowledge that sorting NaN is undefined according to spec. This implementation treats NaN as the
/// "smallest" float.
#[derive(Debug, Copy, Clone, PartialOrd)]
pub struct FloatOrd(pub f32);

View file

@ -7,6 +7,7 @@ use std::{
ops::{Deref, DerefMut},
};
/// A collection of labels
#[derive(Default, Properties)]
pub struct Labels {
labels: HashSet<Cow<'static, str>>,
@ -50,6 +51,7 @@ impl Labels {
}
}
/// Maintains a mapping from [Entity](bevy_ecs::prelude::Entity) ids to entity labels and entity labels to [Entities](bevy_ecs::prelude::Entity).
#[derive(Default)]
pub struct EntityLabels {
label_entities: HashMap<Cow<'static, str>, Vec<Entity>>,
@ -64,7 +66,7 @@ impl EntityLabels {
}
}
pub fn entity_labels_system(
pub(crate) fn entity_labels_system(
mut entity_labels: ResMut<EntityLabels>,
// TODO: use change tracking when add/remove events are added
// mut query: Query<(Entity, Changed<Labels>)>,

View file

@ -17,6 +17,7 @@ use bevy_ecs::prelude::*;
use bevy_math::{Mat3, Mat4, Quat, Vec2, Vec3};
use bevy_type_registry::RegisterType;
/// Adds core functionality to Apps.
#[derive(Default)]
pub struct CorePlugin;
@ -32,6 +33,7 @@ impl Plugin for CorePlugin {
.register_property::<Quat>()
.register_property::<Option<String>>()
.add_system_to_stage(stage::FIRST, time_system.system())
.add_system_to_stage(stage::FIRST, timer_system.system());
.add_system_to_stage(stage::FIRST, timer_system.system())
.add_system_to_stage(stage::PRE_UPDATE, entity_labels_system.system());
}
}

View file

@ -1,6 +1,7 @@
use bevy_ecs::ResMut;
use std::time::{Duration, Instant};
/// Tracks elapsed time since the last update and since the App has started
pub struct Time {
pub delta: Duration,
pub instant: Option<Instant>,
@ -42,6 +43,6 @@ impl Time {
}
}
pub fn time_system(mut time: ResMut<Time>) {
pub(crate) fn time_system(mut time: ResMut<Time>) {
time.update();
}

View file

@ -3,6 +3,7 @@ use bevy_ecs::prelude::*;
use bevy_property::Properties;
use std::time::Duration;
/// Tracks elapsed time. Enters the finished state once `duration` is reached.
#[derive(Clone, Debug, Default, Properties)]
pub struct Timer {
pub elapsed: f32,
@ -11,16 +12,16 @@ pub struct Timer {
}
impl Timer {
pub fn from_seconds(seconds: f32) -> Self {
pub fn new(duration: Duration) -> Self {
Timer {
duration: seconds,
duration: duration.as_secs_f32(),
..Default::default()
}
}
pub fn new(duration: Duration) -> Self {
pub fn from_seconds(seconds: f32) -> Self {
Timer {
duration: duration.as_secs_f32(),
duration: seconds,
..Default::default()
}
}
@ -38,7 +39,7 @@ impl Timer {
}
}
pub fn timer_system(time: Res<Time>, mut query: Query<&mut Timer>) {
pub(crate) fn timer_system(time: Res<Time>, mut query: Query<&mut Timer>) {
for mut timer in &mut query.iter() {
timer.tick(time.delta_seconds);
}

View file

@ -11,37 +11,47 @@ mod shader_defs;
use proc_macro::TokenStream;
/// Derives the FromResources trait. Each field must also implement the FromResources trait or this will fail. FromResources is
/// automatically implemented for types that implement Default.
#[proc_macro_derive(FromResources, attributes(as_crate))]
pub fn derive_from_resources(input: TokenStream) -> TokenStream {
resource::derive_from_resources(input)
}
/// Derives the Bytes trait. Each field must also implements Bytes or this will fail.
#[proc_macro_derive(Bytes, attributes(as_crate))]
pub fn derive_bytes(input: TokenStream) -> TokenStream {
bytes::derive_bytes(input)
}
/// Derives the RenderResources trait. Each field must implement RenderResource or this will fail.
/// You can ignore fields using `#[render_resources(ignore)]`.
#[proc_macro_derive(RenderResources, attributes(render_resources, as_crate))]
pub fn derive_render_resources(input: TokenStream) -> TokenStream {
render_resources::derive_render_resources(input)
}
/// Derives the RenderResource trait. The type must also implement `Bytes` or this will fail.
#[proc_macro_derive(RenderResource, attributes(as_crate))]
pub fn derive_render_resource(input: TokenStream) -> TokenStream {
render_resource::derive_render_resource(input)
}
/// Derives the ShaderDefs trait. Each field must implement ShaderDef or this will fail.
/// You can ignore fields using `#[shader_defs(ignore)]`.
#[proc_macro_derive(ShaderDefs, attributes(shader_def, as_crate))]
pub fn derive_shader_defs(input: TokenStream) -> TokenStream {
shader_defs::derive_shader_defs(input)
}
/// Derives the AsVertexBufferDescriptor trait.
#[proc_macro_derive(AsVertexBufferDescriptor, attributes(vertex, as_crate))]
pub fn derive_as_vertex_buffer_descriptor(input: TokenStream) -> TokenStream {
as_vertex_buffer_descriptor::derive_as_vertex_buffer_descriptor(input)
}
/// Generates a dynamic plugin entry point function for the given `Plugin` type.
#[proc_macro_derive(DynamicPlugin)]
pub fn derive_app_plugin(input: TokenStream) -> TokenStream {
pub fn derive_dynamic_plugin(input: TokenStream) -> TokenStream {
app_plugin::derive_dynamic_plugin(input)
}

View file

@ -4,6 +4,7 @@ use std::{
};
use uuid::Uuid;
/// Unique identifier for a [Diagnostic]
#[derive(Debug, Copy, Clone, Hash, Eq, PartialEq)]
pub struct DiagnosticId(pub Uuid);
@ -19,12 +20,15 @@ impl Default for DiagnosticId {
}
}
/// A single measurement of a [Diagnostic]
#[derive(Debug)]
pub struct DiagnosticMeasurement {
pub time: SystemTime,
pub value: f64,
}
/// A timeline of [DiagnosticMeasurement]s of a specific type.
/// Diagnostic examples: frames per second, CPU usage, network latency
#[derive(Debug)]
pub struct Diagnostic {
pub id: DiagnosticId,
@ -97,6 +101,7 @@ impl Diagnostic {
}
}
/// A collection of [Diagnostic]s
#[derive(Default)]
pub struct Diagnostics {
diagnostics: HashMap<DiagnosticId, Diagnostic>,

View file

@ -3,6 +3,7 @@ use bevy_app::prelude::*;
use bevy_core::Time;
use bevy_ecs::{IntoQuerySystem, Res, ResMut};
/// Adds "frame time" diagnostic to an App, specifically "frame time" and "fps"
#[derive(Default)]
pub struct FrameTimeDiagnosticsPlugin;

View file

@ -9,8 +9,7 @@ pub use print_diagnostics_plugin::PrintDiagnosticsPlugin;
use bevy_app::prelude::*;
pub struct PrintDiagnostics {}
/// Adds core diagnostics resources to an App.
#[derive(Default)]
pub struct DiagnosticsPlugin;

View file

@ -4,12 +4,14 @@ use bevy_core::{Time, Timer};
use bevy_ecs::{IntoQuerySystem, Res, ResMut};
use std::time::Duration;
/// An App Plugin that prints diagnostics to the console
pub struct PrintDiagnosticsPlugin {
pub debug: bool,
pub wait_duration: Duration,
pub filter: Option<Vec<DiagnosticId>>,
}
/// State used by the [PrintDiagnosticsPlugin]
pub struct PrintDiagnosticsState {
timer: Timer,
filter: Option<Vec<DiagnosticId>>,

View file

@ -20,6 +20,7 @@ struct SystemProfiles {
current_start: Option<Instant>,
}
/// Profiles systems by recording their run duration as diagnostics.
#[derive(Default)]
pub struct SystemProfiler {
system_profiles: Arc<RwLock<HashMap<Cow<'static, str>, SystemProfiles>>>,

View file

@ -1,22 +1,22 @@
use super::{FromResources, Resources};
use crate::{
system::{SystemId, TypeAccess},
ResourceIndex,
Resource, ResourceIndex,
};
use core::{
any::TypeId,
ops::{Deref, DerefMut},
ptr::NonNull,
};
use hecs::{smaller_tuples_too, Component};
use hecs::smaller_tuples_too;
use std::marker::PhantomData;
/// Shared borrow of an entity's component
pub struct Res<'a, T: Component> {
/// Shared borrow of a Resource
pub struct Res<'a, T: Resource> {
value: &'a T,
}
impl<'a, T: Component> Res<'a, T> {
impl<'a, T: Resource> Res<'a, T> {
pub unsafe fn new(value: NonNull<T>) -> Self {
Self {
value: &*value.as_ptr(),
@ -24,20 +24,21 @@ impl<'a, T: Component> Res<'a, T> {
}
}
/// A clone that is unsafe to perform. You probably shouldn't use this.
pub trait UnsafeClone {
unsafe fn unsafe_clone(&self) -> Self;
}
impl<'a, T: Component> UnsafeClone for Res<'a, T> {
impl<'a, T: Resource> UnsafeClone for Res<'a, T> {
unsafe fn unsafe_clone(&self) -> Self {
Self { value: self.value }
}
}
unsafe impl<T: Component> Send for Res<'_, T> {}
unsafe impl<T: Component> Sync for Res<'_, T> {}
unsafe impl<T: Resource> Send for Res<'_, T> {}
unsafe impl<T: Resource> Sync for Res<'_, T> {}
impl<'a, T: Component> Deref for Res<'a, T> {
impl<'a, T: Resource> Deref for Res<'a, T> {
type Target = T;
fn deref(&self) -> &T {
@ -45,13 +46,13 @@ impl<'a, T: Component> Deref for Res<'a, T> {
}
}
/// Unique borrow of a resource
pub struct ResMut<'a, T: Component> {
/// Unique borrow of a Resource
pub struct ResMut<'a, T: Resource> {
_marker: PhantomData<&'a T>,
value: *mut T,
}
impl<'a, T: Component> ResMut<'a, T> {
impl<'a, T: Resource> ResMut<'a, T> {
pub unsafe fn new(value: NonNull<T>) -> Self {
Self {
value: value.as_ptr(),
@ -60,10 +61,10 @@ impl<'a, T: Component> ResMut<'a, T> {
}
}
unsafe impl<T: Component> Send for ResMut<'_, T> {}
unsafe impl<T: Component> Sync for ResMut<'_, T> {}
unsafe impl<T: Resource> Send for ResMut<'_, T> {}
unsafe impl<T: Resource> Sync for ResMut<'_, T> {}
impl<'a, T: Component> Deref for ResMut<'a, T> {
impl<'a, T: Resource> Deref for ResMut<'a, T> {
type Target = T;
fn deref(&self) -> &T {
@ -71,13 +72,13 @@ impl<'a, T: Component> Deref for ResMut<'a, T> {
}
}
impl<'a, T: Component> DerefMut for ResMut<'a, T> {
impl<'a, T: Resource> DerefMut for ResMut<'a, T> {
fn deref_mut(&mut self) -> &mut T {
unsafe { &mut *self.value }
}
}
impl<'a, T: Component> UnsafeClone for ResMut<'a, T> {
impl<'a, T: Resource> UnsafeClone for ResMut<'a, T> {
unsafe fn unsafe_clone(&self) -> Self {
Self {
value: self.value,
@ -86,12 +87,14 @@ impl<'a, T: Component> UnsafeClone for ResMut<'a, T> {
}
}
pub struct Local<'a, T: Component + FromResources> {
/// Local<T> resources are unique per-system. Two instances of the same system will each have their own resource.
/// Local resources are automatically initialized using the FromResources trait.
pub struct Local<'a, T: Resource + FromResources> {
value: *mut T,
_marker: PhantomData<&'a T>,
}
impl<'a, T: Component + FromResources> UnsafeClone for Local<'a, T> {
impl<'a, T: Resource + FromResources> UnsafeClone for Local<'a, T> {
unsafe fn unsafe_clone(&self) -> Self {
Self {
value: self.value,
@ -100,7 +103,7 @@ impl<'a, T: Component + FromResources> UnsafeClone for Local<'a, T> {
}
}
impl<'a, T: Component + FromResources> Deref for Local<'a, T> {
impl<'a, T: Resource + FromResources> Deref for Local<'a, T> {
type Target = T;
fn deref(&self) -> &T {
@ -108,20 +111,20 @@ impl<'a, T: Component + FromResources> Deref for Local<'a, T> {
}
}
impl<'a, T: Component + FromResources> DerefMut for Local<'a, T> {
impl<'a, T: Resource + FromResources> DerefMut for Local<'a, T> {
fn deref_mut(&mut self) -> &mut T {
unsafe { &mut *self.value }
}
}
/// A collection of component types to fetch from a `World`
/// A collection of resource types fetch from a `Resources` collection
pub trait ResourceQuery {
type Fetch: for<'a> FetchResource<'a>;
fn initialize(_resources: &mut Resources, _system_id: Option<SystemId>) {}
}
/// Streaming iterators over contiguous homogeneous ranges of components
/// Streaming iterators over contiguous homogeneous ranges of resources
pub trait FetchResource<'a>: Sized {
/// Type of value to be fetched
type Item: UnsafeClone;
@ -130,20 +133,17 @@ pub trait FetchResource<'a>: Sized {
fn borrow(resources: &Resources);
fn release(resources: &Resources);
/// Construct a `Fetch` for `archetype` if it should be traversed
///
/// # Safety
/// `offset` must be in bounds of `archetype`
unsafe fn get(resources: &'a Resources, system_id: Option<SystemId>) -> Self::Item;
}
impl<'a, T: Component> ResourceQuery for Res<'a, T> {
impl<'a, T: Resource> ResourceQuery for Res<'a, T> {
type Fetch = FetchResourceRead<T>;
}
/// Fetches a shared resource reference
pub struct FetchResourceRead<T>(NonNull<T>);
impl<'a, T: Component> FetchResource<'a> for FetchResourceRead<T> {
impl<'a, T: Resource> FetchResource<'a> for FetchResourceRead<T> {
type Item = Res<'a, T>;
unsafe fn get(resources: &'a Resources, _system_id: Option<SystemId>) -> Self::Item {
@ -165,13 +165,14 @@ impl<'a, T: Component> FetchResource<'a> for FetchResourceRead<T> {
}
}
impl<'a, T: Component> ResourceQuery for ResMut<'a, T> {
impl<'a, T: Resource> ResourceQuery for ResMut<'a, T> {
type Fetch = FetchResourceWrite<T>;
}
/// Fetches a unique resource reference
pub struct FetchResourceWrite<T>(NonNull<T>);
impl<'a, T: Component> FetchResource<'a> for FetchResourceWrite<T> {
impl<'a, T: Resource> FetchResource<'a> for FetchResourceWrite<T> {
type Item = ResMut<'a, T>;
unsafe fn get(resources: &'a Resources, _system_id: Option<SystemId>) -> Self::Item {
@ -193,7 +194,7 @@ impl<'a, T: Component> FetchResource<'a> for FetchResourceWrite<T> {
}
}
impl<'a, T: Component + FromResources> ResourceQuery for Local<'a, T> {
impl<'a, T: Resource + FromResources> ResourceQuery for Local<'a, T> {
type Fetch = FetchResourceLocalMut<T>;
fn initialize(resources: &mut Resources, id: Option<SystemId>) {
@ -203,9 +204,10 @@ impl<'a, T: Component + FromResources> ResourceQuery for Local<'a, T> {
}
}
/// Fetches a `Local<T>` resource reference
pub struct FetchResourceLocalMut<T>(NonNull<T>);
impl<'a, T: Component + FromResources> FetchResource<'a> for FetchResourceLocalMut<T> {
impl<'a, T: Resource + FromResources> FetchResource<'a> for FetchResourceLocalMut<T> {
type Item = Local<'a, T>;
unsafe fn get(resources: &'a Resources, system_id: Option<SystemId>) -> Self::Item {

View file

@ -4,10 +4,11 @@ use core::any::TypeId;
use hecs::{Archetype, Ref, RefMut, TypeInfo};
use std::{collections::HashMap, ptr::NonNull};
/// A Resource type
pub trait Resource: Send + Sync + 'static {}
impl<T: Send + Sync + 'static> Resource for T {}
pub struct ResourceData {
pub(crate) struct ResourceData {
archetype: Archetype,
default_index: Option<u32>,
system_id_to_archetype_index: HashMap<u32, u32>,
@ -18,6 +19,7 @@ pub enum ResourceIndex {
System(SystemId),
}
/// A collection of resource instances identified by their type.
#[derive(Default)]
pub struct Resources {
pub(crate) resource_data: HashMap<TypeId, ResourceData>,
@ -183,7 +185,9 @@ impl Resources {
unsafe impl Send for Resources {}
unsafe impl Sync for Resources {}
/// Creates `Self` using data from the `Resources` collection
pub trait FromResources {
/// Creates `Self` using data from the `Resources` collection
fn from_resources(resources: &Resources) -> Self;
}

View file

@ -12,6 +12,14 @@ use std::{
sync::{Arc, Mutex},
};
/// Executes each schedule stage in parallel by analyzing system dependencies.
/// System execution order is undefined except under the following conditions:
/// * systems in earlier stages run before systems in later stages
/// * in a given stage, systems that mutate archetype X cannot run before systems registered before them that read/write archetype X
/// * in a given stage, systems the read archetype X cannot run before systems registered before them that write archetype X
/// * in a given stage, systems that mutate resource Y cannot run before systems registered before them that read/write resource Y
/// * in a given stage, systems the read resource Y cannot run before systems registered before them that write resource Y
#[derive(Debug)]
pub struct ParallelExecutor {
stages: Vec<ExecutorStage>,

View file

@ -9,6 +9,9 @@ use std::{
sync::{Arc, Mutex},
};
/// An ordered collection of stages, which each contain an ordered list of [System]s.
/// Schedules are essentially the "execution plan" for an App's systems.
/// They are run on a given [World] and [Resources] reference.
#[derive(Default)]
pub struct Schedule {
pub(crate) stages: HashMap<Cow<'static, str>, Vec<Arc<Mutex<Box<dyn System>>>>>,

View file

@ -3,16 +3,18 @@ use crate::resource::{Resource, Resources};
use hecs::{Bundle, Component, DynamicBundle, Entity, World};
use std::sync::{Arc, Mutex};
/// A queued command to mutate the current [World] or [Resources]
pub enum Command {
WriteWorld(Box<dyn WorldWriter>),
WriteResources(Box<dyn ResourcesWriter>),
}
/// A [World] mutation
pub trait WorldWriter: Send + Sync {
fn write(self: Box<Self>, world: &mut World);
}
pub struct Spawn<T>
pub(crate) struct Spawn<T>
where
T: DynamicBundle + Send + Sync + 'static,
{
@ -28,7 +30,7 @@ where
}
}
pub struct SpawnAsEntity<T>
pub(crate) struct SpawnAsEntity<T>
where
T: DynamicBundle + Send + Sync + 'static,
{
@ -45,7 +47,7 @@ where
}
}
pub struct SpawnBatch<I>
pub(crate) struct SpawnBatch<I>
where
I: IntoIterator,
I::Item: Bundle,
@ -63,7 +65,7 @@ where
}
}
pub struct Despawn {
pub(crate) struct Despawn {
entity: Entity,
}
@ -90,7 +92,7 @@ where
}
}
pub struct InsertOne<T>
pub(crate) struct InsertOne<T>
where
T: Component,
{
@ -121,7 +123,7 @@ impl<T: Resource> ResourcesWriter for InsertResource<T> {
}
}
pub struct InsertLocalResource<T: Resource> {
pub(crate) struct InsertLocalResource<T: Resource> {
resource: T,
system_id: SystemId,
}
@ -194,6 +196,7 @@ impl CommandsInternal {
}
}
/// A queue of [Command]s to run on the current [World] and [Resources]
#[derive(Default, Clone)]
pub struct Commands {
pub commands: Arc<Mutex<CommandsInternal>>,

View file

@ -7,7 +7,7 @@ use crate::{
use hecs::{Fetch, Query as HecsQuery, World};
use std::borrow::Cow;
pub struct SystemFn<State, F, ThreadLocalF, Init, SetArchetypeAccess>
pub(crate) struct SystemFn<State, F, ThreadLocalF, Init, SetArchetypeAccess>
where
F: FnMut(&World, &Resources, &ArchetypeAccess, &mut State) + Send + Sync,
ThreadLocalF: FnMut(&mut World, &mut Resources, &mut State) + Send + Sync,
@ -74,7 +74,7 @@ where
}
}
#[doc(hidden)]
/// Converts `Self` into a For-Each system
pub trait IntoForEachSystem<CommandBuffer, R, C> {
fn system(self) -> Box<dyn System>;
}
@ -136,6 +136,7 @@ struct QuerySystemState {
commands: Commands,
}
/// Converts `Self` into a Query System
pub trait IntoQuerySystem<Commands, R, Q> {
fn system(self) -> Box<dyn System>;
}
@ -298,6 +299,7 @@ impl_into_systems!(Ra,Rb,Rc,Rd,Re,Rf,Rg,Rh,Ri);
#[rustfmt::skip]
impl_into_systems!(Ra,Rb,Rc,Rd,Re,Rf,Rg,Rh,Ri,Rj);
/// Converts `Self` into a thread local system
pub trait IntoThreadLocalSystem {
fn thread_local_system(self) -> Box<dyn System>;
}
@ -324,6 +326,7 @@ where
}
}
/// A thread local system function
pub trait ThreadLocalSystemFn: Send + Sync + 'static {
fn run(&mut self, world: &mut World, resource: &mut Resources);
}

View file

@ -2,6 +2,9 @@ use crate::Resources;
use downcast_rs::{impl_downcast, Downcast};
use std::borrow::Cow;
/// Runs at the start and end of each system
///
/// Profilers are used to collect diagnostics about system execution.
pub trait Profiler: Downcast + Send + Sync + 'static {
fn start(&self, scope: Cow<'static, str>);
fn stop(&self, scope: Cow<'static, str>);

View file

@ -5,12 +5,14 @@ use hecs::{
};
use std::marker::PhantomData;
/// Provides scoped access to a World according to a given [HecsQuery]
pub struct Query<'a, Q: HecsQuery> {
pub(crate) world: &'a World,
pub(crate) archetype_access: &'a ArchetypeAccess,
_marker: PhantomData<Q>,
}
/// An error that occurs when using a [Query]
#[derive(Debug)]
pub enum QueryError {
CannotReadArchetype,

View file

@ -3,6 +3,7 @@ use fixedbitset::FixedBitSet;
use hecs::{Access, Query, World};
use std::{any::TypeId, borrow::Cow, collections::HashSet};
/// Determines the strategy used to run the `run_thread_local` function in a [System]
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
pub enum ThreadLocalExecution {
Immediate,
@ -18,6 +19,7 @@ impl SystemId {
}
}
/// An ECS system that can be added to a [Schedule](crate::Schedule)
pub trait System: Send + Sync {
fn name(&self) -> Cow<'static, str>;
fn id(&self) -> SystemId;
@ -30,13 +32,14 @@ pub trait System: Send + Sync {
fn initialize(&mut self, _resources: &mut Resources) {}
}
// credit to Ratysz from the Yaks codebase
/// Provides information about the archetypes a [System] reads and writes
#[derive(Default)]
pub struct ArchetypeAccess {
pub immutable: FixedBitSet,
pub mutable: FixedBitSet,
}
// credit to Ratysz from the Yaks codebase
impl ArchetypeAccess {
pub fn is_compatible(&self, other: &ArchetypeAccess) -> bool {
self.mutable.is_disjoint(&other.mutable)
@ -73,6 +76,7 @@ impl ArchetypeAccess {
}
}
/// Provides information about the types a [System] reads and writes
#[derive(Debug, Default, Eq, PartialEq, Clone)]
pub struct TypeAccess {
pub immutable: HashSet<TypeId>,

View file

@ -1,5 +1,6 @@
use hecs::{Bundle, Component, DynamicBundle, Entity, World};
/// Converts a reference to `Self` to a [WorldBuilder]
pub trait WorldBuilderSource {
fn build(&mut self) -> WorldBuilder;
}
@ -13,6 +14,7 @@ impl WorldBuilderSource for World {
}
}
/// Modify a [World] using the builder pattern
pub struct WorldBuilder<'a> {
pub world: &'a mut World,
pub current_entity: Option<Entity>,

View file

@ -5,6 +5,7 @@ use bevy_app::prelude::*;
use bevy_asset::AddAsset;
use bevy_render::mesh::Mesh;
/// Adds support for GLTF file loading to Apps
#[derive(Default)]
pub struct GltfPlugin;

View file

@ -9,6 +9,9 @@ use gltf::{buffer::Source, iter, mesh::Mode};
use std::{fs, io, path::Path};
use thiserror::Error;
/// Loads meshes from GLTF files into Mesh assets
///
/// NOTE: eventually this will loading into Scenes instead of Meshes
#[derive(Default)]
pub struct GltfLoader;
@ -24,6 +27,7 @@ impl AssetLoader<Mesh> for GltfLoader {
}
}
/// An error that occurs when loading a GLTF file
#[derive(Error, Debug)]
pub enum GltfError {
#[error("Unsupported primitive mode.")]

View file

@ -1,5 +1,6 @@
use std::{collections::HashSet, hash::Hash};
/// A "press-able" input of type `T`
pub struct Input<T> {
pressed: HashSet<T>,
just_pressed: HashSet<T>,

View file

@ -1,7 +1,8 @@
use crate::Input;
use bevy_app::prelude::*;
use bevy_ecs::{Res, ResMut};
use bevy_ecs::{Res, ResMut, Local};
/// A key input event from a keyboard device
#[derive(Debug, Clone)]
pub struct KeyboardInput {
pub scan_code: u32,
@ -9,6 +10,7 @@ pub struct KeyboardInput {
pub state: ElementState,
}
/// The current "press" state of an element
#[derive(Debug, Clone, Eq, PartialEq)]
pub enum ElementState {
Pressed,
@ -24,13 +26,15 @@ impl ElementState {
}
}
/// State used by the keyboard input system
#[derive(Default)]
pub struct KeyboardInputState {
keyboard_input_event_reader: EventReader<KeyboardInput>,
}
/// Updates the Input<KeyCode> resource with the latest KeyboardInput events
pub fn keyboard_input_system(
mut state: ResMut<KeyboardInputState>,
mut state: Local<KeyboardInputState>,
mut keyboard_input: ResMut<Input<KeyCode>>,
keyboard_input_events: Res<Events<KeyboardInput>>,
) {
@ -53,6 +57,7 @@ pub fn keyboard_input_system(
}
}
/// The key code of a keyboard input.
#[derive(Debug, Hash, Ord, PartialOrd, PartialEq, Eq, Clone, Copy)]
#[repr(u32)]
pub enum KeyCode {

View file

@ -10,13 +10,14 @@ pub mod prelude {
}
use bevy_app::prelude::*;
use keyboard::{keyboard_input_system, KeyCode, KeyboardInput, KeyboardInputState};
use keyboard::{keyboard_input_system, KeyCode, KeyboardInput};
use mouse::{
mouse_button_input_system, MouseButton, MouseButtonInput, MouseButtonInputState, MouseMotion,
mouse_button_input_system, MouseButton, MouseButtonInput, MouseMotion,
};
use bevy_ecs::IntoQuerySystem;
/// Adds keyboard and mouse input to an App
#[derive(Default)]
pub struct InputPlugin;
@ -26,13 +27,11 @@ impl Plugin for InputPlugin {
.add_event::<MouseButtonInput>()
.add_event::<MouseMotion>()
.init_resource::<Input<KeyCode>>()
.init_resource::<KeyboardInputState>()
.add_system_to_stage(
bevy_app::stage::EVENT_UPDATE,
keyboard_input_system.system(),
)
.init_resource::<Input<MouseButton>>()
.init_resource::<MouseButtonInputState>()
.add_system_to_stage(
bevy_app::stage::EVENT_UPDATE,
mouse_button_input_system.system(),

View file

@ -1,15 +1,17 @@
use super::keyboard::ElementState;
use crate::Input;
use bevy_app::prelude::{EventReader, Events};
use bevy_ecs::{Res, ResMut};
use bevy_ecs::{Res, ResMut, Local};
use bevy_math::Vec2;
/// A mouse button input event
#[derive(Debug, Clone)]
pub struct MouseButtonInput {
pub button: MouseButton,
pub state: ElementState,
}
/// A button on a mouse device
#[derive(Debug, Hash, PartialEq, Eq, Clone, Copy)]
pub enum MouseButton {
Left,
@ -18,18 +20,21 @@ pub enum MouseButton {
Other(u8),
}
/// A mouse motion event
#[derive(Debug, Clone)]
pub struct MouseMotion {
pub delta: Vec2,
}
/// State used by the mouse button input system
#[derive(Default)]
pub struct MouseButtonInputState {
mouse_button_input_event_reader: EventReader<MouseButtonInput>,
}
/// Updates the Input<MouseButton> resource with the latest MouseButtonInput events
pub fn mouse_button_input_system(
mut state: ResMut<MouseButtonInputState>,
mut state: Local<MouseButtonInputState>,
mut mouse_button_input: ResMut<Input<MouseButton>>,
mouse_button_input_events: Res<Events<MouseButtonInput>>,
) {

View file

@ -5,11 +5,13 @@ use bevy_app::{
};
use bevy_ecs::{Local, Res, ResMut};
/// Local "exit on escape" system state
#[derive(Default)]
pub struct ExitOnEscapeState {
reader: EventReader<KeyboardInput>,
}
/// Sends the AppExit event whenever the "esc" key is pressed.
pub fn exit_on_esc_system(
mut state: Local<ExitOnEscapeState>,
keyboard_input_events: Res<Events<KeyboardInput>>,

View file

@ -1,6 +1,8 @@
use crate::{Mat4, Vec3};
/// Generates a translation / rotation matrix that faces a given target
pub trait FaceToward {
/// Generates a translation / rotation matrix that faces a given target
fn face_toward(eye: Vec3, center: Vec3, up: Vec3) -> Self;
}

View file

@ -1,6 +1,7 @@
use glam::Vec2;
use std::ops::{Add, AddAssign};
/// A two dimensional "size" as defined by a width and height
#[derive(Copy, Clone, PartialEq, Debug)]
pub struct Size<T = f32> {
pub width: T,
@ -22,6 +23,7 @@ impl<T: Default> Default for Size<T> {
}
}
/// A rect, as defined by its "side" locations
#[derive(Copy, Clone, PartialEq, Debug)]
pub struct Rect<T> {
pub left: T,

View file

@ -1,7 +1,9 @@
use crate::Mat4;
use glam::Vec4;
/// Produces a "right handed" perspective matrix
pub trait PerspectiveRh {
/// Produces a "right handed" perspective matrix
fn perspective_rh(fov_y_radians: f32, aspect_ratio: f32, z_near: f32, z_far: f32) -> Self;
}

View file

@ -1,13 +1,15 @@
use crate::{light::Light, material::StandardMaterial, pipelines::FORWARD_PIPELINE_HANDLE};
use crate::{light::Light, material::StandardMaterial, render_graph::FORWARD_PIPELINE_HANDLE};
use bevy_asset::Handle;
use bevy_ecs::Bundle;
use bevy_render::{
draw::Draw,
mesh::Mesh,
pipeline::{DynamicBinding, PipelineSpecialization, RenderPipeline, RenderPipelines}, prelude::MainPass,
pipeline::{DynamicBinding, PipelineSpecialization, RenderPipeline, RenderPipelines},
render_graph::base::MainPass,
};
use bevy_transform::prelude::{Rotation, Scale, Transform, Translation};
/// A component bundle for "pbr mesh" entities
#[derive(Bundle)]
pub struct PbrComponents {
pub mesh: Handle<Mesh>,
@ -54,6 +56,7 @@ impl Default for PbrComponents {
}
}
/// A component bundle for "light" entities
#[derive(Bundle, Default)]
pub struct LightComponents {
pub light: Light,

View file

@ -1,10 +1,13 @@
pub mod entity;
pub mod light;
pub mod material;
pub mod nodes;
pub mod pipelines;
pub mod render_graph;
mod entity;
mod light;
mod material;
pub use entity::*;
pub use light::*;
pub use material::*;
pub mod prelude {
pub use crate::{entity::*, light::Light, material::StandardMaterial};
}
@ -16,7 +19,7 @@ use bevy_render::{render_graph::RenderGraph, shader};
use bevy_type_registry::RegisterType;
use light::Light;
use material::StandardMaterial;
use render_graph::ForwardPbrRenderGraphBuilder;
use render_graph::add_pbr_graph;
/// NOTE: this isn't PBR yet. consider this name "aspirational" :)
#[derive(Default)]
@ -32,6 +35,6 @@ impl Plugin for PbrPlugin {
);
let resources = app.resources();
let mut render_graph = resources.get_mut::<RenderGraph>().unwrap();
render_graph.add_pbr_graph(resources);
add_pbr_graph(&mut render_graph, resources);
}
}

View file

@ -8,6 +8,7 @@ use bevy_render::{
use bevy_transform::components::Translation;
use std::ops::Range;
/// A point light
#[derive(Properties)]
pub struct Light {
pub color: Color,
@ -27,7 +28,7 @@ impl Default for Light {
#[repr(C)]
#[derive(Clone, Copy)]
pub struct LightRaw {
pub(crate) struct LightRaw {
pub proj: [[f32; 4]; 4],
pub pos: [f32; 4],
pub color: [f32; 4],

View file

@ -1,6 +1,7 @@
use bevy_asset::{self, Handle};
use bevy_render::{color::Color, renderer::RenderResources, shader::ShaderDefs, texture::Texture};
/// A material with "standard" properties used in PBR lighting
#[derive(RenderResources, ShaderDefs)]
pub struct StandardMaterial {
pub albedo: Color,

View file

@ -1,3 +0,0 @@
mod lights_node;
pub use lights_node::*;

View file

@ -1,3 +0,0 @@
mod forward;
pub use forward::*;

View file

@ -1,53 +0,0 @@
use crate::{
material::StandardMaterial,
nodes::LightsNode,
pipelines::{build_forward_pipeline, FORWARD_PIPELINE_HANDLE},
};
use bevy_asset::Assets;
use bevy_ecs::Resources;
use bevy_render::{
pipeline::PipelineDescriptor,
render_graph::{base, AssetRenderResourcesNode, RenderGraph, RenderResourcesNode},
shader::Shader,
};
use bevy_transform::prelude::Transform;
pub mod node {
pub const TRANSFORM: &str = "transform";
pub const STANDARD_MATERIAL: &str = "standard_material";
pub const LIGHTS: &str = "lights";
}
pub mod uniform {
pub const LIGHTS: &str = "Lights";
}
pub trait ForwardPbrRenderGraphBuilder {
fn add_pbr_graph(&mut self, resources: &Resources) -> &mut Self;
}
impl ForwardPbrRenderGraphBuilder for RenderGraph {
fn add_pbr_graph(&mut self, resources: &Resources) -> &mut Self {
self.add_system_node(node::TRANSFORM, RenderResourcesNode::<Transform>::new(true));
self.add_system_node(
node::STANDARD_MATERIAL,
AssetRenderResourcesNode::<StandardMaterial>::new(true),
);
self.add_system_node(node::LIGHTS, LightsNode::new(10));
let mut shaders = resources.get_mut::<Assets<Shader>>().unwrap();
let mut pipelines = resources.get_mut::<Assets<PipelineDescriptor>>().unwrap();
pipelines.set(
FORWARD_PIPELINE_HANDLE,
build_forward_pipeline(&mut shaders),
);
// TODO: replace these with "autowire" groups
self.add_node_edge(node::STANDARD_MATERIAL, base::node::MAIN_PASS)
.unwrap();
self.add_node_edge(node::TRANSFORM, base::node::MAIN_PASS)
.unwrap();
self.add_node_edge(node::LIGHTS, base::node::MAIN_PASS)
.unwrap();
self
}
}

View file

@ -11,7 +11,8 @@ use bevy_render::{
pub const FORWARD_PIPELINE_HANDLE: Handle<PipelineDescriptor> =
Handle::from_u128(131483623140127713893804825450360211204);
pub fn build_forward_pipeline(shaders: &mut Assets<Shader>) -> PipelineDescriptor {
pub(crate) fn build_forward_pipeline(shaders: &mut Assets<Shader>) -> PipelineDescriptor {
PipelineDescriptor {
rasterization_state: Some(RasterizationStateDescriptor {
front_face: FrontFace::Ccw,

View file

@ -13,6 +13,7 @@ use bevy_render::{
};
use bevy_transform::prelude::*;
/// A Render Graph [Node] that write light data from the ECS to GPU buffers
#[derive(Default)]
pub struct LightsNode {
command_queue: CommandQueue,
@ -43,7 +44,7 @@ impl Node for LightsNode {
#[repr(C)]
#[derive(Clone, Copy)]
pub struct LightCount {
struct LightCount {
pub num_lights: [u32; 4],
}
@ -65,6 +66,7 @@ impl SystemNode for LightsNode {
}
}
/// Local "lights node system" state
#[derive(Default)]
pub struct LightsNodeSystemState {
light_buffer: Option<BufferId>,

View file

@ -0,0 +1,50 @@
mod forward_pipeline;
mod lights_node;
pub use forward_pipeline::*;
pub use lights_node::*;
/// the names of pbr graph nodes
pub mod node {
pub const TRANSFORM: &str = "transform";
pub const STANDARD_MATERIAL: &str = "standard_material";
pub const LIGHTS: &str = "lights";
}
/// the names of pbr uniforms
pub mod uniform {
pub const LIGHTS: &str = "Lights";
}
use bevy_asset::Assets;
use bevy_ecs::Resources;
use bevy_render::{
pipeline::PipelineDescriptor,
render_graph::{base, AssetRenderResourcesNode, RenderGraph, RenderResourcesNode},
shader::Shader,
};
use bevy_transform::prelude::Transform;
use crate::prelude::StandardMaterial;
pub(crate) fn add_pbr_graph(graph: &mut RenderGraph, resources: &Resources) {
graph.add_system_node(node::TRANSFORM, RenderResourcesNode::<Transform>::new(true));
graph.add_system_node(
node::STANDARD_MATERIAL,
AssetRenderResourcesNode::<StandardMaterial>::new(true),
);
graph.add_system_node(node::LIGHTS, LightsNode::new(10));
let mut shaders = resources.get_mut::<Assets<Shader>>().unwrap();
let mut pipelines = resources.get_mut::<Assets<PipelineDescriptor>>().unwrap();
pipelines.set(
FORWARD_PIPELINE_HANDLE,
build_forward_pipeline(&mut shaders),
);
// TODO: replace these with "autowire" groups
graph.add_node_edge(node::STANDARD_MATERIAL, base::node::MAIN_PASS)
.unwrap();
graph.add_node_edge(node::TRANSFORM, base::node::MAIN_PASS)
.unwrap();
graph.add_node_edge(node::LIGHTS, base::node::MAIN_PASS)
.unwrap();
}

View file

@ -10,6 +10,7 @@ use bevy_property::Property;
use serde::{Deserialize, Serialize};
use std::ops::{Add, AddAssign, Mul, MulAssign};
/// A RGBA color
#[repr(C)]
#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize, Property)]
pub struct Color {
@ -178,6 +179,7 @@ impl Bytes for ColorSource {
}
}
/// A source of color
pub enum ColorSource {
Color(Color),
Texture(Handle<Texture>),

View file

@ -18,6 +18,7 @@ use bevy_property::Properties;
use std::{any::TypeId, ops::Range, sync::Arc};
use thiserror::Error;
/// A queued command for the renderer
#[derive(Debug, Clone, Eq, PartialEq)]
pub enum RenderCommand {
SetPipeline {
@ -44,6 +45,7 @@ pub enum RenderCommand {
},
}
/// A component that indicates how to draw an entity.
#[derive(Properties)]
pub struct Draw {
pub is_visible: bool,

View file

@ -4,14 +4,12 @@ use crate::{
render_graph::base,
Draw, Mesh,
};
use base::MainPass;
use bevy_asset::Handle;
use bevy_ecs::Bundle;
use bevy_transform::components::{Rotation, Scale, Transform, Translation};
use bevy_property::Properties;
#[derive(Default, Properties)]
pub struct MainPass;
/// A component bundle for "mesh" entities
#[derive(Bundle, Default)]
pub struct MeshComponents {
pub mesh: Handle<Mesh>,
@ -24,6 +22,7 @@ pub struct MeshComponents {
pub scale: Scale,
}
/// A component bundle for "3d camera" entities
#[derive(Bundle)]
pub struct Camera3dComponents {
pub camera: Camera,
@ -52,6 +51,7 @@ impl Default for Camera3dComponents {
}
}
/// A component bundle for "2d camera" entities
#[derive(Bundle)]
pub struct Camera2dComponents {
pub camera: Camera,

View file

@ -27,13 +27,18 @@ pub mod prelude {
}
use crate::prelude::*;
use base::Msaa;
use base::{MainPass, Msaa};
use bevy_app::prelude::*;
use bevy_asset::AddAsset;
use bevy_ecs::{IntoQuerySystem, IntoThreadLocalSystem};
use bevy_type_registry::RegisterType;
use camera::{ActiveCameras, Camera, OrthographicProjection, PerspectiveProjection, VisibleEntities};
use pipeline::{PipelineCompiler, PipelineDescriptor, VertexBufferDescriptors, ShaderSpecialization, PipelineSpecialization, DynamicBinding, PrimitiveTopology};
use camera::{
ActiveCameras, Camera, OrthographicProjection, PerspectiveProjection, VisibleEntities,
};
use pipeline::{
DynamicBinding, PipelineCompiler, PipelineDescriptor, PipelineSpecialization,
PrimitiveTopology, ShaderSpecialization, VertexBufferDescriptors,
};
use render_graph::{
base::{self, BaseRenderGraphBuilder, BaseRenderGraphConfig},
RenderGraph,
@ -42,6 +47,7 @@ use renderer::{AssetRenderResourceBindings, RenderResourceBindings};
use std::ops::Range;
use texture::{HdrTextureLoader, ImageTextureLoader, TextureResourceSystemState};
/// The names of "render" App stages
pub mod stage {
/// Stage where render resources are set up
pub static RENDER_RESOURCE: &str = "render_resource";
@ -53,6 +59,7 @@ pub mod stage {
pub static POST_RENDER: &str = "post_render";
}
/// Adds core render types and systems to an App
pub struct RenderPlugin {
/// configures the "base render graph". If this is not `None`, the "base render graph" will be added
pub base_render_graph_config: Option<BaseRenderGraphConfig>,

View file

@ -7,12 +7,16 @@ use crate::{
LoadOp, Operations, PassDescriptor, RenderPassColorAttachmentDescriptor,
RenderPassDepthStencilAttachmentDescriptor, TextureAttachment,
},
prelude::MainPass,
texture::{Extent3d, TextureDescriptor, TextureDimension, TextureFormat, TextureUsage},
Color,
};
use bevy_property::Properties;
use bevy_window::WindowId;
/// A component that indicates that an entity should be drawn in the "main pass"
#[derive(Default, Properties)]
pub struct MainPass;
pub struct Msaa {
pub samples: u32,
}

View file

@ -2,6 +2,8 @@ use super::ShaderLayout;
use bevy_asset::Handle;
use glsl_to_spirv::compile;
use std::{io::Read, marker::Copy};
/// The stage of a shader
#[derive(Hash, Eq, PartialEq, Copy, Clone, Debug)]
pub enum ShaderStage {
Vertex,
@ -19,7 +21,7 @@ impl Into<glsl_to_spirv::ShaderType> for ShaderStage {
}
}
pub fn glsl_to_spirv(
fn glsl_to_spirv(
glsl_source: &str,
stage: ShaderStage,
shader_defs: Option<&[String]>,
@ -41,6 +43,7 @@ fn bytes_to_words(bytes: &[u8]) -> Vec<u32> {
words
}
/// The full "source" of a shader
#[derive(Clone, Debug, Hash, Eq, PartialEq)]
pub enum ShaderSource {
Spirv(Vec<u32>),
@ -53,11 +56,11 @@ impl ShaderSource {
}
}
/// A shader, as defined by its [ShaderSource] and [ShaderStage]
#[derive(Clone, Debug)]
pub struct Shader {
pub source: ShaderSource,
pub stage: ShaderStage,
// TODO: add "precompile" flag?
}
impl Shader {
@ -98,6 +101,7 @@ impl Shader {
}
}
/// All stages in a shader program
#[derive(Clone, Debug)]
pub struct ShaderStages {
pub vertex: Handle<Shader>,

View file

@ -4,16 +4,19 @@ use crate::{pipeline::RenderPipelines, Texture};
pub use bevy_derive::ShaderDefs;
use bevy_ecs::{Query, Res};
/// Something that can either be "defined" or "not defined". This is used to determine if a "shader def" should be considered "defined"
pub trait ShaderDef {
fn is_defined(&self) -> bool;
}
/// A collection of "shader defs", which define compile time definitions for shaders.
pub trait ShaderDefs {
fn shader_defs_len(&self) -> usize;
fn get_shader_def(&self, index: usize) -> Option<&str>;
fn iter_shader_defs(&self) -> ShaderDefIterator;
}
/// Iterates over all [ShaderDef] items in [ShaderDefs]
pub struct ShaderDefIterator<'a> {
shader_defs: &'a dyn ShaderDefs,
index: usize,
@ -56,6 +59,7 @@ impl ShaderDef for Option<Handle<Texture>> {
}
}
/// Updates [RenderPipelines] with the latest [ShaderDefs]
pub fn shader_defs_system<T>(mut query: Query<(&T, &mut RenderPipelines)>)
where
T: ShaderDefs + Send + Sync + 'static,
@ -73,6 +77,7 @@ where
}
}
/// Clears each [RenderPipelines]' shader defs collection
pub fn clear_shader_defs_system(mut query: Query<&mut RenderPipelines>) {
for mut render_pipelines in &mut query.iter() {
for render_pipeline in render_pipelines.pipelines.iter_mut() {
@ -85,6 +90,7 @@ pub fn clear_shader_defs_system(mut query: Query<&mut RenderPipelines>) {
}
}
/// Updates [RenderPipelines] with the latest [ShaderDefs] from a given asset type
pub fn asset_shader_defs_system<T>(
assets: Res<Assets<T>>,
mut query: Query<(&Handle<T>, &mut RenderPipelines)>,

View file

@ -15,6 +15,7 @@ use spirv_reflect::{
};
use std::collections::HashSet;
/// Defines the memory layout of a shader
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ShaderLayout {
pub bind_groups: Vec<BindGroupDescriptor>,

View file

@ -4,6 +4,7 @@ use bevy_asset::AssetLoader;
use bevy_math::Vec2;
use std::path::Path;
/// Loads HDR textures as Texture assets
#[derive(Clone, Default)]
pub struct HdrTextureLoader;

View file

@ -1,6 +1,7 @@
use super::Texture;
use crate::pipeline::CompareFunction;
/// Describes a sampler
#[derive(Copy, Clone)]
pub struct SamplerDescriptor {
pub address_mode_u: AddressMode,
@ -49,6 +50,7 @@ impl From<&Texture> for SamplerDescriptor {
}
}
/// How edges should be handled in texture addressing.
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
pub enum AddressMode {
ClampToEdge = 0,
@ -62,6 +64,7 @@ impl Default for AddressMode {
}
}
/// Texel mixing mode when sampling between texels.
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
pub enum FilterMode {
Nearest = 0,

View file

@ -1,5 +1,6 @@
use super::{Extent3d, Texture, TextureDimension, TextureFormat, TextureUsage};
/// Describes a texture
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub struct TextureDescriptor {
pub size: Extent3d,

View file

@ -1,5 +1,6 @@
// NOTE: These are currently just copies of the wgpu types, but they might change in the future
/// Dimensions of a particular texture view.
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq, Ord, PartialOrd)]
pub enum TextureViewDimension {
D1,
@ -10,6 +11,7 @@ pub enum TextureViewDimension {
D3,
}
/// Dimensionality of a texture.
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
pub enum TextureDimension {
D1,
@ -25,6 +27,7 @@ pub struct Extent3d {
pub depth: u32,
}
/// Type of data shaders will read from a texture.
#[derive(Copy, Hash, Clone, Debug, Eq, PartialEq, Ord, PartialOrd)]
pub enum TextureComponentType {
Float,
@ -37,6 +40,10 @@ pub struct PixelInfo {
pub num_components: usize,
}
/// Underlying texture data format.
///
/// If there is a conversion in the format (such as srgb -> linear), The conversion listed is for
/// loading from texture in a shader. When writing to the texture, the opposite conversion takes place.
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq, Ord, PartialOrd)]
pub enum TextureFormat {
// Normal 8 bit formats

View file

@ -7,7 +7,8 @@ use bevy_ecs::Bundle;
use bevy_render::{
mesh::Mesh,
pipeline::{DynamicBinding, PipelineSpecialization, RenderPipeline, RenderPipelines},
prelude::{Draw, MainPass},
prelude::Draw,
render_graph::base::MainPass,
};
use bevy_transform::prelude::{Rotation, Scale, Transform, Translation};

View file

@ -3,12 +3,14 @@ use bevy::{
render::{
camera::{ActiveCameras, Camera},
pass::*,
render_graph::{CameraNode, PassNode, RenderGraph, WindowSwapChainNode, WindowTextureNode},
texture::{TextureDescriptor, TextureFormat, TextureUsage},
render_graph::{
base::MainPass, CameraNode, PassNode, RenderGraph, WindowSwapChainNode,
WindowTextureNode,
},
texture::{Extent3d, TextureDescriptor, TextureDimension, TextureFormat, TextureUsage},
},
window::{CreateWindow, WindowDescriptor, WindowId},
};
use bevy_render::texture::{Extent3d, TextureDimension};
/// This example creates a second window and draws a mesh from two different cameras.
fn main() {