sprite: more sprite sheet work (not quite operable yet)

This commit is contained in:
Carter Anderson 2020-06-03 11:39:10 -07:00
parent c9ae10a8a9
commit 13d56907ed
11 changed files with 115 additions and 74 deletions

View File

@ -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> { 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 { match name {
#struct_name_string => self.get_bind_type(), #struct_name_string => self.get_bind_type(),
_ => None, _ => 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> { 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 { match name {
#(#active_uniform_field_name_strings => self.#active_uniform_field_names.get_bind_type(),)* #(#active_uniform_field_name_strings => self.#active_uniform_field_names.get_bind_type(),)*
_ => None, _ => None,

View File

@ -1,5 +1,5 @@
use super::{BindGroupDescriptor, VertexBufferDescriptor, VertexBufferDescriptors}; use super::{BindGroupDescriptor, VertexBufferDescriptor, VertexBufferDescriptors};
use crate::shader::ShaderLayout; use crate::shader::{GL_VERTEX_INDEX, ShaderLayout};
use std::{collections::HashMap, hash::Hash}; use std::{collections::HashMap, hash::Hash};
#[derive(Clone, Debug, Default)] #[derive(Clone, Debug, Default)]
@ -65,6 +65,9 @@ impl PipelineLayout {
vertex_buffer_descriptors.get(&vertex_buffer_descriptor.name) vertex_buffer_descriptors.get(&vertex_buffer_descriptor.name)
{ {
vertex_buffer_descriptor.sync_with_descriptor(graph_descriptor); 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 { } else {
panic!( panic!(
"Encountered unsupported Vertex Buffer: {}", "Encountered unsupported Vertex Buffer: {}",
@ -84,6 +87,7 @@ pub struct UniformProperty {
#[derive(Hash, Clone, Debug, Eq, PartialEq, Ord, PartialOrd)] #[derive(Hash, Clone, Debug, Eq, PartialEq, Ord, PartialOrd)]
pub enum UniformPropertyType { pub enum UniformPropertyType {
// TODO: Use VertexFormat here // TODO: Use VertexFormat here
UInt,
Int, Int,
IVec2, IVec2,
Float, Float,
@ -100,6 +104,7 @@ pub enum UniformPropertyType {
impl UniformPropertyType { impl UniformPropertyType {
pub fn get_size(&self) -> u64 { pub fn get_size(&self) -> u64 {
match self { match self {
UniformPropertyType::UInt => 4,
UniformPropertyType::Int => 4, UniformPropertyType::Int => 4,
UniformPropertyType::IVec2 => 4 * 2, UniformPropertyType::IVec2 => 4 * 2,
UniformPropertyType::Float => 4, UniformPropertyType::Float => 4,

View File

@ -5,6 +5,7 @@ use crate::{
}, },
texture::{TextureComponentType, TextureViewDimension}, texture::{TextureComponentType, TextureViewDimension},
}; };
use bevy_core::bytes::AsBytes;
use spirv_reflect::{ use spirv_reflect::{
types::{ types::{
ReflectDescriptorBinding, ReflectDescriptorSet, ReflectDescriptorType, ReflectDimension, ReflectDescriptorBinding, ReflectDescriptorSet, ReflectDescriptorType, ReflectDimension,
@ -12,7 +13,6 @@ use spirv_reflect::{
}, },
ShaderModule, ShaderModule,
}; };
use bevy_core::bytes::AsBytes;
use std::collections::HashSet; use std::collections::HashSet;
// use rspirv::{binary::Parser, dr::Loader, lift::LiftContext}; // use rspirv::{binary::Parser, dr::Loader, lift::LiftContext};
@ -35,6 +35,8 @@ pub struct ShaderLayout {
pub entry_point: String, pub entry_point: String,
} }
pub const GL_VERTEX_INDEX: &str = "gl_VertexIndex";
impl ShaderLayout { impl ShaderLayout {
pub fn from_spirv(spirv_data: &[u32], bevy_conventions: bool) -> ShaderLayout { pub fn from_spirv(spirv_data: &[u32], bevy_conventions: bool) -> ShaderLayout {
match ShaderModule::load_u8_data(spirv_data.as_bytes()) { match ShaderModule::load_u8_data(spirv_data.as_bytes()) {
@ -63,21 +65,25 @@ impl ShaderLayout {
let mut instance = false; let mut instance = false;
let current_buffer_name = { let current_buffer_name = {
if bevy_conventions { if bevy_conventions {
let parts = vertex_attribute_descriptor if vertex_attribute_descriptor.name == GL_VERTEX_INDEX {
.name GL_VERTEX_INDEX.to_string()
.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 { } 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 { } else {
"DefaultVertex".to_string() "DefaultVertex".to_string()
@ -279,6 +285,7 @@ fn reflect_uniform_numeric(type_description: &ReflectTypeDescription) -> Uniform
} }
} else { } else {
match (number_type, traits.numeric.vector.component_count) { match (number_type, traits.numeric.vector.component_count) {
(NumberType::UInt, 0) => UniformPropertyType::UInt,
(NumberType::Int, 0) => UniformPropertyType::Int, (NumberType::Int, 0) => UniformPropertyType::Int,
(NumberType::Int, 2) => UniformPropertyType::IVec2, (NumberType::Int, 2) => UniformPropertyType::IVec2,
(NumberType::Float, 0) => UniformPropertyType::Float, (NumberType::Float, 0) => UniformPropertyType::Float,

View File

@ -71,6 +71,7 @@ impl ShaderDefSuffixProvider for bool {
#[derive(Clone, Debug, Eq, PartialEq)] #[derive(Clone, Debug, Eq, PartialEq)]
pub enum FieldBindType { pub enum FieldBindType {
Uniform { size: usize }, Uniform { size: usize },
Buffer,
Texture, Texture,
} }
@ -82,11 +83,11 @@ pub struct FieldInfo {
pub is_instanceable: bool, pub is_instanceable: bool,
} }
pub trait AsFieldBindType { pub trait GetFieldBindType {
fn get_bind_type(&self) -> Option<FieldBindType>; fn get_bind_type(&self) -> Option<FieldBindType>;
} }
impl AsFieldBindType for ColorSource { impl GetFieldBindType for ColorSource {
fn get_bind_type(&self) -> Option<FieldBindType> { fn get_bind_type(&self) -> Option<FieldBindType> {
match *self { match *self {
ColorSource::Texture(_) => Some(FieldBindType::Texture), 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> { fn get_bind_type(&self) -> Option<FieldBindType> {
match *self { match *self {
Some(_) => Some(FieldBindType::Texture), 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> { fn get_bind_type(&self) -> Option<FieldBindType> {
Some(FieldBindType::Texture) Some(FieldBindType::Texture)
} }
} }
impl<T> AsFieldBindType for T impl<T> GetFieldBindType for T
where where
T: Bytes, T: Bytes,
{ {

View File

@ -1,6 +1,6 @@
use crate::{ use crate::{
pipeline::{InputStepMode, VertexAttributeDescriptor, VertexBufferDescriptor, VertexFormat}, pipeline::{InputStepMode, VertexAttributeDescriptor, VertexBufferDescriptor, VertexFormat},
shader::{AsFieldBindType, AsUniforms, FieldBindType, FieldInfo}, shader::{GetFieldBindType, AsUniforms, FieldBindType, FieldInfo},
texture::Texture, texture::Texture,
}; };
use bevy_asset::Handle; use bevy_asset::Handle;

View File

@ -1,10 +1,9 @@
use crate::{ 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_asset::Handle;
use bevy_derive::EntityArchetype; use bevy_derive::EntityArchetype;
use bevy_render::{mesh::Mesh, Renderable}; use bevy_render::{mesh::Mesh, Renderable};
use bevy_transform::prelude::*;
#[derive(EntityArchetype)] #[derive(EntityArchetype)]
pub struct SpriteEntity { pub struct SpriteEntity {
@ -32,13 +31,14 @@ impl Default for SpriteEntity {
#[derive(EntityArchetype)] #[derive(EntityArchetype)]
pub struct SpriteSheetEntity { pub struct SpriteSheetEntity {
pub sprite: Sprite, pub sprite: SpriteSheetSprite,
pub sprite_sheet: Handle<SpriteSheet>, pub sprite_sheet: Handle<SpriteSheet>,
pub renderable: Renderable, pub renderable: Renderable,
pub local_to_world: LocalToWorld, pub mesh: Handle<Mesh>, // TODO: maybe abstract this out
pub translation: Translation, // pub local_to_world: LocalToWorld,
pub rotation: Rotation, // pub translation: Translation,
pub scale: Scale, // pub rotation: Rotation,
// pub scale: Scale,
} }
impl Default for SpriteSheetEntity { impl Default for SpriteSheetEntity {
@ -50,10 +50,11 @@ impl Default for SpriteSheetEntity {
pipelines: vec![SPRITE_SHEET_PIPELINE_HANDLE], pipelines: vec![SPRITE_SHEET_PIPELINE_HANDLE],
..Default::default() ..Default::default()
}, },
local_to_world: Default::default(), mesh: QUAD_HANDLE,
translation: Default::default(), // local_to_world: Default::default(),
rotation: Default::default(), // translation: Default::default(),
scale: Default::default(), // rotation: Default::default(),
// scale: Default::default(),
} }
} }
} }

View File

@ -1,3 +1,4 @@
use bevy_core::bytes::Byteable;
use glam::Vec2; 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) /// 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 { pub fn height(&self) -> f32 {
self.max.y() - self.min.y() self.max.y() - self.min.y()
} }
} }
unsafe impl Byteable for Rect {}

View File

@ -1,4 +1,4 @@
use crate::{ColorMaterial, Quad}; use crate::{ColorMaterial, Quad, SpriteSheet, SpriteSheetSprite};
use bevy_asset::{Assets, Handle}; use bevy_asset::{Assets, Handle};
use bevy_render::{ use bevy_render::{
base_render_graph, base_render_graph,
@ -112,6 +112,8 @@ pub fn build_sprite_pipeline(shaders: &mut Assets<Shader>) -> PipelineDescriptor
pub mod node { pub mod node {
pub const COLOR_MATERIAL: &'static str = "color_material"; pub const COLOR_MATERIAL: &'static str = "color_material";
pub const QUAD: &'static str = "quad"; 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 { pub trait SpriteRenderGraphBuilder {
@ -131,6 +133,16 @@ impl SpriteRenderGraphBuilder for RenderGraph {
self.add_node_edge(node::QUAD, base_render_graph::node::MAIN_PASS) self.add_node_edge(node::QUAD, base_render_graph::node::MAIN_PASS)
.unwrap(); .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 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(SPRITE_PIPELINE_HANDLE, build_sprite_pipeline(&mut shaders)); pipelines.set(SPRITE_PIPELINE_HANDLE, build_sprite_pipeline(&mut shaders));

View File

@ -1,9 +1,22 @@
#version 450 #version 450
// sprite layout(location = 0) in vec3 Vertex_Position;
layout(location = 0) in vec3 Sprite_Position; layout(location = 1) in vec3 Vertex_Normal;
// this is a vec2 instead of an int due to WebGPU limitations layout(location = 2) in vec2 Vertex_Uv;
layout(location = 1) in ivec2 Sprite_Index;
// 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; layout(location = 0) out vec2 v_Uv;
@ -16,21 +29,19 @@ struct Rect {
vec2 end; vec2 end;
}; };
layout(set = 1, binding = 0) buffer SpriteSheet { layout(set = 1, binding = 0) buffer SpriteSheet_sprites {
Rect[] SpriteSheet_sprites; Rect[] Sprites;
}; };
const vec2 positions[4] = vec2[]( layout(set = 2, binding = 0) uniform SpriteSheetSprite {
vec2(0.5, -0.5), vec3 SpriteSheetSprite_position;
vec2(-0.5, -0.5), uint SpriteSheetSprite_index;
vec2(0.5, 0.5), };
vec2(-0.5, 0.5)
);
void main() { 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 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 uvs[4] = vec2[](
vec2(sprite_rect.end.x, sprite_rect.begin.y), vec2(sprite_rect.end.x, sprite_rect.begin.y),
sprite_rect.begin, sprite_rect.begin,
@ -38,5 +49,5 @@ void main() {
vec2(sprite_rect.begin.x, sprite_rect.end.y) vec2(sprite_rect.begin.x, sprite_rect.end.y)
); );
v_Uv = uvs[gl_VertexIndex]; 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);
} }

View File

@ -1,29 +1,30 @@
use crate::Rect; use crate::Rect;
use bevy_app::{Events, GetEventReader}; use bevy_app::{Events, GetEventReader};
use bevy_asset::{AssetEvent, Assets, Handle}; 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::{ use bevy_render::{
render_resource::{BufferInfo, BufferUsage, RenderResourceAssignment, ResourceInfo}, render_resource::{BufferInfo, BufferUsage, RenderResourceAssignment, ResourceInfo},
renderer::{RenderResourceContext, RenderResources}, renderer::{RenderResourceContext, RenderResources},
texture::Texture, texture::Texture,
Renderable, Renderable,
}; };
use glam::{Vec3, Vec4};
use legion::prelude::*; use legion::prelude::*;
use std::collections::HashSet; use std::collections::HashSet;
use glam::{Vec4, Vec3};
#[derive(Uniforms)]
pub struct SpriteSheet { pub struct SpriteSheet {
pub texture: Handle<Texture>, pub texture: Handle<Texture>,
pub sprites: Vec<Rect>, pub sprites: Vec<Rect>,
} }
#[repr(C)] // 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
#[derive(Uniform, Bytes)] // Bytes for Byteable. https://github.com/bitshifter/glam-rs/issues/36
#[derive(Uniform, Bytes, Default)]
pub struct SpriteSheetSprite { pub struct SpriteSheetSprite {
#[uniform(vertex)] pub position: Vec3,
pub postition: Vec4, pub index: u32,
#[uniform(vertex)]
pub index: u16,
} }
pub const SPRITE_SHEET_BUFFER_ASSET_INDEX: usize = 0; 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() { for changed_sprite_sheet_handle in changed_sprite_sheets.iter() {
if let Some(sprite_sheet) = sprite_sheets.get(changed_sprite_sheet_handle) { if let Some(sprite_sheet) = sprite_sheets.get(changed_sprite_sheet_handle) {
// let sprite_sheet_bytes = sprite_sheet.sprites.as_bytes(); let sprite_sheet_bytes = sprite_sheet.sprites.as_slice().as_bytes();
// let sprite_sheet_buffer = render_resources.create_buffer_with_data( let sprite_sheet_buffer = render_resources.create_buffer_with_data(
// BufferInfo { BufferInfo {
// buffer_usage: BufferUsage::STORAGE, buffer_usage: BufferUsage::STORAGE,
// ..Default::default() ..Default::default()
// }, },
// &sprite_sheet_bytes, &sprite_sheet_bytes,
// ); );
// render_resources.set_asset_resource( render_resources.set_asset_resource(
// *changed_sprite_sheet_handle, *changed_sprite_sheet_handle,
// sprite_sheet_buffer, sprite_sheet_buffer,
// SPRITE_SHEET_BUFFER_ASSET_INDEX, SPRITE_SHEET_BUFFER_ASSET_INDEX,
// ); );
} }
} }

View File

@ -15,4 +15,4 @@ impl AppPlugin for TextPlugin {
app.add_asset::<Font>() app.add_asset::<Font>()
.add_asset_loader::<Font, FontLoader>(); .add_asset_loader::<Font, FontLoader>();
} }
} }