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

Add Shaders #110

Closed
wants to merge 16 commits into from
29 changes: 29 additions & 0 deletions assets/shaders/test.wgsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
#import bevy_sprite::mesh2d_view_bindings globals
#import bevy_sprite::mesh2d_vertex_output MeshVertexOutput
#import test_export

struct CustomMaterial {
color: vec4<f32>,
};

@group(1) @binding(0)
var<uniform> material: CustomMaterial;
@group(1) @binding(1)
var base_color_texture: texture_2d<f32>;
@group(1) @binding(2)
var base_color_sampler: sampler;

@fragment
fn fragment(
mesh: MeshVertexOutput,
) -> @location(0) vec4<f32> {

let t_1 = sin(globals.time*2.0)*0.5+0.5;
let t_2 = cos(globals.time*2.0);

var color: vec4<f32> = vec4(t_1, t_2, t_1, 0.0);

color.a = test_export::i_say_one();

return color * textureSample(base_color_texture, base_color_sampler, mesh.uv);
}
5 changes: 5 additions & 0 deletions assets/shaders/test_export.wgsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#define_import_path test_export

fn i_say_one() -> f32 {
return 1.0;
}
145 changes: 145 additions & 0 deletions examples/shader_2d.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
use bevy::{
prelude::*,
reflect::{TypePath, TypeUuid},
render::render_resource::{AsBindGroup, ShaderRef},
sprite::{Material2d, MaterialMesh2dBundle},
window::PrimaryWindow,
};
use bevy_cosmic_edit::*;

// Define material
#[derive(AsBindGroup, TypeUuid, TypePath, Debug, Clone, Default)]
#[uuid = "f690fdae-d598-45ab-8225-97e2a3f056e0"]
pub struct CustomMaterial {
#[uniform(0)]
color: Color,
#[texture(1)]
#[sampler(2)]
color_texture: Handle<Image>,
}

impl Material2d for CustomMaterial {
fn fragment_shader() -> ShaderRef {
"shaders/test.wgsl".into()
}
}

// implement required cosmic bits
impl CosmicMaterial2d for CustomMaterial {
fn color_texture(&self) -> &Handle<Image> {
// if using different bindings change the names in the impl too
&self.color_texture
}
fn set_color_texture(&mut self, texture: &Handle<Image>) -> &mut Self {
self.color_texture = texture.clone_weak();
self
}
}

fn setup(
mut commands: Commands,
mut materials: ResMut<Assets<CustomMaterial>>,
mut meshes: ResMut<Assets<Mesh>>,
asset_server: Res<AssetServer>,
) {
commands.spawn(Camera2dBundle::default());

// Shaders need to be in loaded to be accessed
commands.spawn(asset_server.load("shaders/test_export.wgsl") as Handle<Shader>);

// Sprite editor
let editor = commands
.spawn((CosmicEditBundle {
sprite_bundle: SpriteBundle {
// Sets size of text box
sprite: Sprite {
custom_size: Some(Vec2::new(300., 100.)),
..default()
},
// Position of text box
transform: Transform::from_xyz(0., 200., 0.),
..default()
},
..default()
},))
.id();

// TODO: click fns
//
// TODO: set size of sprite from mesh automagically
commands
.spawn(MaterialMesh2dBundle {
mesh: meshes
.add(Mesh::from(shape::Quad::new(Vec2::new(300., 100.))))
.into(),
material: materials.add(CustomMaterial::default()),
..default()
})
.insert(CosmicSource(editor));

commands.insert_resource(Focus(Some(editor)));
}

fn change_active_editor_ui(
mut commands: Commands,
mut interaction_query: Query<
(&Interaction, &CosmicSource),
(Changed<Interaction>, Without<ReadOnly>),
>,
) {
for (interaction, source) in interaction_query.iter_mut() {
if let Interaction::Pressed = interaction {
commands.insert_resource(Focus(Some(source.0)));
}
}
}

fn change_active_editor_sprite(
mut commands: Commands,
windows: Query<&Window, With<PrimaryWindow>>,
buttons: Res<Input<MouseButton>>,
mut cosmic_edit_query: Query<
(&mut Sprite, &GlobalTransform, &Visibility, Entity),
(With<CosmicEditor>, Without<ReadOnly>),
>,
camera_q: Query<(&Camera, &GlobalTransform)>,
) {
let window = windows.single();
let (camera, camera_transform) = camera_q.single();
if buttons.just_pressed(MouseButton::Left) {
for (sprite, node_transform, visibility, entity) in &mut cosmic_edit_query.iter_mut() {
if visibility == Visibility::Hidden {
continue;
}
let size = sprite.custom_size.unwrap_or(Vec2::ONE);
let x_min = node_transform.affine().translation.x - size.x / 2.;
let y_min = node_transform.affine().translation.y - size.y / 2.;
let x_max = node_transform.affine().translation.x + size.x / 2.;
let y_max = node_transform.affine().translation.y + size.y / 2.;
if let Some(pos) = window.cursor_position() {
if let Some(pos) = camera.viewport_to_world_2d(camera_transform, pos) {
if x_min < pos.x && pos.x < x_max && y_min < pos.y && pos.y < y_max {
commands.insert_resource(Focus(Some(entity)))
};
}
};
}
}
}

fn main() {
App::new()
.add_plugins(DefaultPlugins)
.add_plugins(CosmicEditPlugin {
change_cursor: CursorConfig::Default,
..default()
})
// This works like a passthrough, passes the material to Material2dPlugin
// once it assigns required fns
.add_plugins(CosmicMaterial2dPlugin::<CustomMaterial>::default())
.add_systems(Startup, setup)
.add_systems(Update, change_active_editor_ui)
.add_systems(Update, change_active_editor_sprite)
// TODO: change_active_editor_mesh
.run();
}
8 changes: 6 additions & 2 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
mod cursor;
mod input;
mod render;
mod shader;

use std::{collections::VecDeque, path::PathBuf};

Expand All @@ -22,10 +23,13 @@ use input::{poll_wasm_paste, WasmPaste, WasmPasteAsyncChannel};
use render::{
blink_cursor, freeze_cursor_blink, hide_inactive_or_readonly_cursor, hide_password_text,
on_scale_factor_change, restore_password_text, restore_placeholder_text, set_initial_scale,
show_placeholder, CosmicPadding, CosmicRenderSet, CosmicWidgetSize, CursorBlinkTimer,
CursorVisibility, PasswordValues, SwashCacheState,
show_placeholder, CosmicPadding, CosmicWidgetSize, CursorBlinkTimer, CursorVisibility,
PasswordValues, SwashCacheState,
};

pub use render::CosmicRenderSet;
pub use shader::{add_cosmic_material, CosmicMaterial2d, CosmicMaterial2dPlugin};

#[cfg(feature = "multicam")]
#[derive(Component)]
pub struct CosmicPrimaryCamera;
Expand Down
57 changes: 57 additions & 0 deletions src/shader.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
use std::{hash::Hash, marker::PhantomData};

use bevy::{
prelude::*,
sprite::{Material2d, Material2dPlugin},
};

use crate::{CosmicEditor, CosmicRenderSet, CosmicSource};

// TODO: document bindings here. Always expect color_texture bound to same place, show example.
// Allows shared shaders. Though API is like water so might be a job for later.
pub trait CosmicMaterial2d {
fn color_texture(&self) -> &Handle<Image>;
fn set_color_texture(&mut self, texture: &Handle<Image>) -> &mut Self;
}

pub struct CosmicMaterial2dPlugin<M: CosmicMaterial2d + Material2d>(PhantomData<M>);

impl<M: CosmicMaterial2d + Material2d> Default for CosmicMaterial2dPlugin<M> {
fn default() -> Self {
Self(Default::default())
}
}

// TODO: docs here, explain passthrough to Material2dPlugin
impl<M: Material2d + CosmicMaterial2d> Plugin for CosmicMaterial2dPlugin<M>
where
M::Data: PartialEq + Eq + Hash + Clone,
{
fn build(&self, app: &mut App) {
app.add_plugins(Material2dPlugin::<M>::default())
.add_systems(
PostUpdate,
add_cosmic_material::<M>.after(CosmicRenderSet::Draw),
);
}
}

pub fn add_cosmic_material<M: Material2d + CosmicMaterial2d>(
source_q: Query<&Handle<Image>, With<CosmicEditor>>,
dest_q: Query<(&Handle<M>, &CosmicSource), Without<CosmicEditor>>,
mut materials: ResMut<Assets<M>>,
) {
// TODO: do this once
for (dest_handle, source_entity) in dest_q.iter() {
if let Ok(source_handle) = source_q.get(source_entity.0) {
if let Some(dest_material) = materials.get_mut(dest_handle) {
if dest_material.color_texture() == source_handle {
// TODO: instead of all this looping find a way to check if handle is changed
// earlier in the chain
return;
}
dest_material.set_color_texture(source_handle);
}
}
}
}