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),
|
UnexpectedEol(usize),
|
||||||
#[error("error parsing pragma")]
|
#[error("error parsing pragma")]
|
||||||
PragmaParseError(String),
|
PragmaParseError(String),
|
||||||
#[error("duplicate parameter but arguments do not match")]
|
#[error("duplicate pragma found")]
|
||||||
DuplicateParameterError(String),
|
DuplicatePragmaError(String),
|
||||||
#[error("shader format is unknown or not found")]
|
#[error("shader format is unknown or not found")]
|
||||||
UnknownShaderFormat,
|
UnknownShaderFormat,
|
||||||
#[error("tried to declare shader format twice")]
|
#[error("stage must be either vertex or fragment")]
|
||||||
DuplicateShaderFormat,
|
InvalidStage,
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<Infallible> for PreprocessError {
|
impl From<Infallible> for PreprocessError {
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use crate::PreprocessError;
|
use crate::{PreprocessError, SourceOutput};
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io::Read;
|
use std::io::Read;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
@ -7,20 +7,6 @@ use std::str::Lines;
|
||||||
const GL_GOOGLE_CPP_STYLE_LINE_DIRECTIVE: &'static str =
|
const GL_GOOGLE_CPP_STYLE_LINE_DIRECTIVE: &'static str =
|
||||||
"#extension GL_GOOGLE_CPP_STYLE_LINE_DIRECTIVE : require";
|
"#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> {
|
fn read_file(path: impl AsRef<Path>) -> Result<String, PreprocessError> {
|
||||||
let path = path.as_ref();
|
let path = path.as_ref();
|
||||||
let mut source = String::new();
|
let mut source = String::new();
|
||||||
|
|
|
@ -1,13 +1,54 @@
|
||||||
mod error;
|
mod error;
|
||||||
mod include;
|
mod include;
|
||||||
mod pragma;
|
mod pragma;
|
||||||
|
mod stage;
|
||||||
|
|
||||||
|
use std::path::Path;
|
||||||
pub use error::*;
|
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)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use crate::include::read_source;
|
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]
|
#[test]
|
||||||
pub fn preprocess_file() {
|
pub fn preprocess_file() {
|
||||||
|
|
|
@ -7,6 +7,12 @@ use nom::sequence::delimited;
|
||||||
use librashader::{ShaderFormat, ShaderParameter};
|
use librashader::{ShaderFormat, ShaderParameter};
|
||||||
use crate::PreprocessError;
|
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(input: &str) -> Result<ShaderParameter, PreprocessError>{
|
||||||
fn parse_parameter_string_inner(input: &str) -> IResult<&str, ShaderParameter> {
|
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 source = source.as_ref();
|
||||||
let mut parameters: Vec<ShaderParameter> = Vec::new();
|
let mut parameters: Vec<ShaderParameter> = Vec::new();
|
||||||
let mut format = ShaderFormat::default();
|
let mut format = ShaderFormat::default();
|
||||||
|
let mut name = None;
|
||||||
for line in source.lines() {
|
for line in source.lines() {
|
||||||
if line.starts_with("#pragma parameter ") {
|
if line.starts_with("#pragma parameter ") {
|
||||||
let parameter = parse_parameter_string(line)?;
|
let parameter = parse_parameter_string(line)?;
|
||||||
if let Some(existing) = parameters.iter().find(|&p| p.id == parameter.id) {
|
if let Some(existing) = parameters.iter().find(|&p| p.id == parameter.id) {
|
||||||
if existing != ¶meter {
|
if existing != ¶meter {
|
||||||
return Err(PreprocessError::DuplicateParameterError(parameter.id))
|
return Err(PreprocessError::DuplicatePragmaError(parameter.id))
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
parameters.push(parameter);
|
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 line.starts_with("#pragma format ") {
|
||||||
if format != ShaderFormat::Unknown {
|
if format != ShaderFormat::Unknown {
|
||||||
return Err(PreprocessError::DuplicateShaderFormat)
|
return Err(PreprocessError::DuplicatePragmaError(line.to_string()))
|
||||||
}
|
}
|
||||||
|
|
||||||
let format_string = line["#pragma format ".len()..].trim();
|
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)
|
return Err(PreprocessError::UnknownShaderFormat)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if line.starts_with("#pragma name ") {
|
||||||
|
if name.is_some() {
|
||||||
|
return Err(PreprocessError::DuplicatePragmaError(line.to_string()));
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok((format, parameters))
|
name = Some(line.trim().to_string())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(ShaderMeta { name, format, parameters })
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[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::convert::Infallible;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
pub struct ShaderSource {
|
pub struct ShaderSource {
|
||||||
pub vertex: String,
|
pub vertex: String,
|
||||||
pub fragment: String,
|
pub fragment: String,
|
||||||
|
|
Loading…
Reference in a new issue