ui textures

This commit is contained in:
Carter Anderson 2020-05-03 23:49:45 -07:00
parent 08c6679f38
commit 1056b79abf
10 changed files with 159 additions and 71 deletions

View file

@ -0,0 +1,55 @@
use bevy_asset::{self, Handle};
use bevy_derive::Uniforms;
use bevy_render::{colors, texture::Texture, Color};
#[derive(Uniforms)]
#[module(meta = false)]
pub struct ColorMaterial {
pub color: Color,
#[uniform(shader_def)]
pub texture: Option<Handle<Texture>>,
}
impl ColorMaterial {
pub fn color(color: Color) -> Self {
ColorMaterial {
color,
texture: None,
}
}
pub fn texture(texture: Handle<Texture>) -> Self {
ColorMaterial {
color: colors::WHITE,
texture: Some(texture),
}
}
pub fn modulated_texture(texture: Handle<Texture>, color: Color) -> Self {
ColorMaterial {
color,
texture: Some(texture),
}
}
}
impl Default for ColorMaterial {
fn default() -> Self {
ColorMaterial {
color: Color::rgb(1.0, 1.0, 1.0),
texture: None,
}
}
}
impl From<Color> for ColorMaterial {
fn from(color: Color) -> Self {
ColorMaterial::color(color)
}
}
impl From<Handle<Texture>> for ColorMaterial {
fn from(texture: Handle<Texture>) -> Self {
ColorMaterial::texture(texture)
}
}

View file

@ -1,15 +1,16 @@
use super::Node; use super::Node;
use crate::{render::UI_PIPELINE_HANDLE, ColorMaterial, Rect, QUAD_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 crate::{Rect, render::UI_PIPELINE_HANDLE, QUAD_HANDLE};
use bevy_asset::Handle;
#[derive(EntityArchetype)] #[derive(EntityArchetype)]
#[module(meta = false)] #[module(meta = false)]
pub struct UiEntity { pub struct UiEntity {
pub node: Node, pub node: Node,
pub rect: Rect, pub rect: Rect,
pub mesh: Handle<Mesh>, // TODO: maybe abstract this out pub mesh: Handle<Mesh>, // TODO: maybe abstract this out
pub material: Handle<ColorMaterial>,
pub renderable: Renderable, pub renderable: Renderable,
} }
@ -19,12 +20,11 @@ impl Default for UiEntity {
node: Default::default(), node: Default::default(),
rect: Default::default(), rect: Default::default(),
mesh: QUAD_HANDLE, mesh: QUAD_HANDLE,
material: Default::default(),
renderable: Renderable { renderable: Renderable {
pipelines: vec![ pipelines: vec![UI_PIPELINE_HANDLE],
UI_PIPELINE_HANDLE
],
..Default::default() ..Default::default()
} },
} }
} }
} }

View file

@ -1,4 +1,5 @@
mod anchors; mod anchors;
mod color_material;
pub mod entity; pub mod entity;
mod margins; mod margins;
mod node; mod node;
@ -7,34 +8,52 @@ mod render;
mod ui_update_system; mod ui_update_system;
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 rect::*;
pub use render::*; pub use render::*;
pub use ui_update_system::*; pub use ui_update_system::*;
use bevy_app::{AppBuilder, AppPlugin}; use bevy_app::{stage, AppBuilder, AppPlugin};
use bevy_render::{mesh::{shape::Quad, Mesh}, render_graph::RenderGraph};
use bevy_asset::{AssetStorage, Handle}; use bevy_asset::{AssetStorage, Handle};
use bevy_render::{
mesh::{shape::Quad, Mesh},
render_graph::RenderGraph,
shader::asset_handle_shader_def_system,
};
use glam::Vec2; use glam::Vec2;
use legion::prelude::IntoSystem;
#[derive(Default)] #[derive(Default)]
pub struct UiPlugin; pub struct UiPlugin;
pub const QUAD_HANDLE: Handle<Mesh> = Handle::from_bytes([179, 41, 129, 128, 95, 217, 79, 194, 167, 95, 107, 115, 97, 151, 20, 62]); pub const QUAD_HANDLE: Handle<Mesh> = Handle::from_bytes([
179, 41, 129, 128, 95, 217, 79, 194, 167, 95, 107, 115, 97, 151, 20, 62,
]);
impl AppPlugin for UiPlugin { impl AppPlugin for UiPlugin {
fn build(&self, app: &mut AppBuilder) { fn build(&self, app: &mut AppBuilder) {
let mut color_materials = AssetStorage::<ColorMaterial>::new();
color_materials.add_default(ColorMaterial::default());
{ app.add_resource(color_materials)
let mut render_graph = app.resources().get_mut::<RenderGraph>().unwrap(); .add_system_to_stage(
render_graph.add_ui_graph(app.resources()); stage::POST_UPDATE,
asset_handle_shader_def_system::<ColorMaterial>.system(),
)
.add_system(ui_update_system());
let mut meshes = app.resources().get_mut::<AssetStorage<Mesh>>().unwrap(); let resources = app.resources();
meshes.add_with_handle(QUAD_HANDLE, Mesh::from(Quad { let mut render_graph = resources.get_mut::<RenderGraph>().unwrap();
render_graph.add_ui_graph(resources);
let mut meshes = resources.get_mut::<AssetStorage<Mesh>>().unwrap();
meshes.add_with_handle(
QUAD_HANDLE,
Mesh::from(Quad {
size: Vec2::new(1.0, 1.0), size: Vec2::new(1.0, 1.0),
})); }),
} );
app.add_system(ui_update_system());
} }
} }

View file

@ -1,6 +1,5 @@
use bevy_core::bytes::GetBytes; use bevy_core::bytes::GetBytes;
use bevy_derive::Uniform; use bevy_derive::Uniform;
use bevy_render::Color;
use glam::Vec2; use glam::Vec2;
use zerocopy::AsBytes; use zerocopy::AsBytes;
#[repr(C)] #[repr(C)]
@ -9,7 +8,6 @@ use zerocopy::AsBytes;
pub struct Rect { pub struct Rect {
pub position: Vec2, pub position: Vec2,
pub size: Vec2, pub size: Vec2,
pub color: Color,
pub z_index: f32, pub z_index: f32,
} }

View file

@ -2,12 +2,12 @@ use bevy_asset::{AssetStorage, Handle};
use bevy_render::{ use bevy_render::{
draw_target::AssignedMeshesDrawTarget, draw_target::AssignedMeshesDrawTarget,
pipeline::{state_descriptors::*, PipelineDescriptor}, pipeline::{state_descriptors::*, PipelineDescriptor},
render_graph::{nodes::{UniformNode, PassNode}, RenderGraph}, render_graph::{nodes::{UniformNode, PassNode, AssetUniformNode}, RenderGraph},
shader::{Shader, ShaderStage, ShaderStages}, shader::{Shader, ShaderStage, ShaderStages},
texture::TextureFormat, base_render_graph, texture::TextureFormat, base_render_graph,
}; };
use legion::prelude::Resources; use legion::prelude::Resources;
use crate::Rect; use crate::{ColorMaterial, Rect};
pub const UI_PIPELINE_HANDLE: Handle<PipelineDescriptor> = pub const UI_PIPELINE_HANDLE: Handle<PipelineDescriptor> =
Handle::from_bytes([ Handle::from_bytes([
@ -65,6 +65,8 @@ 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_named("color_material", AssetUniformNode::<ColorMaterial>::new(false), resources);
self.add_node_edge("color_material", base_render_graph::node::MAIN_PASS).unwrap();
self.add_system_node_named("rect", UniformNode::<Rect>::new(false), resources); self.add_system_node_named("rect", UniformNode::<Rect>::new(false), resources);
self.add_node_edge("rect", base_render_graph::node::MAIN_PASS).unwrap(); self.add_node_edge("rect", base_render_graph::node::MAIN_PASS).unwrap();
let mut pipelines = resources.get_mut::<AssetStorage<PipelineDescriptor>>().unwrap(); let mut pipelines = resources.get_mut::<AssetStorage<PipelineDescriptor>>().unwrap();

View file

@ -1,9 +1,24 @@
#version 450 #version 450
layout(location = 0) in vec4 v_Color; layout(location = 0) in vec2 v_Uv;
layout(location = 0) out vec4 o_Target; 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() { void main() {
o_Target = v_Color; vec4 color = Color;
# ifdef COLORMATERIAL_TEXTURE
color *= texture(
sampler2D(ColorMaterial_texture, ColorMaterial_texture_sampler),
v_Uv);
# endif
o_Target = color;
} }

View file

@ -4,7 +4,7 @@ layout(location = 0) in vec3 Vertex_Position;
layout(location = 1) in vec3 Vertex_Normal; layout(location = 1) in vec3 Vertex_Normal;
layout(location = 2) in vec2 Vertex_Uv; layout(location = 2) in vec2 Vertex_Uv;
layout(location = 0) out vec4 v_Color; layout(location = 0) out vec2 v_Uv;
layout(set = 0, binding = 0) uniform Camera2d { layout(set = 0, binding = 0) uniform Camera2d {
mat4 ViewProj; mat4 ViewProj;
@ -13,12 +13,11 @@ layout(set = 0, binding = 0) uniform Camera2d {
layout(set = 1, binding = 0) uniform Rect { layout(set = 1, binding = 0) uniform Rect {
vec2 Rect_Position; vec2 Rect_Position;
vec2 Rect_Size; vec2 Rect_Size;
vec4 Rect_Color;
float Rect_ZIndex; float Rect_ZIndex;
}; };
void main() { void main() {
v_Color = Rect_Color; v_Uv = Vertex_Uv;
vec3 position = Vertex_Position * vec3(Rect_Size, 0.0); vec3 position = Vertex_Position * vec3(Rect_Size, 0.0);
position = position + vec3(Rect_Position + Rect_Size / 2.0, -Rect_ZIndex); position = position + vec3(Rect_Position + Rect_Size / 2.0, -Rect_ZIndex);
gl_Position = ViewProj * vec4(position, 1.0); gl_Position = ViewProj * vec4(position, 1.0);

View file

@ -1,5 +1,4 @@
use bevy::prelude::*; use bevy::prelude::*;
use bevy_ui::Rect;
fn main() { fn main() {
App::build() App::build()
@ -19,6 +18,18 @@ fn setup(world: &mut World, resources: &mut Resources) {
..Default::default() ..Default::default()
}); });
let mut texture_storage = resources.get_mut::<AssetStorage<Texture>>().unwrap();
let texture_path = concat!(
env!("CARGO_MANIFEST_DIR"),
"/assets/branding/bevy_logo_dark_big.png"
);
let texture = Texture::load(TextureType::Png(texture_path.to_string()));
let aspect = texture.height as f32 / texture.width as f32;
let texture_handle = texture_storage.add(texture);
let mut color_materials = resources.get_mut::<AssetStorage<ColorMaterial>>().unwrap();
let blue_material_handle = color_materials.add(Color::rgb(0.6, 0.6, 1.0).into());
world world
.build() .build()
// cube // cube
@ -53,10 +64,7 @@ fn setup(world: &mut World, resources: &mut Resources) {
Anchors::new(0.0, 0.0, 0.0, 1.0), Anchors::new(0.0, 0.0, 0.0, 1.0),
Margins::new(10.0, 200.0, 10.0, 10.0), Margins::new(10.0, 200.0, 10.0, 10.0),
), ),
rect: Rect { material: color_materials.add(Color::rgb(0.02, 0.02, 0.02).into()),
color: Color::rgb(0.02, 0.02, 0.02),
..Default::default()
},
..Default::default() ..Default::default()
}) })
// top right anchor with vertical fill // top right anchor with vertical fill
@ -66,10 +74,7 @@ fn setup(world: &mut World, resources: &mut Resources) {
Anchors::new(1.0, 1.0, 0.0, 1.0), Anchors::new(1.0, 1.0, 0.0, 1.0),
Margins::new(10.0, 100.0, 50.0, 100.0), Margins::new(10.0, 100.0, 50.0, 100.0),
), ),
rect: Rect { material: color_materials.add(Color::rgb(0.02, 0.02, 0.02).into()),
color: Color::rgb(0.02, 0.02, 0.02),
..Default::default()
},
..Default::default() ..Default::default()
}) })
// render order test: reddest in the back, whitest in the front // render order test: reddest in the back, whitest in the front
@ -79,10 +84,7 @@ fn setup(world: &mut World, resources: &mut Resources) {
Anchors::new(0.5, 0.5, 0.5, 0.5), Anchors::new(0.5, 0.5, 0.5, 0.5),
Margins::new(0.0, 100.0, 0.0, 100.0), Margins::new(0.0, 100.0, 0.0, 100.0),
), ),
rect: Rect { material: color_materials.add(Color::rgb(1.0, 0.0, 0.0).into()),
color: Color::rgb(1.0, 0.00, 0.0),
..Default::default()
},
..Default::default() ..Default::default()
}) })
.add_entity(UiEntity { .add_entity(UiEntity {
@ -91,10 +93,7 @@ fn setup(world: &mut World, resources: &mut Resources) {
Anchors::new(0.5, 0.5, 0.5, 0.5), Anchors::new(0.5, 0.5, 0.5, 0.5),
Margins::new(0.0, 100.0, 0.0, 100.0), Margins::new(0.0, 100.0, 0.0, 100.0),
), ),
rect: Rect { material: color_materials.add(Color::rgb(1.0, 0.3, 0.3).into()),
color: Color::rgb(1.0, 0.3, 0.3),
..Default::default()
},
..Default::default() ..Default::default()
}) })
.add_entity(UiEntity { .add_entity(UiEntity {
@ -103,10 +102,7 @@ fn setup(world: &mut World, resources: &mut Resources) {
Anchors::new(0.5, 0.5, 0.5, 0.5), Anchors::new(0.5, 0.5, 0.5, 0.5),
Margins::new(0.0, 100.0, 0.0, 100.0), Margins::new(0.0, 100.0, 0.0, 100.0),
), ),
rect: Rect { material: color_materials.add(Color::rgb(1.0, 0.5, 0.5).into()),
color: Color::rgb(1.0, 0.5, 0.5),
..Default::default()
},
..Default::default() ..Default::default()
}) })
.add_entity(UiEntity { .add_entity(UiEntity {
@ -115,10 +111,7 @@ fn setup(world: &mut World, resources: &mut Resources) {
Anchors::new(0.5, 0.5, 0.5, 0.5), Anchors::new(0.5, 0.5, 0.5, 0.5),
Margins::new(0.0, 100.0, 0.0, 100.0), Margins::new(0.0, 100.0, 0.0, 100.0),
), ),
rect: Rect { material: color_materials.add(Color::rgb(1.0, 0.7, 0.7).into()),
color: Color::rgb(1.0, 0.7, 0.7),
..Default::default()
},
..Default::default() ..Default::default()
}) })
// parenting // parenting
@ -128,10 +121,7 @@ fn setup(world: &mut World, resources: &mut Resources) {
Anchors::new(0.0, 0.0, 0.0, 0.0), Anchors::new(0.0, 0.0, 0.0, 0.0),
Margins::new(0.0, 200.0, 0.0, 200.0), Margins::new(0.0, 200.0, 0.0, 200.0),
), ),
rect: Rect { material: color_materials.add(Color::rgb(0.1, 0.1, 1.0).into()),
color: Color::rgb(0.1, 0.1, 1.0),
..Default::default()
},
..Default::default() ..Default::default()
}) })
.add_children(|builder| { .add_children(|builder| {
@ -141,10 +131,7 @@ fn setup(world: &mut World, resources: &mut Resources) {
Anchors::new(0.0, 1.0, 0.0, 1.0), Anchors::new(0.0, 1.0, 0.0, 1.0),
Margins::new(20.0, 20.0, 20.0, 20.0), Margins::new(20.0, 20.0, 20.0, 20.0),
), ),
rect: Rect { material: blue_material_handle,
color: Color::rgb(0.6, 0.6, 1.0),
..Default::default()
},
..Default::default() ..Default::default()
}); });
}) })
@ -155,10 +142,17 @@ fn setup(world: &mut World, resources: &mut Resources) {
Anchors::new(0.5, 0.5, 0.5, 0.5), Anchors::new(0.5, 0.5, 0.5, 0.5),
Margins::new(0.0, 100.0, 0.0, 100.0), Margins::new(0.0, 100.0, 0.0, 100.0),
), ),
rect: Rect { material: color_materials.add(Color::rgba(1.0, 0.9, 0.9, 0.4).into()),
color: Color::rgba(1.0, 0.9, 0.9, 0.4), ..Default::default()
..Default::default() })
}, // texture
.add_entity(UiEntity {
node: Node::new(
math::vec2(400.0, 100.0),
Anchors::new(0.0, 0.0, 0.0, 0.0),
Margins::new(0.0, 500.0, 0.0, 500.0 * aspect),
),
material: color_materials.add(ColorMaterial::texture(texture_handle)),
..Default::default() ..Default::default()
}); });
} }

View file

@ -1,11 +1,11 @@
use bevy::prelude::*; use bevy::prelude::*;
use bevy_ui::Rect; use bevy_ui::{ColorMaterial, Rect};
fn main() { fn main() {
App::build() App::build()
.add_default_plugins() .add_default_plugins()
.add_startup_system(setup) .add_startup_system(setup)
.add_system(move_system.system()) .add_system(placement_system.system())
.add_plugin(DiagnosticsPlugin { .add_plugin(DiagnosticsPlugin {
print_diagnostics: true, print_diagnostics: true,
..Default::default() ..Default::default()
@ -13,8 +13,14 @@ fn main() {
.run(); .run();
} }
fn move_system(time: Resource<Time>, mut node: RefMut<Node>, rect: Ref<Rect>) { fn placement_system(
if rect.color.r > 0.2 { time: Resource<Time>,
materials: Resource<AssetStorage<ColorMaterial>>,
mut node: RefMut<Node>,
material_handle: Ref<Handle<ColorMaterial>>,
) {
let material = materials.get(&material_handle).unwrap();
if material.color.r > 0.2 {
node.position += Vec2::new(0.1 * time.delta_seconds, 0.0); node.position += Vec2::new(0.1 * time.delta_seconds, 0.0);
} }
} }
@ -38,7 +44,7 @@ fn setup(world: &mut World, _resources: &mut Resources) {
Margins::new(0.0, 100.0, 0.0, 100.0), Margins::new(0.0, 100.0, 0.0, 100.0),
), ),
rect: Rect { rect: Rect {
color: Color::rgb(0.0 + i as f32 / count as f32, 0.1, 0.1), // color: Color::rgb(0.0 + i as f32 / count as f32, 0.1, 0.1),
..Default::default() ..Default::default()
}, },
..Default::default() ..Default::default()

View file

@ -32,7 +32,7 @@ pub use crate::render::{
#[cfg(feature = "transform")] #[cfg(feature = "transform")]
pub use crate::transform::prelude::*; pub use crate::transform::prelude::*;
#[cfg(feature = "ui")] #[cfg(feature = "ui")]
pub use crate::ui::{entity::*, Anchors, Margins, Node}; pub use crate::ui::{entity::*, Anchors, Margins, Node, ColorMaterial};
#[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::{