mirror of
https://github.com/zbanks/radiance.git
synced 2026-06-16 04:26:25 +02:00
Add compilation of all built-in effect node shaders to build.rs
This commit is contained in:
@@ -4,9 +4,13 @@ use std::io::Write;
|
||||
use std::path;
|
||||
use std::path::Path;
|
||||
|
||||
#[path = "src/lib/effect_node/preprocess_shader.rs"]
|
||||
mod preprocess_shader;
|
||||
use preprocess_shader::preprocess_shader;
|
||||
|
||||
fn main() {
|
||||
check_builtin_shaders();
|
||||
//check_library_shaders();
|
||||
check_library_shaders();
|
||||
embed_default_library();
|
||||
}
|
||||
|
||||
@@ -31,10 +35,12 @@ fn check_builtin_shaders() {
|
||||
));
|
||||
}
|
||||
|
||||
println!("cargo:rerun-if-changed=src/lib/effect_header.wgsl");
|
||||
println!("cargo:rerun-if-changed=src/lib/effect_footer.wgsl");
|
||||
let effect_header = fs::read_to_string(Path::new("src/lib/effect_header.wgsl")).unwrap();
|
||||
let effect_footer = fs::read_to_string(Path::new("src/lib/effect_footer.wgsl")).unwrap();
|
||||
println!("cargo:rerun-if-changed=src/lib/effect_node/effect_header.wgsl");
|
||||
println!("cargo:rerun-if-changed=src/lib/effect_node/effect_footer.wgsl");
|
||||
let effect_header =
|
||||
fs::read_to_string(Path::new("src/lib/effect_node/effect_header.wgsl")).unwrap();
|
||||
let effect_footer =
|
||||
fs::read_to_string(Path::new("src/lib/effect_node/effect_footer.wgsl")).unwrap();
|
||||
let effect_noop = "fn main(uv: vec2<f32>) -> vec4<f32> { return vec4<f32>(0., 0., 0., 0.); }";
|
||||
|
||||
shader_sources.push((
|
||||
@@ -73,7 +79,6 @@ fn check_builtin_shaders() {
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
fn check_library_shaders() {
|
||||
let mut had_errors = false;
|
||||
|
||||
@@ -81,95 +86,88 @@ fn check_library_shaders() {
|
||||
let library_dir = Path::new("library");
|
||||
println!("cargo:rerun-if-changed=library/");
|
||||
|
||||
if library_dir.exists() && library_dir.is_dir() {
|
||||
let library_shaders = fs::read_dir(library_dir)
|
||||
.expect("Failed to read library directory")
|
||||
.filter_map(|entry| {
|
||||
let entry = entry.ok()?;
|
||||
let path = entry.path();
|
||||
if path.extension()?.to_str()? == "wgsl" {
|
||||
Some(path)
|
||||
} else {
|
||||
None
|
||||
let library_shaders = fs::read_dir(library_dir)
|
||||
.expect("Failed to read library directory")
|
||||
.filter_map(|entry| {
|
||||
let entry = entry.ok()?;
|
||||
let path = entry.path();
|
||||
if path.extension()?.to_str()? == "wgsl" {
|
||||
Some(path)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
});
|
||||
|
||||
println!("cargo:rerun-if-changed=src/lib/effect_node/effect_header.wgsl");
|
||||
println!("cargo:rerun-if-changed=src/lib/effect_node/effect_footer.wgsl");
|
||||
let effect_header =
|
||||
fs::read_to_string(Path::new("src/lib/effect_node/effect_header.wgsl")).unwrap();
|
||||
let effect_footer =
|
||||
fs::read_to_string(Path::new("src/lib/effect_node/effect_footer.wgsl")).unwrap();
|
||||
|
||||
for shader_path in library_shaders {
|
||||
println!("cargo:rerun-if-changed={}", shader_path.display());
|
||||
|
||||
let shader_source = match fs::read_to_string(&shader_path) {
|
||||
Ok(source) => source,
|
||||
Err(e) => {
|
||||
eprintln!(
|
||||
"Failed to read effect node file {}: {}",
|
||||
shader_path.display(),
|
||||
e
|
||||
);
|
||||
had_errors = true;
|
||||
continue;
|
||||
}
|
||||
};
|
||||
|
||||
let (buffer_shader_sources, _input_count, _frequency) =
|
||||
match preprocess_shader(&shader_source) {
|
||||
Ok(results) => results,
|
||||
Err(e) => {
|
||||
eprintln!(
|
||||
"Failed to parse effect node file {}: {}",
|
||||
shader_path.display(),
|
||||
e
|
||||
);
|
||||
had_errors = true;
|
||||
continue;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
let header_source = match fs::read_to_string("src/lib/effect_header.wgsl") {
|
||||
Ok(source) => Some(source),
|
||||
Err(e) => {
|
||||
eprintln!("Failed to read shader file {}: {}", shader_path, e);
|
||||
had_errors = true;
|
||||
None
|
||||
}
|
||||
};
|
||||
for buffer_shader_source in buffer_shader_sources {
|
||||
// Parse and validate the WGSL shader using naga
|
||||
match naga::front::wgsl::parse_str(&format!(
|
||||
"{}\n{}\n{}\n",
|
||||
effect_header, buffer_shader_source, effect_footer
|
||||
)) {
|
||||
Ok(module) => {
|
||||
// Validate the module
|
||||
let mut validator = naga::valid::Validator::new(
|
||||
naga::valid::ValidationFlags::all(),
|
||||
naga::valid::Capabilities::all(),
|
||||
);
|
||||
|
||||
let footer_source = match fs::read_to_string("src/lib/effect_footer.wgsl") {
|
||||
Ok(source) => Some(source),
|
||||
Err(e) => {
|
||||
eprintln!("Failed to read shader file {}: {}", shader_path, e);
|
||||
had_errors = true;
|
||||
None
|
||||
}
|
||||
};
|
||||
|
||||
if let (Some(header_source), Some(footer_source)) = (header_source, footer_source) {
|
||||
for shader_path in library_shaders {
|
||||
println!("cargo:rerun-if-changed={}", shader_path.display());
|
||||
|
||||
let shader_source = match fs::read_to_string(&shader_path) {
|
||||
Ok(source) => source,
|
||||
Err(e) => {
|
||||
eprintln!(
|
||||
"Failed to read shader file {}: {}",
|
||||
shader_path.display(),
|
||||
e
|
||||
);
|
||||
had_errors = true;
|
||||
continue;
|
||||
}
|
||||
};
|
||||
|
||||
// Parse and validate the WGSL shader using naga
|
||||
match naga::front::wgsl::parse_str(&format!(
|
||||
"{}\n{}\n{}\n",
|
||||
header_source, shader_source, footer_source
|
||||
)) {
|
||||
Ok(module) => {
|
||||
// Validate the module
|
||||
let mut validator = naga::valid::Validator::new(
|
||||
naga::valid::ValidationFlags::all(),
|
||||
naga::valid::Capabilities::all(),
|
||||
);
|
||||
|
||||
match validator.validate(&module) {
|
||||
Ok(_) => {
|
||||
println!(
|
||||
"cargo:warning=✓ Validated shader: {}",
|
||||
shader_path.display()
|
||||
);
|
||||
}
|
||||
Err(e) => {
|
||||
eprintln!("Validation error in {}: {}", shader_path.display(), e);
|
||||
had_errors = true;
|
||||
}
|
||||
match validator.validate(&module) {
|
||||
Ok(_) => {}
|
||||
Err(e) => {
|
||||
eprintln!("Validation error in {}: {}", shader_path.display(), e);
|
||||
had_errors = true;
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
eprintln!("Parse error in {}: {}", shader_path.display(), e);
|
||||
had_errors = true;
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
eprintln!("WGSL parse error in {}: {}", shader_path.display(), e);
|
||||
had_errors = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
println!("cargo:warning=Library directory 'library/' not found, skipping library shaders");
|
||||
}
|
||||
|
||||
if had_errors {
|
||||
panic!("Shader validation failed!");
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
fn embed_default_library() {
|
||||
let out_dir = env::var("OUT_DIR").unwrap();
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#property description Overlays a smaller pattern and zoom in on it
|
||||
#property frequency 0.5
|
||||
|
||||
let N_COPIES = 8;
|
||||
const N_COPIES = 8;
|
||||
|
||||
fn lookup(uv: vec2<f32>, scale: f32) -> vec4<f32>{
|
||||
let newUV = (uv - 0.5) * scale + 0.5;
|
||||
|
||||
@@ -6,6 +6,9 @@ use std::collections::HashMap;
|
||||
use std::num::NonZeroU32;
|
||||
use std::string::String;
|
||||
|
||||
mod preprocess_shader;
|
||||
use preprocess_shader::preprocess_shader;
|
||||
|
||||
const EFFECT_HEADER: &str = include_str!("effect_header.wgsl");
|
||||
const EFFECT_FOOTER: &str = include_str!("effect_footer.wgsl");
|
||||
const INTENSITY_INTEGRAL_PERIOD: f32 = 1024.;
|
||||
@@ -86,53 +89,6 @@ fn handle_shader_error(error: wgpu::Error) {
|
||||
eprintln!("wgpu error: {}\n", error);
|
||||
}
|
||||
|
||||
fn preprocess_shader(effect_source: &str) -> Result<(Vec<String>, u32, f32), String> {
|
||||
let mut processed_sources = Vec::<String>::new();
|
||||
let mut processed_source = String::new();
|
||||
let mut input_count = 1;
|
||||
let mut frequency = 0.;
|
||||
|
||||
for l in effect_source.lines() {
|
||||
let line_parts: Vec<&str> = l.split_whitespace().collect();
|
||||
if !line_parts.is_empty() && line_parts[0] == "#property" {
|
||||
if line_parts.len() >= 2 {
|
||||
if line_parts[1] == "inputCount" {
|
||||
if line_parts.len() >= 3 {
|
||||
input_count = line_parts[2].parse::<u32>().map_err(|e| e.to_string())?;
|
||||
} else {
|
||||
return Err(String::from("inputCount missing argument"));
|
||||
}
|
||||
} else if line_parts[1] == "frequency" {
|
||||
if line_parts.len() >= 3 {
|
||||
frequency = line_parts[2].parse::<f32>().map_err(|e| e.to_string())?;
|
||||
} else {
|
||||
return Err(String::from("frequency missing argument"));
|
||||
}
|
||||
} else if line_parts[1] == "description" {
|
||||
if line_parts.len() >= 3 {
|
||||
// TODO parse description and do something with it
|
||||
} else {
|
||||
return Err(String::from("description missing argument"));
|
||||
}
|
||||
} else {
|
||||
return Err(format!("Unrecognized property: {}", line_parts[1]));
|
||||
}
|
||||
} else {
|
||||
return Err(String::from("Missing property name"));
|
||||
}
|
||||
} else if !line_parts.is_empty() && line_parts[0] == "#buffershader" {
|
||||
processed_sources.push(std::mem::take(&mut processed_source));
|
||||
} else {
|
||||
processed_source.push_str(l);
|
||||
processed_source.push('\n');
|
||||
}
|
||||
}
|
||||
|
||||
processed_sources.push(processed_source);
|
||||
|
||||
Ok((processed_sources, input_count, frequency))
|
||||
}
|
||||
|
||||
// This is a state machine, it's more natural to use `match` than `if let`
|
||||
#[allow(clippy::single_match)]
|
||||
impl EffectNodeState {
|
||||
@@ -0,0 +1,46 @@
|
||||
pub fn preprocess_shader(effect_source: &str) -> Result<(Vec<String>, u32, f32), String> {
|
||||
let mut processed_sources = Vec::<String>::new();
|
||||
let mut processed_source = String::new();
|
||||
let mut input_count = 1;
|
||||
let mut frequency = 0.;
|
||||
|
||||
for l in effect_source.lines() {
|
||||
let line_parts: Vec<&str> = l.split_whitespace().collect();
|
||||
if !line_parts.is_empty() && line_parts[0] == "#property" {
|
||||
if line_parts.len() >= 2 {
|
||||
if line_parts[1] == "inputCount" {
|
||||
if line_parts.len() >= 3 {
|
||||
input_count = line_parts[2].parse::<u32>().map_err(|e| e.to_string())?;
|
||||
} else {
|
||||
return Err(String::from("inputCount missing argument"));
|
||||
}
|
||||
} else if line_parts[1] == "frequency" {
|
||||
if line_parts.len() >= 3 {
|
||||
frequency = line_parts[2].parse::<f32>().map_err(|e| e.to_string())?;
|
||||
} else {
|
||||
return Err(String::from("frequency missing argument"));
|
||||
}
|
||||
} else if line_parts[1] == "description" {
|
||||
if line_parts.len() >= 3 {
|
||||
// TODO parse description and do something with it
|
||||
} else {
|
||||
return Err(String::from("description missing argument"));
|
||||
}
|
||||
} else {
|
||||
return Err(format!("Unrecognized property: {}", line_parts[1]));
|
||||
}
|
||||
} else {
|
||||
return Err(String::from("Missing property name"));
|
||||
}
|
||||
} else if !line_parts.is_empty() && line_parts[0] == "#buffershader" {
|
||||
processed_sources.push(std::mem::take(&mut processed_source));
|
||||
} else {
|
||||
processed_source.push_str(l);
|
||||
processed_source.push('\n');
|
||||
}
|
||||
}
|
||||
|
||||
processed_sources.push(processed_source);
|
||||
|
||||
Ok((processed_sources, input_count, frequency))
|
||||
}
|
||||
Reference in New Issue
Block a user