diff --git a/Cargo.lock b/Cargo.lock index d6b98a960..9808c7865 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1217,6 +1217,7 @@ dependencies = [ "num-traits", "rayon", "rusttype", + "uuid 1.8.0", ] [[package]] diff --git a/bevy_nannou_draw/Cargo.toml b/bevy_nannou_draw/Cargo.toml index 5dbdbfd02..528b9c756 100644 --- a/bevy_nannou_draw/Cargo.toml +++ b/bevy_nannou_draw/Cargo.toml @@ -10,4 +10,5 @@ nannou_core = { path = "../nannou_core" } rusttype = { version = "0.8", features = ["gpu_cache"] } num-traits = "0.2" bytemuck = "1.15.0" -rayon = "1.10" \ No newline at end of file +rayon = "1.10" +uuid = "1.8" \ No newline at end of file diff --git a/bevy_nannou_draw/src/draw/background.rs b/bevy_nannou_draw/src/draw/background.rs index 15614211f..1f45f725e 100644 --- a/bevy_nannou_draw/src/draw/background.rs +++ b/bevy_nannou_draw/src/draw/background.rs @@ -1,6 +1,5 @@ -use crate::draw::Draw; +use crate::draw::{Draw, DrawCommand}; use bevy::prelude::{Color, Material, World}; -use crate::render::BackgroundColor; /// A type used to update the background colour. pub struct Background<'a, M> @@ -32,10 +31,7 @@ impl<'a, M> Background<'a, M> state.background_color = Some(color.into()); let color = state.background_color.unwrap(); let window = self.draw.window; - state.draw_commands.push(Some(Box::new(move |world: &mut World| { - world.entity_mut(window) - .insert(BackgroundColor(color)); - }))); + state.draw_commands.push(Some(DrawCommand::BackgroundColor(window, color))); } self } diff --git a/bevy_nannou_draw/src/draw/drawing.rs b/bevy_nannou_draw/src/draw/drawing.rs index 4a6e22e99..288cf8ad0 100644 --- a/bevy_nannou_draw/src/draw/drawing.rs +++ b/bevy_nannou_draw/src/draw/drawing.rs @@ -1,15 +1,17 @@ +use std::any::TypeId; use std::marker::PhantomData; use std::sync::{Arc, RwLock}; -use bevy::asset::AsyncWriteExt; +use bevy::asset::{AsyncWriteExt, UntypedAssetId}; use bevy::pbr::{ExtendedMaterial, MaterialExtension}; use bevy::prelude::*; use bevy::render::render_resource::BlendComponent; use lyon::path::PathEvent; use lyon::tessellation::{FillOptions, LineCap, LineJoin, StrokeOptions}; +use uuid::Uuid; use crate::changed::Cd; -use crate::draw::{Draw, DrawContext, DrawRef}; +use crate::draw::{Draw, DrawCommand, DrawContext, DrawRef}; use crate::draw::mesh::MeshExt; use crate::draw::primitive::Primitive; use crate::draw::properties::{ @@ -120,32 +122,8 @@ where // If we are "Owned", that means we mutated our material and so need to // spawn a new entity just for this primitive. DrawRef::Owned(draw) => { - let material = draw.material.clone(); - state.draw_commands.push(Some(Box::new(move |world: &mut World| { - let mut materials = world.resource_mut::>(); - let material = materials.add(material); - let mut meshes = world.resource_mut::>(); - let mesh = meshes.add(Mesh::init()); - - let entity = world.spawn((MaterialMeshBundle { - mesh: mesh.clone(), - material: material.clone(), - ..Default::default() - }, NannouMesh)).id(); - - let mut render = world.get_resource_or_insert_with::(|| { - NannouRender { - mesh: mesh.clone(), - entity: entity, - draw_context: DrawContext::default(), - } - }); - render.mesh = mesh; - render.entity = entity; - - // TODO: reset parent?? How does change detection work here? - // We should probably keep rendering into the same parent material. - }))); + let id = draw.material.clone(); + state.draw_commands.push(Some(DrawCommand::Material(id))); }, DrawRef::Borrowed(_) => (), } @@ -184,13 +162,29 @@ where { self.finish_on_drop = false; let Drawing { ref draw, index, .. } = self; - let material = map(self.draw.material.clone()); + + let state = draw.state.clone(); + let material = state.read().unwrap().materials[&self.draw.material] + .downcast_ref::() + .unwrap() + .clone(); + let new_id = UntypedAssetId::Uuid { + type_id: TypeId::of::(), + uuid: Uuid::new_v4(), + }; + + let material = map(material.clone()); + let mut state = state.write().unwrap(); + state.materials.insert(new_id.clone(), Box::new(material)); + let draw = Draw { state: draw.state.clone(), context: draw.context.clone(), - material, + material: new_id.clone(), window: draw.window, + _material: Default::default(), }; + Drawing { draw: DrawRef::Owned(draw), index, diff --git a/bevy_nannou_draw/src/draw/instanced.rs b/bevy_nannou_draw/src/draw/instanced.rs index 3bf481946..20c649270 100644 --- a/bevy_nannou_draw/src/draw/instanced.rs +++ b/bevy_nannou_draw/src/draw/instanced.rs @@ -3,7 +3,7 @@ use crate::draw::mesh::MeshExt; use crate::draw::primitive::Primitive; use crate::draw::render::{GlyphCache, RenderContext, RenderPrimitive}; -use crate::draw::{Background, Draw, primitive}; +use crate::draw::{Background, Draw, DrawCommand, primitive}; use crate::render::{NannouMesh, NannouRender}; use bevy::{ core_pipeline::core_3d::Transparent3d, @@ -77,59 +77,14 @@ where fn insert_instanced_draw_command(&self, index: usize, data: InstanceMaterialData) { let mut state = self.draw.state.write().unwrap(); - let intermediary_state = state.intermediary_state.clone(); - let theme = state.theme.clone(); - let window = self.draw.window; + let primitive = state.drawing.remove(&index).unwrap(); state .draw_commands - .push(Some(Box::new(move |world: &mut World| { - let mut fill_tessellator = FillTessellator::new(); - let mut stroke_tessellator = StrokeTessellator::new(); - let intermediary_state = intermediary_state.read().unwrap(); - let mut q = world.query::<&crate::Draw>(); - let draw = q.get(world, window).unwrap(); - let primitive = draw.state.write().unwrap().drawing.remove(&index).unwrap(); - - world.resource_scope(|world, mut render: Mut| { - world.resource_scope(|world, mut meshes: Mut>| { - world.resource_scope(|world, mut glyph_cache: Mut| { - let mut mesh = Mesh::init(); - let ctxt = RenderContext { - intermediary_mesh: &intermediary_state.intermediary_mesh, - path_event_buffer: &intermediary_state.path_event_buffer, - path_points_colored_buffer: &intermediary_state - .path_points_colored_buffer, - path_points_textured_buffer: &intermediary_state - .path_points_textured_buffer, - text_buffer: &intermediary_state.text_buffer, - theme: &theme, - transform: &render.draw_context.transform, - fill_tessellator: &mut fill_tessellator, - stroke_tessellator: &mut stroke_tessellator, - glyph_cache: &mut glyph_cache, - // TODO: read from window - output_attachment_size: Vec2::new(100.0, 100.0), - output_attachment_scale_factor: 1.0, - }; - - primitive.render_primitive(ctxt, &mut mesh); - let mesh = mesh.with_removed_attribute(Mesh::ATTRIBUTE_COLOR); - let mesh = meshes.add(mesh); - world.spawn(( - NannouMesh, - mesh, - SpatialBundle::INHERITED_IDENTITY, - data, - NoFrustumCulling, - )); - }); - }); - }); - }))); + .push(Some(DrawCommand::Instanced(primitive, data))); } } -#[derive(Component, Deref)] +#[derive(Component, Deref, Clone, Debug)] pub struct InstanceMaterialData(pub Vec); impl ExtractComponent for InstanceMaterialData { @@ -165,7 +120,7 @@ impl Plugin for InstancingPlugin { } } -#[derive(Clone, Copy, Pod, Zeroable)] +#[derive(Debug, Clone, Copy, Pod, Zeroable)] #[repr(C)] pub struct InstanceData { pub position: Vec3, diff --git a/bevy_nannou_draw/src/draw/mod.rs b/bevy_nannou_draw/src/draw/mod.rs index 77fe7c040..61d929051 100644 --- a/bevy_nannou_draw/src/draw/mod.rs +++ b/bevy_nannou_draw/src/draw/mod.rs @@ -2,9 +2,12 @@ //! //! See the [**Draw** type](./struct.Draw.html) for more details. +use std::any::{Any, TypeId}; +use std::marker::PhantomData; use bevy::ecs::world::Command; use std::ops::{Deref, DerefMut}; use std::sync::{Arc, RwLock}; +use bevy::asset::UntypedAssetId; pub use self::background::Background; pub use self::drawing::{Drawing, DrawingContext}; @@ -20,7 +23,8 @@ use bevy::render::render_resource::BlendState; use bevy::utils::{HashMap, HashSet}; use lyon::path::PathEvent; use lyon::tessellation::{FillTessellator, StrokeTessellator}; -use crate::draw::instanced::Instanced; +use uuid::Uuid; +use crate::draw::instanced::{Instanced, InstanceMaterialData}; pub mod background; mod drawing; @@ -64,9 +68,11 @@ where /// The current context of this **Draw** instance. context: DrawContext, /// The current material of this **Draw** instance. - material: M, + material: UntypedAssetId, /// The window to which this **Draw** instance is associated. - window: Entity + pub(crate) window: Entity, + /// The type of material used by this **Draw** instance. + _material: PhantomData, } #[derive(Clone)] @@ -107,6 +113,26 @@ impl Default for DrawContext { } } + +/// Commands generated by drawings. +/// +/// During rendering, the list of **DrawCommand**s are converted into a list of **RenderCommands** +/// that are directly associated with encodable render pass commands. +#[derive(Clone, Debug)] +pub enum DrawCommand { + /// Draw a primitive. + Primitive(Primitive), + /// Draw an instanced primitive + Instanced(Primitive, InstanceMaterialData), + /// A change in the rendering context occurred. + Context(DrawContext), + /// A change in the material occurred. + Material(UntypedAssetId), + /// A change in the background color occurred. + BackgroundColor(Entity, Color), +} + + /// The inner state of the **Draw** type. /// /// The **Draw** type stores its **State** behind a **RefCell** - a type used for moving mutability @@ -115,6 +141,8 @@ impl Default for DrawContext { /// drawing stuff. In order to be friendlier to new users, we want to avoid requiring them to think /// about mutability and instead focus on creativity. Rust-lang nuances can come later. pub struct State { + /// The last material used to draw an image, used to detect changes and emit commands for them. + last_material: Option, /// The last context used to draw an image, used to detect changes and emit commands for them. last_draw_context: Option, /// If `Some`, the **Draw** should first clear the frame's texture with the given color. @@ -123,16 +151,18 @@ pub struct State { /// /// Keys are indices into the `draw_commands` Vec. drawing: HashMap, + /// A map of all type erased materials used by the draw. + pub(crate) materials: HashMap>, + /// A list of indices of primitives that are being drawn as instances and should not be drawn instanced: HashSet, /// The list of recorded draw commands. /// /// An element may be `None` if it is a primitive in the process of being drawn. - pub(crate) draw_commands: Vec>>, + pub(crate) draw_commands: Vec>, /// State made accessible via the `DrawingContext`. pub(crate) intermediary_state: Arc>, /// The theme containing default values. pub(crate) theme: Theme, - material_changed: bool, } /// State made accessible via the `DrawingContext`. @@ -163,8 +193,11 @@ impl IntermediaryState { impl State { // Resets all state within the `Draw` instance. fn reset(&mut self) { + self.last_material = None; + self.last_draw_context = None; self.background_color = None; self.drawing.clear(); + // self.materials.clear(); self.draw_commands.clear(); self.intermediary_state.write().unwrap().reset(); } @@ -192,40 +225,7 @@ impl State { // Insert the draw primitive command at the given index. fn insert_draw_command(&mut self, index: usize, prim: Primitive) { if let Some(elem) = self.draw_commands.get_mut(index) { - let intermediary_state = self.intermediary_state.clone(); - let theme = self.theme.clone(); - *elem = Some(Box::new(move |world: &mut World| { - let mut fill_tessellator = FillTessellator::new(); - let mut stroke_tessellator = StrokeTessellator::new(); - let intermediary_state = intermediary_state.read().unwrap(); - - world.resource_scope(|world, mut render: Mut| { - world.resource_scope(|world, mut meshes: Mut>| { - let mesh = &render.mesh; - let mesh = meshes.get_mut(mesh).unwrap(); - world.resource_scope(|world, mut glyph_cache: Mut| { - let ctxt = RenderContext { - intermediary_mesh: &intermediary_state.intermediary_mesh, - path_event_buffer: &intermediary_state.path_event_buffer, - path_points_colored_buffer: &intermediary_state.path_points_colored_buffer, - path_points_textured_buffer: &intermediary_state.path_points_textured_buffer, - text_buffer: &intermediary_state.text_buffer, - theme: &theme, - transform: &render.draw_context.transform, - fill_tessellator: &mut fill_tessellator, - stroke_tessellator: &mut stroke_tessellator, - glyph_cache: &mut glyph_cache, - // TODO: read from window - output_attachment_size: Vec2::new(100.0, 100.0), - output_attachment_scale_factor: 1.0, - }; - - let primitive: Primitive = prim.into(); - primitive.render_primitive(ctxt, mesh); - }) - }); - }); - })); + *elem = Some(DrawCommand::Primitive(prim)); } } } @@ -235,20 +235,39 @@ where M: Material + Default, { pub fn new(window: Entity) -> Self { + let mut state = State::default(); + let context = DrawContext::default(); + let material = M::default(); + let material_id = UntypedAssetId::Uuid { + type_id: TypeId::of::(), + uuid: Uuid::new_v4(), + }; + state.materials.insert(material_id, Box::new(material)); + Draw { - state: Default::default(), - context: Default::default(), - material: M::default(), - window + state: Arc::new(RwLock::new(state)), + context, + material: material_id, + window, + _material: PhantomData, } } /// Resets all state within the `Draw` instance. pub fn reset(&mut self) { - self.material = M::default(); self.state.write().unwrap().reset(); } + fn insert_default_material(&self) { + let mut state = self.state.write().unwrap(); + let material = M::default(); + let material_id = UntypedAssetId::Uuid { + type_id: TypeId::of::(), + uuid: Uuid::new_v4(), + }; + state.materials.insert(material_id, Box::new(material)); + } + // Context changes. /// Produce a new **Draw** instance transformed by the given transform matrix. @@ -448,9 +467,18 @@ where context, material, window, + _material: PhantomData, } } + fn clone_material(&self) -> M { + let mut state = self.state.write().unwrap(); + let material = state.materials.get_mut(&self.material).unwrap(); + material.downcast_ref::() + .expect("Expected material to be of the correct type") + .clone() + } + /// Produce a new **Draw** instance with a new material type. pub fn material(&self, material: M2) -> Draw { let mut context = self.context.clone(); @@ -458,11 +486,18 @@ where let context = DrawContext { transform }; let state = self.state.clone(); let window = self.window; + let material_id = UntypedAssetId::Uuid { + type_id: TypeId::of::(), + uuid: Uuid::new_v4(), + }; + state.write().unwrap().materials.insert(material_id, Box::new(material)); + Draw { state, context, - material, + material: material_id, window, + _material: PhantomData, } } @@ -486,54 +521,22 @@ where { let index = { let mut state = self.state.write().unwrap(); - if state.material_changed { - let material = self.material.clone(); + // If drawing with a different context, insert the necessary command to update it. + if state.last_draw_context.as_ref() != Some(&self.context) { state .draw_commands - .push(Some(Box::new(move |world: &mut World| { - let mut materials = world.resource_mut::>(); - let material = materials.add(material); - let mut meshes = world.resource_mut::>(); - let mesh = meshes.add(Mesh::init()); - - let entity = world.spawn((MaterialMeshBundle { - mesh: mesh.clone(), - material: material.clone(), - ..Default::default() - }, NannouMesh)).id(); - - let mut render = world.get_resource_or_insert_with::(|| { - NannouRender { - mesh: mesh.clone(), - entity: entity, - draw_context: DrawContext::default(), - } - }); - render.mesh = mesh; - render.entity = entity; - }))); - - // Reset the material changed flag so that we will re-use the same mesh - // until the material is changed again. - state.material_changed = false; - } else { - // Our material wasn't changed, but we need to check our mesh to see if it was - // changed, as this would indicate that a primitive spawned by this draw instance - // has been drawn with a different material. - // TODO :( + .push(Some(DrawCommand::Context(self.context.clone()))); + state.last_draw_context = Some(self.context.clone()); } - // If drawing with a different context, insert the necessary command to update it. - if state.last_draw_context.as_ref() != Some(&self.context) { - let context = self.context.clone(); + let id = &self.material; + if state.last_material.as_ref() != Some(id) { state .draw_commands - .push(Some(Box::new(move |world: &mut World| { - let mut render = world.resource_mut::(); - render.draw_context = context; - }))); - state.last_draw_context = Some(self.context.clone()); + .push(Some(DrawCommand::Material(id.clone()))); + state.last_material = Some(id.clone()); } + // The primitive will be inserted in the next element. let index = state.draw_commands.len(); let primitive: Primitive = primitive.into(); @@ -618,6 +621,31 @@ where ) -> Drawing<'a, primitive::Texture, M> { self.a(primitive::Texture::new(texture_handle, texture)) } + + /// Finish any drawings-in-progress and produce an iterator draining the inner draw commands + /// and yielding them by value. + pub fn drain_commands(&self) -> impl Iterator { + self.finish_remaining_drawings(); + let cmds = { + let mut state = self.state.write().unwrap(); + let empty = Vec::with_capacity(state.draw_commands.len()); + std::mem::replace(&mut state.draw_commands, empty) + }; + cmds.into_iter().filter_map(|opt| opt) + } + + /// Drain any remaining `drawing`s and convert them to draw commands. + pub fn finish_remaining_drawings(&self) { + let mut state = self.state.write().unwrap(); + let id = &self.material; + if state.last_material.as_ref() != Some(id) { + state + .draw_commands + .push(Some(DrawCommand::Material(id.clone()))); + state.last_material = Some(id.clone()); + } + state.finish_remaining_drawings() + } } impl Draw { @@ -629,7 +657,7 @@ impl Draw { /// Produce a new **Draw** instance that will draw with the given color blend descriptor. pub fn color_blend(&self, blend_descriptor: wgpu::BlendComponent) -> Self { - let mut mat = self.material.clone(); + let mut mat = self.clone_material().clone(); mat.extension.blend = Some(BlendState { color: blend_descriptor, alpha: blend_descriptor, @@ -644,7 +672,7 @@ impl Draw { /// Produce a new **Draw** instance that will use the given polygon mode. pub fn polygon_mode(&self, polygon_mode: wgpu::PolygonMode) -> Self { - let mut mat = self.material.clone(); + let mut mat = self.clone_material().clone(); mat.extension.polygon_mode = polygon_mode; self.material(mat) } @@ -669,6 +697,7 @@ impl Default for IntermediaryState { impl Default for State { fn default() -> Self { + let last_material = None; let last_draw_context = None; let background_color = Default::default(); let draw_commands = Default::default(); @@ -676,14 +705,15 @@ impl Default for State { let intermediary_state = Arc::new(Default::default()); let theme = Default::default(); State { + last_material, last_draw_context, draw_commands, drawing, intermediary_state, theme, background_color, - material_changed: true, instanced: Default::default(), + materials: Default::default(), } } } diff --git a/bevy_nannou_draw/src/render.rs b/bevy_nannou_draw/src/render.rs index 61d035c8a..7973ce7fe 100644 --- a/bevy_nannou_draw/src/render.rs +++ b/bevy_nannou_draw/src/render.rs @@ -1,6 +1,8 @@ +use bevy::asset::UntypedAssetId; use bevy::pbr::{ ExtendedMaterial, MaterialExtension, MaterialExtensionKey, MaterialExtensionPipeline, }; +use std::any::TypeId; use std::ops::{Deref, DerefMut}; use bevy::prelude::*; @@ -9,17 +11,21 @@ use bevy::render::extract_component::{ExtractComponent, ExtractComponentPlugin}; use bevy::render::extract_resource::{ExtractResource, ExtractResourcePlugin}; use bevy::render::mesh::MeshVertexBufferLayoutRef; use bevy::render::render_resource as wgpu; -use bevy::render::render_resource::{AsBindGroup, BlendComponent, BlendState, PolygonMode, RenderPipelineDescriptor, ShaderRef, SpecializedMeshPipelineError}; +use bevy::render::render_resource::{ + AsBindGroup, BlendComponent, BlendState, PolygonMode, RenderPipelineDescriptor, ShaderRef, + SpecializedMeshPipelineError, +}; +use bevy::render::view::RenderLayers; use bevy::window::WindowRef; use lyon::lyon_tessellation::{FillTessellator, StrokeTessellator}; +use crate::draw::instanced::InstancingPlugin; use crate::draw::mesh::MeshExt; use crate::draw::primitive::Primitive; use crate::draw::render::{GlyphCache, RenderContext, RenderPrimitive}; -use crate::draw::{DrawContext}; -use nannou_core::math::map_range; +use crate::draw::{DrawCommand, DrawContext}; use crate::{draw, Draw}; -use crate::draw::instanced::InstancingPlugin; +use nannou_core::math::map_range; pub struct NannouRenderPlugin; @@ -29,12 +35,27 @@ impl Plugin for NannouRenderPlugin { .add_plugins(( ExtractComponentPlugin::::default(), MaterialPlugin::::default(), - InstancingPlugin + // InstancingPlugin, )) .add_plugins(ExtractResourcePlugin::::default()) .insert_resource(GlyphCache::new([1024; 2], 0.1, 0.1)) - .add_systems(Update, (texture_event_handler, update_background_color)) - .add_systems(PostUpdate, update_draw_mesh); + .add_systems(Update, (texture_event_handler)) + .add_systems( + PostUpdate, + ( + update_draw_mesh, + update_material::, + print_all_components, + ) + .chain(), + ); + } +} + +fn print_all_components(world: &mut World) { + let mut mesh_query = world.query::<(Entity, &NannouMesh)>(); + for (entity, _) in mesh_query.iter(world) { + // info!("Found a mesh! {:#?}", world.inspect_entity(entity)); } } @@ -66,7 +87,7 @@ impl From<&NannouMaterial) -> Self { Self { polygon_mode: material.polygon_mode, - blend: material.blend + blend: material.blend, } } } @@ -108,9 +129,6 @@ impl MaterialExtension for Nanno } } -#[derive(Component)] -pub struct BackgroundColor(pub Color); - #[derive(Resource, Deref, DerefMut, ExtractResource, Clone)] pub struct DefaultTextureHandle(Handle); @@ -146,36 +164,117 @@ fn setup_default_texture(mut commands: Commands, mut images: ResMut, - draw_q: Query<(Entity, &BackgroundColor)>, -) { - for (entity, bg_color) in draw_q.iter() { - for (mut camera) in cameras_q.iter_mut() { - if let RenderTarget::Window(WindowRef::Entity(window_target)) = camera.target { - if window_target == entity { - camera.clear_color = ClearColorConfig::Custom(bg_color.0); - } +#[derive(Component, Deref)] +pub struct UntypedMaterialId(UntypedAssetId); + +fn update_material( + draw_q: Query<&Draw>, + mut commands: Commands, + mut materials: ResMut>, + mut materials_q: Query<(Entity, &UntypedMaterialId)>, +) where + M: Material, +{ + for draw in draw_q.iter() { + let state = draw.state.write().unwrap(); + state.materials.iter().for_each(|(id, material)| { + if id.type_id() == TypeId::of::() { + let material = material.downcast_ref::().unwrap(); + materials.insert(id.typed(), material.clone()); } + }); + } + + for (entity, UntypedMaterialId(id)) in materials_q.iter() { + if id.type_id() == TypeId::of::() { + commands + .entity(entity) + .insert(Handle::Weak(id.typed::())); } } } - fn update_draw_mesh( - world: &mut World, + mut commands: Commands, + draw_q: Query<&Draw>, + mut cameras_q: Query<(&mut Camera, &RenderLayers)>, + windows: Query<&Window>, + mut glyph_cache: ResMut, + mut meshes: ResMut>, ) { - let mut draw_q = world.query::<&Draw>(); - let draw_commands = draw_q.iter(world).map(|draw| { - let mut state = draw.state.write().unwrap(); - std::mem::take(&mut state.draw_commands) - }) - .collect::>(); - - for cmds in draw_commands { - for cmd in cmds { - if let Some(cmd) = cmd { - cmd(world); + for draw in draw_q.iter() { + let (mut window_camera, window_layers) = cameras_q + .iter_mut() + .find(|(camera, _)| { + if let RenderTarget::Window(WindowRef::Entity(window)) = camera.target { + if window == draw.window { + return true; + } + } + + false + }) + .unwrap(); + let window = windows.get(draw.window).unwrap(); + + let mut fill_tessellator = FillTessellator::new(); + let mut stroke_tessellator = StrokeTessellator::new(); + + let mut mesh = meshes.add(Mesh::init()); + let mut curr_ctx: DrawContext = Default::default(); + + let draw_cmds = draw.drain_commands(); + let mut draw_state = draw.state.read().unwrap(); + let intermediary_state = draw_state.intermediary_state.read().unwrap(); + + for cmd in draw_cmds { + match cmd { + DrawCommand::Primitive(prim) => { + // Info required during rendering. + let ctxt = RenderContext { + intermediary_mesh: &intermediary_state.intermediary_mesh, + path_event_buffer: &intermediary_state.path_event_buffer, + path_points_colored_buffer: &intermediary_state.path_points_colored_buffer, + path_points_textured_buffer: &intermediary_state + .path_points_textured_buffer, + text_buffer: &intermediary_state.text_buffer, + theme: &draw_state.theme, + transform: &curr_ctx.transform, + fill_tessellator: &mut fill_tessellator, + stroke_tessellator: &mut stroke_tessellator, + glyph_cache: &mut glyph_cache, + output_attachment_size: Vec2::new(window.width(), window.height()), + output_attachment_scale_factor: window.scale_factor(), + }; + + // Render the primitive. + let mut mesh = meshes.get_mut(&mesh).unwrap(); + let render = prim.render_primitive(ctxt, &mut mesh); + // TODO ignore return value and set textures on the material directly + } + DrawCommand::Instanced(prim, instance_data) => {} + DrawCommand::Context(ctx) => { + curr_ctx = ctx; + } + DrawCommand::Material(mat_id) => { + info!("Material: {:#?}", mat_id); + // We switched materials, so start rendering into a new mesh + mesh = meshes.add(Mesh::init()); + commands.spawn(( + UntypedMaterialId(mat_id), + mesh.clone(), + Transform::default(), + GlobalTransform::default(), + Visibility::default(), + InheritedVisibility::default(), + ViewVisibility::default(), + NannouMesh, + window_layers.clone(), + )); + } + DrawCommand::BackgroundColor(window, color) => { + window_camera.clear_color = ClearColorConfig::Custom(color); + } } } } diff --git a/examples/draw/draw.rs b/examples/draw/draw.rs index bd84dc095..727a6bf9d 100644 --- a/examples/draw/draw.rs +++ b/examples/draw/draw.rs @@ -1,4 +1,3 @@ -use nannou::prelude::draw::instanced::InstanceData; use nannou::prelude::*; fn main() { @@ -9,25 +8,7 @@ fn view(app: &App) { // Begin drawing let draw = app.draw(); - // Clear the background to blue. - draw.background().color(CORNFLOWER_BLUE); - - let instances = (-100..100) - .into_iter() - .map(|x| x as f32 / 10.0) - .flat_map(|x| (-100..100).into_iter().map(move |y| (x, y as f32 / 10.0))) - .collect::>(); - - draw.instanced() - .with(draw.ellipse(), instances, |(i, j)| { - InstanceData { - position: Vec3::new( - *i * 100.0 / 5.0, - *j * 100.0 / 5.0, - *i / 10.0, - ), - scale: [i / 10.0;4], - color: LinearRgba::from(Color::hsla(i / 100.0 * 360.0, *j, 0.5, 1.0)).to_f32_array(), - } - }); + draw.tri() + .width(100.0) + .color(RED); } diff --git a/nannou/src/window.rs b/nannou/src/window.rs index 7c17b9fd8..a731b17ee 100644 --- a/nannou/src/window.rs +++ b/nannou/src/window.rs @@ -12,6 +12,7 @@ use bevy::core_pipeline::tonemapping::Tonemapping; use bevy::input::mouse::MouseWheel; use bevy::prelude::*; use bevy::render::camera::{RenderTarget, ScalingMode}; +use bevy::render::view::RenderLayers; use bevy::window::{PrimaryWindow, WindowLevel, WindowRef}; use bevy_nannou::prelude::MonitorSelection; @@ -400,6 +401,8 @@ where .into(), ..Default::default() }, + // TODO: unique RL per camera + RenderLayers::layer(5), NannouCamera, ));