mirror of
https://github.com/bevyengine/bevy
synced 2024-11-10 07:04:33 +00:00
sprite: add color to TextureAtlasSprite and make Vec3 16 bytes again to account for glsl UBO layout
This commit is contained in:
parent
17d70f7d67
commit
faacd2778d
13 changed files with 81 additions and 65 deletions
|
@ -91,58 +91,11 @@ unsafe impl Byteable for i64 {}
|
||||||
unsafe impl Byteable for isize {}
|
unsafe impl Byteable for isize {}
|
||||||
unsafe impl Byteable for f32 {}
|
unsafe impl Byteable for f32 {}
|
||||||
unsafe impl Byteable for f64 {}
|
unsafe impl Byteable for f64 {}
|
||||||
|
unsafe impl Byteable for Vec2 {}
|
||||||
impl Bytes for Vec2 {
|
// NOTE: Vec3 actually takes up the size of 4 floats / 16 bytes due to SIMD. This is actually convenient because GLSL
|
||||||
fn write_bytes(&self, buffer: &mut [u8]) {
|
// uniform buffer objects pad Vec3s to be 16 bytes.
|
||||||
let array: [f32; 2] = (*self).into();
|
unsafe impl Byteable for Vec3 {}
|
||||||
array.write_bytes(buffer);
|
unsafe impl Byteable for Vec4 {}
|
||||||
}
|
|
||||||
fn byte_len(&self) -> usize {
|
|
||||||
std::mem::size_of::<Self>()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl FromBytes for Vec2 {
|
|
||||||
fn from_bytes(bytes: &[u8]) -> Self {
|
|
||||||
let array = <[f32; 2]>::from_bytes(bytes);
|
|
||||||
Vec2::from(array)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Bytes for Vec3 {
|
|
||||||
fn write_bytes(&self, buffer: &mut [u8]) {
|
|
||||||
let array: [f32; 3] = (*self).into();
|
|
||||||
array.write_bytes(buffer);
|
|
||||||
}
|
|
||||||
fn byte_len(&self) -> usize {
|
|
||||||
// cant use self here because Vec3 is a simd type / technically a vec4
|
|
||||||
std::mem::size_of::<[f32; 3]>()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl FromBytes for Vec3 {
|
|
||||||
fn from_bytes(bytes: &[u8]) -> Self {
|
|
||||||
let array = <[f32; 3]>::from_bytes(bytes);
|
|
||||||
Vec3::from(array)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Bytes for Vec4 {
|
|
||||||
fn write_bytes(&self, buffer: &mut [u8]) {
|
|
||||||
let array: [f32; 4] = (*self).into();
|
|
||||||
array.write_bytes(buffer);
|
|
||||||
}
|
|
||||||
fn byte_len(&self) -> usize {
|
|
||||||
std::mem::size_of::<Self>()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl FromBytes for Vec4 {
|
|
||||||
fn from_bytes(bytes: &[u8]) -> Self {
|
|
||||||
let array = <[f32; 4]>::from_bytes(bytes);
|
|
||||||
Vec4::from(array)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Bytes for Mat4 {
|
impl Bytes for Mat4 {
|
||||||
fn write_bytes(&self, buffer: &mut [u8]) {
|
fn write_bytes(&self, buffer: &mut [u8]) {
|
||||||
|
|
|
@ -25,7 +25,7 @@ impl AppPlugin for PbrPlugin {
|
||||||
.register_component::<Light>()
|
.register_component::<Light>()
|
||||||
.add_system_to_stage(
|
.add_system_to_stage(
|
||||||
stage::POST_UPDATE,
|
stage::POST_UPDATE,
|
||||||
shader::asset_shader_def_system::<StandardMaterial>.system(),
|
shader::asset_shader_defs_system::<StandardMaterial>.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();
|
||||||
|
|
|
@ -219,6 +219,7 @@ impl<'a> DrawContext<'a> {
|
||||||
specialization,
|
specialization,
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
|
|
||||||
draw.set_pipeline(specialized_pipeline);
|
draw.set_pipeline(specialized_pipeline);
|
||||||
self.current_pipeline = Some(specialized_pipeline);
|
self.current_pipeline = Some(specialized_pipeline);
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
|
@ -41,6 +41,7 @@ use mesh::mesh_resource_provider_system;
|
||||||
use pipeline::{draw_render_pipelines_system, RenderPipelines};
|
use pipeline::{draw_render_pipelines_system, RenderPipelines};
|
||||||
use render_graph::{system::render_graph_schedule_executor_system, RenderGraph};
|
use render_graph::{system::render_graph_schedule_executor_system, RenderGraph};
|
||||||
use render_resource::AssetRenderResourceBindings;
|
use render_resource::AssetRenderResourceBindings;
|
||||||
|
use shader::clear_shader_defs_system;
|
||||||
use std::ops::Range;
|
use std::ops::Range;
|
||||||
use texture::{PngTextureLoader, TextureResourceSystemState};
|
use texture::{PngTextureLoader, TextureResourceSystemState};
|
||||||
|
|
||||||
|
@ -112,7 +113,8 @@ impl AppPlugin for RenderPlugin {
|
||||||
stage::RENDER_GRAPH_SYSTEMS,
|
stage::RENDER_GRAPH_SYSTEMS,
|
||||||
render_graph_schedule_executor_system,
|
render_graph_schedule_executor_system,
|
||||||
)
|
)
|
||||||
.add_system_to_stage(stage::DRAW, draw_render_pipelines_system.system());
|
.add_system_to_stage(stage::DRAW, draw_render_pipelines_system.system())
|
||||||
|
.add_system_to_stage(stage::POST_RENDER, clear_shader_defs_system.system());
|
||||||
|
|
||||||
if let Some(ref config) = self.base_render_graph_config {
|
if let Some(ref config) = self.base_render_graph_config {
|
||||||
let resources = app.resources();
|
let resources = app.resources();
|
||||||
|
|
|
@ -14,7 +14,7 @@ impl PipelineLayout {
|
||||||
.iter()
|
.iter()
|
||||||
.find(|bind_group| bind_group.index == index)
|
.find(|bind_group| bind_group.index == index)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_shader_layouts(shader_layouts: &mut [ShaderLayout]) -> Self {
|
pub fn from_shader_layouts(shader_layouts: &mut [ShaderLayout]) -> Self {
|
||||||
let mut bind_groups = HashMap::<u32, BindGroupDescriptor>::new();
|
let mut bind_groups = HashMap::<u32, BindGroupDescriptor>::new();
|
||||||
let mut vertex_buffer_descriptors = Vec::new();
|
let mut vertex_buffer_descriptors = Vec::new();
|
||||||
|
|
|
@ -55,7 +55,7 @@ impl ShaderDef for Option<Handle<Texture>> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn shader_def_system<T>(shader_defs: Com<T>, mut render_pipelines: ComMut<RenderPipelines>)
|
pub fn shader_defs_system<T>(shader_defs: Com<T>, mut render_pipelines: ComMut<RenderPipelines>)
|
||||||
where
|
where
|
||||||
T: ShaderDefs + Send + Sync + 'static,
|
T: ShaderDefs + Send + Sync + 'static,
|
||||||
{
|
{
|
||||||
|
@ -70,7 +70,17 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn asset_shader_def_system<T>(
|
pub fn clear_shader_defs_system(mut render_pipelines: ComMut<RenderPipelines>) {
|
||||||
|
for render_pipeline in render_pipelines.pipelines.iter_mut() {
|
||||||
|
render_pipeline
|
||||||
|
.specialization
|
||||||
|
.shader_specialization
|
||||||
|
.shader_defs
|
||||||
|
.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn asset_shader_defs_system<T>(
|
||||||
assets: Res<Assets<T>>,
|
assets: Res<Assets<T>>,
|
||||||
asset_handle: Com<Handle<T>>,
|
asset_handle: Com<Handle<T>>,
|
||||||
mut render_pipelines: ComMut<RenderPipelines>,
|
mut render_pipelines: ComMut<RenderPipelines>,
|
||||||
|
|
|
@ -22,7 +22,7 @@ use bevy_asset::{AddAsset, Assets, Handle};
|
||||||
use bevy_render::{
|
use bevy_render::{
|
||||||
mesh::{shape, Mesh},
|
mesh::{shape, Mesh},
|
||||||
render_graph::RenderGraph,
|
render_graph::RenderGraph,
|
||||||
shader::asset_shader_def_system,
|
shader::asset_shader_defs_system,
|
||||||
};
|
};
|
||||||
use glam::Vec2;
|
use glam::Vec2;
|
||||||
use legion::prelude::IntoSystem;
|
use legion::prelude::IntoSystem;
|
||||||
|
@ -40,7 +40,7 @@ impl AppPlugin for SpritePlugin {
|
||||||
.add_system_to_stage(stage::POST_UPDATE, sprite_system())
|
.add_system_to_stage(stage::POST_UPDATE, sprite_system())
|
||||||
.add_system_to_stage(
|
.add_system_to_stage(
|
||||||
stage::POST_UPDATE,
|
stage::POST_UPDATE,
|
||||||
asset_shader_def_system::<ColorMaterial>.system(),
|
asset_shader_defs_system::<ColorMaterial>.system(),
|
||||||
);
|
);
|
||||||
|
|
||||||
let resources = app.resources();
|
let resources = app.resources();
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#version 450
|
#version 450
|
||||||
|
|
||||||
layout(location = 0) in vec2 v_Uv;
|
layout(location = 0) in vec2 v_Uv;
|
||||||
|
layout(location = 1) in vec4 v_Color;
|
||||||
|
|
||||||
layout(location = 0) out vec4 o_Target;
|
layout(location = 0) out vec4 o_Target;
|
||||||
|
|
||||||
|
@ -8,7 +9,7 @@ layout(set = 1, binding = 2) uniform texture2D TextureAtlas_texture;
|
||||||
layout(set = 1, binding = 3) uniform sampler TextureAtlas_texture_sampler;
|
layout(set = 1, binding = 3) uniform sampler TextureAtlas_texture_sampler;
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
o_Target = texture(
|
o_Target = v_Color * texture(
|
||||||
sampler2D(TextureAtlas_texture, TextureAtlas_texture_sampler),
|
sampler2D(TextureAtlas_texture, TextureAtlas_texture_sampler),
|
||||||
v_Uv);
|
v_Uv);
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,7 @@ 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 vec2 v_Uv;
|
layout(location = 0) out vec2 v_Uv;
|
||||||
|
layout(location = 1) out vec4 v_Color;
|
||||||
|
|
||||||
// TODO: remove UI shader def and replace with generic "Camera" when its easier to manually bind global RenderResourceBindings
|
// TODO: remove UI shader def and replace with generic "Camera" when its easier to manually bind global RenderResourceBindings
|
||||||
#ifdef UI_CAMERA
|
#ifdef UI_CAMERA
|
||||||
|
@ -34,6 +35,7 @@ layout(set = 1, binding = 1) buffer TextureAtlas_textures {
|
||||||
|
|
||||||
layout(set = 2, binding = 0) uniform TextureAtlasSprite {
|
layout(set = 2, binding = 0) uniform TextureAtlasSprite {
|
||||||
vec3 TextureAtlasSprite_position;
|
vec3 TextureAtlasSprite_position;
|
||||||
|
vec4 TextureAtlasSprite_color;
|
||||||
float TextureAtlasSprite_scale;
|
float TextureAtlasSprite_scale;
|
||||||
uint TextureAtlasSprite_index;
|
uint TextureAtlasSprite_index;
|
||||||
};
|
};
|
||||||
|
@ -41,7 +43,7 @@ layout(set = 2, binding = 0) uniform TextureAtlasSprite {
|
||||||
void main() {
|
void main() {
|
||||||
Rect sprite_rect = Textures[TextureAtlasSprite_index];
|
Rect sprite_rect = Textures[TextureAtlasSprite_index];
|
||||||
vec2 sprite_dimensions = sprite_rect.end - sprite_rect.begin;
|
vec2 sprite_dimensions = sprite_rect.end - sprite_rect.begin;
|
||||||
vec3 vertex_position = vec3(Vertex_Position.xy * sprite_dimensions * TextureAtlasSprite_scale, 0.0) + TextureAtlasSprite_position;
|
vec3 vertex_position = vec3(Vertex_Position.xy * sprite_dimensions * TextureAtlasSprite_scale, 0.0) + TextureAtlasSprite_position.xyz;
|
||||||
vec2 uvs[4] = vec2[](
|
vec2 uvs[4] = vec2[](
|
||||||
vec2(sprite_rect.begin.x, sprite_rect.end.y),
|
vec2(sprite_rect.begin.x, sprite_rect.end.y),
|
||||||
sprite_rect.begin,
|
sprite_rect.begin,
|
||||||
|
@ -49,5 +51,6 @@ void main() {
|
||||||
sprite_rect.end
|
sprite_rect.end
|
||||||
);
|
);
|
||||||
v_Uv = uvs[gl_VertexIndex] / AtlasSize;
|
v_Uv = uvs[gl_VertexIndex] / AtlasSize;
|
||||||
|
v_Color = TextureAtlasSprite_color;
|
||||||
gl_Position = ViewProj * vec4(vertex_position, 1.0);
|
gl_Position = ViewProj * vec4(vertex_position, 1.0);
|
||||||
}
|
}
|
|
@ -4,6 +4,7 @@ use bevy_core::bytes::Bytes;
|
||||||
use bevy_render::{
|
use bevy_render::{
|
||||||
render_resource::{RenderResource, RenderResources},
|
render_resource::{RenderResource, RenderResources},
|
||||||
texture::Texture,
|
texture::Texture,
|
||||||
|
Color,
|
||||||
};
|
};
|
||||||
use glam::{Vec2, Vec3};
|
use glam::{Vec2, Vec3};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
@ -21,14 +22,26 @@ pub struct TextureAtlas {
|
||||||
|
|
||||||
// NOTE: cannot do `unsafe impl Byteable` here because Vec3 takes up the space of a Vec4. If/when glam changes this we can swap out
|
// NOTE: cannot do `unsafe impl Byteable` here because Vec3 takes up the space of a Vec4. If/when glam changes this we can swap out
|
||||||
// Bytes for Byteable as a micro-optimization. https://github.com/bitshifter/glam-rs/issues/36
|
// Bytes for Byteable as a micro-optimization. https://github.com/bitshifter/glam-rs/issues/36
|
||||||
#[derive(Bytes, RenderResources, RenderResource, Default)]
|
#[derive(Bytes, RenderResources, RenderResource)]
|
||||||
#[render_resources(from_self)]
|
#[render_resources(from_self)]
|
||||||
pub struct TextureAtlasSprite {
|
pub struct TextureAtlasSprite {
|
||||||
pub position: Vec3,
|
pub position: Vec3,
|
||||||
|
pub color: Color,
|
||||||
pub scale: f32,
|
pub scale: f32,
|
||||||
pub index: u32,
|
pub index: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Default for TextureAtlasSprite {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
index: 0,
|
||||||
|
color: Color::WHITE,
|
||||||
|
scale: 1.0,
|
||||||
|
position: Default::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl TextureAtlas {
|
impl TextureAtlas {
|
||||||
pub fn new_empty(texture: Handle<Texture>, dimensions: Vec2) -> Self {
|
pub fn new_empty(texture: Handle<Texture>, dimensions: Vec2) -> Self {
|
||||||
Self {
|
Self {
|
||||||
|
@ -81,3 +94,36 @@ impl TextureAtlas {
|
||||||
.and_then(|texture_handles| texture_handles.get(&texture).cloned())
|
.and_then(|texture_handles| texture_handles.get(&texture).cloned())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use crate::TextureAtlasSprite;
|
||||||
|
use bevy_core::bytes::{Bytes, FromBytes};
|
||||||
|
use bevy_render::Color;
|
||||||
|
use glam::Vec3;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_atlas_byte_conversion() {
|
||||||
|
let x = TextureAtlasSprite {
|
||||||
|
color: Color::RED,
|
||||||
|
index: 2,
|
||||||
|
position: Vec3::new(1., 2., 3.),
|
||||||
|
scale: 4.0,
|
||||||
|
};
|
||||||
|
|
||||||
|
assert_eq!(x.byte_len(), 36);
|
||||||
|
let mut bytes = vec![0; x.byte_len()];
|
||||||
|
|
||||||
|
x.write_bytes(&mut bytes);
|
||||||
|
|
||||||
|
let position = Vec3::from_bytes(&bytes[0..12]);
|
||||||
|
let color = Color::from_bytes(&bytes[12..28]);
|
||||||
|
let scale = f32::from_bytes(&bytes[28..32]);
|
||||||
|
let index = u32::from_bytes(&bytes[32..36]);
|
||||||
|
|
||||||
|
assert_eq!(position, x.position);
|
||||||
|
assert_eq!(color, x.color);
|
||||||
|
assert_eq!(scale, x.scale);
|
||||||
|
assert_eq!(index, x.index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -132,6 +132,7 @@ impl<'a> Drawable for DrawableText<'a> {
|
||||||
let offset = scaled_font.descent() + glyph_height;
|
let offset = scaled_font.descent() + glyph_height;
|
||||||
let sprite_buffer = TextureAtlasSprite {
|
let sprite_buffer = TextureAtlasSprite {
|
||||||
index: glyph_atlas_info.char_index,
|
index: glyph_atlas_info.char_index,
|
||||||
|
color: self.style.color,
|
||||||
position: caret
|
position: caret
|
||||||
+ Vec3::new(
|
+ Vec3::new(
|
||||||
0.0 + glyph_width / 2.0 + bounds.min.x,
|
0.0 + glyph_width / 2.0 + bounds.min.x,
|
||||||
|
|
|
@ -42,9 +42,8 @@ fn setup(
|
||||||
.add_entity(SpriteSheetEntity {
|
.add_entity(SpriteSheetEntity {
|
||||||
texture_atlas: texture_atlas_handle,
|
texture_atlas: texture_atlas_handle,
|
||||||
sprite: TextureAtlasSprite {
|
sprite: TextureAtlasSprite {
|
||||||
index: 0,
|
|
||||||
scale: 6.0,
|
scale: 6.0,
|
||||||
position: Vec3::new(0.0, 0.0, 0.0),
|
..Default::default()
|
||||||
},
|
},
|
||||||
..Default::default()
|
..Default::default()
|
||||||
})
|
})
|
||||||
|
|
|
@ -8,7 +8,7 @@ fn main() {
|
||||||
.add_startup_system(setup.system())
|
.add_startup_system(setup.system())
|
||||||
.add_system_to_stage(
|
.add_system_to_stage(
|
||||||
stage::POST_UPDATE,
|
stage::POST_UPDATE,
|
||||||
shader::asset_shader_def_system::<MyMaterial>.system(),
|
shader::asset_shader_defs_system::<MyMaterial>.system(),
|
||||||
)
|
)
|
||||||
.run();
|
.run();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue