Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Introduce ShaderModel. #977

Merged
merged 7 commits into from
Sep 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1,326 changes: 718 additions & 608 deletions Cargo.lock

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
[workspace]
members = [
"bevy_nannou",
"bevy_nannou_derive",
"bevy_nannou_draw",
"bevy_nannou_isf",
"bevy_nannou_video",
Expand Down
16 changes: 16 additions & 0 deletions bevy_nannou_derive/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
[package]
name = "bevy_nannou_derive"
version = "0.1.0"
edition = "2021"

[lib]
proc-macro = true

[dependencies]
syn = { version = "1", features = ["full"] }
quote = "1.0"
proc-macro2 = "1.0"

[dev-dependencies]
bevy = { workspace = true }
bevy_nannou_draw = { path = "../bevy_nannou_draw" }
75 changes: 75 additions & 0 deletions bevy_nannou_derive/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
use proc_macro::TokenStream;
use quote::quote;
use syn::{parse_macro_input, parse_quote, ItemStruct, Lit, Meta, NestedMeta};

#[proc_macro_attribute]
pub fn shader_model(attr: TokenStream, item: TokenStream) -> TokenStream {
let mut input = parse_macro_input!(item as ItemStruct);
let attrs = parse_macro_input!(attr as syn::AttributeArgs);

let (vertex_shader, fragment_shader) = parse_shader_attributes(&attrs);

let name = &input.ident;
let generics = &input.generics;
let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();

let vertex_shader_impl = vertex_shader
.map(|path| quote! { #path.into() })
.unwrap_or_else(|| quote! { ::nannou::prelude::ShaderRef::Default });

let fragment_shader_impl = fragment_shader
.map(|path| quote! { #path.into() })
.unwrap_or_else(|| quote! { ::nannou::prelude::ShaderRef::Default });

// Add derive attributes
input
.attrs
.push(parse_quote!(#[derive(Asset, TypePath, AsBindGroup, Debug, Clone, Default)]));

let expanded = quote! {
#input

impl #impl_generics ::nannou::prelude::render::ShaderModel for #name #ty_generics #where_clause {
fn vertex_shader() -> ::nannou::prelude::ShaderRef {
#vertex_shader_impl
}

fn fragment_shader() -> ::nannou::prelude::ShaderRef {
#fragment_shader_impl
}
}

impl #impl_generics ::nannou::prelude::Material for #name #ty_generics #where_clause {
fn vertex_shader() -> ::nannou::prelude::ShaderRef {
<Self as ::nannou::prelude::render::ShaderModel>::vertex_shader()
}

fn fragment_shader() -> ::nannou::prelude::ShaderRef {
<Self as ::nannou::prelude::render::ShaderModel>::fragment_shader()
}
}
};

TokenStream::from(expanded)
}

fn parse_shader_attributes(attrs: &[syn::NestedMeta]) -> (Option<String>, Option<String>) {
let mut vertex_shader = None;
let mut fragment_shader = None;

for attr in attrs {
if let NestedMeta::Meta(Meta::NameValue(nv)) = attr {
if nv.path.is_ident("vertex") {
if let Lit::Str(lit) = &nv.lit {
vertex_shader = Some(lit.value());
}
} else if nv.path.is_ident("fragment") {
if let Lit::Str(lit) = &nv.lit {
fragment_shader = Some(lit.value());
}
}
}
}

(vertex_shader, fragment_shader)
}
60 changes: 60 additions & 0 deletions bevy_nannou_derive/tests/shader_model_tests.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
use bevy::render::render_resource::ShaderRef;
use bevy_nannou_derive::shader_model;
use bevy_nannou_draw::render::ShaderModel;

#[shader_model]
struct TestMaterial {}

#[test]
fn test_default_shaders() {
assert!(matches!(TestMaterial::vertex_shader(), ShaderRef::Default));
assert!(matches!(
TestMaterial::fragment_shader(),
ShaderRef::Default
));
}

#[shader_model(vertex = "custom_vertex.wgsl")]
struct TestVertexMaterial {}

#[test]
fn test_custom_vertex_shader() {
assert!(matches!(
TestVertexMaterial::vertex_shader(),
ShaderRef::Path(_)
));
assert!(matches!(
TestVertexMaterial::fragment_shader(),
ShaderRef::Default
));
}

#[shader_model(fragment = "custom_fragment.wgsl")]
struct TestFragmentMaterial {}

#[test]
fn test_custom_fragment_shader() {
assert!(matches!(
TestFragmentMaterial::vertex_shader(),
ShaderRef::Default
));
assert!(matches!(
TestFragmentMaterial::fragment_shader(),
ShaderRef::Path(_)
));
}

#[shader_model(vertex = "custom_vertex.wgsl", fragment = "custom_fragment.wgsl")]
struct TestBothMaterial {}

#[test]
fn test_both_custom_shaders() {
assert!(matches!(
TestBothMaterial::vertex_shader(),
ShaderRef::Path(_)
));
assert!(matches!(
TestBothMaterial::fragment_shader(),
ShaderRef::Path(_)
));
}
58 changes: 6 additions & 52 deletions bevy_nannou_draw/src/draw/drawing.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use std::any::TypeId;
use std::marker::PhantomData;

use bevy::asset::{AsyncWriteExt, UntypedAssetId};
use bevy::asset::UntypedAssetId;
use bevy::pbr::{ExtendedMaterial, MaterialExtension};
use bevy::prelude::*;
use lyon::path::PathEvent;
Expand All @@ -13,7 +13,6 @@ use crate::draw::properties::{
SetColor, SetDimensions, SetFill, SetOrientation, SetPosition, SetStroke,
};
use crate::draw::{Draw, DrawCommand, DrawRef};
use crate::render::{ExtendedNannouMaterial, NannouMaterial};

/// A **Drawing** in progress.
///
Expand Down Expand Up @@ -140,51 +139,6 @@ where
self.finish_inner()
}

/// Set the material's fragment shader for the drawing. Note: this shader must have
/// been initialized during application setup.
#[cfg(feature = "nightly")]
pub fn fragment_shader<const FS: &'static str>(
mut self,
) -> Drawing<'a, T, ExtendedNannouMaterial<"", FS>> {
self.finish_on_drop = false;

let Drawing {
ref draw,
index,
material_index,
..
} = self;

let state = draw.state.clone();
let new_id = UntypedAssetId::Uuid {
type_id: TypeId::of::<ExtendedNannouMaterial<"", FS>>(),
uuid: Uuid::new_v4(),
};

let material: ExtendedNannouMaterial<"", FS> = Default::default();
let mut state = state.write().unwrap();
state.materials.insert(new_id.clone(), Box::new(material));
// Mark the last material as the new material so that further drawings use the same material
// as the parent draw ref.
state.last_material = Some(new_id.clone());

let draw = Draw {
state: draw.state.clone(),
context: draw.context.clone(),
material: new_id.clone(),
window: draw.window,
_material: Default::default(),
};

Drawing::<'a, T, ExtendedMaterial<StandardMaterial, NannouMaterial<"", FS>>> {
draw: DrawRef::Owned(draw),
index,
material_index,
finish_on_drop: true,
_ty: PhantomData,
}
}

// Map the the parent's material to a new material type, taking ownership over the
// draw instance clone.
pub fn map_material<F>(mut self, map: F) -> Drawing<'a, T, M>
Expand Down Expand Up @@ -921,35 +875,35 @@ where
T: Into<Primitive>,
M: MaterialExtension + Default,
{
pub fn roughness(mut self, roughness: f32) -> Self {
pub fn roughness(self, roughness: f32) -> Self {
self.map_material(|mut material| {
material.base.perceptual_roughness = roughness;
material
})
}

pub fn metallic(mut self, metallic: f32) -> Self {
pub fn metallic(self, metallic: f32) -> Self {
self.map_material(|mut material| {
material.base.metallic = metallic;
material
})
}

pub fn base_color<C: Into<Color>>(mut self, color: C) -> Self {
pub fn base_color<C: Into<Color>>(self, color: C) -> Self {
self.map_material(|mut material| {
material.base.base_color = color.into();
material
})
}

pub fn emissive<C: Into<Color>>(mut self, color: C) -> Self {
pub fn emissive<C: Into<Color>>(self, color: C) -> Self {
self.map_material(|mut material| {
material.base.emissive = color.into().to_linear();
material
})
}

pub fn texture(mut self, texture: &Handle<Image>) -> Self {
pub fn texture(self, texture: &Handle<Image>) -> Self {
self.map_material(|mut material| {
material.base.base_color_texture = Some(texture.clone());
material
Expand Down
2 changes: 1 addition & 1 deletion bevy_nannou_draw/src/draw/instanced.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ use bevy::{
render_asset::RenderAssets,
render_phase::{
AddRenderCommand, DrawFunctions, PhaseItem, PhaseItemExtraIndex, RenderCommand,
RenderCommandResult, SetItemPipeline, SortedRenderPhase, TrackedRenderPass,
RenderCommandResult, SetItemPipeline, TrackedRenderPass,
},
render_resource::*,
renderer::RenderDevice,
Expand Down
2 changes: 0 additions & 2 deletions bevy_nannou_draw/src/draw/mesh/mod.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
//! Items related to the custom mesh type used by the `Draw` API.

use std::ops::{Deref, DerefMut};

use bevy::prelude::*;
use bevy::render::mesh::{Indices, PrimitiveTopology, VertexAttributeValues};
use bevy::render::render_asset::RenderAssetUsages;
Expand Down
11 changes: 4 additions & 7 deletions bevy_nannou_draw/src/draw/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,27 +4,24 @@

use std::any::{Any, TypeId};
use std::marker::PhantomData;
use std::ops::{Deref, DerefMut};
use std::ops::Deref;
use std::sync::{Arc, RwLock};

use bevy::asset::UntypedAssetId;
use bevy::ecs::world::Command;
use bevy::prelude::*;
use bevy::render::render_resource as wgpu;
use bevy::render::render_resource::{BlendComponent, BlendState};
use bevy::utils::{HashMap, HashSet};
use lyon::path::PathEvent;
use uuid::Uuid;

use crate::draw::instanced::{InstanceMaterialData, Instanced};
use crate::draw::mesh::MeshExt;
use crate::draw::render::RenderPrimitive;
use crate::render::DefaultNannouMaterial;

pub use self::background::Background;
pub use self::drawing::{Drawing, DrawingContext};
use self::primitive::Primitive;
pub use self::theme::Theme;
use crate::draw::instanced::{InstanceMaterialData, Instanced};
use crate::draw::mesh::MeshExt;
use crate::render::DefaultNannouMaterial;

pub mod background;
mod drawing;
Expand Down
34 changes: 2 additions & 32 deletions bevy_nannou_draw/src/draw/primitive/mesh.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,14 +27,6 @@ pub struct PrimitiveMesh {
#[derive(Clone, Debug, Default)]
struct FillColor(Option<Color>);

// A simple iterator for flattening a fixed-size array of indices.
struct FlattenIndices<I> {
iter: I,
index: usize,
vertex_start_index: usize,
current: [usize; 3],
}

pub type DrawingMesh<'a, M> = Drawing<'a, PrimitiveMesh, M>;

impl Vertexless {
Expand Down Expand Up @@ -311,7 +303,8 @@ impl PrimitiveMesh {
fn new(
vertex_range: ops::Range<usize>,
index_range: ops::Range<usize>,
texture_handle: Option<Handle<Image>>,
// TODO: remove this?
_texture_handle: Option<Handle<Image>>,
) -> Self {
let orientation = Default::default();
let position = Default::default();
Expand Down Expand Up @@ -553,29 +546,6 @@ impl draw::render::RenderPrimitive for PrimitiveMesh {
}
}

impl<I> Iterator for FlattenIndices<I>
where
I: Iterator<Item = [usize; 3]>,
{
type Item = usize;
fn next(&mut self) -> Option<Self::Item> {
loop {
if self.index < self.current.len() {
let ix = self.current[self.index];
self.index += 1;
return Some(self.vertex_start_index + ix);
}
match self.iter.next() {
None => return None,
Some(trio) => {
self.current = trio;
self.index = 0;
}
}
}
}
}

impl SetOrientation for PrimitiveMesh {
fn properties(&mut self) -> &mut orientation::Properties {
SetOrientation::properties(&mut self.orientation)
Expand Down
1 change: 1 addition & 0 deletions bevy_nannou_draw/src/draw/primitive/path.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ pub struct Path {
orientation: orientation::Properties,
path_event_src: PathEventSource,
options: Options,
// TODO: remove this?
texture_handle: Option<Handle<Image>>,
}

Expand Down
2 changes: 0 additions & 2 deletions bevy_nannou_draw/src/draw/render/mod.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
use std::hash::Hash;

use bevy::prelude::*;
use lyon::path::PathEvent;
use lyon::tessellation::{FillTessellator, StrokeTessellator};
Expand Down
2 changes: 0 additions & 2 deletions bevy_nannou_draw/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
#![cfg_attr(feature = "nightly", feature(adt_const_params))]

use bevy::prelude::*;

use crate::render::NannouRenderPlugin;
Expand Down
Loading
Loading