preset: implement texture and parameter parsing
This commit is contained in:
parent
c5b0ce211c
commit
1c2a83df09
|
@ -4,10 +4,15 @@ use thiserror::Error;
|
||||||
|
|
||||||
#[derive(Error, Debug)]
|
#[derive(Error, Debug)]
|
||||||
pub enum ParsePresetError {
|
pub enum ParsePresetError {
|
||||||
#[error("shader preset parse error")]
|
#[error("shader preset lexing error")]
|
||||||
LexerError { offset: usize, row: u32, col: usize },
|
LexerError { offset: usize, row: u32, col: usize },
|
||||||
#[error("shader preset parse error")]
|
#[error("shader preset parse error")]
|
||||||
ParserError { offset: usize, row: u32, col: usize },
|
ParserError {
|
||||||
|
offset: usize,
|
||||||
|
row: u32,
|
||||||
|
col: usize,
|
||||||
|
kind: ParseErrorKind,
|
||||||
|
},
|
||||||
#[error("invalid scale type")]
|
#[error("invalid scale type")]
|
||||||
InvalidScaleType(String),
|
InvalidScaleType(String),
|
||||||
#[error("exceeded maximum reference depth (16)")]
|
#[error("exceeded maximum reference depth (16)")]
|
||||||
|
@ -19,3 +24,11 @@ pub enum ParsePresetError {
|
||||||
#[error("expected utf8 bytes but got invalid utf8")]
|
#[error("expected utf8 bytes but got invalid utf8")]
|
||||||
Utf8Error(Vec<u8>),
|
Utf8Error(Vec<u8>),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum ParseErrorKind {
|
||||||
|
Index(&'static str),
|
||||||
|
Int,
|
||||||
|
Float,
|
||||||
|
Bool,
|
||||||
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use crate::error::ParsePresetError;
|
use crate::error::{ParseErrorKind, ParsePresetError};
|
||||||
use crate::parse::{Span, Token};
|
use crate::parse::{Span, Token};
|
||||||
use crate::{FilterMode, ScaleFactor, ScaleType, Scaling, WrapMode};
|
use crate::{FilterMode, ScaleFactor, ScaleType, Scaling, WrapMode};
|
||||||
use nom::bytes::complete::tag;
|
use nom::bytes::complete::tag;
|
||||||
|
@ -25,13 +25,54 @@ pub enum Value {
|
||||||
SrgbFramebuffer(i32, bool),
|
SrgbFramebuffer(i32, bool),
|
||||||
MipmapInput(i32, bool),
|
MipmapInput(i32, bool),
|
||||||
WrapMode(i32, WrapMode),
|
WrapMode(i32, WrapMode),
|
||||||
Alias(String),
|
Alias(i32, String),
|
||||||
Parameter(String, f32),
|
Parameter(String, f32),
|
||||||
TexturePath(String, FilterMode, bool, PathBuf),
|
Texture {
|
||||||
|
name: String,
|
||||||
|
filter_mode: FilterMode,
|
||||||
|
wrap_mode: WrapMode,
|
||||||
|
mipmap: bool,
|
||||||
|
path: PathBuf,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
fn from_int(input: Span) -> Result<i32, std::num::ParseIntError> {
|
fn from_int(input: Span) -> Result<i32, ParsePresetError> {
|
||||||
i32::from_str(*input)
|
i32::from_str(input.trim()).map_err(|_| ParsePresetError::ParserError {
|
||||||
|
offset: input.location_offset(),
|
||||||
|
row: input.location_line(),
|
||||||
|
col: input.get_column(),
|
||||||
|
kind: ParseErrorKind::Int,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_float(input: Span) -> Result<f32, ParsePresetError> {
|
||||||
|
f32::from_str(input.trim()).map_err(|_| ParsePresetError::ParserError {
|
||||||
|
offset: input.location_offset(),
|
||||||
|
row: input.location_line(),
|
||||||
|
col: input.get_column(),
|
||||||
|
kind: ParseErrorKind::Float,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_bool(input: Span) -> Result<bool, ParsePresetError> {
|
||||||
|
if let Ok(i) = i32::from_str(input.trim()) {
|
||||||
|
return match i {
|
||||||
|
1 => Ok(true),
|
||||||
|
0 => Ok(false),
|
||||||
|
_ => Err(ParsePresetError::ParserError {
|
||||||
|
offset: input.location_offset(),
|
||||||
|
row: input.location_line(),
|
||||||
|
col: input.get_column(),
|
||||||
|
kind: ParseErrorKind::Bool,
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
bool::from_str(input.trim()).map_err(|_| ParsePresetError::ParserError {
|
||||||
|
offset: input.location_offset(),
|
||||||
|
row: input.location_line(),
|
||||||
|
col: input.get_column(),
|
||||||
|
kind: ParseErrorKind::Bool,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_indexed_key<'a>(key: &'static str, input: Span<'a>) -> IResult<Span<'a>, i32> {
|
fn parse_indexed_key<'a>(key: &'static str, input: Span<'a>) -> IResult<Span<'a>, i32> {
|
||||||
|
@ -41,6 +82,18 @@ fn parse_indexed_key<'a>(key: &'static str, input: Span<'a>) -> IResult<Span<'a>
|
||||||
Ok((input, idx))
|
Ok((input, idx))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn parse_texture_key<'a, 'b>(
|
||||||
|
key: &'static str,
|
||||||
|
texture_name: &'b str,
|
||||||
|
input: Span<'a>,
|
||||||
|
) -> IResult<Span<'a>, ()> {
|
||||||
|
let (input, _) = tag(texture_name)(input)?;
|
||||||
|
let (input, _) = tag("_")(input)?;
|
||||||
|
let (input, _) = tag(key)(input)?;
|
||||||
|
let (input, _) = eof(input)?;
|
||||||
|
Ok((input, ()))
|
||||||
|
}
|
||||||
|
|
||||||
pub const SHADER_MAX_REFERENCE_DEPTH: usize = 16;
|
pub const SHADER_MAX_REFERENCE_DEPTH: usize = 16;
|
||||||
|
|
||||||
fn load_child_reference_strings(
|
fn load_child_reference_strings(
|
||||||
|
@ -88,11 +141,13 @@ fn load_child_reference_strings(
|
||||||
|
|
||||||
pub fn parse_preset(path: impl AsRef<Path>) -> Result<Vec<Value>, ParsePresetError> {
|
pub fn parse_preset(path: impl AsRef<Path>) -> Result<Vec<Value>, ParsePresetError> {
|
||||||
let path = path.as_ref();
|
let path = path.as_ref();
|
||||||
let path = path.canonicalize()
|
let path = path
|
||||||
|
.canonicalize()
|
||||||
.map_err(|e| ParsePresetError::IOError(path.to_path_buf(), e))?;
|
.map_err(|e| ParsePresetError::IOError(path.to_path_buf(), e))?;
|
||||||
|
|
||||||
let mut contents = String::new();
|
let mut contents = String::new();
|
||||||
File::open(&path).and_then(|mut f| f.read_to_string(&mut contents))
|
File::open(&path)
|
||||||
|
.and_then(|mut f| f.read_to_string(&mut contents))
|
||||||
.map_err(|e| ParsePresetError::IOError(path.to_path_buf(), e))?;
|
.map_err(|e| ParsePresetError::IOError(path.to_path_buf(), e))?;
|
||||||
|
|
||||||
let tokens = super::token::do_lex(&contents)?;
|
let tokens = super::token::do_lex(&contents)?;
|
||||||
|
@ -162,12 +217,14 @@ pub fn parse_values(
|
||||||
offset: input.location_offset(),
|
offset: input.location_offset(),
|
||||||
row: input.location_line(),
|
row: input.location_line(),
|
||||||
col: input.get_column(),
|
col: input.get_column(),
|
||||||
|
kind: ParseErrorKind::Index("shader"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => ParsePresetError::ParserError {
|
_ => ParsePresetError::ParserError {
|
||||||
offset: 0,
|
offset: 0,
|
||||||
row: 0,
|
row: 0,
|
||||||
col: 0,
|
col: 0,
|
||||||
|
kind: ParseErrorKind::Index("shader"),
|
||||||
},
|
},
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
|
@ -183,9 +240,7 @@ pub fn parse_values(
|
||||||
// resolve texture paths
|
// resolve texture paths
|
||||||
let mut textures = Vec::new();
|
let mut textures = Vec::new();
|
||||||
for (ref path, tokens) in all_tokens.iter_mut() {
|
for (ref path, tokens) in all_tokens.iter_mut() {
|
||||||
for token in tokens.drain_filter(|token|
|
for token in tokens.drain_filter(|token| texture_names.contains(token.key.fragment())) {
|
||||||
texture_names.contains(token.key.fragment())
|
|
||||||
) {
|
|
||||||
let mut relative_path = path.to_path_buf();
|
let mut relative_path = path.to_path_buf();
|
||||||
relative_path.push(*token.value.fragment());
|
relative_path.push(*token.value.fragment());
|
||||||
relative_path
|
relative_path
|
||||||
|
@ -195,23 +250,93 @@ pub fn parse_values(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let tokens: Vec<Token> = all_tokens
|
let mut tokens: Vec<Token> = all_tokens
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.flat_map(|(_, token)| token)
|
.flat_map(|(_, token)| token)
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
|
for (texture, path) in textures {
|
||||||
|
let mipmap = tokens
|
||||||
|
.iter()
|
||||||
|
.position(|t| {
|
||||||
|
t.key.starts_with(*texture)
|
||||||
|
&& t.key.ends_with("_mipmap")
|
||||||
|
&& t.key.len() == texture.len() + "_mipmap".len()
|
||||||
|
})
|
||||||
|
.map(|idx| tokens.remove(idx))
|
||||||
|
.map_or_else(|| Ok(false), |v| from_bool(v.value))?;
|
||||||
|
|
||||||
|
let linear = tokens
|
||||||
|
.iter()
|
||||||
|
.position(|t| {
|
||||||
|
t.key.starts_with(*texture)
|
||||||
|
&& t.key.ends_with("_linear")
|
||||||
|
&& t.key.len() == texture.len() + "_linear".len()
|
||||||
|
})
|
||||||
|
.map(|idx| tokens.remove(idx))
|
||||||
|
.map_or_else(|| Ok(false), |v| from_bool(v.value))?;
|
||||||
|
|
||||||
|
let wrap_mode = tokens
|
||||||
|
.iter()
|
||||||
|
.position(|t| {
|
||||||
|
t.key.starts_with(*texture)
|
||||||
|
&& t.key.ends_with("_wrap_mode")
|
||||||
|
&& t.key.len() == texture.len() + "_wrap_mode".len()
|
||||||
|
})
|
||||||
|
.map(|idx| tokens.remove(idx))
|
||||||
|
// NOPANIC: infallible
|
||||||
|
.map_or_else(
|
||||||
|
|| WrapMode::default(),
|
||||||
|
|v| WrapMode::from_str(*v.value).unwrap(),
|
||||||
|
);
|
||||||
|
|
||||||
|
values.push(Value::Texture {
|
||||||
|
name: texture.to_string(),
|
||||||
|
filter_mode: if linear {
|
||||||
|
FilterMode::Linear
|
||||||
|
} else {
|
||||||
|
FilterMode::Nearest
|
||||||
|
},
|
||||||
|
wrap_mode,
|
||||||
|
mipmap,
|
||||||
|
path,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
for token in &tokens {
|
||||||
|
if parameter_names.contains(token.key.fragment()) {
|
||||||
|
let param_val = from_float(token.value)?;
|
||||||
|
values.push(Value::Parameter(
|
||||||
|
token.key.fragment().to_string(),
|
||||||
|
param_val,
|
||||||
|
));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// todo: handle shader props
|
||||||
|
|
||||||
|
// handle undeclared parameters after parsing everything else as a last resort.
|
||||||
|
let param_val = from_float(token.value)?;
|
||||||
|
values.push(Value::Parameter(
|
||||||
|
token.key.fragment().to_string(),
|
||||||
|
param_val,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
eprintln!("{:?}", tokens);
|
||||||
// all tokens should be ok to process now.
|
// all tokens should be ok to process now.
|
||||||
Ok(values)
|
Ok(values)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use std::path::PathBuf;
|
|
||||||
use crate::parse::value::parse_preset;
|
use crate::parse::value::parse_preset;
|
||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
pub fn parse_basic() {
|
pub fn parse_basic() {
|
||||||
let root = PathBuf::from("test/slang-shaders/bezel/Mega_Bezel/Presets/MBZ__5__POTATO.slangp");
|
let root =
|
||||||
|
PathBuf::from("test/slang-shaders/bezel/Mega_Bezel/Presets/Base_CRT_Presets/MBZ__3__STD__MEGATRON-NTSC.slangp");
|
||||||
let basic = parse_preset(&root);
|
let basic = parse_preset(&root);
|
||||||
eprintln!("{:?}", basic);
|
eprintln!("{:?}", basic);
|
||||||
|
assert!(basic.is_ok());
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -4,16 +4,18 @@ use std::path::PathBuf;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
|
||||||
#[repr(i32)]
|
#[repr(i32)]
|
||||||
#[derive(Debug)]
|
#[derive(Default, Debug)]
|
||||||
pub enum FilterMode {
|
pub enum FilterMode {
|
||||||
|
#[default]
|
||||||
Linear = 0,
|
Linear = 0,
|
||||||
Nearest,
|
Nearest,
|
||||||
Unspecified,
|
Unspecified,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[repr(i32)]
|
#[repr(i32)]
|
||||||
#[derive(Debug)]
|
#[derive(Default, Debug)]
|
||||||
pub enum WrapMode {
|
pub enum WrapMode {
|
||||||
|
#[default]
|
||||||
ClampToBorder = 0,
|
ClampToBorder = 0,
|
||||||
ClampToEdge,
|
ClampToEdge,
|
||||||
Repeat,
|
Repeat,
|
||||||
|
@ -21,8 +23,9 @@ pub enum WrapMode {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[repr(i32)]
|
#[repr(i32)]
|
||||||
#[derive(Debug)]
|
#[derive(Default, Debug)]
|
||||||
pub enum ScaleType {
|
pub enum ScaleType {
|
||||||
|
#[default]
|
||||||
Input = 0,
|
Input = 0,
|
||||||
Absolute,
|
Absolute,
|
||||||
Viewport,
|
Viewport,
|
||||||
|
|
Loading…
Reference in a new issue