Skip to content

Commit

Permalink
Merge pull request #977 from tychedelia/shader-model
Browse files Browse the repository at this point in the history
Introduce ShaderModel.
  • Loading branch information
tychedelia authored Sep 10, 2024
2 parents e6c19ab + 4cd1ff0 commit 6f2532a
Show file tree
Hide file tree
Showing 32 changed files with 1,019 additions and 989 deletions.
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

0 comments on commit 6f2532a

Please sign in to comment.