use concinnity_core::platform::Platform;
use concinnity_core::render::shader_programs::Variant;
use concinnity_core::render::shader_source::Splice;
pub(crate) fn assemble(
hot_reload: bool,
platform: Platform,
file: &str,
defines: &[(&str, &str)],
splices: &[Splice<'_>],
) -> String {
let resolve = |f: &str| hot_reload.then(|| from_checkout(f)).flatten();
concinnity_core::render::shader_source::assemble_with_splices(
file, platform, defines, resolve, splices,
)
}
pub(crate) fn assemble_variant(hot_reload: bool, platform: Platform, v: Variant<'_>) -> String {
assemble(hot_reload, platform, v.program.file, &v.defines(), &[])
}
pub(crate) fn from_checkout(file: &str) -> Option<&'static str> {
let path = format!(
"{}/../concinnity-core/src/render/shaders/{}",
env!("CARGO_MANIFEST_DIR"),
file
);
match std::fs::read_to_string(&path) {
Ok(text) => Some(Box::leak(text.into_boxed_str())),
Err(e) => {
tracing::debug!("hot-reload: falling back to embedded {file} ({e})");
None
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn the_embedded_body_is_assembled_with_defines_leading() {
let src = assemble(false, Platform::Vulkan, "fog.hlsl", &[("A", "1")], &[]);
assert!(src.starts_with("#define CN_BACKEND_VULKAN 1\n#define A 1\n"));
assert!(!src.contains("{POST_COMMON}"));
}
#[test]
fn a_missing_hot_reload_file_falls_back_to_embedded() {
assert_eq!(
assemble(
true,
Platform::Metal,
"definitely_not_a_shader.hlsl",
&[("A", "1")],
&[]
),
"#define CN_BACKEND_METAL 1\n#define A 1\n"
);
}
#[test]
fn hot_reload_matches_the_embedded_assembly_for_an_unedited_shader() {
assert_eq!(
assemble(true, Platform::DirectX, "fog.hlsl", &[("A", "1")], &[]),
assemble(false, Platform::DirectX, "fog.hlsl", &[("A", "1")], &[])
);
}
}