radarmp/mp_elements/src/utils.rs
2024-11-16 01:48:09 +08:00

105 lines
2.9 KiB
Rust

use std::path::PathBuf;
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<uniform> 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#"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<std::path::Path> + 'a, B: AsRef<std::path::Path>>(
file_path: P,
visited_files: &mut std::collections::HashSet<std::path::PathBuf>,
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: &regex::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);
}
}