├── .gitignore ├── GLSLRenderer ├── CmdOptions.cs ├── GLSLProg.cs ├── GLSLProgBase.cs ├── GLSLProgConstructor.cs ├── GLSLRenderer.csproj ├── MatN.cs ├── ObjectExtensions.cs ├── Program.cs ├── VectorBase.cs ├── VectorBaseSwizzles.cs ├── mat2.cs ├── mat3.cs ├── mat4.cs ├── vec2.cs ├── vec3.cs └── vec4.cs ├── LICENSE ├── README.md ├── ShaderShrinker ├── InnoSetupProject │ └── InstallScript.iss ├── Shrinker.Avalonia │ ├── App.axaml │ ├── App.axaml.cs │ ├── Assets │ │ ├── App.ico │ │ └── Icon.icns │ ├── Commands │ │ ├── ClipboardCommand.cs │ │ ├── CommandBase.cs │ │ ├── FileOpenCommand.cs │ │ ├── FileSaveCommand.cs │ │ └── RelayCommand.cs │ ├── Converters │ │ ├── IsEqualConverter.cs │ │ └── MarkdownToHtmlConverter.cs │ ├── DiffCreator.cs │ ├── Extensions │ │ ├── ApplicationExtensions.cs │ │ └── TextEditorExtensions.cs │ ├── GLSL.xshd │ ├── Models │ │ ├── CombinedDiff.cs │ │ ├── DiffCollection.cs │ │ └── NameAndFileInfo.cs │ ├── Presets │ │ ├── Golf (Experimental) │ │ ├── Maximum │ │ ├── Reformat │ │ └── Remove Dead Code │ ├── Program.cs │ ├── Properties │ │ └── PublishProfiles │ │ │ └── FolderProfile.pubxml │ ├── Shadertoy │ │ ├── ShadertoyApi.cs │ │ └── ShadertoyImporter.cs │ ├── Shrinker.Avalonia.csproj │ ├── TempFile.cs │ ├── UserSettings.cs │ ├── ViewLocator.cs │ ├── ViewModels │ │ ├── AppViewModel.cs │ │ ├── MainWindowViewModel.cs │ │ └── PresetsViewModel.cs │ ├── Views │ │ ├── AboutDialog.axaml │ │ ├── AboutDialog.axaml.cs │ │ ├── CodeEditor.axaml │ │ ├── CodeEditor.axaml.cs │ │ ├── CodeLineControl.axaml │ │ ├── CodeLineControl.axaml.cs │ │ ├── HintDialog.axaml │ │ ├── HintDialog.axaml.cs │ │ ├── MainWindow.axaml │ │ ├── MainWindow.axaml.cs │ │ ├── OptionsDialog.axaml │ │ └── OptionsDialog.axaml.cs │ ├── app.manifest │ └── packageMe.sh ├── Shrinker.Cmd │ ├── Program.cs │ └── Shrinker.Cmd.csproj ├── Shrinker.Lexer │ ├── AlphaNumToken.cs │ ├── AssignmentOperatorToken.cs │ ├── BackslashToken.cs │ ├── BracketToken.cs │ ├── CommaToken.cs │ ├── CommentTokenBase.cs │ ├── ConstToken.cs │ ├── DotToken.cs │ ├── EqualityOperatorToken.cs │ ├── FloatToken.cs │ ├── INumberToken.cs │ ├── IToken.cs │ ├── IntToken.cs │ ├── KeywordToken.cs │ ├── Lexer.cs │ ├── LineEndToken.cs │ ├── MiscCharacterToken.cs │ ├── MultiLineCommentToken.cs │ ├── PrecisionToken.cs │ ├── PreprocessorDefineToken.cs │ ├── PreprocessorToken.cs │ ├── Properties │ │ └── AssemblyInfo.cs │ ├── QuoteToken.cs │ ├── SemicolonToken.cs │ ├── Shrinker.Lexer.csproj │ ├── SingleLineCommentToken.cs │ ├── StringExtensions.cs │ ├── SymbolOperatorToken.cs │ ├── SyntaxErrorException.cs │ ├── Token.cs │ ├── TokenExtensions.cs │ ├── TypeToken.cs │ ├── UniformToken.cs │ ├── VerbatimToken.cs │ └── WhitespaceToken.cs ├── Shrinker.Parser │ ├── COutputFormatter.cs │ ├── CodeHint.cs │ ├── CustomOptions.cs │ ├── GlslOutputFormatter.cs │ ├── HintPriority.cs │ ├── Hinter.cs │ ├── Hints │ │ ├── Hinter.AllCallsToFunctionMadeWithSameParamHint.cs │ │ ├── Hinter.FunctionCalledWithAllConstParamsHint.cs │ │ ├── Hinter.FunctionHasUnusedParamHint.cs │ │ ├── Hinter.FunctionToInlineHint.cs │ │ ├── Hinter.IntroduceDefineHint.cs │ │ ├── Hinter.InvalidClampHint.cs │ │ ├── Hinter.NegativePowHint.cs │ │ ├── Hinter.NegativeSqrtHint.cs │ │ └── Hinter.UnusedFunctionHint.cs │ ├── Optimizations │ │ ├── CombineAssignmentWithReturnExtension.cs │ │ ├── CombineAssignmentWithSingleUseExtension.cs │ │ ├── CombineConsecutiveAssignmentsExtension.cs │ │ ├── DetectConstantsExtension.cs │ │ ├── GolfExtensions.cs │ │ ├── GroupVariableDeclarationsExtension.cs │ │ ├── InlineConstantVariablesExtension.cs │ │ ├── InlineDefinesExtension.cs │ │ ├── IntroduceMathOperatorsExtension.cs │ │ ├── JoinVariableDeclarationsWithAssignmentsExtension.cs │ │ ├── MoveConstantParametersIntoCalledFunctionsExtension.cs │ │ ├── PerformArithmeticExtension.cs │ │ ├── RemoveCommentsExtension.cs │ │ ├── RemoveDisabledCodeExtension.cs │ │ ├── RemoveUnreachableCodeExtension.cs │ │ ├── RemoveUnusedFunctionsExtension.cs │ │ ├── RemoveUnusedVariablesExtension.cs │ │ ├── ReplaceFunctionCallsWithResultExtension.cs │ │ ├── SimplifyArithmeticExtension.cs │ │ ├── SimplifyBranchingExtension.cs │ │ ├── SimplifyFunctionDeclarationsExtension.cs │ │ ├── SimplifyFunctionParamsExtension.cs │ │ ├── SimplifyNumberFormat.cs │ │ ├── SimplifyVectorConstructorsExtension.cs │ │ ├── SimplifyVectorReferencesExtension.cs │ │ └── TranspileToCSharpExtension.cs │ ├── Parser.cs │ ├── Properties │ │ └── AssemblyInfo.cs │ ├── Shrinker.Parser.csproj │ ├── Shrinker.cs │ ├── StringBuilderExtensions.cs │ └── SyntaxNodes │ │ ├── BraceSyntaxNode.cs │ │ ├── CommentSyntaxNodeBase.cs │ │ ├── ExternalFunctionCallSyntaxNode.cs │ │ ├── FileSyntaxNode.cs │ │ ├── ForSyntaxNode.cs │ │ ├── FunctionCallSyntaxNode.cs │ │ ├── FunctionDeclarationSyntaxNode.cs │ │ ├── FunctionDefinitionSyntaxNode.cs │ │ ├── FunctionDefinitionSyntaxNodeExtensions.cs │ │ ├── FunctionSyntaxNodeBase.cs │ │ ├── GenericSyntaxNode.cs │ │ ├── GlslFunctionCallSyntaxNode.cs │ │ ├── GroupSyntaxNode.cs │ │ ├── IRenamable.cs │ │ ├── IStatementSyntaxNode.cs │ │ ├── IfSyntaxNode.cs │ │ ├── MultiLineCommentSyntaxNode.cs │ │ ├── PragmaDefineSyntaxNode.cs │ │ ├── PragmaIfSyntaxNode.cs │ │ ├── ReturnSyntaxNode.cs │ │ ├── RoundBracketSyntaxNode.cs │ │ ├── SingleLineCommentSyntaxNode.cs │ │ ├── SquareBracketSyntaxNode.cs │ │ ├── StructDefinitionSyntaxNode.cs │ │ ├── SwitchSyntaxNode.cs │ │ ├── SyntaxNode.cs │ │ ├── SyntaxNodeExtensions.cs │ │ ├── VariableAssignmentSyntaxNode.cs │ │ ├── VariableDeclarationSyntaxNode.cs │ │ └── VerbatimLineSyntaxNode.cs ├── Shrinker.Transpile │ ├── CmdOptions.cs │ ├── Program.cs │ ├── Shrinker.Transpile.csproj │ └── Templates │ │ └── GLSLProg.template ├── Shrinker.sln ├── Shrinker.sln.DotSettings ├── UnitTests │ ├── Extensions │ │ └── SyntaxNodeExtensions.cs │ ├── FunctionDefinitionSyntaxNodeTests.cs │ ├── GolfTests.cs │ ├── HinterTests.cs │ ├── LexerTests.cs │ ├── OutputFormatterTests.cs │ ├── ParserTests.cs │ ├── PresetsUpdater.cs │ ├── ProjectTests.cs │ ├── Properties │ │ └── AssemblyInfo.cs │ ├── ReadmeBuilder.cs │ ├── RealFileTests.cs │ ├── RoundBracketSyntaxNodeTests.cs │ ├── ShrinkerTests.cs │ ├── TestFiles │ │ ├── Alien.glsl │ │ ├── Bonzo.glsl │ │ ├── ED209.glsl │ │ ├── GolfedReference │ │ │ ├── Alien.glsl │ │ │ ├── Bonzo.glsl │ │ │ ├── ED209.glsl │ │ │ ├── Moonscape.glsl │ │ │ ├── OceanTreasure.glsl │ │ │ ├── OneSmallStep.glsl │ │ │ ├── PowerStone.glsl │ │ │ ├── Start.glsl │ │ │ ├── Subway.glsl │ │ │ └── Temple.glsl │ │ ├── Moonscape.glsl │ │ ├── OceanTreasure.glsl │ │ ├── OneSmallStep.glsl │ │ ├── PowerStone.glsl │ │ ├── SimplifiedReference │ │ │ ├── Alien.glsl │ │ │ ├── Bonzo.glsl │ │ │ ├── ED209.glsl │ │ │ ├── Moonscape.glsl │ │ │ ├── OceanTreasure.glsl │ │ │ ├── OneSmallStep.glsl │ │ │ ├── PowerStone.glsl │ │ │ ├── Start.glsl │ │ │ ├── Subway.glsl │ │ │ └── Temple.glsl │ │ ├── Start.glsl │ │ ├── Subway.glsl │ │ └── Temple.glsl │ ├── Transpiler │ │ ├── CastingTests.cs │ │ ├── ConstTests.cs │ │ ├── DeclarationTests.cs │ │ ├── DefineTests.cs │ │ ├── FunctionCallTests.cs │ │ ├── FunctionDefinitionTests.cs │ │ ├── GlslFunctionTests.cs │ │ ├── MainVrTests.cs │ │ ├── MatrixTests.cs │ │ ├── StructTests.cs │ │ ├── TranspiledOutputTests.cs │ │ └── VectorTests.cs │ ├── UnitTestBase.cs │ ├── UnitTests.csproj │ ├── VectorArithmeticTests.cs │ └── VersionUpdater.cs └── global.json └── img ├── ED209.png ├── Export.png ├── Hints.png ├── Import.png ├── Shadertoy.png └── Shrink.png /GLSLRenderer/CmdOptions.cs: -------------------------------------------------------------------------------- 1 | // ----------------------------------------------------------------------- 2 | // 3 | // Copyright (c) 2023 Dean Edis. All rights reserved. 4 | // 5 | // 6 | // This example is provided on an "as is" basis and without warranty of any kind. 7 | // Dean Edis. does not warrant or make any representations regarding the use or 8 | // results of use of this example. 9 | // 10 | // ----------------------------------------------------------------------- 11 | 12 | using CommandLine; 13 | // ReSharper disable UnusedAutoPropertyAccessor.Global 14 | #pragma warning disable CS8618 15 | 16 | namespace GLSLRenderer; 17 | 18 | // ReSharper disable once ClassNeverInstantiated.Global 19 | public class CmdOptions 20 | { 21 | [Option('s', "start", Default = 10.0f, HelpText = "Start time.")] 22 | public float StartTime { get; set; } 23 | 24 | [Option('e', "end", Default = 10.0f, HelpText = "End time.")] 25 | public float EndTime { get; set; } 26 | 27 | [Option('f', "fps", Default = 1.0f, HelpText = "Frames per second.")] 28 | public float Fps { get; set; } 29 | 30 | [Option('w', "width", Default = 640, HelpText = "Output width.")] 31 | public int Width { get; set; } 32 | 33 | [Option('h', "height", Default = 320, HelpText = "Output height.")] 34 | public int Height { get; set; } 35 | 36 | [Option('o', "output", Required = true, HelpText = "Output file path.")] 37 | public string OutputPath { get; set; } 38 | } -------------------------------------------------------------------------------- /GLSLRenderer/GLSLProgConstructor.cs: -------------------------------------------------------------------------------- 1 | // ----------------------------------------------------------------------- 2 | // 3 | // Copyright (c) 2023 Dean Edis. All rights reserved. 4 | // 5 | // 6 | // This example is provided on an "as is" basis and without warranty of any kind. 7 | // Dean Edis. does not warrant or make any representations regarding the use or 8 | // results of use of this example. 9 | // 10 | // ----------------------------------------------------------------------- 11 | 12 | namespace GLSLRenderer; 13 | 14 | public partial class GLSLProg 15 | { 16 | public GLSLProg(vec2 resolution, float time) 17 | : base(resolution, time) 18 | { 19 | } 20 | } -------------------------------------------------------------------------------- /GLSLRenderer/GLSLRenderer.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net7.0 6 | enable 7 | enable 8 | false 9 | GLSL Renderer 10 | Dean Edis 11 | Dean Edis (DeanTheCoder) 12 | GLSL Renderer 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /GLSLRenderer/MatN.cs: -------------------------------------------------------------------------------- 1 | // ----------------------------------------------------------------------- 2 | // 3 | // Copyright (c) 2023 Dean Edis. All rights reserved. 4 | // 5 | // 6 | // This example is provided on an "as is" basis and without warranty of any kind. 7 | // Dean Edis. does not warrant or make any representations regarding the use or 8 | // results of use of this example. 9 | // 10 | // ----------------------------------------------------------------------- 11 | 12 | using System.Text; 13 | 14 | namespace GLSLRenderer; 15 | 16 | public class MatN where T : VectorBase, new() 17 | { 18 | protected readonly T[] m_columns; 19 | 20 | protected MatN(params T[] columns) 21 | { 22 | m_columns = columns.Select(o => new T { Components = o.Components.ToArray() }).ToArray(); 23 | } 24 | 25 | public T this[in int i] 26 | { 27 | get => m_columns[i]; 28 | set => m_columns[i] = new T { Components = value.Components.ToArray() }; 29 | } 30 | 31 | // Overloads. 32 | public override string ToString() 33 | { 34 | var rowCount = m_columns.First().Components.Length; 35 | var colCount = m_columns.Length; 36 | 37 | var sb = new StringBuilder(); 38 | for (var row = 0; row < rowCount; row++) 39 | { 40 | sb.Append('|'); 41 | 42 | for (var col = 0; col < colCount; col++) 43 | sb.Append($" {m_columns[col][row],7:0.000}"); 44 | 45 | sb.AppendLine(" |"); 46 | } 47 | 48 | return sb.ToString().Trim('\n', '\r'); 49 | } 50 | 51 | public override bool Equals(object? obj) 52 | { 53 | if (ReferenceEquals(null, obj)) 54 | return false; 55 | if (ReferenceEquals(this, obj)) 56 | return true; 57 | if (obj.GetType() != GetType()) 58 | return false; 59 | return m_columns.SequenceEqual(((MatN)obj).m_columns); 60 | } 61 | 62 | public override int GetHashCode() => m_columns.GetHashCode(); 63 | } -------------------------------------------------------------------------------- /GLSLRenderer/ObjectExtensions.cs: -------------------------------------------------------------------------------- 1 | // ----------------------------------------------------------------------- 2 | // 3 | // Copyright (c) 2023 Dean Edis. All rights reserved. 4 | // 5 | // 6 | // This example is provided on an "as is" basis and without warranty of any kind. 7 | // Dean Edis. does not warrant or make any representations regarding the use or 8 | // results of use of this example. 9 | // 10 | // ----------------------------------------------------------------------- 11 | 12 | using System.Diagnostics.CodeAnalysis; 13 | using System.Reflection; 14 | #pragma warning disable CS8600 15 | #pragma warning disable CS8603 16 | 17 | namespace GLSLRenderer; 18 | 19 | public static class ObjectExtensions 20 | { 21 | public static T DeepClone(this T obj) 22 | { 23 | if (obj == null) 24 | throw new ArgumentNullException(nameof(obj)); 25 | 26 | var type = obj.GetType(); 27 | 28 | // Check for custom clone method 29 | var customCloneMethod = type.GetMethod("Clone"); 30 | if (customCloneMethod != null) 31 | return (T)customCloneMethod.Invoke(obj, null); 32 | 33 | // If the type is a value type or a string, it's already deep cloned 34 | if (type.IsValueType || type == typeof(string)) 35 | return obj; 36 | 37 | return DeepCloneFields(obj, type); 38 | } 39 | 40 | private static T DeepCloneFields([DisallowNull] T obj, Type type) 41 | { 42 | var clonedObject = (T)Activator.CreateInstance(type); 43 | 44 | foreach (var field in type.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)) 45 | { 46 | var originalValue = field.GetValue(obj); 47 | var clonedValue = originalValue.DeepClone(); 48 | field.SetValue(clonedObject, clonedValue); 49 | } 50 | 51 | return clonedObject; 52 | } 53 | } -------------------------------------------------------------------------------- /GLSLRenderer/mat2.cs: -------------------------------------------------------------------------------- 1 | // ----------------------------------------------------------------------- 2 | // 3 | // Copyright (c) 2023 Dean Edis. All rights reserved. 4 | // 5 | // 6 | // This example is provided on an "as is" basis and without warranty of any kind. 7 | // Dean Edis. does not warrant or make any representations regarding the use or 8 | // results of use of this example. 9 | // 10 | // ----------------------------------------------------------------------- 11 | 12 | namespace GLSLRenderer; 13 | 14 | // ReSharper disable once InconsistentNaming 15 | public class mat2 : MatN 16 | { 17 | public mat2() 18 | : this(0, 0, 0, 0) 19 | { 20 | } 21 | 22 | public mat2(float a) 23 | : this(a, 0, 0, a) 24 | { 25 | } 26 | 27 | public mat2(params float[] a) 28 | : base(new vec2(a[0], a[1]), new vec2(a[2], a[3])) 29 | { 30 | } 31 | 32 | public mat2(vec2 c1, vec2 c2) 33 | : this(c1.x, c1.y, c2.x, c2.y) 34 | { 35 | } 36 | 37 | public mat2 Clone() => new(m_columns.SelectMany(o => o.Components).ToArray()); 38 | } -------------------------------------------------------------------------------- /GLSLRenderer/mat3.cs: -------------------------------------------------------------------------------- 1 | // ----------------------------------------------------------------------- 2 | // 3 | // Copyright (c) 2023 Dean Edis. All rights reserved. 4 | // 5 | // 6 | // This example is provided on an "as is" basis and without warranty of any kind. 7 | // Dean Edis. does not warrant or make any representations regarding the use or 8 | // results of use of this example. 9 | // 10 | // ----------------------------------------------------------------------- 11 | 12 | namespace GLSLRenderer; 13 | 14 | // ReSharper disable once InconsistentNaming 15 | public class mat3 : MatN 16 | { 17 | public mat3() 18 | : this(0, 0, 0, 0, 0, 0, 0, 0, 0) 19 | { 20 | } 21 | 22 | public mat3(float a) 23 | : this(a, 0, 0, 0, a, 0, 0, 0, a) 24 | { 25 | } 26 | 27 | public mat3(params float[] a) 28 | : base(new vec3(a[0], a[1], a[2]), new vec3(a[3], a[4], a[5]), new vec3(a[6], a[7], a[8])) 29 | { 30 | } 31 | 32 | public mat3(vec3 c1, vec3 c2, vec3 c3) 33 | : this(c1.x, c1.y, c1.z, c2.x, c2.y, c2.z, c3.x, c3.y, c3.z) 34 | { 35 | } 36 | 37 | public mat3 Clone() => new(m_columns.SelectMany(o => o.Components).ToArray()); 38 | } -------------------------------------------------------------------------------- /GLSLRenderer/mat4.cs: -------------------------------------------------------------------------------- 1 | // ----------------------------------------------------------------------- 2 | // 3 | // Copyright (c) 2023 Dean Edis. All rights reserved. 4 | // 5 | // 6 | // This example is provided on an "as is" basis and without warranty of any kind. 7 | // Dean Edis. does not warrant or make any representations regarding the use or 8 | // results of use of this example. 9 | // 10 | // ----------------------------------------------------------------------- 11 | 12 | namespace GLSLRenderer; 13 | 14 | // ReSharper disable once InconsistentNaming 15 | public class mat4 : MatN 16 | { 17 | public mat4() 18 | : this(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) 19 | { 20 | } 21 | 22 | public mat4(float a) 23 | : this(a, 0, 0, 0, 0, a, 0, 0, 0, 0, a, 0, 0, 0, 0, a) 24 | { 25 | } 26 | 27 | public mat4(params float[] a) 28 | : base(new vec4(a[0], a[1], a[2], a[3]), new vec4(a[4], a[5], a[6], a[7]), new vec4(a[8], a[9], a[10], a[11]), new vec4(a[12], a[13], a[14], a[15])) 29 | { 30 | } 31 | 32 | public mat4(vec4 c1, vec4 c2, vec4 c3, vec4 c4) 33 | : this(c1.x, c1.y, c1.z, c1.w, c2.x, c2.y, c2.z, c2.w, c3.x, c3.y, c3.z, c3.w, c4.x, c4.y, c4.z, c4.w) 34 | { 35 | } 36 | 37 | public mat4 Clone() => new(m_columns.SelectMany(o => o.Components).ToArray()); 38 | } -------------------------------------------------------------------------------- /GLSLRenderer/vec2.cs: -------------------------------------------------------------------------------- 1 | // ----------------------------------------------------------------------- 2 | // 3 | // Copyright (c) 2023 Dean Edis. All rights reserved. 4 | // 5 | // 6 | // This example is provided on an "as is" basis and without warranty of any kind. 7 | // Dean Edis. does not warrant or make any representations regarding the use or 8 | // results of use of this example. 9 | // 10 | // ----------------------------------------------------------------------- 11 | 12 | namespace GLSLRenderer; 13 | 14 | // ReSharper disable once InconsistentNaming 15 | public class vec2 : VectorBase 16 | { 17 | public vec2(VectorBase v) 18 | : this(v.Components) 19 | { 20 | } 21 | 22 | public vec2(VectorBase v, params float[] f) : this(v.Components.Concat(f).ToArray()) 23 | { 24 | } 25 | 26 | public vec2(params float[] f) 27 | : base(2, f) 28 | { 29 | } 30 | 31 | public vec2(float f) 32 | : this(f, f) 33 | { 34 | } 35 | 36 | public vec2() 37 | : this(0.0f) 38 | { 39 | } 40 | 41 | public static vec2 operator -(vec2 v) => new(-v.x, -v.y); 42 | 43 | public static vec2 operator -(vec2 v1, vec2 v2) => new(v1.Sub(v2)); 44 | public static vec2 operator -(float v1, vec2 v2) => new(new vec2(v1).Sub(v2)); 45 | public static vec2 operator -(vec2 v1, float v2) => new(v1.Sub(v2)); 46 | public static vec2 operator +(vec2 v1, vec2 v2) => new(v1.x + v2.x, v1.y + v2.y); 47 | public static vec2 operator +(float v1, vec2 v2) => v2 + v1; 48 | public static vec2 operator +(vec2 v1, float v2) => new(v1.x + v2, v1.y + v2); 49 | public static vec2 operator /(vec2 v1, vec2 v2) => new(v1.Div(v2)); 50 | public static vec2 operator /(float v1, vec2 v2) => new(new vec2(v1).Div(v2)); 51 | public static vec2 operator /(vec2 v1, float v2) => new(v1.Div(v2)); 52 | public static vec2 operator *(vec2 v1, vec2 v2) => new(v1.Mul(v2)); 53 | public static vec2 operator *(float v1, vec2 v2) => new(new vec2(v1).Mul(v2)); 54 | public static vec2 operator *(vec2 v1, float v2) => new(v1.Mul(v2)); 55 | public static vec2 operator *(vec2 v, mat2 m) => 56 | new( 57 | v.x * m[0].x + v.y * m[0].y, 58 | v.x * m[1].x + v.y * m[1].y 59 | ); 60 | 61 | public vec2 Clone() => new(Components); 62 | } -------------------------------------------------------------------------------- /GLSLRenderer/vec3.cs: -------------------------------------------------------------------------------- 1 | // ----------------------------------------------------------------------- 2 | // 3 | // Copyright (c) 2023 Dean Edis. All rights reserved. 4 | // 5 | // 6 | // This example is provided on an "as is" basis and without warranty of any kind. 7 | // Dean Edis. does not warrant or make any representations regarding the use or 8 | // results of use of this example. 9 | // 10 | // ----------------------------------------------------------------------- 11 | 12 | namespace GLSLRenderer; 13 | 14 | // ReSharper disable once InconsistentNaming 15 | public class vec3 : VectorBase 16 | { 17 | public vec3(VectorBase v) 18 | : this(v.Components) 19 | { 20 | } 21 | 22 | public vec3(VectorBase v, params float[] f) : this(v.Components.Concat(f).ToArray()) 23 | { 24 | } 25 | 26 | public vec3(params float[] f) 27 | : base(3, f) 28 | { 29 | } 30 | 31 | public vec3(float f) 32 | : this(f, f, f) 33 | { 34 | } 35 | 36 | public vec3() 37 | : this(0) 38 | { 39 | } 40 | 41 | public static vec3 operator -(vec3 v) => new(-v.x, -v.y, -v.z); 42 | 43 | public static vec3 operator -(vec3 v1, vec3 v2) => new(v1.Sub(v2)); 44 | public static vec3 operator -(float v1, vec3 v2) => new(new vec3(v1).Sub(v2)); 45 | public static vec3 operator -(vec3 v1, float v2) => new(v1.Sub(v2)); 46 | public static vec3 operator +(vec3 v1, vec3 v2) => new(v1.x + v2.x, v1.y + v2.y, v1.z + v2.z); 47 | public static vec3 operator +(float v1, vec3 v2) => v2 + v1; 48 | public static vec3 operator +(vec3 v1, float v2) => new(v1.x + v2, v1.y + v2, v1.z + v2); 49 | public static vec3 operator /(vec3 v1, vec3 v2) => new(v1.Div(v2)); 50 | public static vec3 operator /(float v1, vec3 v2) => new(new vec3(v1).Div(v2)); 51 | public static vec3 operator /(vec3 v1, float v2) => new(v1.Div(v2)); 52 | public static vec3 operator *(vec3 v1, vec3 v2) => new(v1.Mul(v2)); 53 | public static vec3 operator *(float v1, vec3 v2) => new(new vec3(v1).Mul(v2)); 54 | public static vec3 operator *(vec3 v1, float v2) => new(v1.Mul(v2)); 55 | 56 | public vec3 Clone() => new(Components); 57 | } -------------------------------------------------------------------------------- /GLSLRenderer/vec4.cs: -------------------------------------------------------------------------------- 1 | // ----------------------------------------------------------------------- 2 | // 3 | // Copyright (c) 2023 Dean Edis. All rights reserved. 4 | // 5 | // 6 | // This example is provided on an "as is" basis and without warranty of any kind. 7 | // Dean Edis. does not warrant or make any representations regarding the use or 8 | // results of use of this example. 9 | // 10 | // ----------------------------------------------------------------------- 11 | 12 | namespace GLSLRenderer; 13 | 14 | // ReSharper disable once InconsistentNaming 15 | public class vec4 : VectorBase 16 | { 17 | public vec4(VectorBase v) 18 | : this(v.Components) 19 | { 20 | } 21 | 22 | public vec4(VectorBase v, params float[] f) : this(v.Components.Concat(f).ToArray()) 23 | { 24 | } 25 | 26 | public vec4(params float[] f) 27 | : base(4, f) 28 | { 29 | } 30 | 31 | public vec4(float f) 32 | : this(f, f, f, f) 33 | { 34 | } 35 | 36 | public vec4() 37 | : this(0.0f) 38 | { 39 | } 40 | 41 | public vec4(vec3 v, float w) 42 | : this(v[0], v[1], v[2], w) 43 | { 44 | } 45 | 46 | public static vec4 operator -(vec4 v) => new(-v.x, -v.y, -v.z, -v.w); 47 | 48 | public static vec4 operator -(vec4 v1, vec4 v2) => new(v1.Sub(v2)); 49 | public static vec4 operator -(float v1, vec4 v2) => new(new vec4(v1).Sub(v2)); 50 | public static vec4 operator -(vec4 v1, float v2) => new(v1.Sub(v2)); 51 | public static vec4 operator +(vec4 v1, vec4 v2) => new(v1.x + v2.x, v1.y + v2.y, v1.z + v2.z, v1.w + v2.w); 52 | public static vec4 operator +(float v1, vec4 v2) => v2 + v1; 53 | public static vec4 operator +(vec4 v1, float v2) => new(v1.x + v2, v1.y + v2, v1.z + v2, v1.w + v2); 54 | public static vec4 operator /(vec4 v1, vec4 v2) => new(v1.Div(v2)); 55 | public static vec4 operator /(float v1, vec4 v2) => new(new vec4(v1).Div(v2)); 56 | public static vec4 operator /(vec4 v1, float v2) => new(v1.Div(v2)); 57 | public static vec4 operator *(vec4 v1, vec4 v2) => new(v1.Mul(v2)); 58 | public static vec4 operator *(float v1, vec4 v2) => new(new vec4(v1).Mul(v2)); 59 | public static vec4 operator *(vec4 v1, float v2) => new(v1.Mul(v2)); 60 | 61 | public vec4 Clone() => new(Components); 62 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 deanthecoder 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /ShaderShrinker/InnoSetupProject/InstallScript.iss: -------------------------------------------------------------------------------- 1 | #define MyAppName "GLSL Shader Shrinker" 2 | #define MyAppExeName "Shrinker.Avalonia.exe" 3 | 4 | [Setup] 5 | AppId={{996B4B28-98DA-451F-ED15-8777E28DBDE4} 6 | AppName={#MyAppName} 7 | AppVersion=2.1 8 | AppPublisher=Dean Edis 9 | AppPublisherURL=https://github.com/deanthecoder/GLSLShaderShrinker 10 | DefaultDirName={commonpf}\ShaderShrinker 11 | DefaultGroupName={#MyAppName} 12 | UninstallDisplayIcon={app}\Inno_Setup_Project.exe 13 | Compression=lzma2 14 | SolidCompression=yes 15 | SourceDir=..\Shrinker.Avalonia\ 16 | OutputDir=..\InnoSetupProject\ 17 | OutputBaseFilename={#MyAppName} Installer 18 | 19 | [Tasks] 20 | Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked 21 | 22 | [Files] 23 | Source: "bin\Release\net7.0\publish\win-x64\*.*"; DestDir: "{app}"; Excludes: "*.pdb"; Flags: ignoreversion 24 | Source: "bin\Release\net7.0\publish\win-x64\Presets\*.*"; DestDir: "{app}\Presets"; Flags: ignoreversion 25 | 26 | [Icons] 27 | Name: "{group}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}" 28 | Name: "{commondesktop}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"; Tasks: desktopicon 29 | 30 | [Run] 31 | Filename: "{app}\{#MyAppExeName}"; Description: "{cm:LaunchProgram,{#StringChange(MyAppName, '&', '&&')}}"; Flags: nowait postinstall skipifsilent 32 | -------------------------------------------------------------------------------- /ShaderShrinker/Shrinker.Avalonia/App.axaml.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Avalonia; 3 | using Avalonia.Controls.ApplicationLifetimes; 4 | using Avalonia.Markup.Xaml; 5 | using Shrinker.Avalonia.ViewModels; 6 | using Shrinker.Avalonia.Views; 7 | 8 | namespace Shrinker.Avalonia; 9 | 10 | public class App : Application 11 | { 12 | public App() 13 | { 14 | DataContext = new AppViewModel(); 15 | } 16 | 17 | public override void Initialize() => AvaloniaXamlLoader.Load(this); 18 | 19 | public override void OnFrameworkInitializationCompleted() 20 | { 21 | if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) 22 | { 23 | desktop.MainWindow = new MainWindow 24 | { 25 | DataContext = new MainWindowViewModel() 26 | }; 27 | 28 | desktop.MainWindow.Closed += (_, _) => 29 | { 30 | ((IDisposable)desktop.MainWindow.DataContext).Dispose(); 31 | UserSettings.Instance.Dispose(); 32 | }; 33 | } 34 | 35 | base.OnFrameworkInitializationCompleted(); 36 | } 37 | } -------------------------------------------------------------------------------- /ShaderShrinker/Shrinker.Avalonia/Assets/App.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/deanthecoder/GLSLShaderShrinker/1f1ff6f1de6112bc5ee62ce9abda02cdab79f2aa/ShaderShrinker/Shrinker.Avalonia/Assets/App.ico -------------------------------------------------------------------------------- /ShaderShrinker/Shrinker.Avalonia/Assets/Icon.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/deanthecoder/GLSLShaderShrinker/1f1ff6f1de6112bc5ee62ce9abda02cdab79f2aa/ShaderShrinker/Shrinker.Avalonia/Assets/Icon.icns -------------------------------------------------------------------------------- /ShaderShrinker/Shrinker.Avalonia/Commands/ClipboardCommand.cs: -------------------------------------------------------------------------------- 1 | // ----------------------------------------------------------------------- 2 | // 3 | // Copyright (c) 2023 Dean Edis. All rights reserved. 4 | // 5 | // 6 | // This example is provided on an "as is" basis and without warranty of any kind. 7 | // Dean Edis. does not warrant or make any representations regarding the use or 8 | // results of use of this example. 9 | // 10 | // ----------------------------------------------------------------------- 11 | 12 | using System; 13 | using Avalonia.Threading; 14 | using TextCopy; 15 | 16 | namespace Shrinker.Avalonia.Commands; 17 | 18 | /// 19 | /// Continuously monitors the clipboard, enabling the command if it contains non-empty content. 20 | /// 21 | public class ClipboardCommand : RelayCommand 22 | { 23 | public ClipboardCommand(Action execute, Func canExecute = null) 24 | : base(execute, canExecute) 25 | { 26 | DispatcherTimer.Run( 27 | () => 28 | { 29 | RaiseCanExecuteChanged(); 30 | return true; 31 | }, 32 | TimeSpan.FromSeconds(0.2)); 33 | } 34 | 35 | public override bool CanExecute(object parameter) => 36 | base.CanExecute(parameter) && !string.IsNullOrWhiteSpace(ClipboardService.GetText()); 37 | } -------------------------------------------------------------------------------- /ShaderShrinker/Shrinker.Avalonia/Commands/CommandBase.cs: -------------------------------------------------------------------------------- 1 | // ----------------------------------------------------------------------- 2 | // 3 | // Copyright (c) 2023 Dean Edis. All rights reserved. 4 | // 5 | // 6 | // This example is provided on an "as is" basis and without warranty of any kind. 7 | // Dean Edis. does not warrant or make any representations regarding the use or 8 | // results of use of this example. 9 | // 10 | // ----------------------------------------------------------------------- 11 | 12 | using System; 13 | using System.Windows.Input; 14 | 15 | namespace Shrinker.Avalonia.Commands; 16 | 17 | public abstract class CommandBase : ICommand 18 | { 19 | public event EventHandler CanExecuteChanged; 20 | 21 | public virtual bool CanExecute(object parameter) => true; 22 | 23 | public abstract void Execute(object parameter); 24 | 25 | public void RaiseCanExecuteChanged() => CanExecuteChanged?.Invoke(this, EventArgs.Empty); 26 | } -------------------------------------------------------------------------------- /ShaderShrinker/Shrinker.Avalonia/Commands/FileOpenCommand.cs: -------------------------------------------------------------------------------- 1 | // ----------------------------------------------------------------------- 2 | // 3 | // Copyright (c) 2023 Dean Edis. All rights reserved. 4 | // 5 | // 6 | // This example is provided on an "as is" basis and without warranty of any kind. 7 | // Dean Edis. does not warrant or make any representations regarding the use or 8 | // results of use of this example. 9 | // 10 | // ----------------------------------------------------------------------- 11 | 12 | using System; 13 | using System.IO; 14 | using System.Linq; 15 | using Avalonia; 16 | using Avalonia.Controls; 17 | using Avalonia.Platform.Storage; 18 | using Shrinker.Avalonia.Extensions; 19 | 20 | namespace Shrinker.Avalonia.Commands; 21 | 22 | public class FileOpenCommand : CommandBase 23 | { 24 | private readonly string m_title; 25 | private readonly string m_filterName; 26 | private readonly string[] m_filterExtensions; 27 | 28 | public event EventHandler FileSelected; 29 | 30 | public FileOpenCommand(string title, string filterName, string[] filterExtensions) 31 | { 32 | m_title = title; 33 | m_filterName = filterName; 34 | m_filterExtensions = filterExtensions; 35 | } 36 | 37 | public override async void Execute(object parameter) 38 | { 39 | if (Application.Current?.GetMainWindow() == null) 40 | return; // Cannot find the main application window. 41 | 42 | var files = 43 | await TopLevel 44 | .GetTopLevel(Application.Current?.GetMainWindow()) 45 | .StorageProvider 46 | .OpenFilePickerAsync( 47 | new FilePickerOpenOptions 48 | { 49 | Title = m_title, 50 | AllowMultiple = false, 51 | FileTypeFilter = new[] 52 | { 53 | new FilePickerFileType(m_filterName) 54 | { 55 | Patterns = m_filterExtensions 56 | } 57 | } 58 | }); 59 | var selectedFile = files.FirstOrDefault(); 60 | if (selectedFile != null) 61 | FileSelected?.Invoke(this, new FileInfo(selectedFile.Path.LocalPath)); 62 | } 63 | } -------------------------------------------------------------------------------- /ShaderShrinker/Shrinker.Avalonia/Commands/RelayCommand.cs: -------------------------------------------------------------------------------- 1 | // ----------------------------------------------------------------------- 2 | // 3 | // Copyright (c) 2023 Dean Edis. All rights reserved. 4 | // 5 | // 6 | // This example is provided on an "as is" basis and without warranty of any kind. 7 | // Dean Edis. does not warrant or make any representations regarding the use or 8 | // results of use of this example. 9 | // 10 | // ----------------------------------------------------------------------- 11 | 12 | using System; 13 | 14 | namespace Shrinker.Avalonia.Commands; 15 | 16 | public class RelayCommand : CommandBase 17 | { 18 | private readonly Action m_execute; 19 | private readonly Func m_canExecute; 20 | 21 | public RelayCommand(Action execute, Func canExecute = null) 22 | { 23 | m_execute = execute ?? throw new ArgumentNullException(nameof(execute)); 24 | m_canExecute = canExecute; 25 | } 26 | 27 | public override bool CanExecute(object parameter) => m_canExecute == null || m_canExecute(); 28 | 29 | public override void Execute(object parameter) => m_execute(parameter); 30 | } -------------------------------------------------------------------------------- /ShaderShrinker/Shrinker.Avalonia/Converters/IsEqualConverter.cs: -------------------------------------------------------------------------------- 1 | // ----------------------------------------------------------------------- 2 | // 3 | // Copyright (c) 2023 Dean Edis. All rights reserved. 4 | // 5 | // 6 | // This example is provided on an "as is" basis and without warranty of any kind. 7 | // Dean Edis. does not warrant or make any representations regarding the use or 8 | // results of use of this example. 9 | // 10 | // ----------------------------------------------------------------------- 11 | 12 | using System; 13 | using System.Globalization; 14 | using Avalonia.Data.Converters; 15 | 16 | namespace Shrinker.Avalonia.Converters; 17 | 18 | public class IsEqualConverter : IValueConverter 19 | { 20 | public object Convert(object value, Type targetType, object parameter, CultureInfo culture) => 21 | value == parameter || value?.Equals(parameter) == true; 22 | 23 | public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) => 24 | throw new NotSupportedException(); 25 | } -------------------------------------------------------------------------------- /ShaderShrinker/Shrinker.Avalonia/Converters/MarkdownToHtmlConverter.cs: -------------------------------------------------------------------------------- 1 | // ----------------------------------------------------------------------- 2 | // 3 | // Copyright (c) 2023 Dean Edis. All rights reserved. 4 | // 5 | // 6 | // This example is provided on an "as is" basis and without warranty of any kind. 7 | // Dean Edis. does not warrant or make any representations regarding the use or 8 | // results of use of this example. 9 | // 10 | // ----------------------------------------------------------------------- 11 | 12 | using System; 13 | using System.Linq; 14 | using Avalonia; 15 | using Avalonia.Data.Converters; 16 | using Markdig; 17 | using Markdown.ColorCode; 18 | 19 | namespace Shrinker.Avalonia.Converters; 20 | 21 | public class MarkdownToHtmlConverter : IValueConverter 22 | { 23 | public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) 24 | { 25 | if (value is string markdownText) 26 | { 27 | var lines = markdownText.Split('\n', '\r').Select(o => o.Trim()); 28 | 29 | var pipeline = new MarkdownPipelineBuilder() 30 | .UseAdvancedExtensions() 31 | .UseColorCode() 32 | .Build(); 33 | var html = Markdig.Markdown.ToHtml(string.Join('\n', lines), pipeline); 34 | return html; 35 | } 36 | 37 | return AvaloniaProperty.UnsetValue; 38 | } 39 | 40 | public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) => null; 41 | } -------------------------------------------------------------------------------- /ShaderShrinker/Shrinker.Avalonia/Extensions/ApplicationExtensions.cs: -------------------------------------------------------------------------------- 1 | // ----------------------------------------------------------------------- 2 | // 3 | // Copyright (c) 2023 Dean Edis. All rights reserved. 4 | // 5 | // 6 | // This example is provided on an "as is" basis and without warranty of any kind. 7 | // Dean Edis. does not warrant or make any representations regarding the use or 8 | // results of use of this example. 9 | // 10 | // ----------------------------------------------------------------------- 11 | 12 | using Avalonia; 13 | using Avalonia.Controls; 14 | using Avalonia.Controls.ApplicationLifetimes; 15 | 16 | namespace Shrinker.Avalonia.Extensions; 17 | 18 | public static class ApplicationExtensions 19 | { 20 | public static Window GetMainWindow(this Application app) => 21 | (app?.ApplicationLifetime as IClassicDesktopStyleApplicationLifetime)?.MainWindow; 22 | } -------------------------------------------------------------------------------- /ShaderShrinker/Shrinker.Avalonia/Extensions/TextEditorExtensions.cs: -------------------------------------------------------------------------------- 1 | using Avalonia; 2 | using Avalonia.Media; 3 | using AvaloniaEdit; 4 | 5 | namespace Shrinker.Avalonia.Extensions; 6 | 7 | public static class TextEditorExtensions 8 | { 9 | public static TextEditor MakeReadOnly(this TextEditor textEditor) 10 | { 11 | textEditor.TextArea.TextView.LinkTextForegroundBrush = Brushes.Cyan; 12 | textEditor.TextArea.TextView.Margin = new Thickness(0); 13 | textEditor.TextArea.SelectionChanged += (_, _) => textEditor.TextArea.ClearSelection(); 14 | textEditor.TextArea.Caret.PositionChanged += (_, _) => textEditor.TextArea.Caret.Hide(); 15 | return textEditor; 16 | } 17 | } -------------------------------------------------------------------------------- /ShaderShrinker/Shrinker.Avalonia/Models/CombinedDiff.cs: -------------------------------------------------------------------------------- 1 | // ----------------------------------------------------------------------- 2 | // 3 | // Copyright (c) 2023 Dean Edis. All rights reserved. 4 | // 5 | // 6 | // This example is provided on an "as is" basis and without warranty of any kind. 7 | // Dean Edis. does not warrant or make any representations regarding the use or 8 | // results of use of this example. 9 | // 10 | // ----------------------------------------------------------------------- 11 | 12 | using DiffPlex.DiffBuilder.Model; 13 | 14 | namespace Shrinker.Avalonia.Models; 15 | 16 | /// 17 | /// Represents a single left/right diff line. 18 | /// 19 | public class CombinedDiff 20 | { 21 | public DiffPiece LeftDiff { get; } 22 | public DiffPiece RightDiff { get; set; } 23 | 24 | public string LeftLineNumber { get; private set; } = string.Empty; 25 | public string RightLineNumber { get; private set; } = string.Empty; 26 | 27 | public CombinedDiff(DiffPiece leftDiff, DiffPiece rightDiff) 28 | { 29 | LeftDiff = leftDiff; 30 | RightDiff = rightDiff; 31 | } 32 | 33 | public void SetLeftPageNumber(int i) => LeftLineNumber = $"{i:D}"; 34 | public void SetRightPageNumber(int i) => RightLineNumber = $"{i:D}"; 35 | 36 | public override string ToString() => 37 | $"{LeftDiff?.Text ?? ""} | {RightDiff?.Text ?? ""}"; 38 | } -------------------------------------------------------------------------------- /ShaderShrinker/Shrinker.Avalonia/Models/DiffCollection.cs: -------------------------------------------------------------------------------- 1 | // ----------------------------------------------------------------------- 2 | // 3 | // Copyright (c) 2023 Dean Edis. All rights reserved. 4 | // 5 | // 6 | // This example is provided on an "as is" basis and without warranty of any kind. 7 | // Dean Edis. does not warrant or make any representations regarding the use or 8 | // results of use of this example. 9 | // 10 | // ----------------------------------------------------------------------- 11 | 12 | using System.Collections.Generic; 13 | using System.Collections.ObjectModel; 14 | using System.Linq; 15 | using DynamicData; 16 | 17 | namespace Shrinker.Avalonia.Models; 18 | 19 | /// 20 | /// Represents the collection of left/right diff lines. 21 | /// 22 | public class DiffCollection : ObservableCollection 23 | { 24 | public string GetAllLeftText() => string.Join("\n", this.Select(o => o.LeftDiff?.Text).Where(o => o != null)); 25 | public string GetAllRightText() => string.Join("\n", this.Select(o => o.RightDiff?.Text).Where(o => o != null)); 26 | 27 | public void ReplaceAll(IEnumerable newItems) 28 | { 29 | Clear(); 30 | this.AddRange(newItems); 31 | } 32 | 33 | public bool HasRightContent() => 34 | this.Any(o => !string.IsNullOrWhiteSpace(o.RightDiff?.Text)); 35 | } -------------------------------------------------------------------------------- /ShaderShrinker/Shrinker.Avalonia/Models/NameAndFileInfo.cs: -------------------------------------------------------------------------------- 1 | // ----------------------------------------------------------------------- 2 | // 3 | // Copyright (c) 2023 Dean Edis. All rights reserved. 4 | // 5 | // 6 | // This example is provided on an "as is" basis and without warranty of any kind. 7 | // Dean Edis. does not warrant or make any representations regarding the use or 8 | // results of use of this example. 9 | // 10 | // ----------------------------------------------------------------------- 11 | 12 | using System.IO; 13 | 14 | namespace Shrinker.Avalonia.Models; 15 | 16 | public class NameAndFileInfo 17 | { 18 | public string Name { get; } 19 | public FileInfo File { get; } 20 | 21 | public NameAndFileInfo(FileInfo file) 22 | : this(file.Name, file) 23 | { 24 | } 25 | 26 | public NameAndFileInfo(string name, FileInfo file) 27 | { 28 | Name = name; 29 | File = file; 30 | } 31 | } -------------------------------------------------------------------------------- /ShaderShrinker/Shrinker.Avalonia/Presets/Golf (Experimental): -------------------------------------------------------------------------------- 1 | { 2 | "RemoveDisabledCode": true, 3 | "RemoveComments": true, 4 | "KeepHeaderComments": false, 5 | "RemoveUnusedFunctions": true, 6 | "SimplifyFunctionDeclarations": true, 7 | "SimplifyFunctionParams": true, 8 | "GroupVariableDeclarations": true, 9 | "JoinVariableDeclarationsWithAssignments": true, 10 | "RemoveUnusedVariables": true, 11 | "DetectConstants": true, 12 | "InlineConstantVariables": true, 13 | "InlineDefines": true, 14 | "SimplifyNumberFormat": true, 15 | "SimplifyVectorConstructors": true, 16 | "SimplifyVectorReferences": true, 17 | "RemoveUnreachableCode": true, 18 | "CombineConsecutiveAssignments": true, 19 | "CombineAssignmentWithSingleUse": true, 20 | "IntroduceMathOperators": true, 21 | "SimplifyArithmetic": true, 22 | "PerformArithmetic": true, 23 | "SimplifyBranching": true, 24 | "ReplaceFunctionCallsWithResult": true, 25 | "MoveConstantParametersIntoCalledFunctions": true, 26 | "GolfNames": true, 27 | "GolfDefineCommonTerms": true, 28 | "TranspileToCSharp": false 29 | } -------------------------------------------------------------------------------- /ShaderShrinker/Shrinker.Avalonia/Presets/Maximum: -------------------------------------------------------------------------------- 1 | { 2 | "RemoveDisabledCode": true, 3 | "RemoveComments": true, 4 | "KeepHeaderComments": false, 5 | "RemoveUnusedFunctions": true, 6 | "SimplifyFunctionDeclarations": true, 7 | "SimplifyFunctionParams": true, 8 | "GroupVariableDeclarations": true, 9 | "JoinVariableDeclarationsWithAssignments": true, 10 | "RemoveUnusedVariables": true, 11 | "DetectConstants": true, 12 | "InlineConstantVariables": true, 13 | "InlineDefines": true, 14 | "SimplifyNumberFormat": true, 15 | "SimplifyVectorConstructors": true, 16 | "SimplifyVectorReferences": true, 17 | "RemoveUnreachableCode": true, 18 | "CombineConsecutiveAssignments": true, 19 | "CombineAssignmentWithSingleUse": true, 20 | "IntroduceMathOperators": true, 21 | "SimplifyArithmetic": true, 22 | "PerformArithmetic": true, 23 | "SimplifyBranching": true, 24 | "ReplaceFunctionCallsWithResult": true, 25 | "MoveConstantParametersIntoCalledFunctions": true, 26 | "GolfNames": false, 27 | "GolfDefineCommonTerms": false, 28 | "TranspileToCSharp": false 29 | } -------------------------------------------------------------------------------- /ShaderShrinker/Shrinker.Avalonia/Presets/Reformat: -------------------------------------------------------------------------------- 1 | { 2 | "RemoveDisabledCode": false, 3 | "RemoveComments": false, 4 | "KeepHeaderComments": false, 5 | "RemoveUnusedFunctions": false, 6 | "SimplifyFunctionDeclarations": false, 7 | "SimplifyFunctionParams": false, 8 | "GroupVariableDeclarations": false, 9 | "JoinVariableDeclarationsWithAssignments": false, 10 | "RemoveUnusedVariables": false, 11 | "DetectConstants": false, 12 | "InlineConstantVariables": false, 13 | "InlineDefines": false, 14 | "SimplifyNumberFormat": false, 15 | "SimplifyVectorConstructors": false, 16 | "SimplifyVectorReferences": false, 17 | "RemoveUnreachableCode": false, 18 | "CombineConsecutiveAssignments": false, 19 | "CombineAssignmentWithSingleUse": false, 20 | "IntroduceMathOperators": false, 21 | "SimplifyArithmetic": false, 22 | "PerformArithmetic": false, 23 | "SimplifyBranching": false, 24 | "ReplaceFunctionCallsWithResult": false, 25 | "MoveConstantParametersIntoCalledFunctions": false, 26 | "GolfNames": false, 27 | "GolfDefineCommonTerms": false, 28 | "TranspileToCSharp": false 29 | } -------------------------------------------------------------------------------- /ShaderShrinker/Shrinker.Avalonia/Presets/Remove Dead Code: -------------------------------------------------------------------------------- 1 | { 2 | "RemoveDisabledCode": true, 3 | "RemoveComments": false, 4 | "KeepHeaderComments": false, 5 | "RemoveUnusedFunctions": true, 6 | "SimplifyFunctionDeclarations": false, 7 | "SimplifyFunctionParams": false, 8 | "GroupVariableDeclarations": false, 9 | "JoinVariableDeclarationsWithAssignments": false, 10 | "RemoveUnusedVariables": true, 11 | "DetectConstants": false, 12 | "InlineConstantVariables": false, 13 | "InlineDefines": false, 14 | "SimplifyNumberFormat": false, 15 | "SimplifyVectorConstructors": false, 16 | "SimplifyVectorReferences": false, 17 | "RemoveUnreachableCode": true, 18 | "CombineConsecutiveAssignments": false, 19 | "CombineAssignmentWithSingleUse": false, 20 | "IntroduceMathOperators": false, 21 | "SimplifyArithmetic": false, 22 | "PerformArithmetic": false, 23 | "SimplifyBranching": false, 24 | "ReplaceFunctionCallsWithResult": false, 25 | "MoveConstantParametersIntoCalledFunctions": false, 26 | "GolfNames": false, 27 | "GolfDefineCommonTerms": false, 28 | "TranspileToCSharp": false 29 | } -------------------------------------------------------------------------------- /ShaderShrinker/Shrinker.Avalonia/Program.cs: -------------------------------------------------------------------------------- 1 | using Avalonia; 2 | using Avalonia.ReactiveUI; 3 | 4 | namespace Shrinker.Avalonia; 5 | 6 | using System; 7 | 8 | public static class Program 9 | { 10 | // Initialization code. Don't use any Avalonia, third-party APIs or any 11 | // SynchronizationContext-reliant code before AppMain is called: things aren't initialized 12 | // yet and things might break. 13 | [STAThread] 14 | public static void Main(string[] args) => BuildAvaloniaApp() 15 | .StartWithClassicDesktopLifetime(args); 16 | 17 | // Avalonia configuration, don't remove; also used by visual designer. 18 | public static AppBuilder BuildAvaloniaApp() 19 | => AppBuilder.Configure() 20 | .UsePlatformDetect() 21 | .WithInterFont() 22 | .LogToTrace() 23 | .UseReactiveUI(); 24 | } 25 | -------------------------------------------------------------------------------- /ShaderShrinker/Shrinker.Avalonia/Properties/PublishProfiles/FolderProfile.pubxml: -------------------------------------------------------------------------------- 1 |  2 | 5 | 6 | 7 | Release 8 | Any CPU 9 | bin\Release\net7.0\publish\win-x64\ 10 | FileSystem 11 | <_TargetId>Folder 12 | net7.0 13 | win-x64 14 | true 15 | false 16 | false 17 | false 18 | 19 | -------------------------------------------------------------------------------- /ShaderShrinker/Shrinker.Avalonia/Shadertoy/ShadertoyApi.cs: -------------------------------------------------------------------------------- 1 | // ----------------------------------------------------------------------- 2 | // 3 | // Copyright (c) 2021 Dean Edis. (Twitter: @deanthecoder) All rights reserved. 4 | // 5 | // 6 | // This code is provided on an "as is" basis and without warranty of any kind. 7 | // We do not warrant or make any representations regarding the use or 8 | // results of use of this code. 9 | // 10 | // ----------------------------------------------------------------------- 11 | 12 | using System.Collections.Generic; 13 | 14 | // ReSharper disable All 15 | 16 | namespace Shrinker.Avalonia.Shadertoy; 17 | 18 | public class Info 19 | { 20 | public string id { get; set; } 21 | public string date { get; set; } 22 | public int viewed { get; set; } 23 | public string name { get; set; } 24 | public string username { get; set; } 25 | public string description { get; set; } 26 | public int likes { get; set; } 27 | public int published { get; set; } 28 | public int flags { get; set; } 29 | public int usePreview { get; set; } 30 | public List tags { get; set; } 31 | public int hasliked { get; set; } 32 | } 33 | 34 | public class Output 35 | { 36 | public int id { get; set; } 37 | public int channel { get; set; } 38 | } 39 | 40 | public class Renderpass 41 | { 42 | public List inputs { get; set; } 43 | public List outputs { get; set; } 44 | public string code { get; set; } 45 | public string name { get; set; } 46 | public string description { get; set; } 47 | public string type { get; set; } 48 | } 49 | 50 | public class Shader 51 | { 52 | public string ver { get; set; } 53 | public Info info { get; set; } 54 | public List renderpass { get; set; } 55 | } 56 | 57 | public class Root 58 | { 59 | public Shader Shader { get; set; } 60 | public string Error { get; set; } 61 | 62 | public Root(Shader shader, string error) 63 | { 64 | Shader = shader; 65 | Error = error; 66 | } 67 | } -------------------------------------------------------------------------------- /ShaderShrinker/Shrinker.Avalonia/Shadertoy/ShadertoyImporter.cs: -------------------------------------------------------------------------------- 1 | // ----------------------------------------------------------------------- 2 | // 3 | // Copyright (c) 2023 Dean Edis. All rights reserved. 4 | // 5 | // 6 | // This example is provided on an "as is" basis and without warranty of any kind. 7 | // Dean Edis. does not warrant or make any representations regarding the use or 8 | // results of use of this example. 9 | // 10 | // ----------------------------------------------------------------------- 11 | 12 | using System.Linq; 13 | using System.Net.Http; 14 | using System.Threading.Tasks; 15 | using Newtonsoft.Json; 16 | 17 | namespace Shrinker.Avalonia.Shadertoy; 18 | 19 | public static class ShadertoyImporter 20 | { 21 | /// 22 | /// Returns null if nothing to do, empty string on failure, or valid GLSL. 23 | /// 24 | public static async Task ImportAsync(string id) 25 | { 26 | id = id?.Trim().Trim('/'); 27 | if (id != null) 28 | { 29 | var slashIndex = id.LastIndexOf('/'); 30 | if (slashIndex > 0) 31 | id = id.Substring(slashIndex + 1); 32 | } 33 | 34 | if (string.IsNullOrWhiteSpace(id)) 35 | return null; // Nothing to do. 36 | 37 | using var httpClient = new HttpClient(); 38 | var json = await httpClient.GetStringAsync($"https://www.shadertoy.com/api/v1/shaders/{id}?key=BtntM4"); 39 | 40 | var shaderData = JsonConvert.DeserializeObject(json); 41 | return shaderData?.Shader?.renderpass.LastOrDefault()?.code ?? string.Empty; 42 | } 43 | } -------------------------------------------------------------------------------- /ShaderShrinker/Shrinker.Avalonia/TempFile.cs: -------------------------------------------------------------------------------- 1 | // ----------------------------------------------------------------------- 2 | // 3 | // Copyright (c) 2023 Dean Edis. All rights reserved. 4 | // 5 | // 6 | // This example is provided on an "as is" basis and without warranty of any kind. 7 | // Dean Edis. does not warrant or make any representations regarding the use or 8 | // results of use of this example. 9 | // 10 | // ----------------------------------------------------------------------- 11 | 12 | using System; 13 | using System.IO; 14 | 15 | namespace Shrinker.Avalonia; 16 | 17 | public class TempFile : IDisposable 18 | { 19 | public string FilePath { get; private set; } 20 | 21 | public TempFile(string content) 22 | { 23 | // Create a unique temp file 24 | FilePath = Path.GetTempFileName(); 25 | 26 | // Write the provided content to the temp file. 27 | File.WriteAllText(FilePath, content ?? string.Empty); 28 | } 29 | 30 | // Implicit conversion operator 31 | public static implicit operator FileInfo(TempFile tempFile) => 32 | new(tempFile.FilePath); 33 | 34 | public void Dispose() 35 | { 36 | DeleteTempFile(); 37 | GC.SuppressFinalize(this); 38 | } 39 | 40 | ~TempFile() => DeleteTempFile(); 41 | 42 | private void DeleteTempFile() 43 | { 44 | if (!File.Exists(FilePath)) 45 | return; 46 | try 47 | { 48 | File.Delete(FilePath); 49 | } 50 | catch 51 | { 52 | // No op. 53 | } 54 | } 55 | } -------------------------------------------------------------------------------- /ShaderShrinker/Shrinker.Avalonia/UserSettings.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Reflection; 4 | using System.Runtime.InteropServices; 5 | using Newtonsoft.Json; 6 | using Shrinker.Parser; 7 | // ReSharper disable UnusedMember.Global 8 | 9 | namespace Shrinker.Avalonia; 10 | 11 | /// 12 | /// Persistent application user settings. 13 | /// 14 | public class UserSettings : IDisposable 15 | { 16 | private readonly string m_filePath; 17 | 18 | [JsonIgnore] 19 | public static UserSettings Instance { get; } = new(); 20 | 21 | public string Preset { get; set; } = string.Empty; 22 | public bool OutputAsGlsl { get; set; } = true; 23 | public string ShadertoyId { get; set; } = string.Empty; 24 | public string CustomPresetJson { get; set; } = JsonConvert.SerializeObject(CustomOptions.None()); 25 | 26 | private UserSettings() 27 | { 28 | var assembly = Assembly.GetExecutingAssembly(); 29 | var companyName = ((AssemblyCompanyAttribute)Attribute.GetCustomAttribute(assembly, typeof(AssemblyCompanyAttribute))).Company; 30 | var productName = assembly.GetName().Name; 31 | 32 | // Ensure valid file system characters. 33 | companyName = RemoveInvalidChars(companyName); 34 | productName = RemoveInvalidChars(productName); 35 | 36 | var appDirectory = Path.Combine(GetAppDataPath(), companyName, productName); 37 | Directory.CreateDirectory(appDirectory); 38 | m_filePath = Path.Combine(appDirectory, "settings.json"); 39 | 40 | if (File.Exists(m_filePath)) 41 | JsonConvert.PopulateObject(File.ReadAllText(m_filePath), this); 42 | } 43 | 44 | private string RemoveInvalidChars(string s) 45 | { 46 | foreach (var c in Path.GetInvalidFileNameChars()) 47 | s = s.Replace(c.ToString(), string.Empty); 48 | return s; 49 | } 50 | 51 | private static string GetAppDataPath() 52 | { 53 | var appDataPath = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData); 54 | 55 | if (string.IsNullOrEmpty(appDataPath)) 56 | { 57 | var homePath = Environment.GetEnvironmentVariable("HOME"); 58 | if (string.IsNullOrEmpty(homePath)) 59 | { 60 | // Fallback to using ~ if HOME environment variable is not set 61 | homePath = "~"; 62 | } 63 | 64 | appDataPath = RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? Path.Combine(homePath, "Library", "Preferences") : homePath; 65 | } 66 | 67 | Directory.CreateDirectory(appDataPath); 68 | 69 | return appDataPath; 70 | } 71 | 72 | public void Dispose() => 73 | File.WriteAllText(m_filePath, JsonConvert.SerializeObject(this, Formatting.Indented)); 74 | } -------------------------------------------------------------------------------- /ShaderShrinker/Shrinker.Avalonia/ViewLocator.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Avalonia.Controls; 3 | using Avalonia.Controls.Templates; 4 | using ReactiveUI; 5 | 6 | namespace Shrinker.Avalonia; 7 | 8 | public class ViewLocator : IDataTemplate 9 | { 10 | public Control Build(object data) 11 | { 12 | var name = data.GetType().FullName!.Replace("ViewModel", "View"); 13 | var type = Type.GetType(name); 14 | 15 | if (type != null) 16 | { 17 | return (Control)Activator.CreateInstance(type)!; 18 | } 19 | 20 | return new TextBlock { Text = "Not Found: " + name }; 21 | } 22 | 23 | public bool Match(object data) 24 | { 25 | return data is ReactiveObject; 26 | } 27 | } -------------------------------------------------------------------------------- /ShaderShrinker/Shrinker.Avalonia/ViewModels/AppViewModel.cs: -------------------------------------------------------------------------------- 1 | // ----------------------------------------------------------------------- 2 | // 3 | // Copyright (c) 2023 Dean Edis. All rights reserved. 4 | // 5 | // 6 | // This example is provided on an "as is" basis and without warranty of any kind. 7 | // Dean Edis. does not warrant or make any representations regarding the use or 8 | // results of use of this example. 9 | // 10 | // ----------------------------------------------------------------------- 11 | 12 | using System.Windows.Input; 13 | using Avalonia; 14 | using ReactiveUI; 15 | using Shrinker.Avalonia.Commands; 16 | using Shrinker.Avalonia.Extensions; 17 | using Shrinker.Avalonia.Views; 18 | 19 | namespace Shrinker.Avalonia.ViewModels; 20 | 21 | public class AppViewModel : ReactiveObject 22 | { 23 | public ICommand AboutCommand { get; } 24 | 25 | public AppViewModel() 26 | { 27 | var isOpen = false; 28 | AboutCommand = new RelayCommand( 29 | _ => 30 | { 31 | if (isOpen) 32 | return; 33 | var dialog = new AboutDialog(); 34 | dialog.Opened += (_, _) => isOpen = true; 35 | dialog.Closed += (_, _) => isOpen = false; 36 | dialog.ShowDialog(Application.Current?.GetMainWindow()); 37 | }); 38 | } 39 | } -------------------------------------------------------------------------------- /ShaderShrinker/Shrinker.Avalonia/Views/AboutDialog.axaml: -------------------------------------------------------------------------------- 1 | 11 | 12 | 13 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /ShaderShrinker/Shrinker.Avalonia/Views/AboutDialog.axaml.cs: -------------------------------------------------------------------------------- 1 | // ----------------------------------------------------------------------- 2 | // 3 | // Copyright (c) 2023 Dean Edis. All rights reserved. 4 | // 5 | // 6 | // This example is provided on an "as is" basis and without warranty of any kind. 7 | // Dean Edis. does not warrant or make any representations regarding the use or 8 | // results of use of this example. 9 | // 10 | // ----------------------------------------------------------------------- 11 | 12 | using System.Reflection; 13 | using Avalonia.Controls; 14 | 15 | namespace Shrinker.Avalonia.Views; 16 | 17 | public partial class AboutDialog : Window 18 | { 19 | public AboutDialog() 20 | { 21 | InitializeComponent(); 22 | 23 | AppVersion.Text = $"Version {Assembly.GetExecutingAssembly().GetName().Version?.ToString()}"; 24 | } 25 | } -------------------------------------------------------------------------------- /ShaderShrinker/Shrinker.Avalonia/Views/CodeEditor.axaml: -------------------------------------------------------------------------------- 1 | 11 | 12 | 17 | 18 | 19 | 20 | 23 | 27 | 28 | 32 |