diff --git a/Cargo.toml b/Cargo.toml index 40233f7569..6f75f0fc48 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,7 +6,7 @@ edition = "2018" [features] default = ["headless", "wgpu", "winit"] -headless = ["asset", "type_registry", "core", "derive", "diagnostic", "gltf", "input", "pbr", "property", "render", "scene", "text", "transform", "ui", "window"] +headless = ["asset", "type_registry", "core", "derive", "diagnostic", "gltf", "input", "pbr", "property", "render", "scene", "sprite", "text", "transform", "ui", "window"] asset = ["bevy_asset"] core = ["bevy_core"] type_registry = ["bevy_type_registry"] @@ -18,6 +18,7 @@ pbr = ["bevy_pbr"] property = ["bevy_property"] render = ["bevy_render"] scene = ["bevy_scene"] +sprite = ["bevy_sprite"] text = ["bevy_text"] transform = ["bevy_transform"] ui = ["bevy_ui"] @@ -50,6 +51,7 @@ bevy_pbr = { path = "crates/bevy_pbr", optional = true } bevy_property = { path = "crates/bevy_property", optional = true } bevy_render = { path = "crates/bevy_render", optional = true } bevy_scene = { path = "crates/bevy_scene", optional = true } +bevy_sprite = { path = "crates/bevy_sprite", optional = true } bevy_transform = { path = "crates/bevy_transform", optional = true } bevy_text = { path = "crates/bevy_text", optional = true } bevy_ui = { path = "crates/bevy_ui", optional = true } diff --git a/crates/bevy_pbr/src/forward_pbr_render_graph.rs b/crates/bevy_pbr/src/forward_pbr_render_graph.rs index 084f1a3a76..263600a4e5 100644 --- a/crates/bevy_pbr/src/forward_pbr_render_graph.rs +++ b/crates/bevy_pbr/src/forward_pbr_render_graph.rs @@ -19,6 +19,10 @@ pub mod node { 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; } diff --git a/crates/bevy_pbr/src/light.rs b/crates/bevy_pbr/src/light.rs index a3f1dd0cf0..da3006da68 100644 --- a/crates/bevy_pbr/src/light.rs +++ b/crates/bevy_pbr/src/light.rs @@ -1,4 +1,4 @@ -use bevy_render::{Color, PerspectiveCamera, CameraProjection}; +use bevy_render::{Color, PerspectiveProjection, CameraProjection}; use bevy_transform::components::Translation; use bevy_property::Properties; use glam::Mat4; @@ -32,7 +32,7 @@ pub struct LightRaw { impl LightRaw { pub fn from(light: &Light, transform: &Mat4, translation: &Translation) -> LightRaw { - let perspective = PerspectiveCamera { + let perspective = PerspectiveProjection { fov: light.fov, aspect_ratio: 1.0, near: light.depth.start, diff --git a/crates/bevy_pbr/src/nodes/lights_node.rs b/crates/bevy_pbr/src/nodes/lights_node.rs index 9c4980c69e..5d57d295ae 100644 --- a/crates/bevy_pbr/src/nodes/lights_node.rs +++ b/crates/bevy_pbr/src/nodes/lights_node.rs @@ -1,5 +1,4 @@ use bevy_render::{ - base_render_graph, render_graph::{CommandQueue, Node, ResourceSlots, SystemNode}, render_resource::{ BufferInfo, BufferUsage, RenderResourceAssignment, RenderResourceAssignments, @@ -7,7 +6,10 @@ use bevy_render::{ renderer::{RenderContext, RenderResources}, }; -use crate::light::{Light, LightRaw}; +use crate::{ + light::{Light, LightRaw}, + uniform, +}; use bevy_transform::prelude::*; use legion::prelude::*; use zerocopy::AsBytes; @@ -77,7 +79,7 @@ impl SystemNode for LightsNode { ..Default::default() }); render_resource_assignments.set( - base_render_graph::uniform::LIGHTS, + uniform::LIGHTS, RenderResourceAssignment::Buffer { resource: buffer, range: 0..light_uniform_size as u64, diff --git a/crates/bevy_render/src/base_render_graph/mod.rs b/crates/bevy_render/src/base_render_graph/mod.rs index ffedb0568f..43d88e2eeb 100644 --- a/crates/bevy_render/src/base_render_graph/mod.rs +++ b/crates/bevy_render/src/base_render_graph/mod.rs @@ -41,7 +41,6 @@ pub mod node { pub mod uniform { pub const CAMERA: &str = "Camera"; pub const CAMERA2D: &str = "Camera2d"; - pub const LIGHTS: &str = "Lights"; } impl Default for BaseRenderGraphConfig { diff --git a/crates/bevy_render/src/camera.rs b/crates/bevy_render/src/camera.rs deleted file mode 100644 index f95df2274d..0000000000 --- a/crates/bevy_render/src/camera.rs +++ /dev/null @@ -1,103 +0,0 @@ -use bevy_app::{Events, GetEventReader}; -use bevy_property::Properties; -use bevy_window::WindowResized; -use glam::Mat4; -use legion::{prelude::*, storage::Component}; - -#[derive(Debug, Clone, Properties)] -pub struct OrthographicCamera { - pub left: f32, - pub right: f32, - pub bottom: f32, - pub top: f32, - pub near: f32, - pub far: f32, -} - -impl CameraProjection for OrthographicCamera { - fn get_view_matrix(&self) -> Mat4 { - let projection = Mat4::orthographic_rh_gl( - self.left, - self.right, - self.bottom, - self.top, - self.near, - self.far, - ); - projection - } - fn update(&mut self, width: usize, height: usize) { - self.right = width as f32; - self.top = height as f32; - } -} - -impl Default for OrthographicCamera { - fn default() -> Self { - OrthographicCamera { - left: 0.0, - right: 0.0, - bottom: 0.0, - top: 0.0, - near: 0.0, - far: 1.0, - } - } -} - -pub trait CameraProjection { - fn get_view_matrix(&self) -> Mat4; - fn update(&mut self, width: usize, height: usize); -} - -#[derive(Debug, Clone, Properties)] -pub struct PerspectiveCamera { - pub fov: f32, - pub aspect_ratio: f32, - pub near: f32, - pub far: f32, -} - -impl CameraProjection for PerspectiveCamera { - fn get_view_matrix(&self) -> Mat4 { - let projection = Mat4::perspective_rh_gl(self.fov, self.aspect_ratio, self.near, self.far); - projection - } - fn update(&mut self, width: usize, height: usize) { - self.aspect_ratio = width as f32 / height as f32; - } -} - -impl Default for PerspectiveCamera { - fn default() -> Self { - PerspectiveCamera { - fov: std::f32::consts::PI / 4.0, - near: 1.0, - far: 1000.0, - aspect_ratio: 1.0, - } - } -} - -#[derive(Default, Debug, Properties)] -pub struct Camera { - pub view_matrix: Mat4, - pub name: Option, -} - -pub fn camera_system(resources: &mut Resources) -> Box { - let mut window_resized_event_reader = resources.get_event_reader::(); - (move |world: &mut SubWorld, - window_resized_events: Res>, - query: &mut Query<(Write, Write)>| { - let primary_window_resized_event = window_resized_event_reader - .find_latest(&window_resized_events, |event| event.is_primary); - if let Some(primary_window_resized_event) = primary_window_resized_event { - for (mut camera, mut camera_projection) in query.iter_mut(world) { - camera_projection.update(primary_window_resized_event.width, primary_window_resized_event.height); - camera.view_matrix = camera_projection.get_view_matrix(); - } - } - }) - .system() -} \ No newline at end of file diff --git a/crates/bevy_render/src/camera/camera.rs b/crates/bevy_render/src/camera/camera.rs new file mode 100644 index 0000000000..3c48f61b69 --- /dev/null +++ b/crates/bevy_render/src/camera/camera.rs @@ -0,0 +1,34 @@ +use crate::CameraProjection; +use bevy_app::{Events, GetEventReader}; +use bevy_property::Properties; +use bevy_window::WindowResized; +use glam::Mat4; +use legion::{prelude::*, storage::Component}; + +#[derive(Default, Debug, Properties)] +pub struct Camera { + pub view_matrix: Mat4, + pub name: Option, +} + +pub fn camera_system( + resources: &mut Resources, +) -> Box { + let mut window_resized_event_reader = resources.get_event_reader::(); + (move |world: &mut SubWorld, + window_resized_events: Res>, + query: &mut Query<(Write, Write)>| { + let primary_window_resized_event = window_resized_event_reader + .find_latest(&window_resized_events, |event| event.is_primary); + if let Some(primary_window_resized_event) = primary_window_resized_event { + for (mut camera, mut camera_projection) in query.iter_mut(world) { + camera_projection.update( + primary_window_resized_event.width, + primary_window_resized_event.height, + ); + camera.view_matrix = camera_projection.get_view_matrix(); + } + } + }) + .system() +} diff --git a/crates/bevy_render/src/camera/mod.rs b/crates/bevy_render/src/camera/mod.rs new file mode 100644 index 0000000000..12ca100d72 --- /dev/null +++ b/crates/bevy_render/src/camera/mod.rs @@ -0,0 +1,5 @@ +mod camera; +mod projection; + +pub use camera::*; +pub use projection::*; \ No newline at end of file diff --git a/crates/bevy_render/src/camera/projection.rs b/crates/bevy_render/src/camera/projection.rs new file mode 100644 index 0000000000..2da70c253c --- /dev/null +++ b/crates/bevy_render/src/camera/projection.rs @@ -0,0 +1,100 @@ +use bevy_property::{Properties, Property}; +use glam::Mat4; +use serde::{Deserialize, Serialize}; + +pub trait CameraProjection { + fn get_view_matrix(&self) -> Mat4; + fn update(&mut self, width: usize, height: usize); +} + +#[derive(Debug, Clone, Properties)] +pub struct PerspectiveProjection { + pub fov: f32, + pub aspect_ratio: f32, + pub near: f32, + pub far: f32, +} + +impl CameraProjection for PerspectiveProjection { + fn get_view_matrix(&self) -> Mat4 { + let projection = Mat4::perspective_rh_gl(self.fov, self.aspect_ratio, self.near, self.far); + projection + } + fn update(&mut self, width: usize, height: usize) { + self.aspect_ratio = width as f32 / height as f32; + } +} + +impl Default for PerspectiveProjection { + fn default() -> Self { + PerspectiveProjection { + fov: std::f32::consts::PI / 4.0, + near: 1.0, + far: 1000.0, + aspect_ratio: 1.0, + } + } +} + +#[derive(Debug, Clone, Property, Serialize, Deserialize)] +pub enum WindowOrigin { + Center, + BottomLeft, +} + +#[derive(Debug, Clone, Properties)] +pub struct OrthographicProjection { + pub left: f32, + pub right: f32, + pub bottom: f32, + pub top: f32, + pub near: f32, + pub far: f32, + pub window_origin: WindowOrigin, +} + +impl CameraProjection for OrthographicProjection { + fn get_view_matrix(&self) -> Mat4 { + let projection = Mat4::orthographic_rh_gl( + self.left, + self.right, + self.bottom, + self.top, + self.near, + self.far, + ); + projection + } + fn update(&mut self, width: usize, height: usize) { + match self.window_origin { + WindowOrigin::Center => { + let half_width = width as f32 / 2.0; + let half_height = height as f32 / 2.0; + self.left = -half_width; + self.right = half_width; + self.top = half_height; + self.bottom = -half_height; + } + WindowOrigin::BottomLeft => { + self.left = 0.0; + self.right = width as f32; + self.top = height as f32; + self.bottom = 0.0; + } + } + } +} + +impl Default for OrthographicProjection { + fn default() -> Self { + OrthographicProjection { + left: 0.0, + right: 0.0, + bottom: 0.0, + top: 0.0, + near: 0.0, + far: 1.0, + window_origin: WindowOrigin::Center, + } + } +} diff --git a/crates/bevy_render/src/entity.rs b/crates/bevy_render/src/entity.rs index 5ae9aac7f9..60313a73db 100644 --- a/crates/bevy_render/src/entity.rs +++ b/crates/bevy_render/src/entity.rs @@ -1,4 +1,4 @@ -use crate::{mesh::Mesh, Camera, Renderable, OrthographicCamera, PerspectiveCamera, base_render_graph}; +use crate::{mesh::Mesh, Camera, Renderable, OrthographicProjection, PerspectiveProjection, base_render_graph}; use bevy_asset::Handle; use bevy_derive::EntityArchetype; use bevy_transform::components::{LocalToWorld, Rotation, Scale, Translation}; @@ -17,7 +17,7 @@ pub struct MeshMaterialEntity { #[derive(EntityArchetype)] pub struct PerspectiveCameraEntity { pub camera: Camera, - pub perspective_camera: PerspectiveCamera, + pub perspective_projection: PerspectiveProjection, pub local_to_world: LocalToWorld, } @@ -28,7 +28,7 @@ impl Default for PerspectiveCameraEntity { name: Some(base_render_graph::uniform::CAMERA.to_string()), ..Default::default() }, - perspective_camera: Default::default(), + perspective_projection: Default::default(), local_to_world: Default::default(), } } @@ -38,8 +38,10 @@ impl Default for PerspectiveCameraEntity { #[derive(EntityArchetype)] pub struct OrthographicCameraEntity { pub camera: Camera, - pub orthographic_camera: OrthographicCamera, + pub orthographic_projection: OrthographicProjection, pub local_to_world: LocalToWorld, + pub translation: Translation, + pub rotation: Rotation, } impl OrthographicCameraEntity { @@ -49,8 +51,10 @@ impl OrthographicCameraEntity { name: Some("UiCamera".to_string()), ..Default::default() }, - orthographic_camera: Default::default(), + orthographic_projection: Default::default(), local_to_world: Default::default(), + translation: Default::default(), + rotation: Default::default(), } } } @@ -62,8 +66,10 @@ impl Default for OrthographicCameraEntity { name: Some(base_render_graph::uniform::CAMERA2D.to_string()), ..Default::default() }, - orthographic_camera: Default::default(), + orthographic_projection: Default::default(), local_to_world: Default::default(), + translation: Default::default(), + rotation: Default::default(), } } diff --git a/crates/bevy_render/src/lib.rs b/crates/bevy_render/src/lib.rs index bea1a6db5f..5590415dfc 100644 --- a/crates/bevy_render/src/lib.rs +++ b/crates/bevy_render/src/lib.rs @@ -76,8 +76,8 @@ impl AppPlugin for RenderPlugin { .add_asset::() .add_asset_loader::() .register_component::() - .register_component::() - .register_component::() + .register_component::() + .register_component::() .register_component::() .register_property_type::() .register_property_type::>() @@ -90,8 +90,8 @@ impl AppPlugin for RenderPlugin { .init_resource::() .init_resource::() .add_system(entity_render_resource_assignments_system()) - .init_system_to_stage(stage::POST_UPDATE, camera::camera_system::) - .init_system_to_stage(stage::POST_UPDATE, camera::camera_system::) + .init_system_to_stage(stage::POST_UPDATE, camera::camera_system::) + .init_system_to_stage(stage::POST_UPDATE, camera::camera_system::) .add_system_to_stage( stage::PRE_UPDATE, EntitiesWaitingForAssets::clear_system.system(), diff --git a/crates/bevy_sprite/Cargo.toml b/crates/bevy_sprite/Cargo.toml new file mode 100644 index 0000000000..d9c38e2dd2 --- /dev/null +++ b/crates/bevy_sprite/Cargo.toml @@ -0,0 +1,18 @@ +[package] +name = "bevy_sprite" +version = "0.1.0" +authors = ["Carter Anderson "] +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +bevy_app = { path = "../bevy_app" } +bevy_core = { path = "../bevy_core" } +bevy_asset = { path = "../bevy_asset" } +bevy_type_registry = { path = "../bevy_type_registry" } +bevy_derive = { path = "../bevy_derive" } +bevy_render = { path = "../bevy_render" } +glam = { path = "../bevy_glam" } +legion = { path = "../bevy_legion", features = ["serialize"] } +zerocopy = "0.3.0" \ No newline at end of file diff --git a/crates/bevy_ui/src/color_material.rs b/crates/bevy_sprite/src/color_material.rs similarity index 100% rename from crates/bevy_ui/src/color_material.rs rename to crates/bevy_sprite/src/color_material.rs diff --git a/crates/bevy_sprite/src/entity.rs b/crates/bevy_sprite/src/entity.rs new file mode 100644 index 0000000000..36ce79c9a7 --- /dev/null +++ b/crates/bevy_sprite/src/entity.rs @@ -0,0 +1,30 @@ +use crate::{ + render::SPRITE_PIPELINE_HANDLE, sprite::Sprite, ColorMaterial, Rect, QUAD_HANDLE, +}; +use bevy_asset::Handle; +use bevy_derive::EntityArchetype; +use bevy_render::{mesh::Mesh, Renderable}; + +#[derive(EntityArchetype)] +pub struct SpriteEntity { + pub sprite: Sprite, + pub rect: Rect, + pub mesh: Handle, // TODO: maybe abstract this out + pub material: Handle, + pub renderable: Renderable, +} + +impl Default for SpriteEntity { + fn default() -> Self { + SpriteEntity { + sprite: Default::default(), + rect: Default::default(), + mesh: QUAD_HANDLE, + material: Default::default(), + renderable: Renderable { + pipelines: vec![SPRITE_PIPELINE_HANDLE], + ..Default::default() + }, + } + } +} diff --git a/crates/bevy_sprite/src/lib.rs b/crates/bevy_sprite/src/lib.rs new file mode 100644 index 0000000000..840fd443b0 --- /dev/null +++ b/crates/bevy_sprite/src/lib.rs @@ -0,0 +1,52 @@ +mod color_material; +pub mod entity; +mod rect; +mod render; +mod sprite; + +pub use color_material::*; +pub use rect::*; +pub use render::*; +pub use sprite::*; + +use bevy_app::{stage, AppBuilder, AppPlugin}; +use bevy_asset::{AddAsset, Assets, Handle}; +use bevy_render::{ + mesh::{shape::Quad, Mesh}, + render_graph::RenderGraph, + shader::asset_shader_def_system, +}; +use glam::Vec2; +use legion::prelude::IntoSystem; +use sprite::sprite_system; + +#[derive(Default)] +pub struct SpritePlugin; + +pub const QUAD_HANDLE: Handle = Handle::from_u128(142404619811301375266013514540294236421); + +impl AppPlugin for SpritePlugin { + fn build(&self, app: &mut AppBuilder) { + app.add_asset::() + .add_system_to_stage(stage::POST_UPDATE, sprite_system()) + .add_system_to_stage( + stage::POST_UPDATE, + asset_shader_def_system::.system(), + ); + + let resources = app.resources(); + let mut render_graph = resources.get_mut::().unwrap(); + render_graph.add_sprite_graph(resources); + + let mut meshes = resources.get_mut::>().unwrap(); + meshes.set( + QUAD_HANDLE, + Mesh::from(Quad { + size: Vec2::new(1.0, 1.0), + }), + ); + + let mut color_materials = resources.get_mut::>().unwrap(); + color_materials.add_default(ColorMaterial::default()); + } +} diff --git a/crates/bevy_ui/src/rect.rs b/crates/bevy_sprite/src/rect.rs similarity index 100% rename from crates/bevy_ui/src/rect.rs rename to crates/bevy_sprite/src/rect.rs diff --git a/crates/bevy_sprite/src/render/mod.rs b/crates/bevy_sprite/src/render/mod.rs new file mode 100644 index 0000000000..05d71f98a6 --- /dev/null +++ b/crates/bevy_sprite/src/render/mod.rs @@ -0,0 +1,98 @@ +use crate::{ColorMaterial, Rect}; +use bevy_asset::{Assets, Handle}; +use bevy_render::{ + base_render_graph, + draw_target::AssignedMeshesDrawTarget, + pipeline::{state_descriptors::*, PipelineDescriptor}, + render_graph::{ + nodes::{AssetUniformNode, PassNode, UniformNode}, + RenderGraph, + }, + shader::{Shader, ShaderStage, ShaderStages}, + texture::TextureFormat, +}; +use legion::prelude::Resources; + +pub const SPRITE_PIPELINE_HANDLE: Handle = + Handle::from_u128(278534784033876544639935131272264723170); + +pub fn build_sprite_pipeline(shaders: &mut Assets) -> PipelineDescriptor { + PipelineDescriptor { + rasterization_state: Some(RasterizationStateDescriptor { + front_face: FrontFace::Ccw, + cull_mode: CullMode::None, + depth_bias: 0, + depth_bias_slope_scale: 0.0, + depth_bias_clamp: 0.0, + }), + depth_stencil_state: Some(DepthStencilStateDescriptor { + format: TextureFormat::Depth32Float, + depth_write_enabled: true, + depth_compare: CompareFunction::Less, + stencil_front: StencilStateFaceDescriptor::IGNORE, + stencil_back: StencilStateFaceDescriptor::IGNORE, + stencil_read_mask: 0, + stencil_write_mask: 0, + }), + color_states: vec![ColorStateDescriptor { + format: TextureFormat::Bgra8UnormSrgb, + color_blend: BlendDescriptor { + src_factor: BlendFactor::SrcAlpha, + dst_factor: BlendFactor::OneMinusSrcAlpha, + operation: BlendOperation::Add, + }, + alpha_blend: BlendDescriptor { + src_factor: BlendFactor::One, + dst_factor: BlendFactor::One, + operation: BlendOperation::Add, + }, + write_mask: ColorWrite::ALL, + }], + ..PipelineDescriptor::new(ShaderStages { + vertex: shaders.add(Shader::from_glsl( + ShaderStage::Vertex, + include_str!("sprite.vert"), + )), + fragment: Some(shaders.add(Shader::from_glsl( + ShaderStage::Fragment, + include_str!("sprite.frag"), + ))), + }) + } +} + +pub mod node { + pub const COLOR_MATERIAL: &'static str = "color_material"; + pub const RECT: &'static str = "rect"; +} + +pub trait SpriteRenderGraphBuilder { + fn add_sprite_graph(&mut self, resources: &Resources) -> &mut Self; +} + +impl SpriteRenderGraphBuilder for RenderGraph { + fn add_sprite_graph(&mut self, resources: &Resources) -> &mut Self { + self.add_system_node( + node::COLOR_MATERIAL, + AssetUniformNode::::new(false), + ); + self.add_node_edge(node::COLOR_MATERIAL, base_render_graph::node::MAIN_PASS) + .unwrap(); + + self.add_system_node(node::RECT, UniformNode::::new(false)); + self.add_node_edge(node::RECT, base_render_graph::node::MAIN_PASS) + .unwrap(); + + let mut pipelines = resources.get_mut::>().unwrap(); + let mut shaders = resources.get_mut::>().unwrap(); + pipelines.set(SPRITE_PIPELINE_HANDLE, build_sprite_pipeline(&mut shaders)); + let main_pass: &mut PassNode = self + .get_node_mut(base_render_graph::node::MAIN_PASS) + .unwrap(); + main_pass.add_pipeline( + SPRITE_PIPELINE_HANDLE, + vec![Box::new(AssignedMeshesDrawTarget)], + ); + self + } +} diff --git a/crates/bevy_sprite/src/render/sprite.frag b/crates/bevy_sprite/src/render/sprite.frag new file mode 100644 index 0000000000..1146ac2825 --- /dev/null +++ b/crates/bevy_sprite/src/render/sprite.frag @@ -0,0 +1,24 @@ +#version 450 + +layout(location = 0) in vec2 v_Uv; + +layout(location = 0) out vec4 o_Target; + +layout(set = 2, binding = 0) uniform ColorMaterial_color { + vec4 Color; +}; + +# ifdef COLORMATERIAL_TEXTURE +layout(set = 3, binding = 0) uniform texture2D ColorMaterial_texture; +layout(set = 3, binding = 1) uniform sampler ColorMaterial_texture_sampler; +# endif + +void main() { + vec4 color = Color; +# ifdef COLORMATERIAL_TEXTURE + color *= texture( + sampler2D(ColorMaterial_texture, ColorMaterial_texture_sampler), + v_Uv); +# endif + o_Target = color; +} diff --git a/crates/bevy_sprite/src/render/sprite.vert b/crates/bevy_sprite/src/render/sprite.vert new file mode 100644 index 0000000000..b4a3b334a7 --- /dev/null +++ b/crates/bevy_sprite/src/render/sprite.vert @@ -0,0 +1,24 @@ +#version 450 + +layout(location = 0) in vec3 Vertex_Position; +layout(location = 1) in vec3 Vertex_Normal; +layout(location = 2) in vec2 Vertex_Uv; + +layout(location = 0) out vec2 v_Uv; + +layout(set = 0, binding = 0) uniform Camera2d { + mat4 ViewProj; +}; + +layout(set = 1, binding = 0) uniform Rect { + vec2 Rect_Position; + vec2 Rect_Size; + float Rect_ZIndex; +}; + +void main() { + v_Uv = Vertex_Uv; + vec3 position = Vertex_Position * vec3(Rect_Size, 0.0); + position = position + vec3(Rect_Position, -Rect_ZIndex); + gl_Position = ViewProj * vec4(position, 1.0); +} \ No newline at end of file diff --git a/crates/bevy_ui/src/sprite.rs b/crates/bevy_sprite/src/sprite.rs similarity index 100% rename from crates/bevy_ui/src/sprite.rs rename to crates/bevy_sprite/src/sprite.rs diff --git a/crates/bevy_ui/Cargo.toml b/crates/bevy_ui/Cargo.toml index 01dbc54fae..27783ff4f3 100644 --- a/crates/bevy_ui/Cargo.toml +++ b/crates/bevy_ui/Cargo.toml @@ -10,6 +10,7 @@ bevy_asset = { path = "../bevy_asset" } bevy_type_registry = { path = "../bevy_type_registry" } bevy_core = { path = "../bevy_core" } bevy_derive = { path = "../bevy_derive" } +bevy_sprite = { path = "../bevy_sprite" } bevy_text = { path = "../bevy_text" } bevy_transform = { path = "../bevy_transform" } bevy_render = { path = "../bevy_render" } diff --git a/crates/bevy_ui/src/entity.rs b/crates/bevy_ui/src/entity.rs index f3b6471223..42d784ad0e 100644 --- a/crates/bevy_ui/src/entity.rs +++ b/crates/bevy_ui/src/entity.rs @@ -1,10 +1,9 @@ use super::Node; -use crate::{ - render::UI_PIPELINE_HANDLE, sprite::Sprite, widget::Label, ColorMaterial, Rect, QUAD_HANDLE, -}; +use crate::{render::UI_PIPELINE_HANDLE, widget::Label}; use bevy_asset::Handle; use bevy_derive::EntityArchetype; use bevy_render::{mesh::Mesh, Renderable}; +use bevy_sprite::{ColorMaterial, Rect, QUAD_HANDLE}; #[derive(EntityArchetype)] pub struct UiEntity { @@ -56,27 +55,3 @@ impl Default for LabelEntity { } } } - -#[derive(EntityArchetype)] -pub struct SpriteEntity { - pub sprite: Sprite, - pub rect: Rect, - pub mesh: Handle, // TODO: maybe abstract this out - pub material: Handle, - pub renderable: Renderable, -} - -impl Default for SpriteEntity { - fn default() -> Self { - SpriteEntity { - sprite: Default::default(), - rect: Default::default(), - mesh: QUAD_HANDLE, - material: Default::default(), - renderable: Renderable { - pipelines: vec![UI_PIPELINE_HANDLE], - ..Default::default() - }, - } - } -} diff --git a/crates/bevy_ui/src/lib.rs b/crates/bevy_ui/src/lib.rs index ea5dfa587e..f45edaaf10 100644 --- a/crates/bevy_ui/src/lib.rs +++ b/crates/bevy_ui/src/lib.rs @@ -1,64 +1,32 @@ mod anchors; -mod color_material; pub mod entity; -pub mod widget; mod margins; mod node; -mod rect; mod render; -mod sprite; mod ui_update_system; +pub mod widget; pub use anchors::*; -pub use color_material::*; pub use margins::*; pub use node::*; -pub use rect::*; pub use render::*; -pub use sprite::*; pub use ui_update_system::*; use bevy_app::{stage, AppBuilder, AppPlugin}; -use bevy_asset::{AddAsset, Assets, Handle}; -use bevy_render::{ - mesh::{shape::Quad, Mesh}, - render_graph::RenderGraph, - shader::asset_shader_def_system, -}; -use glam::Vec2; +use bevy_render::render_graph::RenderGraph; use legion::prelude::IntoSystem; -use sprite::sprite_system; use widget::Label; #[derive(Default)] pub struct UiPlugin; -pub const QUAD_HANDLE: Handle = Handle::from_u128(142404619811301375266013514540294236421); - impl AppPlugin for UiPlugin { fn build(&self, app: &mut AppBuilder) { - app.add_asset::() - .add_system_to_stage(stage::POST_UPDATE, sprite_system()) - .add_system_to_stage(stage::POST_UPDATE, ui_update_system()) - .add_system_to_stage(stage::POST_UPDATE, Label::label_system.system()) - .add_system_to_stage( - stage::POST_UPDATE, - asset_shader_def_system::.system(), - ); + app.add_system_to_stage(stage::POST_UPDATE, ui_update_system()) + .add_system_to_stage(stage::POST_UPDATE, Label::label_system.system()); let resources = app.resources(); let mut render_graph = resources.get_mut::().unwrap(); render_graph.add_ui_graph(resources); - - let mut meshes = resources.get_mut::>().unwrap(); - meshes.set( - QUAD_HANDLE, - Mesh::from(Quad { - size: Vec2::new(1.0, 1.0), - }), - ); - - let mut color_materials = resources.get_mut::>().unwrap(); - color_materials.add_default(ColorMaterial::default()); } } diff --git a/crates/bevy_ui/src/node.rs b/crates/bevy_ui/src/node.rs index bf0fadabd7..cf0732269e 100644 --- a/crates/bevy_ui/src/node.rs +++ b/crates/bevy_ui/src/node.rs @@ -1,5 +1,5 @@ use super::{Anchors, Margins}; -use crate::Rect; +use bevy_sprite::Rect; use glam::Vec2; #[derive(Debug, Clone)] diff --git a/crates/bevy_ui/src/render/mod.rs b/crates/bevy_ui/src/render/mod.rs index 990b770dfa..fe4bff7a61 100644 --- a/crates/bevy_ui/src/render/mod.rs +++ b/crates/bevy_ui/src/render/mod.rs @@ -1,11 +1,10 @@ -use crate::{ColorMaterial, Rect}; use bevy_asset::{Assets, Handle}; use bevy_render::{ base_render_graph, draw_target::AssignedMeshesDrawTarget, pipeline::{state_descriptors::*, PipelineDescriptor}, render_graph::{ - nodes::{AssetUniformNode, PassNode, UniformNode, CameraNode}, + nodes::{CameraNode, PassNode}, RenderGraph, }, shader::{Shader, ShaderStage, ShaderStages}, @@ -62,9 +61,7 @@ pub fn build_ui_pipeline(shaders: &mut Assets) -> PipelineDescriptor { } pub mod node { - pub const COLOR_MATERIAL: &'static str = "color_material"; pub const UI_CAMERA: &'static str = "ui_camera"; - pub const RECT: &'static str = "rect"; } pub mod uniform { @@ -77,21 +74,9 @@ pub trait UiRenderGraphBuilder { impl UiRenderGraphBuilder for RenderGraph { fn add_ui_graph(&mut self, resources: &Resources) -> &mut Self { - self.add_system_node( - node::COLOR_MATERIAL, - AssetUniformNode::::new(false), - ); - self.add_node_edge(node::COLOR_MATERIAL, base_render_graph::node::MAIN_PASS) - .unwrap(); - self.add_system_node(node::UI_CAMERA, CameraNode::new(uniform::UI_CAMERA)); self.add_node_edge(node::UI_CAMERA, base_render_graph::node::MAIN_PASS) .unwrap(); - - self.add_system_node(node::RECT, UniformNode::::new(false)); - self.add_node_edge(node::RECT, base_render_graph::node::MAIN_PASS) - .unwrap(); - let mut pipelines = resources.get_mut::>().unwrap(); let mut shaders = resources.get_mut::>().unwrap(); pipelines.set(UI_PIPELINE_HANDLE, build_ui_pipeline(&mut shaders)); diff --git a/crates/bevy_ui/src/ui_update_system.rs b/crates/bevy_ui/src/ui_update_system.rs index b105576f69..5f771214c0 100644 --- a/crates/bevy_ui/src/ui_update_system.rs +++ b/crates/bevy_ui/src/ui_update_system.rs @@ -1,10 +1,10 @@ use super::Node; -use crate::Rect; use bevy_core::transform::run_on_hierarchy_subworld_mut; use bevy_transform::prelude::{Children, Parent}; use bevy_window::Windows; use glam::Vec2; use legion::{prelude::*, systems::SubWorld}; +use bevy_sprite::Rect; pub const UI_Z_STEP: f32 = 0.0001; diff --git a/crates/bevy_ui/src/widget/label.rs b/crates/bevy_ui/src/widget/label.rs index 94d8cc8f4c..10c6f4ae9c 100644 --- a/crates/bevy_ui/src/widget/label.rs +++ b/crates/bevy_ui/src/widget/label.rs @@ -1,8 +1,8 @@ -use crate::{ColorMaterial, Rect, Res, ResMut}; use bevy_asset::{Assets, Handle}; use bevy_render::{texture::Texture, Color}; +use bevy_sprite::{ColorMaterial, Rect}; use bevy_text::Font; -use legion::prelude::Com; +use legion::prelude::{Com, Res, ResMut}; pub struct Label { pub text: String, @@ -37,17 +37,14 @@ impl Label { let height = rect.size.y().max(1.0); if let Some(font) = fonts.get(&label.font) { - let texture = font.render_text( - &label.text, - label.color, - width as usize, - height as usize, - ); + let texture = + font.render_text(&label.text, label.color, width as usize, height as usize); - let material = color_materials.get_or_insert_with(*color_material_handle, || ColorMaterial::from(Handle::::new())); + let material = color_materials.get_or_insert_with(*color_material_handle, || { + ColorMaterial::from(Handle::::new()) + }); if let Some(texture_handle) = material.texture { textures.set(texture_handle, texture); - } else { material.texture = Some(textures.add(texture)); } diff --git a/examples/2d/sprite.rs b/examples/2d/sprite.rs index 89b91a0d34..df8c036870 100644 --- a/examples/2d/sprite.rs +++ b/examples/2d/sprite.rs @@ -15,10 +15,10 @@ fn setup( let texture_handle = asset_server.load("assets/branding/icon.png").unwrap(); command_buffer .build() - .add_entity(OrthographicCameraEntity::ui()) + .add_entity(OrthographicCameraEntity::default()) .add_entity(SpriteEntity { rect: Rect { - position: Vec2::new(300.0, 300.0), + position: Vec2::new(0.0, 0.0), z_index: 0.5, ..Default::default() }, diff --git a/src/add_default_plugins.rs b/src/add_default_plugins.rs index 96f8cb72a3..2c845ddabe 100644 --- a/src/add_default_plugins.rs +++ b/src/add_default_plugins.rs @@ -30,6 +30,9 @@ impl AddDefaultPlugins for AppBuilder { #[cfg(feature = "render")] self.add_plugin(bevy_render::RenderPlugin::default()); + #[cfg(feature = "sprite")] + self.add_plugin(bevy_sprite::SpritePlugin::default()); + #[cfg(feature = "pbr")] self.add_plugin(bevy_pbr::PbrPlugin::default()); diff --git a/src/lib.rs b/src/lib.rs index 10aa66c5fc..0c7feb1bc0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -69,6 +69,8 @@ pub use bevy_property as property; pub use bevy_render as render; #[cfg(feature = "scene")] pub use bevy_scene as scene; +#[cfg(feature = "sprite")] +pub use bevy_sprite as sprite; #[cfg(feature = "text")] pub use bevy_text as text; #[cfg(feature = "transform")] diff --git a/src/prelude.rs b/src/prelude.rs index c65576daba..bdc2b0415a 100644 --- a/src/prelude.rs +++ b/src/prelude.rs @@ -1,4 +1,3 @@ -pub use crate::app::FromResources; #[cfg(feature = "asset")] pub use crate::asset::{AddAsset, AssetEvent, AssetServer, Assets, Handle}; #[cfg(feature = "core")] @@ -29,10 +28,12 @@ pub use crate::render::{ }, shader::{Shader, ShaderDefSuffixProvider, ShaderStage, ShaderStages}, texture::{Texture, TextureType}, - Camera, OrthographicCamera, PerspectiveCamera, Color, ColorSource, Renderable, + Camera, Color, ColorSource, OrthographicProjection, PerspectiveProjection, Renderable, }; #[cfg(feature = "scene")] pub use crate::scene::{Scene, SceneSpawner}; +#[cfg(feature = "sprite")] +pub use crate::sprite::{ColorMaterial, Rect, Sprite, entity::SpriteEntity}; #[cfg(feature = "text")] pub use crate::text::Font; #[cfg(feature = "transform")] @@ -40,15 +41,13 @@ pub use crate::transform::prelude::*; #[cfg(feature = "type_registry")] pub use crate::type_registry::RegisterType; #[cfg(feature = "ui")] -pub use crate::ui::{ - entity::*, widget::Label, Anchors, ColorMaterial, Margins, Node, Rect, Sprite, -}; +pub use crate::ui::{entity::*, widget::Label, Anchors, Margins, Node}; #[cfg(feature = "window")] pub use crate::window::{Window, WindowDescriptor, WindowPlugin, Windows}; pub use crate::{ app::{ schedule_runner::ScheduleRunnerPlugin, stage, App, AppBuilder, AppPlugin, EntityArchetype, - EventReader, Events, GetEventReader, System, + EventReader, Events, FromResources, GetEventReader, System, }, math::{self, Mat3, Mat4, Quat, Vec2, Vec3, Vec4}, AddDefaultPlugins, @@ -64,7 +63,7 @@ pub use legion::{ bit_set::BitSet, resource::{ResourceSet, Resources}, schedule::{Executor, Runnable, Schedulable, Schedule}, - IntoSystem, Res, ResMut, SubWorld, SystemBuilder, Query + IntoSystem, Query, Res, ResMut, SubWorld, SystemBuilder, }, world::{Universe, World}, };