sprite: create sprite crate. center 2d camera (split from ui camera). add 2d camera movement

This commit is contained in:
Carter Anderson 2020-05-30 12:31:04 -07:00
parent 71b3755633
commit 6e76296ce0
31 changed files with 445 additions and 220 deletions

View file

@ -6,7 +6,7 @@ edition = "2018"
[features] [features]
default = ["headless", "wgpu", "winit"] 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"] asset = ["bevy_asset"]
core = ["bevy_core"] core = ["bevy_core"]
type_registry = ["bevy_type_registry"] type_registry = ["bevy_type_registry"]
@ -18,6 +18,7 @@ pbr = ["bevy_pbr"]
property = ["bevy_property"] property = ["bevy_property"]
render = ["bevy_render"] render = ["bevy_render"]
scene = ["bevy_scene"] scene = ["bevy_scene"]
sprite = ["bevy_sprite"]
text = ["bevy_text"] text = ["bevy_text"]
transform = ["bevy_transform"] transform = ["bevy_transform"]
ui = ["bevy_ui"] ui = ["bevy_ui"]
@ -50,6 +51,7 @@ bevy_pbr = { path = "crates/bevy_pbr", optional = true }
bevy_property = { path = "crates/bevy_property", optional = true } bevy_property = { path = "crates/bevy_property", optional = true }
bevy_render = { path = "crates/bevy_render", optional = true } bevy_render = { path = "crates/bevy_render", optional = true }
bevy_scene = { path = "crates/bevy_scene", 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_transform = { path = "crates/bevy_transform", optional = true }
bevy_text = { path = "crates/bevy_text", optional = true } bevy_text = { path = "crates/bevy_text", optional = true }
bevy_ui = { path = "crates/bevy_ui", optional = true } bevy_ui = { path = "crates/bevy_ui", optional = true }

View file

@ -19,6 +19,10 @@ pub mod node {
pub const LIGHTS: &str = "lights"; pub const LIGHTS: &str = "lights";
} }
pub mod uniform {
pub const LIGHTS: &str = "Lights";
}
pub trait ForwardPbrRenderGraphBuilder { pub trait ForwardPbrRenderGraphBuilder {
fn add_pbr_graph(&mut self, resources: &Resources) -> &mut Self; fn add_pbr_graph(&mut self, resources: &Resources) -> &mut Self;
} }

View file

@ -1,4 +1,4 @@
use bevy_render::{Color, PerspectiveCamera, CameraProjection}; use bevy_render::{Color, PerspectiveProjection, CameraProjection};
use bevy_transform::components::Translation; use bevy_transform::components::Translation;
use bevy_property::Properties; use bevy_property::Properties;
use glam::Mat4; use glam::Mat4;
@ -32,7 +32,7 @@ pub struct LightRaw {
impl LightRaw { impl LightRaw {
pub fn from(light: &Light, transform: &Mat4, translation: &Translation) -> LightRaw { pub fn from(light: &Light, transform: &Mat4, translation: &Translation) -> LightRaw {
let perspective = PerspectiveCamera { let perspective = PerspectiveProjection {
fov: light.fov, fov: light.fov,
aspect_ratio: 1.0, aspect_ratio: 1.0,
near: light.depth.start, near: light.depth.start,

View file

@ -1,5 +1,4 @@
use bevy_render::{ use bevy_render::{
base_render_graph,
render_graph::{CommandQueue, Node, ResourceSlots, SystemNode}, render_graph::{CommandQueue, Node, ResourceSlots, SystemNode},
render_resource::{ render_resource::{
BufferInfo, BufferUsage, RenderResourceAssignment, RenderResourceAssignments, BufferInfo, BufferUsage, RenderResourceAssignment, RenderResourceAssignments,
@ -7,7 +6,10 @@ use bevy_render::{
renderer::{RenderContext, RenderResources}, renderer::{RenderContext, RenderResources},
}; };
use crate::light::{Light, LightRaw}; use crate::{
light::{Light, LightRaw},
uniform,
};
use bevy_transform::prelude::*; use bevy_transform::prelude::*;
use legion::prelude::*; use legion::prelude::*;
use zerocopy::AsBytes; use zerocopy::AsBytes;
@ -77,7 +79,7 @@ impl SystemNode for LightsNode {
..Default::default() ..Default::default()
}); });
render_resource_assignments.set( render_resource_assignments.set(
base_render_graph::uniform::LIGHTS, uniform::LIGHTS,
RenderResourceAssignment::Buffer { RenderResourceAssignment::Buffer {
resource: buffer, resource: buffer,
range: 0..light_uniform_size as u64, range: 0..light_uniform_size as u64,

View file

@ -41,7 +41,6 @@ pub mod node {
pub mod uniform { pub mod uniform {
pub const CAMERA: &str = "Camera"; pub const CAMERA: &str = "Camera";
pub const CAMERA2D: &str = "Camera2d"; pub const CAMERA2D: &str = "Camera2d";
pub const LIGHTS: &str = "Lights";
} }
impl Default for BaseRenderGraphConfig { impl Default for BaseRenderGraphConfig {

View file

@ -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<String>,
}
pub fn camera_system<T: CameraProjection + Component>(resources: &mut Resources) -> Box<dyn Schedulable> {
let mut window_resized_event_reader = resources.get_event_reader::<WindowResized>();
(move |world: &mut SubWorld,
window_resized_events: Res<Events<WindowResized>>,
query: &mut Query<(Write<Camera>, Write<T>)>| {
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()
}

View file

@ -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<String>,
}
pub fn camera_system<T: CameraProjection + Component>(
resources: &mut Resources,
) -> Box<dyn Schedulable> {
let mut window_resized_event_reader = resources.get_event_reader::<WindowResized>();
(move |world: &mut SubWorld,
window_resized_events: Res<Events<WindowResized>>,
query: &mut Query<(Write<Camera>, Write<T>)>| {
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()
}

View file

@ -0,0 +1,5 @@
mod camera;
mod projection;
pub use camera::*;
pub use projection::*;

View file

@ -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,
}
}
}

View file

@ -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_asset::Handle;
use bevy_derive::EntityArchetype; use bevy_derive::EntityArchetype;
use bevy_transform::components::{LocalToWorld, Rotation, Scale, Translation}; use bevy_transform::components::{LocalToWorld, Rotation, Scale, Translation};
@ -17,7 +17,7 @@ pub struct MeshMaterialEntity<T: Default + Send + Sync + 'static> {
#[derive(EntityArchetype)] #[derive(EntityArchetype)]
pub struct PerspectiveCameraEntity { pub struct PerspectiveCameraEntity {
pub camera: Camera, pub camera: Camera,
pub perspective_camera: PerspectiveCamera, pub perspective_projection: PerspectiveProjection,
pub local_to_world: LocalToWorld, pub local_to_world: LocalToWorld,
} }
@ -28,7 +28,7 @@ impl Default for PerspectiveCameraEntity {
name: Some(base_render_graph::uniform::CAMERA.to_string()), name: Some(base_render_graph::uniform::CAMERA.to_string()),
..Default::default() ..Default::default()
}, },
perspective_camera: Default::default(), perspective_projection: Default::default(),
local_to_world: Default::default(), local_to_world: Default::default(),
} }
} }
@ -38,8 +38,10 @@ impl Default for PerspectiveCameraEntity {
#[derive(EntityArchetype)] #[derive(EntityArchetype)]
pub struct OrthographicCameraEntity { pub struct OrthographicCameraEntity {
pub camera: Camera, pub camera: Camera,
pub orthographic_camera: OrthographicCamera, pub orthographic_projection: OrthographicProjection,
pub local_to_world: LocalToWorld, pub local_to_world: LocalToWorld,
pub translation: Translation,
pub rotation: Rotation,
} }
impl OrthographicCameraEntity { impl OrthographicCameraEntity {
@ -49,8 +51,10 @@ impl OrthographicCameraEntity {
name: Some("UiCamera".to_string()), name: Some("UiCamera".to_string()),
..Default::default() ..Default::default()
}, },
orthographic_camera: Default::default(), orthographic_projection: Default::default(),
local_to_world: 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()), name: Some(base_render_graph::uniform::CAMERA2D.to_string()),
..Default::default() ..Default::default()
}, },
orthographic_camera: Default::default(), orthographic_projection: Default::default(),
local_to_world: Default::default(), local_to_world: Default::default(),
translation: Default::default(),
rotation: Default::default(),
} }
} }

View file

@ -76,8 +76,8 @@ impl AppPlugin for RenderPlugin {
.add_asset::<PipelineDescriptor>() .add_asset::<PipelineDescriptor>()
.add_asset_loader::<Texture, PngTextureLoader>() .add_asset_loader::<Texture, PngTextureLoader>()
.register_component::<Camera>() .register_component::<Camera>()
.register_component::<OrthographicCamera>() .register_component::<OrthographicProjection>()
.register_component::<PerspectiveCamera>() .register_component::<PerspectiveProjection>()
.register_component::<Renderable>() .register_component::<Renderable>()
.register_property_type::<Color>() .register_property_type::<Color>()
.register_property_type::<Range<f32>>() .register_property_type::<Range<f32>>()
@ -90,8 +90,8 @@ impl AppPlugin for RenderPlugin {
.init_resource::<EntitiesWaitingForAssets>() .init_resource::<EntitiesWaitingForAssets>()
.init_resource::<TextureResourceSystemState>() .init_resource::<TextureResourceSystemState>()
.add_system(entity_render_resource_assignments_system()) .add_system(entity_render_resource_assignments_system())
.init_system_to_stage(stage::POST_UPDATE, camera::camera_system::<OrthographicCamera>) .init_system_to_stage(stage::POST_UPDATE, camera::camera_system::<OrthographicProjection>)
.init_system_to_stage(stage::POST_UPDATE, camera::camera_system::<PerspectiveCamera>) .init_system_to_stage(stage::POST_UPDATE, camera::camera_system::<PerspectiveProjection>)
.add_system_to_stage( .add_system_to_stage(
stage::PRE_UPDATE, stage::PRE_UPDATE,
EntitiesWaitingForAssets::clear_system.system(), EntitiesWaitingForAssets::clear_system.system(),

View file

@ -0,0 +1,18 @@
[package]
name = "bevy_sprite"
version = "0.1.0"
authors = ["Carter Anderson <mcanders1@gmail.com>"]
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"

View file

@ -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<Mesh>, // TODO: maybe abstract this out
pub material: Handle<ColorMaterial>,
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()
},
}
}
}

View file

@ -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<Mesh> = Handle::from_u128(142404619811301375266013514540294236421);
impl AppPlugin for SpritePlugin {
fn build(&self, app: &mut AppBuilder) {
app.add_asset::<ColorMaterial>()
.add_system_to_stage(stage::POST_UPDATE, sprite_system())
.add_system_to_stage(
stage::POST_UPDATE,
asset_shader_def_system::<ColorMaterial>.system(),
);
let resources = app.resources();
let mut render_graph = resources.get_mut::<RenderGraph>().unwrap();
render_graph.add_sprite_graph(resources);
let mut meshes = resources.get_mut::<Assets<Mesh>>().unwrap();
meshes.set(
QUAD_HANDLE,
Mesh::from(Quad {
size: Vec2::new(1.0, 1.0),
}),
);
let mut color_materials = resources.get_mut::<Assets<ColorMaterial>>().unwrap();
color_materials.add_default(ColorMaterial::default());
}
}

View file

@ -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<PipelineDescriptor> =
Handle::from_u128(278534784033876544639935131272264723170);
pub fn build_sprite_pipeline(shaders: &mut Assets<Shader>) -> 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::<ColorMaterial>::new(false),
);
self.add_node_edge(node::COLOR_MATERIAL, base_render_graph::node::MAIN_PASS)
.unwrap();
self.add_system_node(node::RECT, UniformNode::<Rect>::new(false));
self.add_node_edge(node::RECT, base_render_graph::node::MAIN_PASS)
.unwrap();
let mut pipelines = resources.get_mut::<Assets<PipelineDescriptor>>().unwrap();
let mut shaders = resources.get_mut::<Assets<Shader>>().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
}
}

View file

@ -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;
}

View file

@ -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);
}

View file

@ -10,6 +10,7 @@ bevy_asset = { path = "../bevy_asset" }
bevy_type_registry = { path = "../bevy_type_registry" } bevy_type_registry = { path = "../bevy_type_registry" }
bevy_core = { path = "../bevy_core" } bevy_core = { path = "../bevy_core" }
bevy_derive = { path = "../bevy_derive" } bevy_derive = { path = "../bevy_derive" }
bevy_sprite = { path = "../bevy_sprite" }
bevy_text = { path = "../bevy_text" } bevy_text = { path = "../bevy_text" }
bevy_transform = { path = "../bevy_transform" } bevy_transform = { path = "../bevy_transform" }
bevy_render = { path = "../bevy_render" } bevy_render = { path = "../bevy_render" }

View file

@ -1,10 +1,9 @@
use super::Node; use super::Node;
use crate::{ use crate::{render::UI_PIPELINE_HANDLE, widget::Label};
render::UI_PIPELINE_HANDLE, sprite::Sprite, widget::Label, ColorMaterial, Rect, QUAD_HANDLE,
};
use bevy_asset::Handle; use bevy_asset::Handle;
use bevy_derive::EntityArchetype; use bevy_derive::EntityArchetype;
use bevy_render::{mesh::Mesh, Renderable}; use bevy_render::{mesh::Mesh, Renderable};
use bevy_sprite::{ColorMaterial, Rect, QUAD_HANDLE};
#[derive(EntityArchetype)] #[derive(EntityArchetype)]
pub struct UiEntity { 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<Mesh>, // TODO: maybe abstract this out
pub material: Handle<ColorMaterial>,
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()
},
}
}
}

View file

@ -1,64 +1,32 @@
mod anchors; mod anchors;
mod color_material;
pub mod entity; pub mod entity;
pub mod widget;
mod margins; mod margins;
mod node; mod node;
mod rect;
mod render; mod render;
mod sprite;
mod ui_update_system; mod ui_update_system;
pub mod widget;
pub use anchors::*; pub use anchors::*;
pub use color_material::*;
pub use margins::*; pub use margins::*;
pub use node::*; pub use node::*;
pub use rect::*;
pub use render::*; pub use render::*;
pub use sprite::*;
pub use ui_update_system::*; pub use ui_update_system::*;
use bevy_app::{stage, AppBuilder, AppPlugin}; use bevy_app::{stage, AppBuilder, AppPlugin};
use bevy_asset::{AddAsset, Assets, Handle}; use bevy_render::render_graph::RenderGraph;
use bevy_render::{
mesh::{shape::Quad, Mesh},
render_graph::RenderGraph,
shader::asset_shader_def_system,
};
use glam::Vec2;
use legion::prelude::IntoSystem; use legion::prelude::IntoSystem;
use sprite::sprite_system;
use widget::Label; use widget::Label;
#[derive(Default)] #[derive(Default)]
pub struct UiPlugin; pub struct UiPlugin;
pub const QUAD_HANDLE: Handle<Mesh> = Handle::from_u128(142404619811301375266013514540294236421);
impl AppPlugin for UiPlugin { impl AppPlugin for UiPlugin {
fn build(&self, app: &mut AppBuilder) { fn build(&self, app: &mut AppBuilder) {
app.add_asset::<ColorMaterial>() app.add_system_to_stage(stage::POST_UPDATE, ui_update_system())
.add_system_to_stage(stage::POST_UPDATE, sprite_system()) .add_system_to_stage(stage::POST_UPDATE, Label::label_system.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::<ColorMaterial>.system(),
);
let resources = app.resources(); let resources = app.resources();
let mut render_graph = resources.get_mut::<RenderGraph>().unwrap(); let mut render_graph = resources.get_mut::<RenderGraph>().unwrap();
render_graph.add_ui_graph(resources); render_graph.add_ui_graph(resources);
let mut meshes = resources.get_mut::<Assets<Mesh>>().unwrap();
meshes.set(
QUAD_HANDLE,
Mesh::from(Quad {
size: Vec2::new(1.0, 1.0),
}),
);
let mut color_materials = resources.get_mut::<Assets<ColorMaterial>>().unwrap();
color_materials.add_default(ColorMaterial::default());
} }
} }

View file

@ -1,5 +1,5 @@
use super::{Anchors, Margins}; use super::{Anchors, Margins};
use crate::Rect; use bevy_sprite::Rect;
use glam::Vec2; use glam::Vec2;
#[derive(Debug, Clone)] #[derive(Debug, Clone)]

View file

@ -1,11 +1,10 @@
use crate::{ColorMaterial, Rect};
use bevy_asset::{Assets, Handle}; use bevy_asset::{Assets, Handle};
use bevy_render::{ use bevy_render::{
base_render_graph, base_render_graph,
draw_target::AssignedMeshesDrawTarget, draw_target::AssignedMeshesDrawTarget,
pipeline::{state_descriptors::*, PipelineDescriptor}, pipeline::{state_descriptors::*, PipelineDescriptor},
render_graph::{ render_graph::{
nodes::{AssetUniformNode, PassNode, UniformNode, CameraNode}, nodes::{CameraNode, PassNode},
RenderGraph, RenderGraph,
}, },
shader::{Shader, ShaderStage, ShaderStages}, shader::{Shader, ShaderStage, ShaderStages},
@ -62,9 +61,7 @@ pub fn build_ui_pipeline(shaders: &mut Assets<Shader>) -> PipelineDescriptor {
} }
pub mod node { pub mod node {
pub const COLOR_MATERIAL: &'static str = "color_material";
pub const UI_CAMERA: &'static str = "ui_camera"; pub const UI_CAMERA: &'static str = "ui_camera";
pub const RECT: &'static str = "rect";
} }
pub mod uniform { pub mod uniform {
@ -77,21 +74,9 @@ pub trait UiRenderGraphBuilder {
impl UiRenderGraphBuilder for RenderGraph { impl UiRenderGraphBuilder for RenderGraph {
fn add_ui_graph(&mut self, resources: &Resources) -> &mut Self { fn add_ui_graph(&mut self, resources: &Resources) -> &mut Self {
self.add_system_node(
node::COLOR_MATERIAL,
AssetUniformNode::<ColorMaterial>::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_system_node(node::UI_CAMERA, CameraNode::new(uniform::UI_CAMERA));
self.add_node_edge(node::UI_CAMERA, base_render_graph::node::MAIN_PASS) self.add_node_edge(node::UI_CAMERA, base_render_graph::node::MAIN_PASS)
.unwrap(); .unwrap();
self.add_system_node(node::RECT, UniformNode::<Rect>::new(false));
self.add_node_edge(node::RECT, base_render_graph::node::MAIN_PASS)
.unwrap();
let mut pipelines = resources.get_mut::<Assets<PipelineDescriptor>>().unwrap(); let mut pipelines = resources.get_mut::<Assets<PipelineDescriptor>>().unwrap();
let mut shaders = resources.get_mut::<Assets<Shader>>().unwrap(); let mut shaders = resources.get_mut::<Assets<Shader>>().unwrap();
pipelines.set(UI_PIPELINE_HANDLE, build_ui_pipeline(&mut shaders)); pipelines.set(UI_PIPELINE_HANDLE, build_ui_pipeline(&mut shaders));

View file

@ -1,10 +1,10 @@
use super::Node; use super::Node;
use crate::Rect;
use bevy_core::transform::run_on_hierarchy_subworld_mut; use bevy_core::transform::run_on_hierarchy_subworld_mut;
use bevy_transform::prelude::{Children, Parent}; use bevy_transform::prelude::{Children, Parent};
use bevy_window::Windows; use bevy_window::Windows;
use glam::Vec2; use glam::Vec2;
use legion::{prelude::*, systems::SubWorld}; use legion::{prelude::*, systems::SubWorld};
use bevy_sprite::Rect;
pub const UI_Z_STEP: f32 = 0.0001; pub const UI_Z_STEP: f32 = 0.0001;

View file

@ -1,8 +1,8 @@
use crate::{ColorMaterial, Rect, Res, ResMut};
use bevy_asset::{Assets, Handle}; use bevy_asset::{Assets, Handle};
use bevy_render::{texture::Texture, Color}; use bevy_render::{texture::Texture, Color};
use bevy_sprite::{ColorMaterial, Rect};
use bevy_text::Font; use bevy_text::Font;
use legion::prelude::Com; use legion::prelude::{Com, Res, ResMut};
pub struct Label { pub struct Label {
pub text: String, pub text: String,
@ -37,17 +37,14 @@ impl Label {
let height = rect.size.y().max(1.0); let height = rect.size.y().max(1.0);
if let Some(font) = fonts.get(&label.font) { if let Some(font) = fonts.get(&label.font) {
let texture = font.render_text( let texture =
&label.text, font.render_text(&label.text, label.color, width as usize, height as usize);
label.color,
width as usize,
height as usize,
);
let material = color_materials.get_or_insert_with(*color_material_handle, || ColorMaterial::from(Handle::<Texture>::new())); let material = color_materials.get_or_insert_with(*color_material_handle, || {
ColorMaterial::from(Handle::<Texture>::new())
});
if let Some(texture_handle) = material.texture { if let Some(texture_handle) = material.texture {
textures.set(texture_handle, texture); textures.set(texture_handle, texture);
} else { } else {
material.texture = Some(textures.add(texture)); material.texture = Some(textures.add(texture));
} }

View file

@ -15,10 +15,10 @@ fn setup(
let texture_handle = asset_server.load("assets/branding/icon.png").unwrap(); let texture_handle = asset_server.load("assets/branding/icon.png").unwrap();
command_buffer command_buffer
.build() .build()
.add_entity(OrthographicCameraEntity::ui()) .add_entity(OrthographicCameraEntity::default())
.add_entity(SpriteEntity { .add_entity(SpriteEntity {
rect: Rect { rect: Rect {
position: Vec2::new(300.0, 300.0), position: Vec2::new(0.0, 0.0),
z_index: 0.5, z_index: 0.5,
..Default::default() ..Default::default()
}, },

View file

@ -30,6 +30,9 @@ impl AddDefaultPlugins for AppBuilder {
#[cfg(feature = "render")] #[cfg(feature = "render")]
self.add_plugin(bevy_render::RenderPlugin::default()); self.add_plugin(bevy_render::RenderPlugin::default());
#[cfg(feature = "sprite")]
self.add_plugin(bevy_sprite::SpritePlugin::default());
#[cfg(feature = "pbr")] #[cfg(feature = "pbr")]
self.add_plugin(bevy_pbr::PbrPlugin::default()); self.add_plugin(bevy_pbr::PbrPlugin::default());

View file

@ -69,6 +69,8 @@ pub use bevy_property as property;
pub use bevy_render as render; pub use bevy_render as render;
#[cfg(feature = "scene")] #[cfg(feature = "scene")]
pub use bevy_scene as scene; pub use bevy_scene as scene;
#[cfg(feature = "sprite")]
pub use bevy_sprite as sprite;
#[cfg(feature = "text")] #[cfg(feature = "text")]
pub use bevy_text as text; pub use bevy_text as text;
#[cfg(feature = "transform")] #[cfg(feature = "transform")]

View file

@ -1,4 +1,3 @@
pub use crate::app::FromResources;
#[cfg(feature = "asset")] #[cfg(feature = "asset")]
pub use crate::asset::{AddAsset, AssetEvent, AssetServer, Assets, Handle}; pub use crate::asset::{AddAsset, AssetEvent, AssetServer, Assets, Handle};
#[cfg(feature = "core")] #[cfg(feature = "core")]
@ -29,10 +28,12 @@ pub use crate::render::{
}, },
shader::{Shader, ShaderDefSuffixProvider, ShaderStage, ShaderStages}, shader::{Shader, ShaderDefSuffixProvider, ShaderStage, ShaderStages},
texture::{Texture, TextureType}, texture::{Texture, TextureType},
Camera, OrthographicCamera, PerspectiveCamera, Color, ColorSource, Renderable, Camera, Color, ColorSource, OrthographicProjection, PerspectiveProjection, Renderable,
}; };
#[cfg(feature = "scene")] #[cfg(feature = "scene")]
pub use crate::scene::{Scene, SceneSpawner}; pub use crate::scene::{Scene, SceneSpawner};
#[cfg(feature = "sprite")]
pub use crate::sprite::{ColorMaterial, Rect, Sprite, entity::SpriteEntity};
#[cfg(feature = "text")] #[cfg(feature = "text")]
pub use crate::text::Font; pub use crate::text::Font;
#[cfg(feature = "transform")] #[cfg(feature = "transform")]
@ -40,15 +41,13 @@ pub use crate::transform::prelude::*;
#[cfg(feature = "type_registry")] #[cfg(feature = "type_registry")]
pub use crate::type_registry::RegisterType; pub use crate::type_registry::RegisterType;
#[cfg(feature = "ui")] #[cfg(feature = "ui")]
pub use crate::ui::{ pub use crate::ui::{entity::*, widget::Label, Anchors, Margins, Node};
entity::*, widget::Label, Anchors, ColorMaterial, Margins, Node, Rect, Sprite,
};
#[cfg(feature = "window")] #[cfg(feature = "window")]
pub use crate::window::{Window, WindowDescriptor, WindowPlugin, Windows}; pub use crate::window::{Window, WindowDescriptor, WindowPlugin, Windows};
pub use crate::{ pub use crate::{
app::{ app::{
schedule_runner::ScheduleRunnerPlugin, stage, App, AppBuilder, AppPlugin, EntityArchetype, 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}, math::{self, Mat3, Mat4, Quat, Vec2, Vec3, Vec4},
AddDefaultPlugins, AddDefaultPlugins,
@ -64,7 +63,7 @@ pub use legion::{
bit_set::BitSet, bit_set::BitSet,
resource::{ResourceSet, Resources}, resource::{ResourceSet, Resources},
schedule::{Executor, Runnable, Schedulable, Schedule}, schedule::{Executor, Runnable, Schedulable, Schedule},
IntoSystem, Res, ResMut, SubWorld, SystemBuilder, Query IntoSystem, Query, Res, ResMut, SubWorld, SystemBuilder,
}, },
world::{Universe, World}, world::{Universe, World},
}; };