librashader_preprocess/
lib.rs1mod error;
12mod include;
13mod pragma;
14mod stage;
15
16use crate::include::read_source;
17pub use error::*;
18use librashader_common::map::{FastHashMap, ShortString};
19use librashader_common::shader_features::ShaderFeatures;
20use librashader_common::ImageFormat;
21use std::path::Path;
22
23#[derive(Debug, Clone, PartialEq)]
25#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
26pub struct ShaderSource {
27 pub vertex: String,
29
30 pub fragment: String,
32
33 pub name: Option<ShortString>,
35
36 pub parameters: FastHashMap<ShortString, ShaderParameter>,
38
39 pub format: ImageFormat,
41}
42
43#[derive(Debug, Clone, PartialEq)]
45#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
46pub struct ShaderParameter {
47 pub id: ShortString,
49 pub description: String,
51 pub initial: f32,
53 pub minimum: f32,
55 pub maximum: f32,
57 pub step: f32,
59}
60
61impl ShaderSource {
62 pub fn load(
65 path: impl AsRef<Path>,
66 features: ShaderFeatures,
67 ) -> Result<ShaderSource, PreprocessError> {
68 load_shader_source(path, features)
69 }
70}
71
72pub(crate) trait SourceOutput {
73 fn push_line(&mut self, str: &str);
74 fn mark_line(&mut self, line_no: usize, comment: &str) {
75 #[cfg(feature = "line_directives")]
76 self.push_line(&format!("#line {line_no} \"{comment}\""))
77 }
78}
79
80impl SourceOutput for String {
81 fn push_line(&mut self, str: &str) {
82 self.push_str(str);
83 self.push('\n');
84 }
85}
86
87pub(crate) fn load_shader_source(
88 path: impl AsRef<Path>,
89 features: ShaderFeatures,
90) -> Result<ShaderSource, PreprocessError> {
91 let source = read_source(path, features)?;
92 let meta = pragma::parse_pragma_meta(&source)?;
93
94 let text = stage::process_stages(&source)?;
95 let parameters = FastHashMap::from_iter(meta.parameters.into_iter().map(|p| (p.id.clone(), p)));
96
97 Ok(ShaderSource {
98 vertex: text.vertex,
99 fragment: text.fragment,
100 name: meta.name,
101 parameters,
102 format: meta.format,
103 })
104}
105
106#[cfg(test)]
107mod test {
108 use crate::include::read_source;
109 use crate::{load_shader_source, pragma};
110 use librashader_common::shader_features::ShaderFeatures;
111
112 #[test]
113 pub fn load_file() {
114 let result = load_shader_source(
115 "../test/shaders_slang/blurs/shaders/royale/blur3x3-last-pass.slang",
116 ShaderFeatures::NONE,
117 )
118 .unwrap();
119 eprintln!("{:#}", result.vertex)
120 }
121
122 #[test]
123 pub fn preprocess_file() {
124 let result = read_source(
125 "../test/slang-shaders/blurs/shaders/royale/blur3x3-last-pass.slang",
126 ShaderFeatures::NONE,
127 )
128 .unwrap();
129 eprintln!("{result}")
130 }
131
132 #[test]
133 pub fn get_param_pragmas() {
134 let result = read_source(
135 "../test/slang-shaders/crt/shaders/crt-maximus-royale/src/ntsc_pass1.slang",
136 ShaderFeatures::NONE,
137 )
138 .unwrap();
139
140 let params = pragma::parse_pragma_meta(result).unwrap();
141 eprintln!("{params:?}")
142 }
143
144 #[test]
145 pub fn include_optional() {
146 let result =
147 read_source("../test/include_optional/pass.slang", ShaderFeatures::NONE).unwrap();
148
149 eprintln!("{result}")
150 }
151}