summary refs log tree commit diff
path: root/build.rs
diff options
context:
space:
mode:
authorIrene Knapp <ireneista@irenes.space>2026-08-09 20:09:35 -0700
committerIrene Knapp <ireneista@irenes.space>2026-08-09 20:23:13 -0700
commitbbe9d5993bb922ad6b33a21c3557143cecaf960d (patch)
tree387488a0a6b35aa5ba1fef1adcdc400d0f4935b6 /build.rs
parent677b697eb18b9abb252eacff320aa48314075a0e (diff)
abstract over bundled assets
yay build script stuff :)

Force-Push: yes
Change-Id: I694651febb02f42dac904f0dfbf4089c33ef937e
Diffstat (limited to 'build.rs')
-rw-r--r--build.rs128
1 files changed, 117 insertions, 11 deletions
diff --git a/build.rs b/build.rs
index ce74854..a6c5756 100644
--- a/build.rs
+++ b/build.rs
@@ -1,8 +1,31 @@
+use std::collections::BTreeSet;
 use std::env;
-use std::fs;
-use std::path::Path;
+use std::fs::{ self, File };
+use std::io::Write;
+use std::path::{ Path, PathBuf };
 use std::process::Command;
 
+struct Error(String);
+impl std::fmt::Display for Error {
+  fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>)
+      -> std::result::Result<(), std::fmt::Error>
+  {
+    fmt.write_str(&self.0)
+  }
+}
+impl From<std::io::Error> for Error {
+  fn from(e: std::io::Error) -> Self {
+    Error(format!("System I/O error: {}", e))
+  }
+}
+impl From<std::path::StripPrefixError> for Error {
+  fn from(e: std::path::StripPrefixError) -> Self {
+    Error(format!("Can't strip path prefix: {}", e))
+  }
+}
+type Result<T> = std::result::Result<T, Error>;
+
+
 fn main() {
   match process_all() {
     Err(error) => println!("cargo-error={}", error),
@@ -11,18 +34,25 @@ fn main() {
 }
 
 
-fn process_all() -> std::io::Result<()> {
-  process_shaders()?;
-  process_textures()?;
-  process_models()?;
+fn process_all() -> Result<()> {
+  let mut asset_paths: BTreeSet<PathBuf> = BTreeSet::new();
+
+  process_shaders(&mut asset_paths)?;
+  process_textures(&mut asset_paths)?;
+  process_models(&mut asset_paths)?;
+
+  generate_asset_module(asset_paths)?;
 
   Ok(())
 }
 
 
-fn process_shaders() -> std::io::Result<()> {
+fn process_shaders(asset_paths: &mut BTreeSet<PathBuf>) -> Result<()>
+{
   let out_dir = env::var_os("OUT_DIR").unwrap();
 
+  fs::create_dir_all(Path::new(&out_dir).join("shaders/"))?;
+
   for input in fs::read_dir("shaders")? {
     let input_path = input?.path();
     if !input_path.is_file() {
@@ -38,14 +68,14 @@ fn process_shaders() -> std::io::Result<()> {
 
     let output_path
             = Path::new(&out_dir)
-                  .join(format!("{}.spv",
+                  .join(format!("shaders/{}.spv",
                         input_path.file_name().unwrap().to_str().unwrap()));
 
     let result = Command::new("glslang")
             .arg("-V")
             .arg(&input_path)
             .arg("-o")
-            .arg(output_path)
+            .arg(&output_path)
             .output()?;
     if !result.status.success() {
       println!("cargo::error=Failed to compile shader {}; details follow.",
@@ -56,13 +86,15 @@ fn process_shaders() -> std::io::Result<()> {
     }
 
     println!("cargo::rerun-if-changed={}", input_path.display());
+
+    asset_paths.insert(output_path.to_path_buf());
   }
 
   Ok(())
 }
 
 
-fn process_textures() -> std::io::Result<()> {
+fn process_textures(asset_paths: &mut BTreeSet<PathBuf>) -> Result<()> {
   for input in fs::read_dir("textures")? {
     let input_path = input?.path();
     if !input_path.is_file() {
@@ -76,14 +108,26 @@ fn process_textures() -> std::io::Result<()> {
       continue;
     }
 
+    if let Some(Some(extension)) = input_path.extension()
+                                             .map(|a| a.to_str())
+    {
+      if extension != "png" {
+        continue;
+      }
+    } else {
+      continue;
+    }
+
     println!("cargo::rerun-if-changed={}", input_path.display());
+
+    asset_paths.insert(input_path.to_path_buf());
   }
 
   Ok(())
 }
 
 
-fn process_models() -> std::io::Result<()> {
+fn process_models(asset_paths: &mut BTreeSet<PathBuf>) -> Result<()> {
   for input in fs::read_dir("models")? {
     let input_path = input?.path();
     if !input_path.is_file() {
@@ -97,9 +141,71 @@ fn process_models() -> std::io::Result<()> {
       continue;
     }
 
+    if let Some(Some(extension)) = input_path.extension()
+                                             .map(|a| a.to_str())
+    {
+      if extension != "obj" {
+        continue;
+      }
+    } else {
+      continue;
+    }
+
     println!("cargo::rerun-if-changed={}", input_path.display());
+
+    asset_paths.insert(input_path.to_path_buf());
   }
 
   Ok(())
 }
 
+
+fn generate_asset_module(asset_paths: BTreeSet<PathBuf>) -> Result<()> {
+  let out_dir = env::var_os("OUT_DIR")
+                    .ok_or(Error("Don't have $OUT_DIR.".to_string()))?;
+  let output_path = Path::new(&out_dir).join("assets.rs");
+  let mut file = File::create(output_path)?;
+
+  let source_dir = env::current_dir()?;
+
+  println!("cargo::warning=assets {:?}", asset_paths);
+  writeln!(file, "#[deny(unsafe_code)]")?;
+  writeln!(file, "pub fn asset(name: &str) -> crate::error::Result<&[u8]> {{");
+  writeln!(file, "  match name {{");
+
+  for asset_path in asset_paths {
+    let name = if asset_path.starts_with(&out_dir) {
+      asset_path.strip_prefix(&out_dir)?
+    } else {
+      &asset_path
+    }.to_str()
+     .ok_or(Error("Can't stringify path - weird filesystem?".to_string()))?;
+
+    let include_path = if asset_path.is_absolute() {
+      asset_path.to_path_buf()
+    } else {
+      Path::new(&source_dir).join(&asset_path).to_path_buf()
+    };
+    let mut include_path = include_path.to_path_buf();
+    include_path = include_path.strip_prefix(&source_dir)?.to_path_buf();
+    for _ in Path::new(&out_dir).strip_prefix(&source_dir)?.components() {
+      include_path = Path::new("../").join(include_path).to_path_buf();
+    }
+    let include_path = include_path
+            .to_str()
+            .ok_or(Error("Can't stringify path - weird filesystem?"
+                             .to_string()))?;
+
+    writeln!(file, "    \"{}\" => Ok(include_bytes!(\"{}\")),",
+             name.escape_default(),
+             include_path.escape_default());
+  }
+
+  writeln!(file, "    _ => Err(crate::error::Error {{");
+  writeln!(file, "      message: format!(\"No such asset {{:?}}\", name)");
+  writeln!(file, "    }})");
+  writeln!(file, "  }}");
+  writeln!(file, "}}");
+
+  Ok(())
+}