preset: implement texture and parameter parsing

This commit is contained in:
chyyran 2022-10-20 01:59:15 -04:00
parent c5b0ce211c
commit 1c2a83df09
3 changed files with 160 additions and 19 deletions

View file

@ -4,10 +4,15 @@ use thiserror::Error;
#[derive(Error, Debug)]
pub enum ParsePresetError {
#[error("shader preset parse error")]
#[error("shader preset lexing error")]
LexerError { offset: usize, row: u32, col: usize },
#[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")]
InvalidScaleType(String),
#[error("exceeded maximum reference depth (16)")]
@ -19,3 +24,11 @@ pub enum ParsePresetError {
#[error("expected utf8 bytes but got invalid utf8")]
Utf8Error(Vec<u8>),
}
#[derive(Debug)]
pub enum ParseErrorKind {
Index(&'static str),
Int,
Float,
Bool,
}

View file

@ -1,4 +1,4 @@
use crate::error::ParsePresetError;
use crate::error::{ParseErrorKind, ParsePresetError};
use crate::parse::{Span, Token};
use crate::{FilterMode, ScaleFactor, ScaleType, Scaling, WrapMode};
use nom::bytes::complete::tag;
@ -25,13 +25,54 @@ pub enum Value {
SrgbFramebuffer(i32, bool),
MipmapInput(i32, bool),
WrapMode(i32, WrapMode),
Alias(String),
Alias(i32, String),
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> {
i32::from_str(*input)
fn from_int(input: Span) -> Result<i32, ParsePresetError> {
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> {
@ -41,6 +82,18 @@ fn parse_indexed_key<'a>(key: &'static str, input: Span<'a>) -> IResult<Span<'a>
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;
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> {
let path = path.as_ref();
let path = path.canonicalize()
let path = path
.canonicalize()
.map_err(|e| ParsePresetError::IOError(path.to_path_buf(), e))?;
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))?;
let tokens = super::token::do_lex(&contents)?;
@ -162,12 +217,14 @@ pub fn parse_values(
offset: input.location_offset(),
row: input.location_line(),
col: input.get_column(),
kind: ParseErrorKind::Index("shader"),
}
}
_ => ParsePresetError::ParserError {
offset: 0,
row: 0,
col: 0,
kind: ParseErrorKind::Index("shader"),
},
})?;
@ -183,9 +240,7 @@ pub fn parse_values(
// resolve texture paths
let mut textures = Vec::new();
for (ref path, tokens) in all_tokens.iter_mut() {
for token in tokens.drain_filter(|token|
texture_names.contains(token.key.fragment())
) {
for token in tokens.drain_filter(|token| texture_names.contains(token.key.fragment())) {
let mut relative_path = path.to_path_buf();
relative_path.push(*token.value.fragment());
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()
.flat_map(|(_, token)| token)
.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.
Ok(values)
}
#[cfg(test)]
mod test {
use std::path::PathBuf;
use crate::parse::value::parse_preset;
use std::path::PathBuf;
#[test]
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);
eprintln!("{:?}", basic);
assert!(basic.is_ok());
}
}
}

View file

@ -4,16 +4,18 @@ use std::path::PathBuf;
use std::str::FromStr;
#[repr(i32)]
#[derive(Debug)]
#[derive(Default, Debug)]
pub enum FilterMode {
#[default]
Linear = 0,
Nearest,
Unspecified,
}
#[repr(i32)]
#[derive(Debug)]
#[derive(Default, Debug)]
pub enum WrapMode {
#[default]
ClampToBorder = 0,
ClampToEdge,
Repeat,
@ -21,8 +23,9 @@ pub enum WrapMode {
}
#[repr(i32)]
#[derive(Debug)]
#[derive(Default, Debug)]
pub enum ScaleType {
#[default]
Input = 0,
Absolute,
Viewport,