presets: implement path resolution logic

This commit is contained in:
chyyran 2022-10-19 22:47:43 -04:00
parent f43a57d29f
commit c5b0ce211c
13 changed files with 1005 additions and 31 deletions

1
.gitignore vendored
View file

@ -1 +1,2 @@
/src/target/
/target/debug/

3
.gitmodules vendored Normal file
View file

@ -0,0 +1,3 @@
[submodule "librashader-presets/test/slang-shaders"]
path = librashader-presets/test/slang-shaders
url = https://github.com/libretro/slang-shaders

View file

@ -2,5 +2,6 @@
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$/.." vcs="Git" />
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>

99
Cargo.lock generated
View file

@ -2,6 +2,105 @@
# It is not intended for manual editing.
version = 3
[[package]]
name = "bytecount"
version = "0.6.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2c676a478f63e9fa2dd5368a42f28bba0d6c560b775f38583c8bbaa7fcd67c9c"
[[package]]
name = "librashader-presets"
version = "0.1.0"
dependencies = [
"nom",
"nom_locate",
"thiserror",
]
[[package]]
name = "memchr"
version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
[[package]]
name = "minimal-lexical"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
[[package]]
name = "nom"
version = "7.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a8903e5a29a317527874d0402f867152a3d21c908bb0b933e416c65e301d4c36"
dependencies = [
"memchr",
"minimal-lexical",
]
[[package]]
name = "nom_locate"
version = "4.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "37794436ca3029a3089e0b95d42da1f0b565ad271e4d3bb4bad0c7bb70b10605"
dependencies = [
"bytecount",
"memchr",
"nom",
]
[[package]]
name = "proc-macro2"
version = "1.0.47"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5ea3d908b0e36316caf9e9e2c4625cdde190a7e6f440d794667ed17a1855e725"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179"
dependencies = [
"proc-macro2",
]
[[package]]
name = "syn"
version = "1.0.102"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3fcd952facd492f9be3ef0d0b7032a6e442ee9b361d4acc2b1d0c4aaa5f613a1"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "thiserror"
version = "1.0.37"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "10deb33631e3c9018b9baf9dcbbc4f737320d2b576bac10f6aefa048fa407e3e"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
version = "1.0.37"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "982d17546b47146b28f7c22e3d08465f6b8903d0ea13c1660d9d84a6e7adcdbb"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "unicode-ident"
version = "1.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6ceab39d59e4c9499d4e5a8ee0e2735b891bb7308ac83dfb4e80cad195c9f6f3"

View file

@ -6,3 +6,6 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
thiserror = "1.0.37"
nom = "7.1.1"
nom_locate = "4.0.0"

View file

@ -0,0 +1,21 @@
use crate::parse::Span;
use std::path::PathBuf;
use thiserror::Error;
#[derive(Error, Debug)]
pub enum ParsePresetError {
#[error("shader preset parse error")]
LexerError { offset: usize, row: u32, col: usize },
#[error("shader preset parse error")]
ParserError { offset: usize, row: u32, col: usize },
#[error("invalid scale type")]
InvalidScaleType(String),
#[error("exceeded maximum reference depth (16)")]
ExceededReferenceDepth,
#[error("shader presents must be resolved against an absolute path")]
RootPathWasNotAbsolute,
#[error("the file was not found during resolution")]
IOError(PathBuf, std::io::Error),
#[error("expected utf8 bytes but got invalid utf8")]
Utf8Error(Vec<u8>),
}

View file

@ -1,3 +1,6 @@
mod preset;
#![feature(drain_filter)]
mod error;
pub mod parse;
mod preset;
pub use preset::*;

View file

@ -0,0 +1,12 @@
use nom::{ExtendInto, Offset};
use nom_locate::LocatedSpan;
use std::str;
mod token;
mod value;
pub type Span<'a> = LocatedSpan<&'a str>;
use crate::error::ParsePresetError;
pub use token::do_lex;
pub use token::Token;
pub use value::parse_values;

View file

@ -0,0 +1,600 @@
use crate::error::ParsePresetError;
use crate::parse::Span;
use nom::branch::alt;
use nom::bytes::complete::{is_not, take_till, take_until, take_while};
use nom::character::complete::{char, digit1, line_ending, multispace1, not_line_ending};
use nom::character::is_space;
use nom::combinator::{eof, map_res, value};
use nom::error::{ErrorKind, ParseError};
use nom::multi::many_till;
use nom::sequence::{delimited, pair, preceded, separated_pair};
use nom::{
bytes::complete::tag, character::complete::multispace0, IResult, InputIter, InputLength,
InputTake,
};
use nom_locate::LocatedSpan;
use std::num::ParseIntError;
use std::str::FromStr;
#[derive(Debug)]
pub struct Token<'a> {
pub key: Span<'a>,
pub value: Span<'a>,
}
/// Return the input slice up to the first occurrence of the parser,
/// and the result of the parser on match.
/// If the parser never matches, returns an error with code `ManyTill`
pub fn take_up_to<Input, Output, Error: ParseError<Input>, P>(
mut parser: P,
) -> impl FnMut(Input) -> IResult<Input, (Input, Output), Error>
where
P: FnMut(Input) -> IResult<Input, Output, Error>,
Input: InputLength + InputIter + InputTake,
{
move |i: Input| {
let input = i;
for (index, _) in input.iter_indices() {
let (rest, front) = input.take_split(index);
match parser(rest) {
Ok((remainder, output)) => return Ok((remainder, (front, output))),
Err(_) => continue,
}
}
Err(nom::Err::Error(Error::from_error_kind(
input,
ErrorKind::ManyTill,
)))
}
}
fn from_float(input: &str) -> Result<f32, std::num::ParseFloatError> {
f32::from_str(input)
}
// accepts "true" or "false"
fn from_bool(input: &str) -> Result<bool, std::str::ParseBoolError> {
bool::from_str(input)
}
fn parse_assignment(input: Span) -> IResult<Span, ()> {
let (input, _) = multispace0(input)?;
let (input, _) = tag("=")(input)?;
let (input, _) = multispace0(input)?;
Ok((input, ()))
}
fn extract_from_quotes(input: Span) -> IResult<Span, Span> {
let (input, between) = delimited(char('"'), is_not("\""), preceded(char('"'), eof))(input)?;
Ok((input, between))
}
fn multiline_comment(i: Span) -> IResult<Span, Span> {
delimited(tag("/*"), is_not("*/"), tag("*/"))(i)
}
fn single_comment(i: Span) -> IResult<Span, Span> {
delimited(alt((tag("//"), tag("#"))), not_line_ending, line_ending)(i)
}
fn whitespace(i: Span) -> IResult<Span, ()> {
value(
(), // Output is thrown away.
multispace0,
)(i)
}
fn optional_quotes(input: Span) -> IResult<(), Span> {
let input = if let Ok((_, between)) = extract_from_quotes(input) {
between
} else {
input
};
Ok(((), input))
}
fn parse_reference(input: Span) -> IResult<Span, Token> {
let (input, key) = tag("#reference")(input)?;
let (input, _) = multispace1(input)?;
let (input, (_, value)) = map_res(not_line_ending, optional_quotes)(input)?;
Ok((input, Token { key, value }))
}
fn parse_key_value(input: Span) -> IResult<Span, Token> {
let (input, (key, _)) = take_up_to(parse_assignment)(input)?;
let (input, (_, value)) = map_res(not_line_ending, optional_quotes)(input)?;
Ok((input, Token { key, value }))
}
fn parse_tokens(mut span: Span) -> IResult<Span, Vec<Token>> {
let mut values = Vec::new();
while !span.is_empty() {
// important to munch whitespace first.
if let Ok((input, _)) = whitespace(span) {
span = input;
}
// handle references before comments because comments can start with #
if let Ok((input, token)) = parse_reference(span) {
span = input;
values.push(token);
continue;
}
if let Ok((input, _)) = multiline_comment(span) {
span = input;
}
if let Ok((input, _)) = single_comment(span) {
span = input;
}
let (input, token) = parse_key_value(span)?;
span = input;
values.push(token)
}
Ok((span, values))
}
pub fn do_lex(input: &str) -> Result<Vec<Token>, ParsePresetError> {
let mut span = Span::new(input.trim_end());
let (_, tokens) = parse_tokens(span).map_err(|e| match e {
nom::Err::Error(e) | nom::Err::Failure(e) => {
let input: Span = e.input;
ParsePresetError::LexerError {
offset: input.location_offset(),
row: input.location_line(),
col: input.get_column(),
}
}
_ => ParsePresetError::LexerError {
offset: 0,
row: 0,
col: 0,
},
})?;
Ok(tokens)
}
#[cfg(test)]
mod test {
use crate::parse::do_lex;
use crate::parse::token::{parse_key_value, parse_tokens, single_comment, Span};
#[test]
fn parses_single_line_comment() {
let parsed =
single_comment("// Define textures to be used by the different passes\ntetx=n".into());
eprintln!("{:?}", parsed)
}
#[test]
fn parses_key_value_line() {
let parsed = do_lex(TEST);
eprintln!("{:?}", parsed)
}
const TEST2: &'static str = r#"
shader0 = ../../shaders/base/add-params-all.slang
// no
"#;
const TEST: &'static str = r#"
#reference "../../alt"
shaders = 54
shader0 = ../../shaders/base/add-params-all.slang
alias0 = "CorePass"
shader1 = ../../shaders/hyllian/cubic/hsm-drez-b-spline-x.slang
filter_linear1 = false
scale_type_x1 = absolute
scale_x1 = 640
scale_type_y1 = viewport
scaley0 = 1.0
wrap_mode1 = "clamp_to_edge"
shader2 = ../../shaders/hyllian/cubic/hsm-drez-b-spline-y.slang
filter_linear2 = false
scale_type2 = absolute
scale_x2 = 640
scale_y2 = 480
wrap_mode2 = "clamp_to_edge"
alias2 = "DerezedPass"
shader3 = ../../shaders/base/add-negative-crop-area.slang
filter_linear3 = false
mipmap_input3 = false
srgb_framebuffer3 = true
scale_type3 = source
scale_x3 = 1
scale_y3 = 1
alias3 = "NegativeCropAddedPass"
shader4 = ../../shaders/base/cache-info-all-params.slang
filter_linear4 = false
scale_type4 = source
scale4 = 1.0
alias4 = "InfoCachePass"
shader5 = ../../shaders/base/text-std.slang
filter_linear5 = false
float_framebuffer5 = true
scale_type5 = source
scale5 = 1.0
alias5 = "TextPass"
shader6 = ../../shaders/base/intro.slang
filter_linear6 = false
float_framebuffer6 = true
scale_type6 = source
scale6 = 1.0
alias6 = "IntroPass"
shader7 = ../../shaders/dedither/dedither-gamma-prep-1-before.slang
alias7 = LinearGamma
shader8 = ../../shaders/hyllian/checkerboard-dedither/checkerboard-dedither-pass1.slang
shader9 = ../../shaders/hyllian/checkerboard-dedither/checkerboard-dedither-pass2.slang
shader10 = ../../shaders/hyllian/checkerboard-dedither/checkerboard-dedither-pass3.slang
alias10 = "PreMdaptPass"
// De-Dithering - Mdapt
shader11 = ../../shaders/mdapt/hsm-mdapt-pass0.slang
shader12 = ../../shaders/mdapt/hsm-mdapt-pass1.slang
shader13 = ../../shaders/mdapt/hsm-mdapt-pass2.slang
shader14 = ../../shaders/mdapt/hsm-mdapt-pass3.slang
shader15 = ../../shaders/mdapt/hsm-mdapt-pass4.slang
shader16 = ../../shaders/dedither/dedither-gamma-prep-2-after.slang
shader17 = ../../shaders/ps1dither/hsm-PS1-Undither-BoxBlur.slang
shader18 = ../../shaders/guest/extras/hsm-sharpsmoother.slang
shader19 = ../../shaders/base/stock.slang
alias19 = refpass
shader20 = ../../shaders/scalefx/hsm-scalefx-pass0.slang
filter_linear20 = false
scale_type20 = source
scale20 = 1.0
float_framebuffer20 = true
alias20 = scalefx_pass0
shader21 = ../../shaders/scalefx/hsm-scalefx-pass1.slang
filter_linear21 = false
scale_type21 = source
scale21 = 1.0
float_framebuffer12 = true
shader22 = ../../shaders/scalefx/hsm-scalefx-pass2.slang
filter_linear22 = false
scale_type22 = source
scale22 = 1.0
shader23 = ../../shaders/scalefx/hsm-scalefx-pass3.slang
filter_linear23 = false
scale_type23 = source
scale23 = 1.0
shader24 = ../../shaders/scalefx/hsm-scalefx-pass4.slang
filter_linear24 = false
scale_type24 = source
scale24 = 3
shader25 = ../../shaders/base/stock.slang
alias25 = "PreCRTPass"
shader26 = ../../shaders/guest/hsm-afterglow0.slang
filter_linear26 = true
scale_type26 = source
scale26 = 1.0
alias26 = "AfterglowPass"
shader27 = ../../shaders/guest/hsm-pre-shaders-afterglow.slang
filter_linear27 = true
scale_type27 = source
mipmap_input27 = true
scale27 = 1.0
// Color Correction with Dogway's awesome Grade shader
// Grade is after Afterglow so that brightening the black level does not break the afterglow
shader28 = ../../shaders/dogway/hsm-grade.slang
filter_linear28 = true
scale_type28 = source
scale28 = 1.0
shader29 = ../../shaders/base/stock.slang
alias29 = "PrePass0"
shader30 = ../../shaders/guest/ntsc/hsm-ntsc-pass1.slang
filter_linear30 = false
float_framebuffer30 = true
scale_type_x30 = source
scale_type_y30 = source
scale_x30 = 4.0
scale_y30 = 1.0
frame_count_mod30 = 2
alias30 = NPass1
shader31 = ../../shaders/guest/ntsc/hsm-ntsc-pass2.slang
float_framebuffer31 = true
filter_linear31 = true
scale_type31 = source
scale_x31 = 0.5
scale_y31 = 1.0
shader32 = ../../shaders/guest/ntsc/hsm-ntsc-pass3.slang
filter_linear32 = true
scale_type32 = source
scale_x32 = 1.0
scale_y32 = 1.0
shader33 = ../../shaders/guest/hsm-custom-fast-sharpen.slang
filter_linear33 = true
scale_type33 = source
scale_x33 = 1.0
scale_y33 = 1.0
shader34 = ../../shaders/base/stock.slang
filter_linear34 = true
scale_type34 = source
scale_x34 = 1.0
scale_y34 = 1.0
alias34 = "PrePass"
mipmap_input34 = true
shader35 = ../../shaders/guest/hsm-avg-lum.slang
filter_linear35 = true
scale_type35 = source
scale35 = 1.0
mipmap_input35 = true
alias35 = "AvgLumPass"
// Pass referenced by subsequent blurring passes and crt pass
shader36 = ../../shaders/guest/hsm-interlace-and-linearize.slang
filter_linear36 = true
scale_type36 = source
scale36 = 1.0
float_framebuffer36 = true
alias36 = "LinearizePass"
shader37 = ../../shaders/guest/hsm-crt-guest-advanced-ntsc-pass1.slang
filter_linear37 = true
scale_type_x37 = viewport
scale_x37 = 1.0
scale_type_y37 = source
scale_y37 = 1.0
float_framebuffer37 = true
alias37 = Pass1
shader38 = ../../shaders/guest/hsm-gaussian_horizontal.slang
filter_linear38 = true
scale_type_x38 = absolute
scale_x38 = 640.0
scale_type_y38 = source
scale_y38 = 1.0
float_framebuffer38 = true
shader39 = ../../shaders/guest/hsm-gaussian_vertical.slang
filter_linear39 = true
scale_type_x39 = absolute
scale_x39 = 640.0
scale_type_y39 = absolute
scale_y39 = 480.0
float_framebuffer39 = true
alias39 = GlowPass
shader40 = ../../shaders/guest/hsm-bloom_horizontal.slang
filter_linear40 = true
scale_type_x40 = absolute
scale_x40 = 640.0
scale_type_y40 = absolute
scale_y40 = 480.0
float_framebuffer40 = true
shader41 = ../../shaders/guest/hsm-bloom_vertical.slang
filter_linear41 = true
scale_type_x41 = absolute
scale_x41 = 640.0
scale_type_y41 = absolute
scale_y41 = 480.0
float_framebuffer41 = true
alias41 = BloomPass
shader42 = ../../shaders/guest/hsm-crt-guest-advanced-ntsc-pass2.slang
filter_linear42 = true
float_framebuffer42 = true
scale_type42 = viewport
scale_x42 = 1.0
scale_y42 = 1.0
shader43 = ../../shaders/guest/hsm-deconvergence.slang
filter_linear43 = true
scale_type43 = viewport
scale_x43 = 1.0
scale_y43 = 1.0
shader44 = ../../shaders/base/post-crt-prep-image-layers.slang
alias44 = "MBZ_PostCRTPass"
// Reduce Resolution ----------------------------------------------------------------
// Reduce the resolution to a small static size regardless of final resolution
// Allows consistent look and faster at different final resolutions for blur
// Mipmap option allows downscaling without artifacts
shader45 = ../../shaders/base/linearize-crt.slang
mipmap_input45 = true
filter_linear45 = true
scale_type45 = absolute
// scale_x45 = 480
// scale_y45 = 270
// scale_x45 = 960
// scale_y45 = 540
scale_x45 = 800
scale_y45 = 600
alias45 = "BR_MirrorLowResPass"
// Add Blur for the Reflection (Horizontal) ----------------------------------------------------------------
shader46 = ../../shaders/base/blur-outside-screen-horiz.slang
mipmap_input46 = true
filter_linear46 = true
// Add Blur for the Reflection (Vertical) ----------------------------------------------------------------
shader47 = ../../shaders/base/blur-outside-screen-vert.slang
filter_linear47 = true
alias47 = "BR_MirrorBlurredPass"
// Reduce resolution ----------------------------------------------------------------
// Reduced to a very small amount so we can create a blur which will create a glow from the screen
// Mipmap option allows smoother downscaling
shader48 = ../../../../blurs/shaders/royale/blur9x9.slang
mipmap_input48 = true
filter_linear48 = true
scale_type48 = absolute
scale_x48 = 128
scale_y48 = 128
alias48 = "BR_MirrorReflectionDiffusedPass"
// Add Diffused glow all around the screen ----------------------------------------------------------------
// Blurred so much that it's non directional
// Mipmap option allows downscaling without artifacts
shader49 = ../../../../blurs/shaders/royale/blur9x9.slang
mipmap_input49 = true
filter_linear49 = true
scale_type49 = absolute
scale_x49 = 12
scale_y49 = 12
alias49 = "BR_MirrorFullscreenGlowPass"
// Bezel Reflection ----------------------------------------------------------------
shader50 = ../../shaders/base/reflection.slang
scale_type50 = viewport
float_framebuffer50 = true
alias50 = "BR_CRTAndReflectionPass"
// Bezel Generation & Composite of Image Layers ----------------------------------------------------------------
shader51 = ../../shaders/base/bezel-images-under-crt.slang
filter_linear51 = true
scale_type51 = viewport
float_framebuffer51 = true
alias51 = "BR_LayersUnderCRTPass"
shader52 = ../../shaders/base/bezel-images-over-crt.slang
filter_linear52 = true
scale_type52 = viewport
float_framebuffer52 = true
alias52 = "BR_LayersOverCRTPass"
// Combine Passes ----------------------------------------------------------------
shader53 = ../../shaders/base/combine-passes.slang
scale_type53 = viewport
alias53 = "CombinePass"
// Define textures to be used by the different passes
textures = "SamplerLUT1;SamplerLUT2;SamplerLUT3;SamplerLUT4;IntroImage;ScreenPlacementImage;TubeDiffuseImage;TubeColoredGelImage;TubeShadowImage;TubeStaticReflectionImage;BackgroundImage;BackgroundVertImage;ReflectionMaskImage;FrameTextureImage;CabinetGlassImage;DeviceImage;DeviceVertImage;DeviceLEDImage;DecalImage;NightLightingImage;NightLighting2Image;LEDImage;TopLayerImage;"
SamplerLUT1 = ../../shaders/guest/lut/trinitron-lut.png
SamplerLUT1_linear = true
SamplerLUT2 = ../../shaders/guest/lut/inv-trinitron-lut.png
SamplerLUT2_linear = true
SamplerLUT3 = ../../shaders/guest/lut/nec-lut.png
SamplerLUT3_linear = true
SamplerLUT4 = ../../shaders/guest/lut/ntsc-lut.png
SamplerLUT4_linear = true
IntroImage = ../../shaders/textures/IntroImage_MegaBezelLogo.png
IntroImage_linear = true
IntroImage_mipmap = 1
ScreenPlacementImage = ../../shaders/textures/Placeholder_Transparent_16x16.png
ScreenPlacementImage_linear = false
TubeDiffuseImage = ../../shaders/textures/Tube_Diffuse_2390x1792.png
TubeDiffuseImage_linear = true
TubeDiffuseImage_mipmap = 1
TubeColoredGelImage = ../../shaders/textures/Colored_Gel_Rainbow.png
TubeColoredGelImage_linear = true
TubeColoredGelImage_mipmap = 1
TubeShadowImage = ../../shaders/textures/Tube_Shadow_1600x1200.png
TubeShadowImage_linear = true
TubeShadowImage_mipmap = 1
TubeStaticReflectionImage = ../../shaders/textures/TubeGlassOverlayImageCropped_1440x1080.png
TubeStaticReflectionImage_linear = true
TubeStaticReflectionImage_mipmap = 1
ReflectionMaskImage = ../../shaders/textures/Placeholder_White_16x16.png
ReflectionMaskImage_linear = true
ReflectionMaskImage_mipmap = 1
FrameTextureImage = ../../shaders/textures/FrameTexture_2800x2120.png
FrameTextureImage_linear = true
FrameTextureImage_mipmap = 1
BackgroundImage = ../../shaders/textures/BackgroundImage_Carbon_3840x2160.png
BackgroundImage_linear = true
BackgroundImage_mipmap = 1
BackgroundVertImage = ../../shaders/textures/Placeholder_Transparent_16x16.png
BackgroundVertImage_linear = true
BackgroundVertImage_mipmap = 1
CabinetGlassImage = ../../shaders/textures/Placeholder_Transparent_16x16.png
CabinetGlassImage_linear = true
CabinetGlassImage_mipmap = 1
DeviceImage = ../../shaders/textures/Placeholder_Transparent_16x16.png
DeviceImage_linear = true
DeviceImage_mipmap = 1
DeviceVertImage = ../../shaders/textures/Placeholder_Transparent_16x16.png
DeviceVertImage_linear = true
DeviceVertImage_mipmap = 1
DeviceLEDImage = ../../shaders/textures/Placeholder_Transparent_16x16.png
DeviceLEDImage_linear = true
DeviceLEDImage_mipmap = 1
DecalImage = ../../shaders/textures/Placeholder_Transparent_16x16.png
DecalImage_linear = true
DecalImage_mipmap = 1
NightLightingImage = ../../shaders/textures/NightLightingClose_1920x1080.png
NightLightingImage_linear = true
NightLightingImage_mipmap = 1
NightLighting2Image = ../../shaders/textures/NightLightingFar_1920x1080.png
NightLighting2Image_linear = true
NightLighting2Image_mipmap = 1
LEDImage = ../../shaders/textures/Placeholder_Transparent_16x16.png
LEDImage_linear = true
LEDImage_mipmap = 1
TopLayerImage = ../../shaders/textures/Placeholder_Transparent_16x16.png
TopLayerImage_linear = true
TopLayerImage_mipmap = 1
// Use for matching vanilla GDV-Advanced
// HSM_ASPECT_RATIO_MODE = 6
// HSM_CURVATURE_MODE = 0
// SMOOTH-ADV
HSM_DEDITHER_MODE = 1
HSM_SCALEFX_ON = 1
HSM_CORE_RES_SAMPLING_MULT_SCANLINE_DIR = 300
HSM_CORE_RES_SAMPLING_MULT_OPPOSITE_DIR = 125
HSM_DOWNSAMPLE_BLUR_SCANLINE_DIR = 0
HSM_DOWNSAMPLE_BLUR_OPPOSITE_DIR = 0
ntsc_scale = 0.4
shadowMask = 3
// NTSC Parameters
GAMMA_INPUT = 2.0
gamma_out = 1.95
// DREZ Parameters
SHARPEN = 0"#;
}

View file

@ -0,0 +1,217 @@
use crate::error::ParsePresetError;
use crate::parse::{Span, Token};
use crate::{FilterMode, ScaleFactor, ScaleType, Scaling, WrapMode};
use nom::bytes::complete::tag;
use nom::character::complete::digit1;
use nom::combinator::{eof, map_res};
use nom::error::Error;
use nom::IResult;
use std::collections::HashMap;
use std::fs::File;
use std::io::Read;
use std::path::{Path, PathBuf};
use std::str::FromStr;
#[derive(Debug)]
pub enum Value {
ShaderCount(i32),
Shader(i32, PathBuf),
ScaleX(i32, ScaleFactor),
ScaleY(i32, ScaleFactor),
Scale(i32, ScaleFactor),
ScaleType(i32, ScaleType),
FilterMode(i32, FilterMode),
FloatFramebuffer(i32, bool),
SrgbFramebuffer(i32, bool),
MipmapInput(i32, bool),
WrapMode(i32, WrapMode),
Alias(String),
Parameter(String, f32),
TexturePath(String, FilterMode, bool, PathBuf),
}
fn from_int(input: Span) -> Result<i32, std::num::ParseIntError> {
i32::from_str(*input)
}
fn parse_indexed_key<'a>(key: &'static str, input: Span<'a>) -> IResult<Span<'a>, i32> {
let (input, _) = tag(key)(input)?;
let (input, idx) = map_res(digit1, from_int)(input)?;
let (input, _) = eof(input)?;
Ok((input, idx))
}
pub const SHADER_MAX_REFERENCE_DEPTH: usize = 16;
fn load_child_reference_strings(
mut root_references: Vec<PathBuf>,
root_path: impl AsRef<Path>,
) -> Result<Vec<(PathBuf, String)>, ParsePresetError> {
let root_path = root_path.as_ref();
let mut reference_depth = 0;
let mut reference_strings: Vec<(PathBuf, String)> = Vec::new();
while let Some(reference_path) = root_references.pop() {
if reference_depth > SHADER_MAX_REFERENCE_DEPTH {
return Err(ParsePresetError::ExceededReferenceDepth);
}
let mut root_path = root_path.to_path_buf();
root_path.push(reference_path);
let mut reference_root = root_path
.canonicalize()
.map_err(|e| ParsePresetError::IOError(root_path, e))?;
let mut reference_contents = String::new();
File::open(&reference_root)
.map_err(|e| ParsePresetError::IOError(reference_root.clone(), e))?
.read_to_string(&mut reference_contents)
.map_err(|e| ParsePresetError::IOError(reference_root.clone(), e))?;
let mut new_tokens = super::do_lex(&reference_contents)?;
let mut new_references: Vec<PathBuf> = new_tokens
.drain_filter(|token| *token.key.fragment() == "#reference")
.map(|value| PathBuf::from(*value.value.fragment()))
.collect();
root_references.append(&mut new_references);
// return the relative root that shader and texture paths are to be resolved against.
if !reference_root.is_dir() {
reference_root.pop();
}
// trim end space
reference_strings.push((reference_root, reference_contents));
}
Ok(reference_strings)
}
pub fn parse_preset(path: impl AsRef<Path>) -> Result<Vec<Value>, ParsePresetError> {
let path = path.as_ref();
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))
.map_err(|e| ParsePresetError::IOError(path.to_path_buf(), e))?;
let tokens = super::token::do_lex(&contents)?;
parse_values(tokens, path)
}
pub fn parse_values(
mut tokens: Vec<Token>,
root_path: impl AsRef<Path>,
) -> Result<Vec<Value>, ParsePresetError> {
let mut root_path = root_path.as_ref().to_path_buf();
if root_path.is_relative() {
return Err(ParsePresetError::RootPathWasNotAbsolute);
}
if !root_path.is_dir() {
// we don't really care if this doesn't do anything because a non-canonical root path will
// fail at a later stage during resolution.
root_path.pop();
}
let references: Vec<PathBuf> = tokens
.drain_filter(|token| *token.key.fragment() == "#reference")
.map(|value| PathBuf::from(*value.value.fragment()))
.collect();
// unfortunately we need to lex twice because there's no way to know the references ahead of time.
let child_strings = load_child_reference_strings(references, &root_path)?;
let mut all_tokens: Vec<(&Path, Vec<Token>)> = Vec::new();
all_tokens.push((root_path.as_path(), tokens));
for (path, string) in child_strings.iter() {
let mut tokens = crate::parse::do_lex(string.as_ref())?;
tokens.retain(|token| *token.key.fragment() != "#reference");
all_tokens.push((path.as_path(), tokens))
}
// collect all possible parameter names.
let mut parameter_names: Vec<&str> = Vec::new();
for (_, tokens) in all_tokens.iter_mut() {
for token in tokens.drain_filter(|token| *token.key.fragment() == "parameters") {
let parameter_name_string: &str = *token.value.fragment();
for parameter_name in parameter_name_string.split(";") {
parameter_names.push(parameter_name);
}
}
}
// collect all possible texture names.
let mut texture_names: Vec<&str> = Vec::new();
for (_, tokens) in all_tokens.iter_mut() {
for token in tokens.drain_filter(|token| *token.key.fragment() == "textures") {
let texture_name_string: &str = *token.value.fragment();
for texture_name in texture_name_string.split(";") {
texture_names.push(texture_name);
}
}
}
let mut values = Vec::new();
// resolve shader paths.
for (ref path, tokens) in all_tokens.iter_mut() {
for token in tokens.drain_filter(|token| parse_indexed_key("shader", token.key).is_ok()) {
let (_, index) = parse_indexed_key("shader", token.key).map_err(|e| match e {
nom::Err::Error(e) | nom::Err::Failure(e) => {
let input: Span = e.input;
ParsePresetError::ParserError {
offset: input.location_offset(),
row: input.location_line(),
col: input.get_column(),
}
}
_ => ParsePresetError::ParserError {
offset: 0,
row: 0,
col: 0,
},
})?;
let mut relative_path = path.to_path_buf();
relative_path.push(*token.value.fragment());
relative_path
.canonicalize()
.map_err(|e| ParsePresetError::IOError(relative_path.clone(), e))?;
values.push(Value::Shader(index, relative_path))
}
}
// 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())
) {
let mut relative_path = path.to_path_buf();
relative_path.push(*token.value.fragment());
relative_path
.canonicalize()
.map_err(|e| ParsePresetError::IOError(relative_path.clone(), e))?;
textures.push((token.key, relative_path))
}
}
let tokens: Vec<Token> = all_tokens
.into_iter()
.flat_map(|(_, token)| token)
.collect();
// all tokens should be ok to process now.
Ok(values)
}
#[cfg(test)]
mod test {
use std::path::PathBuf;
use crate::parse::value::parse_preset;
#[test]
pub fn parse_basic() {
let root = PathBuf::from("test/slang-shaders/bezel/Mega_Bezel/Presets/MBZ__5__POTATO.slangp");
let basic = parse_preset(&root);
eprintln!("{:?}", basic);
}
}

View file

@ -1,28 +1,43 @@
use std::collections::HashSet;
use crate::error::ParsePresetError;
use std::convert::Infallible;
use std::path::PathBuf;
use std::str::FromStr;
#[repr(C)]
#[repr(i32)]
#[derive(Debug)]
pub enum FilterMode {
Linear,
Linear = 0,
Nearest,
Unspecified
Unspecified,
}
#[repr(C)]
#[repr(i32)]
#[derive(Debug)]
pub enum WrapMode {
ClampToBorder,
ClampToBorder = 0,
ClampToEdge,
Repeat,
MirroredRepeat,
}
#[repr(C)]
#[repr(i32)]
#[derive(Debug)]
pub enum ScaleType {
Input,
Input = 0,
Absolute,
Viewport
Viewport,
}
#[derive(Debug)]
pub enum ScaleFactor {
Float(f32),
Absolute(i32),
}
impl Default for ScaleFactor {
fn default() -> Self {
ScaleFactor::Float(1.0f32)
}
}
impl FromStr for WrapMode {
@ -34,49 +49,47 @@ impl FromStr for WrapMode {
"clamp_to_edge" => WrapMode::ClampToEdge,
"repeat" => WrapMode::Repeat,
"mirrored_repeat" => WrapMode::MirroredRepeat,
_ => WrapMode::ClampToBorder
_ => WrapMode::ClampToBorder,
})
}
}
impl FromStr for ScaleType {
type Err = Infallible;
type Err = ParsePresetError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
Ok(match s {
"source" => ScaleType::Input,
"viewport" => ScaleType::Viewport,
"absolute" => ScaleType::Absolute,
_ => ScaleType::Input
})
match s {
"source" => Ok(ScaleType::Input),
"viewport" => Ok(ScaleType::Viewport),
"absolute" => Ok(ScaleType::Absolute),
_ => Err(ParsePresetError::InvalidScaleType(s.to_string())),
}
}
}
pub enum ScaleFactor {
Float(f32),
Absolute(i32)
}
pub struct Scaling {
pub scale_type: ScaleType,
pub factor: ScaleFactor
pub factor: ScaleFactor,
}
pub struct Scale2D {
pub valid: bool,
pub x: Scaling,
pub y: Scaling
pub y: Scaling,
}
pub struct ShaderConfig {
pub id: usize,
pub name: String,
pub alias: String,
pub filter: FilterMode,
pub wrap_mode: WrapMode,
pub frame_count_mod: usize,
pub frame_count_mod: i32,
pub srgb_framebuffer: bool,
pub float_framebuffer: bool,
pub feedback_pass: i32,
pub mipmap_input: bool,
pub scaling: Scale2D
pub scaling: Scale2D,
}
pub struct TextureConfig {
@ -84,7 +97,7 @@ pub struct TextureConfig {
pub path: PathBuf,
pub wrap_mode: WrapMode,
pub filter: FilterMode,
pub mipmap: bool
pub mipmap: bool,
}
pub struct Parameter {
@ -96,5 +109,5 @@ pub struct Preset {
// Everything is in Vecs because the expect number of values is well below 64.
pub shaders: Vec<ShaderConfig>,
pub textures: Vec<TextureConfig>,
pub parameters: Vec<Parameter>
pub parameters: Vec<Parameter>,
}

@ -0,0 +1 @@
Subproject commit 9e89aafe0f6a63645445ca8302b88e4060274c72

View file

@ -1 +1 @@
{"rustc_fingerprint":16488513895628825392,"outputs":{"10376369925670944939":{"success":true,"status":"","code":0,"stdout":"___.exe\nlib___.rlib\n___.dll\n___.dll\n___.lib\n___.dll\nC:\\Users\\ronny\\.rustup\\toolchains\\nightly-x86_64-pc-windows-msvc\ndebug_assertions\npanic=\"unwind\"\nproc_macro\ntarget_abi=\"\"\ntarget_arch=\"x86_64\"\ntarget_endian=\"little\"\ntarget_env=\"msvc\"\ntarget_family=\"windows\"\ntarget_feature=\"fxsr\"\ntarget_feature=\"llvm14-builtins-abi\"\ntarget_feature=\"sse\"\ntarget_feature=\"sse2\"\ntarget_has_atomic=\"16\"\ntarget_has_atomic=\"32\"\ntarget_has_atomic=\"64\"\ntarget_has_atomic=\"8\"\ntarget_has_atomic=\"ptr\"\ntarget_has_atomic_equal_alignment=\"16\"\ntarget_has_atomic_equal_alignment=\"32\"\ntarget_has_atomic_equal_alignment=\"64\"\ntarget_has_atomic_equal_alignment=\"8\"\ntarget_has_atomic_equal_alignment=\"ptr\"\ntarget_has_atomic_load_store=\"16\"\ntarget_has_atomic_load_store=\"32\"\ntarget_has_atomic_load_store=\"64\"\ntarget_has_atomic_load_store=\"8\"\ntarget_has_atomic_load_store=\"ptr\"\ntarget_os=\"windows\"\ntarget_pointer_width=\"64\"\ntarget_thread_local\ntarget_vendor=\"pc\"\nwindows\n","stderr":""},"15697416045686424142":{"success":true,"status":"","code":0,"stdout":"___.exe\nlib___.rlib\n___.dll\n___.dll\n___.lib\n___.dll\n","stderr":""},"4614504638168534921":{"success":true,"status":"","code":0,"stdout":"rustc 1.65.0-nightly (750bd1a7f 2022-09-14)\nbinary: rustc\ncommit-hash: 750bd1a7ff3e010611b97ee75d30b7cbf5f3a03c\ncommit-date: 2022-09-14\nhost: x86_64-pc-windows-msvc\nrelease: 1.65.0-nightly\nLLVM version: 15.0.0\n","stderr":""}},"successes":{}}
{"rustc_fingerprint":1842804115855352081,"outputs":{"10376369925670944939":{"success":true,"status":"","code":0,"stdout":"___.exe\nlib___.rlib\n___.dll\n___.dll\n___.lib\n___.dll\nC:\\Users\\ronny\\.rustup\\toolchains\\nightly-x86_64-pc-windows-msvc\ndebug_assertions\npanic=\"unwind\"\nproc_macro\ntarget_abi=\"\"\ntarget_arch=\"x86_64\"\ntarget_endian=\"little\"\ntarget_env=\"msvc\"\ntarget_family=\"windows\"\ntarget_feature=\"fxsr\"\ntarget_feature=\"llvm14-builtins-abi\"\ntarget_feature=\"sse\"\ntarget_feature=\"sse2\"\ntarget_has_atomic=\"16\"\ntarget_has_atomic=\"32\"\ntarget_has_atomic=\"64\"\ntarget_has_atomic=\"8\"\ntarget_has_atomic=\"ptr\"\ntarget_has_atomic_equal_alignment=\"16\"\ntarget_has_atomic_equal_alignment=\"32\"\ntarget_has_atomic_equal_alignment=\"64\"\ntarget_has_atomic_equal_alignment=\"8\"\ntarget_has_atomic_equal_alignment=\"ptr\"\ntarget_has_atomic_load_store=\"16\"\ntarget_has_atomic_load_store=\"32\"\ntarget_has_atomic_load_store=\"64\"\ntarget_has_atomic_load_store=\"8\"\ntarget_has_atomic_load_store=\"ptr\"\ntarget_os=\"windows\"\ntarget_pointer_width=\"64\"\ntarget_thread_local\ntarget_vendor=\"pc\"\nwindows\n","stderr":""},"4614504638168534921":{"success":true,"status":"","code":0,"stdout":"rustc 1.65.0-nightly (750bd1a7f 2022-09-14)\nbinary: rustc\ncommit-hash: 750bd1a7ff3e010611b97ee75d30b7cbf5f3a03c\ncommit-date: 2022-09-14\nhost: x86_64-pc-windows-msvc\nrelease: 1.65.0-nightly\nLLVM version: 15.0.0\n","stderr":""},"15697416045686424142":{"success":true,"status":"","code":0,"stdout":"___.exe\nlib___.rlib\n___.dll\n___.dll\n___.lib\n___.dll\n","stderr":""}},"successes":{}}