diff --git a/Cargo.lock b/Cargo.lock index 5544548..b21735f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1739,6 +1739,7 @@ dependencies = [ "pollster", "quick_cache", "regex", + "rust-embed", "wgpu", ] diff --git a/mp_elements/Cargo.toml b/mp_elements/Cargo.toml index e48bc00..8c09113 100644 --- a/mp_elements/Cargo.toml +++ b/mp_elements/Cargo.toml @@ -12,5 +12,9 @@ mp_core = { path = "../mp_core", version = "*" } flume = "0.11.1" pollster = "0.4.0" quick_cache = "0.6.9" -encase = {version="0.10.0",features=["glam"]} +encase = { version = "0.10.0", features = ["glam"] } image = "0.25.5" +rust-embed = "8.5.0" + +[build-dependencies] +regex = "1.11.1" diff --git a/mp_elements/build.rs b/mp_elements/build.rs new file mode 100644 index 0000000..b7acf65 --- /dev/null +++ b/mp_elements/build.rs @@ -0,0 +1,122 @@ +use regex::Regex; +use std::env; +use std::fs; +use std::path::{Path, PathBuf}; + +fn main() { + let watch_dir = "shaders/elements"; + for entry in fs::read_dir(watch_dir).unwrap() { + let path = entry.unwrap().path(); + if path.is_file() { + println!("cargo:rerun-if-changed={}", path.display()); + } + } + + let crate_path = env::var("CARGO_MANIFEST_DIR").unwrap(); + + let shader_path_base = Path::new(&crate_path).join("shaders"); + + for entry in fs::read_dir(watch_dir).unwrap() { + let path = entry.unwrap().path(); + if path.is_file() { + println!("cargo:rerun-if-changed={}", path.display()); + } + + let merged_shader = merge_shader(&path.display().to_string(), &shader_path_base); + + let out_path = Path::new(&crate_path) + .join("shaders") + .join("elements") + .join(format!( + "{}_merged.wgsl", + path.file_stem().unwrap().to_str().unwrap() + )); + + fs::write(out_path, merged_shader).unwrap(); + } +} + +fn merge_shader<'a>(shader: &'a str, base: &std::path::Path) -> String { + const TOOLS: &'static str = r#"// This is a tool that merges the shader code with the shader code from the shader module. + +struct UniformCommonTools { + model_matrix: mat4x4f, + view_matrix: mat4x4f, + proj_matrix: mat4x4f, + camera_x: f32, + camera_y: f32, + camera_z: f32, + camera_target_x: f32, + camera_target_y: f32, + camera_target_z: f32, + camera_up_x: f32, + camera_up_y: f32, + camera_up_z: f32, + + // camera_position: vec3f, + // camera_front: vec3f, + // camera_up: vec3f, +} + +@group(0) @binding(0) var common_tools: UniformCommonTools; +"#; + + let path = std::path::Path::new(shader); + + let mut visited_files = std::collections::HashSet::new(); + + let mut result = process_file(&path, &mut visited_files, &base); + + // 将工具代码插入到 shader 代码的开头 + result.insert_str(0, TOOLS); + + return result; +} + +fn process_file<'a, P: AsRef + 'a, B: AsRef>( + file_path: P, + visited_files: &mut std::collections::HashSet, + base_path: B, +) -> String { + let base_path = base_path.as_ref(); + let file_path = file_path.as_ref(); + + // 如果该文件已经处理过,则避免死循环 + if visited_files.contains(file_path) { + return String::new(); // 返回空字符串表示已经处理过 + } + + visited_files.insert(file_path.to_path_buf()); + + let content = std::fs::read_to_string(file_path).unwrap_or_else(|_| { + panic!("Failed to read file: {}", file_path.display()); + }); + + let re = Regex::new(r#"#include\s+\"([^\"]+\.wgsl)\";"#).unwrap(); + + let result = re.replace_all(&content, |caps: ®ex::Captures| { + let included_file = &caps[1]; // 获取文件名 + + let included_path = resolve_included_file(included_file, base_path.as_ref()); + + let included_content = process_file( + &included_path, + visited_files, + base_path.parent().unwrap_or(base_path), + ); + + included_content + }); + + result.to_string() +} + +fn resolve_included_file(included_file: &str, base_path: &std::path::Path) -> std::path::PathBuf { + let included_path = std::path::Path::new(included_file); + + if included_path.is_relative() { + base_path.join(included_path) + } else { + included_path.to_path_buf() + } +} diff --git a/mp_elements/shaders/ppi.wgsl b/mp_elements/shaders/elements/ppi.wgsl similarity index 100% rename from mp_elements/shaders/ppi.wgsl rename to mp_elements/shaders/elements/ppi.wgsl diff --git a/mp_elements/shaders/elements/ppi_merged.wgsl b/mp_elements/shaders/elements/ppi_merged.wgsl new file mode 100644 index 0000000..0736c03 --- /dev/null +++ b/mp_elements/shaders/elements/ppi_merged.wgsl @@ -0,0 +1,103 @@ +// This is a tool that merges the shader code with the shader code from the shader module. + +struct UniformCommonTools { + model_matrix: mat4x4f, + view_matrix: mat4x4f, + proj_matrix: mat4x4f, + camera_x: f32, + camera_y: f32, + camera_z: f32, + camera_target_x: f32, + camera_target_y: f32, + camera_target_z: f32, + camera_up_x: f32, + camera_up_y: f32, + camera_up_z: f32, + + // camera_position: vec3f, + // camera_front: vec3f, + // camera_up: vec3f, +} + +@group(0) @binding(0) var common_tools: UniformCommonTools; +const PI:f32 = 3.14159265358979323846264338327950288; +const TWO_PI:f32 = 6.28318530717958647692528676655900576; +const HALF_PI:f32 = 1.57079632679489661923132169163975144; +const LOG2:f32 = 0.693147180559945309417232121458176568; +const LOG10:f32 = 2.30258509299404568401799145468436421; + +// Common Uniforms +// common_tools +// model_matrix: mat4, +// view_matrix: mat4, +// proj_matrix: mat4, +// camera_position: vec3, +// camera_front: vec3, +// camera_up: vec3, +// light_position: vec3, +// light_color: vec3, +// light_intensity: float, + +// Uniforms +@group(1) @binding(0) var params: UniformParams; +// Data Buffer +@group(1) @binding(1) var data: array; + +struct UniformParams { + origin: vec4f +} + +struct VertexOutput { + @builtin(position) position: vec4f, + @location(0) r_range: vec4f, + @location(1) idx: u32 +} + +@vertex +fn vertex( + @location(0) position: vec4f, + @location(1) r_range: vec4f, + // @location(2) idx: u32 +) -> VertexOutput { + + var out: VertexOutput; + + // Transform position + out.position = common_tools.proj_matrix * common_tools.view_matrix * common_tools.model_matrix * vec4f(position, 1.0); + // out.position = vec4(position.xyz, 1.0); + out.r_range = r_range; + let idx = u32(position.w); + out.idx = idx; + + return out; +} + +fn polar_forward(cartesian: vec3f) -> vec3f { + let r = length(cartesian.xy - params.origin.xy); + let theta = atan2(cartesian.y, cartesian.x); + let z = cartesian.z; + return vec3f(r, theta, z); +} + +@fragment +fn fragment(input: VertexOutput) -> @location(0) vec4f { + // Sample data texture + let value = data[input.idx]; + let ear = polar_forward(input.position.xyz); + // var color = linear_colormap(value); + + var color = clamp(value / 75.0, 0.0, 1.0); + + // let r = ear.x; + // Valid range + // let r_range = input.r_range; + + // let outside_lower_bound = step(r, r_range.x); + // let outside_upper_bound = step(r_range.y, r); + // let is_outside = outside_lower_bound + outside_upper_bound; + // color.a *= 1.0 - is_outside; + + + return vec4(color,color,color, 1.0); +} + diff --git a/mp_elements/src/elements/ppi.rs b/mp_elements/src/elements/ppi.rs index 2a18951..e204df8 100644 --- a/mp_elements/src/elements/ppi.rs +++ b/mp_elements/src/elements/ppi.rs @@ -1,8 +1,10 @@ +use crate::Shaders; +use rust_embed::RustEmbed; use std::{ops::Sub, result, vec}; use crate::{ app::{BufferKey, Ctx, DataBufferPool}, - utils::merge_shader, + utils::get_shader, }; use bytemuck; use glam::{Vec3, Vec4}; @@ -259,8 +261,9 @@ impl Element for PPI { impl PPI { fn init_shader(device: &wgpu::Device) -> wgpu::ShaderModule { // let shader_str = merge_shader(r#"/Users/tsuki/projects/mp/mp_elements/shaders/ppi.wgsl"#); - let shader_str = - merge_shader(r#"C:\Users\qwin7\projects\radarmp\mp_elements\shaders\ppi.wgsl"#); + + let shader_str = get_shader("ppi_merged.wgsl").as_ref(); + let shader = device.create_shader_module(wgpu::ShaderModuleDescriptor { label: Some("PPI Shader Module"), source: wgpu::ShaderSource::Wgsl(shader_str.into()), diff --git a/mp_elements/src/lib.rs b/mp_elements/src/lib.rs index 874e0f1..8092bf7 100644 --- a/mp_elements/src/lib.rs +++ b/mp_elements/src/lib.rs @@ -5,3 +5,8 @@ pub mod renderer; mod utils; pub use app::App; +use rust_embed::RustEmbed; + +#[derive(RustEmbed)] +#[folder = "shaders/"] +pub struct Shaders; diff --git a/mp_elements/src/utils.rs b/mp_elements/src/utils.rs index cd675c8..9591969 100644 --- a/mp_elements/src/utils.rs +++ b/mp_elements/src/utils.rs @@ -1,105 +1,9 @@ -use std::path::PathBuf; +use crate::Shaders; +use std::borrow::Cow; +use std::str; -use regex::Regex; -pub(crate) fn merge_shader<'a>(shader: &'a str) -> String { - const TOOLS: &'static str = r#"// This is a tool that merges the shader code with the shader code from the shader module. - -struct UniformCommonTools { - model_matrix: mat4x4f, - view_matrix: mat4x4f, - proj_matrix: mat4x4f, - camera_x: f32, - camera_y: f32, - camera_z: f32, - camera_target_x: f32, - camera_target_y: f32, - camera_target_z: f32, - camera_up_x: f32, - camera_up_y: f32, - camera_up_z: f32, - - // camera_position: vec3f, - // camera_front: vec3f, - // camera_up: vec3f, -} - -@group(0) @binding(0) var common_tools: UniformCommonTools; -"#; - - let mut visited_files = std::collections::HashSet::new(); - let path: PathBuf = PathBuf::from(shader); - - let base = match path.canonicalize() { - Ok(path) => path.parent().unwrap().to_owned(), - Err(e) => { - // panic!("Failed to canonicalize path: {}", e); - // PathBuf::from(r#"/Users/tsuki/projects/mp/mp_elements/shaders"#) - PathBuf::from(r#"C:\Users\qwin7\projects\radarmp\mp_elements\shaders"#) - } - }; - - let mut result = process_file(&path, &mut visited_files, &base); - - // 将工具代码插入到 shader 代码的开头 - result.insert_str(0, TOOLS); - - return result; -} - -fn process_file<'a, P: AsRef + 'a, B: AsRef>( - file_path: P, - visited_files: &mut std::collections::HashSet, - base_path: B, -) -> String { - let base_path = base_path.as_ref(); - let file_path = file_path.as_ref(); - - // 如果该文件已经处理过,则避免死循环 - if visited_files.contains(file_path) { - return String::new(); // 返回空字符串表示已经处理过 - } - - visited_files.insert(file_path.to_path_buf()); - - let content = std::fs::read_to_string(file_path).unwrap_or_else(|_| { - panic!("Failed to read file: {}", file_path.display()); - }); - - let re = Regex::new(r#"#include\s+\"([^\"]+\.wgsl)\";"#).unwrap(); - - let result = re.replace_all(&content, |caps: ®ex::Captures| { - let included_file = &caps[1]; // 获取文件名 - - let included_path = resolve_included_file(included_file, base_path.as_ref()); - - let included_content = process_file( - &included_path, - visited_files, - base_path.parent().unwrap_or(base_path), - ); - - included_content - }); - - result.to_string() -} - -fn resolve_included_file(included_file: &str, base_path: &std::path::Path) -> std::path::PathBuf { - let included_path = std::path::Path::new(included_file); - - if included_path.is_relative() { - base_path.join(included_path) - } else { - included_path.to_path_buf() - } -} - -mod test { - use super::merge_shader; - - #[test] - fn test() { - let merged = merge_shader("/Users/tsuki/projects/mp/mp_elements/shaders/ppi.wgsl"); - println!("{}", merged); - } +pub fn get_shader(name: &str) -> Cow<'static, str> { + let file = Shaders::get(name).unwrap(); + let string = String::from_utf8_lossy(&file.data); + string }