Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

C# API #425

Merged
merged 5 commits into from
Jun 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions Checker/compression_test.fs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
module CompressionTests

open ShaderMinifier
open System.Runtime.InteropServices
open System.IO
open System.Text
Expand Down Expand Up @@ -52,8 +53,8 @@ let compressionTest args filenames =
let minified =
use out = new StringWriter()
let files = [|for f in filenames -> f, File.ReadAllText("tests/real/" + f)|]
let shaders, exportedNames = ShaderMinifier.minify options files
ShaderMinifier.format options out shaders exportedNames
let minifier = Minifier(options, files)
minifier.Format(out)
out.ToString().ToCharArray()

let pointer = &&minified.[0]
Expand Down
24 changes: 15 additions & 9 deletions Checker/main.fs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ open System.IO

open Argu
open System.Text.RegularExpressions
open ShaderMinifier

type CliArguments =
| Update_Golden
Expand Down Expand Up @@ -135,8 +136,10 @@ let canBeCompiled lang stage content =
canBeCompiledByGlslang lang stage fullsrc && ((lang = "hlsl") || canBeCompiledByDriver stage fullsrc)

let doMinify options file content =
let arr = ShaderMinifier.minify options [|file, content|] |> fst |> Array.map (fun s -> s.code)
ShaderMinifier.print arr.[0]
let minifier = Minifier(options, [|file, content|])
use tw = new System.IO.StringWriter()
minifier.Format(tw)
tw.ToString()

let testMinifyAndCompile options lang (file: string) =
try
Expand Down Expand Up @@ -164,7 +167,7 @@ let testPerformance files =
let contents = files |> Array.map File.ReadAllText
let stopwatch = Stopwatch.StartNew()
for str in contents do
let options = Options.init([|"--format"; "text"; "--no-remove-unused"; "fake.frag"|])
let options = Options.init([|"--format"; "text"; "--no-remove-unused"|])
doMinify options "perf test" str |> ignore<string>
let time = stopwatch.Elapsed
printfn "%i files minified in %f seconds." files.Length time.TotalSeconds
Expand All @@ -177,29 +180,32 @@ let runCommand argv =
let cleanString (s: string) =
let s = s.Replace("\r\n", "\n").Trim()
versionRegex.Replace(s, "")
let options, filenames = Options.initFiles argv
let options, filenames = Minifier.ParseOptionsWithFiles(argv)
let expected =
try File.ReadAllText options.outputName |> cleanString
with _ when cliArgs.Contains(Update_Golden) -> ""
| _ -> reraise ()
let files = [|for f in filenames -> f, File.ReadAllText(f)|]
let shaders, exportedNames = ShaderMinifier.minify options files
let minifier = Minifier(options, files)
let result =
use out = new StringWriter()
ShaderMinifier.format options out shaders exportedNames
minifier.Format(out)
out.ToString() |> cleanString

let options = { options with outputFormat = Options.OutputFormat.IndentedText; exportKkpSymbolMaps = false}
for shader in shaders do
if filenames.Length = 1 then
let shader = minifier.GetShaders[0]
let resultindented =
use out = new StringWriter()
ShaderMinifier.format options out [|shader|] exportedNames
minifier.Format(out, options)
out.ToString() |> cleanString
let outdir = "tests/out/" + Regex.Replace(options.outputName, @"^tests/(.*)/[^/]*$", @"$1") + "/"
let split = Regex.Match(shader.mangledFilename, @"(^.*)_([^_]+)$").Groups
let name = split[1].Value
let ext = split[2].Value
Directory.CreateDirectory outdir |> ignore
File.WriteAllText(outdir + name + ".minind." + ext, resultindented + "\n")

if result = expected then
printfn "Success: %s" options.outputName
0
Expand Down Expand Up @@ -265,7 +271,7 @@ let main argv =
let realTests = Directory.GetFiles("tests/real", "*.frag")
for f in unitTests do
// tests with no #version default to 110
let options = Options.init([|"--format"; "text"; "--no-remove-unused"; "fake.frag"|])
let options = Options.init([|"--format"; "text"; "--no-remove-unused"|])
if not (testMinifyAndCompile options "110" f) then
failures <- failures + 1
testPerformance (Seq.concat [realTests; unitTests] |> Seq.toArray)
Expand Down
14 changes: 14 additions & 0 deletions Example/Example.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net7.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>

<ItemGroup>
<ProjectReference Include="..\Shader Minifier Library.fsproj" />
</ItemGroup>

</Project>
18 changes: 18 additions & 0 deletions Example/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/**
* Example of use of the ShaderMinifier library from C#.
*/

using ShaderMinifier;

var shader = """
out vec4 fragColor;
void main()
{
fragColor = vec4(1., 1., 1., 1.);
}
""";

var file = Tuple.Create("filename.frag", shader);
var options = Minifier.ParseOptions(new[] { "--format", "text" });
var minifier = new Minifier(options, new[] { file });
minifier.Format(System.Console.Out);
7 changes: 5 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,12 @@ shader is minified by hand by experienced demosceners, Shader Minifier is often
able to optimize it further. See this [2010
report](https://www.ctrl-alt-test.fr/2010/glsl-minifier-smaller-and-smaller/).

To be notified of new releases, use the watch feature of GitHub.
Shader Minifier is available:
* As an online website: https://ctrl-alt-test.fr/minifier/
* As a command-line tool (download from [Releases](https://github.com/laurentlb/shader-minifier/releases))
* As a .NET library (see [Example](https://github.com/laurentlb/shader-minifier/tree/master/Example))

Try the online version here: https://ctrl-alt-test.fr/minifier/
To be notified of new releases, use the watch feature of GitHub.

## Features

Expand Down
13 changes: 7 additions & 6 deletions SMBolero.Client/Main.fs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ open Bolero
open Bolero.Html
open Bolero.Remoting.Client
open Bolero.Templating.Client
open ShaderMinifier

/// Routing endpoints definition.
type Page =
Expand Down Expand Up @@ -48,15 +49,15 @@ type Message =
| ClearError

let minify flags content =
let options = Options.init flags
let shaders, exportedNames = ShaderMinifier.minify options [|"input", content|]
let options = Minifier.ParseOptions(flags)
let minifier = Minifier(options, [|"input", content|])
let out = new System.IO.StringWriter()
ShaderMinifier.format options out shaders exportedNames
minifier.Format(out)

let withLoc = new System.IO.StringWriter()
ShaderMinifier.formatWithLocations options withLoc shaders exportedNames
minifier.FormatWithLocations(withLoc)

out.ToString(), ShaderMinifier.getSize shaders, withLoc.ToString()
out.ToString(), minifier.GetSize, withLoc.ToString()

module API =
[<Microsoft.JSInterop.JSInvokableAttribute("minify")>]
Expand All @@ -74,7 +75,7 @@ let update (jsRuntime: Microsoft.JSInterop.IJSRuntime) message model =
if not model.flags.inlining then yield "--no-inlining"
if not model.flags.removeUnused then yield "--no-remove-unused"
if not model.flags.renaming then yield "--no-renaming"
yield! model.flags.other.Split(' ')
yield! model.flags.other.Split([|' '|], System.StringSplitOptions.RemoveEmptyEntries)
|]
printfn "Minify %s" (String.concat " " allFlags)
try
Expand Down
14 changes: 14 additions & 0 deletions Shader Minifier.sln
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "SMBolero.Client", "SMBolero
EndProject
Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "SMBolero.Server", "SMBolero.Server\SMBolero.Server.fsproj", "{C1A4652F-0F92-4530-B1C8-2AAC9C383650}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Example", "Example\Example.csproj", "{1C6C7E5F-41CF-456E-AEB2-8D501D43D2C5}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -84,6 +86,18 @@ Global
{C1A4652F-0F92-4530-B1C8-2AAC9C383650}.Release|x64.Build.0 = Release|Any CPU
{C1A4652F-0F92-4530-B1C8-2AAC9C383650}.Release|x86.ActiveCfg = Release|Any CPU
{C1A4652F-0F92-4530-B1C8-2AAC9C383650}.Release|x86.Build.0 = Release|Any CPU
{1C6C7E5F-41CF-456E-AEB2-8D501D43D2C5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{1C6C7E5F-41CF-456E-AEB2-8D501D43D2C5}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1C6C7E5F-41CF-456E-AEB2-8D501D43D2C5}.Debug|x64.ActiveCfg = Debug|Any CPU
{1C6C7E5F-41CF-456E-AEB2-8D501D43D2C5}.Debug|x64.Build.0 = Debug|Any CPU
{1C6C7E5F-41CF-456E-AEB2-8D501D43D2C5}.Debug|x86.ActiveCfg = Debug|Any CPU
{1C6C7E5F-41CF-456E-AEB2-8D501D43D2C5}.Debug|x86.Build.0 = Debug|Any CPU
{1C6C7E5F-41CF-456E-AEB2-8D501D43D2C5}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1C6C7E5F-41CF-456E-AEB2-8D501D43D2C5}.Release|Any CPU.Build.0 = Release|Any CPU
{1C6C7E5F-41CF-456E-AEB2-8D501D43D2C5}.Release|x64.ActiveCfg = Release|Any CPU
{1C6C7E5F-41CF-456E-AEB2-8D501D43D2C5}.Release|x64.Build.0 = Release|Any CPU
{1C6C7E5F-41CF-456E-AEB2-8D501D43D2C5}.Release|x86.ActiveCfg = Release|Any CPU
{1C6C7E5F-41CF-456E-AEB2-8D501D43D2C5}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down
86 changes: 48 additions & 38 deletions src/api.fs
Original file line number Diff line number Diff line change
@@ -1,41 +1,51 @@
module ShaderMinifier
namespace ShaderMinifier

open System.IO

let getSize (shaders: Ast.Shader[]) =
shaders |> Array.sumBy (fun s -> Printer.print s.code |> String.length)

let minify (options: Options.Options) (files: (string*string)[]) =
// like printfn when verbose option is set
let vprintf fmt = fprintf (if options.verbose then stdout else TextWriter.Null) fmt

let printSize (shaders: Ast.Shader[]) =
if options.verbose then
let length = getSize shaders
vprintf "Shader size is: %d\n" length

let names = String.concat "," [for n, c in files -> $"'{n}' ({c.Length}b)"]
options.trace $"----- minifying {names}"
vprintf "Input file size is: %d\n" (files |> Array.sumBy (fun (_, s) -> s.Length))

let parseAndRewrite (filename, content) =
let shader = Parse.runParser options filename content
let code =
if shader.reorderFunctions then
Rewriter.reorderFunctions options shader.code
else shader.code
{ shader with code = Rewriter.simplify options code }

let shaders = Array.Parallel.map parseAndRewrite files
vprintf "Rewrite tricks applied. "; printSize shaders

if options.noRenaming then
shaders, []
else
let exportedNames = Renamer.rename options shaders
vprintf "Identifiers renamed. "; printSize shaders
shaders, exportedNames

let format = Formatter.print
let formatWithLocations = Formatter.printWithLocations
let print = Printer.print
type Minifier(options, files) =
let getSize (shaders: Ast.Shader[]) =
shaders |> Seq.sumBy (fun s -> Printer.print s.code |> String.length)

let minify (options: Options.Options) (files: (string*string)[]) =
// like printfn when verbose option is set
let vprintf fmt = fprintf (if options.verbose then stdout else TextWriter.Null) fmt

let printSize (shaders: Ast.Shader[]) =
if options.verbose then
let length = getSize shaders
vprintf "Shader size is: %d\n" length

let names = String.concat "," [for n, c in files -> $"'{n}' ({c.Length}b)"]
options.trace $"----- minifying {names}"
vprintf "Input file size is: %d\n" (files |> Array.sumBy (fun (_, s) -> s.Length))

let parseAndRewrite (filename, content) =
let shader = Parse.runParser options filename content
let code =
if shader.reorderFunctions then
Rewriter.reorderFunctions options shader.code
else shader.code
{ shader with code = Rewriter.simplify options code }

let shaders = Array.Parallel.map parseAndRewrite files
vprintf "Rewrite tricks applied. "; printSize shaders

if options.noRenaming then
shaders, [||]
else
let exportedNames = Renamer.rename options (Seq.toArray shaders) |> List.toArray
vprintf "Identifiers renamed. "; printSize shaders
shaders, exportedNames

let shaders, exportedNames = minify options files

static member ParseOptions(flags) = Options.init flags
static member ParseOptionsWithFiles(flags) = Options.initFiles flags

member _.GetSize = getSize shaders
member _.GetShaders = shaders

member _.Format(writer) = Formatter.print options writer shaders exportedNames
member _.Format(writer, options) =
Formatter.print options writer shaders exportedNames
member _.FormatWithLocations(writer) = Formatter.printWithLocations options writer shaders exportedNames
10 changes: 5 additions & 5 deletions src/formatter.fs
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ type private Impl(options: Options.Options, withLocations) =
fprintfn out "#ifndef %s" macroName
fprintfn out "# define %s" macroName

for value: Ast.ExportedName in List.sort exportedNames do
for value: Ast.ExportedName in Seq.sort exportedNames do
fprintfn out "# define %s_%s \"%s\"" ((formatPrefix value.prefix).ToUpper()) value.name value.newName

fprintfn out ""
Expand All @@ -70,7 +70,7 @@ type private Impl(options: Options.Options, withLocations) =
fprintfn out "#ifndef SHADER_MINIFIER_HEADER"
fprintfn out "# define SHADER_MINIFIER_HEADER"

for value: Ast.ExportedName in List.sort exportedNames do
for value: Ast.ExportedName in Seq.sort exportedNames do
fprintfn out "# define %s_%s \"%s\"" ((formatPrefix value.prefix).ToUpper()) value.name value.newName

fprintfn out "#endif"
Expand Down Expand Up @@ -106,7 +106,7 @@ type private Impl(options: Options.Options, withLocations) =
let printJSHeader out (shaders: Ast.Shader[]) exportedNames =
fprintfn out "// Generated with Shader Minifier %s (https://github.com/laurentlb/Shader_Minifier/)" Options.version

for value: Ast.ExportedName in List.sort exportedNames do
for value: Ast.ExportedName in Seq.sort exportedNames do
fprintfn out "var %s_%s = \"%s\"" (formatPrefix value.prefix) (value.name.ToUpper()) value.newName

fprintfn out ""
Expand All @@ -120,7 +120,7 @@ type private Impl(options: Options.Options, withLocations) =

fprintfn out "; Generated with Shader Minifier %s (https://github.com/laurentlb/Shader_Minifier/)" Options.version

for value: Ast.ExportedName in List.sort exportedNames do
for value: Ast.ExportedName in Seq.sort exportedNames do
fprintfn out "_%s_%s: db '%s', 0" (formatPrefix value.prefix) (value.name.ToUpper()) value.newName

fprintfn out ""
Expand All @@ -138,7 +138,7 @@ type private Impl(options: Options.Options, withLocations) =
let printRustHeader out (shaders: Ast.Shader[]) exportedNames =
fprintfn out "// Generated with Shader Minifier %s (https://github.com/laurentlb/Shader_Minifier/)" Options.version

for value: Ast.ExportedName in List.sort exportedNames do
for value: Ast.ExportedName in Seq.sort exportedNames do
fprintfn out "pub const %s_%s: &'static [u8] = b\"%s\\0\";" ((formatPrefix value.prefix).ToUpper()) (value.name.ToUpper()) value.newName

for shader in shaders do
Expand Down
9 changes: 5 additions & 4 deletions src/main.fs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
module Main

open ShaderMinifier
open System.IO

let readFile file =
Expand All @@ -8,21 +9,21 @@ let readFile file =
else new StreamReader(file)
stream.ReadToEnd()

let minifyFiles (options: Options.Options) filenames =
let minifyFiles (options: Options.Options) filenames out =
let files = [|
for f in filenames do
let content = readFile f
let filename = if f = "" then "stdin" else f
yield filename, content |]
ShaderMinifier.minify options files
let minifier = Minifier(options, files)
minifier.Format(out)

let run (options: Options.Options) filenames =
use out =
if Options.debugMode || options.outputName = "" || options.outputName = "-" then stdout
else new StreamWriter(options.outputName) :> TextWriter
try
let shaders, exportedNames = minifyFiles options filenames
ShaderMinifier.format options out shaders exportedNames
minifyFiles options filenames out
0
with exn ->
printfn "%s" (exn.ToString())
Expand Down
7 changes: 6 additions & 1 deletion src/options.fs
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,12 @@ let private initPrivate argv =

let flagsHelp = lazy (argParser.Value.PrintUsage(message = helpTextMessage))

let init argv = initPrivate argv |> fst
let init argv =
let options, filenames = initPrivate argv
if filenames.Length > 0 then
failwithf "Unexpected arguments: %A" (String.concat " " filenames)
options

let initFiles argv =
let options, filenames = initPrivate argv
if filenames.Length = 0 then
Expand Down
Loading