Skip to content
Closed
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
58 changes: 33 additions & 25 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,12 @@ use std::env;
use std::fs;
use std::path::Path;

use bevy::asset::AssetPlugin;
use shadplay::{plugin::ShadPlayPlugin, system::config::UserSession};

fn main() {
let args: Vec<String> = env::args().collect();
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

which version of rustfmt are you using?


// Check if a shader file path is provided as an argument
if args.len() > 1 {
let shader_path = &args[1];
Expand All @@ -30,10 +31,15 @@ fn main() {
.insert_resource(user_config)
.insert_resource(ClearColor(Color::NONE))
.add_plugins((
DefaultPlugins.set(WindowPlugin {
primary_window: Some(user_cfg_window), // From UserConfig
..default()
}),
DefaultPlugins
.set(WindowPlugin {
primary_window: Some(user_cfg_window),
..default()
})
.set(AssetPlugin {
unapproved_path_mode: bevy::asset::UnapprovedPathMode::Allow, // ← this one line unlocks external PNGs
..default()
}),
ShadPlayPlugin,
))
.add_systems(
Expand All @@ -51,75 +57,77 @@ fn main() {
/// Loads a shader file and determines if it's 2D or 3D, then applies it appropriately
fn load_and_apply_shader(shader_path: &str) -> Result<(), Box<dyn std::error::Error>> {
let path = Path::new(shader_path);

// Check if file exists
if !path.exists() {
return Err(format!("Shader file does not exist: {}", shader_path).into());
}

// Read the shader file
let shader_content = fs::read_to_string(path)?;

// Determine if it's 2D or 3D based on contents
let is_2d = detect_shader_type(&shader_content);

// Copy the shader to the appropriate location based on its type
let target_path = if is_2d {
"assets/shaders/myshader_2d.wgsl"
} else {
"assets/shaders/myshader.wgsl"
};

fs::write(target_path, &shader_content)?;

println!("Loaded {} shader from {} to {}",
if is_2d { "2D" } else { "3D" },
shader_path,
target_path);


println!(
"Loaded {} shader from {} to {}",
if is_2d { "2D" } else { "3D" },
shader_path,
target_path
);

Ok(())
}

/// Detects if a shader is 2D or 3D based on common patterns
fn detect_shader_type(shader_content: &str) -> bool {
let mut is_2d_score = 0;
let mut is_3d_score = 0;

// Strong 2D indicators
if shader_content.contains("bevy_sprite::mesh2d_view_bindings") {
is_2d_score += 1000; // Extremely strong 2D indicator
}

if shader_content.contains("bevy_sprite::mesh2d_vertex_output") {
is_2d_score += 1000; // Extremely strong 2D indicator
}

if shader_content.contains("mesh2d_") {
is_2d_score += 500; // Strong 2D indicator
}

// Strong 3D indicators
if shader_content.contains("bevy_pbr::") {
is_3d_score += 1000; // Extremely strong 3D indicator
}

if shader_content.contains("forward_io") {
is_3d_score += 500; // Strong 3D indicator
}

if shader_content.contains("mesh_view_bindings") {
is_3d_score += 300; // 3D indicator
}

// General patterns
if shader_content.contains("bevy_sprite::") {
is_2d_score += 100; // Sprite indicates 2D
}

if shader_content.contains("VertexOutput") && shader_content.contains("bevy_sprite::") {
is_2d_score += 200; // 2D vertex output
}

is_2d_score > is_3d_score
}

Expand Down
7 changes: 6 additions & 1 deletion src/plugin.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
use crate::{camera::PanOrbitCameraPlugin, utils::{ShadplayWindowBorder, toggle_border}};
use crate::{
camera::PanOrbitCameraPlugin,
system::drag_n_drop::switch_to_newest_texture_when_loaded,
utils::{ShadplayWindowBorder, toggle_border},
};
use bevy::{
input::keyboard::KeyboardInput, log::tracing_subscriber::util::SubscriberInitExt, prelude::*,
sprite_render::Material2dPlugin, window::WindowResized,
Expand Down Expand Up @@ -66,6 +70,7 @@ impl Plugin for ShadPlayPlugin {
toggle_transparency,
#[cfg(target_os = "windows")]
toggle_window_passthrough,
switch_to_newest_texture_when_loaded,
),
)
// 2d Only Sytsems
Expand Down
4 changes: 2 additions & 2 deletions src/system/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -230,7 +230,7 @@ mod tests {
#[test]
fn save_and_load_user_config() {
let test_config = UserSession {
window_dims: (1024.0, 768.0),
window_dims: (1024, 768),
decorations: false,
always_on_top: false,
last_updated: 1635900000,
Expand All @@ -254,7 +254,7 @@ mod tests {
fn config_path_for_user_config() {
let p = UserSession::get_config_path();
let test_config = UserSession {
window_dims: (1024.0, 768.0),
window_dims: (1024, 768),
decorations: false,
always_on_top: true,
last_updated: 1635900000,
Expand Down
24 changes: 23 additions & 1 deletion src/system/drag_n_drop.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use bevy::{log, prelude::*, ecs::message::Message};
use bevy::{ecs::message::Message, log, prelude::*};
use std::collections::HashMap;
use std::path::PathBuf;

Expand Down Expand Up @@ -124,3 +124,25 @@ pub fn add_and_set_dropped_file(
pub fn debug_tex_keys(tex_handles: Res<TexHandleQueue>) {
debug!("Num Textures: {}", tex_handles.len());
}

/// This runs every frame and switches to the newest dropped texture AS SOON AS it's ready
pub fn switch_to_newest_texture_when_loaded(
mut tex_handles: ResMut<TexHandleQueue>,
mut shader_mat_3d: ResMut<Assets<YourShader>>,
mut shader_mat_2d: ResMut<Assets<YourShader2D>>,
images: Res<Assets<Image>>,
) {
let newest_idx = tex_handles.keys().max().copied().unwrap_or(0);

// Check if the newest texture is actually loaded yet
if let Some(handle) = tex_handles.0.get(&newest_idx) {
if images.get(handle).is_some() {
// It's loaded → tell the shader to use it!
if let Some((_, mat)) = shader_mat_2d.iter_mut().next() {
YourShader2D::set_current_tex(mat, newest_idx, &tex_handles);
} else if let Some((_, mat)) = shader_mat_3d.iter_mut().next() {
YourShader::set_current_tex(mat, newest_idx, &tex_handles);
}
}
}
}
55 changes: 26 additions & 29 deletions src/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use crate::camera::PanOrbitCamera;
use bevy::{
math::sampling::mesh_sampling,
prelude::*,
window::{PrimaryWindow, RequestRedraw, Window, WindowLevel},
window::{CursorOptions, PrimaryWindow, RequestRedraw, Window, WindowLevel},
winit::WinitWindows,
};

Expand Down Expand Up @@ -104,17 +104,17 @@ impl ShadplayWindowDims {
#[derive(Resource, Message, Debug, Clone)]
pub struct ShadplayWindowBorder {
pub enabled: bool,
pub thickness: Vec2
pub thickness: Vec2,
}

impl ShadplayWindowBorder {
/// Get border thickness in __%__
///
///
/// If `enabled` is `false` will return __x__ = `1.00`, __y__ = `1.00`
pub fn thickness(&self) -> Vec2 {
if !self.enabled {
return Vec2::new(1.00, 1.00);
}
}

1.00 - self.thickness
}
Expand All @@ -124,7 +124,7 @@ impl Default for ShadplayWindowBorder {
fn default() -> Self {
Self {
enabled: true,
thickness: Vec2::new(0.05, 0.05)
thickness: Vec2::new(0.05, 0.05),
}
}
}
Expand Down Expand Up @@ -264,29 +264,25 @@ pub fn toggle_decorations(input: Res<ButtonInput<KeyCode>>, mut windows: Query<&
}

/// System:
/// Toggle mouse passthrough.
/// Toggle mouse passthrough (click-through window).
/// This is ONLY supported on Windows.
#[cfg(target_os = "windows")]
pub fn toggle_window_passthrough(
keyboard_input: Res<ButtonInput<KeyCode>>,
mut windows: Query<&mut Window>,
mut windows: Query<(&mut Window, &mut CursorOptions)>, // Query both!
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

unnecessary comment

) {
if keyboard_input.just_pressed(KeyCode::KeyP) {
#[allow(unused_mut)]
let mut window = windows.single_mut().unwrap();
info!("PASSTHROUGH TOGGLED.: {:?}", window.decorations);
}
let Ok((mut window, mut cursor_options)) = windows.single_mut() else {
error!("No primary window found");
return;
};

if keyboard_input.just_pressed(KeyCode::KeyX) {
let mut window = match windows.single_mut() {
Ok(w) => w,
Err(e) => {
error!("No primary window found {}", e);
return;
}
};
debug!("PASSTHROUGH TOGGLED.: {:?}", window.decorations);
window.cursor_options.hit_test = !window.cursor_options.hit_test;
if keyboard_input.just_pressed(KeyCode::KeyP) || keyboard_input.just_pressed(KeyCode::KeyX) {
cursor_options.hit_test = !cursor_options.hit_test;

info!(
"PASSTHROUGH TOGGLED → hit_test: {} | decorations: {:?}",
cursor_options.hit_test, window.decorations
);
}
}

Expand Down Expand Up @@ -480,14 +476,14 @@ pub fn size_quad(
}

/// System: Runs only when in [`AppState::TwoD`]
///
///
/// Used for toggling on/off the window border.
///
///
/// Press `b` when in 2D mode to toggle the window border.
pub fn toggle_border(
mut border: ResMut<ShadplayWindowBorder>,
input: Res<ButtonInput<KeyCode>>,
mut fire_event: MessageWriter<ShadplayWindowBorder>
mut fire_event: MessageWriter<ShadplayWindowBorder>,
) {
if input.just_pressed(KeyCode::KeyB) {
info!("Toggling window border");
Expand Down Expand Up @@ -529,10 +525,11 @@ pub fn update_mouse_pos(

// Is the mouse on our window?
if shadplay_win_dims.hittest(mouse_xy)
&& let Some((_, shad_mat)) = shader_mat.iter_mut().next() {
let sh_xy = shadplay_win_dims.to_uv(mouse_xy);
shad_mat.mouse_pos = sh_xy.into();
}
&& let Some((_, shad_mat)) = shader_mat.iter_mut().next()
{
let sh_xy = shadplay_win_dims.to_uv(mouse_xy);
shad_mat.mouse_pos = sh_xy.into();
}
}

impl From<Vec2> for MousePos {
Expand Down