preprocess: implement stage separator to complete preprocessor
This commit is contained in:
parent
394e09678d
commit
3f83e0fcd0
|
@ -15,13 +15,12 @@ pub enum PreprocessError {
|
|||
UnexpectedEol(usize),
|
||||
#[error("error parsing pragma")]
|
||||
PragmaParseError(String),
|
||||
#[error("duplicate parameter but arguments do not match")]
|
||||
DuplicateParameterError(String),
|
||||
#[error("duplicate pragma found")]
|
||||
DuplicatePragmaError(String),
|
||||
#[error("shader format is unknown or not found")]
|
||||
UnknownShaderFormat,
|
||||
#[error("tried to declare shader format twice")]
|
||||
DuplicateShaderFormat,
|
||||
|
||||
#[error("stage must be either vertex or fragment")]
|
||||
InvalidStage,
|
||||
}
|
||||
|
||||
impl From<Infallible> for PreprocessError {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use crate::PreprocessError;
|
||||
use crate::{PreprocessError, SourceOutput};
|
||||
use std::fs::File;
|
||||
use std::io::Read;
|
||||
use std::path::Path;
|
||||
|
@ -7,20 +7,6 @@ use std::str::Lines;
|
|||
const GL_GOOGLE_CPP_STYLE_LINE_DIRECTIVE: &'static str =
|
||||
"#extension GL_GOOGLE_CPP_STYLE_LINE_DIRECTIVE : require";
|
||||
|
||||
trait SourceOutput {
|
||||
fn push_line(&mut self, str: &str);
|
||||
fn mark_line(&mut self, line_no: usize, comment: &str) {
|
||||
self.push_line(&format!("#line {} \"{}\"", line_no, comment))
|
||||
}
|
||||
}
|
||||
|
||||
impl SourceOutput for String {
|
||||
fn push_line(&mut self, str: &str) {
|
||||
self.push_str(str);
|
||||
self.push('\n');
|
||||
}
|
||||
}
|
||||
|
||||
fn read_file(path: impl AsRef<Path>) -> Result<String, PreprocessError> {
|
||||
let path = path.as_ref();
|
||||
let mut source = String::new();
|
||||
|
|
|
@ -1,13 +1,54 @@
|
|||
mod error;
|
||||
mod include;
|
||||
mod pragma;
|
||||
mod stage;
|
||||
|
||||
use std::path::Path;
|
||||
pub use error::*;
|
||||
use librashader::ShaderSource;
|
||||
use crate::include::read_source;
|
||||
|
||||
|
||||
pub(crate) trait SourceOutput {
|
||||
fn push_line(&mut self, str: &str);
|
||||
fn mark_line(&mut self, line_no: usize, comment: &str) {
|
||||
self.push_line(&format!("#line {} \"{}\"", line_no, comment))
|
||||
}
|
||||
}
|
||||
|
||||
impl SourceOutput for String {
|
||||
fn push_line(&mut self, str: &str) {
|
||||
self.push_str(str);
|
||||
self.push('\n');
|
||||
}
|
||||
}
|
||||
|
||||
pub fn load_shader_source(path: impl AsRef<Path>) -> Result<ShaderSource, PreprocessError> {
|
||||
let source = read_source(path)?;
|
||||
let meta = pragma::parse_pragma_meta(&source)?;
|
||||
let text = stage::process_stages(&source)?;
|
||||
|
||||
Ok(ShaderSource {
|
||||
vertex: text.vertex,
|
||||
fragment: text.fragment,
|
||||
name: meta.name,
|
||||
parameters: meta.parameters,
|
||||
format: meta.format,
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use crate::include::read_source;
|
||||
use crate::pragma;
|
||||
use crate::{load_shader_source, pragma};
|
||||
|
||||
#[test]
|
||||
pub fn load_file() {
|
||||
let result =
|
||||
load_shader_source("../test/slang-shaders/blurs/shaders/royale/blur3x3-last-pass.slang")
|
||||
.unwrap();
|
||||
eprintln!("{result:#?}")
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn preprocess_file() {
|
||||
|
|
|
@ -7,6 +7,12 @@ use nom::sequence::delimited;
|
|||
use librashader::{ShaderFormat, ShaderParameter};
|
||||
use crate::PreprocessError;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct ShaderMeta {
|
||||
pub(crate) format: ShaderFormat,
|
||||
pub(crate) parameters: Vec<ShaderParameter>,
|
||||
pub(crate) name: Option<String>
|
||||
}
|
||||
|
||||
fn parse_parameter_string(input: &str) -> Result<ShaderParameter, PreprocessError>{
|
||||
fn parse_parameter_string_inner(input: &str) -> IResult<&str, ShaderParameter> {
|
||||
|
@ -39,16 +45,17 @@ fn parse_parameter_string(input: &str) -> Result<ShaderParameter, PreprocessErro
|
|||
}
|
||||
}
|
||||
|
||||
pub fn parse_pragma_meta(source: impl AsRef<str>) -> Result<(ShaderFormat, Vec<ShaderParameter>), PreprocessError> {
|
||||
pub(crate) fn parse_pragma_meta(source: impl AsRef<str>) -> Result<ShaderMeta, PreprocessError> {
|
||||
let source = source.as_ref();
|
||||
let mut parameters: Vec<ShaderParameter> = Vec::new();
|
||||
let mut format = ShaderFormat::default();
|
||||
let mut name = None;
|
||||
for line in source.lines() {
|
||||
if line.starts_with("#pragma parameter ") {
|
||||
let parameter = parse_parameter_string(line)?;
|
||||
if let Some(existing) = parameters.iter().find(|&p| p.id == parameter.id) {
|
||||
if existing != ¶meter {
|
||||
return Err(PreprocessError::DuplicateParameterError(parameter.id))
|
||||
return Err(PreprocessError::DuplicatePragmaError(parameter.id))
|
||||
}
|
||||
} else {
|
||||
parameters.push(parameter);
|
||||
|
@ -57,7 +64,7 @@ pub fn parse_pragma_meta(source: impl AsRef<str>) -> Result<(ShaderFormat, Vec<S
|
|||
|
||||
if line.starts_with("#pragma format ") {
|
||||
if format != ShaderFormat::Unknown {
|
||||
return Err(PreprocessError::DuplicateShaderFormat)
|
||||
return Err(PreprocessError::DuplicatePragmaError(line.to_string()))
|
||||
}
|
||||
|
||||
let format_string = line["#pragma format ".len()..].trim();
|
||||
|
@ -67,9 +74,17 @@ pub fn parse_pragma_meta(source: impl AsRef<str>) -> Result<(ShaderFormat, Vec<S
|
|||
return Err(PreprocessError::UnknownShaderFormat)
|
||||
}
|
||||
}
|
||||
|
||||
if line.starts_with("#pragma name ") {
|
||||
if name.is_some() {
|
||||
return Err(PreprocessError::DuplicatePragmaError(line.to_string()));
|
||||
}
|
||||
|
||||
name = Some(line.trim().to_string())
|
||||
}
|
||||
}
|
||||
|
||||
Ok((format, parameters))
|
||||
Ok(ShaderMeta { name, format, parameters })
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
|
58
librashader-preprocess/src/stage.rs
Normal file
58
librashader-preprocess/src/stage.rs
Normal file
|
@ -0,0 +1,58 @@
|
|||
use std::str::FromStr;
|
||||
use crate::{PreprocessError, SourceOutput};
|
||||
|
||||
enum ActiveStage {
|
||||
Both,
|
||||
Fragment,
|
||||
Vertex
|
||||
}
|
||||
|
||||
impl FromStr for ActiveStage {
|
||||
type Err = PreprocessError;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
match s {
|
||||
"vertex" => Ok(ActiveStage::Vertex),
|
||||
"fragment" => Ok(ActiveStage::Fragment),
|
||||
_ => Err(PreprocessError::InvalidStage)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub(crate) struct ShaderOutput {
|
||||
pub(crate) fragment: String,
|
||||
pub(crate) vertex: String
|
||||
}
|
||||
|
||||
pub(crate) fn process_stages(source: &str) -> Result<ShaderOutput, PreprocessError> {
|
||||
let mut active_stage = ActiveStage::Both;
|
||||
let mut output = ShaderOutput::default();
|
||||
|
||||
for line in source.lines() {
|
||||
if line.starts_with("#pragma stage ") {
|
||||
let stage = line["#pragma stage ".len()..].trim();
|
||||
active_stage = ActiveStage::from_str(stage)?;
|
||||
continue;
|
||||
}
|
||||
|
||||
if line.starts_with("#pragma name ") || line.starts_with("#pragma format ") {
|
||||
continue;
|
||||
}
|
||||
|
||||
match active_stage {
|
||||
ActiveStage::Both => {
|
||||
output.fragment.push_line(line);
|
||||
output.vertex.push_line(line);
|
||||
}
|
||||
ActiveStage::Fragment => {
|
||||
output.fragment.push_line(line);
|
||||
}
|
||||
ActiveStage::Vertex => {
|
||||
output.vertex.push_line(line)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(output)
|
||||
}
|
|
@ -1,6 +1,7 @@
|
|||
use std::convert::Infallible;
|
||||
use std::str::FromStr;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub struct ShaderSource {
|
||||
pub vertex: String,
|
||||
pub fragment: String,
|
||||
|
|
Loading…
Reference in a new issue