mirror of
https://github.com/bevyengine/bevy
synced 2024-11-10 07:04:33 +00:00
sprite: more sprite sheet work (not quite operable yet)
This commit is contained in:
parent
c9ae10a8a9
commit
13d56907ed
11 changed files with 115 additions and 74 deletions
|
@ -119,7 +119,7 @@ pub fn derive_uniform(input: TokenStream) -> TokenStream {
|
|||
}
|
||||
|
||||
fn get_field_bind_type(&self, name: &str) -> Option<#bevy_render_path::shader::FieldBindType> {
|
||||
use #bevy_render_path::shader::AsFieldBindType;
|
||||
use #bevy_render_path::shader::GetFieldBindType;
|
||||
match name {
|
||||
#struct_name_string => self.get_bind_type(),
|
||||
_ => None,
|
||||
|
@ -453,7 +453,7 @@ pub fn derive_uniforms(input: TokenStream) -> TokenStream {
|
|||
}
|
||||
|
||||
fn get_field_bind_type(&self, name: &str) -> Option<#bevy_render_path::shader::FieldBindType> {
|
||||
use #bevy_render_path::shader::AsFieldBindType;
|
||||
use #bevy_render_path::shader::GetFieldBindType;
|
||||
match name {
|
||||
#(#active_uniform_field_name_strings => self.#active_uniform_field_names.get_bind_type(),)*
|
||||
_ => None,
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use super::{BindGroupDescriptor, VertexBufferDescriptor, VertexBufferDescriptors};
|
||||
use crate::shader::ShaderLayout;
|
||||
use crate::shader::{GL_VERTEX_INDEX, ShaderLayout};
|
||||
use std::{collections::HashMap, hash::Hash};
|
||||
|
||||
#[derive(Clone, Debug, Default)]
|
||||
|
@ -65,6 +65,9 @@ impl PipelineLayout {
|
|||
vertex_buffer_descriptors.get(&vertex_buffer_descriptor.name)
|
||||
{
|
||||
vertex_buffer_descriptor.sync_with_descriptor(graph_descriptor);
|
||||
} else if vertex_buffer_descriptor.name == GL_VERTEX_INDEX {
|
||||
// GL_VERTEX_INDEX is a special attribute set on our behalf
|
||||
continue;
|
||||
} else {
|
||||
panic!(
|
||||
"Encountered unsupported Vertex Buffer: {}",
|
||||
|
@ -84,6 +87,7 @@ pub struct UniformProperty {
|
|||
#[derive(Hash, Clone, Debug, Eq, PartialEq, Ord, PartialOrd)]
|
||||
pub enum UniformPropertyType {
|
||||
// TODO: Use VertexFormat here
|
||||
UInt,
|
||||
Int,
|
||||
IVec2,
|
||||
Float,
|
||||
|
@ -100,6 +104,7 @@ pub enum UniformPropertyType {
|
|||
impl UniformPropertyType {
|
||||
pub fn get_size(&self) -> u64 {
|
||||
match self {
|
||||
UniformPropertyType::UInt => 4,
|
||||
UniformPropertyType::Int => 4,
|
||||
UniformPropertyType::IVec2 => 4 * 2,
|
||||
UniformPropertyType::Float => 4,
|
||||
|
|
|
@ -5,6 +5,7 @@ use crate::{
|
|||
},
|
||||
texture::{TextureComponentType, TextureViewDimension},
|
||||
};
|
||||
use bevy_core::bytes::AsBytes;
|
||||
use spirv_reflect::{
|
||||
types::{
|
||||
ReflectDescriptorBinding, ReflectDescriptorSet, ReflectDescriptorType, ReflectDimension,
|
||||
|
@ -12,7 +13,6 @@ use spirv_reflect::{
|
|||
},
|
||||
ShaderModule,
|
||||
};
|
||||
use bevy_core::bytes::AsBytes;
|
||||
use std::collections::HashSet;
|
||||
// use rspirv::{binary::Parser, dr::Loader, lift::LiftContext};
|
||||
|
||||
|
@ -35,6 +35,8 @@ pub struct ShaderLayout {
|
|||
pub entry_point: String,
|
||||
}
|
||||
|
||||
pub const GL_VERTEX_INDEX: &str = "gl_VertexIndex";
|
||||
|
||||
impl ShaderLayout {
|
||||
pub fn from_spirv(spirv_data: &[u32], bevy_conventions: bool) -> ShaderLayout {
|
||||
match ShaderModule::load_u8_data(spirv_data.as_bytes()) {
|
||||
|
@ -63,21 +65,25 @@ impl ShaderLayout {
|
|||
let mut instance = false;
|
||||
let current_buffer_name = {
|
||||
if bevy_conventions {
|
||||
let parts = vertex_attribute_descriptor
|
||||
.name
|
||||
.splitn(3, "_")
|
||||
.collect::<Vec<&str>>();
|
||||
if parts.len() == 3 {
|
||||
if parts[0] == "I" {
|
||||
instance = true;
|
||||
parts[1].to_string()
|
||||
} else {
|
||||
parts[0].to_string()
|
||||
}
|
||||
} else if parts.len() == 2 {
|
||||
parts[0].to_string()
|
||||
if vertex_attribute_descriptor.name == GL_VERTEX_INDEX {
|
||||
GL_VERTEX_INDEX.to_string()
|
||||
} else {
|
||||
panic!("Vertex attributes must follow the form BUFFERNAME_PROPERTYNAME. For example: Vertex_Position");
|
||||
let parts = vertex_attribute_descriptor
|
||||
.name
|
||||
.splitn(3, "_")
|
||||
.collect::<Vec<&str>>();
|
||||
if parts.len() == 3 {
|
||||
if parts[0] == "I" {
|
||||
instance = true;
|
||||
parts[1].to_string()
|
||||
} else {
|
||||
parts[0].to_string()
|
||||
}
|
||||
} else if parts.len() == 2 {
|
||||
parts[0].to_string()
|
||||
} else {
|
||||
panic!("Vertex attributes must follow the form BUFFERNAME_PROPERTYNAME. For example: Vertex_Position");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
"DefaultVertex".to_string()
|
||||
|
@ -279,6 +285,7 @@ fn reflect_uniform_numeric(type_description: &ReflectTypeDescription) -> Uniform
|
|||
}
|
||||
} else {
|
||||
match (number_type, traits.numeric.vector.component_count) {
|
||||
(NumberType::UInt, 0) => UniformPropertyType::UInt,
|
||||
(NumberType::Int, 0) => UniformPropertyType::Int,
|
||||
(NumberType::Int, 2) => UniformPropertyType::IVec2,
|
||||
(NumberType::Float, 0) => UniformPropertyType::Float,
|
||||
|
|
|
@ -71,6 +71,7 @@ impl ShaderDefSuffixProvider for bool {
|
|||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
pub enum FieldBindType {
|
||||
Uniform { size: usize },
|
||||
Buffer,
|
||||
Texture,
|
||||
}
|
||||
|
||||
|
@ -82,11 +83,11 @@ pub struct FieldInfo {
|
|||
pub is_instanceable: bool,
|
||||
}
|
||||
|
||||
pub trait AsFieldBindType {
|
||||
pub trait GetFieldBindType {
|
||||
fn get_bind_type(&self) -> Option<FieldBindType>;
|
||||
}
|
||||
|
||||
impl AsFieldBindType for ColorSource {
|
||||
impl GetFieldBindType for ColorSource {
|
||||
fn get_bind_type(&self) -> Option<FieldBindType> {
|
||||
match *self {
|
||||
ColorSource::Texture(_) => Some(FieldBindType::Texture),
|
||||
|
@ -95,7 +96,7 @@ impl AsFieldBindType for ColorSource {
|
|||
}
|
||||
}
|
||||
|
||||
impl AsFieldBindType for Option<Handle<Texture>> {
|
||||
impl GetFieldBindType for Option<Handle<Texture>> {
|
||||
fn get_bind_type(&self) -> Option<FieldBindType> {
|
||||
match *self {
|
||||
Some(_) => Some(FieldBindType::Texture),
|
||||
|
@ -104,13 +105,13 @@ impl AsFieldBindType for Option<Handle<Texture>> {
|
|||
}
|
||||
}
|
||||
|
||||
impl AsFieldBindType for Handle<Texture> {
|
||||
impl GetFieldBindType for Handle<Texture> {
|
||||
fn get_bind_type(&self) -> Option<FieldBindType> {
|
||||
Some(FieldBindType::Texture)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> AsFieldBindType for T
|
||||
impl<T> GetFieldBindType for T
|
||||
where
|
||||
T: Bytes,
|
||||
{
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use crate::{
|
||||
pipeline::{InputStepMode, VertexAttributeDescriptor, VertexBufferDescriptor, VertexFormat},
|
||||
shader::{AsFieldBindType, AsUniforms, FieldBindType, FieldInfo},
|
||||
shader::{GetFieldBindType, AsUniforms, FieldBindType, FieldInfo},
|
||||
texture::Texture,
|
||||
};
|
||||
use bevy_asset::Handle;
|
||||
|
|
|
@ -1,10 +1,9 @@
|
|||
use crate::{
|
||||
render::SPRITE_PIPELINE_HANDLE, sprite::Sprite, ColorMaterial, Quad, QUAD_HANDLE, SpriteSheet, SPRITE_SHEET_PIPELINE_HANDLE,
|
||||
render::SPRITE_PIPELINE_HANDLE, sprite::Sprite, ColorMaterial, Quad, QUAD_HANDLE, SpriteSheet, SPRITE_SHEET_PIPELINE_HANDLE, SpriteSheetSprite,
|
||||
};
|
||||
use bevy_asset::Handle;
|
||||
use bevy_derive::EntityArchetype;
|
||||
use bevy_render::{mesh::Mesh, Renderable};
|
||||
use bevy_transform::prelude::*;
|
||||
|
||||
#[derive(EntityArchetype)]
|
||||
pub struct SpriteEntity {
|
||||
|
@ -32,13 +31,14 @@ impl Default for SpriteEntity {
|
|||
|
||||
#[derive(EntityArchetype)]
|
||||
pub struct SpriteSheetEntity {
|
||||
pub sprite: Sprite,
|
||||
pub sprite: SpriteSheetSprite,
|
||||
pub sprite_sheet: Handle<SpriteSheet>,
|
||||
pub renderable: Renderable,
|
||||
pub local_to_world: LocalToWorld,
|
||||
pub translation: Translation,
|
||||
pub rotation: Rotation,
|
||||
pub scale: Scale,
|
||||
pub mesh: Handle<Mesh>, // TODO: maybe abstract this out
|
||||
// pub local_to_world: LocalToWorld,
|
||||
// pub translation: Translation,
|
||||
// pub rotation: Rotation,
|
||||
// pub scale: Scale,
|
||||
}
|
||||
|
||||
impl Default for SpriteSheetEntity {
|
||||
|
@ -50,10 +50,11 @@ impl Default for SpriteSheetEntity {
|
|||
pipelines: vec![SPRITE_SHEET_PIPELINE_HANDLE],
|
||||
..Default::default()
|
||||
},
|
||||
local_to_world: Default::default(),
|
||||
translation: Default::default(),
|
||||
rotation: Default::default(),
|
||||
scale: Default::default(),
|
||||
mesh: QUAD_HANDLE,
|
||||
// local_to_world: Default::default(),
|
||||
// translation: Default::default(),
|
||||
// rotation: Default::default(),
|
||||
// scale: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
use bevy_core::bytes::Byteable;
|
||||
use glam::Vec2;
|
||||
|
||||
/// A rectangle defined by two points. There is no defined origin, so 0,0 could be anywhere (top-left, bottom-left, etc)
|
||||
|
@ -18,4 +19,6 @@ impl Rect {
|
|||
pub fn height(&self) -> f32 {
|
||||
self.max.y() - self.min.y()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl Byteable for Rect {}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use crate::{ColorMaterial, Quad};
|
||||
use crate::{ColorMaterial, Quad, SpriteSheet, SpriteSheetSprite};
|
||||
use bevy_asset::{Assets, Handle};
|
||||
use bevy_render::{
|
||||
base_render_graph,
|
||||
|
@ -112,6 +112,8 @@ pub fn build_sprite_pipeline(shaders: &mut Assets<Shader>) -> PipelineDescriptor
|
|||
pub mod node {
|
||||
pub const COLOR_MATERIAL: &'static str = "color_material";
|
||||
pub const QUAD: &'static str = "quad";
|
||||
pub const SPRITE_SHEET: &'static str = "sprite_sheet";
|
||||
pub const SPRITE_SHEET_SPRITE: &'static str = "sprite_sheet_sprite";
|
||||
}
|
||||
|
||||
pub trait SpriteRenderGraphBuilder {
|
||||
|
@ -131,6 +133,16 @@ impl SpriteRenderGraphBuilder for RenderGraph {
|
|||
self.add_node_edge(node::QUAD, base_render_graph::node::MAIN_PASS)
|
||||
.unwrap();
|
||||
|
||||
self.add_system_node(
|
||||
node::SPRITE_SHEET,
|
||||
AssetUniformNode::<SpriteSheet>::new(true),
|
||||
);
|
||||
|
||||
self.add_system_node(
|
||||
node::SPRITE_SHEET_SPRITE,
|
||||
UniformNode::<SpriteSheetSprite>::new(true),
|
||||
);
|
||||
|
||||
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));
|
||||
|
|
|
@ -1,9 +1,22 @@
|
|||
#version 450
|
||||
|
||||
// sprite
|
||||
layout(location = 0) in vec3 Sprite_Position;
|
||||
// this is a vec2 instead of an int due to WebGPU limitations
|
||||
layout(location = 1) in ivec2 Sprite_Index;
|
||||
layout(location = 0) in vec3 Vertex_Position;
|
||||
layout(location = 1) in vec3 Vertex_Normal;
|
||||
layout(location = 2) in vec2 Vertex_Uv;
|
||||
|
||||
// TODO: consider swapping explicit mesh binding for this const
|
||||
// const vec2 positions[4] = vec2[](
|
||||
// vec2(0.5, -0.5),
|
||||
// vec2(-0.5, -0.5),
|
||||
// vec2(0.5, 0.5),
|
||||
// vec2(-0.5, 0.5)
|
||||
// );
|
||||
|
||||
// TODO: uncomment when instancing is implemented
|
||||
// sprite
|
||||
// layout(location = 0) in vec3 Sprite_Position;
|
||||
// // this is a vec2 instead of an int due to WebGPU limitations
|
||||
// layout(location = 1) in int Sprite_Index;
|
||||
|
||||
layout(location = 0) out vec2 v_Uv;
|
||||
|
||||
|
@ -16,21 +29,19 @@ struct Rect {
|
|||
vec2 end;
|
||||
};
|
||||
|
||||
layout(set = 1, binding = 0) buffer SpriteSheet {
|
||||
Rect[] SpriteSheet_sprites;
|
||||
layout(set = 1, binding = 0) buffer SpriteSheet_sprites {
|
||||
Rect[] Sprites;
|
||||
};
|
||||
|
||||
const vec2 positions[4] = vec2[](
|
||||
vec2(0.5, -0.5),
|
||||
vec2(-0.5, -0.5),
|
||||
vec2(0.5, 0.5),
|
||||
vec2(-0.5, 0.5)
|
||||
);
|
||||
layout(set = 2, binding = 0) uniform SpriteSheetSprite {
|
||||
vec3 SpriteSheetSprite_position;
|
||||
uint SpriteSheetSprite_index;
|
||||
};
|
||||
|
||||
void main() {
|
||||
Rect sprite_rect = SpriteSheet_sprites[Sprite_Index.x];
|
||||
Rect sprite_rect = Sprites[SpriteSheetSprite_index];
|
||||
vec2 dimensions = sprite_rect.end - sprite_rect.begin;
|
||||
vec2 vertex_position = positions[gl_VertexIndex] * dimensions;
|
||||
vec2 vertex_position = Vertex_Position.xy * dimensions;
|
||||
vec2 uvs[4] = vec2[](
|
||||
vec2(sprite_rect.end.x, sprite_rect.begin.y),
|
||||
sprite_rect.begin,
|
||||
|
@ -38,5 +49,5 @@ void main() {
|
|||
vec2(sprite_rect.begin.x, sprite_rect.end.y)
|
||||
);
|
||||
v_Uv = uvs[gl_VertexIndex];
|
||||
gl_Position = ViewProj * vec4(vec3(vertex_position, 0.0) + Sprite_Position, 1.0);
|
||||
gl_Position = ViewProj * vec4(vec3(vertex_position, 0.0) + SpriteSheetSprite_position, 1.0);
|
||||
}
|
|
@ -1,29 +1,30 @@
|
|||
use crate::Rect;
|
||||
use bevy_app::{Events, GetEventReader};
|
||||
use bevy_asset::{AssetEvent, Assets, Handle};
|
||||
use bevy_derive::{Uniform, Bytes};
|
||||
use bevy_core::bytes::AsBytes;
|
||||
use bevy_derive::{Bytes, Uniform, Uniforms};
|
||||
use bevy_render::{
|
||||
render_resource::{BufferInfo, BufferUsage, RenderResourceAssignment, ResourceInfo},
|
||||
renderer::{RenderResourceContext, RenderResources},
|
||||
texture::Texture,
|
||||
Renderable,
|
||||
};
|
||||
use glam::{Vec3, Vec4};
|
||||
use legion::prelude::*;
|
||||
use std::collections::HashSet;
|
||||
use glam::{Vec4, Vec3};
|
||||
|
||||
#[derive(Uniforms)]
|
||||
pub struct SpriteSheet {
|
||||
pub texture: Handle<Texture>,
|
||||
pub sprites: Vec<Rect>,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Uniform, Bytes)]
|
||||
// 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. https://github.com/bitshifter/glam-rs/issues/36
|
||||
#[derive(Uniform, Bytes, Default)]
|
||||
pub struct SpriteSheetSprite {
|
||||
#[uniform(vertex)]
|
||||
pub postition: Vec4,
|
||||
#[uniform(vertex)]
|
||||
pub index: u16,
|
||||
pub position: Vec3,
|
||||
pub index: u32,
|
||||
}
|
||||
|
||||
pub const SPRITE_SHEET_BUFFER_ASSET_INDEX: usize = 0;
|
||||
|
@ -69,20 +70,20 @@ pub fn sprite_sheet_resource_provider_system(resources: &mut Resources) -> Box<d
|
|||
|
||||
for changed_sprite_sheet_handle in changed_sprite_sheets.iter() {
|
||||
if let Some(sprite_sheet) = sprite_sheets.get(changed_sprite_sheet_handle) {
|
||||
// let sprite_sheet_bytes = sprite_sheet.sprites.as_bytes();
|
||||
// let sprite_sheet_buffer = render_resources.create_buffer_with_data(
|
||||
// BufferInfo {
|
||||
// buffer_usage: BufferUsage::STORAGE,
|
||||
// ..Default::default()
|
||||
// },
|
||||
// &sprite_sheet_bytes,
|
||||
// );
|
||||
let sprite_sheet_bytes = sprite_sheet.sprites.as_slice().as_bytes();
|
||||
let sprite_sheet_buffer = render_resources.create_buffer_with_data(
|
||||
BufferInfo {
|
||||
buffer_usage: BufferUsage::STORAGE,
|
||||
..Default::default()
|
||||
},
|
||||
&sprite_sheet_bytes,
|
||||
);
|
||||
|
||||
// render_resources.set_asset_resource(
|
||||
// *changed_sprite_sheet_handle,
|
||||
// sprite_sheet_buffer,
|
||||
// SPRITE_SHEET_BUFFER_ASSET_INDEX,
|
||||
// );
|
||||
render_resources.set_asset_resource(
|
||||
*changed_sprite_sheet_handle,
|
||||
sprite_sheet_buffer,
|
||||
SPRITE_SHEET_BUFFER_ASSET_INDEX,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -15,4 +15,4 @@ impl AppPlugin for TextPlugin {
|
|||
app.add_asset::<Font>()
|
||||
.add_asset_loader::<Font, FontLoader>();
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue