From dbd5be569a81e543d42cbd6c687752bceea06545 Mon Sep 17 00:00:00 2001 From: Laurent Le Brun Date: Sun, 1 Jan 2023 19:35:31 +0100 Subject: [PATCH 01/32] Online minifier: update the code example (#201) Was broken by the unused function removal :) --- SMBolero.Client/Main.fs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SMBolero.Client/Main.fs b/SMBolero.Client/Main.fs index 6c321a9e..c2e9f943 100644 --- a/SMBolero.Client/Main.fs +++ b/SMBolero.Client/Main.fs @@ -25,7 +25,7 @@ type Model = let initModel = { page = Home - shaderInput = "int foo() { return 6 * 7; }" + shaderInput = "out vec4 fragColor;\nvoid main() {\n fragColor = vec4(1.,1.,1.,1.);\n}" shaderOutput = "" flags = "--format text" error = None From 8bcb5324100e9f9e45bb8db1c63d310d3bbd713c Mon Sep 17 00:00:00 2001 From: Laurent Le Brun Date: Tue, 3 Jan 2023 00:25:38 +0100 Subject: [PATCH 02/32] Add Crinkler library, use it to generate report about compressed size of shaders --- Checker/Checker.fsproj | 32 +++++++++++++++-- Checker/compression_test.fs | 66 ++++++++++++++++++++++++++++++++++ Shader Minifier.sln | 42 ++++++++++++++++++++++ lib/Compressor.dll | Bin 0 -> 1921536 bytes src/options.fs | 2 +- tests/commands.txt | 2 +- tests/compression_results.log | 14 ++++++++ 7 files changed, 154 insertions(+), 4 deletions(-) create mode 100644 Checker/compression_test.fs create mode 100644 lib/Compressor.dll create mode 100644 tests/compression_results.log diff --git a/Checker/Checker.fsproj b/Checker/Checker.fsproj index b8c4dc10..46c18a98 100644 --- a/Checker/Checker.fsproj +++ b/Checker/Checker.fsproj @@ -44,6 +44,32 @@ 11 + + true + full + false + false + bin\Debug\ + DEBUG;TRACE + 5 + bin\Debug\Checker.XML + true + ../../.. + --update-golden + x64 + + + pdbonly + true + true + bin\Release\ + TRACE + 3 + bin\Release\Checker.XML + true + ..\..\.. + x64 + @@ -58,7 +84,11 @@ + + + PreserveNewest + @@ -71,8 +101,6 @@ ..\lib\OpenTK.dll - - Shader Minifier Library {059c6af3-1877-4698-be34-bf7eb55d060a} diff --git a/Checker/compression_test.fs b/Checker/compression_test.fs new file mode 100644 index 00000000..b12d9765 --- /dev/null +++ b/Checker/compression_test.fs @@ -0,0 +1,66 @@ +module CompressionTests + +open System.Runtime.InteropServices +open System.IO +open System.Text + +#nowarn "51" // use of native pointers + +module Crinkler = + [] + extern void InitCompressor() + + [] + extern single ApproximateModels4k(char* data, int datasize) + + +let testFiles = [ + "from-the-seas-to-the-stars.frag" + "the_real_party_is_in_your_pocket.frag" + "ed-209.frag" + "valley_ball.glsl" + "lunaquatic.frag" + "slisesix.frag" + "yx_long_way_from_home.frag" + "oscars_chair.frag" + "kinder_painter.frag" + "ohanami.frag" + "terrarium.frag" + "leizex.frag" + "elevated.hlsl" +] + +let writer = new StringWriter() + +let log fmt = + let logger str = + printf "%s" str + writer.Write(str) + + Printf.ksprintf logger fmt + +let testFile (file: string) = + let args = if file.EndsWith("hlsl") then [|"--hlsl"|] else [||] + Options.init(args) + let minified = + use out = new StringWriter() + let shaders, exportedNames = ShaderMinifier.minifyFiles [|"tests/real/" + file|] + Formatter.print out shaders exportedNames Options.Text + out.ToString().ToCharArray() + + let pointer = &&minified.[0] + log "%-40s " file + log "%5d " minified.Length + let compressedSize = Crinkler.ApproximateModels4k(pointer, minified.Length) + log "=> %8.3f\n" compressedSize + minified.Length, float compressedSize + +let run () = + Crinkler.InitCompressor() + + writer.GetStringBuilder().Clear() |> ignore + let sizes = List.map testFile testFiles + let minifiedSum = List.sumBy fst sizes + let compressedSum = List.sumBy snd sizes + log "Total: %5d => %9.3f\n" minifiedSum compressedSum + File.WriteAllText("tests/compression_results.log", writer.ToString()) diff --git a/Shader Minifier.sln b/Shader Minifier.sln index 5df3470a..5bb3b99c 100644 --- a/Shader Minifier.sln +++ b/Shader Minifier.sln @@ -19,29 +19,71 @@ EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 Release|Any CPU = Release|Any CPU + Release|x64 = Release|x64 + Release|x86 = Release|x86 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {059C6AF3-1877-4698-BE34-BF7EB55D060A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {059C6AF3-1877-4698-BE34-BF7EB55D060A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {059C6AF3-1877-4698-BE34-BF7EB55D060A}.Debug|x64.ActiveCfg = Debug|Any CPU + {059C6AF3-1877-4698-BE34-BF7EB55D060A}.Debug|x64.Build.0 = Debug|Any CPU + {059C6AF3-1877-4698-BE34-BF7EB55D060A}.Debug|x86.ActiveCfg = Debug|Any CPU + {059C6AF3-1877-4698-BE34-BF7EB55D060A}.Debug|x86.Build.0 = Debug|Any CPU {059C6AF3-1877-4698-BE34-BF7EB55D060A}.Release|Any CPU.ActiveCfg = Release|Any CPU {059C6AF3-1877-4698-BE34-BF7EB55D060A}.Release|Any CPU.Build.0 = Release|Any CPU + {059C6AF3-1877-4698-BE34-BF7EB55D060A}.Release|x64.ActiveCfg = Release|Any CPU + {059C6AF3-1877-4698-BE34-BF7EB55D060A}.Release|x64.Build.0 = Release|Any CPU + {059C6AF3-1877-4698-BE34-BF7EB55D060A}.Release|x86.ActiveCfg = Release|Any CPU + {059C6AF3-1877-4698-BE34-BF7EB55D060A}.Release|x86.Build.0 = Release|Any CPU {CF735CB3-7698-41DA-9E91-69D0057087CB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {CF735CB3-7698-41DA-9E91-69D0057087CB}.Debug|Any CPU.Build.0 = Debug|Any CPU + {CF735CB3-7698-41DA-9E91-69D0057087CB}.Debug|x64.ActiveCfg = Debug|x64 + {CF735CB3-7698-41DA-9E91-69D0057087CB}.Debug|x64.Build.0 = Debug|x64 + {CF735CB3-7698-41DA-9E91-69D0057087CB}.Debug|x86.ActiveCfg = Debug|Any CPU {CF735CB3-7698-41DA-9E91-69D0057087CB}.Release|Any CPU.ActiveCfg = Release|Any CPU {CF735CB3-7698-41DA-9E91-69D0057087CB}.Release|Any CPU.Build.0 = Release|Any CPU + {CF735CB3-7698-41DA-9E91-69D0057087CB}.Release|x64.ActiveCfg = Release|x64 + {CF735CB3-7698-41DA-9E91-69D0057087CB}.Release|x64.Build.0 = Release|x64 + {CF735CB3-7698-41DA-9E91-69D0057087CB}.Release|x86.ActiveCfg = Release|Any CPU {7A0B4487-C3F6-4753-9C8D-FEE09049F52D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {7A0B4487-C3F6-4753-9C8D-FEE09049F52D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {7A0B4487-C3F6-4753-9C8D-FEE09049F52D}.Debug|x64.ActiveCfg = Debug|Any CPU + {7A0B4487-C3F6-4753-9C8D-FEE09049F52D}.Debug|x64.Build.0 = Debug|Any CPU + {7A0B4487-C3F6-4753-9C8D-FEE09049F52D}.Debug|x86.ActiveCfg = Debug|Any CPU + {7A0B4487-C3F6-4753-9C8D-FEE09049F52D}.Debug|x86.Build.0 = Debug|Any CPU {7A0B4487-C3F6-4753-9C8D-FEE09049F52D}.Release|Any CPU.ActiveCfg = Release|Any CPU {7A0B4487-C3F6-4753-9C8D-FEE09049F52D}.Release|Any CPU.Build.0 = Release|Any CPU + {7A0B4487-C3F6-4753-9C8D-FEE09049F52D}.Release|x64.ActiveCfg = Release|Any CPU + {7A0B4487-C3F6-4753-9C8D-FEE09049F52D}.Release|x64.Build.0 = Release|Any CPU + {7A0B4487-C3F6-4753-9C8D-FEE09049F52D}.Release|x86.ActiveCfg = Release|Any CPU + {7A0B4487-C3F6-4753-9C8D-FEE09049F52D}.Release|x86.Build.0 = Release|Any CPU {2DF47B2C-A68C-430C-B23F-BF51F68DF74D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {2DF47B2C-A68C-430C-B23F-BF51F68DF74D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2DF47B2C-A68C-430C-B23F-BF51F68DF74D}.Debug|x64.ActiveCfg = Debug|Any CPU + {2DF47B2C-A68C-430C-B23F-BF51F68DF74D}.Debug|x64.Build.0 = Debug|Any CPU + {2DF47B2C-A68C-430C-B23F-BF51F68DF74D}.Debug|x86.ActiveCfg = Debug|Any CPU + {2DF47B2C-A68C-430C-B23F-BF51F68DF74D}.Debug|x86.Build.0 = Debug|Any CPU {2DF47B2C-A68C-430C-B23F-BF51F68DF74D}.Release|Any CPU.ActiveCfg = Release|Any CPU {2DF47B2C-A68C-430C-B23F-BF51F68DF74D}.Release|Any CPU.Build.0 = Release|Any CPU + {2DF47B2C-A68C-430C-B23F-BF51F68DF74D}.Release|x64.ActiveCfg = Release|Any CPU + {2DF47B2C-A68C-430C-B23F-BF51F68DF74D}.Release|x64.Build.0 = Release|Any CPU + {2DF47B2C-A68C-430C-B23F-BF51F68DF74D}.Release|x86.ActiveCfg = Release|Any CPU + {2DF47B2C-A68C-430C-B23F-BF51F68DF74D}.Release|x86.Build.0 = Release|Any CPU {C1A4652F-0F92-4530-B1C8-2AAC9C383650}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {C1A4652F-0F92-4530-B1C8-2AAC9C383650}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C1A4652F-0F92-4530-B1C8-2AAC9C383650}.Debug|x64.ActiveCfg = Debug|Any CPU + {C1A4652F-0F92-4530-B1C8-2AAC9C383650}.Debug|x64.Build.0 = Debug|Any CPU + {C1A4652F-0F92-4530-B1C8-2AAC9C383650}.Debug|x86.ActiveCfg = Debug|Any CPU + {C1A4652F-0F92-4530-B1C8-2AAC9C383650}.Debug|x86.Build.0 = Debug|Any CPU {C1A4652F-0F92-4530-B1C8-2AAC9C383650}.Release|Any CPU.ActiveCfg = Release|Any CPU {C1A4652F-0F92-4530-B1C8-2AAC9C383650}.Release|Any CPU.Build.0 = Release|Any CPU + {C1A4652F-0F92-4530-B1C8-2AAC9C383650}.Release|x64.ActiveCfg = Release|Any CPU + {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 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/lib/Compressor.dll b/lib/Compressor.dll new file mode 100644 index 0000000000000000000000000000000000000000..e8adecbebc8c2f56fab01c598cf2454e9c6b4d3a GIT binary patch literal 1921536 zcmeFaby(Kh*7tiOsHiAlVq*t(q8Qu?dLy8i*x22IVk|`w1#huCaoO123Zi0*Ep`ib zw{kvTTb^T&Cw+v{3`IdYCUelx}#zaK2$w$lyP27|$d|58#6hCTe$ zKlfDle-CV}42CQP_hm8c$Z)pM9xI=-g_kWExHH~Tx-e^;+s8*>z{i3e% z^Ufi^sH&+yn@0Ji{%jTHpUQ6$)sCMXkF{8ylKQjd@&JBbLSFip4z-N>jYt1Q_fN%} z_3qkBef~W{KTm_9+r*59b8WYG{hRj2P}n(Bnk~ z21B}3(m#G09E$u7D)cmlPKf?i`uoSflImi}~5@-{fM-RjAOlM^A$x2)7K=3+rL=FTcQl{d31&Kr;_x3!}lXO#CS1 z6q7XnE>~{I&>@;Ysn3jOmpU=h{U^EZ{RSfF#=JA|EDa6#Y4>k(^`QQL`tOYXC10$T z&XByyIin$Y^oF#CxuyPdO^JLHhWdNPqp>gXqB2Q&%(^j}`^269L z6W|@quqJ9SX_y2lmHG{0(TEdLt5< z2@&W0fKiRo|BNBPiNQ3dno_5i}1L96UW*#9l)u*ZPp z^#H>`biMatbdxPyuV3{0;|yK8Bw%Ioalni($aOl4-0OjiGF=6@HL76GV-6bS7t`;v z%CwBxk&DU*F9T|!gM<;9kowHc>8ng z^(YKl$`@b0^oRStI&$fJp!F{R?fMz|XcvIoFHb;P8EvmFD+eK0DIV0=0Abr5&}Ic= zppWLz$>E?UGK0p+z=M(KHq}&dP)M@%#K|KXVC)181Ydxg>jxT>b3$t~3%M6>VC)|U zcB5 zY_a062XG__@5_cj>(>A@;3p2%+XU^SKO$SQz?iiUbhQVqSPgZ@en7iZM0a6-KogWH>|oN{NgE$r_W#% z?+-11A*}fIg3+WRas%R^E$K(gv=JxgtJaapSrdz-<_&W=_L=hAFhd z=h6z;fm~ZX?v~na{MKNqeqLIy9sz3iXD}z$A{>7X;a4?4clra~tOs3Yg~**%a1Tz# z%4`Mpdp>B~ zn?YA9e(5!$w)^m^Wds_%LNPUKJR;>*!hrnBB{vRl0(Kb=uocgrXa#snTNsXsjKe)*t9DszvL@ za(wCSgwghO(H)*ya`T}1egUmz##EeQpG8ytWf&l2J>2*~n18a4*4r|8zqUIDp8L?+ zF#+1%v1n}2y1c6+Yls=6L7^~wv@Ta1#pu2;Xyf)HV)KEHN+?~(a}<%mLjV;@BDa1s zy;U27fjQM^eRz)Ant^~W*U^bLw zcGDAD7+f3&I0!p)H*aTEh>4Aau*3i0iK*Vz}=$?I`i)v$_bVpi7QrqOD?+EvuOqYjF!}#fk z2Zmy3%qvB!<2Jg?{Tgnq#&9d^{J7`^H*OiZo&P&IBFltSr70?B+R5`=3 zC4ly$FtA<`x={>!Mt|gP71P{^!K+gR@nGB{dq^fJmk>fCp_b zP`fNo^;Qo0t(yZY-;_dpyoAvMd*FI&dY?Lp6)P>okZ!0o&x6R-j5t(QyZm%bhUOJ$ zHM@=hUmgByTVu~f(_*y}s+JScy{CCqLTA)fo%^Md;eJ^NXsAIq)}S-QBD_UWYd8>7 z3%f9)#FgkS*6Hk41;$7nPmxzJm5+ov*<~AYN3Jo13_}s|nFn`!d38-WL=R|*XK<+B zbkM#!QtS1i-(w}PcYPBE=9NOE)n3rA{ZTtA-GQYL8Q%l2L`mvpJ%F2s(fwux_YZ}$ z*Fx0heaE!|9)P!Aa2I>ReXX_M>I;@fX!X2tgSO}+pshXVI;F7f_kzY{#;b+*Ff~rz zXMcv;LvKJOEzS`o5k4A?m4`aThb^GxSQf_Y8Zai!pto|`Y3A&q<&lUl0ZN(1L?XP` zo>r31k4up-sh6=1gC+My>HhOx&~j=ew~0XGODw`e?V+Wa0d1om z?a>6}CQYF8Lz-7}&S2{3Pds?Kl~yIG6$(IPr6SbC74-OGtQ7KuW(tNja5|<6C~??Z zoRKHR!QFoscPHz1;;VZ=pgY2MpM#F<1{yR6H2X+2x+;@?R~_`@2^hW9(fVeR3kTe8 zh578iXf4wo*5wRbtEQ+0HwLsjNpBZ*2;bJuYL^bQvUa_im+}6Jo_Tv0bknZ_WNC<3 zXPaZ?OkueG_ZdfH9~g)sldq9*AtwG<$y@ksdm{a!jQ4`ouV%H*QB+tCA3vr0Nv(b^!;JFYPNyMS6mM!2=|(^2J-s4cyVT+27?E}cq9CECgA8>Xlopi%W6X7m^5yE zgJJDKZ_#aVqx(c0_wWN`DvoZ0Lzwz15$8u}TuY|&tR@(~N(da*g1WV!m9sgZ_7CJt zKQZ-MbLf*aHh#xINHu8j8KI5Y04-=JZup%5ZK(6(sw=eRwV>5XgIquW8lMzNV{ttX zT~^G>f%lar21_nLv+D=9@)L9?e?lX(V!A;mSi9RWKIt}5YyoP1o@fj|h`l}y;Lhj; zqgN5o*WPH%9FKt+bCB!y9mcFa&|YbJH_e9H7ezPk8@$TWjxIM&V{9v*BhpZJwbDwg zUk=06eC2gFbjWY^KingjF3byAL7;DGVM|$n7mA>Oz?oTk>(*kaOqL0$OvC>_)2|pDt?kd@7 zl!Spf@@0A`w5}`QUi3#dzb;cYbzrz1f_CR3a`|uI_?MzEHaAB2>NMoO210Yc2kO!c zkxe=1V@Y1nT4&I;e+PQCAj9vk1yMySzMYnCmjFZ(ZRLy3Rkugz79R;(V*p@}HW@bu z%zxAF&{(Xms*`*0V2zUR@5_Mz%43HL77?baCmH zgwf>}osZjxMz^6DINuRky%x0Ymq4V&UOH-`BF8HqXo*^Cwg;gd)~5O@n$~hR47eL$ zoNtTyX4x_SxCy}T4QPPoOSLSR->CcL=-S8))j>5`ce=Alh(zrM{ho#Odu}o4xTSzH znK4@M1sV@3!yTa`FhM6>z3#a*=4<8HZd;$@xu#RyhN6=ui}LRt|7&RDVf%Kp)Xn0m(Wb!!@EzdZ07)JZ7jg z6te&VSHJ!4D`tk+_2IVEm{oWc^cp| zWz8+G!5G~Fk%BrjAE@$FOx3|Jsw8|aMsJf_gL>`(JunoF^sA6t+6myLD^JOva03+L zJGn8xGd;VjLru3!DVS2tsIiBw&_U47sy7Q4y&d?K_e-7@VcF^9*p>Z*&9nj6X zNGzu6D0v^DCGM`BHBPtatOY^Cl)bJ!2lx3yXy;U2=-&*l%4pf&O%J2AlKhuJFfQwg zlA^mymhmu(jfLjE8g3@-e>ZGEt#q4x69ssE9V=t9K)cdQ{)IC({{a}ts=R5$V9aOF zhuk9FDkr;Yg~;Hiv}P|y!{rVg<-81SqjY=C2A!qnwpusv&bl$X zet@xg7Ol40WR{PmUpqJChSmq&6$7X`kdEvsq4u;2VAo=3BVJ+PsOmYdry^W)3$%#l z^xL{VLs+j5>aT(~`y!yRh_H~2Z+>ircL<;q)w0Zu1D=c!2aOhlfIaV#Yp7yF10D1mGZ2FoIz+xVrMElhaO3QL2JK-292RYi z=49eQ`u$*!SD*E?rq+d9TZ|vdXe$?>%U0T1ll6RW>Dp4i2A$9BhvhKs*@3s9?bc3R zyc8n+wP}U4hv8<62Zej!+ML{gqPoOY&w_B{`G7fj;r@6DZNKidQytNLsUv!}39vpF z{a##5A2Z}trzM~bH663;MK>`KwK6l%SW%Kz9ak9lYtxEK$FS^GLi(k0g6BSHFB&4} zJsNPR9j@h1Pj7GJ_%apUSGOiEH7;YIo2oq}s=#QF1g+F=gu|cEdc6Qs&8h(|+{caV z4QTCFG*)|HppdTNB~N1DyVk;?H-PR15ec~iV{=y+!<2~3Nsn+*on`)m0FzyCGJ|%r zA1!gnWiDzn_amHEkG7~%*z&pw&$NSf_Ba|oIcRz7>aj}~tP#19TiFGpUDE*?=`h@C zi$>9}^fp`%`Pmz22S)(PsOB+z3LQ1m=C))Cve<#%QKN z_kRX0<~Bwz>2ZHjxxA_N>^&;|brA-13|TY|pnjoN$NSC42135%vRy8`|leu>%> zZFmtcVFc=&?t1|AoDQ@reu(U-2w1TT?qroQGK{1(y*1|R7RG3nqM&6<16r#hd|2g< zPr80x&>?5gRF0p6@F4}~t1Yx!GMZkGqQNW-j8J(oMl~LP?Kz*6EuHL3>w_*ob@!n* zQF)260#;1(q1kJ*T-_B~?*M><0(&zpoxgiP%W5qekLrTPX$S*!*u>VusH+p)@13x6 zCl54Fm5*<|f^l;mj66$tPzy5Sm0v8a@=9Hvy~edRx;K8vg>dCsw9=JEBe&A&wU5|)o+UFV=J<=YBYL}z8 z6FXoGZ$vAdN_82kBhpQ|-uYJ;$kP$Ds?gx5BG(K`!|TK*j21QoVU>mAD{lkDk&FuM%2 zo;sqV^~_&J!uZkwwKaiouYRMoT(7^YJVT_qQn0KVk(V>AqzMecTHts$M2aaX4_2;X zeF1P)XL8Hw$hBAr`tI=I<4MCfM%#fE8#w^ z-OAUFd}bjopM!{NHP9x3fNhFj23@{Ks}kc<3@1x#KKD0bba6jiE3ZVjv0j$^Q~|=K z7Of^)A49StH$zjUkpmhgLEUfrgi>6Cs^7=(6(q|_N<11K7oMR zdRKJxBHZ+c086#awbaW_yME|q+D>b--mj*ft1DH{`Th$7SMy?OK^GXVY0$`22)V3j zKx->A4{i)?yHb}^szx~upjBod;JXg5$=a$a`XT&A#j|V5a(5Z9yxbcrKDXemQL2_^ z8(>L#)YjV2n&$+FR&HUXEw{`xLb5*tR>ml2Soe&Ms;KmmD+?OYGijAo)un=N33YY8 z%}fLx+zqR0h?ROX}+Dt+5@^UG3unL`=$B8fuZ$(FVV_90uGA5Z$4= zfw$6~IOsmyK{N5?QU$=6jySYevolGzr_W0GHoe1g;xWJ(ZNmc((HfweaE^0;Uh4e( z95m9cMY!o!XxEi}^(_yrOK1Ansr%rqS#;jS4UyIUfF;hLwVKoUwXO)~X$cxp5A#!$ zBjwel|H)9mDrKc*G@I7U1l(v#Zy73M;QB)}y!E7?BmumX;4W6BWBX)!TU{F6-g3xr z1Ov?%LCdMP9&PjhLRv$6sN(G_`B%FD{kr=D+TEt}BdWwCZpEv`N<-Jr#%P{wFq$?) z*Uyc9Gbs(Nr)7HoGc6~*e7QLUQ?G_$rGGv|T66|1Yl6m*O|rKc?w74}>8%wyej7AT zX%y{`My}0t^sPCqv-1G6uhC_Rw8-75i`=TESZOa)UH^ppt{~vC9M5-{VJ*{J&<0wo zX?^kK!w@uz=wh;~F;;3%hij)hc4duYp)Pw{>(N^+UAeb+MsBHQ&extWj%rxD&!UlM z4uO#*z2kZ+@mWXha0}^(Yx&u`Us&?E;{O73GcVuMq|wz z(231xt%`&ewHA%Oy7u)Lg&R$kGt3q^JqOFBPePlcm!}m}iv8RlqmysaT963?PMSW~ zv2x^cI1RX`lO(-rrQ>yx*r}~$x-Q>tO2wDv#i+3Wtpt0(JQV_d-J{i^51{A^ zoZPOBBAtftwH2)-C4rx{z_RN2oO7JkEhSlfwX3v}m7P23$Zjxh6kJBXn1DPQMu?!OyyV%uvJb|uq{TT^(tkZJEr;_2gK(F{Mv-tx+!=%LDxfn-QI_3 z#c#}naCjro0KKg1V})?;q1c=LfY$mVw6>{Gw%3l%vzLNqJqcPy}@VY zE29#O`*ygo=Nafj&4|Lv^jqqkYoN+Aj?kLxwb(D+7xrF5&V3KwH_4COn3ss$F9##4 z4I10^JiZ-4BrFt~YbRO(I*LZh=nSReNqUUl_YpqT0n4=&jSa&X!a$|=3(e3H?a=Vh zM9-%8p~EK7I;+y3O%jYEn#D`6!T3XI@(*QcH}j*mtH0)f(lT4sN>{80j46qywF}b6 zbX_BxIMFIs0^tnbX_Zv+^!W^ErOkl+F^Ejr0Jzx=MuYtH@$)PUca^j1m&I~cXK0bC z5Cm%yp4ayb0|IEp>O+Ei4H3EN54YndT3MNf3gDA?)skz#RMI?ti!c6}@znJ=KW z$rq4c+uVoo(4HzdBlTh_Xd`MzYlFVNMyrozPF0m{_9*+ZSJr%0w>#hO3@{-U^KL(( zO_hNhT423SN=~1Gq^SeVQ8g5&Z-BTOm>*LLjojK}FF(gXd3~7B=M!>O)8XXk`uGx8 zh#?Ho%ZQWCwC*YYDw5V+@#gLHzH+}h?Lj1eo+(CGYQK-^yW6b7z55?bni^SV!i$Es)zSy5kRrk03TI~ z20G(Vnx?23zaWxNJNl*9fTf=?np_m4;n$Emd=YL=9oxp2v|K-8w8T1ESJNWWAsPdw zKA=NYdD^AJu!C*{do;reTH{bo4gcgiEYB}YtNAuW?&yk_s7mjYleFUQ(%PnLLD`Ie z=`pyrOeN(f^Fa41dsw*=Q%!_^^QFtJ+C@!=>G!?5JoNxyR#k+1OG~_A6Iy+ggUr!< z&aP^iwNlB2!(asELBmP4`n$cclKPEnhLfnR?SpXr(um9rqst5LP;&ZYSn*kpoOf=( zuA#_v*5PV50?V@+(Hf%1Xq5@>tv?yt>oYL!XyZ=%2;FeKTzmc&Q_WKIg9@}lhF~Sr zD%4J$My=R;KtewC+aI+wdQjcZqI*EOWBOL|IWKDW2Y^PYoZ3~{(x!blx%V72ccm5E z+as4%K6j3Q7OXj0w+!HpN;x0jVb4~bZ}vmDnr7Izk!ZZQgUI$aFupa#p$sbN+3EnV zpMc2ZQ*a}n(_4tX0jjTX=JdhTauw9VHS(u#>8-KC8MYP;Kkd}qdZSxG*Jih^sO{3)Kd3^t(^Z74>*g@gp4OG= zgt+J^M)_V(`ayeWCADo_c~c zt!RDC1}$748DCn3S|63cgH+_br&a5A9>%VgnD4B^tCNzuhPpxKRK2~!S-9aZQ9FMM z+L$mjTCT>ZPb1JteQ~Xxo_SdpMBI1aOL=XK-`*oK_y;XlT>-91uJA?BWW5Brt|heS z3cVfw18#q9`ek%6c3Vbo3wOZXxeQvA-jbPDp*uuHiK>m!INAc*(?q!E8ep$;epGj#X+JIAzRv^a^ylFGJ+AwucqEmY!4T zB{B~5L@k7eKY_MS>+R<;7|ufhnO4xzuIr)|;-OqtJu$R6!uw{UcCtQtZu@^?$4Y<)+Z-_R?gA!jshh0baiY~45^%NR5 zM6QnRO!=+p(%Fc}!*fq=LK3yXzSDT zyS^H&j4GLpxR25HdZRPRh1SIR&^(pX^iqW4t{~S%Z)C^m^~H3}I%}n{Be#J1YCH7F zfSjA^b$=EH_3ey-ZnGFs-Hiwz8jEnEj7A+pZnMswMhVEJErq*-0%$E$_Ao?yM2Bqj zJ6+d|{kqvS8-rT!OE5z0pv7r7n-~Xr`zMSaY7N~2BclVIhux)>q{4I&eMt36N!H05 zcu>Xz)NLe|yQor>p$ce1R?v7QJNtC@6w~B-ranxAn@bzO(pT(F6?NmQqFvyos;jNmz&)rEwfiM#W3!=q^#`r{hec~mmu4Lz zo3tw%jo4ef5^jkAz<6acKa&ypAp@`Vg<7*UMCiV*n=6%^toNd~w!Uy3wT)cX%kgY_ zG516#$$h2Va=qIrNUJu$kmGIABlW2(Mxq4IHLcp~Fn@Uxt@j^j-BBeWtuE7huRQjaOxngxnZ?sP8DUbVFooD2&;9 zqw`rsox*xoSxPyL$8C+nSA7hFHbdo;?44GZKKQ(G2CYXWG2b%}+>Rj_@Kt5! zdJl9r*9E-u1Xv{?JRvRIyIBF_9|Af|2Q0ozN4aX?!7n8-%WW~$O;e>|C>;&ZH8=ka zMBaP__zwnDQ}r^k48Z0qK8N-~qnf@!3)0Jy7upYA>yk86RiPSs#c8X|_ilSYTU{u< zR%7LIT|mL!plP%PeN=J4=PKy-PfWc#^5CUEB0m0fG+YDRqy!^}R(H2L(5~q-zlR0=a;{lBJx`+8|hhQ{o zjJ?MvuyW!O8YLW&o4J5i4rk;7OCa)4>pWdQOa&vu`s&HwY%j2S5+XX?M`b-F3gXu zj>tJ(eXl43T{{IQ<3@nK)0>~YKk%>CX&5()gYJ3+nz~>0TMun_CeXQBbe>Z&x>C>5 zWei~0Ubru{MXuD*kxfOm(yF@TP*wcQXMnwu#kLcW+j){MM<2z&>tqIa<2j5giv5{* z(VP+4q^&gV0cf{$xE2|O<9T8jRtD{?vln4t%}%&o{s8npMQ=xk0+z`@J%wqVDjh3z z1FF9Skw$sp1}RA>qoKyRLYt}7rPNAXTdAX{?^ZzLw#cO&O&_gQ&k5DEI8}vKqH5e_ zw7p&%33~MtXy)yBHOK=~-X%eYDTPR@(#8h$kuo1fvk=h1+AIfY_Zj*C#sfFd2)$Ju zq>*oa3aGaYx!irR98w7IRE794>0yMW1GUxWw&odwo~##DHFO0%Q;o-XN%?7XeY}bs z4=rDIxB*spUpx^;>@T7l-UeNlEpWe;1$rLxq zz34O6fcr+(t!y1=J<+#Y9YRps^8xfy4NUd;0Jo(k*A|HcsKhX4Ijtoh;M%B^v*;ok z`?R92Xc6Di3F}=R^iv3}ur?T7d~^1DCauSLmFsHwfBRCEHsxx#E5T z3g{*`$AtOtiL~}RK&x~X;n<_dxoSpy*HbN^ohI`jXe%enm$|eqZh^K+m;RNiC~elG z&8fOY%c`IbIzzpcrDd#+Yad5rr9yGkyd6Q)DUCm-4chq*dx;<6b zeY&s}8dtQ~JvPA@`-4`rzA6dQS=LQOw)pwPxtXdOb5!DLF(2?=Z%1AwAe=#&e)uQ4 z{4B?ZR7CD$PegWThJANHZj-j9{3l?X>Ce2HR2c36t<^RS059S(A5a#?wQ<{ucn{T8lYeN1iFoXlDi z+QBOb?~(57D7gEoAzbJ?A|aI-Lczsw>#2ZvLDP1Sl9SYVzfcda>H$R7o<-wnCqRQ7 zs4Y>zzNkL_UgzLacjUZ!VBo+N&{?{Zq>;vwsq_}3Jo}Os$)RAl8%u*0H6c7u`()N9 zFs$@0Yx-AO<#pCBbVn|~5n8RhfaYZ}e^L8*A$JC|R)vLJdLB2<6Ww)lXx(cKIIa9| zm$-9g(Qh~HO?9VWwBt$)6w((TdlZOls{na48IEaL^_zk4yz#jEEF&VzwT|YSL3U0++=hdW%Kls3CZtFuxA8x>6b z^}6te3Y=G3(K_P-IISD*18psl#{n^_s-6FYS~CqRzw(Wc5}^JyK?^ANzTiwNVGgZH z+M9~+qIJ6%o%cEndQHDTvh4+3R#leP`Z$jF9EHdxWocHY>5m;%P50G{$ zY98+qnWgXVr|O2WQ)x;`AGl*j1OChfc&YRE#cSkJzQC=Q5i1#{L+hm_v_co6i^`=s zA42%UEKK?9bFrn#Fn;R&dDH>a>~BEZCC3+Z#PNh?fZ+;k#-jL~Up3!ByWy@^*gxql z#mgb|(V`9_-}Ny?&aE&m>Tg*)Q`(FhEs6{khq zQMu1@eT`8o4toVvQO~Hm)niw<4mu$MRHZv-gMpSMX?ctU+*L9$R}ZRoZXEJZojUb< zi>wD3R*I)Kir)_h72c}W4d4tjW- zwX3w%$5lH&1LiA}>02D(2Cm5Em;ta=AM>mM!<4Gs*Ee^59}&*B5xLUi7(&DhEI-mE zQnvO0o)HpKwbnxR`sCHc&{G23Veljh**Mcp;Vjez#z zIpf%_z4O&@z$VOB(npl*&JkyWp6|fSfG776X_|$8ohqR=%81dqy5}vK zkL9A8Nb|aa&eU_8Q3Vlqz4EL44tvotSdP3y>xT(&Ef?Hx+QMtAP}XTFpsQB$R84`j zD$K-aEtDust9Uwslc?eE$bsd&8 zw4y#d8Ds_bT2E-rG5~6;coF=a0Zyue$V62UtLlhp{~GjRe!A?VmGZL`z+C~WtEZZ= zDINLdLnQDVjQ3iD1vI_K4TomBORGp`V(>)iR^(BPnshq5-NHb$ihIeg0B0mTwjZWC z>dk0>P2f%%k+q&`xyo4Sa1Gb;-9>Gvj?Xmp1c!}sw_8RA@*#y)4Jq{(L4HM9XY0e)>48I za0j_}Dmye?2G^hp=_2`DycZ%DbZ@*@hbhob6{RfN%=g~K=Wa^CQ%0h@X(O$J5p;R) z3+Q^C?By0AcV#&K9o21OtbUt3oi1l@^|~QSvuSq~XcwO&@^du?!nLpMRtc%N{QKAl zDxYOlzo4gTk81$5ta^vmcG~g8(&MV02a*l}}Z*n<^3=*Aeql35HW%+_-s^RslV? z&bMf-EQOWtO6Yg#OzE$w9H@0}euce#IdSdEHMlYL04X+D{-k-e;1_NLYn>O#0~q53 zIM^HAB&8qrI)q<^V}9#Rz=vSGdOv~IQssZQZ}BWws<-Mzq4m+hk|=k(J%w@F8sUka zpmX#a3Jx)V*MB0it+)D6rOl8HG;}kj4(YAiD!sxvu^7}%X=s;0v=$^|V1kMv%e0XV z(0$>;Gvvx>n~VQQ>r_reGAl7$scfW#K8$&F6Yfuy5-%Gu)lL_LQ+tVq*Fn(0rhovw zeYl}hw`mU;A5^l)RuS`!R%4~m3cvx)oD%vbaQqNj7ZxCV{TgZw8za0+OZQ_IT4#JQ zzg=Ghbky&EtlN+9mX4sKbViLoLvK};ynoQv^0X?w%}gRfXQ#k8S{snf7H+*1o>8J+ z04!D=E=6_pO)Bm7*ZFquIl3!O0}5=V%PZ+?Kck*GHuB zEHujMJLIBi0A1(dO9Q3OC$G{`h_b`_IS^UsgZTxW0B=-bsq70Qog3)mv#4!R0(nHs)>~wo9H*Qp3!vq{C*|eF$F>2YT?-F8BLpw+yLF=uIRi>SPpln zJ&cSx?ndOIk6ZG7UK(i4iX)f&6k2Mm%(2jpABMZJGmMypFyhKWJC_wS(Hq7WE#iTC z3U#y~+I)ew!3?;x9N|8%X^j{QclLh3qBIQa;tu3isp8)+0b0Ak46x%_#@2rm8VM5+ znPrX9#>#y6>eoviX{}zWj>tqM>b~B1;CB)HQ?!!x3g>7QEc<7N)}S9~tQW2D_Bgaz=~mXuaA)XlkYtbdeYMK6{6Uw# zdiu__kV{zyqtXKGjq89$%v@;I55j$=-+U>xk0I<)6=#tSrAo7Cz5N7up%GkXtJgKxRbsfNt5%w|bo8<^V31zh5fLVC+`FZbU#Ut3~Xm?eLNVj6byoA1lL~P>Ytg9@G(Ks(Vk+^7)L0w~C(S zw3upS0S#C2qIm-hG}wvSf~#2Rq^Gdr9$=U*Q#my6=PUmkdkgMrT}-O#O~~}EJlgl# zOWr9pD61i~?;&4Qg_tVyRfCcHVvh&@sv!@Fht_*DAVFJ3Hf=j$TI|o1X<2DEo6-+oTvoxoswt2o3*6uv&{9;P-`1X1Z7u8{Iv46b zMdO<%!eL1;iVmh#T_xa6N)jTp1(h5mU!1T~JU^Yktwu+KUV;|UEUEbd^k5j4k4~Uf zT?hEH^B9fXhk;(I20TP6xh}$3sQe}WB|t4Jyz=fqm&XSp64?#&sr!B17ULD=wBMSw&kU(&7-|O zAMjs{+Aw8H<30eQ)a5K~xgAx(eXPrJjDDq~T@)HMOW@@4NHkgpBT~?X){za+9?PK} zIW!H@%f=30g*n-2Pdh?*;)X)(35`sGaW)Sg5Iz zHXFc06{Y9;<%B=A0W9xHE9wQqx1IrLAW!qBhvBZu`*UwJ8t+A;)IQK1%CF{`>Fvn~ zM3VIaevis>W3>}zjmCgyTSWY{-FWK?HF*(E?$naZC-h-igjXwBoY4oy=7KS->@+%~Vp}+kw_)-R&ni(HheekU_8KZ)v+ZuWQwS zg`h#V5m|hK8Szwk_SCsJ*|ZHJF-iyR&(Y;Cea+0T2jlZ&7|-wG-!qMTuWGN^Rarb= z6||Ac6UoitZfUFWt_A(2f=gH^s7aelN_jxmT^L=p9gWL*Fc24kCl znuH^jZB~5;w}n1H>gh)7oH`$&{4YwIc@tGXmW~DWRq52VkNoQmBU<^|-o>=?>6O85 zy^6}IS3(_>qeq=Y?eznU9{-74>hHaO=!;0-J(wzY3s6=uh?+qwuWsc7G(j#r28~jp zdH5yhvpe__p@ZeaWkiM_Cy1v~Xg$`fE2BYI*9*a!I$>+Lf@VLB?wVbIQrLzS=-HsO~*f-*IjYu!W&bVV&S2Wfv3G~g`eeOYd z(tywNQEQ-$VnGs-+@SH6(1$x&4#6#(9|JFR<7=o_x)Zyh+g%?6T>ge!6Ww9Ib;Ib( zJ7|P|h4J(|US$~oqu4gU(Qk0K>w%7m#(ak|&}u1?=XGLlDh=&IW+u|TrKnxY2BVcD zpuc|cY>I9e+f|FKrVRO`UW`moRXmrzrfQpv<=Y<-`EeUl)-_-hP(`zi3WKdxO)1d? z^i&cce>}RQm8nk454TQQgp=(6!P@?>UEq0K)kXGXG34ydLt9ZE;ZJQD{@bHC>7(1? z>76jr^0df;|K|8!1v~+Rgwl<`-R#&p!`u*QJo}edV z(0F4+I8K2bDG!$KWH7gsna@+XsD~M}R1rY&o@^cL7vWT6RUblygpuR##$uRXP7w zozAvl7`Udd4oa^DtWw3{!wov>t98CwFIh`zD;+cfjfXYRc$Ppbw>A`;{4h#%K_hEU z(49>{U3EvidjJFDcS1YXlh#U=(C6u*leGZc?uwt!Sr`pl(Z}R%xMtL@mtE)OG;QHa z)zL|9pk+?r^EG{4c_+Pbx!(TQ_761n3_4SWkjbFBjUP{+>XGguB&^1fJk(|T3a zvS{TUn+kZOUk%7Bqs8?K$5Gqs}tJ_h4~Uhrhr2X!w7!YHVDT6`s-O#mW4Twy%a z?)^YpX(@YJPBm%O)n_D=H8+;4U{F$f;w+_?n|9!H4Sz)5{Dd)TJharmi}S~Mdb1e^ zI!l+}Lkoy~TK&@LlqCAtFIr)}SYM@YtPi{b>*R`N=5lns6 zKJ-SXZeHbAt@NfVNHrcCB^?9p0lV5EcTkgc%2oPUqvWLACXDW_jzceUfx28l?Nx8& zlCRRT-Hh<1S}Ghko1@y|mDia_i9U|*T;QcVItqY?;ZBzsOz8PA9 zt5{i}BXv&^)XpD8V|-`qjT-=CbQ);6c7hgHHd6HwYS(q`tNRXGVO4B4>TQ~*nYSt8j&Lz0$lPou#WR(pA}4`Hr+ocg1pMo!udNS6RXa-H|#qBJ^cpQQeB# z&1Nve*5Yn4-I(uHgkWgXo*%3j4(6%^D{kqfK#3fHnRn5xJ&4v1U6S@MMDA05Iyb7s z`k@!JX*w5LDRdhjX!a-5aC3H4jQ_ z+FnsknEDR9X9eWm1*7ZO7h3yaaMvt=c2!$OjYlwMUx9W_SBe`I=sZ%_g8AAQhx*Ve zP>EKU*2nZ8h@3A0?b9@9rIZpM{YmG`bof8hY1Kgoi%GGXr^@?OowX6up(PA}7OLxE z&H~Vue`joVN-qc6V!5sErkzvYO(+xWsvs_Or`3BPjQN*oJzqoXTt$G_9Jtwas8=sX zYs_sx_i-@ZNMqIz%zsnqbb&siygm`G+bKYv!GHyNPqO1WVM@_S7kvwjiYh4w>ts5w zve!G^LuafcBo$f_rgrJDyv+x&MCtStZHEJuz2;F0;dK(4`v|NYR#oj!4Z4l0&M_(# z7t|p)S5M2)k1kz1(~(QOm1n^D~Z=-2uSCB^$9}DOajg|f?HW(DYc-^O8+0go^ahUvI z^qq`cxe-_nQw(}};>P}#sLfSol-P)V^IgUA&1dL#)Gw9n)NL_*3UdC1>37$DS`{Tc zdl;58sXVb-iE9Q`l#=vSoqu{-mGmybw=L+N=CtN1Q=NGM;U&v4e_4L&mXrGE=5qgRKVgbE<--_Hwjr>X>XtkUGDefAZzT;W` z8j*auoW-e>m}Us$=&kroQRe2Ytm;=s3{JTm{L6X=;OmISfnv}yY4@Id5iocN2Aq>=#c5cD z^#uD5M{dg#y8NtbP%D*f((0*y?SdL2-w;mw4}22^g0rrMB_%79%GV9qIplE z8@&uq-|9-%N!Os)x=n1#0Gg<80xzFH?x7yp)n%Yw6VV;r5L$VibZJVWv3G*{ZHblP zD)cOD4CB}$Ga~|^71X<#APP`D4lBObmHU=LBvmU zsE8iQk(1C$6$9i`^1j9i%TEf!$gTH1wmPlqs*W^sJR(b6Xl>9Zuc3O0`A#Lmy(!2A zs$Ms%CYD>d0F3Kk?08Nq_3xT4R82bZ0lH`O@-+3`$z*Ny2QNT7+8x);y3hV^p#7;pviAGL1`+6s88%yLKLKC(5m z{w)CE%>YGo*UhQzdWK4HEwp`I(;saqrz5q74nqgkpx*!T_RYv>b-(VG#;tH)SJ zIn9g$7zo!F0iTtKj8QeELmG5TDpxtJ%1$-idPnG)2exDg-|NvT=S(ZD2Dqg#V1>S& zuC@~0$GYn-)_fjX6Dva`Y}HUcYeY}A>DOyQ>!q%=QQE2d>RnsLCD@yxRL$oK_L^&L zmD4f%Rj%#%hDLziJAYDjbyaS_(PMNpO}RkMObC}%vA;}i+!z&y+OwNjnWNB zmszwj>aA}@<-mcuyX=1k_;V41+3QV5U)lolDltsA8d{K2y2aCIWm|%7t3rU5nk8=v z;lVU*n~n8>;|LuwM|C`TYtI?k1(B1v0fuInAE;dUm$ri5qiGG&g6LZw&`3E**|BI$ z(Y30&YHnFxAa}AMmN%@x=gNDbeKR1}`5x8&}L{`|Dj`I)Hcv^id99` zf&1wMi`SEmUW5k=bk|)R48vOAOAW{gx2m|Ue*oeVV9fOcRMqFLYx~oxta{j?3UJG= z#(=HT6n}j_+H5(DugdyD^oAqXBZSkP2K_@H>6|$PD58uftCADnsf=TEC#>|$ihrqp zS8ah-@@!oTdg|S58qJNLscT<5>vnzDl19_4Lt32d)&TP>8qi9o)TQZg7^&YiXR1dZ zg|)VtY8&a4m)5}i2v2-PzqR!mD|jrlOV6Rre24D+^q_&tEh_6wZl+(-8*D_ln=U5y zb#VNhK9?w_GtWtf&1S8mb23#`!3nX#jiK7+#t($Mpc%mSIl^OgI!B*HuD2>SW%S5q ztwML<8$^1mP+LpsV4M@Qn$EO*ThL0~i&M5UeX^VaU2q*Mfx5Y-S7B?UF6oK75ma%2 zYp-XNM!|WjR5I!r41e9}9_TQP9LP9Y>#AQ~XHea1ED^9o zz!CvV1S}D-M8FaOO9U(tutdNT0ZRld5wJwS5&=sDED^9oz!CvV1S}D-M8FaOO9U(t zutdNT0ZRld5wJwS5&=sDED^9oz!CvV1S}D-M8FaOO9U(tutdNT0ZRld5wJwS5&=sD zED^9oz!CvV1S}D-M8FaOO9U(tutdNT0ZRld5wJwS5&=sDED^9oz!CvV1S}D-M8FaO zO9U(tutdNT0ZRld5wJwS5&=sDED^9oz!CvV1S}D-M8FaOO9U(tutdNT0ZRld5wJwS z5&=sDED^9oz!HJ~Uq!$a`l2NNdmV!zsnWcZ6jManf!Ul5rqH7$<9-jr6q&i{a{i|_ z%luPPM3H<_qeiKs{j&cz(KE;n7Ad9JsdvtQ{aRjKV3 zMO~pUIF<=|+L@4iBGc|)mfL`l7qjyik~TYLGE4_~7=;A>BnmIzoPV2OYw0+t9^B4CMtB?6WRSR!DFfF%N!2v{OuiGU>n zmIzoPV2OYw0+t9^B4CMtB?6WRSR!DFfF%N!2v{OuiGU>nmIzoPV2OYw0+t9^B4CMt zB?6WRSR!DFfF%N!2v{OuiGU>nmIzoPV2OYw0{^E(z!cHGsI4g?u&9G6Vsud_A6m{H z<~DYo<^+?uqR|{@9%1Waers;y;9)-EWxqM5L8MLA$``#pzwt3Ac!r$}G@4Hvt#7y` z4z28AKHp=yF*MmKxTMj1(zwTpzhn}6KfUqNJ+H1OO|f6C?RRCbXus=-u~JO9O-18` zgrJL_E;pWAdzx<;$9+dQWT@x#l=!flBPy8VLzAq6OPRVRm``BB6#LEExL5X!m+pJm z@3N_6wBL2YSm|WAT_w*6u|XHDZ+cqa{L9FY112-WF-DBBHJKTbF`}b`$;>D{BRbmo zz;gcU&#C-xd4#F)^DrB2%}wbgx7o|i`jls6Yb&=?p7!;w8_kzOpIHT$_UU@We2Rg1 z#eT6i?)yEE2cGu3?3@_LNn@o`#&A0)&k3i3E~I)&*#9RVO%aaqM%xtr#T)Guvv{Ke zKMa4%n~iqHec;ZqN!Ff~V?68+o-o=Uyy#<2G)8)TFou4$8*6POsNd|y*my+N`(QLT zxAlq49Cn7k6?5r}%LSu#0&K5K-(nxw8C|lEt8ccMkrHElVFg!12GM`FvEuufD<7qINznH>e0<(x4Z@7IM zIb`rBRr?VSvGPTa2;WXd^Ral(ZulGW`F-V!J`ujXJj^i>p0?0IT7Q1;85R@oX~LO; zUgo!u{Omn$_(bNoI5LyL6GCMEJ-<>?STT|HQ^I2GCp=J)%sZ1(V---+WImWclR$Zx zzxYJ_;Tqv-*P}-d`+^govLMXIjFBcQW6D`mWb^A`F-Cij6CU;+Nk;2)#3#@VpB;Q6 zx;xoBcrwNyXOD=WlJ<_)5x!;Y9ekbfrouZ|73>|o5%W%ZXYW`aYF3|!c08N6$LoLL zf%&>8CI0-C;$ik=s^rLn-=@$wKO9f_iQ{|ahF9ooEBmm44ANx&gFo$)3`S|v>!6j zSmUhxR{S+6cl%uviiQwYPLXhupa!RVR zNkzUh*Z1hJb7Af3!JLL|Hc304V^6*$_0OJ?^4@6gkm`h2WGh=Q^HdGX!+h4meEhw= zBleSqzy6it)is^A_+BP+zoNmW*n4(f5fg0@^fDjkFKf9QI|g+8A0qp&JMaG*&eN?p zjOYCKW9NCBWB;i~_vSn^XOlV6WIn<`yR(e#{bSf$ND?xcB2BjTj%kvnq*K(>_R<=U zur`_FaNW7xKUw*QZ-}i6`seObnA zNt^0_>;D)2|BJnr|Iyy)-}aJH7tsGhJoGo%SR>5Iv@wC143%#x?;_w|we)JVaTr!s z*_f;OJzKno7D*FZwk~#avlY8n3ZXvkXL1X081h(Yj;r`ebFd(zBxE^Ep~(*8YG`i@ z%8>fk+T!HiKmLr|KOWA1X#G9jHhN5TaZqlB-3%O{HI36{U06t|9-1Pn+NbhI7j^%~ zd1MM5<$%+p{7ey*1G9vTayA6v-|3{6MHO=IH>L=ezkExZLQw?ENLFbT!$|lyq79NMt)F69-ffAybgB9q=C~E4CT6 z7mJ%w|CRu+@h^B&tskPo{*&y>{`22FLOykU{lzc)ANY>{q@VfU_^D~rf6JP-q;5k5 z#oRQXkNK_H2%3tYq*C zjj>JoT!WByJ#Ei(j?C@_pWW?(EeC{2$Fa`^r{p~JNl(rkmL)6Sj1LQ8*Hr!!v1C52 z_^`!5{)OOu6hHZ)ZJr;g$3jF0C-MO2q(Lt96VZW57ny)p5glB?+#@=elKK`)N%1oK zbI!EvWHPhYrbof=_h=$Kdzr&hqd{)t#p;Og>}QJf#H4R)EZs}($a7HA@G3gvJpFiJ zroovE;Y&1i$cZ|cBEnLIBGWp5M8q-776y^|tr@2LMJdxD1{chD!%9leG17@2N!vas zO?n?W)athn9&Y#SLz{4Dn9QCf&9*$Bd}dEqvb?aGA`+gYGI>&;Q&_3rQcmQY_7m>N zOLI%7-;e6=$K-Zyn8WY(g=Fg!5vh;ycRvwnv>i_J{5J*riL)?ewkgUA!DD8>*_!2S zKVb&l#asW*e&ZZcNn;@SL<}V&bGD#FRDI0v6+vHfLqZ)U;$JZiJCWK}m?Of-pc#rH z9JxnL^J#<=X!%5h#qc9({%5VlOULUwYskS#Q{Hn9GRI7jf6ZY}clzvvF+EAM{eR6p zX53$MFLmOLsh&FVD&PE{r=Dhr*)uhUN90Rn+BY1!5gjMBs znqzq`9bJwG*5|*{{Flz{cwpJ*L(xjwPZk*#6ODYkr_Ja8i@k4wkD|K%-_34FfWU+b8Wm+LQG!8@ z25WFtcE~Qwz%0ZEC5k9EZ3-&Z+N!Os{Mvu3tya-$1S+zdKoZ`0 zC=ia<@<@q3KZub7TugP7~>KP^b79|6$_vEB|X zTcR8CZ$c-~?qSRZZ?)uG(}F57h-;c~@eC?lLo3AOO$x6f{UX$W*(@0ud~I=_^DxbA z#57?P9my>r(-JQni(--&4#&vR&_8^DC?>vVf!Z!ah3(Wf5!+e@lJv@K%04J-0@2$> zQWlarY_$LPa8@ADjz8HuAVT!Ju~u6v&7OX%L6l-GZ_|Y|TD^of879S7pibVO&h@k?QGNI3E)_USEbqfOpGYBh+niv{suvS70N; zjn#XeKI{n1y2=>rzd8rK(E}GyS7Oso3DYorq{R=Vra&gE=GF?cr_XBoJbm94Mupu| zFVXV*UX3k(No$4G+h1SQYIKyBU!6u(UJ~wOH&wR78=wFBg8&VuBr%x89=({N=pm91hUu&LDV^(|cvAg)fSP+gx}EAj@<6BlAL!e;|3zm~{}Y|-Uv^Uc-~O8Q zyRqB3Igp4z2AcGwrWoL2@5rnf64OQ*f+Y5tWZ5YUahRm^-6V&2o71D8g(39-(eWP8 zzo%SYo1G+IQ^2kQ-A1Hrw@;3t7k!`35ZR$@ZA5Q{eUe}1TYo}aZNWtHZ81~(BC8OE zmn!V*7bdgyPl-p4K}fVq^i{+KKNK}_v@5gqDJQ-m)wg%Fr6SPQOVqxbtmHMx3@v{@ z)d>+?qCT4lGkg?r*eeMw%GK4tSRwhy2eRO(mROB`z8P8YK6fSGM)Ka1j_ixPI|f=% z(X3M;MGiE9TdGl5o8E{8oasl23|Gkq!m`JJ&WN+l70Ta8twj?G9)N0;)Euf-ipswN zO}$*#?Q*gvq&mbS?>dQKaI%(&d<<;<2oyKrO3TUQw6_Y{6F@QwgbRKou$m)va$c20 zlG*glV)|A{WLqJsb+T%4)huLi6n>O2Rwy5lEV8Pn#D@L8y$LegXsHl=ADXEU+b-ob z%9eNZ-(fL8B*9&l;L-IpMIfS5t{}lzoTHRHfN^lX*@;t)5+qTRy}L z<26pRjtsOVi=iqxuSWFI9I5l|u|NwDCt2=Dl^`{=NS2L?r6ONctul(FA$xwd>J$^R zQP$VyK$=5XO7cmXMLBrPaAJj}s%BU5E{Ftum_yV6c1bIr?|f>7_yn{&Q=P)nKk~8* zQnM8HLMqXfO6_f}?Pa@`r zwN@{U>yBSn*t@rrm{DS)jdoeKlenv2Vu8EW**4(BKi@#o=j+_+!@4UIJsTja*^MmD zr9NCM+N*?;u{>*Dic9;UMON=ml+}lmS+$xH=UV>eL*q><>xEjqm+%_A=PRn637TkDd$Dm=b*zK3^t?>?P8n{nUC$xhNo0?k?(DE4d!85 zrxH){7H~sa=#JEkU=A1(WDR-8VcMn|EXihUqiMnK7*+4w->K?>T~#eXN@~*wgO1`K zC=~C6&Vpn%T#z|kVc$77Zoavh9!Awr z5OOS?*@_vXEwZu+V9vc)sIwFG8VHF2>jYMg+_q*Qjs>1f-l& zi&mIlhT*h?y!}`h;Qx;ev$5*YRtk+e0mh6YGJ|1c=znj}?f1BB8l^`n@5oArs1fploK{UL__ zB!a3e#qlTfqT4KQ(#x0f{TzOwvZdQu*0%vdcZq~mU;E40-dmDm6` zJE5c>lLH}0U?AE~r_C--`UjCi_%~XzR|>^{#c(RxbPSN3ETwORDjb>Xq`FUt_dp4I z&0L7q2ltWf@5;iMcd5%*Rt@xpR!*+B5Y01hqIT0tk-1HxDkzZ6Ner5;8n?a0+eb;S z(BHc@6bcS;vnqP1#e=L(0!kg1=uWSa*>-&mlFAge$<5YDAX!lNcC2QZah|RncTKI- zdjTq)!FbxwAoPBP&xfwG`SWjeQLk^53A=s!?#{=Hle45U_I;Y;hSt*nb_`G(ge9M% zQWBkGAN~p8eytQZ0jLsyg|7hcZUA_WQR4sfo=zMPvyO|7x<8-aDkwMqXDCEg*Y% z=rBs4sr6wQkx{`Qy@gSc*wd+n)HmO{96l;gLpF~9Td2=M*3%w_ZVM8;!Af9~#{eDD zUU1h(<(0-P4vm)WwZf87*uNBZU!s!!Z8`A8$-tJG-*>2k2$D z1&5MQ>jIKrZKFJ_kw$F>uPc~Dx)fB(*Uxw@>5pz!?M`1eQL~m%gAkR?hBBZX{-l<8 z_G-W%B1aOPUn`MFIlWHu?frsG3aDey8&nKanAj$#*I--2uGKbV?kE}iTHE_PcZW&!Eo~DD&7mN_qf5__08k zyE~PgksqXaYL3F{OU02~#&IhQgG8{MA~f+bv`qD$3*C9B42+O|DX;H#=nFRKj?2EP zZu;&RdXe;t@zc7}?~V8bW2?od;bjl>i!a}aY*BqC*DoHpn@V=2UqrP(55FY+jdr}# zc<}wlVBod*A5zX(dCEP=-cdSs2#Vh@mhORc4Dt@(NBzQnp^(p?0P;A2m~0Ejg~qIq z7-YSYO;U3pOOSwhU^X)Y3r}KqITW^0O1}%DfgB-TZdQSI94NbHwg=%DrA4XqJwm!_ZBTtro89oG7MoQjcCpJoI##ORkSay_l z3ibb`=2AlD2bmib^^H^q9%!S4-=>8>F)dO}K(~^zZETtqU-~3(5lna^Ys6L|EE|FZ zCv@#uPR$hpfdtvWg4EP@eWlFIZ0i^{aJd{>#|_-pOAR_KpdcivPOlxhv2ek*UXVIk zw|Rze`TnS6&+Jej({JA*j0qGjsO|*;0$x{pKT?yc9KForRp(m{IaJ}cZ(s073G6PH zadSXZ%W3!mSNb*=?CKiy!hI(~*t3}Ou0v!yz-W&hN&Kk3yBc2@s+8@!7wo0Jj|e`5 zmr^`89K)T%%3Be&B8Ux40X(eIs=`zrK)KMpxg%X(o_^Xv*F|qd6hX7{#J>G}pl?oXaip zU)mP8hjU`Fq{I@DMW34Rog~|$?;WFA*As>!$Pt(2yAuGZg$JtJzl1{mHU z<-NhDjHpctu|Qp0-x?M`jmE`lToR2-a$nexO-h8&COb#}6Pfm4W1%faVbw%T0qB5* zG4m8{9th^%upJ^X&cH*M-(;6mfZURH2M7`4yNIx;1!;#p&6T+e2CkzXA)qfB2eUtg z@|Bg;&riT=u++~3^`D((sb?F-P-W2`(r>#|s~G~eI4u9ZHDlDJNrm`A87tal|2&s5G z29pWEJQ;}hFY9T`sFv(sE?9%*lz~zyRmN+WZ)})91Xe!Mkw!9x!?jil=<$Gf3CR+q z^x9xwO6F+;f3|W6C4&0RkcQTfO%x^;k-3r9AO|7P+Kg?3peN~wlU=IkB0ww-MusD4@yh_4zH_tDp*Mi!VEm)aQ;mqI~ zQ}7XbZ+=%P6|JMqqXWx!J6M>1={EKsQ#sLhFfoNRD^_Vz^l2FeN6rJQc}N((AhiJ0 zvWw~1UQ+Z4Iw{2;Pi^DFr_gUAc5$U5Sm zM9X^6UUhAu8dg(xv~Pgbfd4lxR^yV0OH1HHa^DuNP0{W#8`=^u>NWc2k7*BRGb|6e z5``zfhGghX_$D_-OX3ak(o$ZXbYw4dEj-&YWW#<-(-kbPoVOnI*`mRO+gs2>wy_L* z)@GOL+-wDYhah6XK{4yQBSDy_{v1I&wfIZ&E;6mAuYjZ{0RH!P^kGC0qQ(q;D48rQ zO{MARg6T7A)$w{I*JiW{QwWC<)I|2q$^=}U>f=0bdceg#6Im(kiOAA~S2Q3c8-!(t zQI#+pR1?yi!f+UN<~xO1@mEaj3q1qb!$I9b+}C5f=(~g|8-(&i(lsC%mqUaBs0;bR z_ge6GNdF=7!G4g|aSpmjc9=OtOPNJh&+CJ3#jQDL+YW>(>h)A}Yol1|2$5pt1AGs4 z-^D5p3$uP;DkXK+#e;5r3r}~a=Hv^z_T>w+*5!-B=l*=5pk{KuaH0k`{=XVGi#ABY zOEs8La^Qf?nR&=Lw3SoG#Nrb2X~NabHY+3rCIwb8S9C#5a}lb23)ZBwzIPNlCv!iG-B@mn#ZGVQgrSwhnt|>#`t;11GWxn94$QO3h6detL zb`**~MsK8$pKZk^M`e+Hem!QEMNL|g?@|Yk1J(mBO9XP`q~9Hw6eRY|0$80OTxb$R zW&qdRtd}f}PStqfw1e^%mX0=dL;7&1kcPn((u|=N(y-=atU2Nyh?FHUa+=IOSG21> z`K=A$(s4=zd_ozZaXzrfmWEG!d(BvB7x_Lj!(Ld_tmnD&tV^XQMP@A)E&iK{eP5V^ zR}f3Mm{T*k(w!xy=0{LDK)c8+YXirL!t2&?oWMOSEJ^}3krc=m?%S3xe72Pjp(t$c zJw|w4xzn1j_Gt$17jg+}YWbN8IzZ72deeW>`IQ}Xu7Vx|{BfHMG8!G(C^Z~|T|drM zxY9R@fju}>gD#*SzcRTj0Xfev`YNH(YLrP2bpZDBLpV$!J16nnMc8);`+W;n>Z7D5 z@|4ZGiBbYVD+xiLPHn^&0VmJ~){YaV{pV27-z@6k@_>_6`#W)x1LUL(6ah(@Av?PL zB-s(kjYxhJD?7@d-Rli2CwO0yREVy@n}YC71UdG)VFaLNC&vi1_3hg`i737jARNCL zRtWsijqlS8n5AROKIR6A2O`FXuG7Y915=@YyocsiUugY_#vSrL4jZl z`r9FN6_OLU6+BI4=*?Q^r%SM6GwOw&Zt%7A@#s|LN#toua3JYi!UBXy(#BiymhZ(bziVin*tbGqRcagrYS@pe zTN^K~hhkhGNXLv|D}8aaPPYC??a*G~n#I0VDvbZp6B^!JGN-~Pldv#@7H+pD$zM6% zXZq4H**K z^`U4?GL+jdlgW}c=(vrHPD$InKBWt$isZK-kG^XAyEyALmVd!elIE|TMQ|gBq*3xjnc|R zO$qcLVwc9bmt$XFWD|y%q?wx%NerhAy2^HGNM{iA;Ipb(dPwx#}npk2sU=;cn=@Krhr&FumYr`wg9MuKwDG*?3T)2Yw#GJcXB z`*BN)5o|G)B%EGQdN+8?m@25~J-z7V(o`Z&xy+d|r*9!Xp^$D-ekHD@M&*)f(fBifPk4PqO;^K2<8+!N%P} zzxj16{(tTKT6^r@e|~{}bF(@!P$~X9tq%J}!{Ex;Y0B(Hv|twul#2KcBf}WSzR}wZ z{33xV0NSDn8gqVCW;@-iQ7+PH|B*u*P_YN9^)JLxg?#0|?`D-UJXU!76DD_1JD7k{ttTa{gqHXcKm+G zHO|8KWB9;2JU~WFkRO13;AUeE*aAcHN(4qB9~B_3Fd2dg^4R$p48^`dc&s08NQg#5 zN2Cw%UQn^OdajV!2`(QdhXZVjelJLUsc1dNY(>@lVn5-9Vs^Wt{izM6;-on&#fZw< zGX7S3lP>vX%*U~a_A)(=TEgehZKzbAO2cndCEG*Z+a&vYo{OdQ!=Uy-BsS=F{=U*^ z>OC(wbKW~{8u$QBEZEs{Dv65@s6_Af60jr$Q^>Xk3sJWR_2DD7>N-KZsESwF-tt~< zc(zsFh_}I~Bzv9k*fks~FND1`d8h0Rw1*BklD`MF%7Kw4__~&&gQC{-sxM4p2_OeIKQSGuaOcB@YvI5vd$Dms|A! za=`Y&GZ>>$CK){@fdmFd|C8~~t4r){8uDM^xj7$I)A}d+n(#L_!N5JYlR&O8#)j+- z^F@EOH56*jM3Iwl<^P5R+Ahz*dOJua0jFATDKIVW@p=oAp-KC!KWV*f;_tuCdV8w9 zMAz$W9?#I-db2M^ZM^=9VHp5A&}U*F|=dlAV!T5lyr#+dasn^L}Vz1@l& z-L1Fljd#)Yb~&EE=6d@nPVxWmUT-N}U)?Sw>!`VQ0I|4)S<7Iv4MT;7Ym2C=jV3q(~yy6 ze<88s;nJguQ>mQ=?~{%Kt#8wBq`C}jMZGKe9yV&39WXpiT~E6<49^NthRmj(#FcpP z<+#f1Z72aiX>HN3?vF>`7XSvG2$I+lH@Uz#5yOAVzV%It_9nq(r48RBvxACVmjz|L zGP8vsqonI@%MtbnN8{kav{jTk%7BLmG@#?u20F@V1Ax{07NN@+_;6eMAv}*kI7Ghb zh<9)B7QzT|{3YKfP}ciP)Z)23EdNCV1dR8gX^*b|Xj4Glt+MY+oA8(c4`6KSF%6KM zZqP5VgT8^x|9_7PWTR!gCvxHq4m5F<17A%bBv1lf%QOE;9|&nq8V(c4mLo(Kal};z zS=QP@%5DF6(b#bRD4)W%fn^Qn<7n~E$SPSv;g|dkD#N!DJ)jydQOjb83!hFcLvv7I z(mejpQ(zLl{HE6LUm?+k(BNyV->S_$T))3V##5}{pHf|sxqh1KcX!`&uzr0ct3Ac~ zy_e_dX8n%gFTZmA4v8&)I_q~gTyvc1`h}dZr|TD4yI;S?%m0@38(}S>m@4`-2LfA} z1mB;4yL98oAZfgtd(jR?GHnv)LK}d@s^&u+{{x*@gbfX+ybQogKW}&NDmSA`M4J-`b#1x+N-#MSFtoT z0|3>7q)s<#xtiDVI8UdFF6~&+8s4eh#JFd7QJVv1uKMrVYilC=dhPL4N~hXt>AAgI zYozqgrIit}w{+w{Cjs-!&j>-vmR2%g0RG|wi(%vgt391+%#r(T5XM3vyHEVrI`lh3 zrjb*XFinRXiR*r*(~%N7%}W9lh*f5|8Hl-^Zu@3II}F@UqLv(aCf~xitq3u<1&X== z1|wvj=T83+C%jVJ_78D9p2!nHStrfp(ljN#Nwypa3q;x}DNb1}97TlCxGEY5gJA-Z z0!nJP=kD+nNayduJ8)Ryup1QAO?a>O=P#qFza<)VXjp#3>974{9~~az_68uoLFX}@ z-S$s~r6Q*(ae$1DFWa~U8n@O^V6rj85Wk>5S4io{W9Uan1%^-$mhuL|D|I*c6Cv%1O@kWjGt>ab{l*oiRKRzd$kf%aKcRL7yP=e~*Ur6~ zRBzxF9i}M17}dA0Nrk?B?DOauFzn!nzFoyZXf=V`QjubvcS}<5g%X|~jW;~8Q$MqBL`@0-avPp*z_8a~4pt9}|ijd0H;|P>>wnZwwp=UQ@pk!w3AE zifY>V=l3B;>6U*U3n^uofBu~K=VwSNY9H5`f8MHJf{dL0KHSbfQ#%I#3}m}iKjueW z5rNkUgMX$2X%ZnX19K6}MFdC=zrK)~OV^@x^xeQ($Q0Z|dSFVX645u^0q-=@&nCQA z!~5dbgZK8eJ%sn)knt4oew6C^_lLI+{@N3UMlA+##sts9J3U|1{!HtYR4azR4DQPc zCNzhjC-8im>|w&hTSV;6sn^AC5?Fzqja6tEI)?X*Q_K;*KXhu3n}T7VP-R zOw?cf_Xgt-x6klb56k6l{MFw?xx)VHk?WlKtDnj_8~Cfg@3$Dnp8KmmNQkgIfAzi= zdO4`=ND2(q;IIDp!LN&^Pq9kBxz}fNy}k<=o|X6#JDvi(d%9j52``_6_4??Ak@cDa zGmd}r^*SH3KOA48J|((d@5R}qZr1Ayl*?GJqmb*It=H#ix25*?78WuL?)eMimG5lAywcwTud`X-_WN&Sjx}EcHGB+4 zh|Ul2gGHZ`q#%5x0ydb?i*WJ(bsyp@Au5gG*B*qRs4ITW&4#(ZRj`p{&-FG~HWF>=VI9Rby%H&>)e{3q z4(>*cWN|Rd+{1N*DL~`q8(@ zP>;HRE>YJ=NRAGZwQKaV&YIl&Ys2&TvkK3fnL&mKH)Jg4xCT`xFi$K^R) z$X903!QitYU*YW;qG|529|B&_r8rpmHYN_av zwGP)taHABYr27x&M(|Wd6i@BI8-3(r^nmcx8p@|ha9_BmiSUey^Wd7bfABIwSLYGB z>P=Z$jbwo)u`Y=4W^jyTy&C#iNxguM4Uk7cO-yUIZ{@+T9Jz?VhDcmu3J=jXK+K|u zY}9vOAQ$56Qv8+S?@9bE$KP}KTYV3wbyuk1k=JN&o>&+j96A#eB_h}+aw!WBlK_8u z5a-kPd(J0?`Ao`e%EmMIEZB zdFW`Kp*EqgQ$enBhh%h<{-O`{srPWOgY>|t)6r#s9k5@3GvNew3O{&vrM??X%4U7? zpXv81Xs6By%-t5o%uk~+z!Z*8>wRwGk!6y&1cyX>f+S-5_gvz+>EACg=})JBY3Hba zhq>sXXYh;o+vM@wsuRG3!GTwr z{XPDxGw*LKKHdq>Y)sA~{V)t!Z?ouBH6ZNnIf7rj^ z4GlHjjGEFq)s)gjO>^_8mRF2gQc!~pe`#<=(n($2?uxgoN-m{J9^{qSQ64+-!^ttE zg#Oge&+^7e@H13l&3j3==$=gWrp;-WdW8jU}_fdkB zr%TL?n16EKP0vZ%6huO4DXvhs!EBqGB{dUx(2|Q;pOYBKGy(-bn`_x2 zvN#eo=mTii0d}8Gqc(%al^nm|Z2PGh+io%T*Ly+ZokIG}*h2#ta}ZR*aLgn`br;_x zhiz;lLUA{o5T?MaZET|W#-~@p2w=^XSnh}v3260l=e5a!kFAO&3!X8LL$*?gouJGY zvLP-F8=H)=|Km}?cLA3Oj77{+n0hODCWQF0>c?L_5z@wmssWNuue|avaQ?{Z@Q^yG z{HJT{KJo3D?AtpT&uI(R59?>yfV&YX!ykI0Zyl@f?ad76alWR^z}~pN6;4)jc?((< zeR~A>(@J#qt-%FBZC39|d?-F2pK7D~-p2i9bl=CgPo?|5#{Cs^pJd#p(S1MT{z|&< zZ`_Zdd%?H|IX*UpJD-=U*MmV0jY<)g4THD}zSO=?hK*xwY>ULQ;Nf!cHHXItv+lm8 z#l`lyhVB*{J`iVCHm|+KBo=)@;1UC$Cct+aoUhHO$`{^VhkJO8o4pf0?7qa!tU5fr zW5ok*X2Ct%?8Z1eAj}P1962qu+^Y+sd)Lwsu{84J>q5{VNZ9~o*;36TOpX_E!1YQg zFUN}b@;8b@w~F>n-iy#z=Z)}*=Rw;$YQ&)%L>zxCCV4}qUqk?L?#~!LfMaU%mV?2k zgORInbQ8||lGR*5v!rf?7R$OJKsaxceFa#RR& zUzV&FFQ?7#b{h!=9Zc5~iDbl9YEN5uy_!buSz)Y0GY}Lhn~;SE5^(Vc2Og+4ddQYk z@TA!}Dp(Y9gZdFE%30WBh;LoNz4x4nvpYxZzF71rxm=bsh`D&I-9yn>yVEIM{T=xW zR)6(p8{fyV(rQ>D0Z?nl;&a|%d|)}%8VV<#!4tToyXceUuL~zHZhqc zi2SGz2Xs#Vw zt)e~%SZU-N*r`4Urz{UTaFz6tFX9XV`!1-7$_WsF#|l3KD7PaWdswo$nO znvRS9Q?S{rgqjz%h49V!xzpYz_^t#l(e8~qDR%C+2**%Z(Uw1OxR;nY(s3EFbB|K9 zJa#VC7XiC{8^zA0FEwK48t>>=jf17K5j(eI0pStydB&{K*ts@l#LiuS<~qgBok=~Q z*trxjm&O**B|x79-dM0Q1j=<4&}it*|A>P1m7{&o{{{o37O>^=I|NSn>qY=oA__Sa zg#i*b(r;XFBJ>a1rD;|ntS)^g>UN+n#vF@>N|ELPGh*Y02kNbP(Bi2N zg4B!#$Ne>ZvOAH-#JwxM+A|t|>GlCXkjzW8%jD=|m(ZuA*H(PXr4FiJKeoaqnpB1KZLV z`%;9)mDF35Q9n-h^mk_c*hb;Xx9YcWb^XK^Mg2~Z5lTH?UrCi$7-gA5?`Fh02O^X~A$+g}$S{0Q^^H1I*w)Bh>>U?(VwFjy-Ncg6=$7@Yzi zTsh|y_~64sUEzau51kf1_%*Qi*}w-AJJr((AN>B2)5Zs%LwO#Kkq&$?!`_Y$zW-T| z@WIufG@#_^fDaz{8Ew+B_}~Imc1nD(?|*uX59Al9Rp0~XPpGL=;e(}g3Q8Mf-r9~2 z%t-pL+P}~C$DS2@aKm5D1Rsq0>@4Dgi?Qc-hYto~lAkF)u;KJ*c;gy=useLP?d#%$ zyD|jt_FLZ^s9oPkV$9E(N9086VsYCafbq7>3GDi4Phe&*&k4 zFbc|Gjt@rOPfeW)A1vUu6@v~{x8s9DP?enRE%LvrK9Z*y=NI{*Mg0xf0(FcC_&!;V zMyx8J&;M#sf9Lv=_H?d~TcVzJeRrQ!-{>>y-wVZV^36xw1TFqDofff~Yx_KX3+LNR-gx~|G7-??FTEB!hiY-OR-17!oNdC5 z)q9@)I_PLJLE@vvr@-nQ5(V7)%g*ViTs!UaBhsH&KJKDF%bwuN65ZT{o7d?Efrwpe z=?2<(7sOz$S-8Sg723tk4n65kAmq@Zn|&ek+$y<$Y$Lf^iVs=

SB<)UkTcBZa5^0~LVZcWExy2YVB*Z(ccMqyOO^T1@d0eS`AE^VVy9E->u6*Wp= zw=3~R*`O{QxM@k4k1hQNkK=w62ndwiiEM~>wHq%DuL6k-A z5g3|CVHS>&$QDiWq^EY*q_=`i0y@yDHl z^`q|wdP!&o2imnhTYk9TGA*1>Bn_K~f&7JsQ}D~8$j!YvqOvuKp{C%67VVm`nL(`H)l zoC()&q7AnA`A{kC+9f7LQ0fx37SNS8r7M2pK}+~RrS@h} zC-$;V^rub;Rc26t+L7;lV~HL->C-W8?Iy1SXa32>EdU7JC58n6_*;(N*i?nVQ|`j} zR3;Ic$byrI9m5UZLFb_{j4_Ha93o((!Hq&Jjlc?GU7}R`!^)x-fGp{zSJ>OYBOi62 zSNgNk_sAK($v(0X;Ig&&Y^D~>C(T5C=^}v-)YlbwHo$QV5gXkPz2=BB4pRu`QDutv z(i9Kk;xj4gWV0`(j@Yo#emQ2_wF^P%(Bp19XsulMJ?0rFmV&Tl;Dp*9oT=^7c7Pj4 zmqYWlGFii^W5nD_c+CfD>z!6xKJInegVEfA1q+ijgRnybVVVkZX)*g6V<0=CAZ3!) z!ZTKw&t60(qcp>1fV$QN2Mm@^HefVFL+mth2H{f{=M31K6^k?23g?Dc>Ond%?F~&_ z^OHQ4gXDy91w0YDG?Oz!m)h0f=n3m;A0vvcqXra(C-B59(@>A|f@_Zc z9;3p+E*0QmCkrbKgeJ`6d795@mSQszPxm=W+^~U089j0RdV{1d4`g6%Z({t{<5&fW zN^)s6JWl>gsQ!tS0?!J)=D|3_^9J$<8J?H%!dB>N3WV{+z2(BLjm3pUBjXSk#u&p~ zr9lV%gTWwVf{Vb~6@_68A8~#2Ch6;s5RSZ%VHld00~Cz^%7iRaoGMgx62wTt*sqzl z*re42I|M9uEk2A$EOCs%N~IYEmrX#50e`@ym=>XWH45oolA)>|3RTq+clRRJ3l7LZ3K6QPt4gQ52!=ZKCglqa!Q<_e)4_S*DATNw z4Mj_cOQD8?2X5Bzz$rr2xG*00bjAZGf(NGdg9oNT(S^ooDegl8=|xfCcN(N+viy^C9+`0>we=x`2_0HmQi>sr+k!|z(64je+uyT!Trnzpb50+*m&*87_ zK6`beMR?L{soWiBS?O))Y8@7iNW1heoBOI{oBNgwn|mSdZ4I3lUx4#7jVKegBh_`* z6=Q)h99I>kC-Qb7*5;X3W08*9B%fgGfU;9gf?;=%q?Tjb&y0DsKz{@dE4~L3E^)i%)%49t3(#OyfiqJ$Nq7@N1RA7ge&}@@7kphv< zsnsFcy21eyv%5(P4tpp0Nf4XV0qtS3bw#1ifvQ&D$TF{&{{%Oq%ns-(#IAfWZ!_X6 z_s7-k)>nGVRv`U?1mFL|-kE?$Rh^ALlgU7U#2b`g6woNqrbaXxm&Ab1zzp1h8I21{ zRg@M@wOUJI22cTmlhh2CQNOCK-ED1a{i@ZrDu`PGn1p>(0jY}n9mfT+KtN&szxUib zlgYwjtL^hW&)-LK@7#OtS>E%$=e*}#-Mm^jOg?B>c5`l{Q%@oo(&p8x!g}lm#~BXK zvq{?UYEPM-r^_knF?MtSz4<*?$IM1r5P-IYi@c4PuJo4K6_L(6p1JSrqlSdD#d(_e zsfQg61b~{S%mlsS_1)O6dhD2&)#yV{aisR6|KWj;Oewl-Rs5%6pET!GD)r!)pGF*y zQ=!m*KRpDOlx|VYi&e&9kyYaMybDt+k7Ye;bt7qOi zeD94n%;i{o2b`Z(Y^j`><=1>4dz#*LdFo!Q@iu-RGuB`>-IcjMLFQd#R+!YSySbO& zSgDt_Ei7YHVw=>kK4>(@YO*zbaih=SX>pVjeA@(Evrg3)uGw|*+kg1Q(&Avuk2f|x+n-z<8}A5IuSN2^*dHC$W^P5fip#avXp`vU!z7zQ_AOwnX{uIAOfY8aNr z>>|`mbK|Ai;dylExm{7vCAA39yD*HqfsS$6Xj{fqL$m(S9{6=F?N%|d$6*0zN$w)b?DB` zdKs3oI9BXMv^U^XChTQ%!yHQ;DaRo_HZI#&pA4~bVstz@x3020beY!}o#Tm^j+=XX zc5P}I>Rjiji3nAnzvlPTh>j^;$Tak-4?@knWmX-%0iHZz> z4Z-z?;CS*i5nh_+rm4WIZc+435%2R*$;>pRy~=4A+S+8iqV;Dq=4|4UiWlS=i~%Am zALcdIg7J+EohgRSnuP}ZW$V0TLM-+=Tl5HW*;w9DOxH%Cx^i>6rNDEwII|Kb2x-;v zv3jNG2Uk66f}V=0afNxVs#!VFhE)8AFYiCw1HDLm5(bQJSG4{yeN)i*6sJP-`rFm) zP08|4K0haPbj*{iZV4Yz0a6I2H|fqLwXI%961^l3!o6CY!-NNzJen*XYtTyG<`3ul zEz}F=Jnl$jpWXy6OvwuMWedfO_6A4dSow>J-l7zzO)27-v&#Gs$h0`iiBLkA66dCd zopWX$p!D-%Qo~e~b|RmC9x%S4>E?5HZBk8#bE;crXB*p4xen5kt#!js%?j_r$Ttuh z15K^cjhD?Z6$K`@sQhcvjbk5FKtN2*9>qMQ)3q`SqS;RepJBbYj`hO*@7W_C487BM zD!k{dMIMTviF>7?SRdV(S zZ}qm>dGmxhtZxeMY8Qu2MTX@CxTn_hf6HEcfAgcxS>@VOi-SmlBTYG8QNFcJ(>yKNSt=_F zO_yJRT54I6%!Ehqco~h^Pt)3JosXO*Bi{v=fNh@c-Nr&EGpz&a!>bzOMPTVs>(z02P?&i^KBT;ucYe8q{&aWjzPdo>+4W_Io z7|U8PDQIxUXjkXXPdOrli_CLw?J$uEd`DQF_)1XHR$ePT!Jndj8HzZF7)2n{u^=w<+c~20q_OJkX+7w`dJ*yy_$$@K`i} zlpv>KSz=g*cmQcZUy%{GP?aX|kXbAuhFzP)Wh?UL7bpvIIhUPB+}#|#x_z43C$IHm z0Rk2Ew{{%1PJi_tk_;!;c(kWBU~_hM^sp?b$hn@{oXtTahumU|N7W4{;`dJY!sZ>UgiRWnbJJb_L=t}YXI5HAHTB|=c^=`Ag+wBOk(bktd&JPtTfn&Rz2(2Ypj_fcB zaDW@UjrcLhf~G?C294#WlQ2f{JZj@4@PK^I!iT``FxGZe#(0@hvdY((@BPJMOD?h4 zk{aPR#c0T8NQ#9aalR-(1QeO;t60phK|znHAfzLoy^O>rRbpe`7j=;1v>7`(OHaI)2`AQk>MYPf)iNFb`X>p4Ynnt4|{%3-;Yi zQp#oV71M?L$*zs^3wx++rRq_`5*sUG2;Epxbm?V^SpffBcf4DW@^36RMnZIZv<06w zn|b)79VL}&jeS8hRbjc*7C%h=Tw^Z&8|}n~ZTvH)9dYuDHn}nWwdEUsXeQm=X+K+y$P;HI*9aTv( zR3Vj&w`)96e(0TRtm<0h$!#J`shm9yW3kmlsC0>mXo(!yip^iBO)>n__cFR}AWuuo_UNT0SoTx=fB5bcCuCtSHRsemBEV!Yx!E*#&f-&Ik< zH)spin7e1~Olk|*X;zr^m&)Y!bh|S9VUDR0z|U6-4jYT z|Hmu9m$qcWX?O^Z*NMA`e6PTvHSV=w=Py0hqwEsJo?aaV%k}6r;$ZqJa$MkajQPQ|bVv6xa5`%3{4jVHl={?4POnio ztwK>+!*3OGuP_@Plaoc0C#J)(k)o%tUBP80%+}s3@|Ju^0Qj86T-$bfMmR!c=6M}m zy@;;jqn)QZBUEwIHT3dsdarDiBR3Q{Zaz%Ko-*$T5sY@hcBi`$S4^i{dx|lxFn>9L z7p?Jp*tg8N{de!<7vr2uCGj{1POcLFd~1Pn{a)tKtMc1eXHxnQX^Q~$FWT>y^SGM(Q?~z<$-EJrk6$YA&^F?t_Elw)2i8 z0+H2$0{i(bJU4lsblr3Yf%QiXcvwaep1f`DxB<5d7l)*nUQ|7uRRELRy9STTWqP!? zdG$qt{p#HiWI=;lM-@;Sq1-rJi~F^XDwbay$_FcFV+ux{6p>1JCzr%q7DsDSzrg*= z{#U;&bcRYBrS_Oto6SC!!}D_U%?m7l=i4~uMJ5-cKAeoEsC#BLt3{Me%=z-TaiK-R za(`RK{j}7*z`BRr24$1fs)YbNm*cTH11yu2d*4Bhm$ANeADx=J%=)mJ-(>VPw_L62 z!%15*sbS*%4_)-`LGe zT*#sDZjQ;X3YOe%0AkRUuO%+qAO7ft7q+{7z%`|60* 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�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ɢdVIT^J4@#URAhsaI?7q8)eCpEt` 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

%1U?&@}dDyZU>*gwj@Nn5%Li$O? z%qTMqdVWul5dmE-VVDC94`Vo_3$`$G`pS z!ng8byIxIA*%G+3T91hj%eHNN$#y8-r`s#v_yb)ad~w%LBnzxsV%r~NWieR`3)U!G zKU&D7A89M=!eXw9xg-#n4BjeZ9eEk_~Eji~)xq5B%J?p3!fuRTH9iPO9pXLu^^?_JRh2|f*o|YQvUG(+Uo4ViXk8fRBYnnWkB7qz3x^91= zKndl>KRo7tQS9)MG&pydUH`dCiZu4c&Gg7@IHWyzs1eA4_ih?7Qr>IOscpCMF|;{iK*N z&wk#}`Zcb2({N_=NX;Ch>k~5`gzQ~0?R>Jf<7rjE8s)t5=L+u`K1JgXw8;K^>6Zaf z&dcKBUNju!qdD)JuRr9IKVVCRn=E^1dS;}*D@LLWOE0w{`^y0Ptz+VwEWglQFuoy% zAIu{k4P{LrHz*XA?=R0==X+g_KljHgoX>6f4`7|I=sd8~6CI0@Kevoo9zQu%z*r;%`9= zHe8JqvPQYREx)}7ld34EsHP^}&a}9mcX`BtC5?w34?^){UH^c8ga)> zhmM_QdTZ8Ex4$zx=Z%h4?RQ?8@Y$yN%Q}ebhRf?csk5eAuK1iQ*THfY5Ai;YS1$S3 zfuUsp)9(YA$fZ1)9t1Ism!_{V_O-75;iowupzA06hA~k?@lo#gs9`}LKl zCa+@K;(vUfJaBW0itgs06!Lij{*J~=_cxdPFps?=%qxhQUDEi4$G`4e9bf*gxz4dD zRIuUuDbtUuW|w%|@x-MU>f_+wWYUhj_evKI3Fu!JaPGh&dj_VX$xe!!+LCzv#Q&A?O%fi z&sgxO?ri1KNiTX_jeVxcyGgt`M(N(Mm};%ZzHxCCU&LyEK|V>RpV0ULJ9n_UM=^hh ztSpjems%PxOzc_2V2Ijr;KC~Ld6M6Rf^AwI3~ zS2w-xZ>U;)z0(+*qzUsk6<>k(2ezv9YQ&73mJ>4lIhRoHMRmMS(?h)c8vv4!3VV|WCz%it^+?l}-_3zT&I#@ZK3rdEHo1w%3_Tp5JH zYBb_{>wQFp?uorRS;zZi-h9n{X$izg;}gSwQsf_aPcYhWpE{tQIK%{D*+BtSr>rgH zGVZ~bT5}$>(5(CA!w>H^&Auo44|N>Tc)HpUcHrqFS^^NH>Dk9V>QOY-agFuSyE9!& zX!bRy=`XAgQ3?_HthI;OJ*WGO^eCx9F?U7afmToES*FfxZ2h*))rLs#5mQ#TnWmg- zIip$fv}{*5YW$WJ1slvS^Sz}H37}EzbVnmOlF9pWRDh@;!9pDS#dm!rP+kKh?~a8ub=P~YuK;bm(dozjoQDIyq{gG`1uz) z9_Xg#6gck;vM3DayC!XSKULuLdE0S~4|*>Pd!sS0OE)Orz0&(N4qLYj^6zk}+H#~z zuIeL7JjguJZNkrASLdY1=EwVN`QcFJk^2sOe5hI;m;^Y%w&hY*VpXTP@mdkFwOHzOP)umQpyRoG4n66(P zn7)G@ZXlu#d;0n^TuF4ckn93XG#;t)bRbh7NKpD}aJ%|Gzp!s^@hNqG<&G}10l#nC zb79l`i4Llm2d^ssXny1b-v4!G{*%Y{n>#+P*B(>k5%`Y%)pj6cpTW5DHAN2}@09Tig}J|6F5$?h4DxAMs=aaQ|8 z<@ZjvQ}Wnvy`8tR$dYc+j-HeH^n7HHv0jLi#wV9N73&X(x9>0qmgq~jztRR)14jHkk0FfVIf&M3*E12n z)tHq|zr9?7`(}-@TDxVO^IP8>nyrqmL=OG&Ix0lD$|dSbgD1IOAsw-#=_!VPrNk4& zNg+g|Ki-Aq4N4N)zs5WS-S4GZo8PCzCx5S4T{Wk`#R8q`-_hu?d1dO<&04*t{mi7u zelv-Nq|nOJy#;e(S)=R^wUAN*)d zgN{c!%qV}k-N!5On*4J7p2lx3c`Jl}PqR!zcMYlRy7$%ZMF;YS9OuI)emnwa_hQBx z*;N*#KS+G}Mj%0`Pd`{^DIC8h+6e3t*oD=G@jnMMXBmbuc!QXG{1;uHT=EdlLgTA> z$*aCghJQ{{r8PK{Wz(}W|KM}SlJ-=8ae>?u>=)RccS(T1%3s;{i;PvRP z=4JD1)+tls=>>;`TUVx!`58Xdp_L4MxGnnyD{F&C862(Te`ua$Uya8{C zoLm&4mfNrjkk8%?t+F%s-eWDT6APqw-eBW(9}&>>l52d6wa@7K#rh|PszqdW>_BdbFWuoW3!}kh|*Vs*Y zV*aGP*s#QM>&1m}HM?v$gD8I-`dpxWNLA;Z7drJ___FOsypJV~UzlIz)CaB%50kT` zVHZ%0zoKRlGgnOGH-0`8@+(5sIl&;A1DMD%L=~+VI|nouvBO|KpGfWi5qq`*jcI&x z$wzxNrwnGK6!(?9D0u3m7WG}1m+aSLMUi)#@hKXQaq^NY&jDu3Ag71>DjG2)t%y}g zhwayH4au=2^eaBK;-LGDSWEjJ(^H;jy0vj_EZ)bG#%s#>5+iX|EpKIW|K2Z$tv}N* zzkckl7sjOVh}XBU%P#Ej26Js-+XF|*Z{_bCpLV$XpLpx><^Gh(kz=kVe#u8q)5km6 zjT+h_?+P@6n5MV+oUBrj~{YJVRjX?Oav2A<=&Zrd;>C(T7o=@otiCwEyNBSYI zZ^ewMAVvxrx@bJ6>Ic5wESAlu-`v}|+@d?)JbwK_{~?HpuHRVuo?m~G{??vwg*9`R zB`foqRw0>p6U?)QL`Ux!b%{tsCezykL!NxAA_y`q6<~{ezUr z-`cNxkm=THynpt(B5y!!F6C;!de!1LB^JW_Sh7({nO`Tg!+5+Qe+(>UGJ_{3`&u85 zsqz%-2YXBSqU)#SjgjjZg^FI5H9yBqp)5Nd#juYmV7>W0>r18=85{k!x4Gfm3CP0oa{#(-T z7nV<^*}r`H0by0CFuIlNm)njphbt~#*0r}LUwBM|g?kRB*0$bt@8zsF=~vS6`Ihaz zzkPb~g5#pbm2-Tke_At7mt#oYb^97TvrO;3C0D<5KQ!y0==KWBH?)!AWD2rBtlp*o z2!<)?_nTjz;rJtKQCLtoKhpS2<##bL7d8;OeqnwSvVY-p63C>IH$Krb)vEr|&C{*d z=9>`irusJy+fa5$$e(FH4t7{FJX?dsCCh8#ZiD_gVUZL)(|u*HGAkz^uelDNr`s#P z{jA&nLgPyxkDT&fJU8s~x2dM8Rop9WgTtCK{wsOUyQ1Zt>H49!!Q6$7D;6EEd33+c z%ypMS@if)}Jn4}dq58HxT^SjOZD88Si6Bw^vx6nWjJW0@euRZ)r6zdFi2UO>H(b_baru%j_=r z^}9v;$3709WHau?&Y72;YBM*Q?w7RO?yevd@{1ILBAder=xj9QSc~W`@nkKhzQLV@dZ1EuXmL2VZ^$w|@Zg z-|$=(Vu6yzBfq@2QCsLF;woL{)A+>Ov#`UqzE^O#hQsCI3s?0>sWxkOiJ1PQkrqRS zPfGc`WS!NrTM=zf54o@Li|P8o8Zm7>CE7FKPl}tfL5y7eMe~n%{RU@bkX!+158u@- zHnw2L)V6Mmw|<^>JZZyw`Z=0DG#)N~Hbo!8x(G6t?aJVXJO{|;C9~Qj=K*qG#H>Uo zEh+pvtl#@O4ldJoZ45f!uFMl`-AH7qmymmFcWUO@+cxnWS3G@}L&{U9CcZ1~ zjm3UCa;B$Mo6HM*HaBdNFX-mHsdyhty8UwL3*ihaf`G1HUi$-Oi8$XF5OL#S-xV{T zWhfpAl!0B>!Dp2&?{DQUu%KSg>fM%aNNtd*i@#t#g&29mr$5=hMSh{n_DhbopV-Pp zmDYJ@y*0^6N%(zgzlQZ}el_t-JCx-2y5TvEAH}AmxcNAYzre0};3aTh^Sy)J3uRhh zHKWyriW}FRKY&ls^~s^1A{ZS0jCTPi>1p@6!5R&hG#)mMfgb;@J`iVvLJK!eEjY%u z^K9k#{VjUge{$38yLWHEggWb6S-4G~_He+4aZXN14clk4KELmC#G2B&>oL^r{VpO#I0Y71w2wk-`V&~bw3-gexd1StbP|ODd_$a))!*^ zJ&4ol&$}Z%u#{duzrKQo%FqDHG zUG%SC)r(nn_bl%`cH4EYdwcwS=qKpX5Ljss^Z4gT>iU8 zsY^n5=CpFOTr|BtPJ|SNRGIRV|*&x+o zpz#=MUlD%i*AKlaPj2tDbf#+0ChOjAA!TYJy|*rPon(Dvo%hrg#p;JSF3@wNXnex* zluw>HGxC$1{0muha_vb*;}a{tNITfSMvCZ`PM==+zA2c;a{cY;w*!y)2<}&8eEp_y zkrp$%MPRR(f(Q1h31dbTjI2TGXhaxePZ?ts^WzidC+Yeb@WOsy;G6PYZJUOSI3L@> ze)WjV_42f|tcA~+gMLzEf_(K0pOpk{rtAAJ;{p8A3wuYQSXe3dr;+2fT5lSeuaRG5 zzqZFO=a}7;kc|`38#6_~f)_V4N9VrKMlLDgD8w58v3P+iQG% zUW^4PwEMc8?W60Hvb&RZ6wvJlD}^2J#kD=US(YUC8TQE}>v|y`!}Wx=9==a>{bK2l zcD%3JGBEdU2nxlB`mfWkI$GN$JB(SDu6U}kPyd|TeA;tbZ`Gbx&M(i_JYAG-r?Kq= zJF}PC0_xB72+&sku?|>`$0ubqs+KBreY8Ez<)4U&XYuI*q58zz@31cutbGe&dLoor zO$Pb7unSp#Mh5d=bp2xaJ7ZQK8Q=fxc7YAR&i3c0hCKBdipCnM8@^-XmSXR+e`lzE zW3xS~wLSjBak-n*xJ?#&u2tCRf$d<|YYx1odJ!}}SRop&7^>DG{g}}K5ip2?f}HNh ze1=?J@ah7X^IRaWGlUsEz0~}J+Jt@%&gmV>JO|!|kdZTbs=XYPj565S1PIZ)d*UyW1RYXftomp1~`M^c{@%v84N7 zxINPSGwqIed{!Ky(WkE%{Q^3`xO^peJ01TrOy_m&;yT*)9AG!^qs53}Iht$Me=W&7 z^!f2~PRjXPQ@@@%@4&nNPe%A##F7)Y!s3Q^_p?63dO7aNyzuqmsn0d@l-MIQf6)EG zuYcW{@y=eUXsVrn%~=MuZK5u*|8&K`_LYpiy@tMMPA5%d~v$n zg44U>E_U!#;(Zz~O+RDpCBD2fx<29Y%rBqdeD!`h>!)>}H6}9D=Wa}=VomN@PPyAP zsmh$tCP*hNY5c_ALT^Erqd?$}YL_KHWaC@d);FVs^i3KJnr3UhTJ9PagNH z;_=$IH1nKv{TXB57}g;`n@5YHnw498*lusDzE}UvOvaZY4 zJy2B*q0@M2{XpwR7_qv~&`$s-a^)8Y_c377$79@n1XA*^^jm{MZXKm*>_%sY?MExTa!htyG;BxV%$j{~_~wjS>{`oa2R<$Lh;7cGyt>?wKmrD^Bv>i;W;biDwC^~ZET6{ zs;MuEWx?tzZ)$($-N;_;ckg&}t%t`F&3P|09{K%GX)Ap9jQ)`Qefl)pl(r9QB$sI~ zxIYLjk7(Uyy#D6%ppc@Zr0FNj-@3X}n^j=K2Cu8h+VO~i+TdmIcSUx+{uM&+{n195|N0?C}d*i_wSC}~nvR=$;0^3F^t14B!?ItF?D)#B;pngby8ZRxs zxb&+Sd8y~<|E+M+><_&j^sMicUfs>}-N7S65eJqu9=4tns}BwB)`0c!m2~|yJ^19g z4KqR@0tf3SVf`rd7VPBAcNOn7-2L;OUmc=+1}EQt*zFTON7qlwLm~T2#YDTwj=x+M z9M+;=R`l@o+Q0IZ^OpM4dwMi2xgMXW+0CLr>#i{!=662ZCHHx|8h9T|8n0M-5jw)I zlw@{+%sjvv|6%xQ&XTT=rjP0Rg1x>VRP8H@-`zu@IPLc};pd`v*0ZDjG~3#K>;<|J zG=6FH@@F_Kl;JUmGjU(^`^EbY;?{c6?-!PD{Q40_3px7@q*yq^3889z3A=)tD}PWb zyFdYKh`ow2b#gX5FmrX=3ZI7R86$Lijl~0Y3z6f- z$I78EXgoCiaU{XK8RTw2t-$|$mMQ%{W7}t3_7z`yxM%$!7Qp=t+y&Vh%ET+V{a5mY z@O&NeyTkNS=blcy@35t4pCN1aPArS}jir}dv*kSt^<6y4V}>$rNAY7@cQ(@78p~LG z$e*Uo=IHll#`y2T^T61DqrGdSM%9Q{rN>RJ+syfyJKo3ASo(>J?&;Hq9&cRsm>B=N zDK>yAv;Cg6;=`TMmJ3SfuHA5CBK5649%1`lT>Jv~9qd)`V8AoxyJ&jL?f)ZR3(Zq( zf0MWAg`^3pRj-yDZQN5;5%JRagz2N}%dq2v5F>!|;N)C2m9X&Dq4EV>ER$5@KD0X( zqdCvk{xGo*H<9#gY_8R9;k|-5$ z0Ia$vf01*zq(=H_JQ?E;h~*mn@grtDo917Us8b*lsbFXIV*l}#FDsN?nsr23r&+s} zuB?;i7w>#Ju_w5-tYQ5d%tWHVqJ&&hvR5(}mc2jbw|y|v(rMk%&p+FQAD=-#qu<}U z>mAG+?-BL`tMngVZOPS-b}JURxwsXv@)p9MG5U|quP|c4#~Z*{`22DgaaT;vdU4dx zx5@?WT2yHHYN=-52>f2ZKg6AH$Cl%U;l*7IF=xv;S(Cu}6H@md-i7veBLpR6GWu06lBcIFn|$CBn(S{{3<d_k zBE^J4bp14ajI}?7dz8C=y8S})9WG2OA;KbcJsa#B{?ES(+vzh-bl()!`6M5|7_a|8 za=>~cm;r`)1jGA4H|dh#;d-RM_56}vdGl6G(D)&H%Flg1`h%U-;@_(}ybJ50$#cv$ zazt|Lv@`be^Y@$SJ@n2XKK%c+z7diuhZW=$A&`X)o|Tmd5a}IqWU5?WFPk7xt@ItUzNLudx0xcxx;*xeG^&OTvL z_m{?H`O$dUc8A#cW6)vZc6ZUI50MunE=3|x>?}FtT5b7bYWfbR-p7*0OY0kbeG8U=KO?+@axqs~=K3Bc)+WHqut#(d5mE*?S@V>wCK20BCd|Z71T%_H>1mDdrJxer< z+_B)044Je*2%jAEgEop=Euc^wU)JDthtq)$J7!GrO0Hf|lh+k@_)qc7#m}hL zRd_?X}ogyTm0Oo&;Q2S zE09$KxlwYRu1M3tu-*kO18FT3_0?~$u)fu`T6E*Pus2Uk7aBSf*?jepm?C7W!Rm6pOTT{U@g{D24s-_0&x7yJf9cmRcGL9!r-+(8VG8xhL95k^XHohUs& zedurGrWe7BmQPPvHzAEpNgRsSg?f7c&ee{IWEAnv6My8E0vV0jmNWW z9$=kt3NdC3K22ISR;wv&a7j=M{L#ZK8JgZ*rnAGzrl@pr`{*t;-?K%}Y$ zq=64K{b+lQ&mVDOY9jkq=s$rv07i~V9Ul83Bj<2N)u)p33-8nIk>CF{WWDO^PhooM+G(cQbI^Lw zr4U1ad|j~lL6wV=00~WXt>oV_(`u(_4OjhTaE=>?mh= zmO-I-ej{sC-ygPC2?s1xi{?zwtaq5yx>xh1wOU&4E?MWp(_(RYjiuWo#m?vA4ElZI z;)7f>mdGbC9>rQ8`uu2o{b02XVdMbGpw}bZ-y2u2W*xCPZnE?A=T_ys+n4)EKW7|0 zh_!>Kqtfe7={n%=Vb!dx%KcbnGsPzKA9(69jV9&&3^RQ)4^%O1gep zf9qQ#WPVcrK6efD`{nlEY5#&7h4!vK9x?u$F24c2#hs32?06HZPdtao(Oz!dU$CV6hnDYL{uy6>FGwYAWF8`jBoYD{2F9PjjYvsJ zI>=%if+?$sh02?Wg@yjNcIrp&Ref-hj>>c8CH7RF^0!A`{bS!lj@mg zq)k##pV}Wc#ck}?#~V)ciqpgka&4LyTesnMyTxf%^{>PR z9K+}7_RFI$mCP;>Fmin*&#TaQgyn}JeFtm)gBaR|GMPUxH-_`}*n0hvuHQI)pk(TW ztX9bOft}?ca*MpFUnkrtT5Dx+!)vdsXG9*%^zZ9}8aYejF}FUDI_}3NZ@qhPudU7M z>m`46slHkz6;JeK(x(N053=EcEHH_bi9RDi!-zD{*=>AAVtZ zV2nQC=fLY0OZTnI(NMK;q_RNO_vJO`chtYwrq7cb>8iA}8ZpV;8&^iWH^1fU*I~Y& zW3=mq;k{oROu+kC()=vk9)5WNE8KujywoN5P2nb6)-*mC9qjdyLh;xR3?BzDNCrsu zBngG+`swi`hkYf*f-T}uedxt&pPaY!zN;MdAxA9sBbGE?W9~CQt76 z^rXp8oz~lXE$gtZNr&pewGlU#G=5=zl%{VT{%R%Qp$KOF#Q2k)3F43vS+gfp$?LS@ zeS?#kyt-G_w4=klr{}I*bsaw=$nik&)~d;?6?h*@y8Zu^ ze3ZhIh#g8AKRsSD%HET<%b-G0SJfl1pzkF6DJOdmc=;%@2)2oCk1#(PBk%dMCy#x* z?v#4!gyY_Wy&O7N410;Vu%z)BWAE_SuHT=+?dR7I5Mzb7R&U0l@KX`IHd zr0FAuAGz!yJOzNgnp2#mh6qV1ghvj20@2{0zj6*@sOVAXBH{jv#wXn0rpRBMALYgZ zcjGFDI<}plRHdzLyyTyieuwENrQ_uvpMh#^N20Dm`CG3qlr0{dX|dJ#sU7=&9K7-> z;!28tGb_{Z+>T4fEZelRS^j9ek0p&)3_lt_KjX~UJ&-rt|F5P4ZXk1Epwq+DoS~We zMu-MW8o&AVlXis?d%S_117Aekt~Lrqw|OrAUcUI&X5PLW7Drl?(d0AJ?Gfg8e)$F- zF8CHOrwleQD6 z>uU8a%h&mBeLC;lI&8)F!Ur^y=2LfvW%{$xz1zAuZAyL|`?3@LTY2!o`EEeZFohel zT8iC9x<2}Ex_&A85zf=;rS>*pl^XXdG5Y;%Y>|fC>(EXdPPncijkk8_+ zDHW^O#N^MIdP zqew%gP@KzA=+4fDbG>a+g8MA1I-(`^sC@L3Cl_u@uQkP+)_m@nzVV3l$Akjo5hs@B z#@n0mN)25?^_$avyis2L1==zM4H!%LW`3L$#$QIPLUe58y zZV9^v-OpKDU06G(;76xvy;~e!f8JKJ-xxk6AAMjZNdD~8{|9{FFG!y|n+N7L%lCVYZ;{kKv z(a&K)YU`JD{lep4nt#ZS!5Gd^AlPU;x)c{WZ&v#3-PIi4J=Vn6bDMpw|IgFcEj4lD z`tF6V_%^C!zwE&FW~nXm^TzjSeJzJQErn)25u^8>9KY9gm3`aR{}i8Mbi7|nIa0fy zTAKG!3|D)UM9M1}8yoid0xO&EqWjNudtThkQp(DQW5%>7?zXl0l#;HwX9gm^hYt>3 z?HpjKjC!$l`LS6|1;6)DY!BK*(>EjS zGbwy&;TYNGY^%(wsmJW|x}PsR1p9-=FW-E#SbIrID-?>P`8C${e{x2-x9qIv2^BhP z@{0M|V~RW&%^VjDd;{JLU?M7puG#miAGzPyUp3=Z%!y6U+i2ph z_#2x3!u)QEyyuSq1UI|Ap^#U&%bdjM7g5#5Y5bv$RXXg6+)+Ro?{2kk^PliLhrr@)OreAiu$L{tWNKYKHK?_PjQ)RQD~$$x>(& zjo9zU<|4s5P%_*NbMGMxPl&l_`tr?BNwwzyhc6SW2M-?BiJO||gl(bm%1u89 z1~p`e@LhEM!tzPld_TX2BZ%nw&uV)F2p6nxSsXl{J^7MtNQDGwgl70~eR%zWdnWy;j3IgMOh({|SGA84EK zntsl__{8^JrC7!uEi!r=j&%z`_b-&RFnNpR+(ttONNbp2vVnG#Zi zBe#hoACxhvWC3XfCw%@L>>V3VKvL@cA+au0Cg_&aThe1PxsWp9{zt%E$ zb{W>DPe0-QG-TgF#u!<_udPA%)4JM4J=z{=s7&m5rNgy_@qKl_)yI<&@gPGss9o=~ zxBs2>!**s$AuF$amo)3l5x1fKf=C(m40tF(On#a+^AGfRAah5hcTd~r?AQXD z{1^T>j9?h&@GtD?CgvLQ{#x3~bye(>Kb&n59&n=!{w87ady6{Vs=MqsI=E?$nT1N? z{mpH@eE;Ko)OLb0Yrc^649ow$==K{c&tdmi7(-!9ACXx?5^Vw-+R#PUFFc<3<>LSb z0c6F&{1~haB0Kl%K5u;FhO~mlOOH3Md`ff2_aHw6_bf9+YxZ~Ed0!W*y~xsbOvgII zXT3e4na82qryX1M)O3aM31d*#-^WqQB~Q7fMc>lN=a-&$@=nY0R#{p3J2PUV>lfw+ z^t`y%Gvjw)wQBb?#=5x5B0D$OF7|GybZtN7#(>1t!||D4H|MOgiGJ)dZ*YZyPMu2Q zZAEpPsH|QdEuCij;(XHP1pm!%#-j!%1Ymj2CU{=+xJT!u+EvAGG#XM+Onu6I;7V6lO+rpEnlq z!rOx*24GDmQheFqHoW9l7u%Pu|1p??_ zzAOB?&E6q_b8KRQez!V)|KePHj>bdxuQ}wA6pD?={PSn2Qk7ihwA(O1`Q76h;`R*R z)z)F}WXCxUoAw8maO;Nm>GlYZAKmfH9{+(%d>Xzr|Ev&`fBxB3HF)QFn;F(7s&P*mTQd$H&^*uGoKa!|9gp8a;{6()}sNcrj#= zX5Ta8*RmDJ`i}h@_$<_Z@$!Pq`49~Yz8C7v|b*zLvE`$2G_GmKsTKKib6N?PWgO0b2H9>xcRA_vhN|?7O=3;}t73 z=c-__FMk~L_OnL~jzYN(aNQ&(@vSQS;;(h!0mDEsN*8j`y*o>1Ql|liz`d47?f4j5a94^rDC4JbCV? zbv31w)?;h*OS*mX$anD;23^0o=?lI(o+q3URNinr?(q84UF{}kI^5-Wu1u%t9{4ZX zPxe`WNR9a^K)28Q_LE^bMB_0xzj-pV)!<`uQyQ!a$mS>eo@K=N&Zzdn>JX4}c8o+P znQ!K3oxVOXwtcXY1Z-r;)*(4)kaIwG)g|-S#>v~hw{Q2@|Dl)Dbf*XBYqqj{X0GuM z_+hVFa_$@Kp90a>5T*yn3{@aw7m@iZIa;M{1wEerOM4t-yVN)=jo(=QftA>>Q!sD| z?m4D=3cNgYmlH3HPZ*sr2N}-%N9KIwId#K2%ar0hgSI=Zp892N{HE#okYnV-&z@r- zdrESxMU(0eJS$%&YtAb7l&hONd%k|1bq(UiG9&R5uSZ(`D2iC69*miqO9EyDUbGc}KTVDG%Z=BQ89R^{CpUff%p-r!VjLk;ZAAhubGuA&MexGjJxc;KsD{TKu zj|Vj7s`&3cx_%*gYiDzHUrN7+_)#k6L_L){?-jfv!ZRLBufZNj+!y^GVS4EDAo|UkUBQ#nVSKED``PwUY_+#7Zk4pomUdFCyUx->n-_b*zW#?01Z?Q+tK_&4DS3ue_x zM|Di6AG2c%WM0ASoar+?1hXM}c`~si*h3uV382sXnY!T&9awdMe5Yb0lJ+TGYXRn^ z$WFWZzl0~Xr<58W)i8t~>Ht{@t3ptIYR9vbXqh?t*Nd^pVP|b~%xWkUzbX&h(fD9# zyOklwmwJ6E?uacpT`2pE#(Dg0$BZsHwe+-$>+!xgdXii$*e?LAR#2XLtddY>)T&K&^^kmCNwrxRTE2gZcg3KU@!;zh*1N8VC zDac(K!l@nC@Ckete?@yW59+TTqTl1nJRQzRP>>A$7%4_pjd9JU6G;I(8^NApq3TsE zT+h+@u!d$M^z{Rq{#@+>Ddoo?hMfgq&Vjz@_8H56Am1T^3R(wr3rJ+SeJsE(7haH- zB!fVX({A-~arX<_qFfS>^o)G%gB?yldx3s{%uwK4)Ac@$kGq{DA1+Y6-W7NOIYR2} zv{<@w)kiE0p*{WR_880mV8w_(%||;5<*Og&UgbV*LtgrWuLyevvMoR@CAdG)^byZ* z`u(rX&El>L?$Y%c%MXwbX8LZya^lH|-5d4sa`zXUIv2!v1-6V{f_<5S)mlTlQV%p4 zc)(zD_2=&_j{Y*PJ~u{7hBG4={xy8b#UKC8Zg67zN4pO)zosH|l8YW4n4TuFYv_CV zR#VgXxcNh+kx7tO1G~ZoDzs0s?OOJVf3SJ9`{WzvgLb-K_|um!nN{1ebo_br@^8WY z?~Ij4=2~4kt;(@qrIy~X-Q7Cy;Dn+1C*tTSHUCCrsl;9O396#~9&df$5bx9dVSIZs zX0_ar9Y4$VOWWRU;o;iD^W8c)4BLSv-5xF1u-C6UGdw+1eG)WCy>KRD5+WN!L*bja zOZxqEyj9-yU$8R-*zqLts9j}5yh*ZiD>qKQyEK03^dX+bU}ju$$!7Zfrt;H&vl>fF zJ?ZTcw;r3%tK8Y=?1MZHO88hijovf%>yNXDgvP<$Z`!-o3^#|UeQCohI_dY){48bu z0QbwoJtu?JJApt98?uYYxyaZax}BK}5tXv%W`P2&Th}7iXZzc(EuE&@*YTa7=(Qd18)~OE?xSrz z+fKoEaFwRKm+*pa<^i$XVGNQP2C(A|U3C5CkFSYes|UDgd|C=~k7qXBl?*?F2V+Pg zn(}^}anjG2CpI)hBp~Wz3P+lP5A0?#B1pWSthx?h_5_9uBJl657}^+Kvn;)S@EXbd zHsmVd91$N6%JqI@WthD6W2}u>mb#e4oR(+|zq9ELGj^~li=NHVQs1=pYTpn0k3i0@ zRNfv_?1uM?QaA0_=2%eBH}|S8T4dytIq-q5(E5pVjk~ep?fp$?s~;%AC)VYvt(q5T^GwALpr++3(U&b|Hk(Z&Sx0w8FBZE zTzJIFbTM?+_cD>1`s33)_{GZ%x;<<>>`We@k3Yk|a`{`}Wx$F#F)=fsUbmp<%i|x_ zbXiv7=ZMIccb6kY4dEvm2J(Hhtzzpiwr$Ve6`B1E$yd@!6Rel7%xFB~dzv6Vn#C{d zNr7b!$*oHrEfDvzBi#-fzi@m&T)c`e2eYCgxa9ipH+=vu*})x#hUR9 z$mx3AdL3(_-%r~Q86WRv(@PwUuq|@Y3s(DwG5y4K(eyIhAKbjo^-Ti)u^*Ms3+KSqnu7fnB5dl%=t zh$Pa@2gdKj%!l!L^129Vd}7_uw>~Se&rhwoy9uLes zLJW%g8vAZ!!_jTCIgXEQTfidtViSCduJ8ZNUKPhR*c#)P75^#UnnDmVCGVaz3iYYai?JQH7;Y~ zoyJw@-g*>rx77OOv6r>{s(l~MRvTxx^0kMSw-6^3JHNoiU&hl*+Iqk%fmb?Ad3W4l zQFQF}cYF5n+S{hsXLts0n3|Ie?+r1c)6xeQUa4HuWAlG{c=qT3q<89;iFWzNG<2O6 zGvwm13WcBGeJl;pE92~UuAW4Mx+RTQpMOAmK^_vUgAP^4#bB07KQB%H%ww+nGa+PI zTUYE`q}Nx~{1xfX(w0RX(?x4oKS+t!mAC{-pW!4`$*6 z6+m);{NS@*5WTjf`AIH&1$qjiC@?2#=%VYV`8ng`rCy93P1YI`+bEpjD}RQr;;z?o z-aZXbm9pHDxl-Oio<{`t_ov${MgCiGKyvKv{z4JI)-Gl2hynR)&t8C!?6qlB#r7dZEZ2L%F`Al{!gZVzPmmc)Gm3jp)kt@WS zlJ3!ww%j{X>BovOL3Z<--gy4`_3t=rVfX%#mPh-pa#^&${^>?%!p$1*;MS*xCH&Go zj`a)sMLDkA^sR2G@rz3$ZY&M=k2X5XExCzi5_$?HTR0<2VCTF4M!vOYA}S!wA{1Z= zf>a>#7Ac`yo|urpt?PiT`-~6kK?SA~0rk82@fl!7-DZ|xgQ@{#Em=l9}KSQ#& z@!Dd8g1b99&0YCs)u>vLRr&Dg%O`p53#l@;R_42t#=Lr=+BolFg&E-rQ33- z#;NjZ{41|7mlOAoy5>B&K&`$>R*?m@zaXFJ_Q-F~8`c8_TEygBbfT!`+)*BlKWx$* zW2}Km<1_bo!bqzI0MCc)Zl7B&3U*X&O-fsR`|4%tj8XnE5rQ@Z9HEI$0Y`dUcRi_-@rTa2u+4At!3 zZ=9B(>8*GtUJk9hf~2@wKb=_!AnBusr08hw|xPX)`v`@yKQGLQDzHqc?oz_~rYc zR^i)jYfk>$^f<8cMtu6wr`dx^%=jPSt?8Vzfr5)QcBso9V*>ikELk*`uu9Dyn|I5aB3b`yu(Eu zF918K5AzA0A-j(FGWHW#Rd7E{ZR>#t_&@5d0xpW?{hzJa-PqmTN_Ps_g@7W8AXu27 z0xDvQ4YsI=pa_D9iQV1U-5sy`-{;2X_HJ(XcJJ83-~Zmv>nwYFJKuTcnWyHN8L(ls zopCKQ=1aS`mo8W*uP!=w+sn3fkuE*2`_9=|F2+8jm~7wt%3Z%J?lUz)t~;!^h5Taa z^{r+*f$oq0J$b0vUO+lxskuElt&g;mRnP_+zxwzPFV9&?<}KH2f%42b*!7nGW03a# zM_Th$Mj2nv{q)VV=O_K75I*VSH_E%1nKSJmE7Y|0BlfI)KXcpoXAVgZ^ZJf#_V@v| zi*An;`U-O>AhrWBS@6yHKDl1mrB*7^(=Nkp%=uEY0tL@^5XQ&$I(W~z&)=i|(rk}3 zxVNlc_|=7WVMjYeuPAn^5Zz9izUus(lk#3QZ$WzLFOyv<;&u4t%{<04ZhDVhai#Ph zA$sJjybYw`sQvxYe{+|hBlYZJD$ZK!@NwYz*bGVjWbzgPDd=N2Bl++=W-E;kS-mNZ`V@v4pf@nYhsWS1Ok9<4KT-I|#G zoi|!+deGwPukw$L5J$h+J`RCPk65g4miXATY&7qB9btLM=UQ{ylq*Yp&9?PfF!_6`Ph(ZI z()tr1F@drqHb&P({?5#_IC;8QA*+n_=YrCg8@9uzdOn*p=jrCvR;gFp2D>{umBRZI zDwT7q6+EPuan(|#_tq;j7Vl$8)0@^u()t_NLRhVjT0xVQNMew%N90guwutZ=nI{6A z^x6Sk;t5EH$97|HjlR&&dd7d1oWE={SJ)Q;H`6!w|JdJT<+56zst+7844=nRh<@sM zB4m}b`u*(3QxKD;lE#}|`N}tbcGY=ya=cj?t5n&E+`I3ubU{pJ21SNC-23AY;#0mu z%=k}fcppm|U(V|{@Qk=yZtG(x-r{pLKw>s+UENk2dqW5O1_3 z*e`T&s)-^#U8PMurva01+w8fN)o)OX)YJG&x_@c<{eRUz+`Wgb<}Yb_DEF6C`F)z? zi#B5dT0!F#9-mVC8wwWVB^{cfX1EiIlz z&A}hj?a{aWsae~o(>J^NI=lU=%8&ZgC!qasw=VE7#IJS5zJ$_#kIZewv2PBkg#wyZ zc(_P{_^){VLhMmk#{?@MiQOvJMm?Rm;=gMLU5poYT6ekgh)8Q}(>j|lgZQ#WHW_ZW zdR@C4I1BG%N%Jo)Pj%Nv(s+2n__7o4q30j9iAN&^HJ9d#4g3bR+v^ls>qzw`uP2Yk zr&n)$U)esbrbU?Zr#EGb8YuWI|HoDNJKr?3oj!X&o-38ky5aMm;%^ptJIBT-%J*F_ zqr$I)@xBm!^rH`fE5+?mLgUk29*tz`geVB^@T7j$3erTmr0ds*zQLIp<$C$9X*~MY z7n-%5Om^(dN27*4d`x0Gb#kcR=>8QNH;q?So=X$ohs+X~{fGEakbJGlP`U4pkqupP zet)!|z92F(&^-7;f$|Mor$%DC4i~Lmv0dLvHnaS%);KjHR&f7aVSbTLzKgK|HTTEA z)~{k(KzgF@(Iv9D2y)>AnHI2nSCL&g{g^ysF(1F!<(uZab+p)X)zG?9y+IrC zH~EYoICh*f#V*pI@8!>lHrMg~zFiA!YeWw**>Y&;om`b_^~C#F()^b_`9-W7*r$%H zoUvv~+?619eZa*k)gJcXUz=yen0aHabij1)rb5NYoh@s8c+80A!IY~@7;$q z&{WcRlr>`G_k3(kF@(v{Ebfek=WTp=E^kjf+daS8a;#shHVm z*{v;|jn`doIKRh#-3Q?PQF&)fl=Tj^-%_~5snFkTy5oH;>GrdI)0EN4VBsmp6Ty}m z%;5KA{)2zH&P~NPbC+~|+0##Mj6U-CtDS%s$?7LS<|_Y-&E`_|h_ulNq#dIp9&8Nn z)5Ip@bn*Ek*SO!o*3s<|mVesE%g}!jW4+OMbkkqpcf*;pCJYtfBpd#GJi0#h@uQ7B z$nIPiDC2JJg^1b3cP=_=nRYwk!SSzOo?$247^<-EDwk&J(C-*Iyda)V4Zq0bw) z=1tPNt)1^!$ocr-qbYlZ>dUS? zgfk&XK8N_V34m!y+AAZc+Ewk6lU|!!ba}H1aW?8-#EkEIZQ z>TZv4>vp<6eac&I1f=EB?;3X>o?+~mVg0?PuVrP0Jz9`wK97%Hy2@wB!vo92pV_$r zGAV{I*P6~{;Hy99<%#AIns#Bzj>_gkjMp5j_IpO2CV3FI)%?JA+dgeDN^Em9>-xT_ z@9{p(5A2B4<$NHp3&5UG-PIa+7-$VSkC2@SUNBg30SxuQ{za`Nv{xNq9$7Qbw{{C6 z95?vaTX8tw++=JAmYUn6PkURlzS7)lh+f@45gwm>@j1}Wkjv>Mb6`rKJmd{|F#UjY zFJR+ACK2R%2FT-*&=a6@16e>kSNCf7=sGLV&NQNp$<#~3_r>F5=PEo{-QWD9-87m1 zed9bv-|&9ysBxFJ-Hek1AGf@O7DHw*o}LAEEzm~&L%(02`a}#*(0J(fN^ieFoZ6l7 zQedyYo^lR>vC8@bWbK-8g$hlldqLHg}cx0vOrB%21>`Uny04 z`RW(DZ)3lq9#%Hzs@O)K&3sj)QL`tASKs)+B7huTpqrSFRCwS-R#(`Y(t(lsA<(3u9FYtf7mn`s~6cuJYKlA8+wk;kg=0)%q z(&BMtXhL#UNLD=7!e2^PKWHsqxr7=cmk!)Eja2nP#0M;=!3^~kNe~>(r0Y|a&;QOo z)#R%wH-pBnE5EAJ%b1blXq770rhcuj`XM99Prd>lA^<_^75}|M*YCnS8_4_?c&(}Y z_rA<~;BVz`hz()O@F7_<0#cFdIoMOtpZOp6%LSUi+$h);MCSZGk1Z}D>IWYm-MA2tdmm=GyN#~*#Xe?Z^_WIKOMS&B^@R`ieIToWuqM^An&0y* zlY6bq*2L7k`sZduD1NJdJlbh!8jn8xBQY|G#v{z{;`|F(^$#8+u^_-pfPK$|&kWQa zk2xa=i0*(HBfM6XkIK1*#1n(8bWOHR0iHOT{_%OrBMIWDrS6Xj_a93marDw|_JF1j z^gQqZ#0Ei%|66}sOvHdlj*3}+`}GnxQZ-_Gy8&BEt2H7HR z9%Q6z_t2hZb*z#+JzPhvkLjmh`RBxpZisVuF#iKW{?8DX4=!l~H*^hKRC{cNl4S(< zTa|{MU^~FfEJy)3FN#Fy_))Uo(EY1wUrLkDsM-J5E~B2tOOH3{<1v_n#nMdE6^$=D z{VS#?^-~{=$pB`rr$C0=HT&Uo{mT3!X8umdQl;OoJ3YOawxInfzE7pBA95DS*yQIR z{nRHm>LaCo1v!cB6}B0z&D)%BS+a!9fzWvWoj# zypN?+^y1si59{G8>H3xVA9$PSIbTL^NS&_*G-cNuKn{+0tCMXFjbGRC#nKOAIB;Sa zczi;;OR4jlx;*E~XMu6dH9v!VMySoUlD(3uy-*Wa1DbbdQE#8F^i{79?!c^+E~}$t zvh|Hmm~^;nVV*v?-RPtS_79Olfwj&Zs@vp-Y4YmZdwlbJxrz6&l!|^ZHppxvzL~p} zzCL}-ZnD^Ey!!NaHO*fIKP(tBd+H;zg=g|4TdZ8no1Z1jkGlB3z?-aWVyUBk72ctw zbE&t@EMj)9-OzF9;&Sv8G(DB0WJ2*XK*1F?qw7%qo34+RN7DOqES=C6l5RH`nJml0 zdt|;>*DN|h}aCcniv&7wF)vAtoKdMiu(10@QjCRJ~f7_tu2(_sNP4v*-UgwW5w0Qg4Df7o0 zL01;uU&iKXRW~4}F)$Cyo6l z-rl3@*EfB{%7QcPd%Z4UIL9Vwlf%HP-^bNJy5%(9?#u`w^L}v3pz4l+;N$CJLqJ;^ zRSEj=$?&Po>T$_`O6*yGh_8K8*w>mgo4)Dk#z=k4$QROOKm#f95L*@I@`!SdxBiLv2}4>Nl6cyf3;g7LC{Hw2c%S>+$z*{b+vl`ko>P6j8=xTG?eFG ze3?7I2V_O2$KM%2*sYn()(DbE$+XFfkdhubv6@d>yzJQ4mX~&2tJ>EgbftaxWXsVT zdz>kSykE9KXU9%A_E|<5d?>#2W6e~&|J^9B?AO=H#fc0+it!zoZpSE|z&u_uJ_ZUVN!YnIy?mE;eT%YdoS7m=pTg~+=tK0D{X6r2X zN9E}dVf#aI?#v@s=MQtzpW5yz9u~T%bFMI!a^#9`k8=OybUa>NS8LLYbW6C~qg%eI zBO`Ns7yJn&W5H4|81O+|A&1m3o8lrIsPZejhk8*gSP`>3X{xUQx&)y1mlL z18!avu1_0zfDuiI_Hk!T2-TO9{vGV4Kr;4WehKEjQHNtYU~P7Gq#E`%Thi?pZ%>dp zFp}j7Q4h31To^k9G>nJ*bcg`9DwV6>5tDbBZJlO6t*?94hv~mXt_S(o@ls8aL8W=J zQzs4=_Br&yD1LWv)Xqo23g%mqloW6@CBtZX<-i`zO8tq&U&ZV>;v1I7!zBFR>&a)E z&nkxZ&9^6|7aHqizR0nhtfBX>*LWXGy8on*f12iX==xOkTlV7f#6RGc3w-U>hy2Zs zpG(sx`}&fb9$s5F_O9{cKgUG3yf^CSs;jU===y1S{V(MinH487IM_o5BBr3_6oUgh zSwopzdGl?jz(&?vj~!pzC7||peDs%7=T?IqnNvi~3@sCSn(*#lCRV=r%l&xJ8|o4c z>*OkF`m2r)eakO#xr=~%&w*~g8-!Le4xVWB`p}wfX4sb1#SAw`yt!b$vv0xEMZY&x ztXD1&8*wVr=Y;9(%$4g}mTNH$pMU(v^L=>gM!V&8f8=eSF<7lDX?oE7sJlM_Bj1zp zFu<#ZY*)z0(0=3!JY2+!;0pf^(f3wh);}U!p0pY0kX(v1$ zF4*7@wsuncq3368LO#Qi#;ZEMq|iU&@=?idOZGb>IZHeh;33X zOAU!`d@^;M#ZHgfEth^>t(cd_XEgDT_VE*8Ty%Xjy}9O_M=*MEn38@(?8;@WYYksM zc>KU-^X9dMCKQ@GAHSpPlR|#9#g}uGjuXD#oN#EF$%>;5Y91LdS#Z1(eusQ^fB6h4 zS!o8Nn9bHCCqqLNeW+TEW6Soxa&cHIm%anP9k}}ZT@3vI-F|g?i=9uW<5%MKjWAcp zWGmmC+*mODf^}rup%?o^t|@};pz-H~Jl2Hw&dei&_DpSM6z6~5;)_*<`-rnn&>`D1 zH$T`dOI$X5?9-P|@IH-SdijjLurygpG~VpXV{Y#$@b->RZ_<5iVhnyCF|5@g0qGTK z;r(af$<}5|O^eN6Hv76_A!mR~^u{5z8e3-^f0C8vn>z%br}3)NH>d1NO&o(rNlD|S z$74?F8#4a_F=@Uiq$+m!i^i`^Z|(I3@-BZo%4Ex#%k>U)by+l{W5uMeZ$2WTidSl0 zbT>6Lk2*5w)A!L$6#PTulS1A@9LiG%TbherQute%xb0n+?-BQFwl@hYvG}Y_l&iw; zE9BUvN1n9pw%bGQ96fR~;V{ziSI>6=dFQ>iPTKtGp+`!tb$B03nw~Vj=7hfj7~pJG zt`o)794rJ*m7^xdH;;|TZ8x{uot>T9hnK~#>Gmn}b9T?CA@Lhw9tSLT<98Jv-g=Tv z)bPL(QC=>JeeP*|>hxFl$7p*=6Ti^!&k6l1jv}OoXnbV+K+Yc6OE{a$?j?geAF)qp zo@?QLKW4G1&JM!NG50shb%^tq^3Gcm-tggB^Lazo7kxK&aBbwr>robCyJpTYnQb+6 z$GyfK6?O!EPvceQS55NQ@oyv@<{uSG6h*QeZn&|b(<(a(O;EHwj} zdiXW2D(+k>KewvmvdwhGu6^-l#f%ksSojp(9&P;@q0us+Uv=l%ZVeqHJG9$>|3Oj3 zzQe8SOPAdztMgzBxK*>(*R1w-meg z+it5_lN&8>uUG5?6gOaf`0dSwZPQQG{xqrZl>JB-Eb0Erd3mo%8_8tfD_fqp)9|xZ zOu;Ti#typC9&uwy<5wL&QpCGd>8}|rb3RR))0O=x4ICCOE@E@|gz-Ma8I?Hpnfb=s zM!OfA7fJIzjkne8XIj3BiGP6I&Su#wUafNBVHDJ&M|W4F4WA}vjC0#K1;3=}r(VCV z@c@!-H5^~A}6H~etqgEH^$8-KuWULA7C zTpHtHzs$SCfO?g#f5!XVc<6W}`#1FWNM;<+pCv^rSM?h6-C^Cww6f(IMxDd&>G$Wn zzR@%~WU^-YULRanIn8WKUZ0r_4f@(ceG8ZR>kcQ?%%yk_lgH^sS6bp7i3OxQnG)u-I!mXH4G^+~Be$%+@~Ram7XwAT$_ zr0D_nga^};uuchfPi`uYqJS1A+6DFshW(<6Zwuas>NmnYLnu>r|1ggzg9$z7eL37a zZ&s`#PUjo5uGY=T&Nks&{9-eAF3dnWwzq8ee5T(G1$JzM}LYx;w z55oI2e%0|QrG8YkQ?Y)blE#-k{iAuT02c20xT7fi@fDPp!ra))KhrmDMR~J5A8y|( zcgf)aO%EDR_Vkez!%M!*_#ylAz{nphvtsyc1mpk1m=)hgk5_e`-!Ul5aox@xl@1xU zD2TXeytKUe7xu1juOoWC{?DGh%RQq+>bz08qibQ`ohJK+rO%5mKE5#`d9$&x!?5p@ zoko0b{oq36$C7woh`!qUW7)GzXHT24d#3w5$94C%x;5!Nw*unCQW&qU`bQkE-afk0 zq3F#2EZ3|JNbc~YPH)78C5=y6{)x8-?3j@hBp*TeUbti^_LcE{jGskdMtK!as@3!)b%Trrk zek1ZCd-g&*?0k;0|GrI5Z--p6TM`sKBwvBsiv2Ujbo}mUZv4kGZfe&1gFpHf$DeAV z7w`pmP@3m&Ae+GbuY83JU6$g?r-5R9bQ$?Jbjd_>ORL06KcWinOVlzxE*(CyHV1Sk z1rUMbne?x3Inz;SL)7=VeJpACPOXUJZN! zjC*5bMNH1Z443&;Iv2cTySsP!Rd-&tdc}ud8hgZ;X*ony1DSsTEz$g-(Zpxa6NGes z>W{u;q-l$Fb;})3tLEG0n7GCA*SN0+#zMZuSem zbmo3PYDKa62P95}D@w_DgdOWW87>@$P2nu*`t{XcB!?Bwm4h}xuX!-1=fa#2oVtNo z8`|l9S-_h;+7xoK(?;}dKr19ote~6JwG(KtUXNWX= z%O&P8*#spCWGnXwJel|ka0yu*#nOuFipHlu`l;>(qo3I+_4tXfy$ZXE!TgagBfW(w z_OIxL5>8jUAN$_;>df(tQq#=V4ZIL$(cDup?msV%zgV_QkmIT%FLrDiQ`kdkq zuvdVGwfAtarKF_$i{=OEEeHhUyQ99m^5i|^!mZ3+xEvqIQg#`%=Y}hzu$s|!gkk;HfeO8$iGS((VMWwnxkUGr|0}j`z+)NJcFm4~oBFJ3 zpYb!XVF5$LNY_uxcir>tSq_7|!d6(JKuP0K<}aEa?00;p!E4vQ%I_1mTa)_xrHCJO z&_E;I=p!~8TfIFjP2lt-)$zc7r}}uBG8=IA{vX}Z=Z9X~Y{STqYlPY4GF4^-xT^KJ3tb53RBO@Za_A`x7 zns}0`t)nV=ROv(iH7lgjx`eu8E#eou=B<3N&NKRZ8ZTG85XOPH)w43$mB@};pC&(W zNZWE}c-(7)Mp&Pide|r>)X0?;CzCZS^P+d5n9ru6Ugu)V%(dg4hu~@l+#~(WKT9bF zr}}%Km;L3O1U3i%ZgiUEkGT0pK6@B22(LS&+o!uebduW*&}Zc2Fz!__-^+Qes+2p| zz(tQ&-n{5JMgcH(jM<|7Y{Rw^K#mG)wEb@T4 zee2gZ?bbd0gImwc#+?-F0r~K&)0fVlQ;#oj#kWk3j5aU*eURhoucwU$ZL6r*$D8g? z!uKf6q=|RJX`-NCAOnZ*W1r=<-6wg2dC0gq@z?rC_rd3Ad{W74v3pn3^-H1O2tTQ2 z=EI7ZAq=1KeN3G@U39ot+iv-)RdxK9^+?3$XnZuk=rjJHjUHLpy=bq*hFh&SziYLx zTjclmeE13f0X5k5gxq$DxX~A35$E&1*gd;x^NsW0^zqn@^}ez;b6z*)sr{x+lYee~ znXK5Ckfx_J`d59P9sGMS{xOY*&?l$l8J8qM3X-zIk@S`?yXLiDGJ0&Q*zwh3@Y}-? z^=cI=daC;>pEnm57k*=k_s86PUHFMbN!v9u`+0lRU#{p6{GM*FzQ>z3JPa6VeDrt& zej&O7_6>s!N_F|H$=9Rb&-xHBA1WO0QhtWW8RDOhVPp&J&Io+x!Cb@45AoeWx1qex zuJx);pPa$3Jet6p0ojTxQ*_hQ$d7d|UrTIjIJi$nkG1ZleqFG_`&j;){sJx&7YCLS zpJv`6^M=~a|I+yMZGQl#kC4ax*;R4amt1APRIjEnE-CiYVgvW>{n~XuK2!JJwq{+; zZrbgr6B$yV*sox`Pq!yK{Lf8qII#gTT1cJ}nTaF*C&(R$Fv83RtW*>8(LY`*Cg;+h zp*qYc0@p&uKmUiuL(A8kuxF&)#g=Z5zU)`AQ4kuB^!&-y-_prs{o}WjbLeQfPSk!x z=^r1QBnoSU$oe4|9}sV6*B^_si|G+q+vbN^p(giDA_labRxrrN4!_rbdz5uI*2-Vf zc*Oe);w(M-{nC#Q(A^|{M6zzc*CD>KKhuv8gJCni`00S(%(&mVLbAQFRa|t#gCAE0 z=EeJ`qbpW9==;fN$D0B-UNrD*j`#K7KFz0@BM!b&|M>XgUoet}$Tg>`U97zffVLeB zYxmi``yIQbzNhD}I99GYwpV}c6LWfvx_wUTSMl>%Bz{LmFK{iPAK2X>jYeRD1xlJ8 zQuwzPjD!RmFOczcU_^mGAa3-l(?`1Tue$q`R4e9b`biV7fL;Yl5>~iEPT&Z+-zX+t z@#0;ZV!Lza?UT@DTJ;%W9bM_}r}0WnUsndRFN0cWwR981>2aAuuJzb(*1!Mag?+9f zPJQD8{uaNQN1Y$l$E$F>fjyzvTRt8F<+*($m(_0(;3ajKHN;i(tMgj7X5+ENj zWUP>#9uNm#N!L&4hw)nJ=jXWMW8x^R+JeSQh8GxoYJQ(J7rqU!S>&-8zopxgGx|g! zE)fQAN#j!=U&8tpMiT3fb61sX{>Z=$We+(lw0iiVs70se_*A>^XDhb39Auolqs%?) zM#H|~eJp8w`jS^c9ORt!8IjvKdkFyFlJb_U7+g82v^f zKyVVS<_}GOeaH`@aq)x`{yBa?YTx;HsnmgU9b&$?e;QND@hy#>#+x(pLDP(!Dnc3` z&ClBCUsx3~mho3GpC6+3eEs?4V(RBFRV&$S-rlmRWB;9&h)Nibw(^QwR?eE0=u`dJ zX5&opbFq98U`@jX1ER@kn8hsE$YNv?Yy)<|k?8V^6tH579<()*ez#ChPHW=C^O_&pL)a znpyWrr>6?J_w;bs-P0$W`s}%pHnH{INX5BueU^FU7qQE}XluLtHprrBSjJy#$TceIIC*(JrdrT}=h~^O=PrF%DmclR1)`e!y zA7eGEN_(%Q!#$s}-;gVs{xtuCyb#K#P_?(Rr}_82ep7Kgx>T&ap4@Z68I{uqt9es5JgRL*q z#+dJJ9#S}Uyhm$%p2jPUyu&#P{vDAEJn7s1+0in_I~UjgxYuvFVqSvAlQZK@yiBI? zNhP0v?%Krt1}>h_Wnvyjqm_FHx4gQvMyy#hLxGt&tz81Th@7+l+KSW%kN>3tJRUmW?Me&n{hdh z!4kYr)Bj({8_g1(AT_8ry#B-7VU9EY`*nTc?!~Ne>+0}Abi{K3F z;Js0&EN-kwqo1ScnO%9sO--3BBjQz)j+-l4F20gy@{2nK72|}ipYBh6j(;)phxJMn zw|M0_w|A_}vFYQ;w-u3oPZN*M`?Dm@EPU?Oe$xvcR^+EVp51DP=ef=%p^ra4t!?$Q z7CvuPe`e{@Mg1L?wsF4sYGWNoyid1Z3V8r~slc2Fc=KQ}2Qh11A?M9Yi+wWq@X`IF zKHe}EOk&OW9xUnhN-sY&$4=<_)!QSj{^J`DNROKhOCL>aZEdx0;Q5$0EqZ0*eJp9b z*_Ah7DZ@Hw;tSwRtn&V}+MQkyGsdrXmXoVlx`%z2T*(y``)nrOSzz7h)K|0R|6N>B zf7I=jeC?s>FU5GbWLgLNRT0k%vOgfV7DfWu-5K^468e0*+GAqj<+~jgZ|+g!W9**V z_&nVo{|Y~Q)&wFGSN^ZyC-HnS5?HleIg1~%8p-UK10zi#KMpdol+QQ^UtgP6(D<{f zZ^cG#s^z_5(&x=h(>Nc$H+3uuDE2j@@#vGE;oUe_5BtYzT33p_{;%(`~SW6YNsLp4SroT z6QMkfS9*U&5jv;4TK+d(zdq$5J3hJSr5j)W@8H*tPq8!p4Sw<3DE6pj>oq5?+U_n| zr`O3R;^|JJ4zo_HV2oNO=5 zNP)#jEO2%ein6zgxcJKdHM|&!5i9eB@Tw_e#!{MG{R?^kayIjiMx^@pzsINBTvCUhE8?D4UFeW9FJDOP)RDaV(dtvbBmZf` zDY-9RJu!5ki`jzm(c3RKzjO$DV{ORQDZ#NPjFMg#eq&hnGw=Cr`fd+IaB%lZiXYW?ny?ZuMjKaf9S&)4Ic|7Ei>gd{gXK-Zu1 z@nX#qmBy#<{%7R|&YNXF7Z>{)O1eE#<`-zDBzJ#H5x+5Kw8|K{f2yogP;X{$PZpY9 z`s{yID_Ogdw7=biq~Tp=I!=G)d&;QPp9Jjl{~i3sj4emz_aH6}Rx(5sAZG+QUCMnU z_}WkS9Wor*{jr4CKk;++|1Nz=HneVDE>cfjUi>@$*G9|#FW?s!iO*^N5x47+Ox7y$ zSHY5X+q$eTdt6Xqx1{bamFDmd#ks5QkqVp2L^@GqB6Eqs@(6P1g)6^L}SzSB2k3_qP=G zGuZ=;%A=h{IArs0RG#&p=ZJQbz zzw-VP^w_p$a>v0ZU{76ilJBem5ms3J0XY|BPkrbG$dDp7t)^HsT|Zr?Zt-WdJz#EK zQ|&U@qb;3mUM_!Wo>nf;(13X#N7KZm@kud$wK-L+a&YYpFEY*T*SxX~s+PCXEW|e~ zp=YPdx$G<>2By!g_c5Xd-ly@Z(^GT2TJvn6x_yv6`Judujr&aypN3WcfLfQG-txW7 zWn-ml|6ejehSTFBz+*O3-IBVy-$s6NuK6W)Jy;(q(XHNQB_ue3Mu*w)Lh@jjMx z`*a`QFc$!OB*9Dy|A(%R%YV0$zXK#3tp63)tM~JEE^%`02di}i zB(eKNfc*wJoFLhTGVLR0gy0!=km1btq3hR|d=Q(>RC20egO;yO_uqf2@UG~zo`UjB zT|S7-Plgyb%nZRA)ByQzXh1*M6<3qQjoagQGQ7bs}9N2xTB@{UykMPJ#~4eP7lrU5;L4#894h$?wNx!TE3D_Ol2enhJ9cjM!vjZgpnvStgA#v^TiSuy<=$WRJ6Jm_z}IY=noJ-7(xDmRNRwYHzu?}NYJoXx+H zu2|+|d#st3K~!1O=U?E_CYw=8d^nOI1`OxMk(FASsG}~wq_$sj(jMe)Kbcn%vo@BC zQu^;7ZhW}o4HqWmd-}&G770P6A3V783+QZOD~LTAH7D?hkKU<|x9rG!s`S!b7wQWioBcuPsJgzErjY92G`*zs zC&WiZWU?^V#LQgtr&%m2B!z$-vS~1)?LcZ2C0ISqkN{L5(PfPSOb9s#-x zbO;@9RQB4?#~_gk=ow9%Leoo^cmOKbp6Vdh0I^DFE!=6DnD;6!sDdt6K<~s~oq7+$`bU=Wbn}H!A9B36m6u z85fr=P6$T+*AG765^>Qbx_+tsXR&cx{nA7H?k|XgucYafJ$@o%(DQF}5=V-%y{9Rb z3>c-vqs-OZ?aJiVQ*d< zpSQ*58=MTe5SmccHr&AR^Tf@Lm+}6KEmg||*^Tb8672xs7BMxgSYKYsCqQ^8nz!xx_&PE5hNtZUWHwkU{)OF(4mAm zHJq&gocy+GtFbM>GHwXJ#?W}fe!#b1o)A9cM$z!YDzrVtE^XPt)rgZwK z@N?DMBX<3TEz`RY!w-<#AY=wacu#z~J}K-mSBCROGhVdU-?Lh=&0Hm2zxw!+!XD)x z-!+f>hdWh`uuUjEX+<%MMFVM!G(PeAo4-Gd8S22y1kAj!;}j%?a1NS2@MJH3lzskG z_h!V=0{V)khi>*e>^SWwkNSAZd6wk1(!9V`pA`H6t%b}7?N5hNZ@+jvFbkC3(=_y5 zzxvz_MJzVdn;|l8a;ho42%Lldm&%iQ$m~H+_ zW8XH#`!pVIyH?wL3jSHaCVOfeeRs8Tzx6XWJ#TL`$^voJFS%e^7v~f9DIo)1|9sb^ z2;Qgh<&6EJ*;W8-7ae^2AFKbc&(_f=Ds1^+dXf*Xx<1s#-sHz|e*MGLA$hGW7d-R& zeqlw_My!AGp$EH;R*1EoKK5;%%M0oXomx(}HMEAcsJ-O@)+-n^2 zQ9T*yEdI>%f~H*uWxTs>6L%t_-nLbrdmvr0r13~$uY&&YW%L)UrW21;3i@QH=IqpO z%lI;W%sEhS4kg`xD1pey1+ZVdrVrg8_-oZ&@|5KlMiDf{YiWO(^`zBp9Zl%e^@%wC zRi_GHEp+>JeLvC-sSa7@5EJ$1tN8DI{nrmXI+U@kz}i+`4=eyoa(rW$`XS?!So|J; zPXL9J++n`MOP*Wk$xux5M=E*|2@9vXf@EqX$D$=LGYx-!ddV5i>@#_QS_#$3&|4Nyz zc>OQw3;7zr^&}4v;}vAiQA!@dwnC}T_G&jClu@Z)dnGL&d#>t&o=K@Ac4WM+uCU{B z62CV5uHFLGJLhl8iWd0!%VJKz;NT1EFWkXz4Tp40-0NJ*CgaX_%Rk{4pW%HhbGE%O z-wL{rU6oEeR6k}0P~3;c%jKUCPG_^$!RCQXcHC_q;^{=L!d|JGclzb759EL^^GmVw z$HYGLWS$=<&`i2Mb$d-4|1kT0mM|XLKIhId;L>kSOs{|(Qr#H@dW8S8w_KNq{DCj5 zQ?iC$8D*DHntoEBc(s?OG&=RaX}nVSix2~2N0@q@%6I7c)%i{L{^g>VxY>Rdp;Y+H znehr|AqrW7`l=5s2C)9YTLF$I(nwoxUON3s(}Q>is`fhY0tD1KX42N?-Kl z!mk=#hUmNISOFlE3ZE0x!y{!*jKl}cXAz?kFncTL4 zED$s18<0?7Ey0X07Y{$^9^JBy>1pdkn|9-ylz4Z9rZ-JrUFYw>Ya#ZNxQwU->$3CG zpG~n#DCA(ARoXuQanX3x^_@2M6=ajM*&oKtI4654g4E=q7NU^J_M}9PpK}0=G`^gfkKv#HN4j~x zOG~nzH^MA(_nhLtLr+KJ{R1`&WsMdMw^?O-yZ!Ono6+PFV0IqR!Ybh(kI zC&y>r#rs&&^pf5m(0H|zYCSJvOVKw)EK}c^G&r*Nykh?rKKkU0 zyyc(2M_gFa^d(seFt**~7K|%1+M$nN#KV~*U`GYYt!5If!S`UfuG5$AX=mLmXHO|} z;Lodz9q>MubbVa$AtHrgX9M&IiM$1A15q7aR%3ajj}9&0d9Kmog0m|{$5#Guhw?7HE7EV=QbDPjFeeR(^tIeQO9n#z0szK-8+Y=eyc7I zq?cEy?ZmCevcH!!$HMoP!?wVz>6w)-Ek(T3c6}MJIc1djx=qV%@>tK@iT7#xYikdx zQd5&gA~mYl$8UcVi`qDMtlO3KDcyynAm&tr$w z(b0a%d|B7dn;*KH>gC zn@HF`(xh1yu8u7mbf>Uwy5*JkOWs?!^R-V3`xV+anpx|HBU$qdG(oasf6R+fmkt}R zC_l|6{AJcf#P{{Vq@pchWH`-~lYvqMM7BTJb9vfqu`V{Ze^vxOl z*aoW?ENOh%wMWHy$1E)F`c?gd?C48AiMYMkS%a;e=3B3Nlu@Yk7zaiF(s+dBu_fba z!-xZaip=V;tz)k)Hi>vt-Fv82Ql0Co47z?*oHM<_rcB)Xq-6V@`DfQWT=13w`wMbK z;VE7odrO|>%?m|2NJ~MQ zo~5q1?K`;oKeNzWLx$AJ8gv`K?@;vB?}*+7%x4cBSGQ#^gPwT*eB1x3_DOhaHZ7r4 z$%r#{=kY$4bo<50E0(`u4i=)`d>{J#Qp#s@CKCrFqoxmCzpnDZpBW=i7n~Fcu{1v4 z_37;c@3u6L>O0fVYf$U}OGQ5*Ms7STJwYq+$qRT2;-e7XaF<*Cu&WsS1sO`>_VGg; zeo1-l_Z?3%pSe7*?AoED#qmCk4|$!-KgIDtXGGv{@SV!#@Mfp?cZpkWJnhU7|ILAH zo-{r~*RKzGL3|~Q5)qFHJQ>ZLL=Ya?lKLxg#yY#D9xHn-$$w0dN6m*{7x~L2^UF7K zZgncPmd&0q-(PHVab1Y@Rka8^XIMADcEuU9*A375G{E~<()7$3{oNL;7c6OfQpyK6 zW?TSo!g=W6lR_*WtxF+b{x=OgKjsg&+cbVzgA=7DDfZQ&@#-osx%wC|EsJe;XMf!Z z7ONhg{`j+GJ3|^Lcm4X2AAA@A)1gw!Hs5VG$1Gy{dV}>xUR*_-G(PFauNfon;FM|Q z{7BvBRZVMWc|4nQ*f`ECY*|QQx2f0;mySJ>*LtUz#mw6MV`*HG47^XbPnYqn$*-W_ zpEKjN9X5}*Ot5+IuF#$PCJE{H?zi|FIRzi2@k%>>VJ;TDo-xcA)-0X3nKUik*5QkN z;_)I+nq7~mi}>nx8$Nr!|02u9c85Qlc`$e^-p7*0kGe~fz5`nstYt1tdkVQ8`tjYo z&%UL%_wKA-VG!1XC0(Dc@&kQA64k-CtC!sMiIW#3HUk!h`0=&!XyLn=P|D z{}v^;(THd~(#r>EoA7=Z@9H&(bY1h*DJ5%C-dgr0-XYE_GyVFf&zoVkz_$DBtQ(e! zecbVT8h_4=&-PfoU`gZCMLuywr>~6OkX|jhq{XVZrVAfh`dT88z3!Eb3dlT66F&|= zE$g8rJjOp4|Bcga<$^#S%9a>b2D8hNG3p0WC3|HmL=g~RfE z!yfH1&YX$3O1v|@{_|law3rjo{^i~K|zLhPR8falSU$sGS#Q=%d-GRE0SzsuJ(7_@o9;cehAbZtU3lPwIQT&yA0*UsF8Ajgj7-3{AAL zZ~AY!9pRQc-Fa=%KINhh4(@|Eu%z+mL*DaKPbOP%x@FgE&O=H$VbGrs`nkf5`iS>`Lt-padC>ho&d! zV%7aN)#po;f5W%uX1NLJgZs%k+0HI(P^ef`_(!Bm)`XYdQy09nTJdu77@_(rYSzsP4=nasPy~R;WjPq{8>>i6>&YbYjbMPwiw46b=8SxVn0IzoQ6P2I^CeiG6t7Q6 zb{It9`R9?wKYwhvZq^u+=q01-e)10=ga~MUR33}m`EBas7pTEzA>*4>%bTwKkL(Ms zWfy!U;PTp#X9~Sq?w;wz0yj=O?v4C9ajR2(g-oTvWbf{-Eop<(Im3)>MOSri(pi!dOn=0YQt%zIy=-_X&NXd|o`LQDmc8#EEE| zy7dYw&L=R=Gbnt{=t#$eUnNeyoA)l9evf*4wT%bD&cf=SwsGge4qCRdUDiE3@RjZT zTKEKAA1ia4GV|;Z*M_-tY2>e}kBbPn%YJvS?s{bCXTJLB1M5!x=H|htG~uOrgU>%x z)~6(Ud>G^VtM1UCi>(Y8X?!#$G4`^mzU3aHu}cm#dNXVwXQgZHtd@##aJX`0=p>(43uAby4hDMiXI3kD{?d+^IKZAt6e9rKWX}G z;wH6;P`dpzzyB-wEIz{xTS`j0J**7W&0Y`uo2^9FWCf^Jrt}wGFPEPMt9`-p0c{i@ zU;9h`QhJTrCH-Eyf3%lJ+1vAB#pQ|zgYu_Y2X{+Z)$gO7V&6gpPU96LpJ4AIIMoxh zJM6p%e;G4$3S@S}07_{i%jx>Hx359}@{d>g{bJfDcD))#on09&5xal#VaJoVQm2)( zT2=c|G52w{*Rdb4r19!kUJLJEd}Z{gi=RCgTC6@cD!J;EUcrbHOB%1V_A=r2X~7+{jX2FViUbTh zTGzX4mpbmi5yR1CFCb1DpY-w)S`54I5Q_q}F=RfEKoA;A8lO0O75fytd=sW-bvtHq zizUya0&bX0Yn7Q1m||mt5N7Qx>~^o(W0R02hHqo1zEjN8;P>2kRO1VLb`O^n!uRr( z-1WhXop$?ejbUhj^TmW`AVSI?pFQz3dHU){9c;s%oN=>#l&LsZ?b;8^o0m&3v|oED zWqipu?G$kW#82a;<%t;k4SNqf+&~Ss3Dil~r>lI$Iw3!i-w-b9oy)4tJ#x>K9-;I*rE!_Y1u+2k! z!mq`w(QC$aF`awG$f$m?Fa<;Sw@rw&e-daJbs&Ap{$lwR>vZY%D9bbUnv2u5pTB~- zV4a-u`9*FF1%M7H=dm4pC5@Nn$A6{Y#L8{DU37a`nsezB^e$9q`001T-^Xi~yVtVT zF}IoCn_D#QS93K!L)WL9eX6`aG`?B2biHWm*7I7B?UD|)8ddmQSTXNH*N^=!Ucb9C z@ld|iJu+Ez>zyw?5BY8xv)g=?^Ri>r5!KqS)8ERja9dtC&J<9>_(|EYYq4NF+ z*ayVlvtuMTWE;W>903d`!<+^_Va{B8D*gga6|-X%A|oY@kLGuE`D-Qj(LvgQ4?2|5 z%3kuh3e7WU4KLJQawD*WU5fLep)*WJ)k73?{W)t-Xg{h<3T=359&2v2e@fToqi)Ss z9PHJ#*v(4o9@R2Va=sn4KR9niY+q2(_sd?C{$ritUpMg9F#pDQA4|IZH2rf<-XPyY zwkzfuYTB6wTcBFf?GeN8y6Z1tpNht#EdSVRKK+Ao&|S{+B-S#L8Hu{*8K%W%tgU;^ z!y=@?@Bu;f{wVU>kcu?k?8{GaJYMwmwI;8Z85>2lbovw0Xq-ZS@6Y_N`1xg?R*BDc zeac<7Pk$6AIw_O1GUuj8Dfy*j5YD%lKwPvetPzCl}sK6L%U^2%Ipp`nzb z-)}p6^)ZiwPaT504Luw5eQ6W?zQKWjops|YTBU8@KEXO6Rxa3LeOS>MA$NMy1(x1A=KlsLCv%YIu7k%^CczT(0B~Da+ zr#N5IzwW8A*Vdo2o+fkb`ub$Oy@(4-8lQIZ#EOYFw3W5~n?C?^>|hN;4yafwimqP_ zKe6(GT30tdm(O_&k<$d$o~Q zVtADM{o3*;j&c)*uN9&eo1jv1*N4AX&f!E20dY5IHS{dxgTWm9P)43{f3EadoM&6; zeWM)}dz>)Mlc4Z>n^`7z%AeoXbo0p3Wn=QsxP-r^@d(Qwzy;dek>O_#M!rIfp6oXW zT7++ya{WD#yRYM=kH z$0XKu{KDqeYZd!io$t5pN9|d0=G%*}nHS$bPi@3ZplBiT6-eJHaQ_^?}F{$yCBZq_d`RCi!?S3vCn+}>vMC(z8?5Jjb99XmHE+$nSX#7 z0B|I^k8kEK>H2bN{DKySmC3rCi3u&alwere;e4Xy^eNUxeZPDwj;$+`f83cPUL#Bv zFK+#xshgD|4;{a!+bf2?EdN?Dhy&&0-BV%dnljRooFkIq(}aZl^S+6P9GD~ zzI~Mgg8Q@5<6Zyyz=;``gPAtMdN;^E7o!zqvhy}0cG$-z_s{6H@n(&4_e%27UmN>I z-73bnvSqc|Kbw>o{>>p~`rFgbe!LRQr(|UU-+UCm{zu8FNn+9bCdOZe3`DY`5Jm}^ zQ-OIGO|r4Texsy$`P-S#IO=ffUd8*LkRl~IB&Q_)tYtjwtiyVTge<{)K++$&*n_ZB z#TdEFF_YU%sLFA{ML-aTa3aNJ4UQd4z2MtOkpQE-XCZ`X-|El^i{o| zFP@svgAc#3{s3NryjQS>hRG(#`Ih)^Vkk<}OW*QQY@7$_@xA)9Ge2%zHC^X<=X%P` z2sLM%#{a)yKX8v!Y!NB5*0~<9bz-GO++3fS&Q)$G@_*>|DDy9SEsZ=z{Z8__RPoV& z)lKQWc(+TKMf8pzA%kys2*&UIPFmFstLbO7!2KPwes|=4yq~M~^|TuGzMJh`&}e7< z46|lfGW~w(Uz?D~ngZ z>8>BR=cY!K7&3JD6>FQsET^$+1{YAQ*Wv3AmdCi{CC~sY9kQD%yE~9_FX}EU0TbPS zy2~S!iQ?=tcTYq6uQOI#?_1EY?Squ9>ySRDbKkigzBR}``LtQ@UC*nJ!TVTp;{~3D z(>uuNNvip$;^nnA}U*aBO7UH$#lA}RA{<;^t;Ud8(nDJzDy-Br^n&Zy{^;)N$P!uwd#?Gd(z9GLOt z%ZxKm8LTb!WUe5J%(o97{eEra9eLJHZa<7>a%;gagHzr$eX>&@cwGTZd$=)j*Se@x zOzxfaznSkX=l;xRYP{OQY5n0r8=V{10M}bT-}fl)yrFfCsr#ZQUc{&LkH?kiFR`n$ z)a5BR?N#$5F&-pkG^p9k;wAG{>1nZcuH}j3m;#D@OKEy3YZC7LMfmIiZv98UUz_%8 z@BOILn{Lm)h-YbQb0aT9Nz;#&!QA!%to9#4?X98BECyYlRQ(10pu6?P>>pS;cOKX7 zA(kPFoxQ)F_nn9|qVei(zqQ6!s+6~ig?slcSH>jiV=sr3b7m{zrw$9I?O5C4h5c#| z)1b({dllzSaN|+6N4hh8MD}GE!9>v^nhtUwP6FoNYc9|A+B-)&cC(oi-{s($&5lPA zBwe5M_J(#=5RFG$`w?Ux*QY_>LtkpQPq0`r(y4TV`x%|_8M;2@@xfl}!(QQ*cZh31 z{(=2G_Jmlk-BHEWKB7obyieo(Uyx7O!!YxlJ?{ZqDU*FW?{IMP!Hd14>JNEro_wYT zeiOZLVxG=R!c1lkaV*|$M5tna$-GX5I(l83VY>cW?&%-5J&DKXX?lr~N1ErWKm(99 z2g8_=2k~RfZ55LZPUB&Dj87g9mD>w|N%^;s*#Nt~Lnf7`kMeIoAJhCI-e2dIZ@HWA z?Y?rsaQl_xBd_{>O6`PLVrJD2t^Vtw*%Gg(eL9sns<8WLJi5zU?p>4U_e(F&blDXZ zslu##4f$mCXWeb9xoe*14<6E15jVsqX#C3j!Cv#pBlZdI`C-h!!`jr#gy>DX61GmW z-Si{TyxXMQmGKE0ml!{Yct7|CQdX!NYI<_sT-Uvy`#Bjm^4Wmj#_T&(=ueYcwqb9I zmif6jo_GA}&cBFQn_Y+1?I*hae_;=z#1SKJHG9QKeYPCt6kg7-)&je^$9Jt?9qqQB z{f1o8d?5Y!>LIs4$1wIDiGM@90%qpOI!$fkc8Gt5pJ&COM(^ux@Ec}(&-7zyynm;L zbInA&Kl6&U%kCoi2JUO^KfGm&cl+=@-Tv(B6UYY)WON8vF0e$*Cp1Bb{WQKMDTBEeFfPbkZY;DAFWa~ipyd_gXhh> z9no)>Ly28ALW|E-eDU{!#*_2oQ5t@X{e0_bYSrnM;lsQ9E*1A{7q*jbpEAAK>+H&Z zeyI>z{$u`)O?o+Oo);ZiV8)v|h-@!a~j_+#(d*ZJO7QVcdo5`AK&74-agwmSgeRYnzaS# z-*|h(wHjZ|y04AeJ>t}>K_l=!mUREo9r#8DxKe*BL06RxqZ)?}U}M>`H%K zp>vakI zC5=y+E5N?izdaxgo33($?tt5>V&?+vGud6MQ#o$jz~;A!*xvbKWzVd)Z|;Od_)wiAo2ZQ9jk zmc4P`%-WqBAU?YN*%`kupXDb5d&85V1z9mqqDEv-7b(2=KT~>kd1Lpa*p;hVTinjX537oZKh&ypF# zbFj(+bzgRMo!dLJm@mmwtrP228aKeHOfPH=jbAEx$0c*1&Ogz~wJv(Sa0w5-+pCe) zZZpI&@%W8W%kvZ)xZcVoq0#ViP4PaBkL4gP{R}4%!zp1fmmk2;6Z1B`}CKOYR@sxZX7*hfutaB~4GlulkdRe0+d-x^JJ|s=rO| zzQMU~H2+fYmm+S5-*e-|xmHc)du^!h<_5309c*ZgEvdnvo}?skY%VC?}n&DYO+*!ZyZmNiJP2KN(wY-ky3JN?4< zqH}7+3g(0AVsG(Vm+JCFfAJi$A`GM;XceK)N3f$htJ_g@|7KTSK#sr&`D~(gt3w*M znOgB~Q*)cxsE`R(uHSxRd%pB+d(>%WQOlX%%m;M`Mt#5Vpzj`ya)Ho)S2-d6;%gRGz z=F+>lcTOaZ?Ch|q*Uy}x`rXPoeJ>zO^( zu6)6IvE-%)j#WN;h5eq)VG$~*u5{v-;f_xu&wlcmX)^CY(DwIVSC}G>o4wyRck5tc zG~>yTH~XhOQJkY5{LCfkVYM*pbv>WFdJxdT8lT6K#;+_7*lTI!qb82`YZbTY(#NGH zkt2>9ZW`Rp2ytRb=6i;}h05 zM0UaqGuY+CD+T{MkU<#0*e06yP^atDMgMbUvUEH%FMN676DBjxUwVHzkDD#F&pET{ zhvus~nnzf7?)tLTDR;b|w!QezcgK=#V}_^o53Ig|*S?lYzVXS8^t$_Vc_!xTHGloH z&C92LP|P19PHuX!`WAL2BRd@UGCcwu0sF16-)qvx;v_I4AtjARSbpKY1w>w{?`Oa_ zpYP1@64)?7%uX%hcYLGq(fyax`a)YhyEXIX{ITa2n{0VqsZ90H)rKSW9h^H9Nj^2s zGPHHmBHb(fQLNXY+nW>eT$?u0_>|=zd#$TI2Ky?*I`v_4X@s=mD&O+>2kVV?HuiQN zWfHy7a&V<(>$}sxrSa>cPe{%&$_o8oUV=i+wfO`dJ7HDIwXIp`)*i)$lLf0 zjfbTnmp-vzbQfqYZ$W)AW@)#)hCZvT!|r*^sT8IVpDH<&Bp(u@(C&BY=#kC10b z!YX}`I^>Qk(--5JXH-942Fb%7_rGp5J%9UFSrck1zNXtlk5}>jvZ^%Wv&nlj*|8$7 zLs#=%4MUIiyjNbaUjU+|@sR#z)jb-`;ISUcH zFi``r9Xv#??ANV+e?~%+c|~;u%B@qsrt72oKd0q2aFHL=8jviy=43!C``sV7>UG3P zqlA%1PR@<*r`R9i$M|!tYG12k95*4dzMkv@U)xFuMR&_lYnjqb1P zH?7azlf2n`IG?XP>j_c#F&bI&PWwCpX;1kl+ z2igOCJ7ry_%`SL|M!o&Y_6mEgz5NHP+y^s~jGV0@c6VHLJYvQNL5HWGkz79INN51t zT(v7*`U5Q)h^Gkgyfp78E!1WAcU|fSnv1oJq~RuAXh z4_yquanT3%p3r|bnoM?TLyPZ`%?DYoy<(a?+9_@dGIX%XihY$*8(1w`xa~mlz7I)w zU#k8AS)jk{AwCnSMFhv zF_ts(ZkaKx`tK)Lr+R&=`7~1bb434+k?+m}C`rDY_;cBc{mDJ%)GasTq?5Z0@_rbr z*w0xVzvlh`SwPOlgYl~Vq2DL9zoKe~kdx|gPDmY%`W+e{zg!~xVaBuH4*84>zP@ zcD(y?2#rJTsIg48y~PWwGgHSJZC*A1v~6hPmDuwaLcJzkzPH>l{y}<^{x`Gi@IKvs z*2mN)J}%ylBlbMe0wi-AY&PN}f-OmZ19Q3DD@RESX#B$Z0;N4tSX_Pp_?09ojFjUp zzelA#3mrM#CjR`jGpCpJIF3&pNISCWn{!XQxNc>AFL)Pm#QR@)=2`H2x_!d-8gTkh zCVD+u?lZzXGk>ZQslKnpKdVu{+O>e`zAZIzkguFRct4g+V_WU@`6v_AdV?T z2K6t{IMZt8D)au03N0Ol_ZvKK-#2W{W{XYZO&7G8)<|%_W+8b^tWQ{Zr+Ed;Vvrrm27U=%}8jzMLuP{>iSqRF|)IOe_o5 za=^(TBv&Jlx#II5m7vKl|1~}nW`+TxEHD!Tkr!x#+9EF+w9?=I8b4Zvnxi>NfT_#> z75wNY^Ti1%*s=-*?7q1ciML$XbbL(DpLy2c_y4**V)J6f;)Q-io0w$Saofv$vgTjY zL$}jtkUIZfeyQU}n-ym7vbze9Z6{v+>;3|7C;PigVQc<<|7jCj1l0eU{;GI^*QCf+ zlF2%I-?NxGd%0b(-Pl=E2ai*%AI_QfW;dG8&ribk97IB3KMa`t#yujz>j(Q1;sRs; zMh=uEtt;~^L?wpG?E$uS^{dHwQv4iDUYRYO^tN_ci-v;hpM~)P4tJ)0$mj!{5YZ$V zROl0t$OdFc5QKs9c7VSGztt`u@!jalZ*Q%eX&k*Uz4H(6(t`dQ)Ie4!>KzB=8w(8hEnecdHF& z#uuM(WsbsMrt#_SAL1Uzz{jH)UKqykjP`kdG#=^wWxh;ZLceFVhg;cgnQt`Ds?gVI zTfSbQsY>Ic{TJm?tI0m%L-A$S^#k?0yO<@qgbwmrxKpwI7je+_>lVLIx6VvV@0_3b zu$I-v-@{vEy}g@&^>yIcA7gtrt4pO;q`B-rJ~QP{(72=cJdID7-?J|dwTXS5E57P$ z=`EMsW|TIbcdl%jE8@nI#-9`8LA^H+jk^BV#UDotQ8-GgUZ3>i&zzA9p!ov+o`?*w za$O_^p;573$?Zn1^)yTC<5D5o>Y!r2U~oeGn=YeA{vUH!0T;#g{nuxAcXt&p2w+pP=Qn_}e~#sS3c=KK4zGGOJVidORn z9%{et%_Ge`K!;{#HdUv7a7e%0(r)U(L5@gQEXn=^eA#ag2-BAjpD@1}7cU2I+(&J< zfbQ)>jV!QXJk@L3AeO|;J&B8K99dj%W4rcWEoW8EWpZ|IV@(`(+wo%oWqQ=Jj3`&* zdiCInTd}=a66fQD>A|lbV6BlK)mpxHFl%T0C`(j$4>xQBlwDJc7N}M#+952U>aXt= z=f1>yy8JeY^1Fe;uqFw-RXCLxezPSfZ3*z*<+4A;#%)MEhUhDhGNUPrjqAhxez5#~ zs5L9}xy8(ECina^yaQ%H=~yjFd+;n_eiL>brX?Ttv6g!Z)*qr` zN)jI*uhUr?us%-6e}K8)VHAD2Ki>{**|@h(E~jNr>bMLVTe~AZb#dE}=Ew*2m%;Baifa*XZ}a{CFKp62F}CnSWj#_!DdjV`q1D?IA<$efHn+ z?@p{+ADbW9@1P|Lsks7-z45mITXId!!1}Zs5**!KPnISthMcyD;I&%TWA_$7SlIb(!aAwa%&FwABl~ z{>AH9lI=4_U)ubq_wn8A@|(@u89xj4aGLwxyI#8iFP!imSwDMxGvDR*2l%qf5fxLC z_(+)}*8T@uM|d}9g`!~n(AExv>-R|6crf-#-Nuy>$%MKowH&%09~g4jYSoj!heGiB z(yYvYcJp6bMg}%29OLpzh1anp@w2Tk{q~t1#fLC%NAp^7pjp9MVOFUL?*l;M5gy+{ z`dfRXNVRK8JmTrYXT2ijxl6J>;r1IR-=ydYKuqE@o*wi*l2Rj|#acaGJ0!GyzkR_e zj)}RvrXn@710U!KzR%OeeO9kJJJ)J+QoP6Si7xKsb0i*P^e21WlQpHcXn8@;CXn^w zZ?b+l`U~g*+zltAfW~Bd$yhI6nH_j&yA~{1?epgCsNawmD%Ljy%<|)-XMJFmFtb`m zzfZxYUC!Wv-h?>_$duKeB`ZH3IAh13qK)r=8Ay{P?@^Y$^nyqty`F~6=jhSHx_5|P z7`hil=#$rXY&uw4g*I`0_s?P z;aoIGGe4}Fv(&{S-~54b@hN_qvm2s|Uu--E$0-@BCh6%%(U6%nfWH#6`Xs87>w=7` ztE`s1PE+mc)mgKz-279;PZr*?!hT`%(j#m8Z%AXe1-_H*VarRBmu;xCav)X=>%BcF zTw->qB;PML|1sKsG$l=F8_6I!_#a`i8?TV%M%FLvzZn(}()Maeu3&yo-27(9hKYWv z_;)cTgHG=i3Hsn#9`NjhA5! zlkE}aPh;XM!ZMk}lN0m>nJib1EQw#3p2o#%=tw7wD3IWORL+CG*(u}(rX=yoO>bLD ztBjy90gc6Yl)8B63_^O(TsqGa;tiM|L9g=|PU%$c5BWZ0;w_*jL3hKvE6h*&{kNNi zzT82w{+yw&;Tkh1@rtp7vKtTBN6bD(nEwxQR%dA(Cxc}-J}G-C1HkOY1LKWe73NNj z28iZ!?JB~MD*x)te&_!Vv5sjlut==?^pVUR`rH2oud!Yt(~AEMevqb+Cu3lYfPt^W zFKmB-`7ZZ-n!X(sSm3Cy{~P*huiDT?r2Q+q@fq9G!8LpAiMKpu8Mr9!%iThuI>FrR z#&68ts6grL#@Ab|%^}haetUr0PLazN86<-M_MIX_U;r^5Zpbgp@heV|L-E ziK>W_Gxo0c-fPbw%`W;%>tS7b{eOuMipwF?#cynUP@8^A%9@fdn_r;_^IVfrJ68|o zyu~30&YGGu&Ix{i9eA{NcMw0`Ncsx<%W}lW#6*B-%3XMPz1P1j4q7Z<79D%7$eTzZ zdW!Kc!D4n(d&S_fv%O04?Fz-*0&#WBuh&to{C5AU^_!D($tOtqF*Y05{#kT%0Ol?I z)SAPEvLWe}iP~|0vKHnyS)cszIQ=oA_OCbpR&F=DV=J(v#|0 zI`1A^qFolcn#+Ifq*JQ6f4ki**nH9hyu0IVo;r0xmN+DJj2#|kwz4-~$C9K6aFbl? zX^fi>(@ZTQRL)Wtzu5Sj{vHh2|K*<=Z~U#dJY=wez22 zzpN9gl_)T4>`Ki(YE9cz{P=uj4a*e|2mM`GzMW>ijl?G`PYlyfjD(RE@sW;Cf4te7 z(o61|u`yb7_H)wP3bhJO z)3cr3-V4e<;qk)Ow-DcF|JK#NFc$_MFszUFS4(hrYAyggcd)3uscZT_-1NunEw1%g zaBc;R33IBJ$<#Nn*_2dmc$T6Sg#|M3aTS-e`WccXd95ApBF`i1$|7e@Hd-tu|fLE<4raBE8REzTkQCqB-720 zUbk}1Y|;atC)=A7@{(VA>)M~f{2`>D!2k20MiFG+xT$AUj9DKctiK>r#EX(5ATwbV zDxI&&*UKdR<+EpLiNVZVGm#MNd#-X=zBVS$4}G^>y7yFQMxm!M_)IaYpFySteeCvL z@Mzp3Cax@AC-Do}mq0(rdh?>FMCb8>&pb+P2hkcvzrT+4VoBC7%r9*HC#(-)9(pL% zi?Bl2ki6p^BX37ntQBXwVvyMd>#w7O5I2_6@#~j|bT&YMn(si9p?vpL&?j$r=XH8EbWz3|jsB~3WOw~7bt^k${v2Fy;A=BnpHsj6KO>WGIi+_xTBlg)Ek*I! z*F5Ky<9)I{!sF9;d9IzSC(TMC@fxBJ;RHwEGT<|`C}B@EoykEY5>+Nwu6XNM_kybV zrwg8nEKx@@PDngCp&x|3dYSzpYpzV8t`MjwMMSMkk0_uVb8k5Z^k5qBW1-LgE)5|3dme+KCfn{qo9pl=cuq zft&|vxdYJ0Z`Y`{_6R9tI_sYmE0#6t*a`c+X`!Q!-i5StoIN8U^-6rh5_tXN#In8< zd_tYVo4d8x-J!eS{DCmNx#TL?7F^er)XC;_{2k@3F}fGpMD~w-`VQveMyYi&_}*f2 zWx4RM#~Ud-Z4`FYo8bgju)Dy*qH`am@WGRaB335$?Um~?cc+*ZEmIu(8B3Br!u=^m zUjaohTNFGVa-UR)fI{pJEE>a376|tCO!-pJ&NA`g+HOm|FKgD#jX38S7hl-KF}>mT zrcZ~A*X;Yk*Itt5&^qn>9zOqDwD7On?{{YCZ6#`Lepb_B9;VYqUl0 zkkyl?&kx?!gpc3Y^)uhOyj9RiOl(g{QOcdF-%$VdU+w^@j8~$`9X|47H?^h^~2lcnGfgFm-@%Y)LTo^>uz|b+Whs$ zp**wdY4&mM`?B8i#9?L*vocc-h0on<#YaEG%zp2TouNGULUqm`#Nw!C-zQVD}!%PXH@6njt{EZuJY^&`CH zqXE6_k_P5qo!fbHEVgFSzlv)oTSQwdby-@a)APN(@H&>GzmUxkaVXo*j~tFzo{ z-|`BMvCDpYmReF-Gk=Nq$@Us9pKt~hT0?sVU{iZjE!6iR>*uBco+J+YYZ_*6pd8V+ z)(&t=$CG{XR6i%vR9)u%cKqRXjhyBcDiyRZrCk@K^#z9kKKFhMG~4>L)25zF6sPd| zM;^Ji_h^URzVFYpO>hrtXTIxWCO%KngRxn}#ABq{FMKivu|TO056QdqSsA+a9E@1n zKc?qNP-p0~?+^o7zr6Z^wu@kWoFO`bi$22RiO;{GqqThFrOKvrx9l2TQ|&G`{+`FC z4w^jiYQMK0^U6vy4IY-{QOL4dRis;w{^R;3cUo_@q06HECMRw!!|UAi)Tf{5IW4g} zeUk4-IUqLPO7{pvf7~evt@~-wz+ds9dv1r=&Bs0L7hK;(KA~HGcH6H~W;b-llQ6%C z(|5Wt7CMe8HZIkcCtmR7^7@#%{k;1xj<`12;@+F1LiEnr@hL39a-ErQ(S6bS!Mm2G zC|}%et?^T_9VEX9_lFey<3ibW{#2BZ|FeC?$oIECq$xv(78sJ}-?Crl50_5t5L?z-XXyEPVHJu?@XC)&L$UbexvNBHEFGNpQ3Jb$E& zyq>RIT;~Pl@p{hSg+3Q^nzte2n~z4Y<2Bzs&=vj^BH<57pX{_J#Mnt~<@yL-a zm6Ld7jh1VMP|l1OluCTwghElJaB`sAlO?9h9U5f@O|o@HfUU2To>uDjd5iE`FROp( zobMi9f6wE`9*#-rYd78Abk(te&r^z}Y4kPzo%Hs~W$%K$GfX`KARC=;9szM;DIKpN z_Mka6Ckm?{ghwcehi%1yg&^MkLzzIY$H4ZIC0Uvs{9S!onxq%>NA}K_u;+9{>FmQIPes=|PSy_IY&ddt%~OEqssH zA2ITD>$Pc~E$X&7Qj)KJVf`-@FXHCTuLUoxR?U6rxW#hYhVMwE+G&>_#UZOPTkMenk#_G+pV}^+6})j|EsS zmSp{Geqz4MGvC|>E9EHnS1|WZE!)(7zHNT5dnKbM<0D0nHYxJ^)d0tRCAS@3-g&DV zUdNKeFC-t8l-8op*?|b1^mTQ%wSFxOdN$BzcNtH6r^2;$4rUl>cerwjAWYINw^ z#aWi~UE2R?Sbw%=T`gbz!t%m+dxVcxfQjs%?9zAs)F_3ulm66L)%O|s*(;Z&v&X>D zPw|zaiY*r0uTGeLLh_b7%F#S@`N`g!hgi;UKJ%YWubqw|=EQpm@5cGMtI`Vh?bf1g z%3ZvUB}q?Vd}8D=z2<2I>*StER8|d~)dg#D#Y;a#sZbm+J!n69TU*=6@yWLzn2piQ zCloK>YSX;_dB=74{ylrE)pb+mFX(S%`;3v#TzpBspOLv->t~p|Y`LPX&!PVz<5J41 zKBm?B@G!N@qYs2+3xi6ba2s$c^M;$9X?%lxzU3#EDTw!ihu$6Lm^ZT5>~V*i?5bY* z3SP&OY!91m#>ivixDnCm$|GU@HSs^m0&#QjQNTBpuE&xyo{e-W;bS^~_iWof#m)C2 zB9dOhCz+NN1}S4xQ~bf3%6d`cE;ppffA*`o29U-1@BQ(>K2JvG6WGqBMD^c%SSa@^6fR(GDo0-gQZ3(LH6pF8%A3e-h z=To1ckx$lV74_B3-}*g&Sw6MdGsn;iE$cf^i(Jl!Pndo}`rCrie{c@(IO>1cM+zhw z*l7B9qp);%(D_)^TNbO@zk2mOSI;wi_zahi;-qvywx}4DL`^1Nb z(K+(xk7y&-KNiaMRn!iC_0S@?bkY09Nx7_ggyBLiHA);vTw!32lR~wUHv7@-^S|;eQ}!pHP%?2 z8lkk_(>!6_uZ4BCB7MGn9hKDG<%?tV*SwAMwEXuyUO(&6IXEWYO@|HlR-~S_O(}%e zu_Wm!+&;PFpA;>FXm$I;czp;lEXYDNQ%fD~eHX>AH5+)KTE-uW;dU*{SavtPTG+5We+_dKN4gP=s`cdq#*IIm=7 z-u9qI1ngLa`^@U2jzZDW~cH?as2ht(td;e44~7g?=h(pQyHq*8i;$(%vhI ztOtLS^~psazSSdGFJGC{c%;qF=;|9G|J6plj=-DZ6FAQyfYK_Y?E_p7_ASgq;VN1_ z>gd)lg+BlbJ#SiVRf_DzN2g0KesUsJEY1ksmzk)Qep;q2%+h7c8<{SAwhNqX~L1)T45f6rHpWDtHBt1qB~U^>{#zf zMQu&Wl^)RS&%I|p0Ilw^B_?In5+F@T!?0;@@9!kKxs`WyLvvd@8f+Wx8& z)jrr|mOdo_+sJ;7s6zeoOYX7xKgVX-?%!hF@mp`p6llFJnxOniLj(qeJ z#xKNgVx+f1VY;m8rd5m5><)$%DcaDtjE0_VtlA73mEmrmbiG8~#)ZFV;@pPgl`5~L zt@|STUk-W4&xO+UE9}4lGc}&-T|s=*9w$Uog`|P?Q~zowW>2*zaZSML}UhD36PVW$9rS>zxR@99L zV9T`2H+x(jU2MF^Ebc0B|HP&7WDvS*jn-*(wy_UJlq zO;6vctBqQhe}u=oA^H*a5T>mVdc`t{g85y0aM-8q=bcRVe@t67Vp^ysUml+z=_!m? zNIto!`x@{;h7_z_W{+8{mn>7N73~>NdYXOm;|{m)b=~TS_czvabbMmj!E{mV5XH-j z?~mj4@AeTzt2aMoGt=C*Lg}j$hTwIwJ^Jlq+^fl*vgf=hs}JKvw2Z|Jo5?I68Dq9$ z)`kNn5|1!_jg_b3br}~vc3*Ml&j{O-8m9m|g;f^Fm*?E~UjzE4Cw;i|@{>mr-pVYw z!TMg}ZO7n&S(iK9@Y;;mN%|Qo?_k8hTm|$rJu70U1Vm(XN#e^cd8AKg0g_iG1LnER zFtJ|$evrkZy@x*|%EXwmdp!U3Q6?y>oqav4d-URIBh1^G zZ}a<{Z!*f`m}<{k%il+jZ~BdQs;<~_aKECH`GOs*%ZDeLTjO;sjinzKJ|=6&_%V^a z_>9jgBJs%~@7V9)U%5{AAX&eD{e&Fkt=^5)pWd}%DI`H zBMJ?g^9uQD^3DEpuGjQeE;NYy$o*_zic8Le)G}_jR(||K@jGGvhMRVdsik)KPTtygXP&gDRdbI`MFiPFKQ5X{ z^THL1kZ%d^eq?01Mn4W1(|_90MSOU<>@(@Bn(*zq<4c&|h51PgJ)~LD#^5#1pW@~& z2G6iTB?msQ-`r;Jlje&;yfe=+cj#~bD}FO%jRznm@rt)syHhr!8#O}=QFedIDin8~ z7+Iej{3rkF7p7O`#LL))#@k(pP)>YY;~2aG@!2K1{A5i3a^VpxXH~mL^lNDU+GfYX zmsLwn8K#NXW;eY^d{X5eiH~gy8yY_VeGe-YX}=9QN4u$=RGqr9P6 z7dbxHG^g=JQk+7320oZ$R!d{Y;$M?^h3s#zEWjhCy-moP@KZ;La2^f4P@#CxzIiEG zrVamfTvzFp&&*2AEAZhF=07>?InA^M!r(1QdKqsIaYu(9*ISd(v2JJks7@UQwA*@F zv;OPq>nk^XTa0u_S!$KGAUWT85-2x5i1v)3;_?C14is=olpFPHjM{tB%@o$JLCN=v z*Eh~ot>e{ocBi-oa@`=?2C|ccqa+H&$KaD5S+Cvtgy-p8C;VwSjlH$xRB!7j&uG>D z<5$|f9XC#An=}%yFh3b*e~4)dyU#j*Y&av&rUG`++w)xyIG3b}Q{gite);8zwEh;R zpCRLs&VTayk01P5E0u(2YH3QPyzf8z?)BzYbDd8XwK)D)Gfza)&-n2wZk@u*B?Izy zsXNtb_vyrGYhJ9GkNx>^o<+my<*)Qe@BOyGupdjq@w)q`PbUZc4N@j14>h;1yDQyqAUpU^KsCBU;sVjV^kCE?}GM=GUko(*_f6^@=->+Z4 zfTjaI2k}h!K9-UZAR!FPc>n}t{kr~`1;usXErT2aTNw4Mu4KeMVVA=1x1`<=(PJ;_ z-LRTluJ&|qBoq73h_FKm+Sio<5y8{ zgPobAP?xDu`2EaSg0(=v@8kdDd&nCFPk`o6`lJr#&D`JQu8#|oF;Qz_d~}3oC`EOM zOL?egGhy6-Zug`7NuU>uS0;-L=1=%O!u8R62|^|qy#kbNX~G`;hUG*J9^FUr%_gsX zT>d&gPDB z`Drq%kVBM7?w3zz-_-15kM|A7Pg^ch_trMNzFt({(WjG2iG6U_2VMvFc@1z@%_Mcd z&{2kQ)Nh?6Vf+PYXRy|793_)HskXqbT#(TLkz>$8Fh5C;O}^Pb zvi;d(?|~KoeF%~haN(F{bp+4X%{5yVFL-rLkENe}DlP^_^u)(V+`4q>PSFK)1l@k- z7rucm$@d7iU&vqRqi!EqXF|FT5RmnYZ-@380?2UX>f?evcTGJ!n4i7?d?g?4{bv2=mJQ7e$B$&pStuEdOtgZl+HwR#q5Pq|kr>vjujf{&1Rx%8vqyP@jR zgMPnMe~FJ<`Q8t93eGpkxf_+#`ix%sOT#&(Hd2pYT0c9=7)^F?#Jmi||s_Q;HruxEilxN%oJh zzh=n%1fRdkKQ0hootVuR`*mAuvwup-nfu$HYmC>iB=O53ue3D{)}&pwKKc5|u=9Bx zH!jTRP-)QNi+K0k1-pu)Gx9sEbbe8;W8Jnd@cOH*-(za~ey~}TT-|kz(|*ml0VICo z{25_-lJyy?f4OH}`No?*c?s4Ay+T*1_5f|q!oMT&36DQ%@e;A~5QgKCQy%bf6{1rp zO3i&&!v1Hdc}Q4&&&LIyj=($pq7{)FPVBVW{IycO&_X4r;dPR}^2-PPV~(s}$bN97 zIF9B>h_ga05@UPfR=Sy4R6J%LeZ?`T%daxI%FGp<&o^}Z^JRR5`T4z%*s<7hrCIFE z$-N3|*6lBD^rzw`{~ivZD|?^)dTWLYU;oH8KKXiu><@N*ByZTL=TI?zGjDu{;kzfk#Uq%7Wxz}degN~=2-iP@uBq_6&h9%pC|E?eF{-ksrwmd z+XMP#)OGKS3V$-Ln+N8}HDzaotTl+M>4W(e%g5JLCE7Hw^|XHOkJk@AtyTW}s+xA` zR~Efa?pRSXPlfl%_OSU?TRU;-FGgQ!KZ|eIEy?=ilvm<1KWI!O4qZ6~b24zswYYtH zzDziOYSrklj(h5lF7hQds1CNAtVinjqDR#jwWR=gq96~zKcMH+0inLxTZN*=ize46 z)cDDL|`Ob9wJThahMf{(hH9tMOe;==7Nz$7wPe@*}p=RMhUx0m%C!`DMJM#TP@&iY) z@VXalfp$6PbTPM?txuUHR+x74UXAIRn?E-Fo#i#`wqb2&91637?vxDmr=$cIPs7Obqr4&7X3(yc`8A^PjaeC% zEv=$WbDy{#P+4;hNUv8jHUu|mV7K~D-=jP7L}~IeNxV5b-n2D2(+d7?U;8b{be->_ z3LjePMB#+xQ^_aE_K^IfE5Bexp9du&K&sMn>Et`%_o)g+SB@{+%`SaN)$T1nKdX$- zkoB?qo2(l$l|lQ!+_})W<$J&I_{FRM$mH^(Y6`$tX_a*^#AoI@e$_mtq5YX|1Fp@$ zn`C>)He}~`)Xpq0UY9|eMl^S^S8Pu+U%g~x@6Mi&zF|ADB-{JH|hQ!O}H(UWV zl#(K#`9Q*ONfPF7@Gn5Jh#QNZZS!vE9^`Gdc$uI1(rxkikd9dD!$>s6Vh|$_xccQWV>zpZKpO?kwJcV9ZRx3%vf%w_Ib$osiF1-e~SpM=_wucK64>~T?T)__lDuQmjEGn0+7FiMap*>A`{5KO$nSwD zHRN=Q_bU3X-Z{Jekhylziw=DH+UM3aq_K}5pwh2ZlWYRKE zlh0zdl(F;7-4|{-<1%@a)uIv;)(ri%UNf%w@RQ?1jJ*QfLg$#m%pLb<=myghC5{By z?R?ZJBlYnK-uW3}e&Mn(Y0FdIXcl)n$gAUe^@?rQY_I9=6W^Ma$YoN3yif8Y)8ky{ zHHx=SVO5a!PI%h+%ahbGCx43Dys77eKexM2_FEZgt4xlFY3=psO18vH(7ptoVj>GP zZiq8@sISx3IK-TUXMdS?Egy9vwRedTj$oE_82^r}m(8!FjDk@ow>%Tlg(N;P@_mAuuMEj9 zpyr$FbxpclcdKe{o$D1QY;|jhbi$Iv^Z!SF2~m=6LDp?$tp^FsEkZ`77rn8)sb*dz zYS#5*S4J;tBj*Z?y#v`x1hu zOJ|^HM+LCI$?{;4`K@{_uW35>^i#X#SBIUz`>CmGW|VHe%QPxz!JY*%?@Hr!60b17 z7-Aps&v}sblQc5K9+oc8rQ7k<*3YauIyTWXUG;SIslttU?FV-MbIB{_K19L6ZW)DL zqg7sY{(B^>blJWkmG*ood-j++-X!TKB!6Jf8;FvC#)B2R;4K+Fy&lM}OYwgU^$Avu8YrX%UTx#6!|g{_$a4@TSoGgSo_0^Z%_LLZn=W(II zrmXhUTz5q~_Uaq%nH%YZC5c~{ALa5#^vy;fI{vavUq{m~uT9N^Yj~BKl+kuSJ~`&0 z-Pm_U_dBi&8P$48v9f*fI+kR6h2$CddSI6WXLwP16ZWZxi~zoj9rFEb{u3*o4Ow^5 zxca~uw)aao?5wnYKtz+nKe4@a^M!ByoA;+}^2obUpE7a@(nGlax%D%hc>`Vy-bV!5 zB}pG++v^ zjG>)vH@@AvE5E6g65rpvP)yJ))1MA0C6_E%ot0{Z*Rdq)XY-f5@+ROvd%;JP|Hg-p z>|g2nn4}zC(|D6qlYv#Zr)A_cZaN=Cj1lzQ(yc+nJ(p?jQENO*e0gmYVtF<>_a(HSXKWY^mz8{kqYQ7h`iu z6|UCtrb&7GgV*L4@jv-_Jzgie=tb6Hs629_Xc&+!5{X8>|DW3}3&rNK*|hXe zTZ_OCZTZ^6reAj36I^shTv)!^TIJzKla>ytzT56TUdNK`|C}42(DUFIfV|TQ zvm-oBxp(}(Eb-3*6jb`sjH0xUgC-+kFfEeeunWNqGGa5J^8V@{3;84zd<}IyS|@ z+Z&_SV~__dWyg^1U1pDnZDwW_+^~XE%a!HE^3jVuzSuR>)Ioa>dR_lsI8$mZ-rhQE zyM1i3?cVb@-)QDJeO6UFa69t6Q>oD2h?mFkqz{DwV*T2Gg?bhIbjW&x5g?7z*=Tj~8cu(lEv0egY&IU# zCX)Wfw+F_ue6znfjZfPqmCn~S5A|DA-{-RJ%3U5_AJ=bL$xxd9CSQBl-W``eXIx84 zhtC>YrgVyRRP^oXb;8S^#dc&5{_OHj6^aK|l>-LX`DC^vwx!vn{yjB*w%GPawMRgs z3gyaR-B6PB6t*w;;uo|Wp>vL42Qb>-6PM4+Mx_5ciPvy>!RFuW^9D$~!t@nuzj0-e zDHPK-x9oVZ!DPqaI%B<7s*1NqY9`-tNl5v#++k&O@mo(84C;W_Nqj=~9IV&^-xKn; zjhScUtDmiZ#l{x^6Yb~IC)?t?*=30nvt2*lJZTY@vhMQBj0@fH9@&1w{AFERy3VMp zBU8%!wo6_(?@t}8PCc={3-+z51?`<@Hzy)*?6UKFG#!Qe(kqHwhqnRy6eBJDUR`_ylvndVOyK2 zU4Q*j+7I*M5MhVBWqluM^d3j~EHLNJMxq@%*1y_Aw|&C$L7M!f=hHkXl=RsSa>?Ub zWkZVgeVAywXmX`>r4RS2jWji$e)LLEzL6~N`}wFLbypK?y>5T9#|xWF!2dL(Vo}Qy<|nqk!S7~No&MA=YG6rAqlN4IT4S4*9_+C2d-I}u$5na5 zP=@|S;?qYTM58^T$Tw>LCf{#Z`(f1JsSMKEPu4HgJ|8uW-Kf1k+^PQ{!x-0m;CzU7 z`^aBpeTKD{+e?+!avB+lhva$V>{;V|XcC_^df|R;+Iw7rR`aID3B>GZ)U!(3 zu|8>1R2qGZKZ%E|PZ~e#&MII(lV#w>@dKLG{BFB2Pe75aB|}k&3z%yMiO>E^bE-}{vq5NPiv3q$14{9?jorHq+D_JQSbJ#+A}0HQ ztj}2fQc?8xr+NU^ZBA0_T=44nb02c5e(=3LC?xdm_av7wzezlX(qG7*CF>E6YtSot z!Q$uo6dNDk^>f+;(|IrQ75Vc1xMm+YvL1cyQBqknW2l~k`~{#C*!8eR0;D;_3vsP~ z&e{9A@{5nZAkQ9XGf8uvJ@kOkXqPtLxacDkwIJ!AUE>RMF2t4j_yc){#3O|tAm<69 zDey1kGcl_b#d8E%zr6I2>W%C6zc3#D_zsLlqdz@g z34IK6V`!^Oi%FI4yKK$wnCoVJmNx#l+Y2Lzj!;TniwIPZtNpOM zA*|*S`jGYM>tE&`TWaX9LErnu&&R{5mZQ`<$4PB}hmNKj1eK4?}a^^}ftKc28;dhi)WEzt)vj zzb_@}>6v7x71k}nY^sNZy=%z&jHN%yIq;{&NOiJ)hNimoM%n4EmZUc7)UGUO@j55hxnx2 z__VW*u@?T4tY2S$!QRv$^S#xp;lb_2cCXI z^Cd_r?bU$7{7Tj*+8Wo#L7!oJ3_V>&N`2CI z^Vg-HzV=9oUj!->BO?y>x7l^z(s5Ud{OypQQrg4B2Ken4srh}`HQy&@jXcmGd)hDG zZh?m3lWVsvY4kB>HyfK_6&j8h+Q)JImZ0>RfvqA8;ZIz>Cae|l?b6zZ?-w6^)qOvE z!mKNIrn*3VVZ&nqrJ7(Kd zTj#$ED=WAkp|CuIRd0X{ zYM<}Oy+65%!UNtvtT=~n0S4Pshzm;+pYV8NM~wMbFXQ{k@@@TmV}Il+Y&rAa@+SXO zj2npe^V+`{?b5ufZG2LlBRj^V#N%}mpJDtARya^kIzN;3=gjyPtBn| z`b|oF<5*J@pdI^XdP3$sTV>SfLbe{WqP`*BNc?Pm7cVcg=Rly3h30H-cJ(-%J2cL8 z@6maI_6^SN7K2B>K7o8@@E#ySK|bkBNmD+@k_q4wSasanG)*W}mj$iEgVN9H?Wqb?5exH+*9<$+wX0kuv_o z^dtFx;qeA>vjA!qN8jm43dNoe`4-QAo~+ux$Zf@x)=M<|)R6T_8*h*m1)K@m7Iz;d zDMtT}@pAn%DkIBr_34Hgw)Mm3;!|O{9NRipt8SLmH6kj;@=$NQjwOjN=lDmw3c5A8N(}?7lJT`Hx9zyBJyl90O5kh=S|;{H_0~z?I-s)z%jcdQ@w* zY8Ck`iO=xy$Ym{3=OCUucB;yWXI3lY+pbx%!$h<1CE_6Kmo|QSs>d!9j|aIQKv8A{ zl_|;nIacn>sM{ZRn8p209d-L+XU+Pm7gt6mm_`<`Sy|9?&!e)}qVTUte1?x7cFSmw z6S$DsL!Z5NK)fU-@iF`(<@_Ju#Br3if{YjL&k-NbluKi$S%o!hSH1YqgPP6p$@+!q z!;ata`GUIfJSImEY*=mjh_^NA`FSN9nbTHmp1Jc!v2L$H!x= zr`_^GL|*;66w0a0}$l6a)sgWP&; zWSy5semllkZW^-g@uTF)sfdTHuMgF#p;T^#iqcB~R4d^dlL-zKvC-Uvo`qPKr&{Mj z{ENvuX8%=h>N)x>9gqo-9f41RWuyN?;uGdKG2@#aBjc!e9X;DeuTSt3c^aX9#Pr=s zH@ZJrQ-7n)zN~ABFD{H9j(@W>F~529(_hUGJP#|OoIIliUhmd_`DnXiL5}vP9yMH7 zLEL#za>xgvzz7S9G)@d{o>|E=x3TEK!!5AdV$p8x(>Yyu@YDV==ERT3wRmg z^)N{fVSdbh`6A5|rF*u<0FRI32i&$_;t}*GZnv{$U*AjhzB_j=Fv~opf8f9QYfsnc z89sh6-u^&|B9CWE_K#S(!?m9>wwYbVY@D!m%)GA3u&aANU%wVvnSBqwll99ze%bG{ zp*#h?&-i~Xr|q6)(q~2cA~ig%DvreGLPqsncHv68(}9({cDfHQnS$4`B=HOLH%d&< z^?ba}_&a>^R$SH$v|e0X7Tfc(>xIYFOBYiG$L+13caOyoypAQ=UTO9W%w5s;3B7M4 zw-tkRag}8KV&p6Cl*-;~OOCa_fG>aDqVG&D2HVey>fG|mnipmyW)iP3e{jiRe)$ZN znbx;V+}4be>|WGWeV>mP0#(P7jyuiX9@4IGieD*wcHG@wllIkhHe0i{MZ;f7yL;kw zEXnp5D$l^09ZzWzPbyQS^7D&&ZuA^zYB{oxYgOT-@T_Q>)7vBytij%;(Z8>luHF zMosz+v@ZhZCWF@jtzt){42^`6c-Xxnhd;>eF&dBDa!9epCdexX>}AdlkGs(Q??FhBNyleBH1MoVQWc#J)Z?-Hlp<)TpDu^tA zO#!V#iE2hs1Y$^xgu~i(OA?PU_Ai&OxcgP>>Z|tDG+Y1dcj8{R(VBR~y;iP${xSd6_uuc6nLx<~=;vS0DtWo$>!v|Hok z^>)HV=V$m7iH{lI(&lH__7l=b4v+9z&CAEDUc7F)W6$G4xvmb?Y@ro6IPUcQtUweec#hupGHf@Z3yK0}+%s=_&d*ioh%yHA@m0P#^s$A}f?;yvEq57g# zHt7rC&j5-;q20Jg7OWzt_soKOv>go;WA>gwdlW1OZ({ZmTh3i_(*r#WL;Md~dKi`s znEmk^lx?*9=hCn=oq8nBS&*9Nl3m2gKcBvqt9b#bS90ctqE4;)IP8AybJ`=N)MLDU z_hX-aFXzv3T(l+kuX?GTo$)$JU#K7YmM=dR=YhH6Vel?EUyQy7qr-#hZ~fzgtY283 ziqT)%tIo8gCAOTqB=NB22}p7#V}^-Q=Se+1!sJKg(_wrBt)kV53?g9 zjfHDBV2G!UQCr6lL4*F_{;UniTv>f?Plu4ixPp0G9;lB`k@XAr5B&r?;y_0SxUSPu zLffC<=XtcZot4aYC6ubF5i zJ}X~#hID!(2LAY}E?zonko~jay7DqR>T@{w{`x(L(J2E^?x05W<(dfzWh_=Im6xGI;0c}7;Zb@SsA>JB}p$S{=AaXUtnRN zZAr(V@y*;NS)cIu;Il838ea@;Bu^RgJMP)c^`3Gi(t1JD^JhvvhN!u*TAs_;IKU^R+=8aWH15ZcjKDf$;_ z_h3}z?T)?=Z8qoXwQ^|s&P2RUw%2g}(e6L=Kn*=TZ(=p?i4)J4u-$fbcDFOBMViTv z*I6A?fL)J9v(}^t&25tOV*4v%`~&*rDlr}cH$RH$ABa=C&cf%?U!bU-OT3`^U8X- z`MQsvzK)&OJ{0NX7kc?qu3xzvRu}lS=cwz|Hh6tw%QDlJzI|@GCU$P_b4%ln;B_pG z$FI##_+GN?KEGB(w_6FO;h9;F#@{)-Tkbw0#VFzJlGW`yt;aExx6jO@Vvx!5!(@g1YjTZ4W}^$JqEa_$(fjF7l;p zCzvGwIjQeM(nlJ-rO6(^VO)LMW0k92fxYe*xL7ILDY}no)A5gMcOsvWvwmY_#ot@a z+E)47+A^;Afo7j;Z4N@5Qt??+HoGzU&`^JvZxkDkUm8ytU!O2fVc$SW*2f;deEysj zH6|h6BWA9Le813m)a`%m_87yXT zhjpbm`94GYOB=u8d~|Z*;D<}|IazNs`53YN{C>@TR57tjt2A1Radhg z!VB+XTMA_Q_ny-(XtG^>GtD|oq?^?CK|I}yiu?r#M8?`(Qfy1_QAQbEw@vQ{bE9Tr zeUm@ho>}DhN;&`B?=l6ljymCWEakytD7WhJ>;DITMVBj)TDm1kKVkghBkEG)@31$V zv5|MOJwoG;n?JQjpDxvyD`b7b^rN2;7asxi(oV@G@npZh2K-=XHoxxpk)yv1mzKJC zP*4elWhgD9aLR)@L8c{eD9w ztX%CAJEF<@*!HWu@dbAD1F5ZBl6Va5U+wlAK0-W}hWDKu+g-KzkMo(n->PW*3`8y! zFP*7n$c`X%jq=y0O(|>_UrE+491nn*@iEj4XwK~aC`@1N_8QI^hV@5xiW(lGB#~V2 zmnMnG{uLU3y6w@XFCQP_b-C*^v_D%}c7L#aZKg8y?qKuHWfD3dKGmZl{dfLqX}WFu zhWS%6m708iye}O;MBgS-UIOejB0PgG@B5|k0<@8=pRFI{i*LZmC$O8RT&w%AcXaVf z^LJY@FZ%BrNe|)ip|8KS_d;}{>=Za>Vwff)4*r(5HT`sua9@xYpYT|&+b-4nNw7-PJN|R`mtkm{G;EH%m*4JiAR_|**||NWqlgb`gPx16E>9DWEa_J zq*s^NaL->Q0ler(=D;kcl9 zuBd{o#y7-2FowQ8DQOMFtdlxqQW~}ALq`4)-Q`Ynm!q2v^r1{^z>YPjuN~8FxW6!WZBR#jqmFIvs z7ME%e>QXb8d0^>F{|D7Ocr*EeHyhT=#vpd)K!RsWwrP)*Lp2s(8m*o4| z^bndam6H1!RWYrPMe;c1s!_jPZ*)9g2~kuz_jo{*xjVb>#t@{&L#;aQf*a8Rj!r&VN$lZiQTSGt(Ar9Gd6R zN$f8yNq!RUA1V4v{ImSo_J~wmDZM>(i^av?we3;(W!!ADEXm)BQ0O_{ZzY~W9R!?&O4IYWA@ss=McZ$#?u#y^e$|> z{!0z-gd?vta*k||{Pr$z6?pmqtW^y^g5Ko}*2Y0@1N|<@ z)sug}IeKpxIEfl?x>5LH#TnL5@BX0w8RRLha$A962hB{6SnqI8tng~kR*heU&yw_{ z`%~P05Zvnrx%J)5iubz@>#@Xi=C>`Y6(KJ)>&&aah;eleUF8_xr1rU1!|dN8E-XoW zY<s;eC5in zoENIXCx_H7HQMvNomi zX;`zQKhu>)MB-uhznu0E?1Bjr1a_bqErVUeM^D4;b&%V_J6*IJxN(zJVs*RVZK~a2 zox2}E99WX{M0qG~KY5@Hj3f9L#uls}hO9yM+#<7^Jl4roF38LR#Ph$@O-<0ol?wbX$O=Nr6 z<6XQzt}SEr`QLFtQ*RgeCy#P{!uyZIBMNCm(!ObPk~0gg$S*PrCa{GbNBi2%Z58fxvqTLwOtd< zK1j3n=l!_$*LSlJm$%JgtEKuPovinn4FiWl+6@AN5q-7eVNDs=Vn zrC$(lqwin$k6#k(u>b5Tr)8&81m_#&k>}ht6JU}~KRN9W+E*Ay*-rsTAfD1?)2AYTfOn zim#XN{J}=uG;u?+J=v`fjLn~%R=8{NQcqS|uP!p-RL2(an!MoYZI7m^c9yV7kF?F) zx8d$aK7PtR{cDI;Gi1E#_wB^^fBe!zp$MCkm2~!}lWlC=v!tmWKIuqDEOq%s|9*9l zzsl@a!j30{EOw(jSJ-jE4_~iSZoa*CUV|-r&1UX9@L@-}xQh5d@?xvbG0C$X(=sz` zFU7v;h}TJcIj2ALQB|R+S-#e^TN_4OESR;})h!}$h2ePRl-JT?Q-C?J#h{)hR^y#w zldp{(+HL4uYzLMk{j*bk8#3ZZeAy$vd#WubIkIC;4BL@w>F>`@@y9MrUY=#HSr_g0 zHz3?C|60|7TO)rRYaDVN>EG%=3IBwYWQ(0s^4H1Syiv2yI^NgUeqno5%8U(NBUzsm zd(@ty;v}^O44_Ufp(9)#ls44&;jRzkI@(@4#PHbh##Rc$lKO}E?u6V zZSc_|#q(cPGuMZ=@lHAavT^=HzE~~|42ZbczzI00D!^O(=8$3cP1qC|u;WgYp(AKAXJaDaXmt&1vb+-sE(adXY zgJt~?2bLuL*z!?|KMkv@MyprEqK=Vcw{S!3C4PMgtLVYTrXzXUz9G_sEJ^xgr+!1q ziP?+3ay#q2u_m9D^LC!P*r;2TlZd-RhnE$~*^V#^%iA^e^WTZD@H&=cd)WQWrw^>v zmfIL=&P4a4?|t(5N8o2pP{$JG*)>X`*t9bD$-uRTEjD)9y`ZymXH#rhz$w2MZ7s{& z%)GF^?&H&5Gx54he5dOxmj#=xEmWq?slyvJ^K@kUrT80i?HP_3q2$IRZoY=Ce}Up+ zG9StM%{N)Sso%)#VJSqn;lcAA%Q8(&XCJK8 zz&c>c2fR+=l}Eq9TVal!&S-@ha#%?reHKV}Jp3=?ReUxU(h^E**8;2ljUQ;f>0NZ% z#F%6=_C5Gc(wohX^65+1+Y(Mk9;Tkz23c-wp3uzX;F50hS`13+RVC{}*g+%m>-gjq zT0it&y0H5b*OSl|DKo@XMh>%{Fua;-X1%}D%OsRsjs0;pp;z7CJ#st69NavyyuwA7qZ<43{iqj9bD3``L zPTZ5aMUcOx$$PLs{MB>E%xQG`PF2+%PuXXGiR}@ZQ?68Tjw~JK?=Yvw*HP`i&DO-N z8zyWVKDeo~RoM0e%{LrqDi}}uU&=dub{OAy$a(!?$gGY+QP9byT|`noi)Dw3v@bR5 z#&N#($YIX{Lgs89tVz2p(X-{zCoc;*CG4njy5u0mLcB|kZ((_3eEddx&W4^P#(BkLRo{!?b0dQSdp_8=-#O@X;Mp0umuS{=e6<~C@jCHO&!A^Z zmJh$ZWF9_W=c$iZmviUr4(6IMwnUV&Bwi=!VYvRZq2vsl_r?9mzb{|O5q}FhZVD?s z`=#}u7<{UE)r6We3rtaNp1ZqXuJE}!e@@~P?k_Ga2U&`c538N00QM@_q4a6#h)91) z;*m!lqplW?RFL({qn`}P)T8M{;*qz13_UHG=|d8q6n)m(h8Vku9Lm=(Y6V> z=|Nu2PWou$fnUaYHQ7%;DZUEOGCS#~J@%wzLn#zp#}%C#`+TCsu9Id>gYuU=i~TMa zUeqY^dVjj~%z67%n%{8i`G(#LZzY*+7#!|8cGD@%KC;caZSJ|ObsMvNefKP{XMI^S zKPH|2XvtxQtMv5*+V&y#oUknbJkwzDy1@7*1)aBF%*a3QasHvmM_7{Wk>CF2_iX{g z{gJnmr!0$eTtCcq)Zoyo;}I8@BtB{OlrXKx_e-&tz*>ZTY27KE%jBu+kK)g=uQ0sU zuP64iEBSRu3{+TSJFz732;ds(rGI3fI(N1NTP)4DJO0Y!2dR8`h3zN(X98`g zt-RwDy4E&%Q0~v&x0QCqdaxwv^S|`h^+)h&#FgF-I_iAvm(`Ys*9KH|zBdKifhF0V zoR^ovV+656d22%fbKBv^ZQ@)Pm8y2XyJnr-rRXtvwmnW#?U*&9;nRTE5Akov_8BvN zxg^QqD=%BEh%Rdxw5IcqFII;lu--SLGb@EZF5|d#NE4@7FV1Q5cSticcL3w&D*}+`@5>q6Kv_rkmW@iRIFh;=SpY)8Pkqz z$Ll0su!0~b04zz!rBqV>z&Q0T`;e`OauhO$*iX_r6aK=VTIa&VDy6R<%bjQA`>-0h zEar6%I2{oDdp_dClEiC_`~|Oh1l1~fO&Q%{$c2CvI@-1&)~;Jh$CJJGhAv0yVrE|< z@yn@S4T(w&E!jBcT9*n|+d_)eZ#poaMlM`B{L1y#*XCyXyM6q#+OkCowt>W-6Z*#Z zU2qi&pS%U$#?HLs5YgD@H}9@= z>g%*JEph+MJO!?hh)KLc`i@+0O1`gm(5pM_dYeKH#~Xp*m^ry{)7R&%*E;(*e*5aQ z=<(%D@g%)Qg#JeN4@gb0UFcJ1wQHh(jlJl4{oS=dyUo?J@+>*CeK9^m@*i9NO3Pos z`4?{c?xbzfyR@3!lwo@YEeUP5ECB1j(#hWOkkc1sqIKuX3!ScO_5sa&oA=qo%&XRE zR+Sc{m$a>c&kr@}8DzJlh25HoTaK)1-dLkY@V>tGFq#4EKjs&c52=e?-}{W!Pi)%?8R>+@P(z;=`M3CkbD#<#c= z*bx1+ApdF77lR0|eWb3N_ratoha*1OW+pS{khqVr9TcA8Q)7_XD<%Wiv*><=@_ zXYinSpS|Y@TlUd$CPXV-ZrSc%qtLYRjt7;shku{Aei``}WP7!xF72x{(^`#BOE-*W za;?|bmUhO?8?2h8%$)J(id|^Eg0&9qe5#Q@*bWlEFh9zv5BWw9qSMufQtbynmba`O z2WIMEf4lv5?Z<}oZ0uqSEL}7FMcYAmuSSqb(L#F*I;{HkZA|2vlP&Rj`HDqzqjMJUBEuWen=v%^7x7Zi_Wjs{b3JZ{n=#?0N>EQk2}RL{2!7YIjzrt+x#hd zf)>CNwvEweWP8~CYnZ(U$b|RtXY zMb%uDOB&)iy02`kw=&Q%C~8Mi=l#sM#rq^)VRN{I(NsaK_^s>)N zq?h}rsb9LRk964D#H)7GC7bWybu3A|!u-gmKf6=&5|G~{E$51?A1DpBhqnKQ76L@P z@ibJlz(IcLpL2$`z8TYEyyJzitaQY`Xc z^T1P|!mN|adj_ZP^9n&64}P^8JEHt|r;Uf&Upksudk9`9@d?WhIrSO452Vk9LL1Ki z@-KJbW_O45w-pM91}@gDC1yH*4^?Up0|yT zzlbbT({|tV;E-SAs%qrC*N|fk+x2^FwLRci`Dr6gYu2ff{lg_+CsABV=cY3ffR;ma z%o%2-VWe?=mcPiDe=PHZ&7R9a&nFjKd6#^KtY3B3Yj> ze@oSmBK7-!geCD9ZvU{OyVBRR>{ab6lq>F(O?Ca^sdkJURH+5x$pbi z@APOj#B$e%&W9(B3|))(t(FBZ&Un4fI`mn=&=tP>%Hnk_$@a13pJDzcY9ZtH>v;0; z(d-)YN-2}SG|S!pLH;Iuc%|q|7fQj;NA%GL`8YT`2Zbk5^tk4WyAB4UG*#HU|hp$`D(#lifiu8tz#m;L>t-Ck*{*%XSR zebZa)&e~%;^G>_=XEv|W@HNsX=i7rlpnvwe^z*F#&Yecv@2+%xr2Dwu-Tyz}HQqW@ zC~kJXvHH;9pQ`m%CiQBVmKDrjm15s;<nu2zYA4*f26 z^TkBOUtpSFt1GRothY>=f4BePcbfH`c%N(^Tb~(j&x5BYEgR2gm*s+gzAJ2Zwf!_H z;^|t=exfrxT&wKV}Tw8E`-=FN$#Hljx$d(- zdDv-xvn#`#CcLSL&tplp$9Q{A+BhZaH(Va}q$ISzI^Wwvffk;&tTvBs^b3s%yh16S-`wcMen}3G ztWr*0f3Vhlh-Tf}v-20yPkt|Cx$KI+U*L^^X4o%SlKjEOFI|2KYjv_dx%2^7>~qcEkniBg>IRePX`sm|>MTah>VnLzOgfybt@f zj@$D%K(%^B!`@FKzH82nys&oZ`{QQ+*oRfR;k>;_(oXVyBz=vMU&AN~=1a+cAN8mq zSF%f&Re+VmXNY_^CaajNpR^B1dz*cqq&57G`nftO#$u&vf#uWE1?%Ukj?Y*&ax>j( zJ>70`oe@LBJT_Ip>p=%@oN3o0-D&H>4!=6Q$$E#^u_W;s9`EZ(=@wXd<7v>oXnc6s z^bnt4&uvffTRT|0F2AtllVS1|<5Bw86L%|s>7}go^=zEjyc%q(U0q|m5Jt;9{TPsydJNU{fXW+d%ly2$Lq#7gwT@jXVXWF z{1(cpA>Yp}uR*J_~Bb=buwBG{O5r3vQP062kZ@6w7Yhy8c z?&9hh!^=h^ea-UZ=@(x-*>-i68p$Qv1V`d^EXCnx&kWG{onG zjE7p=!A?7V>iwo+JvSRyq`V|U?Ska*bRQ@nklt!qIB3(YrY zJ*#Y|wCHRa>h<~V;(PXU5KsFJy+1@xx}jQAq~1y^=WZ&zj-@`l(&R0i)B*7+{U5SE zIrWPLC2s%$*f0<=9-)>(pcDB&7kt0puMvCNZs(-$zW1hX(%6e8Enkm!eXz$ip;7tt zl%3Tya)!jOU%p#YIGq1mAFF?^^|IHEJYUugu!(9BJn2_jXd)se>tpkiu)Oa@jU33W z0lN;oA@J{M&y&dlcB1am887gp6dwdIK0JN&xpQF;%O#P&=k|8F>w&mSSv}1aR5i=sB>=FCu!nU%&C&f&mFdp_`3H0*n1E7sEXim{L!Q;ktW@vcL+)^ zx%2{QK&&%BG?%SQ6ot>SX-F@%E??KytF6{MGZhDwp15eY7t&#%uus6o3X^_kR zFYF8CEsn_OYbooV=O_C#oY~=n8d3Q-XWptZY`(+sw5;+W>}vy1@4BwTc98jRY1#65 zB9uZ~_Hh7|j9-nzuiRlj#2$@10PqQ<3RkFYUvl}*^CJlQJzD9`mLzD9%d=kJvf9(u zbstjDbKCDfj=S(|#A`*5zI^_}5q)IN$n-hS53zEa0d0^2{#tjxR_T8E>aQa>`*oty z^5=Yg)#YK&b#4cQTtBt_;k-SIYYh0s4YWW|{&J17?uqqVnLbbO!#&Mly}vk54{CDM ztmczB&a{&I^>y0{v`wHs9J+eB|5r{?@)8wKF05 z%btf~TFGfVM~~$`6uBJ6cV%8F$~o9LbYGjrjh^`X<;xt-P^L%SzirJg(7WgCSB2&L zo$n89=Q-00xHhHrqy70=7+7Ay6XooFSWnl-)n3-_a__%p4rv|r;wF8K$k7hpt< zN6+R@=kP^ekJS!XJ0fs-)}?kAjt$ts;S6Q|IO9+B2N^`KYbuNinMP^MhS~{#3&tct zn5|1LPpyA#*;kg~wsIEXa{jXX1Odg4-%n?KJ;zxeo0>wIp7Qhmh?yRqZLoiWSWsuU zTr~EnFJ}zicA@@_y`R)M#WefesJ*@78*fC;+qJyUre+m-bNHffYX4HJS`FV#b=v*3 zoRSS4$-TAHYrzf}N^bF}) zy^R#h^tz(2(OZh63-(tWRd{8<(ki#)kBrIX+qXZ=z1>;+;}IqFc>6hXLU!NYvMPAt zqZ%%MaQkO{+t>Zxf5FC@N2feC{TU9I=`oimPBx-XAd6N-a-qhEmA3D!jU=K3IsgAD zF`q4?Mwba%XjL>9(exwejK~T3u}!^PzPdf#Td%QR*2lpc^1~n45jCr6-SE$!-)i!^4Er){$@29V zgP!fs^4K!}&#p0FuBL@_p7ZxtzH`#ff4_Bi<+&U#)9b3f=e=7z)~NT`j4)bRxxi)H zmt4M@UzX#jSQ*5xq*#XgfhC82IRj`1^cCq~MF*`-^daK9Ne+D_!@doZd-lP_CDS)V zEP4G*;2(2mnD*_-^p)TEY`vXj&dKzYWqiW96>gv_~_{GHP)NfZ{+$|@2{@= zFHw$M8NVEH|G7OHua_RV6ZOK)J(_mf_e}dwWctANs+X|HCjV!WA1nLb&6*`J>}w$bJM?em+@ssw??;WtqS8@hw zM4#YbfO)E2^nMU#+4|PYRENstJF*{f#{D7YE0#Ncf)va)kRQ(%}RazLQn-XIIx zgj|04%(p~8aK$ge6w36u(>}-_oO`7j#{q0Vqy%SXuI~0xl-u_lU6A!d)j{)a-1t3W z!HI!PCqtQDwf*hheEVU}+A5UGbB{l^<)v}LM=u5(TpaMu4}%_mA?NUInFvpmFXqp< z(-6F%c;RkZTy6%wk_tbg=^2h$0yhKgq@@4zobL#_+ZGD;dp5s4{+Kx4;%nx_^pV>+f zt%+V$F@qM?ymd*i-X7&s{(q~#v2;9ThMK{w%dNG(qP$c0gBN;e`h-8<K@ncWOfZxL7&ZXLho}mZ# zKIqVP)pn*z zF5kNSgc{fOeq_rywSUEt*V;4oktN5`nQn#3_l-gi zR7!s4xsjh{c#=NcNt_M4@|>YX=0|zWSDl?L%JiuFm!tL3Aew{Nvo+-W-D&>_qiun! zfO?o&pta+ybzfRvvXx-{eFEYg?YKtZ?s||~mzMQ?54>lC=QZkg4>-0ggoJy7|B=9d zq0hu_OlRcWll@D*)0OkJ1wBz;5_)h!$XK(sHAGOnK>VALIILK)|S-v~t zM|sa*aaAwNII~BshdX*wV5Gwtzgjw(8;+r8_=T$rycZhn1L1#2g3w70NGSjE(VLrn zSLb6wciG~HnjY8vSmn$)?hZw%((nFfs-FrAdb`cId*57iq>9|!cb{HQ?1EL4 zOU36KrMJ4_`}(shrholt(@(fwo~sYPPazL_3(nQ8Uvhb#nI8)YO@?s=SDx%$hfnnT zZR3QUgPv}&Z$kACb4}-R_!*f#wf!R2QN+Fj9qrLA%l<@X#$1^mckG>^pfSW8C*5s( z*A{==qeuASP~WE*Tg;h}Nl@Us_?2J!&%8bE@%wkQs&Z@6pG+4+nO|k`2V}w6glA*$ zd%u?ZhAsU7T(&hR)8ih$#IBztpe4!Z-9>8L;a+L`)g5}wV|J3m^#Zy6*8979bx^$j z33Z6G>xsgf#(VgzwSqZJrpLYd<7$L6)_|w@ZF}{@bM-;}{ojn=!@&N-nE>zQwztw_ z81`f3-Mc4*Y>GNGd%QkkDYtCaL*o*&>Wzrn+M@IBufKY#Ifr|OKSH)p7vM=p-1*@L z6r&f;zIW17?XRAr+Mg}S_4VZZ(H)yyrl)-TQO;8))8kJ6kAZeK80RUrtQ?j;&$K^| zHmL2h!B2s^4NcA_b1|l0o~R$c9RlBiG1-)}<&T1s^S;csE&jdZv9)I_+O_eX-}_Q?~qPI1}fYh3#ES<}&5{9rtg`od)Xj;^th< zzvTR7{c3N0(HSiz=kJLAT;r~;M6knj$`lww(Q0yMz1{2j+gpBI^<>oSUkZ!Qy>zc> zsn0cfkQ+DyOM&(j`~UFl;soPKBk`tnSNUtd{((^AY$yq}V~%2P-G^Jy)%pnebKn0{ zmidReXJFkDjQs@Hz}0W+5u<~csTia)UCyu5Fn@-Wyqor5(SF&FuKT6CMOQ&V z@_P^bP!jUOnWO&g(=VIOW6JcD$9xC-6k7t=&+M;2GN%NT>9gOzf?)hd+g!cU=?A4d ze~Lyf&-4Cd;rqc8y*NL{9>8z3K+m6ZZ`CsMNT#Wk1*DT6w%O=YG4o zT3(iskbtJ~RY!|;q&}_-XUNz?L3E6(FZmTWd>P+7ka<6@( zK{rnVdfb(^()_UBe})+6h+;nhY9<`{-EV7a?V%nYT-)DZ-TQy>txc8w{5f^dx(A;h zf8yw{=a|n7WqGh)f3fzZ_7&UGgYM^#D+?%R=#zG=rHafl8X9ZWS6BW(n zGIYIu`2J*+DAZ&r;Ge_q4B_~vqkYh5fgYnGPvC#`?8>#bWR#W{NA1I&eaAgV z^bol{tj{k{0$tf(Y`K1FT{BrP-%9A7>-|T5NotK z4&Ufu*@7~Et@mg9>!avb#1R-zY6$yKo!+uM8I#L*uYLck_YJ654xQ7WuGSaF1ihPc zBjmMfKV7XCb3MoV5$BJ=0J z^G{jVzn4@`rEc9BrgM;5qtwl&L*?th;n`=Ael1m)@M-G$mX*m-IWJ~n01<+;Zr3M;%+^LC5FpEHdzeX@NV1pIUNean{Axu?I?^5)$B z(m>;h74y0e?wv#*F0P@AHP;~HdpK|=i@TKU`x#{ZSV|FE!oy&_G257PhS9%+-WKQ2 zv&?I{u5)&^SHqv2zCWb-+$WB6yYyBxv6udSFY*cR3Y|wEtha{4WqRcHlIJtQ;7j56 zfer=EINJX!=kK_`*`EoxJAXhOfqp9FCe9#|;Lma%QMPYmhj;zvjn}+h9yI^8n(3=+ zH4nDM-~Z0uac1>PQTmU#dT`yHj{=v(w!8WJ@cuoy9t~m9 z_<^w(JO7&m4XJ!;O?WNeMbVFc`1Psz zPcmKgulZ`Or?d=Mksr0?-CfRjs_& zZ$a==J;scQG3i~oe6_rm<@~%Y>q#!pv3$z)w;WYHGhVwtHus3?9~QOwcF>}f`p1tn zIevrr%}}ndZ2y$SUNwI?$o3hjD>oPTjSD^yR4}8#SnbZrxh8^e8 zpnaQ#Bfkxg_sb8`G`&6c{zsTDhBAHX{!{kx-&re!sVQwAS#Mu?4C9t`ZhY%uF0RzC z#O*cKFPxt+Xu}UZj!nt$)JaYt^UHC6xf|mF?z6~-exGifc?W^K;QY=2VeXF)qng@Jmnl?LNA2=eZkmRx@1;9nt5h@y(V!!E`W`>G?0m z3upMwbTgFcSL+XF$6wqZiRT&7e-sZMJwA(P;6kjxKaZz?Rx#2GcyxhCl5^d&whu`aV+<%=J?{E)1ehWjqJA!Gk24#L(*Kg|4%GL49xmFy% z_114E-#-<$etPA8KaEP+z_iNrmDhOX?8xxh^Dp>M`L^QVjqM-tUwrLqOQ!Qv|1MLC zXPzCj?c%nT>wI?C<8YaN>-;U-_+griaG@$FmtS7~6w$Ywd#AFBJf;50o(V?|{Oq@E zg_2lFej*A%~DZvUG2VScmF-id)vKi)3mVBc4oa_aZqTl3b!YV!kT?`YGe?lYB5 z{$rW{1DPMV% z+gr?fQJ3pHv^rI%@1Yy-Z@UxxWT%s>X1si+n=I@9ZGCYqHAi)VY#3-zTv0@Qpa@!;P zuz9b!*(-|&KU;6)GZ!BF!}R_4&7<2+Gb9&8E?<6mN%FO;6Zx6)uCLr9%zfIjuQNT4 z;D1Z6tE&s8^^Yt51aWFttYMmUl576&ALH~vWB%A3vaDhAA?NFSa#-fC%unm~U)lTx z>ODeo`Hb(5sI)lr3Gb*^{_(D;Te$gN4wvb>+x`U0vq-M&?BW^-*sYuL!w;P%`W9?x z`EG9a4yMJa<)Mdfe?9(m`0i_4p40#I_^a~_H+i)CetO)JB1wa89&>5o}9}^yg|im^Kib*B{OWi zYyH$y8)AKTPu)1PbE~J4%`xIv*~&w^NBuoio$8$`a!CT86neDy)#bZ_w|5^Ox6ALt zd^uIw>A|^_`O9o_{){J`jsO0i`rm~;HL2?NpT9cFbZ%8HU#*|YGN1B?S)Tan7JI#g zw*lW1=#IzxwEvS&KfXC<@Uql~W82*S)*x2B6_%K59?N33}{djBtgF=YrAH82d()r_|b}g95eX|KAn3ed|AI&1J<9t(5l;SFPior zem3~I(9WOTihQnn?*5iPJy?tLa#a3csEeqPx*oP$P|mNs=F6xF@GEz`Lm2ysGnY)C zJU+|&d$9lFSE|JOHA|Nu=O@bpkEC+@aZZk&7y1p)HREn5@dh5G8NbIU-k@xMm%5z4 zS|7P)&pP)FQMo*sAJ*#Qj3>!)zUsFpp}h}(ak?;KL)^M5r+a^YQXPlC%Tk_t^pNvq+*A2u8>2q7t_8WY z()DpXzj4i;cYY=)Xp-wM>kD`7d3@h6?uT`B$>o>sPinchlqYrj;;aTOn+XnDpnS^1 z^&dXTVtedBUX-PLeA{0(l%uY97|5Kp>+rO2O_%*oM{ayQXxw|f`r>An> z2zagj#8&AK=b83ta2~GFCwtF17c-Revu^Kr&VO6hd7`EKA!ac4>Ojo=q{T;=A?4 zyaT_$gL4d=`8c|!?9$Jj{&=sDe80NwUXB^y@cp`${KNMPnK_6yJda#FV|Fw)%KR#w zzxh;|dAt{L>CAhma{-SDJtJU%waBi zFn-M!G&RrQay#Kz?_Dq*6{D=VUg>!&J7kKVU{;q#*v-Ef^+eh~2 zQ)s(o+tso%{pB^Ebk;7E=`qWQ*olH?cC+Z)X1UM<5sQR732JHieOB{)3T06EO6~hb zP-f)v?a8k*QtL{7_;w$xhx2c*a7?efQfW&!{yXb~J~1oK2JO7ucE!AxubGZO9jMr; z>I*-#@m);MCwsI}U6lbN2wSpPS z?IZUucjh0i_)Mo8o*Dk|-#5Zu9J6g}v)$DlzQ0)AA6&K9aHo+0cxcb++H}vApf$H< zM!mAVXY8dRXQwi!1}vRBu6E4O9xEQX_nYnEy7e3`^Uoc7Aqc1v=g}PZRJlCI@+MNa zvOfGUSI!Fj`I&n@z4hMqs8uINYqt)bJeQM9+u1qv?b-MFzcVDc;?9;o#&Gy!?cN^w z(w!#;Z^}EBwBxOMu^fIRcYUPKSE-@%M>KEoQl)!~I9#rub$)tozGAPgNRv#DyZr-u zvc0)+yIZRY^OM2?X0}=K`lYQk`q|=#TK>)Uwy@RY@c?J*s84X`qAkCO_rE2bqyPON zYU}*)&rVJ0;Lx5aukq2b}fG$FV%SKHeZ-#4djHmsnfHVk%4PW9#kf>iB>b3$DUAmb~r% zd@ys#ytyGWcNKneB>VWcOxcb)$KQEx`$rKwbaNk!m>#l>!(Hc}Eq%b2tS#$M?UgKh z|39^@k@uO;`iHzUl1$02KpV*_Ci`vzuCX0y=rMaE=!R+gS2vpVci^&$3rGC)MGwH@D6FZyYvW;7PfhkvFGyI0dvPOl<6(Ycr+AvhU1gY$OY8A;(JNBiiGcFvOZqf zr%|TQmNfAj3cDJ=Adh_=SG2@gEqtG`_2*n|T~D_!at0;Mx|htA@sqjeS$@f07_{tB zqv&k<{9NUzr|7k&74f_guKnQIJz*)kvU5>zv^?pHG3uBJAhEeXpY1(y+_nhs20ds& zitj$+IO?8XfoZ-Q^kP48cK_G3g4*}p$qNix{dXj|e4rDtO7z&qNlQNby#L$@UTapL@pdDS^- zdGdFpQP)o}p7KWCI&;bNSf8J$Jy!faENnaR%^`KHt$8-nBA17{z&w}gYJ8iuYc?-rHTmSpYyk{oAg zE1>1$%$jtw3iZFQUOPGP*~|C;xO~9kG$?6)46hHqfC$c@`NX8a*Vzd^L~F@zFg;ZPx;b^BQ1K-cs;D_^fF%= zdX9dyu`@u6<9CGBb3hykvLIvvgyU>lv>^I(@C_u{aP!-aojse$v?G-1SKEK6LvUX* z?mE!Xo*ndxScVHqa6EGK%~@;Zxi61sWugwo+IxN;TJh%*hJ0mL#M;@@&+R<3H=KDU z^Q)}%^XQEn#yLw4)F;&iFOy79G~^-nh?sYj<1SjgvGl^W0Om^~ioY4$VvjIec`*CUPU?lRnbdqePZhLtOG20!12Ya!En_x)L}t-mnc z3}yP==Qr++L~Akw+TOh9**w>Dp4UtpLYY3b{*dR1D0k*~jztNueaZQ|TYvR9EL(r5 zNdiFn*<0xfC(469VQJ!dW1-!I{xx{a$EN0XdC-p|0l^)6SB*j`e5|BEyB z+x$M9yZVOfqwWj*?MCzZjB_$s9{trF`p}wo_FNv*>^b?sebvZ0+~wlDWgwSt-5;R# zFxmG%*;=>lcGU2Zf1P)N-{|%8)_+$|`OMSx4>!&M%yyEqlJnY^njx=66^6e0k$-XZ zjx$Rg_LKSJuDs)zg}Pqs)?`1Kvs5y-O4}2j@-NtWr@QCskLx06Ukh)(*t>zUinAi; z`5@C{U0!7ihJ93MVVO@+;fi~vac+cigZ7`}OD^AidB_5Pq-IddQ!(@ZSPKfqM;^PCeFKSOWsX-Q7(l}nP8F-%l(hgrZ*{|3B zb6Klh9$$|@kGXAm!kq@gBXq&hCodj7`^#Dk!|S(Z;f-&7 zd@g!k!{4+skNh)4gqr`~9eKl%*qWcvQ?<8UAN4#6M@sknnM@~Y0Q*`==I7m?zq_{g zT&CAN-?e@Ijc3BB9nsGxYj>QVij%6DimNu5Opm+z+;SXJpPNOW5sx`I(-M2QT+<%5 z<*j_^4FzqI1GM6|^w5inJ3?@8KiV&r-d9)aad-Ibxl!`ynGRKYG^^Nq--X`}T%Ei* z&D;{=m#6B3=N9u|4k~yoS{41sncxwM2bssYkvfH|d}q34dduz)wZGylm*=j$inGO; zzz5fA?z!^OK1?n19NSa$3^k4nK_DMVityhUq_rnMcmQ&Use8hk~~b zZ9rVZv8KPBrOi|PL#rC;LH^;+g*>}jPCdqXQX6{C{>J+7{$(C*VnAMT-2~-UyobtJ zE-T6hb(WuPclJc&iuB+bSAx!D*wP>F_Gh$s^3^lKx?GPkPV$d;f6e6T`d5FXvC+Gi`QZ%>ZrtRWYG^-)mLj`R4DMzSk_*$I_1=yyIO< zS=z;hs5Gk`no=~eOs{qMc7Ao z{h}iy{|sF*`lS_99;|5deLk{2bIu;d*%rS$+O_jO>l3S=J)3qbc6HrZgXXpv_$t?+ zOIVAy0{hh_i>u9$9rQAX~nBSnbN1MRb&b9Q8Yd;wJ<;lRk zRbRaP!S)-+x!n4--x!;5dRF+H>0>HYKKRu@4wvb%-k$Od-0&7J$Fus?{$4Po zK`vjGZ+FLQTRKTD&lP=SmgN{2CG;TKuAg}Q@w?S+yEXF-n^Vzm#GYmYN_~!4rcdUF zbNzid^dj6LYWYoPXZCvhxxLN5+ZJCQv}|$h@VURFzt3{QP^Qm%e{xqp+G;gLd7@ux zy{hxS2%X<=$$h7Xb?nRZ^g3R**|G{J!}mm<>)dHn^P?R8MYDi|!LRj=cx!a6w89q; z)!}fNesi0;uAiLgh4#v`+;@#@{bIbe3`gCq{x-UG9zF3$vG1-;kA*BhS2Olzog$m_ z59{q^PydC1CqE42DcPu#(FH+6y3Bv=&AIgdJ@m&!9dea?`Wcypj zmTph$^5t&-vvq1vQU0yibIZH)zxLm{)%V{!-;BAybcO$xli0sW1>fht{h{SB?|*zb zoT1FGviCphG;X`^m-)Ld*Yq!Z;>rA?>5EL~_O=e&8d~lC;Gma}EYJCF@YJ+ObBwzEag-Ks{70_>_FwdFIX5o0JbkWVO6#VP8%Lj5|6HYGi*3*Wm$tVf6A^uaBtZpqlXITm^e2@ZGv1?pQFK(+2f6SEHTENH*bpC$n-n* z7g_hYxZ;noH$wb0JEGXH*}{nRKW2S?abDjQ%=06&8~3@BwIb~4r1o=vI@o$Ohs*Sr zO+R98xC&7A_XbUW>$i_4Jo{qQmMhy1*E`knF_^+BDaz9qd#C;8eKBIzV?o32RQ&r%t|vp89@qT~Xi@X&9@G}ruYsK+Uu<__e(38* zKOF2gr`2{&C6{kqKR7=gI6u=66zpk!e%*&79_YUQ^vvR0e?7xwDVsn1qrs-8mwXp( z{35t`Ym>bk;XnKHvo&{53Vtr{qsiKzu3zDBhH`z%u5X+h{ok7%xvB5h?*wfa|NiM6 zuV$F~Wv9Vt6-}|L7oeX7q)$(p0B~a4KI)2!bQl_SK|F|3a4)r#A z?kz1tGfnn>$^5e}zxKvA%O`N$h=)-aM-79$f+PN@zBkIm4vr)&%Z>1B`CH4S_6OQWltqcd*vwd~C9Mk09 z1tBB%x4pgp_gYVy=nS9qZq=EMyM?X~ti0-lzsA<&931h>9sO%w^W#!%L%IC2>s#ma z15+fIukP>e%_ps&q-j`Z&VW`e4n-Br>Na0HY5!Gc%6EQzEp4G3O>4Tir}jg?7hC52 zU2X5hce%WW#y#Eeor!A$U;9*(v;Sfj)4ZGG?eW7^{iptBmg^R@ph%|Y?%7M&Pn~}+ zF!Rs2=;P3-4YEIV3jvKx!e$l~!X#=2(CE&OZ`SQI=XID&kK^%2q$tb! zv~~NyJ$uHnd^yuzvQNLP?N?U&+BPrb_LA)rcg9=G-8`71<9#;FA(?IH9c_HVh@ zIMWKQmlp_q5>KMwKK4B0d{DfJ0(a_Wz>PjtnG&vDY1lGoLBsQfYX?7D*Jo?&#tQxA z6nBR{VOik5eB7Te_A%O?E2?SyZ|Sq#MPs(}{6HE~Y|eG<(eIAEB|Na!wRBneV_hGs zYhd}iUB;wq%bQ&bS@~uA(VsM#dWU1PC)66?Uw2;6+7S(pb^H4<6R~Bb&)V(XCnM*rM0@@eN15M9_v=phv_TedKpKa2aa2y?t&{ zhkK`mZ{2iYS!$JG(>ShIuYHB%LkkD2&Z-mC;E{+oIox%Ax??Zl+&$T-+41Ct^Q#7> z{XJ!$51@5`)_FEiggz8Yua5JUrr_YvIq%jvIrwzslJTF_y>HdxUzo3J+9rh_-T&I4 z{e5okcy7mcA9J|OZ|nB5^Y&J_(HcN+5ZdkrE~XR=FKGJp3ma#IF3(z0KlIQ(oA0l2 zRX_3fm2sSKXKhI4hulA$^G}uTpI0;);Uk|v8@Qp>@s@9mnrzd*bNBS0Ym(J|bzo+j zsmsDv)SMTitUG_08&u{O=8CqbI7N-VGu*Q$-b8H6m&R?zXT;Ud*!QL>%8=_h(f7Wf z^IKWJ*N8@;&3|LM7|QgOkA6lCk^%L0_p5bGZE5{ty+3+({#sgE&GfXZ(Zko;fpnZmxdzZbUY*RziKq+BzvrQ!`W0>8#{8&vab?g$?cWUBn|VrC z67s}m4wvb3EKknZdzNWj(SI^M?%5;$pu6zRy<&Gj3Vaz7eXHW!Dc9UOl*=yR*tjWctglZ_)NK9mkf7E47~P>UfX432?8A^_|!#N3QwA zd-oV}XU$I~5eH`7cj%kf$LwH&1F|x6bdz&5iSg;_3Gs;&G|BO4>AIw@9RFPf@vBGx z(|pJaa1GqvaQng?4R;*edbso9E`WP2+=Xx#!F>$wVz^7-Rv=F=xHWKl!|e-qG~97; z>*3Cay8!OBa2LW|1ottxi{UPTTdAlh8n}Joj)OZN?zM0i!CefuQVHVW_JunR?tHk{ z!d(P+G2BXJh=V&H?jpFADuBbC4|fsV$~}O?oey^r+)7oz;m(J<2yUes{DxZrZJUo8 zw+2AC6|na5(c*(ug?wCDfZbC0a4Yu#gj<1K!}+*#*bDCa;jROBUAXJPT_0{-r9cmS zL%18k-5BmBa5sg!8Qjg`eh_Yru?j{Am`AU|-i`8&EcP`vg92Z?GvZu`Zyyo=aewRa z;aMO<@#zL#d{Uk!Cw_u1Q#@HZToa$IiPuarq~+)goIA8L<=?iS_58;wZJ<~5EA_v< zF{Fd?C^AQN#q|~RzFF6Lew+J?_|JM-k3Z2*#K(;h@ynYC$VG%we9uVB_~Xfz>8epV z?H{&GS66SDu4sTL@2!C%T;_itihsGci2tRt<@3=4#q;kD72z#LS;iMrd>tt~)ki$X zbUT8LMp)*{{D{_ye0mQN@tn`mBukvbTO?Qy=XhIin74TDqk00SP(EFU3%mizCqK{h z*@7FEym{@7i2f1pJof(QbIy+LHhs`*hH$-)|KjV9XC&==tK*XoRzFpvdH0Yx>+k() z+LJ@$A3U(({DjQ~0W0H%6}*-9dFR?|+l_oDx>3-q5!cd|KKAdC4%!l2A@Q}_|M~os{*~deQ@u~d52?%hHY$mf8ve{Opk@T-*~HT)uo~98-I`&cJd->DVHvMFCBhAQxEgFhn0t5?JUVS!f+-- zbt!4t&{Ja!@rk;S+_a=@@rlggnTAp^{0u^4`k;xr%p4IKqRTM`g=eLt=nSFpnMvt7 zb$X5u%8XA)*M;jQ>e7wTmf^wa@hM_Q7phxSp>5y}fE)K@EP=ZbDlye1W~S(?NVi(Q zVL(?ZYON4MR<7PJIXNveEl0JfAIoKs}=kS&6#r>?}iMZbpL65Hwjug`z+{ zQ1vtzZcXXJGLy3m8Sy!3S()a<8h8qa3BIC(M88UyDCAq#3&j+l(#d+fK3F_IbddFU zB}BxB1zL|E3 z7X=EsSGE`7ZBqnXHBP_};|1J7dVDkK)fUuFeN#pJnp^<~)EDpwwUdGQLHe5O-=e8V z_Y{pc9R5NN5x&b`!222qm`CHmPi+N$TzZb{=?I1fi29DD{F10WdqjzRTabKkK7D*e z`fnZ-@zsf*dNj^O&~wus5%E>x1bmLh<2T99SRN|Es}bKge;ImHd$fH_q%R=8<p7bN(^}g_W5Tl`vkHC={MvKO)VLldJ0P zL$k7Sgzier%4M~v6j1-0*-hjx_iyh|!RIR^FLHbl#qW)^{(N+pcs`KiLw>%P;yc)Q zUOz}Ye|nhp{FT8XenhbK_yUUWJ;HjtCR{w9-PL-0A;sSsZ9U#MLOlPfjpvV1eCsaO zpO1?a&)-LKD)Xm=;;-0fpZqBCJoi(EEFaaPt;cgZ8S--smkxF9dCrfYXIMaVRPYmg z*c~Py$7_a&a&&1Td@c3Y0pkV!8};uy)QAm@b#q)zHzZIkh{~$Y` zpJ$jfiO1lGc=K1yVSZ?1eAW+3Ow}djrt@54qRx;F11e`%3WmPAZ~0%}O!2XdDA6*0 z*hPNxa}1-02|hkXc51r_QU5;K0v^)}*dRzievV-=J^^EITlshm7x_fd`12u+cOTO@`npEsH<{$bRz8K4PeV%2eA!ES<0~2$ zZSf^~grMU?A4|UJjW(vxt62AHBSpH8X#Q%8f6S*7l&_<4>>}}t$1%>A$1%q3jbnPS z5V>46yaN}St$3q*L48T)tWxdr1IBrILxSD}Lka2$77*M_u!!IZg4YRpT@m@I%e3~} z)XfH`WhOy_i1^9iLP|86zKJS(IU+67YIsb%Aw`!Hh21kZAv@8KrboLsI6g5aOXUSn z6z~_sr;~FkARhYmu(T=ai2_9p%K@L2I*P)h4QW~6Suhhsbf;yefZd&wm6#=_6-r=U zW_(6kA_S%wz-kZH>5|Y5W~%zgw9KI~VK5g+i%(CRVl>i?aZvB*tn{?Ryr6Vl1`PRw zb)u|3BzNEU74mtI^x!w7FTbIFdWPh`i0q?xXx!RMdigr(4HF^sBYL!uYnC%dP=3B- zlz6@m`7_Q@dA>yN8PXHMIzfLT*;hZ2J^BIJzf;JrmGjpSeVJL}`R)@0b}IoVJ|JLUva?T)75GKcm!6*g>&5I2ballxtr|LkS>DW8NLGUrg5$-+0~WEj&`;lLx~SEzh%7O5!d8HmLEAk&6x6)mt&N_ zv+|Nnc6oWp%R{Y2d&zt#g^v|{d6ML`=|u6|R-!M3`tJhrLscFr;#V}bo_`#*+a_vf zd7fFF#%E8>Gyf#{l;@d)NX}iIXGW3!D8(mR0prRhr!2Q}_C>_U_sO2Pm*(REtVhT% zxs%%GkG7&cu8>_+)XsYQ9D7vIdyCprZl4y^zdhAH6}t;M9@yP4@P!Eq{I z4;!!dOt^TiwJ$#}V95c-Mf#iCfi=F_pda{;^qivn-Tskh-@ST^!Wr_@ih{B2AGxEg zw^}L9$;G1l`6kqd`;@4-_hW+x=ipsu|r@YiTU}eQp@o3w@HN*HHAV2RN z=Nz9|-Wl@q3`42Cz9M;FH$d=z5zVvWdkH+B+F>8*tpyE5cstTBdGy>lYB$bbhI%rz zI9wkzS(liLw%kx%c2=$-k&Lwf@TunLhUzl1a&%&dHTyX6SrI=xBRe1~L!Yk048p{@y{zb6b-0Dl{I4&^$1)qlhOm zOu#o$^uyMaZW{H6oM_AR4UM0V*9E7OdnCs9I^vAT!srW?ALoTwXK1K1aIgu z`Zt!6-I7OsX^@a~8k)j2HPkn&+${x!OQ>=>^g!^1Qf^T#$U6n{rZl?TY zI%Pa{f}mTLZ&&eB`4T_ArS|DU?Y)WWzvU6pZY}BvXsf&q4_U^`fvm8Q%JAf zAba+c38I`C)X&b7ea`vIFndy3PGTy!r*gz#bu8VIj}=JI@N>QtKio@{^G6E-`}7u& z(Mx@x-cf%X{;(*o#bW~Yr*f~+JiUPC?W1Vi;__v9=ifWG;l4%iCdW6b)2Jrg zl?igN(m@gBnF8nszxY#A<+(<3-2Wu}e=GfC$i8D<&L=sE=_cAkUYBi{E#&NV($8}I zW{R&yeh@j{FA+EEXeOp*r5m05nl75mEX~lEm@o}YVB%Xa9WbxdW$1HsNt$>~PM%(u zmZZr_)@0_Ur|WYJ8hut8&ihQM6~#Y3NrT&oILcPOm@Y}ILBuA;XXkJhp*f;nxlz{Z zodD12CMW8Q%O^mjrhY@C{^xZgZ^C&an6DHcO?Y*xU>xDNjTJAwgy$2E+gkA|ke**j zIBu84YqJ!;N5T(F_zA+9-t&YrJ=Y1x{a$!gYar^&^!Hg;%UFLA3tMU_o~Je%!a4uW zgrg3|%bRevk9$aXA1VC+Dc)DY10_6^aBiO%DSi~;OwS`ye4KGy`}V_gfo3PgtI=%C!G0TKsav8$7?g;T%W^)Gyh5mZzGZ`n#O|O)`UkB z&hhz#ccS<`gmeBU2-i@&(nRFfl5lUr+Y_Ejct^t55{}0M@H$L5>*o`M<1qugN(g8D zDeFt6sVJY*Hzb_%_a)pUUxYJ%@(E|7NX}o@Z?b-p`?stQCR6`l{V2=-S}GrpQT*R^ z_c;(7n-HI^OJZ?VVq+7NbcwXd0?3Jt)yHSUmJX&YHa0sa32+XGjm=3-!vqu%8=DN) zkQ$!|TPm{*90K{LGZGuCi%&=sIYYja(vovxyHi1oKP2G~n{cq-di5X->4a?{u!KO{ zHv!Mhgq;Iy*dxgl%IY+Q=89*r~|U zSW5={6X`@X9p#Gr7Tba~Nom>obU0Iin}{?S@p|TqE>+_UiE-w1X5LyMQI*aq65|rH z^m%re9haMw0~4H_Tmvl2P&3B`g(`74bwa)g`H-Yc4!2VPcyN!YA&Fxl-)7At` zm7d#AY9DJ)K{+(J)R-5~3>r9ZqG37XcyLrsPRmitxhfUpW8#BT#hTK)M64A)I>j7( z&O#sM7?0{$QA;NMt7+L%1CN>U#H`r(N%3jC^2~aAz(CZxAb&BS|1^O*v1QS$BQ*Y~ z)&kPw!HHmw)x_s$Ohch~UX{+zV2IBn{?ntOX`p%xiK%(2Ow?*f(a=(_P9qK%XmEq1 zN>|0jXJ%#QWn|@MYhXj8E?W;Og);~k(NBX!^y{Z6=*0j}hpvl0-T>)9YgE?uWFVrHCBs83SAe$?2pB3omWWjLn>`%0Ido~F-E%NE^T>5PI2 zS7#{#yo18+262h{TqPbH?VUBEE|}g}7l2R~V?8h|IXx>L^-59}FiEE<30Y$IacnH4 z>VqlJ?u6gndkKW`huLbScndof(?3K{1O345%&bY7M81)?ePUUg3HrMCG6x{sWB`A>aQ~-gPJp@&}HUk;16Tj@S`o>@GmhvtzW-* zRJdqGLptAdLKqhz3@dkn{IBwQkc>le;}w@H{I&Pfx?z9X zH_>W@@ZYwf{fC^sgwl7S_02fihy7lbNdLB!K7XRf|0u2RzDMgYwaH(8L|WJOnk3Ti zrTtvL(7I}XLFE5LUjdn(wUmAitq)~(5b;6x3wYAYGCemvw0}?E1E%K|@M!;x- zoJ^eT?gD$RvSFS%2~K%u0>oWd_=f5(#&2OIz%PR_K3(Y!VdCZ-1ay>7Hhr@o6`mKl zJOsbIEi(a3K99`_Ec5430ht$w1*d2GrNh{&P9eny8+4#-RhJYGTj)l_r{|i}Nb#`s z%^Z*IqK-H3P78o@CU~BE7z~G?$1Jxus!BJ$R>T5l&GC$L zIvH|2Lynj8=XgiqobLbN|63g3K7h4m8A2$BqYmPDOsl@s`iXUc{5<2VJMejY4s{t` z+~*P6(r;Kk#>)_bOwZ$QzF4m?Wcs-*#u4&wepZb$%?Pm{aUD4ygcz=V22kV0{SFa) zj-O{7p*kPL)%2*J$2h!L?=f9mE=XgiqobLbN|2rIL5B6}b@r_4flG`4A2Q=SBEiO!i z<${E7q4OKF=)C7?ia$^A!vHbgtwHAyehv|Mdpb|WCH3(Vyy=Zw!dWB&o&KNwn1S713KT$Ph{v&fe7z&`l=+Gfbx1?FaU8!FZtNx4 zr*MqIzKAtKh+znEKODxPF5)=M7oSB~8*a=OYl308pQ8@l7~TSI4DSgy;#hIS0|<`> zh|dg#8^ebY#J9a+{-fc>veV(l_zbu;aO>f23bz4nq%|LIq;)32SpYG7Hr$xc9Juj$ z&~v!gR#{E>I)F&mM!2z@O>kqn-EbpaN8!f!Z{WuG(ZE1lLvIL7LH>B^D(ofn7yDI| z-sD#ySV&OQM}+4SWdF-y!W;G#@o@wT33~OT=Li-P^zBdOkpE^B;d+9H2|B8$r5~lV zzX!kOh;OjP@1SQGJwUd7K3JBc{P0`q>8gCt>+_HuA|2(2-=9c?Qt_)iQ;f8xK?wS+ z%wDDL<&u9EoJ!1wvamMDA$5t~HcNC=A3gL8tdaP-CBEGk{ciZyMfAs+d2fqnj`Gh2 zTJfuC_}w#gelo?5^T`8>FrQ?gmvh3_w9aiu`3cE00Ck)fdKG1=9Lv{apo+gYggFU{ ztmPz{$U0p}2U`F@7i%D&{T1o)O{8*tk?VTUSK=%1=@4%)^3<9Zv)+@qz40BVcv;rl7-Sqf z{S3NbcoDXrJ}uiXa#)y%fd4o?dzmm8H{sZNyg@h2xZ6qP`$fA+oh}I0r-tRh8&orJ z;XYlLO=&Ag>0HHe46Li72b|h|;D?^5gBKSiWld7WSkeRO0%1Kj*!bpA72P;ytLcVx z;#I6kql|~yg5fwnY`MzjjB#w1$`6N)dxD1OEPbwCq?Gvq`3gqhk#kk~xF1)_4-b*U z84Xb(Bm%tb#!S)vfqVp8W70C)9=*9G6lZNUzJ=#xrS>dlGV=Z5IXSDUybj$RGWy2apT2d*((A84v5) zCK8M`E!y;a31JV;%``4Hc|Y8XA_n*gyOE(U;S2)_XBbL2!)Pf!PKwt{@%d6b(`OBa zMZ(uYGLw}^zepuBUi4k~-F_JSL)#xO2ydSa{}{*ku*g70jq#w-jJU3ox3{-=%=EuP z#Y&Z{+*7q$^%^y6-FshculwuNtyjOn0}UHBZql?_^9MC8TDEH4rfs|S9XfXE+@)(b z@9qyh+@oi&-hKM^>knJJw7!1+0f9lmA)#S|28TyPMnw-9IxJ@Rh>@d4j~V;OqvK-Z z;uBy$b8<>*+V~0S8JSu7#|+syxf3T%&YLoI+Vsa~nCP(eqr_jd56Aa7Nb~#v5&nK^ z6QjR^!!=U))0x6w&_@bCOZx>zN#XZ(6X_>Q;iu@mPfUj`7!EVSSePA#!yjG(4}dRx zVu+s-qXbzz%JDHULyT6%iSP(`E)qgx;K`xJIV3+U;v<#e@IAC3hzm2$L^+nrje&5C z7uP_gzwrnDhpo(D1>hYEZxIn!006`~6CMkY<0wdJ8Y1|vA=sK=dxD(_dK2tHun$3B zf}sRQ5lkhRLolDGC{Oo@S0EfQi7Wa?jd-X;0c1~30@~yEsW?P z=uI$`U>rd`!TAK265LF155dC(PY^s$@H)Y2gQz@$?FsfF7)mgX;ADdH33C2R3Exa` z562TMCU~8o*I-d@dxG8s`w)yKm``viLBZw!8UKgnW-1Y2lf}SZiji-oOEnPhu*BLtbe(OhaDA z0T}W#J^*>bmQL{?z2;)rBjK@H{*?Pe5%;{i$Wxis-^N?#s zm0;ss)f_O)=xb5q;(Jl}&1bwsdFVY7xF|0h%HR<3tSA@1w_q73%Ew(smQM&e%wd8K zoJpI*Fy}!~j<6s^Il)jug7|6tk6+c~w!r{Dm@levj5jeI;s;6mM4U`DV}AH8v=rkn z@ejYlt5@Ms#`(NCAQIYRq8U~2yLe^`k?Dthqd=9K4p9%B&05BY`XoZDiA&T6eQn|r z^qX5;&~MIJ(2uiTA;5xu;g1mey+l5u9_ahB{Fx|eG>}64X-pxQQk`0X?_h<(SAR0#uOHOK)E$6Y^a&0(`l+$pW27I8 z36`+F3>SJ9)8I88_}m3rKU$#RW5gY60br$wYXY=m7iF-~4~`)sJ_h=e`YO@J=TGuk z-nm4ZGq?U1g`-Qfhgak_44PM>t-atz`lvTbwCj(5@z8}|O0+}9);U(8?w{J?E?agi z_y1Enb;$GqdklYSbB|>GK6b;O+O2P;cAxjs4N4E6qz3H*b+G}gh z^!R?$Wo^qIb;4i%@v^pK*J~|mG`OPevLHULTI3b&u>l9)SpUQoZM%-WzWVOK744?Z zt0wNeaYZ{TYSoBNJ+5lMYxhR4kgTiP4l$uWRNZz}8`@%f{j76WwR4B}D}225-`X}U zhtKMh@VEBU{xgzSul-xwt+8&v&Y%9)=EPn&pZnl7?MEs8BYuy)rkz*e_w0J>u4xk@ zKkIe*)HQA0qv6XIw7IUmxHxddx2e~)->>cHf993z+Fq0DFWd3wb?uo$pBDD+eM1`^ z`Qw^d({E@CN;b?|^!^R4?#!c8lWYB>eYB0w&Pv1o(H^*+H+;hCf3(}b7_)56`G2%G z>qqTb|L{$1$hez-O`LI4`}x7a1&|KCKct?c9gHuXJ|HZEfs|sShu?bzA$l_NjASqyN=@SFmyYs~i8- zwi^@wN0Wd4)%pfyj-42NM|+}R^~{5t?pUnts3oF&e;e1WyiwkuoMR|&0KHJ&0LG!b z0rWPg7OA%Ey^1}1?3GuA<7#- zZ|b_ z@&+&tQ~VOqr3quL3zV)lsACKP~HG)P~H$nc?0N+@`gCd8$bo+4S+Yw z8^B_eH-KwV-VjH50~n3+1~6YOZ#RBCc~H5O?$godn{}OD3H5pBiTewB{~qUK=zgeq zoy%!H5A^f$dU|!RPvZl>Z;T%M*T71%k`Ig>n&ETfowu&8|0mU_dq&=GFaDJ5lRq|p z)AFZ!`F!1M(kqP)#ra&F{i*)_-_m_n{`x}Bsf|eA{nK~oJC%3iIrB=aMpKZs- zcFasn^6@^M^v`ZhfKSYjl^r+z_J~jGtj*ugcyX9d>(mK>sjX9e#y&J>%_)P{=h*k} z`wmWM==01yQNEWekMtRLU+&7yCt`dOKHIf?XU-U(+8w7=^~oLMQ?zqM+L|xN_{1%K zZRqBL@jlOG?QJo4*9f0V)31+ux8uD&pZP3keg77JpLaU@KXmEVXrDuVryuR{ajMVH z!F$iWb0Xen{NCFw*Hjxb{|8Sdv3={++2kB$jG^C~^Ldf%Q7KCK5nux91HET5jIe#xKnV35xnJ#`;_{C2WW z>pEjjcl^`Or{I;^xBosj+$Zh6{bM%0k>Im##>K0hR>%3w892Q6U*CoJ3_Ra_K~6~> zpBMcC`@B?Rf=`zJ^DnM{HQi@P)sCNQeoFHRYTo!-o!Uu0HFpiZFYH>H&%JSTIz9hw zq|b=pBUisWIoK!s%E}XWI*;>NHMR36PqYs5*{J;^a@V`*KGoM8&42P_vd`l+ew}si zuYLJg2Z+P}{!2GmpNzEt_`kn09;$%`>>$g(_6q-5hFix%!K-NRZw{=u%YT;XXTn-N z|KSM@Xa3YV%u>vM6=99unLmDB;~_5oUpD2%f&7`XX3v@X#Ju?no_uQI)6YCxuxRmf z&%f~ElBLU*uUNTi^_sQo)^FJO(#xARZ`r!-mF+uTEqra~>$~1~bN8ON_P)Ju|2qeY z4!--|`-eXG@bE_;ANl0dqn{l+{`nVQe)aV?C%*me`;$NX_*3!Er+zto=Ipuizy9|7 zg^Pb&D*5xT%U7=ceeL>0PWd40;-o{k*$w&RTs z`~STD9&S%X8a;57;PIoql{k#I{PVyFQemd)&)H*mJOUt`Rl)pMv4V4d{Jgp@&ed1_ z1pcmOW&EsD0rU4Z#ngjOHG3%{)C+#|FHGfZjYT>+y>qoSr}9$Fzs0W#6+A9db~5C` zI%f*M3hv3ns|Vqg1gZ=m9M_xi3MIUXK$TI1i`~I6$s-*1IO3H`IIi{Mr6;_)K$Xda z7E13CF#NcpxNVtY@4dLwxZ$Y>>;VlX8LwGB~eF<+(cqrj*2#+SbE#adGZ%23>;k@vh zN;vNE#7j?jCxI%H3GYmJKH*&mpHDdMCC96Pa9%fGN_cM(t*j-S57uucyf4KU63!E{ zJ%r;#9j_w7eT^8rmyK{g!jBOiK==v5c_T$J;lUJtp70RDO9&4m{5s)-2!|K(f5LoITLdgwLS(M+mP#3LuW~iiGP4 zuS9r0;gtzj$ZuPP@B)gzhw!z8S0%iV@M?q?5ni2eUO%fz_%VvFMR+mc_Yz)0_X+pYUkH8xS5xctgVVgf}8QpYX5gtu=UBcrCuSd9^@CJnE6W*Bc0>YaSUPyRn!ixy+Pk1rm zK7^ML9zeJ}*Am{C@Iu1-6Ml^F3S=-A6JDM062fb+K{;8}w-(`E zgf}K!LwJ9}eF?8X24yti)d`OyyawTV!W$EwPk4XA*AiYqBigHw@alvY5nhAvWBfef z#r%A0@q7tCPq>mt?Mb*7;r$8M5MH6Zc;1`v>V*69^Mprp`pzPK9H%E-&*=%z=k(qp zeF3K@d@ZLZypYrP5b29JJ>kbVJ>kWizK=*>!tsPFQ$+nM3=r{Ngx4Tk!|}c%-kakI z_hmd##78q8D)2bQ!v(HqJX+xSgjb#>@B+dc6TX&k5&M7t|BnOz|KkAfKuVyULwJsj zFWzSoN;_5(X)g=za>6SKcC_H7qa8lDzeV6;&kLTj!z-C~HKkH|-qn>x`QiB^yl|fj zUbvqHuT07}lW;xZdP2veg~AhF0lKG<5B*wzFa=aVHdzSJ<22ETt3Pr(!=RdK9PT1|7_(k zz;XY&xUzxU7|;Abx$Oef(y#`lV}3EF{7{aOKF$y28S6*GB2a_n4Og`n^2^_}w;kmi z%VYlHSyF62E+6H-3sA>?7Lh+{ zB#%^mW4}?$5B8rf@HE#C({}-BV)>hFO`E#-&$1lx!6OElIu1SCvcsAtse zDfEpwN1<;}0!JGk5c&pl6cYCs)CW1_Pc8KSvG*l_F`q2 z*kh})Q(BW{NXRm>5K4tEqKZ&ktwYhENR>8Jb<`GWiM5orV=3BdJBcm!@0@q^@!)uL_$Tr8w8zil zWAiDQpSy7JCcw3b;|M4IyV=JV@sFPqBE~q%SNr@({5#^s&+y~u?hJpG z=ED?tlNjS+Jx=23XOEZkM=$$$CI0kwIq}zz_BLME;COtwKb$exh$j99+s7C2=Q#d| zzi#$?@b;DaJ3*d7inpgf9D)4!>dj%y&ro~&FdtaLMhuB>gk4VJ>uR5WSpHdmVSVhO z;`Q0=gV${+?PBk5mQOZc6Mwz!?Irqy?cD-@e4X6tM@ z6d$K@3&r14oKJBc#cUn15ye(2UqP`jm$ZL8#X7nU7fi8+%A+Y}>*6YkwN%coCv_CV z*HFu(r}!I+**ZE~XE#wfJAQ`K{&T1L8C1@$kFqG9Mdb#n??JJd%I)(vm9usE94cQ& z^(_=Hpg5mmHeXvQ{))}6zeHIO0j|Bg%q18-a~N)#fK=)qIf68W{NLRoI`Ow#TJU$^>#kR7Am(= ze3s&jM3N70ifvSWnqpx-k^e%mn&O`*)=+$mVlBnHDArNDpJF}5=O{K%yq;nc#ak)P zp!he6vnc+AVl%~7igPIbmSPLVCn?US_$tL#iZ4@aqxe^fg)GwkOBAaqK1{JbiOB0x ztf6uv#q7NR_FjRO%Hyd#mey}Tv5v}PS$*0+J{0Szyf4Msw0?7n4OE^&aTcxbOR-fuPynald z%Gv!%4sCA>Di;=z{HIdP-ct#rSWV^IDb`TT?(fXhUpXq*Qh9%h)2Y7@igi>zj_Ff* zZHo0&9!W8Kucti41}dkIv4tG!-=E4&RKA$v42lO(oJ;l96lYO6yIwKVc$!hUnabH& z+d}0nsXT|u(ALgh0Vrv58XtTmDROBCl*{n->-DIP>|9`)afVjGoDrr1E` z^(ht>68mE*9!}-;C{|NBc{(Qu8j9ypc^1`gLa~<06DZbE{2s*`+8+G8Ka!rxKO|64 zQ+Y><4OIR<#ktgrYjmpgw522X7*Hw|?94cQzv4!Hn6z5aC zlwsOm0Tf%Qd@jYeX}oPIwo&=J6knwED^VF+VikDHWrTAlt zbri3mSWj^_#q7PbDij;2d^pAIJ+-P7o2Z;Tjezg#qy5#1$}_0^1B$aK{+wbn#S~*P%F{%3~ziek1dcAa89mH$AoiQ?}l&Z2lD#W@szO0k;yt4?t~l`p5*O7UAvPW4+; zY@_li6zgbz=_nQ!lYD$caS^Q_MzNa8GnhWD-=1O(mCv9!kk+q3v6jl;rdUUDBCAjJ zYf`MI^3fDqsk{xv1}dLQaTt|rC^k`f6vZJ_UW?)kDmPGkk;+3U&Z6?w6z5R<4#g&_ z-;m;bDvzVsN^ug!Hj2woEG!}UzDBW{;w*|a6tAUNOYshhbrf%=SWj^eiVYN-C@y8C z8Tjv<0kVF9-z-XqJkN=Q=Q2Ewf>jV6$I#V6_B_dG|859UKMq!%c>Qs7HInI%r>l+( z$HS@^uOAOjrg@Cd^mv>EPuX}p!AXv*2)rCu0eI|K6(aFY=Gu#^0puxpw8HaoA|Zd{ zLC;}{*vIwVX3!eukE~y^6>#{?Gx_-+ey=Fg$LCp5UkHk^J^htlQ^AnLrL*Mao{BG6axOjd1c2!>P_-+(p&(YrmkG1z7!Lj!7LvR9o z$0=_w(cXVV&Q|l;^Hvj=Pi&9lyJ46<8@~kODiUu$%|5<~d?IHL*Qbme#`QwfB1G16 z+kGs4t$>j*Sp!<3*`L{JU-a?BhD}k6%J$y@$Omg705o``KG5i1B!hw2xo1p3dG9!S_Y5 zKiJzVh%ujzb|B zc>DZL*5}z=$o&&# z&lkb$Eg}KVgJi`NzlRu!VRpnb%#KL%z6X2zh`fJ9zTKC!kF1Y7;vwssj^l@5M|%jy zzpOsKKfvB%BJUv~X7fF+U*WlkSzwr1K#c2!yc{tv$BeRwP#-hu!1z82emgUZhaEpS z%JJPGCMhXbIzN*2z!d0*m(?e7<@z{&S#+2W#H=-l@qG&Xl|B{^#)ukZh9vJlIQoNp zQ#z0F{TlXm7`{J+*>Q|7^1cmwYYgRhytB8?$a`bWU<|SOg}jervY+3{=puiW^2f`S z+E3o6nFvu4BJaC6;v?&8IRB6t+=0mv$1tl;aI8H(g7KTG2@#xPpHB!*wV!Xv`!x># z!VTZSZgN$1bhEdQjQ1dBbbtPx+9Q8u(=~pGBk%9t^8NZz2MQWRll$P9UC%;24xX7c zX5pjC9pk%^I_gVV#zjrLME#`dUT1mL1`Ye;Gaa4V;V zvI;BgKN-_-UG%ZQ_5ap?=ky8FzrT&IE&jP`G`SJIk@)<;iE(~=$F!>5zIhq9?r+vF zIx}Ht?;j5QTo%5#XMXc+udX{bPpuX_Pj~X8yS^t6zTeRIuc-$X)!*8yB08=1%g=+? z9REIY#FZ^uMji3%=5c>)mA$72ZvW;z4Kw|(fQH9bAs?&$ND zb@Y`CpUuy0x=Zu2^E0ZAuNw{TNrv@pwdBaK_s)0eeIv5Yrc2@KPTwWp{e3}d%NW0gO8&kJepRW&KG zSGB|-%(kvo1Kn14eR8cw=T9$c^zDg}W0o}UxbE__$Hp%P{W@vII!(@?N8cabQh!mO ze%IZF8O;tnxtCvOpgzR^o4bVp!vZRGxiamo_7^@48c|duY@u+W(pMkup0r^~BRUBJ7@noYqeL8?)_r@ zHePA|%Hte?Z(|rW zVONGQW>+K4sWXRunwB7KsL}766Tg~P{T$x8$~SKu%b&0;;Kol`9d!M#Nn0KzP3qU+ z=5`+(W$Kngws@Zz?zi#B29ZN&y;o!0{(H01Cf@GW^i)rC=hYrwM@7#)=G%FvZVjffAqHT6>JC!e12DEG!TkIH3rQ5~oBe{228)}62QPe||&E^IyY_n`s%>o5K3 zuaNiuT5@($$6mFzHLKlI6Sj59>64E?x_si-H$Jq)4q5wF+>Y6uD%P9OeVQ7+Ij}~< z-c=KaZHv0Id3K$De|fU*>l^=Gty=iqnARDYJKKp(bH88k>lZ;@G55~BG44g1^5ce% zt+e~H?pVjh>9H$XjlXng`~AIfF%6(SH|~wjc(VQUkiWAvy;l?sTe`*P`8L%%8=Lly zTl{^kMl}u|*?i{w#feASp7tB^^CwxWjx5jqu}}TLiMDdynb{9h)wMf3tq}41)_Kt* z)VF?IdOPl?24eD!ogZ$_8d;}(>y>F`r}SCyN6%)H9wjcnrSq+FuxO#5+BUkdLi~aH zUFJMGx@v)M%J!)*JU(dFH772uNwcQ!58J5zw|2gun{wp$sNCD*GB2usUv?tz(2&{c zAzzQkKezA6@Rl=k%LH}rTc-WdenDRdhiYH5^qssm<7mgz&A$Ajs7}J$%V&qZb1`W0 z$>fQL)7R|&eexS+7Tu7i4nbJ^$GK7QNz-nuxOJ)HqqRvPi?nnFN{C)rG&u^@qpK{sz#>#*Ck1e;R@}>*Bc0DM+BrIjY554|6 zzO>2c#Zs96gRd57Dz!^L{acsQ`+uz?Rvz}-_K!yYet*)OW4AsVIj}{U@cy^D_<&tO z{mZ?9-re82+GXdq=AmDGmh{;PDRD~3&WDrs_sP#YGuB#^y=`pAqg%fkniuc8YSm(4 zf5gb}kM{Mx*Y?uDezz}AI22stk@t-5y~kbL{L|FFSG`tlSdk`VcDg~HdFvLQQx~}J zOO6Tj+uwH9lP&3$8f_o&wEfb*>Q~k_>FZm*%-W8fo`>vtnmK8B*VVb}Z-l4(P}pPY zvZ&Pg{=q?)w|)It^BtA+o9Aw6|7VxbB}+H`_M7VY*}G>l+$NjbLFlR#EA<6iuN-N* zH9V|czr!i{V-x=L%w92|sIbhzbyo+PJJePGv?=9-ZhJ0OJXI!emT5(YD+6y2-0}Mx zPpXz}v9aI2t3Pe=>Hl}s$M4+PeKJ@#=A7_e<+V4{t{*RK)Z+aan423_C&fIue|AFn zMDrglDoq>H_g?Gf1-W|`7+of~g zM;GEf=H%t7Jg!asd+ES~kq4qSU;KI2uYb1Ajf}M|`fmC0fN|&d&uu0T74}UN|d~&auT{qpD z-23LUI?GKLtpA=m=JC_|x!=VLG1tGk^2UZluk5v}yU$O}8$9pnu*0dx&mG9^k{Eqy z*zu9O+Whf6AU<-y!D^THEZ(*1je@oMTaT_xm>ylW$(k0wuBwCn1oiCi-tIKC-K6Vb zpZyr#fAyIeO;dr+EA{u@-tijagKhH@sXJvE@`1*3QtcX(y z@4DZp_o-g?S^DR{X9nEh&@2PjweH@6%DtSR@~9}NJOc$c&su_8+4_Q;S2LlER~w;> zw>m*gidnG2Sc=_XM27VeF55Cv2k_KQV*x z1a2kv5o5eM4r6;v97g|H6yqm!u>H9l#`?E8jP(Pz5&Ni*^}{H}d}8|z6yqmwP@YLK zzHdAbu-OUcaTtc9P((4lVUO+6ZfE%#B-=A^80DE9#`tnL+#m2o4r6<~avb(>+(&R2 zj}H@vy8||J82cli!#IA6INT4g=1YftY)=G-F+b@X#(bMOjN>DZ!nXedVBc9nqQc)>EH1$(e2yptdBq`)vxsths);KlMwjKd(t*F| zHx{1%5zbVL*T?6l_?IaYX-<@n2?nBiDK1J-cW&Do-IJ?u9eXSgDU z{ilKF>>99xzsL{?{m-5w)38eP5Br?8Yk3M2$=tbJ*lUrT21brLuNo=E^;{igWIfYi z57#Br!F~d?4)c`^Ei6vO?c!<#&KHh0;7VVz++(<|fa~t~3m2Hf;$xw>9v*erB3!M& zPdp-btXW_L&ib#4v$%fAIC0#Ona^HJtS^cC?M_G`y~}9-05}w|a|HNjxMkM;03V$#498E-GEPkt{Jk9h1?2RZw}vzi97gnc;?{=P~ddkf!w z!D9^T6mLbze3SDRo*l4f9mkn-9C(&bx3|@GyzDnxlOZ!aIoo4-L$4%eUb|$RWK@y4 zn%8u;i+T>5?5z$ZdpM7{H9>vA`7iSGT;>eq2uR6c;a%=&~h9ln&Ii9sjULWvs zrTQhW6Bg0Mpa6x=nFqift6L_u`8v4x(})m-uI&`|+YUkjm8*SD`qN zVs`(gp|}o}hfrLX;-(bWqgYFEeTqXVZa}e)VhaCDmWJA zqLWf&o*GGTBnU8oND#;z1dO+W9TcMoi=&P5PyY#H;**l_JUk{cO0JWT6f*|v#K(|d zD;XV41fydoo08yFkTIZu@-fL&K3OY_p4<|)L}4@p7==Qh(TT?N)W|WZ_8$%;#TkSN zjKk9eJQCUOnQP!#M>71wc_bKqJK6`1HAFbe;*8z_j{V})39dYN4GmZ$bH7HmjPJqW zFWe^zVzG+N;TKYy(-QRKO#S4U5iR2kH3lNoz>^LJs`HdC|+utUK|%W$-V627iH|b@{X!F6kf>0j%q5jIbnx6q5SU+D!=pNWr;VF z&fzwTCxo=yl+7nmAJFZrUBA8<^{e!68D5U2bi6%iuU(&%TOHWB0kVR@A(yd3e~3)y zo#gp;y!=z7qjpU6581J7u4ukR=J4lPS+>XXoZ|YzKTcTwJu$8Vn>7WR{}`-Z^WW(XUEFizkCtapPV*^sCH15OtXzR-t^RH#=FN0&`*`Gr#k*6H znr&*l^#eaeu6cBSIdap1r7Mw}J;PQb&pC8qjf_=$%*ZuYXRSqUaT~Hu=3|3D zL!MRPZ<%MPa@QlahRxi7T)n%`M&!EpDt(UJvh0e?^B;efE#uAOHX+a7q}_}h;*hzp ze9sodS##h00=fEp=dH-i6Wq5UH^m&5dCs<3+Ywtr>dE8X*5G}aXPvn&b8XYEU!q(W zx=!YXzl0r#)dNS%+#36x%=OypUtzg5J6-15v*%@Q-ri~_mgkG}Wv-d=m&~=3ddkOx zA^0oT4bzG%ePsBe2~r_6JHDgO;(p;Da84XOh&*KVwlE0>pGS3<}N9O8VU&&nC;|jrtlL_}W%Ul?KSmxS~@5o%Yv7$U5Yd40;T>tUgGS3?RzRY#L zn`LfVe~RFG_hp{{QMJS9Pk&L8dA^@f<{2R$5#D6G%&nEr5&5kmnVZ(uJR;|#OBb2z zj*pSKIed=HwM)0lTz%=R%=Kl8WUi@FBM<9kRnW=Yaz9$;)*oicT$sE?<}m(bZZ;Rn z+*GlOeE!KvXfN}O9iwC}T%9g+{iAg{^t8R2oYf5iH_>78Y6%7~V^E&c3pPOW^Em%Ns!>?qX(d(Sd)x+=0To_d41lBinXh(SY;W8IarOVtj z^;4OftL%|^{;Hp4ZmaM_=Gv6%C$T;pM>5wx8!2-`gQ+sNc3MfeZm-NUT3wNOeubx` z{MYKIuzvoh9c6CrGE(Llm!`^?@Omb5^8(*97>_=nn#@geLu9TN+R0oy zzPrrxPY#l~&?JiB=_Z-$PP{8~L%>{_YX+{6xq0>`nOk>%L-@5rGS6{8Cv$!6YcjXA zvdLT{J(szuo1c8WnbW13%&qN1WUg-9R_4X7MgT^3?Fvp z-P`3BpA3&ni0atw?%D8RV%rUWzIiX)_xr1zV!Iv;udv~;;l%7m;cJ@L)+9we3qSGQ z&$)B@{}EnU+vVSjnS!`=a+8e#?q1@-v;SDCF7*)IdY#)ksrT0K^4fMbX<~Wtzyr^o zKSf;)ue7&c?c*v>@%!H&46xq)GyJc+)oS@p@fMG`SxmD(vxE;gGE5MftHtt(C;kye zRu;GKDr0K&;cwvypSAsJ_b|2C|4+}}d3^%Jt$Ww5{<&)vvGJb|cYZ#mrugsEhhf$o z55hBTro)5(xEub}u@2te$?oFkZ#BF%-&9k)wR^&()xXsi4W2%qf8WqcBym&`N4`By z{h*zv*e7agLBP0*Vuz@VlRHFj@z+I_|2VC!B(^lqSF6X@6gwC0@m)Eqir8fD#UL#@8FZCJL-i?(=A8Bu-`zB|p>biOYHqeDp`s?P=wv5`R>dBagF~Uz25n_saSKw(#p0!8;Nb- zX_>fjbC5X1GueA+a&vL;7gL_LuF*goxGwTklQE4%ZNq~V^123!ZGU{z_uCkaxL(!p zeZNp2@xtW!yN1lGCN5v~_R8R9e}s>FHoe@XLL70pGzHc>%YbsLE@-cAq8 zOll==-?*jkxRD*j8WZPT8CS;^{&%$wEr06WNvt|IW$Nvi%3|P{j|%S0Z!M0QIO+cC zh2dhZd9JNvM0>Hp@Xh~}|D~h2r=8n~UkWk(xg(v5nhW4fT_%#m+7LR>CqV-)< zIkCPjJK){vO~hKWgAXKXTZ{U%Ie7XMV`~2Nahn`bOkMOroxF)1#OojaI`DA$aB=(a z53R@7w-8tRSkA0_zoU41YwHG4}4lPRB z-&VXAS?FKq$9m$rLE+~$SKEj~3ui}8AJ{?kUwQ7u)1hJF&p(CCZ0@HOt-p0!lpjzK zzH!8#<)hX0#R@;Q@=tHxKs;5Xu69ZMJN$zaectVDtSbg@&FGar(nE|%{PJA07Qv$5 z{q~o(9&9H*&6p7Ne$@~$ve(rkQ3L)AC*!ZBm^pE6lYX7ri8I3gux_~BSlk|5#dbKS zu{dVrFR62CX~ji@zrB;BX(kHC`zO!YX$x<3Ez-C4dy=?)Z`p%Os}+TB{^rLT@gbu4 ziBFwgzR@A#sHW@oSN44o-ov}bt?q-{h#w?)7HMyG6x+vNvi9mit+F~(YA4QWJh_~DSZnctDstQ8(;dZY4-O1ff95AX@md*W3JDjbv1c;E z_H+<8PHXgI>$Xirw?F^=H0=Fg@urt%)zRY}Mg7_Dx_Jm;;?;4620tulBL3Fo>ju9~ zX)GR1oSD~uVxVY?_5VG*e{J#l;>l^p3=hM54#+tB?wF_HNxzK?deFL^IQ~8HuKJr6 zVt_hkPhw_!vD(Mm^J51+37^ntZuPj2+dv!%b&QLihc6W*&v%En76aE*bh{PUmL5lK z#oh+5_cxZ6#Nfe;ZhRlwN%YlrE^qrXOpLC6;r%XMC9!R4`?tNLJBYsq?H>AJmr!xz zr5&n;$J&ZDK55)xW>`Z}yRd5c%nF^v=K~YwUI}k0R{f*S?DPM?IQ?b(`wK@j66Z8* zKDyuKa^k@@o{bAO6oiL%YMN>5(nEZ^=Y!8z{L@&xVd(wd^ga#5=99Z#>r$?fsOlf! zrD@n#9C_+OmFDTa#fULKPadW3CI+AA_vg7yeZ{@!r$&WOYa|A2-ur0Omm2YxiKn79 zBU_3Q4L9Gt`CcP&(H}4F#q^a#|2J<>-LtQUn7i?fXK^b#id)u?es9CLCgSP8{U;wd z-c_{r*B$I@X(X_u;z4 z2+_9AuVA~ehnRXNV*9fSEyN?I*MC@jUtiHUG5h(*ocdzT-qn15IN4cTvqI-H`b1~Z zq;HTnv~73MP$#6##dq6@XLjqfd#lzH3;&(`&cE|?;vd7Vv`;$HPaJm7@AFUG`-*-W zH=MliUT<;FutVic7qp_!ceg9XAMGYqu6zBHpr+wsmzkpjf{)Y@r=|YfPh8$mZ1Q>M zxHUyj!&`b4xP9I$SiGDzV``tRZ-_p(qMvKy-Vj^-b7`OF)z0F=8U-_(#5NPBuD_gF zP_~2kAbEeY&__Da#q%h3Sy0MLGfg0e7gEK?s?9alzK}FU zGin#jcp>e&Z2m$W{X&}1rT1!MH^4r1yFIA?Lh`CT)waLv3(0L>_o5?zJeMqYR9}@n z{#^P?wP#Akw&&8=Z){syE_g28&@bIkE%mvS`n&3Ahhfj9lxkNdFX-@GswER}s|x-< zmp=Ni==z1m2J@n#J>DG^`B?THqJ z;RW1yd|xDOzB}H3_ZLOd%Gs(1mQRbM-Z@)rzkgUH?Otfv+c33A3j8n<{ufD=Jkx&= z`WH#R?AtMAX{RE|ynd#tcVm#tR3v!@8ZuO#MUrm1>Y2yAhf>Y{Zw{z`?V)tfV_N6Y z`46S3s^$y7+V@a8aL4LZXX`_0PW!LNZ(i|G%3Gg4qwhx#rE-UtSMZwrQ2KIH=#495 zA4&;nsvnLGeJJ&)`c~@c?hmE8&pRKog+7$_{@P=DNWF)W_tcdM=>ZQV(+uBHR=0;z zRYPGFL*WDINV~4%A6|VRMdrY$pcjT@6(uQky4vf8c zUmB+Vq)Fz{`_h8PJrD2Qb6>K&sT%L`#eHe>@wx?(tL{sG51*kuGw;4+@EEQdnsHz1 zFkav3?+N#%YXhh5SsHy`BI_mhrROuhy;;BKed#a%dlBC4?@N6=vWLECd|#?ubnVZw zHSbG@4pz8Y#~-j>1^@3$EBgKtHUI8Csl7*w&#k}TllnHjvajpKds5=|`m=J6-IK1) z-}sC8-92gK_XEurw%?O_t0r!pzV4nhHh;(U_KWXH84;>F9+~%~cPee`d3DM?X^de+ z=*fh8((+UHkNjx3Cmox30}NTa%!4By?ADs}uapyQW!r8;?2!s>0fD@9KaY+B>fyV5+bF=y+{1$o$vfUp^N zrGL5~Jv}n*t`t%B*SmA$?n*_C*Ni^-)?I0TdXpzL2Hur=1X#bA+~cmaWACt$H#*#v z9@iZA_oxm# z>E~*-r4Rn(~9f1zZmy?>hf!vd*q?(|Og?i5I=xl+e}uN6q& z^=>}){>1{R=8Sb)Jx>)#Bdj%^);UxlHTt`UuJ^YE()B%sW2b&uAT4>PTIBA}3#8Q* ztU;>P1=7lOA7>0&R3Ke$lJ#EBM+H*Fz!?<+XB0^9U#K4R(WC-ta!Qxko{0sLs?}5d z+?WEXT*I`{wMG_5N6$a|Z1;cyspAQs@}naPqVbdi?i&o0PTk=J@+}Y*Gco z%psmPY|@e*^RqRVZBmETZH9I`W0N}mytn^^qc&+m=Q$sKZm~&utLopm`HfB5b*Fi9 zi|sb)b9JoGjEy$Q@ZR=~msi=O!QQI&(qfx*&6xJpmXB@H`|2)U!S4h9Gq=&2cWlz( zhdq57q}Ze<6(_IUHO?kI-BfUlb*(e*d#A^w;4K(O=>q~K-+qOpf8h6$`Dj;?p`*0 z?gzv;L8X8H@5}(ac0u0R!1qJsJy<;O4bH$dVvQf+Eb`3sAh~>oNsxK#R)lLt5I$}Q z;hP2$&gwB9IGNN>jwJH4od{2hCVT+J13D|$7p9QLoCu<_dMv}LRNPH=& z$#IEeHK|ESn)swd$6M^_?~s1&Sb^mI`yfaDJ80nZWK)U!XpfR|v}~dB`ZbAs4Yi|{ z2<|nU@ROAYzpf*kMCJH9)|hBaj*GSzKr)NvF?$+`7jDZlZ%vVI=bKS%X)DerqzS-)3eTx$QsXk+(uV{}@o5qIU-yCxeWQ;ppx!qDiR z4od}$NckXRLZm4+DcNY3IF;M$kn+K?U@pd#loUTWE}_^fS%ZwJio#)$aj89$lAUB- zBje+vBBRGU#%0&|q!go*7K;_RvwyV9%ZvHvgidztk{$8#Bh3 zY!9eMveDQ#E-E=PdGfGWV(FOK*jm9h12%lY6x$O?F&>s{F_%1KL4~^y61}v`$K_b@y$0M#Ya3gRDI9~F!0X`OZ5O4@Z=ni}w z@P5E?AoKtp54;`l1mLxRV~hiUV;e$&V{R(}#~2y_$2cQ^PXHbQ9ODWDo&vl-aO~$U zz;QzB1{^le%cQsAEiV=j=i6l2UtdWy>uD8y2X{f?ALG3Ej(n_|o%QZB`@1Pb{S zYbdr-jJZa#Q9PDF!Rs#)A3GSe6k}f?MNo`m3duk*_7PG##dv%mvFo=+1PW#<$8n03 zOEHd9q>B_+Cs4ReG4`EIcSw986b4d^V*)9RVmz*q^b|KHP>7|Ny`P>*F^(amT#9il zA+hUD_P&1}mE%}Px=1m5AO1GQIOb&fo5YJ_4oOWhjy)s|#W)6$v=rl5M2eu;hd{wV zF}t2jrx=ExOqmq3la-m`DO7Hu7{@qLKE>?){o52zC1OGNhs5tmaUjKboFj!%jB^x{ zo?@Iwkl6J)&bvq^D$kG+jAx3cQM`;|Job>XDaN@8iCy>OT!xfO6f9JKI>i?$o=tHP#d9cD+erL42O)(}T$Ml}jAEP%kqi{qCQwMHIGN%sir=R= zmtvgjkn$-esPymusSHHM#K0|Jie^k?LR|c0`DQXD&16bS=5Hn;IHnhus7XseK1-m>cEme~=MiY~iQ0#s*DiZFY zN$j#W#AD!sTN7hUiB66)rOKaffzSOxc>**LuGooQa?*HXqQ(?wBACX7H`0+&T&wwV z+5~7i+?|ibbU7Nx=_MP-Kx*g-x>$LNkxkn|baE18n?5CohuaHk3c^l}OC)#nEZ50K z`P!OVB#JR`u^kPKBVA=oFr|_i+$i5i%6ISNjzeQiPNq4)nsRQ8>5yy^yo}|$dB`-^ zpIDw4nE=lKir?vvNlT2jKWjAub6AP-=2gyvF|EgXpopaf$GeqvSLb z8)57@ON!Abrx+|0OGsRbCQ@ThCbI(9h-9p2Qs9mYOB0Q$li;2J#@{6Q(tu$Y1#+h{ z?A&yCo)abCp=wf0kLwR&;96X4D#_z*8INV+zVyh|VIp5e_+N z6JYR^niMUk4tvmEE(fN8flo%GqdXOQF~R=)ii{VqBR`*VJm2DvJ~>`aPHf>{R!<&p z@Knq>`Fe4c`0aLAo4 zk~TTyh`my&|>3mge?EDXWkDaA%5T-UJ9Qg$!kYzln_ zQ?;DYl*uWnMt04N9${Rj#lwtAX3gZtM0#+iq~dXeMq&Pd!!VgYNTD7)-@{H%g~vot zm&A^LQ{m%$#8t7!m;x$7Aa+%pE)pUWNmwa(lqPB*!zJQV(373n%ke1S=2v@p3VkFa zA10c3<3wXTrzXHt)igS36`Rl|CBxH7$03k9na=xZiQ^NYuZm9!5DB}!6I8Hg2Xct= zAB7@^@c-kzVEDEK@~!FkZSeSeBlt@YX>jk2-*=9mEyr(-DEa*ry8ohts?F6h6isK< zk;^rdm*_IZN+q=Z%L~*rJ}u=s%Jq~RDF0s($jLXqibgwl?`44P-i#pOUK+WxWiq^P z!h5g5GlPV|6WLua6qHhF21+wfnt{>`lxCnb1Em=#%|K}eN;6QJfzk|=W}q|!r5PyA zKxqa_GfD9u1=21+wfnt{>`lxCnb z1Em=#%|K}eN;6QJfzk|=W}q|!r5PyAKxqa_GfX7n7grbZwLyXzwpS6>yUpnpar;;oZ85^%8pVAbY-nGJ_&5x6s|&+h1_>dsy^64& ziPOvA_OUM7V#LRR_LYc_Lko4SpqJx9m#>eX^)BM{)UDu)TRF^h(I)f3$Af;9i0PuN z2ze>c%7dXGVpl%%`SY7Dy_0dNN=rYp5 zzEZx>CiB6^gMO5V>7pzT+F}MhlM7wGKE{*F>E*+|Qaosr`QYP0KT5=OQI-XDwV|Mg z+banBFM`uE!M>}QcvI*@ssCiZydvG_6| zUnSz>%YnKk@S}t6RV0spPA}&*<3k@x@u6QO;^WgpU3FU+|1Na-`sgDBbQ$SjUunFd zP3D6iZ|Fyfm@dk!P}dB4CKtMVeau%br)PzIS26MR(1%jK(618l@#*2%*0qCq3AR@e z#y6bP%YgmYi4T1!#fN^Ch>tG=>RLfB$AvCmAAJ;Ydg?Ic{zRM12j8FQM~Rp&%JQJD z3GC`%dlg|knVg>4MLcMe`QYP0KT5=OQKrshSuSCDnzn zjzNMKY_B3b?)98rI_$e@18)m`VB3-S_Ml%S;^VVGpI<~jE_C_&=)=b8d391AM`)Az z;Nw9*O2l+gmI-Z%1-oIey^6422B(+B?PFcE#fXms?JE%s%+>MjGlSQol{eXN(m=~=ja)I(d0 z_&Cu1%Si5j$)TfxeP`QPKM(A)*m?Ul7xtMhtBZPi&X22@R#74rE<`%1*efnyNI+i(}USfAI&++ZFu zUsK-<`nN$h_a*u)M!Ao=I${oledipaF4|-<@$E%FO2l+gW`nxvU^jyEqf`gWFrF+< zFB|qRa+uXao6H9v5BgCe{c`2;<<(7DpV>ek8cxSK78V2Qo560n_@=|(?wAh)U|-!EY6QY6}bq{TNin~2skcX+%xhv&1DybQohh8^TEf1ew2vmqAVTi+Cb0ZLYJ?P@p$!e z*wnzjQaosr`QYP0KT5=OQI-dFGr+E%^P^M;%P^j0oL-KLc+e*E!N-Gsl!)n~OuZ70 z|K4!?yU^w9V>}_C%SZ?NO8G&X%m*J2`cWdLi?Rr)YX&`&3thfG#*@qG<-@*GJZO{o z;Nw9*O2l+gmI-yWeLxSlR}jV%!RZ-bUnw56$$aqf$bJ-jFkKYoL0t>j&EothRFR7? zo{OBG%|$$DllkD|K|e~wbWx^RRb9~c4H7i4y^1iNSWYhk_LcI3Hkl7T9`vI`Oc!M) zsA~ni92dHLeT=7w(^L0Tjt6ZrAACIMM~Rp&%JQME3GC`%dlg|knVg>4MLcMe`QYP0 zKT5=OQKnf9*MM)p^}h>UzCOki2)c~4u&>x(V3Yaa<3T@4#B@<+fVx?rXKcG2{Q=Z!9O`T7`780a$6!@g2HXp{Ni<3T@4#B@=X z18vDcyDoJ3`dBZI)4Ry+Gh0lbj|1&15g&)J2A+TF;rS(93e6%h$*Lxyb3+VBa|>sE;<84?Z6BqeM&>WoD?W9{}?oY_B4WCzjL8 zfc+A=p*EQhJ|6U=L`)ZDMG%h_^m1J2^7S#EB2G^|5aub^oC$3*AACIMM~QT1<^DA( z*yih_k4#R-ITjWJ)SlmFy^~F)de}e9IK3R$ca8%XwQiZH(6oL&a(zfOGULn%J=t3-T!R;X(Qy&M<1e0_|sh||*yg?cW=7+(*4 zD8+|dCDz%YuCihh-)BgEpBD zK0oM3iPAxz5wCA^q0e;Dhu3I_P3Krx45*Jj&|V;?&+IVH>*s=gI_O5cM4#2eykv2D z*|2|+!%PotG9P?9(T^f+RL+Z+!G%6Gf<82yj&m$523Z|^pgk?8?;H!SuLJ!o&^5e7 zpVh~?F`LuN$NfmC3){;GeJGvZ(616@f)o|xO&VU z&#?~vE_x=Xmk0Yru%*Yq^IF&pMmX=m_PT_=@tlUlw-e)0A`|E$i4 z9skbpxH|rIU?0i(`pUw^CM!7o!Mt4LbZ&F|sLJf(J|DL$yJ!z%Mq=YSaEw!~iCF%N z`u6KQdK^T&LZ4O7f;MM^Zu(2~nJ&&77EbRr><5m0^}K;Tl;#cet3);z{Tud^4Cm=sxUP7KKJ$a|Ye1J#80M$(?yvD>MjGlSQol{eT*lE)60W>=Vu1YCiB6^gMO5V>7q=%rMeIj2lKBB zUA{iXqXS(=!(m@3KWLNr;Nw9*O2l+gW`er8pqJ@Fm(|BQI3MS8dS2uHbNAWkQ|Www zaVQb`X2&~=Hw=8cBEEeV@U;wdV_%}r?BMa9!|7dweXsG#_YSNMa`b_Hg~aC{{VI|A z3+4U_179yA^r7c;T*bz>AAO?QiFKK7xN(^JR8asQe*LmTJ| zbB@I44gD(-A7>8KHGw}JY_B5BTPCMxhW!%fa?nAW%m*J2`cWdLi!!{%!0U;87rLm! z>kC`q`A-7a#qAY@If~%)Ot9~&4aH1>52bM_`z@wO03RRTtKfZ!ne*#hh1bVx54_IE ze@%V7CX}!L5?!|+?X&9wrmua4zI~pc_6@Jlx3>w-b9mjB^_u#4jf2-SmeH=tA9y;P@fUD8QYifn)+7Iw}NiYOZ3q;`oR0GB2F)C z0=d4A1-=ZnJlKk0dtE}`O7~kBj}o!_9p^l{y5C{vFX#J!SDn9{^H~DiI&wGN_vlej;Fd6`_wTPA?nwm10Ai%m<$@^rJ*f7iD4F z;Ql8Ku7h0Y^7XNv26P!|xqU1{Ta5TP(7qD!aTuU(7U&sV=<@Y3FWH=)1@@g|L4CBz zeDLw0A0=YCD9ePpnu%}@bD_)E$9Td(mysU!mEu90%m*J2`cWdLi?ST3n*(|oE_C_& z7*8IjXN7&Gc+e*E!N-Gsl!)n~>>||FO@e0&u)T^fp5dIH3HFuZL7U769}oIbBBqNn zukG;t7ocZ$q086Dcy9B0>B{k-P3D7-2mQQ^uucTnWHg-H$1*M0WyIUnI_WVT76ale zsGAFVnJ#o$9pu=~d`|B+>^sMTdT5jR;Nw9*O2l+gW`nvBlVSdc?Nx;F7&yIj*jI`N zZ89HxJm}|Tgmo;OPCmDf_4GN)dCzvzV?J06h;yK>b_)2%?G=RWjNtSPuV>x8}I(23yov0g0L zWyIUnIO#DR76alUIJaekUb+iiRtGtr&n=wZZPV(AEz1mzy^927rK0X%!Su9hfNLaM=0b1Z89Hx z-q6p>2vGUi40S%m<4Bao`TP{sX;i7rLwta%`uK)AM>4#u?&LP>ls6+kdy`ub%T&cSqIP`gu|%Xh63Pqxwds zB^wh{M~#h39o02CE^&OkF}Yc*=B-CXrNza^j7o1CI%=RX-WZu;9Mv@`!IW%FNl8lP zcAJ}GqU2Omg@eVP9x#mmzm%iWSW7cdnt{>`{NJ7dRV6Q>(hYaPKedeD6XPa$gpx^D zo3~YnT3PGWsLQt#9CTx?+(@pSf<)&5nxC=f|?$gTi<>mFfg?c||Y_+U4 z@~c?_O;rt5^p&+FJF1FaLdC)ULdDQ>LdE3rRzH)kLH6OwHuLSwUFkcQH}I|Bpl-0L zvQW(yXswc8$x_i&!JyXq>uEghD#5*rAOr`v3jwL_kP}bA+E^vrfbCo+xn2v#{KS-% z%gQuS30GJ-m_R+}GUxgw^48X`P214ULXFl{Rc!^e4YH8$WAQSTHF(NVmC*MtBY4mB zFu2nk23K?!D&F%F+;8{`+D5bL7iGo@EhzWxF0Mp%hEue$>b0->N}S? z+hKhkT+>sind&7}fcAR~_7pOp{hz{ihqLEgRw90XPr)DR`$KO1Tlt#g{$~B@++Wxq zGhxipeqlVQs;5vj)K{q5D!^L7q&7T(|myZD$2uLY|dpWZ+F4Fm4~&A$xZH0xo)VpU>czkzJV=d4y`MXD<8RRAC!l& zahZ~Iq|8tE6uhgc3``}ja zT_-A`0c=-ToR!^$%J)J9uY*nG@}nTT!(?Csb)CzcZK!Ja3N=Ej3pG>~g~~SQ+kAgZ zIg_8kSI!*7fjLSq3!jHo2{U0E{4vd4d3T|FrYF3sL*lbRnexlmbc)1h+{iht`nF6>^;~PAf#h^4(z)LCNj1slp$k`jqf0w<69M*Q?zLB z2Q(lA<^wwm+f{_r-euT#6KtL3W2Kp!+lQd&I9`;FPna)*D!`l&sun6NENAnzdRxkx zJmt6>&y)Rx0qY1`FND-jSJ-zGv?T6wZf@6#`C;SG*`JKd+Rr&;F7_16D^)@+Y^mq~ z2#>>(WpI4Nl+-OTKLz^=!J&;?Xb{>^XrQW5{EWopO?-qV zs$ikEt){hlevqZAsfwYpwvsGW$@6Fc%%c?r|1)%6s_HIOy-@+in_4iRQVF+V%b3sQ z#HozVO*Z@7gf?&Z!1aJPocmzK`H)Hog6$w@!?{dVv8+&06(RWAyiHz)vU*P~_5k!j zpr;UcqlchA*AwQ10Yc6-mEd(9wk$_H&SmnrRrM28>av3R2S2M%J~WALfc@U~*hXxmbI!}C9tum-l_%&wQa z;1$zLa1V`;%fA9yJd;5^)Gb~HK9%f%uCr}&d^ugG#Fi6cZ+HpAr;aNXJ=w7lRu zv#ia-0!NSmi~zkXe%o}F;Gdxq0zaX7;o`^gy0A56GO$&$jKp8U4(K|Usa_-2Ao==6 z4c9m2g@A?R`UcMr*W?%iZNTorrdkBy(s}y{U^qXJdHbz0ZtLYXv+F76`C92(&sj&F z0|&w!7*TwllSeu|R%X)U5RN157?m&qwpa`bC>X*K{zK)k#^_{2^&gF4EW`lY9p@Nc zyBuP0(q-4!DnEC@Z=igP$+KQCURRwfCwLt66HJrgxQ1=`V%m0`2kyBG6>fOI^|+5L zGlM*q$ss?e?_B0=N1nssII0N8QAIfJ$k_yPk8`_Hd7zIF7~?Ml4lWOKR5>{-2ds z_7o~7%UALSKfSL!rd3L1^c=|Fdz+TRH63jFWwc-Ad!({**(XpwoRvd=qMmb^bNv#z zZRJjLn(O&n0q}!@VYK?{jsX%SyC?Ubj2j62MLn zZ26om=d#zerTE=(8JDuAMCvgoLfct|35iRx7k~oZMSXG>$asd+)7+Zi3lZ> zTe#J*6kI?clmZKK2}{KVMM6OcD7setx?a$=sH}*(6p#fJ!%bF1jP=3_g5kd0mzypi z@c%q>&Lrn~a*{3Ium1ku@9V|BUX$7Pd7haw_n9+iX3k8%n%PkvPx|Kg)tnCdiG%KA z(z;}~;@NT?#?LD=a_6884byGn6I$tZ*>qD-KeFFQTu8$+`TI*Yuct zE#f(63dYv6)zqS%d5GB~Zjbn{XizJ8L#vmpQeDfMHPj_nEtDHJ3!aI0yAK)!+)=9(tSl)eZTE# zl{yz1_o?k*_We$|?8s{s_onzxtIVf}lMXbly@mYixfj3p!8}Cd3~RUGf2$?CWFJhv zSeUWFoQ5-|C3mlo=BfX}@4GM=W#Q4dWkx{Fz%%3w%w^8N^W%*6mg1w+?R67f(=7EM z%t7#u{&t^ksr_IK>x=kt>QbsjkBI}Sp`$KCe$ZN&yP*F#%*l=)L-_wKm{(CGh0CX^+1)dXt(oa*x-V+0Iu(9=bcUtAgZq$8f7)$_mGXQh zqV(MW9b-59RWsUyX3Vc@xAhk0KjGHNhm!5&eLY=Yq?Eb;l)0ArGR$MRKiS$3%crPE zmTpUJk(qNbwr-nh%|In8NMN9#}Z+a&ovWqwR`HZ9p+({ zPgYZ>nUOgB*C}D!PJYBnX--v(izf+x#fR(~U;pnFKc=}z4o#)8Ih!Z~Y=UMV6 z{StYx4TYzozKMHl9a**{S4oGG-$uT*wn)#CKNH>8xT~c{W!ozp8=SPD^fU5m{&|&M zqbuDS)?vatY`1u~YTOx{>AT*=R*RGFv(Rt3`Ye{O(jDDrqthP1ZV~xSWhD4RDr?bM zu;#&7!Qj4lcd$Z5t?f;DN%`hAVLa4=@lXikp{W=T1=YNbk+E6D8F_Yp-EL#9b`8dr z%Q3Dp^R*&e?mBZN-9Noi-&*_Sm3FQ;=spZ#n2In=-R!g_CLRA9_iw(2?mrE`R?r<6 zcNjmUbyk#hM0`qRsOJ4$2T7D(unF>wX~{s-MDY}NMo7iUhR<7aoQEHKII=jqI#Zw z8~yG(dx|-VMVHwD@5apG;VUSGti5l3CP0SPIqn!G@SS`rS`VsiO!R$>sNli zzpj@=b%AThasu=g0`kepE!l(iBfE6@GT<3?E!hXPt<=me3TM>6sP0;S+B#XiVKq%t zms@oRH2!3`E7;_hN!w~{t{YqGPjubLb-5_N_pQiluQrakm3^bjuSkQ6;9Xq=&+!pF z$48c9%~OZ{q;2Z zW@wx>JmjVwig5E0SgT5I^8QmT>odyhnaZo5J=gZ*LRg<8KlA|5->!O4r@ZukXzTwB z)=h4GHU_Lx-zw7Aq@~P1;a-m&(N4BZ-R?2Gt6wws z@yO4}oB-x!W+?aDP`b|-={_p{ZCKxhxt-9dr`OJ;~~!;8m7+ukf1i>3F-sEz-gCZ!N7@Q?v$c4&IT{+9C??%Ae`7Z~&}BVXWZ6 z2vS|Q>b8oiB^)FinK+#(mgh5 z{q!}Yy9RNKOsiw_eWdeitrPzftOsG9CUny6@A%*HWxtZdss@?gyT&DRuoh(2dc5DoyE+>0HZHE) zO!Fwz*W8c5bkGg(7yUEfZxp(Q4I!lxbyr%}5=(8+X{O&R;e8Uu%whNu-spO-WbSWl zt&4YqXh*|nM^S!h?E-o?#6zzYD6jczX+^z2S(o+WxXn7fPJy)^#^2BsMmw@n_j!Rs z)b3W!Pg@S`etoTDuY#@ptL)!pTh`))mCDs`=w8t+_#J_zR zHEKQC?&x`Q--KfxnI?LSw852@(qAW>?&pljHzMBY2K-txby!SXL?7XH^I`2~CAry= zx$*G-B&~ZI>Dtd#9({ri_gYaFh#mi0s`TxYZ}*b_$o&HBzv#PA5v%J_J6iXVz%HNs z*@E1?tKCJX+!RsGFm^v&*9B+j%gudfU|x7t%NX7v6dLp8by4JgFF2z6CSk9E@dtee zHK`SL`OadB<~Vi1BuoH1exb2TTSe-m6x3}bO=FK|3 z3t%mQv4XS6-Dl8XmEGz0UCUdr)<(Z;7Hhm4%kw?-UJUb%(>HtRHLHe=VqVCrZg^dj zY2ndtc=gR*Ww35Y$9F2M88A*6++UrKGT1V=0q?G+;k{Lhn!7PPhBpiaS|e%Rj~xD6 zOWg-^Jd%k19=s3lI=~k=tS{on)Pa(%-+?w@EK{$hwY&BURB8KLbbr){{s?^%+?f7| z^6Oq5e$;>1kHFX+P1fmXj#mG$&et7{S9tMRMm~^xvHv; z>sf4OgPMtXgPCZDW_If}&xO(+5S^!$@0TZfo|of{Qu>>I$;@|G#L=DyZy~)+_8h>o zw<2Amuj2Pj7^~rkBe6%g?liT(_3d&W>k-e$_I|vtji{DbC`EHVgHD0A)3N;A5OIZp z^6}`~C?C_u!_u9QJ*Ej_j6`E@%!_Vx#!@bKmUTis}_ z_b;;WWaOl!-FLws-xQykLUp)W+fXa-b-3*{7nBSY@o?I|YJS^uA++wNJhwCZ4vI%S z3Tp?Ly$PLZie2!(HGLX=HTjT3Fc<4rb*t5`lkBoonqM{dl;u(L1bwS3oT zJG|H3c-@Pxttmg3=zOf!=GGc}X}` z^2|&BWLy6%Sf4EG@2F0uJobubt-7wq%~+(UKcY5cwjV~=_JG3H%stu2jtb=^YyOZv^fCjFWCT?}J4-Tn4-24=O} ztrawvA@4U2>Epxr*gZoMtJ8B2$CH2Xu?uzgNd3kNo~y{BIdon%-k zPHUZdK(^`U%yr#Q^0`Kxj?$lr*hyEf_Vnk!(eeEitb1Uba=xSLKmqd7f7;f68P*$R z{e#qM=-d6K>p9-sSI48Wjn4Up#$drY-df)A_bP7sI+- z`$HYMe}XXS@`-n{Xlp~=O?qzfPTQZ~!uo^uXMnN z)nUfXA`R&}x!W3BmIdRk+VzR#)!hAWyFO7oNZwv0eR19WO!u4nQ7+RD;J3>2urAO1 z9hI(^x(z^^!uQteHo)sSul;va{?og`($9G;+c8r9~Hqzo)pgaaH~9g&XAr+LV9I(_hunHQX}uNr-Lpb3vJ~$K*SBJR zb~@%~u|MtAmLk2IJO!HFl+d_C2LFGmizf7EVO^lz}Ag|P$QZwEfut+ui5 zv2gbeYmFU-Qd_8>Et;{Ov{B7i)1a`=uc+f#Wh_qVv{%8-lO*ibFit>I>ic*eGwI&$ zk?#6=1=}+ae&>7)Jy%SAe#PNpHxYVZ@udLwtt{_cI^ynR~RRnU$r*ls=X#|XT2sa z?X35T%*V4E@@OialW9Cd_25i6JctrhML&gqFVOx(ar?S4^}3ZU$Bp8F2dUB-PNt2N zeH6V9!CbrZ9;DztQ^4+TX|0p}j-Jx>IouHUevPaxR4i!dnOX5QN`Shg3R^4v=12lF?wbDHci zR+X}){m|v7#k1b}W??-bpN*Kas#0%* zf7EF-3)VI;cGWTUb~y^kLd#Dt$bCBgNEgiI&qW^3?I_nl9flfpRLgZ)#TXxZgfx4N zoxS2{)>zj{x5hfv*fFIzIpa@HN|`w+@!r&<-6@9~d5$@rxfqLA#LLuakG9nFy@lz& z=}Z~-^PzLHh|ipn(;?m$EvQ!u9-lK7Db6a)$WPBqOSh!#(~FSy^KlLb%H;eGkMg9` zy+-&a$~TJNlUTd6p3X}vos~AG(`Gi#7}=mth$)2fVm+~`o3vJ7J@yl=!#@8tld!(S zD(&<096Qn&#v?DNzJBx1R2I|Ug{3!;w9J}^{EG}{VCj$J%US?VbW#k`Y_h^&O%=}Q%zgk3?J&o{6#B8ZBx@ zU@?rp;VbiSlz2P&H>etZVGa2Yv@mk%#Tf-U%=}#zg=ICI!H18*Iu6DTOTxcWb)w(W zXYnk?Sv<4(x-cgmpVw|x^sBJ1hVeK2ZUGh<=-Z!QscH9PE6!T~eb#dS{nnm-b*_bA z(Vv~J_WZMEQ|8DJaN7b)=d1^jJq=%A`q;YIBE1&!Zet{5HO;DMOGKFLId*#viOSH^xETFf>nz=Vy`%lA zdpM$+V65O@$**-WLNEKY&erFwcK_~3K$Cv5t=#r+6qoc4 zuxM#~<(!dj51R1ohxIua4~9F+Yens{Sg*%AlrG)cujr>?T}1u`5AHysZ;uC(^8Ixl zq3tI9?~#7=TKo=b^`%g++ZW~V<1T&O4)FCQ_Y|p8T+9TS{99RosoU#5gJhW3?p>cir94XRYW$Pad>#(x^{jFWf!swAavwZ6iY zN92EGTUskVTg`fv&qC1JpA0GB&pv~vaxEIk?DVdjH$Cm|I_=JZbsmfpw)MK4RJ7+# z-S&#(X4{|JVBJynryVQ9yvyg~w*K?5UMcJEh~a~izH7?ucsXvU!+7Uax$fKJon)>4 zzE*klsI&V1UU}|yt;&167Uw$Ew?~Rd^XSv~eG$fL`s9Apf4*etXNdJPai-r4JWI5y z`LF8s$}V%FJXGY3lvj?0TI>aAId+#3A^fHk;V3?5>uDGbbio525o`q*2vt<+fLs6U-46Uz3-PP3dzOxsM)=-!%CVyoa(;j!(q>?RKub??>NPmNVUUw%|Df z=LT(bz4w-Swd$i+x|*<%KUkYxnv*cstGx$%KlQgtU9Bj;rkq#PcjR`vSZ=o{-S2yn z%4PJAu!=DLhI_G&%8Wl(VSWqa&zj>xy&sCNO`rdi_H!w$U10pdXOWr9-ocNmI~uzL zzD@7LW%}1DFXmmLcH>HG$`{!VS9?aO)ux*C(P60UpD3MP({WPKf5EPQ+9Z@S$yK*x z63)y)N}0BT_hX*r(v*{GwvMYuQusF`%*f~4VBG=Zj9ctI8!a{V zYCNyqsp#uuKSP;$_Tle$uf{UC!@YNdwI__zhx5G}?srnhl74!vR@G^z>z`=DWckti z1+dSnyQ#GARJ+wQe->oNbvkZbHzo`cqYP#$&jb3uHg z6vjII+VdF|<=N>I^chLm8$JVb&NJ-xN3Zc%MebGfU|5HdC&86S*1C22C6{@g@T#xp z+wLxg)eGZqcx!g4z6RFd9m%%N`w5voy4~Sx0Ce1>o>yAC%P7*pr}sACT(0Ffm+RHi zIo)>p>A6DedBB?XxrlSc9C(QK2Z!jLADuNQ_J6qQHr=xW_nIg??ao{k>B_k1ID6DZ z6Cb^fFXX+BPq!D%c-O+uBKJ%)abJ7C4#o?3Ph*}N+Mm<;{SjCP!1#kVAitO0iyu`- z`x9tFtJJQ)pLXrP)1R3BLc8T{g^r(2b1}BiaTNJOX)oh0@{8J@WzXxl?*?m67^nWX ztCbj|d5zVNv-MAbbw*i#rTsjz75Dp&?fx2AKdEq!lg$Df{iSuYavtX)+wBvuo+GzS zo6*>&aiaIW*54>?++&`}FHjrMfM0r}?9r#`u)5lCQ|_F$L8e^=>%J_6XFRkWn7f~` z*?zZJDksK2V~eyY>22+Gq353Sd4=K{eT#lyq%3?9C0Fhfm2(2yLKBX5hPA79wCfr@ zXMyQ`Q`YS@MX0;d?ONOICt#he-L{b1ZIBHvw<5eU{oLWdp8Sj6ir>8U?kMt3>~oc2 zc$(Z`{twn0+R^u_hu?li4`Q4tzT;x@+NpEyFzxpeg=sZ@*T7i83+yn_7RFNgv|v=B z+n|k8b-!^wxlz%JVO>Fvnz~zX@U?#}=EW<=R62cJUgfBEng}QJC`&!5SbewC6!x$Tij z&mP&WMMZ}KYViQhj_z>_WvAM7m@!B zH_m`(mc55Gkj8WQySl@#Hh*%h?fwQ>x4>AzIY;P;z}>NB*^D!Mv=$Z5^Yb?Ab-IP= zdD`u7f6c+GeSX*WbIL2&{|jRUSHn;L?%3y9j%SPRKiOJ^(ziVJf+PGzldz9~u_M)A zn&Vw*?MiDcoH@N9%0K#H`(3B@gB;uGg|*C>H#PepDZRd_{f=G@Yp~>XukCf+OKQN{ z(XS$lXm4p)O@FmK2BG(P55qw>d5*9>iT__Id600zb|%`Nr(Nk?xdvwTtGYZah82Uc zqh_9`4pQ4%_hUZa;~9m*ex&X8cvvUFIQ=9ZBrnB#K#zX)Qd|E^u)bE-Z&&vtAH2qn zKezRN1?wKIe-V|1gj(({3*tVM7^Qxs)-!Ug=eH{DPHBF|)K~NTI>EYIcOQKDYgAXi zh+q4>z=}3YpT*grn!BB|I8FQG70+tnG;WM-!fUwNII7xp<4)RIpT8g0>0iwsecfYT z%J}QFEv5XE;g<28NN)VCmDgVB>QUY)US4JN=r?rzIT6-rFjmvoP%+XdgC=aoHeoR= zZAUKq^jmHJ?}GIk@;{h65_Molyw>Y5<=h^V(Ad^1F6O?*f1L-^4wS#2MRj@6KXg2H zfb}65E4T;lahJe2G$ucbxi{cu^wZEAHFRM<3}}YkMk5)`d8Pr(KJiRZ~OTg z-^#-Nz!{tE=X>&RlkMM+VOO`%tuoLlC^({o7i>I(Ir%j5~DM7SDKI*F;*_b)r0nsPCb5Tzkk&9g%LU zUDy3el`*9b6VhM}?um0XN^!z?vW4c`vDR)D#!PtMX3w|dTWOU4SHDT=tD@Jzz6Hjf z*fjn4TY9?gb|}=G+pIDdPX14N%l5wsb_9m|zaD2N%+})sUB(dBiuBiM;~EEgwKck3 z@P0pRhugJ>%3fQRr%0D%c!#3*SGi?gX{Jx#gF8KUGtv6R>hhK)jcN(L3AP01w9g-# zTbx}8=VxYSr0Hv2lxDlVZKqiR_MtF#nvFSQt8>+!lk7xm(QDQ4o@onTt44l&+VSHO z*k3OBVaASWb*STqT~0;$*7H5suZcOoIm?^WoNm|qt6H)N#v}H7P4VszXMIp!c=d5B z|E25x0kGD<@HzK2_Dr%aFYfiMrhltB7O0%d@j5%^cKiPK!g>J4YC03=(xfqfZ#V0r z%6l@r+`ntPpYjgQ|AQ&J$CGQRO*P>qdo9Wq*&DpmV>LWMRs9&OW68hZr$2_adK;WK zlQ90JD#mrDEitxN{c-MD3X{<#o9d*IS8J!-daDoz>E5uux0o~5ev0*VbWh`_Y1fv! z+BKcGRmOA1ZM$hpFc;VEtb^6<1kNQ}gYOWbTsz-Ov)f7&N4?*I=3en#xprrdniGC^ z|Mu5+kr&a&@%u82zv&@77o}JH6d9uYpRuO--DB^`??E@+fL|O2g1_2p1zc^NNdvDm zLi{3&F=vZ8FMH24=Bzh{GW48}Q^oXO)w1AK26URXz^@SIW8vp!=ll?leR4jU8{CY! zL0KLqV7rc&-%n6GwMb!JUPX6+^&uGNS#C%B{BarY3H&!>U$3_03j01^f%Of2pF64U z?1=XW%S?Iot~(p~`;0%3Kk2`a7bxj9%DM<^%fbe=a2*!?;CXuCtF)S2&mQQxs->8x zp+tzmj>A~GG~Hp<;YdQCUr*(+G1C#GpFWy2(NZ{JKsZbFl*;m2TsO8UN56avpdeAdpE7e+nb>3tXmssr{qK! zoO7OaK4Pr}+FCP@spZw`NUb>~ofl#ZXX;LkXJ-3b71K-Ks@Obvwll96y$%1~31c-3 z(0O_OU+Xhj^?jV@Ec1*}B@I2>39qt*IvK(Dqna>x*|agh`>$&6b(%v%cm)jRvcDK9LPnn^QNot5@woUK=M8EcRxQ7y0Y;qKj>z0eDv0j^(>blw?-%GI{w91ramq$j_e+}8lCH^Uzpy_F-(iU0 z*-`It+&rVG{WoRHgj=$?F7rjl-{al7zFs-@s1I8zyrnf})^Oi;*JSlD%sEFjXFOqa~IO)R-pf-~2<;H#v{BNxDn&>&uq{G(g8GUJ+^xax}Yu%F`^^qc< z>YIJ4c|-X-OAG%tS;b&dN8?+auyq> z_S|H(&-0VjF2^)!`(*roxr_Bp@#FOCsd@@K`UB(sW#}$`VX`^~?$3gK2n^YVb(rmR zN$KxMx#D-%vy;_xFpY3awp+K=67G~U|lB0Xxh7xbRVoC#yT1Du}N8<{mrO zOut`Yd$lRm!fe85;x>_O^sD(-t4;I@m$_fHcGB$4v%imBXwBeTXW>s0dCCT*VrJ_dXonEw6?|9{)X`XYXuGG*p_ zQxo+I5n2nhMZbe9)Y;!0EtUIw=GCd^U@oSz3!8W?_6HAu-G8Nfih3K_0b|oHtefz) zsnXXXGn3Qw*7qaW1A#$}`tWvj>Kia$LcGX6B3h?zf&Bv~o=>=LWa?+hmg!0B&wThc z_!z#}p0Cq)qB>0Dvm@K;)c0UIKi;Hm;&}_})Ma4$y9)nb4P)enja(}^Kh@&vT(4;J zO7%vBx1wFsZMoSW@3A+zTG`d(H}s?Ha8>~3A0n84h-`HFQ<_u5dgwW8W?;UpRn4*2 zi)Sb*wdP%G$?Em}a1TDWSupM8p|4F=8(yER$1lHty$ObF8qbhz{wDJ0fj96y>3`bp z_JX|xhHUbOZ1Y#|F(#w1klsI_clx;PW&>>ctEK-8bdG(~);|X}{Y94Inb5aHHIFqG z>kCuzdVg}v(r2oMoIzS-d*qkzL!LTjfajatpk^ZvW^d+uap@jDJ#V`h^R{8dXIx1N zc@4LA_?CL!JL-gwEMv5PvMkn5QuXxIkGiSl)c&F$YYAg7#rpa99>hG%Yt2<*=+Fu% zlfI8UR;O-wyiPsk)K~4+ZvULNr*b~jZj(H&dwuW7>)O_|y`~NJ()G9&!Fqq{^J%P$ znOObjbX#%8qc2j?sV+Z*ib zB0TyXz}=O5O=#}m!s+x(tfD#CUxKk3I#<=HqW@Csjr!6(+VT7q#olv#KXx|Osm{jE zZL|89(m6|t`18>jkay3(IgqV52XeYvfc?k|w&-&SQd+*KQ7u}(S}j_4s9LoA5Vgpc zRISBn1$(tH+|xYblg_%G&Gva)rF7GAa?LSNdx-B*%vtYRbGn({j=&$1VVzVf&c&RQ8q@>04F<&R-6Tdsjv(1`f%iuf*93w+DU-(b=qL0A?ytHpO?J3IEi zFUH>Y#n}7480l9|6|_s+(HWR%*RlU>4)&kT*%WUyy6!`2>GGIb>f2tGzT#!l#mgPd8Pj@F{r+eg(gXR6_04lOBR%rYnsV*V z*@J>~(DBpyu5z%^^)AZmJ~T$Gw)cwiYyDj0)g0v2Y~&Tr6EY{xo3P6=pzE%9XF=tt z18J+vDe@F~SBlRTr=03C?Ru|a;&1F~Z3V>%^-J&ff7SIKm-14&@i?-;d+WPECcS?cPucQ8-X&G*h~|8*FrV?PCbO9JoSHX0M>Mbw0SpQuF8=vdxGOY@8V|4{KlNbzsddPW#bi zLAp0gVWIZYYdwjxPC=$y#q*(w&m4>Twv=xx?Z^%ogZaLr8prC3<);^WUbjdO$N1YC zol;vb(}eQkNj&SXhmAJc`F7zL`CDrpjD64heF&H9smcylDoCzPxN7T^(#@og&Z8P_ zjwwUNHtvi~@9Ed$9X-azcu!xXa8%sG=<0VZ9^Zm7e(U_kngFau593{(`+SK~dK$lU zy1LH8sa3{B`(U5jRz81+#()V5IQ~r7?RwacGW%WB!*8;Bn0Ly7KFi)+hfUc2r)gR% zF6JJ_)@>cmqr#qE_MI^&O(RRZzt`e^cC*JDVvU?v{r9?N_PXkF5JWj>R-uhfIj9v6 zktg>1RFCt%op`>l{4nLoq|pauwETQx(xg`27#(AOP{ve6oi}Anmt*_f8{K|LrZhBT ze;S|5a!>xyc)+A}t?{AJk#@CqRqB~A*J@|I!tWJs-4>MFP#yOP!m;)3?gPGg%YWya z=NtC9=RjgkKUZpZO?+gSB~v=M^T4YellkD?hU=3G-Tg!<->TJ-DtWL~?J~7nXxG^q zxY9M<-#TMzJo7=%y{2D>(X`DvY(TIzapCfSTG&31 z-ZI*GD$7l+_PScxbK)M^0ndz>=keO({=aS>2xCOwVqr0Z7Kn^K$X zTB}^T_Wz)ro}kW@zFlGZga4^b-#*4#{|57o5XrUL_*ybbf9j`od_4LyBmci1;Qy-!LEhDq$9GrT!-9UI%mHR_fnAZ;Bd*QCq4168s*AxnwK#kA!X-W|fD&{Y`T^ z!x7&zN4!hlG^hNbKE>FkU#ixR8F{UK%jCK7^FKW%`(S)!=i&RTGbYc?IU%OrY3}*J=3icM*XM*aDI62Y&!4Jx z-Go(!-CVEcuG)3)=isqf<{JgZUt`l+!@F@d{(78^k8g?Tv+?!QW+^Qy+X)laYBsIa z@2Io))zH|Q^fov)vH7Mbm0c<)#+KzmvbkTivE?fG?Im-y`#O&$8-J_Wy4|a?Pu8TP zv1{q-u!;Q!`kHw6I}HcxV~v5Y(We?Iy|kZ|=LWjUYdMc7Z7ChJ8?k4!=mC(K{1{IQ5RgSO=zo~n&{hb@^37@*rb-tW&XVPETUTJ+R!m_xvUR~gk zb}h7?0q&D;zKW&tcioCBC9=E=3W2fRhX%O#8@xBymQs;HsXB+9VrR!de{jzSq zO6P{+9HQ>hS%+!uPXzBB*UZH`$Jtn;*{Zk{;iqzJ&a{zvV%XRwuM8Vo=DE%@kNF&T z+PK4S{Pn6Y<{q_VM#scMhR3vpqCWZP-Sb8(VFh8`~qS zUUm1C6xx%+>eUk-^~y{CO6Xn4 zXVOIHx!1Wsb(p8db-W{_J<_^Nnsk!3Ojqrv$67;n&l>Bas=1fpNn;@_U;6<&9$CUDWBFleb5KC-50-~bf{LBbso9aG--CNCpGCl z1M?vmU*SxrOmn&^<=M9B{M(AXoHPfjbu0F%=qD-rIoP9p-Kx6dDqHrt@dDQU+HJAE zXO;bzdOo}SOfcd}Y}cq}Ek6|ByIbYykIrE7$Be~HpJejE ztB*FiM#tFZy0N8SMo-$h-cMBx8=WpUI>r$ZydQSf z2^MvFI&Ds5d-^WtT-`@_rGJ)`@n`CdE>qODm^MqNn@8D(j(v_2&Iw$Ou}nv(G#`HW zUG?hoFnf8FRj+z~-W~NS2lJjsz4y|81b)8^bNp8N{~P%Ir#tZ-NiTip8Nl@43-7L1 z+rwPwq07<;b9$xrVQb5WDG$;%?u~8a#2b(|x*WLn+!(pO?wZpy*Nt7PeEg66tkV9| z8TvFH@i^iXA>dRQfm<=IlEjz5O|r?F^* zs#{z6TVl__4ydfI_t05H>W4+ z%S(PvbWdHs(XU}0SOn=G!TZEWyR#2l_nG)MIo8L|SdKom!}*Rtt#)Ig`+1dDSx-%0 zF4A6~+4>~Hv%VCbF;m|5U)`X719PQEd26BXA!9FLOLudzu~46%lBv`4u2gkr9MYiv z2(!*{x8I=+>R1@Vx`5%QG!7JV+g|U`Zca9+cVYJP2#Xmzd6n5~4`@(%m?d8B%zf#* zh17PN^5>+Lmw)FS)}a0bbDf8OEwon;`$6VlegB+xeg0aZB|o(^z8Fq7s5fEm_i(Gf z2adh5vo_1o4#K6^3es9hz22rs>1U6Rq8J~wdGeZYzz1E!NU$o}< zuCVla)U>_tBGIaytF6-c5XQ=D{>xgh{HxXi-xn?S+$*(vX~!>nJm4A!QhHBAJJ>i0 z-zAu=rrc@Yvx3cjMvrnH*%tfKyYRf|o3F5|1*LFu%#SA)x^Kbu4&OtZSf^CCb-gK{ z4;P6B(C1*UKK4t_M!P=y)sWsh>oiT}@u#U*)#|Dp})U)u3*LnR22>KO@8A#M|z(8cO>zO&jv53mepJFeiHW)uP+H zit{7##_bcIMmzGE2DPt;+p6m|YPG%9@}`yMZp&weQ?aqX3&7gxQoH#4c@3)le6%TE z;WBN=`>|;(K>Eh+0PC}X@%>x0C9~SgXBko0v@YpT+Ecq_>}v7Tb0;l$2NS|O7`%(Y z`?z@<^*fln_HP09-DCgw0_-2xd+s-v_BEm=IsUIgoAaS&=*&Z1p9{S?7!$kpHlspN zo$Dh9_$$>XQ!k7?QMwpCW7jCV-tVumX36z^TMCQ4X7*k0eQ(Zqr_}bF@Kt-Z{d&Fn z`tp5M$hT6}k4-5~&QD6)GbBnaq;_ik{;F_ygW7aYgX&tN&qh!S5e9j!v~F>VrKb4y zQVZ!^f%Pj@V0l7?e$k)~gc&mK$=`K*>uaardfr@zzof^nVFMTZQ6Bz8aCT6u??UB1 zx1`|AV=Qd-tJc>)qXKtdsxmh>s5L_kYMUdR@K5)v=}%su0)P6fzMj0LK_!d~VIW<3 zt-=q5H6!p}!5;;Gl*fJSXRSL?u7*7Ov_Z2+bY{Jp>DyOL9mCioU!Mu2r=;*zDE+7N z;7|Lg?DgoQZ)i|2xWXx~Rm_h$WzH@yduyT7|l#+b28|;#zCFGoNYhtLttE^>QleWKb>W7IoK|pQ|X}`Z=-s`QfE^r5=5* zFI)x3P6YQ|WHo{dOWG=AyyF^Iwc20lmyYxHi1T)c^EURr(zG2;b3T%+a}gcqDB`>nao(mB=c@YK z)#E#n+o@S=qR88&m{;9KQH`K5m)w~0;*lnv`$0{)q4f1#q3VkMf|YmtboRq8#B+D_ z_0Orc^_Sudq{~!jO%84K<*G2RQSC6lQSE!QtF0H;e6#8h-cmn~(4w!PcPi*7n(-Vs zd3iwfnoGXa+XpMMgwomgwpEn(2gH3iE5_CiS+3sEQaXNik zFlGy>satH9k)4{4V0Gv4%DU5OdsnVIrY+Lr507^@`Z~`1#@M43ZB*&pZ+-U7Y_whY zU>DA;rtw7iOuWiIA4@1}RIG`Cr==C<4Y zf*D&MnQT;7!ZhJ|)%-c-DW%gJ=L~tCeNE5I*c+kGmR#F1HnrGXkbSUEpM!xjG&($< zWn1c1%UX7Vnscfu$}HNCNEf|tTZr~!F8i)r-U%d~B{;7Kb3u6Ko3VT`^yYi&mBydc z&voIO;yBCKGdxr_HaKOCYwz24{!T{wTfPRpb#`6R*Szv-ty4DK&vJCH{|#)yQR{j7{pi#h zM;L!<>6o&ub*iiv)M2eyS5VaHZ`|v8E9Ry3HRo*Z%}zhKwDE|@;jO-winq;npV~v7 z;!l^EZaj9mPkt`ddq8$6{_R*ZsORwN)Rf2dWjp+9op_Kf=lD!I7+c@B za_kV9H+k2oI9sQ27tD^N?6fbvM=@@7zT?bOd`rlF2co~(kk{d(v)WMa=cC@w-&p=8 z2FY5&lT~;vP7utrq(d0+n!fSk8ynU2Fn{)F_v*s|jQ{Zd0PRxPJ}0g;zuS2e+De$F zlbW=x?=Q~6tr)}As9)MWetecsw~eMuw9Lgm48(OV-uKMy(EWNT3@6>(sCr>GAPnZu z^gs2kHps+v&!I+@fyqOkZ2B|$wdRg})F+|5_*#7E&taSLO5+w{eJ|HJPUZ~twD|U{ zu6yDgl`~gbkyftoQ#kb)cY|FfkbU~E6b=&}Q@)LDt{c1Bbs^W^DaAAPbc|o8ck7vl zjJq$Y46FVIgFQz_>EsblyMJq`+P_teiwT>tCyImAGy29h^7m^S_rjLn7uj?QJsWlX z7}jPOe3ussn~-64n_0Pj+WpOrN62mZaqR=^pG_Z0X{*bHYuy@!hvbeOnT7NFH)Aam z${u}Nc1720)uBsEbT9mSD2%`9;WnjG?ev>gferY&;Y#aF=+O5og0I@^peVmH+MT(l zYYl@en>ZhPD%y#uXeXwkPoew%w0z&2@$c<0R)fA{UB6mw9YkJNmLqZIy*qByZr5l( zs*ce_SnceJ*#s`FXn;_p5DksXE^vM&*q{?Z}_A`!ae05O<8my9A07h zE#^4suiwKR#UqdF)!dT1agXo~o0mPL;QXb&SegE3A8w>&`)>>E|6`x6j0c4$h3mD_ zHS2Mof9+TH-~9LH68pctD)$+h;68&M_u1LwK7HNJ9WV5bPaCd})+i@MkNbS~XcLRF zo&1RXf0xI7DF3V7t5jx_40gZgKonC_z{06FS0M>s`%eu#s9qUpMtq~mGB%m*C|J%Rs2^Q zyu+XI@c+9`-E`k&r(JAH!XNoZ>65PF|G0<$>-LmBD7EcE``SPi|MOM+Pkx!FKc&x6 z+gJMk4?PQsImwH?!{3JMUin+}@c*2XD*aD8{&!XJKU>BB*v886Ke}V3|Jx_*Yr|Fi zFIMrt$HV_4POJ34)oJ&mmw2a70@uCLC-32Z;~tg%pLMW(Emy_={wn^*zg3w&=dG*s zf2U*YYok^CSD*6^|M0gf{r{myJ9@_sw*N`^BmZ>yui}5(Rh9n#;%w=IQXl`QeQltM z|M@EZXFUA>{fU+SuV}Ha1updte;clQ6&LN-S1QwM|0CsH@M6b9?B2)AIO!Tpxz1HTEK(hQrOiToaLWT2cCKA`m);psZ{wOu>YMD_++0w zAN#vw+qRtir}y4#-}LvLzTrIQkbgcHDqDIbkG37O|5yFjHDyW1{H1@wxkqr~dM+k;5S^}CO9s5{I^^`cR%NT!O7oodHMm)BZ9{S zXMfN2`vfPqaC!a@oYO+yBe?4?Tt6$g=Rqz{{gv~G;N(MGo`0Bg*Q1=Xfy z_X-X?&gDZ-axMrS6`XsT>t_V_3r>!5{g~ji;KH+9e@O7)b6h?wxG1>yd9FVoc<2Q# zkG{w`A-GfUz)M`eS8&%WT%Hx&`6`zOUgMk>+$MPZb*^6&9D0Mx1OMPWBsl#~E*}%z z`6ibq1dqPOLOm@TlN|;6NRBKPosoh0FT{ z4+|a?+}Xh0X9On%=LGi)?rh@zg_}9Yf}Hb$M+E1ma{Up(He;Q5>f+Bo+L9$UcWv4xz~Hk=EBM+K{GxqiRkA;G;%xqdjxIVN~OaCSSc-z7M< z1D7WShj!%hw2%+)#O1MNoRfmnf_nrH$GH1J!G#ZT`KaJbJC|p7;oK(}-xlZX!LFQh zD>#RDJj&(yzjGcD-1Zok$0a|`1fq7aR(4`IulejmvYAr*nBm@L(&K7X=RsPS51}J(6c}c__>|DmWpyQ?Q!N-46)P z3r@}D`s0E_^SC@bpL0xbT5wYEP#bsOFSsDMcM;cDi#dk{2e#qzF(Dri^1-ECzdy=( zNN_=L|MpzJa|g~D!8yUBJ97Qroj4B&?q9~`LxM+k=JI%qv-%L{l#qwoxqMJ?RPeCm zUAX(ga?YcIi@S1pb_M4?!9%-oc|maW!(1K`oDe)BxVSraKlBmKi9I+M1!wl;@_xZN z!Lhx#eo}B+aA$(+XZGeCUBx*hxN{#a&j=3f%jHqQnfJS%uG$>qa> zi-OY!a{bsrob!Ua4(9USLpTozjvmV8nbn*FALX1A+%Gtp;`#-_!-sKsyn}O5aOQ9> z&k2sM;qo!Tfg`wF9m%;zaP(tb-X}QT$>qa>Q%7-mUhs(EzN5K*R`B>STps#3XLT&+ zUcm!`L&tIb@bR3pg8Kybrn!FL1kQ26ZGzJ$a{V5`v6Hzx*~Pj4G|tJ>Ij05pp26h< zf@5cL`S4ks3ug;HhjZ~<&OM*v96gV7@zb2g1&2Pv!QsoeJS#Yqt}w*IVZU9 z8ZI9cJS;dq!1eP#;vBt}b3*XIkGZ^8a9(idPq={u&Ti)N zq>u-05b_&24+&1(#N|=JnV)lcPH^#NE*}>h8shTdTR7)#b5iiQ;P@}OeoAnc z;Lz<{zcbG{a0ll;!GnV1cXIt9!O^?9JRvxK50|F|j|-07%k{^8!+AvTz@=?M0wOpP%k#k1y;5sf( zoWyxp$YUpS`Jmuo!K#bvhXn^tf`>oJ<*9QycL{F$6qgSRE(#v&;rc`8agLwQIVCuD0hcEwU&!TM z7jZ5K9u=IsjO&klk#pBZ&hamE?)f_B*f%(bzr}e-@TlN|V09IDANvmHyx_L)a(PN{ zTyXk(T)!wdvx&}>zu>lCa(Unm&hfiAr|#xFCgjO`xP0K(obv_FBZ5c&z~y~g zI1dUQ`6HK)2~Pc)%kzRq1P31E`aOb+g0mxBzf17oU%9;VA$ zj|$F?b9tZOp*Oj_@D}IX+nh6k3;z=GcR07b$9dEjV)GpZ!6}Q&hy9#0lR4)E$LqK} zGlg?Jz_}neRnO(o2F{~``x?1C+QhkE@Q~nQGuO`rIY*~*4hfEjguI3GxRA%Dad}bj zxZr#%*B=oapULHF7U!_wo-mj93Qo@9^5i1UF~MpHmxl!p3Qq0J^^@(K(}Fvfb9wKs zoJZrF$3M)ub9c^NdvFfz$vM6^=ak^KRb1YC0Oxd)^N8T&fm}W&IB*b`X9f2O?mAfL z3+@w~JcR3a9?Chin)A4jM}>Uoqg+3n;v5s4IE>5lg2y|!JbF0ikl@T3F3$B)A|r{4?%f+aTw}^_)8e_iX0!&<&jX1xE!B-pKW% zH*rn~?)$lr-^@8GI5ouOalu`J3%7FpQNiikxIFg@&Y@p&jtcG+oDe+pEADF>%sD4G{u?eI6P&w`%X7cwJT7?Xel9Nv9u?g70M{QD-1U1dPZv0k3(o$5 z%M)8TcM4Abk;{7o_X_U(GuIy%-1iqQ&k7zCoEqW!alu`JLl1HNKEa(2b9qj1M)3IG zxPIml&TWr!jtfo+4i&k6PH^%uF3&#BIq?MNPQke+xjg+8=cM4!(_9{XhI2x2Zj{SY z&vNb(oPCbVL(g*_5j-Y1@B-H#evxxgaPnm?4~%gRy~24!aQ~}Zo_vjSL9lwA%SVO0 z=M66J6+HG2F3Q@H+MfOAhh=V$}xgy2rW8OcrD zeNJ$+naiU=&Ygl2g2Pj}ekjB_+`>5~I4O8&8rL5cTo61ko$IGtIp>AEIFrlA1xLeN zo)DakaCx8L_-rmu2_6^RH<#-V3htf9<$d!xX9W)m9$moo$J;m$EaaRQJR&%=nCs^R z_Y3Y@!u6xua!v>?2<~0V^#j{+9*c60ZqGR(xN8S4&k7zC+$T7&BX{2~IJ`5L#{?&1 zT;BE}&H=$=LVu*4>yHTz?84=3g44Tlc~Wp@1()Xp_X{2pJRaxnqaWrR65P2vmyZb^ z{0Nti?!j5@$$41tpy1xUxPDuLb6jvra9|bJAKROA+diDtzMR8?d-vn=0l|5}y$5jp zwj}4c-~qwmgSdWDa7=KI;I!b_q1?Z`;OuHH?-M*IIGW=63Bl>ZxIBJ1=dm@M<418$ z3GO?V%fo5TF~QjrxV%qrYAu&%PvqPuIKPg|Qzvom5}ZAm%lia}PvP=m!GTk`e5{Le z*J+%yg7cr?@)5y>)46<9aQ+M~&z#A*Q?SZ#d022>aHyN>4+8ye{p&8>zs#$yuXjj(?VYf`H;LtGFF9`1c4VMoIE(q@WE!S7~a~>BQ{T-Kw1gqb3d7t1x!O1^xeYJ&izu=tU z;lFVG%!8cU9^%~hFz3`GoI{Ut?k#eTJ;6CCcues4lUzUa6zAO2oKw$mR->E;1m^{h z2p$t$c%J(gf01*W;QrUSJoyIa)HvrZ!Ra@-JoFal-nTjT2p$kT^bXgLzstEGcvP@@ zkL!m8$9>b-{99gduf^p9lQ^gSoO=W(Cv$nCj&niq&=esToUG^av|!c1<%velQNjJq zT;AWpxv!OTY6j=NnVfSG&WYKaM;3A(+=g>z3Fkf`k8jK6nVmT21Q&Ma^4^bd9uS<_ zgUhoC&Z)gP7gupkBspgerTe@tnga zavomCx$`8>8Nr2x&V7Q11s6}{`svd+_Xr;U1eb?S=R7EQ^b9V~oyj?I7U#U+ zo(z}w3XYx4<*J+WsF3G{Jingnj|gr%m&@aVM+66Yxc-=sk9~^E2hZo6`!wga&u}gZ z9=m|c2S3YsSn%kDT;7}I+;$P?xZwN-E*}v*Ab3ph;Kkg1`clqgf&-Uvc{0bjO~}(i z-gi0I9~9j61uh>G+j@v z=f1%?`c2Mbf&<^;@;1Q*!M#^;{n&RnhXp4EclLAr!1p+}2~G))3+~$_+<%{QT=3uz zxIFzs&IQ4}*Km1{;DG@y&kI)9a(Pj3Sa9|_uHPkiQ1GzeKEb0uICR1A;@(arZ-l3xYeJ=lZD^ILBY)oEIE>iOa_Y z_rJ{LLxM-gxLm!$IV?Ez8ka`}Ctm0BPQe+$oo{gcalxbi69KcTVH- zQNfw%T%Hr$*2?9{8Jq(%Irq%soE999aCveb=a}I1LN4!G%z0FBW?L@L3GNrHmU4Zy z9p{YTg5bU#xPDe}YDX>~7TmQHm*Hf6b6RkZ;OJktexKk$!G#C8 ze%lD=xZsrF{9n0#*F&6(g8Lul^6=j{#{}md;d1pT=K;Z)zjJv`a9@$jG? zoa=Wz!8t3q?@2Bn6dZku%TrHtE(-2>hRb^ekBoBp__LgQp5v^Z=NuN?FF5f6*YA0e zbKoV;dBGzubNQIywpX}3E;uDP{2JHq6Fexm_&V3`dV_OTaQq)!o)TR6CzlV5bIuEn zzscpJf&*`Jd7I$OzqmZ~4(F)gPQeMm8NvDYxPK{ME1Mrt7Ux01eS(JtCns_DSwH9D z$()OVb9G!kIE8bc;GqDQ7X**ib9t_T^N`?v!2?ZPKibT>U+|FNk)Y6@%6Uj|L2$8! z>-S9KJRrDNa91nW9~G=-aQUF%&Y4`EnZ-FLIn3o5!SM)}4+(j{;FQqM&*AQS=5mhB zkkV~FW~Z|;LJiU&k62d#O2AwoYR5_w&C);;LH*(Pj1UOFL-Dvmlp&V zqg*~NxNkcy@7$hqL2!NtF3;@9IVX5!#>5-P$cBYop61qX>#{il7LJn4;(*=piU4sG}&tikKoOf|{V5pvU<= z@6H_8b+YN4&+qsB^V=Se*Ll8P*Y&=y`?|0Dy6>dxj(z29R`>hAc*)vVf=7Z%NQgXkN&4OF{+o#JprsRl{?K9+hbGe*tN_HqYK2xsmpCxDek#hDZxxgy-r<80sO76EEEoX<4 zZO6#{_6j-2lpH)(?zbK%XS^MQrHYJBnl>6rTFyZwhn4J|C)Y=neou|uAGXUm zsN|@U#eBJ5ERb_T=`T?FgG%nNmyZuAS-(i`H!3--U=9zse)$g5`3ypC{*tl4DA?c;)&kCA*YdaG_jpQgYWta(_h0j#jzf ztK^iDO_#{^1xmIm*{`0!Q_fx`>+h8NO?S!Js${#8&G*Rl5haWJ<$g;@&dCSmtba(!J#scG+5U*!?|W3v zmav?wlpK9Z?zcT7XYX@zHvL`BmVP<=Uy!rmML8Q^l5S&HC^;OJ`=d%uDB1P8T<=qIP{~z;a=k^#wm0N{hmu2Y%Ka%N$Ccc#WaHcN@n$8v zR>}RAcjR29WS5f7@5=QyB?sP9`rntcL&=G_(*J>+y-N0dDE9}I?D$COAC_}i$x$T- zKauM_pUT;Ld%lo!!HAqqO16I~_j{BaTrKw(e@BZm42g=z2D3A4kZVa?D~gX-=C6mT*<*7)g$ddaLO1~{z?sq8JtYoi}1G)0?1$sFLlx*Kb?vE?kx2fD8RI+I^ zxj&+0OP<{C-CWN4E#z!eaze>sl3d?qkaI-IsV(LH;Gg7d-%8FNCHs|Z+FGu+DmkHK z*EVu}@wRdfDLGmo_a~GrCd>VfDRTDiAZP1Na(3-3XTvUX_UtNWzmmAgA{-~1uR=GcRl$;$$%h{{sfRgn#xxP!u5jD@2>%|;7+fS9Vv0Bca)8uTem2*hR zuK9Ameu12gN;WImU#Ha9%h{}C??Smhpyc2px!>rJvsujza=%T}|Kc(c*`EtM6D`&$6a*ioEaG~5EQu9S} zf4`EGt#W_#VmT+2Y`9eJFIKY0C-*0m?7d9x*IzDYqms=^_WxO~kF?1-aD|*hO76N+ z?vE%rb(P#-<(IQd$$_io{*aQ**U0^jYvpWhm$OO9RoBV=E+q%9m-|CX?pJc^2D!dJ zAZPE5a<<+i=aiDYH_QFS9dZsRIizIE?Q*?-g`A^Gw%jTASE>0fxxZh@aV4je+;xw9 zeB?eQKPcze!*UKhDrXUqbMP5C7r!WHYgEpO*X3*;l(S9A-Z$j_l#=al%KaWC2j7zW z!%Eh_E%zs5a&{^G{#9~+my*rz$o<|SIXjeG^{(6>Q*u(t;rHZvLtM^&B^y7G`^`$O z`cUq7eI#eYu$+sP?D<&k_bWN|iQMn_RL-%4oRdn{e3->ziu zYPrAoD>++~Y)Z=g_OIn^`bN$LN{)Xk_glY{bHVp=HYwSvWb2P| ze@N-~{3Q3A#^h{Oa^#2No#kv-vPsEF zCC8MU+Fc&cyQh-(k+Va|!Tsd^u#z29<$g!0oU0C$bHprX`$2N{D7orjx!vlZL{TmhmyTYHq4RhQe2Uy3RdPbfu4=j7r{u&uxj(4%i__$Oe~p~Glx(P# z`x8nI&X@bcN{%Wyxj?QjsF$-z$>D`^zjcwE4GuXME7_vtDkaC1oK$k6Ngm&Jrkov0 zHZ{xrQ6)!~$o(F-oa0IkEtUJd%j6tTa`9Pmzd^}fkK7+nvSqp4Z#hTKRZ6zB$o<7i zu2Qo1T)94}Wc_(^zxjMQ+m!6MK<$1ZU!~-rl6^{cw93buE|#-Z$)-!>{-lzP zKDpnlWSf$`m&x_f%jKL=6$pHQ;6LGJe}xj@Oj8|8Y}O>#EhEN7dN^&N7*@fJD9 zZR}QTzrq*Z&CBTa(`UO zDJ2{3lk0=sat-{{RK+4D%q}N zPrrP;U&&ocjwspql6<^b$*uvp->2r6<^HgegG!FQBG>DqayBYCrDU^`y|2s12Ug12 ztK@i0?oTP%`?lQg8j`d9T{*knle6JNIeR~rvqQ-RpUVAJpUb)bGdWj{$l0Z2i;@ez zl#pM3$VrIdV>B%ef#|&c-}B zi!J2rnj~kNLC&5nZyz}a zm2BBp?su8w?A=e!0VSKJ%KZguE|vRDO0GIU?iUBjxj@ObX>z|q$zHSE?^XKs2h05t zCC8L(J4~)GI6}_WaygrnY?&qZCzRZOq}-oUa$L!#W953Ql4D9X9xvCMZE_AN{VAot zs#30ZDcPrFOO;$7J4w!gQ{@~|a=|>gKd$7+X>z}-R?bN!>*ve;_If#6l^j_p_uCf9 z*`Z{YL+8yo)vO--6`kr-EvNK$+_zuIY*T2S90=RxxW8CIh!Alb5zL* zCEG)Cy+_F@CHo(g>x~b~Iih4&kKA9SWS^2ff0gSC9+9(9a^O+9-x8K{Ovy<#KPJ}) z9+$J_2{}iUT-7W0yOf+#vf)X&KCI;6-;{nOJ0fzw?P)p3l5|4q5SOUdT9opc{Uod_>g}-h59iL(Roq|8uoyoY`y#J^FXya!7PY*i5@znF?ahx8h_u==3TYD?l z)_KLIn{K)`q+#bNYwoMsWv^V*zIL70Qmgx|SC3P3pJTgUp98f|%m1tU)j64(($Cj> z(wg zP*=Zjk)z@CGn|VXn_Oo$FL5tjc9v)P*=uGx{fHUmGiM!XJ?iLVDvmwwc-sjl&aRv@ z_oS+mPx;^NO8(ED&pNlEVa;`|a~m4}&%W;eq1pfca2sc2>a>s4@jsneLf9`{e&J5P zHd%Zz2N6HO_pEy*9q27|E2yB>R(+k zykd&@ctv8xsp}s9yxYf*I3Zhz6IPwJ$|!19oxV!_b}7UKD`W4)e-L87^VZJnKZaay z!`jdPwM8p_^F85bzGRI4@;Ui+)=uM}@Bb~&|K(5WmvKjb8FxducE0Q4Z$IDnp-9vJ z4SzCz=TD~cC+n9#|HZXSUp2Hnq5WAqp43UBXK2m$CAN9mKbCjb^lQhd$EH2te^Fy< z#hRb%{CWS~_dmn`Vb|-u?cYDoZphOAc28``aT{wluE53>*th~4S774`Y+QkjE3k0| zHm<3_F=W#YIYFJQH-`w2P{2zy;s~^9P=H}YvHI4OW)i~=L7r7nkf&X!w?ZD|ZM_2v& zZ+!lvpY>^8+URarT%UF(>FU>ug%;u4!6W(_GuQsQ!27%Y2%a)i*D6Hl3CJ z3~O#*x_N2qvv6tS0`1n-EZ~l-C*#m`$2He4s`sqpWa;XcEO6Alo+X^J%VM(zLXBLH(NT zUOT=JYxdWAC->{<>DQ;`s75!VEFFI)YX1Fn)YZFd8=OnlJM(nwx42=+l7_}bHD}c} zxYu=Xy5rV9XN#9Q-3=~hea$Zy&RFXj=GQArHy;07u9l(J4#SP8_cSbVulIt|jq~sI zKdY(v42D_ITtCsZPdDDL`{LgNH`gz$*LGI@?_KBw$6K>$*E84z$I-UH0>_4q^UM2E z+xz3|w1LOh@Z2@lG`rmmHBIwRuV0Yvg_~~v+WW!1+*RLD_n$9@b=5DZU6OA2wC@pZ z{C__k@@GxD@s})L;;vtu{>787zGn7%4)}GaZ#3&$fpqJt?TMO(#)VD4d2Oewt2wcL z;fy9eEbE&s6M6S(^GG|+j9Q*#r*nMoS2mqd-*{sEB3?YdJPZ>Zdi*lejlbUEYbtA( zoMCI`%g}#)p5Ls;5w%O|Cp2KX`PNKdvb=GDHm?~?PAAW^_SI{Gvr9ML;YBsaj(^{) zovwXbvNk#ExMQ}N)92PN)4rZbpM?`W(Jz}S-T4^LUGGuG{iS{_)^ps1)-K)gvw!&> za%6MUQrCn=NxvVZapcumJN;joZXPqV?>`kyeB+Wwn#e6oH{Pt;hUN_&Da|-@YGyc^ znkTj`(>|wb=g_>KHA!>cxhK~1lcmxv@wxoUhnv8uXB7K{W9tV zw^Q16`;Ys#0W(dvo@?jVJkd#UwduxL+PGw?%hlBEuCJ?UTJN{K^v5q)^PJZ#ZJe)t zW7k;g)L!Mk^W9%t{B-kKJKmCd=fbsvu4k)_-@|m{jDN4;htK-;yn@mlx43@ElG;V} z<3GhL;BgAjAB+3~PTt(w^+~ ze!EUT-ml-QYqTHh+3QQ!y)n|wXYKlFKZh?_I)BN6=7#z8HNTF!-dmGqyg5fzHgRK{ z7A>FYsb8>E`*c6?m!DJDJJk3sUhjCvHP!vj?M%1cbJkAh_%%N~9O-Q0Ii4}$kBaem zt^J>L^GiGa_*^Ics!lU5pDSyAx<9tIk;iso-$B!iGv_FEAn6Oy+ACYbG{?_9iJ#k# z82>wq-@l%8$Is>mc4z&DjFNtzAFKU6z=jQzZa<7)&vd7AqL(zjFzK#Ko67XY<^T0K zmD*GLM;3{hrJL8fzYnMV=DI=Oh|`^KZbP$sX{}THA%jmC{&Ms8w@KQ0kN>q(qxNWy zf4|;Pu4|@;pZxydeAW)0ZrsZ8j}hf+C$ebkxZi8W`}JGX zghom;uQ^Bkdx&+uA<`T-ch0f1|Hu@^mnhA6bBWucSFWVb3ES*#y9?Y zFXH!(n^n8O-PAn6#hloBY|xNt<~R57qTgKD+R-Mq>J!@(<2!xL|D-!VkINsq#p466 zW4zy7(8Q*=j&Zbi_%C0(Ch(z<{(gg#OH4U20h{Kif<-uT})*8Ml5{@%WC>N|zb94;(~Y~t?c`Uo4Q~F1##ysu&F>fZeGgye7uNC{)d}qC zUzaQGJkpN8jN4wjVPk7&nehD2YG|Cc;lrW@dFT#7_ zjc5d~F}EZ`jN&zJj`A<(SlEE78At4$A-12IA*|H6_RkQV$c&G`QB+L5p)^CBj~uiI z;Y-NPv2nP=0bGMNAJ~iv@P7C@68I#XdLZNCZSWe@h7ZB4X&EBUIvC;e2Xij1{g4dt z9&+MMWf|gVceaN1jX?7!!pFI!?_mbAAvt2-IZL6B|}(H z9o`1LX!Hu^41LoX6EBX)5IfGu5P8(N;Ba|{sHELCGeb0?YTCW;x!&MhjZZl zb2G%YC$Y9%iv`ZDVlD6*KSpEtapLp27T3uc;!#wL*Z34N<24?3N`|oEH6DW;c#S8a z7QDv#Q!|7gudxwz;gfJ~H8q^e1^uWFAA}F0UTPxnH8g;a!>`d0HDVt33%T)r_&Vy- z#)MN(V~^2pgJURu4g0Nz>$Nlg0PS#EZH6eryWlYkIQI?Q3wU3BhUmtd7G{Vuk)wU` zIKy}sUgNvShu63o1@RhFD2z8P;#f3-*BC~lc#ZF(yz4j?u0}<8jVV-yH#suIIcN;8 zafb$;yXz;9a~j@+*XTv%c#U72&c4M5&%mQ$yv8e?Jf~cX#=B7gUSkrK;5DAw$T)aI zQ-;{InRf;AjKUX}vgUaIvJCMiD!Xa&IREBhAL2E>fn0dka_%9jV$K?a$br{*?b*Ed z@ETX3PQ1n_3gb=ZFg9{AXN`8`#cQ11!uu1iaX#wBYxJWiJ_(KIa$e?df`=m=_gZ5& z%ExQ`3o5~Dd>C2qad`51>|w6a3vWYJv}=4AIq@3LJfHdFHU1d|@f!W82e0u?G=NXS zNnY0Z+R5YG1z&>K_yH=%Yy1h>@fyVi>|wmdtx+4^4?jRf%uQUFAx=OoT%!w~a&d;} z#~Ux5ye&iM+0Wi9*fUr0EHF+G8vN`BZJpswXaFC9{a3RmnX};+9ma%f}1E!$Z`=3s)yBOAxsVemTcg`ew%+ugwX@oMG<-N?oqG+v9U@ERk?jn}vm zwc#~>iGp}Tfb*bHyvF^}7+#|t72L>q;SyxRYrF!L<3q3q1@IbIq99(QxRH6{HEx9l z@f!C=3A_z9pu(FckMk{j5nkiFs2neD$`F%Llzp!8QWV2$yaJ{0A@~An#cP~)GuMdM zcqr<|+hJt~>(1v(5QdQ(uW`3qI2Nz56m{S=9*jbGJN)cco*mZQb{l(P1%O#r%_S{<9gvcopmU z9P5et@EWf~gLsX%qfvYmp5M>fa;)hEK1W{R+_VQ@<-Q>=UgOMYhG@rYtVJPw5^nYy zYs8vpJPP^o8b5l2&mFu*!<*VO!2IE}Xb5kK@r=B~Ix>!Hh_!u}b!N>qKJh+lgxB~E z^5Y|MzK49s{-izx^&cVHH9j@W_2M-SAPYYDafWyd#qb&@eZuwNH6DuubMV5eQ8_*c zA4K{12z(7y;^XjZRE8IyW{4wD1>O!29HT--a2w$Hdnc#R8DCq4qN|AM`U zH;gbx1W zA>IxzK~cOPhLON))PK!-;x+DtO!z3w|Au?g5^9FncUgIsuiI2cfP>ORU;coxp zUT9$lDn5&RIGyiKMU#oM75>4TGn4|X8~J_NVhHd7Si&2ShM;4KB2;#6e9*Fg^&#+OWH zeB{QvVHfJfhvCbp2R{hM&>&tvB~xsVhVVtO6?Nb{-~j5w$KZ&T@uTq2?Wn`s;5(=t zFA7;3WW`6|Flxak;pFWzMH{{do`x)VKfD{6@qKX8j?4*P2X93q_%PhW$ok;T@LFWJ zojnf|$cRtD(w$fbd?$PlS@9!q)15gNz8`M4OQx{lU9fQ1Oi_go!Xeay*YB1oW}+6Y z20n_0@cmG?JM+Qk!&A{P-U%N@gZMruiZeyt3idEO3F+_-*oi9eJ@6+~j?deJ8sx=0 zVH7#>Bd~bSOi_Y2!}C#*=J(1JXQN)u)dpWdqxd-7xr9AWO(|T4D)Bz}BJ$&h;0}AU zMtIXctO07}*ed8j19&gI1GVA1;j5?}AA>)k4!myPOtCxa#GBxWsE#qK;rXbW_Aq=; zYrlif2v}g^S)ir}R-%5q9ePm|?}L9qA$%AfxnHL6ajX-zp)T4(@GWGeJq|OcvPSqk zxbyzp7it{vDrBZT48K4oys

EI<}~06vSt_$W-GAjhWQwg<46XfK9UC_;N3Y(-Jp z+u)NZh97|6pi%r7Tznw)S`GXc(sfQ2h0}QUkr{7;=c6&L2EK{<@d-H9%ofmU0lnaG9r!h4Y)-wQuORrpbO^ueqZ-VQra03U{*Acs~1cRnOj*zqQ~7jQ1G65T1xq z)HvYvD1q;Uub?0Zv9lnVA@cMF|S2RFP8+;Bq@8bOl zH=oJg!xzGXPyzKeI3Km)9q>{#h!4SMPz&|_a1|QE$Kf}~NX-~LY!>yL%Lf06bX}80 z`H|c^RF3z+VN`(^)=aSkRpUeOCzOvj9F-}KLWTG`csnZ7YP7badAH!r@Jv*M?|@&U zYR;=ahW8ulVm>Z-KWd{r0>@AXKCgoL9?SF0{2lP1_x2{+XrK)5+8?~S5kv7 zg&tHveH%P>4%d$N!JkkMH3f4s#R+H_Z-+OcF3!~je>#c1gs-gP-Ht}68Gy4+W?#`> z2MbQ&*{9tB+fHRYX^+95(Ewgw&HA9SdwHKg$2^_|d>C$W8vBqnH^MWJ{vO)lVKsc# z;O%e)D!})^EIZdleKA~u25Aq#DDvUsaC&W~uxQ7^`;iwv0NwL>MmTQ|+;ai*r`-x~ zMt*z<{tNZt^Xqs|pdj82A43lO0Nk>k_XEBN)*&n20}oip`1lUE61nhkxa}g|QFse% zLIUrHan#DSjKaAN_6gnvA4VPcKDbQ->wqtTm!m%XAe?eK=lu(N173j2y1BpbNmPO# zfR$%(Kky#-3aZ8rL!*=Zz&cdGg(#2qcK9Hw)9wp=6&2Aw2n~x_TiT7V3>DIDgNslp z-U)9CbitLHr#%jLc5z>5Z-rl> zYOZ(WO!jIs*M;waAE2@OXoqu`FbC>g@M2Vs_rn+5ya%W+SehxOp$f+L!flr^H@qLd zj=HEHhBu$Z-oVG8&BME$8W${H&NG6qf?iav9SaXRhZ^d;;EPB{`ykx*eAb7#8NHd} zV3bdL1zdr`_|gmb{*3A#=6=ClFXVIKA=U&oqY>I$pz$Kcyq{y?bFJ)$5NmrepOu%e zRu6E0;o?iVU-&U-_VHYBy;itX^Niz#H=quD2Yd<@;bU+$8pV&og_ki;&eaO9yqx>a zm`PavXUrV|_5^ zO1@v=i{YE76<>4}W1tHB0Q>@#;YZn?`F5LR~bJ)$oCdBz?|#gQ)rBF@^9yz zhN|&mMW*;3m2uz0ckrDDg&8vix9jBl1HK4ehT0gj6UI=hHvXNwOHm#*R@jVmcs~rI z5$4ke#a-+Z#y7yj?q*DmZG%1c@*ZOj-uqaC5YGcO)erI7|$lu zhglPRK0E|P@Kx~U$GBgQF#pFh#c{~k!}}keiz@JOIEE^z*FC}BNBMu{y$UN(7;lG9 zqJHgMaB(l=FozDFSKgD{6I9IjR(J}k#EYkR&!9TSDThtSKzj=ep;E?) zz>L2!e|$b%jBJeA3P;co$Lb?|H+Y(LrX~pwdxrb^DDMaOFmf>GC_L<0?g8!9@H*6k z?}XibJPToth2G~7<8;Fv{?2C`=PHBOp)PzkT>L!yhx#aV_j8@J2jO8auqJp1d>I88 zCjs+c^*I5;jPHTvAQ=hMFZ-fy%qj|0*qsPlke4Ngc>{i9`!Mf=`HRR@-V&) zeuLs1TNvYcM4kBJw==~#D8x8^n74{G!I!{~P=aeIeTSdxQ3Ye_hM2><+(-NX{0g-) zP71Dmk87m8{Yz|gG})^)J{zdW`4*u;tlXGXpA`z!@EA>*~G`-)*o|^n6n42 zMk9<<^$FhrP?+{G{6zDt?I;}kl=CvriUi-4KI0l_uYi-jVEwrkFH9jL;}?uji&`18 z4L*+wv^l`)FS!TQ4@1{#K1*mHghgMm51F$WE<^>|wZQk2v_HZ6f6coEmEzlB>o+{V z_ypc94gUicyk;)meTqwH;5*2I7dqNd6mNygQ9s@XyHM&yKC@sP ziI;fy!o2J(p~vUL8svS7y#af3vP4TC@1k7B)MttIXSu(y8?`;hI=}(cf**tB+#~eoBE}Jsu3#>&aLoi6ndI*;6G6-*RJ0;OH4!6)L7wi6rjcj??M&KEd*DgO4^6v z<|dvuuCV|fhw|{c{TKsvaDRR9A4tdC@~38rFp6@nVOY68YsIyP;7U}v%U~e;~yF5#LkDQEIFf&VBfhwr!hTow|*4#Ub@lhS~ zFFZ0!9E=2OSPt((PR5DAk5HWUQFyYIJ;pe0_%^b$AH-42A2}IQe>B&M2DP;IU+B;!x72`68ypwrG zk%wc;;0LH(+ry`1iRq|B+w;(YO7SjeoyWPU5vMU{)W&)mYO=(~r~_YUXYElt_sasS zQ7gUse9@Q4!Z$G(Sr;p+e>pgnKRE`C^_(VaYQv&2oP zg7zLbburgKyAxiF;@qz`7;NPI%ylKkV~jG95X?S%=NqmW_Uhw;k)6t$UngQ_EPQ$DBQW>Re1E`~!gEkR zHC^y4)P*l>%MuHag&IG63svEDSMV-EHfjQJH8S9fuFMiMkr8i$Hy|^9>?*!L_<3Jz z?eH2Dz<0t=kQbkV2Vc#e$5+5Bk(YA?;fF}zN8y3j@Gihx;pM0R-vQr4QI1W*sn_!S z(_RiQL3Vrqu0qAsjKF=`xh{Msd=U*%Q*vFFIO2Mq`6zn^evCr2kHF#^m@~c-`q3c1 zAAS*FZ@@OYGUf+79yE z!E}b+>Z8x3T8<5oieV9>5pE!*A#P{5tQq6C} z%Q(dm-e*sNbMV=(+2&p7jMeV*?jXq0Ol>dz9B zUf_MDtrcAOBJ*LKFx+B*`--oF&!KYsFg*HYzO!*(>R|P&oC}|XtD~$N*JXN*?{$NG zMlh!D4cgvf|1bv;<37I4X9_iL__tNu7kvIZy#I%|M!X9?jNYf=ZtKIgt@{tMO*d8iqN zlU6e~y#6bm(IjIse+S&{8=e>LMHF_8@;!kyG<}yPo=Nd}!*zB2kR@*ZiS@x3jAe;E z{>gcne=EHCXU6ATacKJ&?-^|!gif4=2AFdkF3Zq~;kTG4Y{}G#iWr|$@GCS#yU5as zI;4M__dI+Mxu}W2&rlFQ3U}2pCiSIoE*g4svarKTk(>GZ;ghJGar$9qwoW)W)&QrY zVd`x#iCU;H$k7QWs-QjypFuI|WALP0ozUSu@G%s}55U9qI{vPOdjt>LL?;Fr(+5Ln zjJd_(q)m0gM@<>@qe0rc;K`eDZrXitCGz4EaNj(g=)zl|9}O^OC;ao~I$@%{5AL&t zPK5Dw@D>!n55TWb6rX}+lQ)>a|#5j5RtmW3MKWkXMjZSQ`Eo((hDLl47Cpu|whp$ZLT(lQX z(eX1E_n2ebchHG$RL8k`;7iDjkHSxp6F&ks+mU;ud3cUdCnESD+-@hX7heXyKp}j= z&N?v-wc;)Cc+`fkgs-CDDxP1sa2K5z!MDP1&=@s^MLKaO>U@Viv#U<*zZ>Vpcfm1a zqCS6jomhp;v=_s^CtS1#^T7vT>z?clY9esuUd#bsTEeyNtrNv@-sdpBk4~iC z=ULuYCw@Q!)C5dA@hIxS55nsGXs6x_&z-6hhWB`v!m|BYs}J}bf%Z}|H9>gFfjW_g z?}z(Mqkf3bQ1~hue3xs7dzrbXjBh`PeTAHi6MzG#mt%+EyhFJ6_z0YSDD&soPPoV6 z>`#0LTxDV3G9UAF`ZZDC2~#MDFF!&jtTUJ!Psu(i`GmqlF&|VHZ(J=GrgS#Bfx$tFh0cvH=EpR2O z=3Jvte+>JN8Y7&COtgn#tb%(=d;D0|=Q#G8)(-c#@ys&+c6j~?%!is@_${hpd~u>q z%s^w*SHoqfk9I%o*V?I%!L2K~cZ}nPcOpOY?}3InJa=4IF}w&3XzL7rKwfGLb9Lev zR7g!V44^!G7d)woXOQ|nxEcku^?{Wqv)^cU!Y8V!XB_`Lop=*PsYyWHXd4<3s8 z@fFaAy6^!wh{E_`XsqE`!#iO&isO6XS$3TeA2J^}uU01#w5OnH0oO*m7Y-vQzNk(o zUPpC!QLhuHBR#$q-hsM?`3?+sU&!A0h`kC2P>LGeBHm-jLwgCVKwj!A;T?#-eB$5# zvu-Frd!BqJHHFPO@dygz6L9Jh_84Q9!)H)0^~3P*Zte%| zVkw_5XpD9n{3~+d2VwqM%!!&7c*1h7op#gN>?72|_+3zc4jFHRx)$yQH5S;6{2c3r zDO89rJeU20^6?Hh`8?XGx55umC*v5-XAQla>to(Cu=)bV#kawSFJwLOV{qCO6Bk~>I^&06{iW>lPgsAry^nR!YA)mcT+SS5cfyB}i}nP}{4;wJpAYL% zNV|6EZ(|SB9)mYu!8Ou849~feb@-Hd!Y5HVeh?b2!ZW@RR--cQT(ApO;=^zhRp51g z))*x@)&fsN6?hNqM*7dW?{K?oS;qv=FPzfOp23&GYf(P+-SC3zc{k!y8gF2n&!~qn z6vhw3ya0O-UjRS2k+oo)%A0iJUgW1e0*||y=LPSE-*oWI;wx`qAEFNGt+(pL6(|oM zgcU*7O}j4mBO0VV?{=Ly0`=kj@Mq*@oWd14G5ZeQA=Z35{Zq@;x5069%#;=5DA}948cmry|2jSDG6+ZyKL~ZyKGlpd=6Dp6N9hb!d<*P-f@{ZD_OfOuf-icK&v#V*1)nc)=cm{owAaChP(JO3zj1!# z#yjDqXp9;^{2J+K&x`Qvpb^^hp5}Q$t+cnmzo1@xFRXrs&qsVKJos7m1Kt6zK%@8o z96((otS8*NkLMp>4xdB@tsTyIjy1%4;ETwHABKPWyH0rVMQ{%C{aGKyAxiD zbhLNCo1#3A_+hxuYdqI@3#>*ZcpsedI?pw}Vx>;Jf#P`UAU{*Q!Jfmnz$tHXUVJ%h zLJ_SUK7vAceM~1Vd7GNAc$co?*+B-p4}OY_c>Oz^7y0o;LppIP3gE5pvd*XyAAsV0 z>hRUD5tZTH@KIEb?}sHH@@#Tm(?>jCsFd~=xYZ}LF!CjPf@5{7 zb>a-vMtdu~^DFM3Rs$_bzJK5=;XTMoeF9$nHTMYL3qL?M{0RK$8}=vXHGa!pMPr<| zaFlV7nVLFy6-rRk3H9IcU5oZ&csc5zy&pdM1NV{h_WZ~`{E6eKDS|6elA4k+KI8t$ zUc|S+Wk0h=IhXlgJYOPPgz=-WEF)W#GmZ_ug>0idJFqY_Tl8q>g%!v`dlhU!0lW`( zqa-z9IE2i!C*U4g*`k;BGH6Fu+MUpk;;euX+1XAJJXb+#DcT&1uXMYMCl2atvKUic|W(mo2U z+pxBHJM2a=#vFv7pmxR_fj^^Rj@50OEzU+dd;or3kS$uNw@%I$e?^_zwZL7cWQ$R1 z`r$BY)5d|DZO8qly$&u%QO@gwZ=e#ctEiB9B0Ju&J#DC!V@u&|G{~{la5-|*?uECY zKH59s>nOr}bUS2=Yf(NmVOY6iwy2|~1)gN&dTH;3gD8d{hS%-HzG6Oo@WP#07wRK$ zHR@-~G3eQaHK#rRw=W`7W7CL6X>WxC$V7b{ie1?gwCiCp>ZRVjTejF@cdngltSZhH z-=SW7;U3vy3F^lC;FD+=pV%{79I;onDENVTcpEa}T_x<#y}1_rFf89ETU3wnE`o!| zjZeaweOZ5e3;Yz7{K)#4SS!?m*YB4tjzLBEYFIFp^~c-b)2Iv|hvEHse(|C-TO5Z> zoVOKrAt&Saz<(eQ?fL_<#r?>NkHOOqWc~4em^qF8j4y_dBRzfuR+O=~e`0SOnl0Y3 zWQ!_%csg^R!CG-%U3s?nVJ7buyk{2mR`xKy5AJj{&kpq-_}np!$$Sbb*uyA9d*QL! z;#t&zAAynMxKDV;@jUM~#$p^dJmduS67zAwYfj`nfFFVf%w~NUvjV=0M!7EqmDyqu z>ZIKdUqOTTIGi?zdxx)v9Vq{weD{WLp%(lwESSr>;mhHbHJHy=I3n+pg zhP%(>9^o$=-HK@`Uiz^_mOUr>`Rjz{8W?iXB*T=+3K-Oe*bO(i_L zmit0`A3S3|`wHIFuwRqp4n!eeS90-b_x3& zU#1Zm@F{qJn`_5c!abLAU3fd3vW#a0Z-rCOVm@MuaKh)16+Z;$dbk&OH+&0K;Z4hV z*C9PVq48|i5MKoK=dcIxXH^BL51RsR= zc=famHFV^a18nJ#*4W= z)QfL}5iR4RP1mb0e_-EG{XAfHqC7(DBC?hExnc;p?d1??etS|>Fe+Xf%LleMCK41RnU>yK~0 zo3<|YGrkh8x`(yJm)*;~Kt{$axi4GHLvGq#@Jdubdk@_CFYFn-7dr0ezT?C2lLweT z^%bFPaXTty4l(%jgRBqj1rPB~Lw@S(;Q1(k_ra|nW^d!oa31pE9Z=ts&F_e~7tn^n zcsqRKaX!oN{$Bb~6d!`-2-l_6Jk5Q0hW()Dy5LVJh%b4T&m-i-x5JN-8DIKbwzwYY za~TIdiv+$Oe*Smf1B^NHe74x8pY@@=7`CBed>34W{P+ayd4cyoKL5pRapFr{7rqm2 z{xbIz-vb|gh4&Rc1-Ff|4*1CHtUpTP^((W*sVIea!3$9o?}Im?I6er&D29({L{CU`d-K*RVExZS(F-|%+$cNE0O z;UVv_R`^P|5P9)VcpmcMTjBM{kMDqYAqTz-9{WCX#ka%z(I~zTeu&2K`Z)U(jcm%A z!*0}zkHP#8cvs+^@P0IkkHE|i*@yUiI2R4!JKzq(tmkGtBQX3i$K&;%@VS=YJ%I0q z5v0TS!!J=DKJ*#;4eZ~6$Uj{EjetZY~2-V?7;WkO09lQ}9iDGygT#l0X zcK9la<5Tdoui3YF53K)&{e$m=&x~^3NqiQ6#~l8_I^+AHFU9p5c%Q)KKkyF0cf)gk zVnf6Yt&* zk4)4I!5>gN-cXn$_Cdw?7Wfour#=Z+?T{lZo3n>^WQ?71L>}#>MLFVe)Qum4dAsI_ zUVH&uu^XOobi3z>f9{dP&-7gTo;l*gy_hH716QFjyrm>Z?7epmzoX{;36p39pV)`% z-8V;g7^eg_pnPqfrW|3`#IaU*J?f@?7(TRL4u8kMu`n=|b;cL&pCjg=4tx-XQ88;9 zfls3nd=$QhOn7f;j(7)|@uRTxfE+QnEzdO!qA`33?tCEgEMWf7i-u_T!^~+pLQI|_ zs^L?pi<%fb*vx&xSHee-4Dfb8Yxxc)5jh;d@}&bk-2x zegyXyCGj!%50t`-898DZ5?k?^Ql2ADL-}|oydM?eBXE}N8r}8*k|}M_&Dmt55dwSb3_7P0mG;pKL{6D*+2L;_yLOJQ_yx)j;LS` zA^17c)1G%U&kzc-R!%5R=9;%=@6BUOR7Sn!v>fp&^5wG!V3(aaY{TBJ%@GUcb6$KH zp16SfMU4mUSI1t(+u_{{bA*!`^CF%p2m6rmo$&NVo)g+fnpmGR8Iw8KU<0z^U9hW} z^`SlmZ#{?W!uOxczB-S4&9Mf!)A`hCbB4!V$h~9E`iq!PD|?tZ=q~1cf-H<#1a+6P z=Q*|oUW?ou8-V@39MOW$zl=5iGxu6+hgEGn7aZ$@BUiA7jA^|xM>Jl`nlMhdo#zGF zsL8u7M;w5P*oPLl6qVzHFzfmpF-m? zh&tMJ5AuAYAjeu^#v?pCoY(Ydj#wOKy*O_#JmN8)BYYja73mmf0M2_nN4VHaqj0Au zSSzl#1fGQ|@KN|wFKb18>67eh(`@m!)pt}z6^N2U1E_jAOo zIQN%&`v*DVQdGtL^}}aA%;CS0!@m6}M>L}zd>i}_#qlY4^f3DzZ-)y%=2^gZ!A(D5 z?eInLbd=9~wF9n1h4|4=bHrx}-Yxjz&v-9=o+Bdo0eJrxTq8aKM@N`H-uz{bxCYtr zUGPg(gcqxsKPtgj!CO%&J_IwqVlUwf;Br)V16P$~ZcsslsrSST% zbHpwvGKGBt??e6g0l42c>;ZfQ)P2i1_)^&Z9ru1a>c8im{R4XdKLEo&@m%9e$8yAt zKeGok|F0ZzJkoJ&6?_Zj;Zty)$Q5S12OgS{%fGSWJp=o)a)lLNt;-e1=jMt!e4aj6 zq&CUrzx%`YgiUkB+j+VC|8O|(=DFgaEpkOa=d!~mCgqAwe3>Cv%tameYPji^xgv%) z!?~zMtA|&iR(uEi2(@W7f65i}P&>XA-iGoEc}Cz$REQsfKW)XFsHx7+6_27K+M{sW zt#d_^b}M`VnM!!C!ppbG6-ImyJYd^gzF)8=@Lg1l7X`Uu1uDP~z!N63K6p3$4wX#h zUQfvtk03#N9M*1^D-8HnxJe;%pr!=Af>L|2&hXsrbA_IoAbb~v_GLbBj~#M_4R3}^ zk-@|`@M+|wJqkD9F;~R#h45r##5+^zU>|btMm_t+^{=(cB%!Pih8eiSa>nKj3Ez@2ts&GF^%1vJV!kH9mFa>W?F9X`J+ z_mP_X-I&+z>D`u_WLwn`&|1siuEXfs<_Q@5!)cD{s6Z6E6!oN*r4e_P> z=Zc&I*oXKQ_&##tQ*hydT(4FSZ<>}Xx>(yjxY(R4JbUwQgp~)ehWoId&~h*}w7cLw zhj6cHx5FLExWBYV;5mopG8euN!$pU2kF;^%oWt2a+Bk5!g|TRl!nWz$1KN9`=ZIVp zro9U;oWYp12jJXt=1+SHhGw$=X^+FeEcOpR1s^_=j30)#S#w218y{YA6z8J77cM`V zHKkpDOs;qa1!+&hdn>rtw8vokv7C$cKIlCzS5(n%IG+23x@b?q2W`0`N_!mMd;(+A zJ^(L0k^Mn?!R%b|Ix5EVA43z5qXcW4fSq&L!?X`V|6I;XyZNMC@eMN3?x@NYJD<#R zM|%KPp2B{neE|AS<-FQBa78uG7wu7a`8?Ky_Aqpx#@@wuLVFF@h)=?M?d*B#WAK_< z_6h9~*fO6rq`ezD7O-x#>+4t_6w=lQ-doT3+Oe>GA#0+o5A-hL7}^bvT=60bYwH6a zYG8cY~~KxK@R-@^M41sEp|FFKcdL47wo=sd>9SHsUx1fO?)uDB5y7^fE=<>g($ zI8OKjN-$301-arLR6zXzbX~|=;X9z^BGwb{goak`3*(f*I4WhFyo-K(0d7U zroJ0ayOj3^_pTa#i5&QRU#_?eRpGnf4wtdF@!odU=Q`eNymQLo|HIz>hi5rA{^Nf| z>DmvBib@D!ZlRQfqO>xa^ovSGKQ=9`HfyCQmWrg96hktEBovFKWc|QUjH0?FNhOTJ zP$~O9uDaZ}_kF)V|9!vT%3m)>wKN(HQkwXR_XKPhg3howU)or z)3dSqgEhnH?D7n3BD+!h4DTgxr~1jBKk|9T{KMyhTt|xIY?g;UHg#U|e6qY(8#$1C$H|iSQP=aiP%b9b z`>vEt$`ES2BSc2AkZym>Xl1GI6>>Mwd$yku?ICvm=e zd4Xq&bE*BZYxj!v<6Jh%%N9DOb4hu%X4pm}$4Pq4vySy%yHSoUG0)C%j=X%4wd->> zPu6+e`8sAB`6U~pV_sY{yhKZDW4*j}NlpLWt>==w><#z7bIg&omfFWPZ6&`TxE7H& zttHl*tF`jiW$u0Fo4?$>|CV_$o>lUTcbtpyq?gqUH^1k6jc1>{ceOb+p5`Ca3>THV zXN+fwY`wYMg0Ck=O_=4MEnj%pOx~HxJanl=>oy1J2& zVm!(9B4PP)kq|MS%m$8eLL?L!Pr-?i@asvDP+&X-CrA9bTqLYFo_X@<)* z83{d&r%mHXXm(B{OfjBaa`m~!Y&;X1MM9?*_A#Dtek5$ZAmYD=;MsLyBn)UB3A>G_ z`^6Ezzt7mrXUj{>0j1unL7PYzN}gj@ZyO0$Q`c)#QX*js&5gNnhe&vj>eldt%OYVv z1;*1LH4PT`rIK8P|G{-!R>HB3DGhEV3MPrEJ~NF+Cgm$YZaJ_-{v84>JF% zNJ#Tup|d&f5(%r!PvfqU@O8IHSQ1?)-Ocwkkx%H=&h&AId1CqKK^xfoCP-j3JT z`5Mn|x$gQ%=wm#c`$fVz1B}yn=0r2y{2NbNMkJg$C=$|*r+Q{2yh}gh*(W16MnWUw zNs~tnF$UvFk#Sj(Fwb~e$<(3d-yBYnU51%AX6E?bQ-v99b%x#MTb;jcQ5{Y&JE*Nnsd zkrMkZ@=UgWx*YYo>tg?M`8zwzPh_z*Pon+X$RX@=eMiZs$g}@^*>QD6qY=yyyjormAj7Ssz8qX$TQi`pY!E| zA6pyNQn`F}jrD9TbzU0@KQqB=8+>BjQsDR%^2<*np|;iNa@l)>eVlu~ zO!%kgq~1g>rcmE3hkRzu>jm<-jjp}kM!rvHeV4poljoj3MQ;1Tb4E|wY@IVlUoSg+ zX+HJ3TO#2SN}Nkic^BRF>9UMI`g+;)D{E3umGdao%VdqM&Ry>;Ki+07>20=KV@zn~ zIVoRcjNbC=Na#gFJxiXo!mygoj z_Sy1H^7VPYM8Z4lvroDFjy|?m$|HX@S9)D}HWl`1DQB=%pC`}VZQS~FdCXp)Bl=AF zEu+q}wtu(Y$k)^5<7Ddd<#*)h`=Zu9cL%6sXl7skhh zS7@Y{%ACZw5YhL^qmS_3db+%w#`=8uEkRE{(*Eo={+aSkcGzAnH?vExkY^;>M{gtZ z3Fo_x@;jR7t&WQGbFXWmm&wD9HU>ReUd3jw&5;u**Qdyttk;X=CzR@2WhG^LQmwdf zF6q(Z%S`&{d2%`}^_j9o?YOW??;~5)i3|Ip`^aLNwDioB-?GH^O4;C;IDZCdY_c=O zdfj8=!rK(;p>CYtz3-apOJu!z=3j4EKQ27N7`;RudR$z{i*A>9lBE~PTN{{D?^`Sj zk9QsQ&GM6z%$>gWh}ggS<#C}YNqQ?en9cUdlaH}OpCdnEm%drX zU11IDwPjm^*QUu4)YbFlb2QY8<>w^pp<`SaOG9(JRi2dQUelY%dugnPE8{{Z()DyX zfi!)JoJVuLSni}xbpK9q;UZG>GKPYm^m6WcPx%|&^@i6P zBYApq@3_#8EIm!WLZ#!Zk`<)czFS_<$C|V~O*ZUnuJxX>ic&rKIgyqC(>w#%QWZhIsrE?mPt+q2~BB-&ms<8N|r8fRTu zNv7U7H!dtAU*92{47WD)6gioh`b@cn*?OgHpJ%T0KJw@ho{f4NIhwWlBpE-_-0F>G z9+lDUvf0hXruUP}sBN4Z@0e9y8k9>W$@0GW8NU{T9y$eU)r*tMThi zYL?pcUc2^W0^&PK2QFWjcr^iBcfH9oo?YbVIr0fc=_{XgjOTrpUFv=3nS&QR>um2VPkzbx^+MTo zzH_%vzTCFJvr=#Ka$K1BinXn;mt%{K!~S#RdS>cd<=%xpTlLge{S3LtnDm_2{p`2c z+VB zvLd`|p-_mYH+g=gE&LxBpg| z^saN)Gv&nhtV8>(lI`C2J+JL2AE%LCeUwF%qx8C%8 zdC>-IM$eMP|8)QAk+Fl}4zqC&D3VHE1$I;tt_sn2- zbPRI*4s)ef|HiYOGQE%7#uPpBZJgf=ZEfqFU-nD;rkp%FOb)U z_|Q{Ns}>*D91)5W zz1JN19<%ke@~Fe(!)C{CDEpFW{|WLr@@;Q^M0^;?Y&}OVVv5(Ul0Q(__T94nk?~=r z?TzH^_=`%RP*yU}_Qa(4(1ZzkD_Q@j_)un_?(*EDeEj$wDK6E+HIQ0qgY3io=tdyVAP~Rcoest zCg`i=mF*l$&ym$qtW~|BeSA2zgZI^Y$~-FdLRt5+_^?lJDf39W(*E)js&_Jec|@vx zY%h}MUhaJL+46ms=uNJ0eOale%V{*!SISRG);G!@Xrfoj>#lUY^xg8~tKvgTeM;x} z@CwbnZ=WvKHQn{ZuHKil=yv%QDf%usu3LO)rO%PIySsK*8INqx%Q~~Y=e6Dw;q4sjTRpj`F@;tx4IN0zF;EjgAkE^yYE`t@J|K z<`&NieWvVvt7o{rMD8794jnUXY)mBObMy*%!5#6TL~k-aJ`AQzA0>a7;CZK~O^gqZ-DOU?8N(!N_-^CZ zD`eNnol5?rlm&gY9xG(fpvf31LX#YO)W=iyY`6zSrC2}35`eyk%^Y!Xe<3lqF z^)@n_B7KZ}kpg{*{Ej|);=S=<=ydnK9(mAb0cConOnS(<=&j@@RObdqxs?M&P9*r7mU)QxtA$=H0v%l4|>v)_;5KTjv38C zlht8T z^{%l#;dA%qCdbqp%bUn?z7u32qx2%#;|te1x?Q%}Y|MI&?Ea-|q!-9hTZ~y>DO-Q# z9Q8i3)>i9PZzK0npf}zYAMRn7ULx1fu!m=|JaoI~s-7s1`PzKxJ>}#I=WPGFKR72k z+g>E^`q8sj-}qB}_>K8`-JhKYrTP?kXr=M!4dr#e8IRs-xAUSz?$T+~ zw(48uD~BY6e0@hW4^0Tg(e3hs!xBP)KB;Cx$c-d~mHIq6A}+zdC*yNLCd4O%+Il1T zD9L(>?2?cW`q_V!{Os_A&_>TYA|doSG9m1+Poeyc^?FiLLTF0jwdO>|9hDIBY;Pq$ zW{#eGv@z692ov<`b?kdgLMYLT<$z<2!D~z9kh;d87s_MnCHQkepTF|e;}Swky=Q}j za1X8QQzTzwrXJ1S$0vmOdNlh`u9wR*Pe=$UdNi*($$9C~9LglU`^gER{wWEeQcsg7 zHZr%-?eZs*db{qYI`8C!u+R1#XC(N$hY6vP?epbZXC;JGeahJh;pB4?LUTP;UQeE$ zE?;4cUM5SLm!D>rIP?PNrMHpIE_6&iN5);`wR#iz0TF$-JhN3oXrT9$g>2U6$PZYr*KM5;x>2U5 z%f~6#=gY2_B!nq_J$q&KOI=^RZo7ogqCMY3;yYe}Cc-(iyd%jIbUtjXvx<$!_4 zrq7WpDA22?Cxmk-)?3N1SfVFpB!s~?xMq5}d^*!Q(Hjj;2#?)p-uiiN$dy^fV|&Y? z?rTzPFP3Xb(>KcGVF`YBh~vvC^wEp56GF!k=1p%f#u^ywdwQSzgz(h3gfL1kyu*4M zpWyu57jip2`&$DO5<&$Zkq@xm zJ~QP@l+R;WYm-o(bT)oY6 zo^6!qnQ{_^dV!oDrI*M~bB$TglhY~CXUdk(8^7L9eod(!ndiP|y}nAWdeIt4_l$ih zA>1|JbKdq!dGrGJk>0u3vxw&Q*(y(2Xb$z}at4`ti9G*R&{FZHj4DfQqO7{-r!j$Z=|I@Med@r-sVl`U25L-^kwd2lJyDlQQGK5vV7_FMEzj*i&RsrCh3&KDDyrMQURFlgzE2+awr7Fujbtm< z+MXh_DA1?K56Raz%YVFM9qO%QcQ)#MWJ;Omww^E7QWV|iUDxzI&xcH(U-I7fjcu^! zhHS9PvsZ5;e_!pr^|~KQCKykuyoEe{l3c`?==kOQa`WJrJ7kNGtN}e;E~LUft7M~( z-G{cfk~=BTi`ICq(AazJlgF=h?QKt%Hyw;cSX^*_XQk$Z^PUbw|`;45Rk(Rsty*HoAp(){`c-F`!tawm~Zwho?Jzp-PpZ8iT>+JLl zF}75>iBhl4+U5SBNS`my`O$jNd&Wk3&!532hV6{fcePCn zbuUfy@ALbeoU%9F@AZ2NWg#(mTo_%+ZI-0(O+u3lGU+cIofQugNR* zUY)!b6F%}@@>b@Q*9$Y`%S1l*JNM)^maO)B_GH{u=1?CkUu5kE^}?l{6T<-V*VPLP z<;Rr$vtHOBf2Hy`#)zlAbN6P^mv47t_b@pMOhk zA=B@rzqngs7(`FM_xmRK42gbs_xCcsyW@XvJ;<{erJpCe(n{|oM^dJbm5hh6o;ak3?)dM7!A+I}DJI5~?|erIppYZAkGjPW~2TghIu^m|A9$$Uy| zpCq5A-0voxC*P%^?LWwb9*JSL-*0)VEF|6UZ(J_FpeT6$_jG(_A6h>Qm(xhB;h%S8 z$6l^?#CF-}TIZs7mfKkyS3e~5c0W=aUq3XH-AL1W%UhYGkC$_paJXa2v-`LPdQW*5 zc}LVgkahbyM?F8)iC zCbg&^`pTOr(Z|X{D$lPUX351Qx2zwQ%g^ble94DIpq*&iB!vOQ#v3@vAp2+Si>W5S1B{c3-KeU(EQF*1G zXXHeR^{Mh1GWB`#ZN}JtmHdhleTS?z(AxI@gVdBK($D_~ajLwSe1GPjBKxw#_JMLX z^Ymi*K0W<8Qn~z^>3W4cEZueY=Rb+^6jJnL*`1mG{N#E$npXZy<91m{ranu)$Ebnz z!zZ#@hVl64sYE%1Lj4Z;A`Sd=M5)|Nn*QCO#Bfxm>zh?S)Q=`h^vh*7EA>%w7GY@p z@T}}N*mJ=4d*#$D>r+n~niz6P_OsBf@(CvCb7eXGymo`EBtP4q;mbP1e69cezrSbT z?-}@e2L7Ibzh~g@8Tfk!{+@xqXW;J{_v38_r`K&EK6efK`gh#vND!QUmiSe<5;G| z@|sxQ5X(`qoD|CkV_6)_(pavK<+ri?DVC8fvH6MR*|EGhmR)0cLo9P+nIFr0V_6u> zxv^Xo%dN587t7jT9elqgvAiOd17evU%W1Kk9m|qfeh|wovHT;J^|u~8?muFAVJy>P zd2KB7VmT?6vtwBt%lBfrDVDop`9~~I+jj7ME{tVrEU$~@jj9Nd@<*ZoFjb%wJ-;QN@EVswS` zpQBs5jUJwtF|_;Op&4z5cNmgR&r9`^@JaQqd0FlH z=j4sZ^?u%NR9@H^-IkV}J!C{qhY`aD<_*ps)_z!C?&uJ{ihk#s!MS-O`e$7|?B>D4 zyyL_}FCU(gF<``?K^eK7b2Ek;WGJn1^{~wT!_u=d(%X+3n2{4bgn>j)Cfr`5TSngh z@!S7AF#f#$-XiDnVK-#=@b~pDA09jF?A#6+{i7rO^L@re_r5YaeMDA9>VdcG5&S;5 zf1gpey#51+TuS%c{sS{YXj#pPWaPHXH4y{*XLZXsaB{(aiz6+g|HzF0+Pq}}^OUcN}$osFCoKXF$5qUWy@(#>Mx4hiJ!v+~sbMHGaJ3XUw_TU3o^v3A8)A|q3 zYoD8&ZB80Rzm8qugV!>IBM-Ih;1|*BH#~$_t98iD$VeMJAh&<+=pLCF!`k)F${OJ8 zx@MS^VfNS)+F1yB83$jMlbxLveQ9nO6`k|{+!(&E(WC$1ybjs9|M8ta4?8?O5ZYyB z5C5;jg}wjvKG7qEaLfOEp934G|K~9dY%TulxrBv({i^LSi)L_axFL-F_ce~LBLo(7kXXhMP#s?OE2qXT-_eKoQ z{L43o|MhzvvV8O4i&78XqbXK&Y)jkd8UN) z+J8ax-*@GIEWh@n!fDZ?w;!3|mI~kfd9}J(Q&|~T4Y<+jwa>EHwK%ZbfwR7^Mz^et zjGQpFMz_I(hV{=nxT|SBF!K%nveshvRd~2Yx0?s&4b1GGeQ+s+@XPuMJ3sm`@K}sKNkZ8F=jfuV+hcRYfk#|!xFxjn*co*2 ztG{eNA$GSOxEubm{ekE^bs90Wf9l{tnHj_LI=M%EIUxF+TJ-0YbQRm)aKm5^&(T-* zA3h|6^ncIA|MaSNSyz7~m`jt zR!0Bf8Qn65_Rq=8&h^atA$G3++H~L=zxN+Uvk=1EY6q5TY|47LMj4lmxZ#G3T&wWp z|Gw(kxv^6{J$ePMv0L;(@3z@cBld`oUB@r}{MwQ8EV|&o0~_1pz!gl3&PVKB|Hp)c zegAcxLipy-b$sQBth~WFf3D==(KA>c+yB5?cCUQ<=f3}ACO1W&@SO*C&yGG1qMu?e zS7!CD{Ra=v_}8aR2wS3i9sH1T=pp~-`^=5eEobns1IsVWs?j|ocj(|@u1V~SLKsvn z`aJsc%lzm}{`E8G!1cKLPy@+1Fdd=GfqroEdLHOqGY)=r?SZel`2-H3$ANy}Gyi|A z?K7jtPx1a1ko9gBjyZUT4E^_(S)pC_(479c8UOl(DLFK)-Ie`w{`K{+=uy(L-9Z@# zKSuqY)ys#w_XejQ+!{`Z9`)+s8M!GLH}rQY(%M~~5<(xJR3nBS`~l+Nj>C;$WAtd< z^3r1utqn41{~wsrEOMf4>-!n8j} z(k}Xu*ndz)SX|BV+P3Q){DxTVs`gh#`+L!??K(%tAHF!yvxoY@$P<28MqB?)?C5v@ zy`@L^_0R)L>eA6Z0JD1xPS5Z#$PGsw_Gj&${jcwbw$b-#KWyaS-0WdPJzoz_T=ZOD zIq+HZzkRDwbe;d@8`t#D9o&CF^o*89j}}`X(RJXHxVnA)Ks7u&E2CXrZq~t>%k^LE zK5&mlC*oiC=BbArxL2dwLR|DnvDY2^Ng_HEHU6^I(zAMcN5}G)D{@VAkLVGii_3a% z7X5zo>)4MR(Yx!*=spKew7cu(Tt|D}^iMzV#$n`v9(!xw`yh5NM!(x5G&(rOe|@`S z`>vhZr!_nG?DVXx5H7JE9lNb1nHQbS=;1@S`ry`sA3t7s;D^g#LSiq=`O7`ot!od< zZAd8j*AwvI1~;^i-@zjtF0>tZ(}=;={C|FD&|i+@ZPNX4mp$yyixYnK3>gyr+4euS z|8!ux`|`iP1UVzGqmW+kgEG?}>2Jh>T$aM~5bVUXj1t?U#=J z^NxDTy7=>R^XX_eod-WDpNW3uVjlczcJ!+QkC}`EXML4_PG~&-kyO&Z4__{c|<_FJq0aq@QE&(rxt60ogvm z+>t|igqNxvd}Lke6VqMoC$dld?Bfx1V7x=4$2|B*i5}HqzWnzS`hWWeufMnbJp+Hw z!2hi?P_0c>RkhAlRegKOepOY;8T#O=s){UM=TucK%C&7oRaNhsZ694#)#6s)8&g#^ z;WppTuc{g}&OUckRqYvXzll{+n8E9OPPJF7s!k=9A>7LX*6<6*zE)Lr0lgW+EZ$@@p~PI%mI2(s6D;FP z!XjhhV)`71R3@g~oe(EoFedtOy_wX#s*~DJzEUBt$LPrKM zj+wm1M^tdw8?F}@aW%u3#FH%M6MmrPQu}cMT^YgzX0njgY-2yiyjfLsHtp%l2&OQb z#jN35s+Cq%)#V&I(3jy%rij;A%~$LtX<1d(X|$pXgBZ&L%wZ{O*uj2kEq9G+O;>K< zRtlKSB3847UrAWu+R%*4=uI}`d5F0zkD zA(;zF<9cplJTrKf*IC8q?4;V;&WTfLK`Ol%!Wi!5aTc(gHEiV<4tvMCC7BDjg5G2? zhN;ZrMc(8?HnWRRR#kNrC()F)bYTFw+`;`k!2*`?5nr;4@UCmeiJZg5bfPa=jNu+0 z;W-vj#yYn13)SCq?wm|hE};{B$>J97rjTb?$O=AYGdtN&!u#$Wl4(H-UFkaG0TucW#aW#F(Ad5W4FrIsO zfJb#Vlqy?^4b>HnEKger7LWqt6G9pbiZxf`H1y=!8R)RnLUKh-8URgE$Y*d(>a^wTtr(^>BQCarazesV+6Ny z2a~vu89d69%;6;#vY6$R@d2Ok8DFx4AE@Mas%te(&!Jy<=8?oPG~i^CIh$r& zz$LV&BVFi0Uj{OmY({V^`iE8rHLk zulRYhUG`i4(J`7+GL&;?nW4VJ#OyvOzd5ou+ z!wbAZ2}@Z)86U8Q^=#rRcJMtvvzz@Ky2Ue^!>L7Gj^|{OIg4{SpVnN;Wu(!S9`vC< zH;~0mjO14GnaDj9FoQ>UoY~CfC5lT@EEID@lk#`(0OEgk5{RdlBp*D-)WWN{NCxrN)A zz}-w`8V~U(MLf-1UgQ-@Si&;i=6yb7EgSfpEqu*)?BW;p@CS!(b6zBpL>=mL0;iBn zW14av7jg;hNF|LfT*I|o&pX7C8Jc#3D4#{w4eI!jr>JFKFd zwQS&Xwy>S=*hwY3*-y3YKC_7D2x@UG4QR-zoWWU~OA9XI5>iMdjV@eGFRo(%gBU_K zd5mHVoy50Sj5g8!YE--s3~ou#SyvW-B}Ro*(&zz5Kx;UprS4 zIFec%O9L9xh-4bml=HZN)?7*luAmcL=|OL?7>(^BZv-&Qa8%9>;SMr*Z~o(UkMJ zfY!97J(qJOUAUTF^ko1ya3jOWWhA$78+ULglew4snZd(6#uGfvbG*O;7P5#pSjJnt z%W6L26E^TUU$TuIRIrOmcC(N0jq@i$B1zQZSdQaFPT_RUUmcJi}aGU_QmX#_KF)87nE{eLmnLK4Cqd@daDh z#y3>3lb`vOJ?tZV?`H=NBc8)aq87(epW|srBTnZZoJ~`jb3PYwF>Og9m5y|x3s=*V z-dsn2GRR~I!^mX>qqvpZxPysI;vVi}8Z#*5Q6A?>o@Nfu^Aaz!kP;TNl;yld8SnD} zAM*+8`HW3`$u@TI9Y63RmHfu<{6V!JtT$>B&*2aaE+>tv=*rdfq&L?yfDAGj!Z2TNCy81dLp>UB zA}4by$(+gAG^H6WxPVq%!lkq)m5y|x3*G6#we+PQ1G$00WRXoSBN)Z4+{QR2a2Izo zh5MMs3<`OaSv-mgLe92b6=3BmJ7eDh0 zyZN0zsJ6>Gr6%zl&XF8V9qMu%CvXytIE^!C%sHIPd9>t0TGNJhbl`H*=tLK~(}Qd2 z%k>N(gG`1nj2wnDlF^LecE&M*yO_*W3Yf+W3VD=S6!8?#@Er4akp&d<8n3g2H(AbG zl<^*`DQ69zvYyY_#Fu=rY$L4#^t1O6S+{ z#n1f0ZhmJ!;U~`zY7ilT!%3nRb*M{yj;A3fb1KRFgR?k?b2*RmxscXe!lk5e8CQ_T zRdl60J?KRruBSig+`wS67{*NuXC$M!mD|W?JQJD3Jxry5Y0RLIM|h0Kd6L;Y%UtI1 z5(_BiRTi;?r7U9wZ&Swmtfrhbe8PJE$>)5*7Pj&=-%`O&ex#CL*~9PrLHOCVpau~V zIGiMorVhtap9Y-BNi^a#&frYWrU}hBkCt3WYcAnZQn-xENuv{8=*Bhlq&I!(#{e=I z#EoQ;%}wMnlF{7CZR9haiA-WLQ@M|6Oy?mU=22!*#8W)Y9Om)@FYz+Pyv8CHvy@U+ z@D^pf$7(+0W7hI18~BV(Z00Mr@ipI4!A^dpl3&@w@9Za3dPY%$n#7UF5gbJ=j-f8~ zIi3?anMRz(8Jx-4G@%*iaXuH)ic4rqJ35d`N3P^5y3(B<^rAP{(T@RSFo+w;Vi-3u zoRN&;7RGWrB#Ufr zVmKoi#Vw5CcE&NDJDJ2}rf?tk^8hm_Se zIvh)V8gK#)Ihj*AoijL-vuMJ(G^Yg@a1pJ!gtny6fmE&_jjQNFH?F1!z39Vr^kV?& z3}P@t7)my|}4N+5PtI< zr8s?zFbd#29m)bZX}Cgi*V*?x6#AddzmF?`{ zTPpa0UHn8Pzp|UX?Bfr@Zr7UX97Y@o9L|v(MJ?)ZEcG~!<2jL&IE7O=oijL-vp9#Q zG~+zZ=K?OGHJ8wqcC_a*E~g_`aur?Z#?|zo7rp6AKL(J_4P1I*wd9_CRV<8hwgDW2w8p5u95;3XFD3JZCSMJ(nG-eego zc#C&9l_f-m`sZER-;-%`O3?BXXX`IX)5WgmYK_PG93=P)9~ zlgJSyaWu84!?D!kIF9E;PT~|!<#f*AOwQsQn$nEsw4fyy(u#{|!=(iJ}r4ruU{;V#C;D z0i%cpQHdOYWzx%bZeX70T+H~f6gpKZ)8EAM{S`p)-d?FHP;J!Enp z53q%2AB8n-coJt;MF^};CPx3U+u!I_3;3Zz6me+ZcrM$)4EN2DpvyxSO#A+H? z!)JU!BVY3^-|;=`SkI6A%tkixE1QYBO$=PG_Roi>~ZL4BhEL zPkM0x2hp3p^rJtAayaoE$v_5kG($L+;~B;Y4Cf?HA&JvDlM$TFIgH|bE@U)gxR`OI za48d*#AGgKD$}`wSzO80TuU0Wxsf@{wUS9y)sd6Q+-@ec2@g7;a;Dn4R04XoiazTiu~;v2r> zdz$!x4g5qi8`;EfY$0NkdSP4I5y|#+pd&leiCx%@J&0y6y0ACh*q83~V1Hsckb~$= zU;5FXLphvyj^ro?aWq3XhT|AYA}2DOlR1^sIGr;Y!AQJW#V+j1?sO)az39q5bYoxkqX+vF%Yht3 zZ~78Pe-7m^j$i;sF_6I|Foa_{o}naiBEvbEQ#p;(Ig=5b%{h$XJT4%a(Trg%myp7x zOkg6Dxtu9XV+L0+i>tVrYf0mJZeR{KkcDyiZT9_2Bf;7Ok18J6%I&+{TL@d~xP#v3eU8FjqPa#rvj^?bl8KH_5q>4va%ws%3HBa$0&$5IXUf@Mu<`rsroi|v@GU|AT z<*eX6>RHJuK4LWue8Q)E&KETD72ohJYiVK~>)F6h{LDr+@hh9z!d9F0H@2l6?b)6k z*pZIxOec0>H+H8p(daye6(#tg1t7FTjL z*Ki%zGn*Tk!(7t2g?Ze@?PPEV3%Hwm$mCw`=K&V+5ZUCAM?QrVQ9>!@R8qwwEaovD zrzU1s%waC++{`>~<#y(C z2X}H8ce9X8?&E$QWD!|plS3Z)6jDS9rIb@a6%VtRM|q4VsOBl2=2@0d!}GkzOT5CX z)bcuSu#{!g@ixnOm-l#|dOlzkAF-MSKH*b7!=<2GzNC?_`G)UUOB3r@&jx0^6WO z*b*_~Dz4^Qt|N`v+`t@eVlFpx3%7C`^U2^27H}8$u#imd<9;4w5f70~4teBLKoP~1 zQbswIRPhLld6dU_f+u;3r+Jno)bKnn@DeZcDz&`E8@$Of-lC3oSk4OG<9$~00jv0k z)im%4Yxs=M`I1Jy;v2qYE#K3`53FYcKk+jg`GrmV#%3b6@()|HE!)wKNVcZ~JJOMz ziJ}v`vKxEQnP~Q+3ticVZtP2U_M<2J(~AQ*kb~(>AL8goe-7m^jv$@^9K}EeaWn}G z;aHAiD8oqPM22$`r*JAsoX#1X#R$&k9L{AF=W_uUGMbCHn6Zo_h4Ea<1ST?xR4!)< z)0oZ`%w!f_7*0WG8keie1>1-PoPZM6)Md=*r%7BZht1j~?`-7qJ|`K^#nP`VdDy`g16U zaX9e|;7A5Ch`}T%koETM+yd4ZRB znOAs~*La;bc#~zkMIG<3oOfBl`_!|NReZ=ttfqlaSi`4$&KG>iSA5Mke9KzCr-^l} zX9GX-GtF$|7k=e8HnWATw(-7T8@8n#?TKUuIsZeQe&i>b*~l+!;#W4ag_Z+? zt=O7v*^YL!Cz2iLz>aieXQJrDF6_$g>_KOu*^@4GWpDPO8~f6o{pdkYdJ)S39LT}+ zrVo9Iqd$jmD2H)4@eJTdj$$B#Ihq89a16(BJVO~qA}2DOlQ@}ENa8e3=M2td1ZOjn zb2yh#oX-VZNHU`t!^Mnc9G5VjOSy~*Ok^^tT+S4xGMyP*!AxdxC0BC|*K!?c%;pAe zWDYlx&duDyJZ|MS=99r4+{ps&<{lQ3$-Ugi13btg9wLhza>*l~0tzXngi^{Vr;;ij z<`EY2D39|5)jY{lJk7H#;W=t}o)>wEmwAO(spWOv;7yjYjJJ53cUaE5tl&NBS;+^i z;zK^-V;cB`HGIlve8HDA@)ck64d1br?`dKkKd^xx`H7!tW+R*UmEYLR79zIu-eMcJ zWjor@p6%Iz4(v!rc4B8bu?xGh8@say(d@}ybfGJI(~TJRr91o4gP!yvmIFADgE*Kz z^d*jd^yd%`<#3K5o&g-mQ4C@*N0Y!1j^S92XDGu+qz5z zW^)5`xQV%>b2GOvk6XE&`DAbhcd~%HxQB&gaxeFBKM(LA50OPSIpmT@J_Qs}ObMlw zQBDO_Jj^33=20Hwah~8wp5keq;aQgO95uYai@e0kyuz#0@)~dOCQDhyTh#G3@35Q| zyvO_0vyu;3#fPlsV;cB`HGIlve9o6N@)ck64d3z|Yx$ma{J?rP@FPF*GtF#d6Tk8s zo7qA{J98XcvklwPj`l>dJv-2W9qGuzy0SO>(2W@OWj}h* zll|#MEC+BP2XQcc=t~^^=+7Y>%3&N%JOenAqZr5_26HqC4B=Rg<9LQLj6_c0M22$` zr*JAsoW|*#!I_-J2+n3C=Q4`(IG+o+kYq-45n~w3I4&WD@m$JfOkg6Dn9Su&VJg#@ z&J3<#CbPJbtGI@1xsEihXErx*BXhWkx!lYx%;Q#W<96ng!5!Sm0`B4-7Lv)m+{gVq zz=JH}A+pFOmpt+*ppYVpDWQ}y%Bi4=hk1m>Jj!D{&J$GgBv0`)&#;8&sNs2D;6+~I zWnSS`YI%*L| zmhV{0_cXDNA6U-@e&i>9W+T6_iC_7R&1@l}z4t0xvklv_9qnjOBs`WA$ z*o9r$josOU&P1~(UFgc*>_azV*q83?M-O_kKfQ?M01o6Jdeeu##LEav2kt$Rs9{%H>R9D$|(G46a}%v$&G0xSDIYmg~5l+1$X5 z%;6^HlFrTC!aQ!}Hg0D=8Qj60EZ{Eg<{lQ3$-Ugq13btg9wLiua>yl*d_7*0q$4}AGf{M67j|Vgc4rSd6V0CN zMHjlVH~Y|y81|(*`_Y4*>`yOZIe-H>h=b`(ANmqUKl*bBhjJK)a|H1W;7E>QAcGjp z(Iha0V>p)MIG&*lBast0k>Q-g$(+KeByk$2a|UN}79%*Dk(|T1jN&}b=R%Sh%|(pi zV#YF#OGsfnmvR{sn8+k1lgi~xVJg#@&J3<#CbPJbtGJqLxR&ck<9cRu12-~uxPv=cz+K$UJuD=Xd%2JMd4LC5#6x6}O%A!_kxv1I6j4kGrIb-l z1(j6sFpsd9M|q6Ld4g)5`Qm{qX#|NpI*dr00(jq2h*EA^d*jd^yiS^PQ zAcGjp(Iha0V>p)MIG&*lBast0k>Q-g$(+KeL6SU;(>a4PIg1gT%}CDSTt;yo=W_uU zlFVo>Vhk5EmT_D{N-$nt%4JMoB9oX*Dwi{bsZ3)!Gq{48%;HL};%ctpTCNMyGiDdg=2ibug>Bvs( zOcb5ig~xNB9;R@+qgZLFEhA4@4=fM~9OB(r#ula^=`Hr>0_p*s~{J?rP@FPF*bI>d|@(Y{zmEYLRmLQ^o z{=(L5!?tWkJK7T&Y%h1913S`@o!FVEpp)E%UD=J@*@MnRvuCiE>_S)eW*@o{!@fax zxgR~~$^P^rmIHzV$ZNTdG_GehHv~7zIo!lt z(z%&if_d^*ZsT_5lffOqopJ$paX0s{kj&s-c^~)l01vW=hk`7bO%A!_kxxNTD2phj zgi^{V4=Q9ORXofiEDj!(kMTH9P|cG(6+A7U;aQgO95p;2ydYoXC0^zgUJYvHYrM`I zyvfpFnS6^n-sT;a^KP(0zQ_C2vyu;jRq{hVVl^Mr5PTxn@F}11IbZN)&?vv+Yrf%I zz6;jM?`dKkKd?U7Ab;d1ex{j?!7p+Xzw#TK*%Gu|gu4}6vklv_UC>UpCz9>ifeyir zvLidOGf{L3c9FZX8@sayor7q(CwtL_uIwG`BfAm9zI125poi?q{`4Z21A+tPK^#nP z`UHJt9R29eAsiYUCJ*Nb;u*k^!BKJ`gBZ-wL4q8@F&xWr93Kpo!${-=P7H?2lQ@}E zIF+Q}G&Z}E96XOaV1v;SIcX-mg`6hu9vg9fg70<+$86c&duDyyx>-O8@Dr` zjNlG=CkwcXyMue=LNd9R`-1!B13btg9tyH#HaX;y7v#$V3MryED3PU_>=AU9(d@}ybP2l3z1fFuL5$p&?(9d8pr_oQUc?3m$OAcugXtagk$s7y zU(jD3!l4`%94?O_o&g*g93=-bh{3_pGJzo+6C5j#<9LQLEJ&0ma3aHlljO;q!l^-$ zJdM*igEND(7?F=K;q@)A-QA6zOgV*(R{Npdo& zTpmo3Q<=u}V1~Scnam2Vlvi;z*96zf>qz5zW(POO8=1pR!CaZn&D;{qlecmkw+HiO z26u30ut46$-P{u_l$qSieZl?m0Ul&g@Q}ObiEqGnN!J8}%mdUrM ztzhf=m z2TgJvKd?U7Ab;ei;Ah#)Mt%u4$zS=6&A}Gg@{3bj1zXE)*p}^rcCtN@Y#;0(JFsKW zQSQXfLXsOZkO}P2=0(~vVgmSyX8GB3^L`t+!x$0AK<}Yk$i|OvV$C%OJ0yK3n&bV zWHBW{sVt+Mil9IqwE5r_eoO+?lQ}DBFW@GS++{CZJZ*ntRf{2~XWCwN(I?A2cIf#;-*d^Fi?#AxH9&t_zBjy#u9!Flq0 zE(k7^$&3yzl4H0y7%RtdNsuDPb7^pyoDfWulb9T&%FCG&OqJ7^9?XzeFf*7XuMDn| zS948pt-Ox3;CeZm8-g3<9BvBc%Jkr7c?pT4IYz^^F&ZB zpX90FY55G#2212~L5+N#7lIe%OS~MsB3}(^c zazpT={E44~X1S4Hf=%+*;5WIMErAtk+n=@(Xd8jH5ojBMwh?F>fwmE78-cbFXd8jH z5ojBMwh?F>fwmE78-cbFXd8jH5ojBMwh?F>fwmE78-cbFXd8k5Pe!0|*Vb)&|9mz7 zc)O`#^3$I2)g{XK&bHW53OAsj+aI`Nwg#=c?&H&t&JaUGX4hO-z#Z}wz6*4T(_6-#-J zhsot`<}! zPGcCuZH{&vgE*YN^rQ=&XwM-v+eI8qPxhfRQEboFZ1Uf<{b?J4|5_ukRqJOt_&kTS zzkgm^Mc76;BJQ93`|a&xndob&4|i|f2mbHBukF@9j=;d9XHJ|DGh^(OspBV48q}*_ zpSWHzV<(N7eDU~6mkjE4)|o?l$M=evI&Ji%i$_nGJZbEpUbDtd?RE6vjynt-J$35X zi5E?n72^&jO&!#0`jkmWP92jncH-!%y(f+zGiCDB$>XN=9y593k)x+h>@%ZZub7FW zCygIBcIvbde|b()ub(%2beC&Wx>`QJgkMo&Fq(u~QM zjh)gfX8QOcW5$e~>a~pgVBbH+&5eKj zVYJkr-+0ogtIq^A(IU{q@^E2~{@~iV3i<*lgOQK6NE2}DND(fmE z{8DDiXWbNKRcF;^)n_$kHD^V(d|!5Ec2;&#c2#zDc1?DDc4KyPc5O~wPE$^EPDE~0 zZgg%;Zd`7BZbEKKZffq#+^pQ9+^XD~+}hl_+=kr7+@@UHZskSg#pK22#pNaBCFUjN zCFiB&rRI6ChRzZ7KHH+P_1+>|@9p<{scyZ8`qq1BZoP--zq^N#t@ki9FFh|KFEg(w zuPU!PuQsnPuOY87uPLuN&o*EAQTeg?aryE23HgcnN%WUhQ8jG5WYz=jDrqjU^;l_iX-sKsX=QtURhbraZPht~{YUu{^0fxjdyjwLGmny*#5ltGuYZs=TJWw!E&q zp}euYsXU@0vLdP?rXsc?t|Fl#u_CErWJPjCN<~^ldPPP>W<^#-QAJfnZAD#0eMMtM zQ$=${L}g@URAp>sTxEP^LS>f*8!vy-w%W+!K-WT$4QXJ>>8 ztj(^=Zcv3y>d?k+IZ-*$IWal0IdM4|Ihi?GIYl{DIn_BeIkjrEKBpn4rRw5C-Hi;D z_j}c3wbo5b)ztrQ)lE}=bACiYWId_h7%VnI^D$b#g8l!DZPnFVPD zMFmv_)de*LwFPwr^#u(D%>@yKk%du((S4U0 z!PTLL>q8Yc|D}%qWd#=%R~1(m*RqC8JR%TTe=|0u^PiwTJ!lx=GR%lXFsXQgdeJq~)ZCI%>#i3_UI~bh%hPE-^PLcVupI z=yhqi>7n0MxAv=s)_(VUzlzF>ZtYkJtsU==%A1*&7J61z=vp02#btEFePbgY(s)zYn6dR0rOO46lLb*T&;s;Z(! ze`?U3B6Ox0ohdHIGKuCv*QDX_ZQ?mL>)0whVR*kOI zptd4(q!`^OK{ra)iPChUEWN0vwGTDvK~efoTuwqxk}677K^eMGl@3&=`!u!Aku5W1 zg33uYL#E|ss2Ou#OmxJV;%|K{rnQU3x8Bnq75TS%topO7{jD;S^s`hI^?NP3vpDaa zme4y>!gH+uyKWgBdS%O_BzndvYW|OkFUt8_Mg40XExjNj!BM1nJ1gt=_h8LmdiY=8 zjV)vH$1C~kd#mVgJvz5OtP=kIUGpz{_W$giQ~wXWyX74e_wShX|M@%VUw_?2rB$sn zaYWMZ;~Z^njW@H7G_TGyt7e*0tIeqO=F{f#$ckulX}p>qXskIj(fpZW{!BM_{>yb* zyr23=KlhnBUZxdWb#`r7uSJ?8|5*S1{u9qMPga{F>vg&2oJgyQbF$SAKS_NKR3}4u`Qnw_n*?ss?2?L z-o;JU=~3pqIIFEcI#Y(;RFzlLx-xGv$3?ZiI}@zOldZ+mti!Xc!E4NE4d$~5YpEFP zs03@MWb3CiGg+2-tj5}@!3-8*-4tWZlwjscwq8oJR?4zYssBU>%{k!{g)&Hf}_P_T0BdVe!j`O_#_upH-xh^{5M$xj? z`+cR?)Oy4c{gK41RtM@J zqD$L4@!vca|8KB9h-#~Ywtk==#I)5xTOFu_xVAcIs{?hA&{hX+b)XKC+UlUK4%9(% zmxxB^8zTM-ox5wfrr>X9?qc$r3!wKKAj;VPsmXJCK7#v=aDtG|++$xdxO zm!08k_TR4WX{?M$?b3Q)CD|1ev96a$&53s9px2$&C8CFjbCpMibLY+Fajxh{b0tSZ zMYL--(wq;E$mr5~ZDN$`GiqGzljs_ZhU_@kF4VZbBHlUcOy{bbbCaBVuE~#aez~q7 z#<{^-&o#-lDh)-k&I@N1Hx(y2=g?FV?+TRK(x|dTSI*Uz#kjhpt~|z7Bvq~&N${*& z&%I}LiJ0kmCAcD_#+8ss&Z)ONW|p%;@y?Og<;FM{p5 zP@ i.Trim()] let filenames = args.GetResult(Filenames, defaultValue=[]) |> List.toArray diff --git a/tests/commands.txt b/tests/commands.txt index c4b1c825..db549dc4 100644 --- a/tests/commands.txt +++ b/tests/commands.txt @@ -60,7 +60,7 @@ --format c-variables -o tests/real/heart.frag.expected tests/real/heart.frag # Other - real files, to get a bit more coverage ---no-renaming --format indented --no-renaming-list mainImage -o tests/real/ed-209.frag.expected tests/real/ed-209.frag +--no-renaming --format indented -o tests/real/ed-209.frag.expected tests/real/ed-209.frag --no-renaming --format indented -o tests/real/ohanami.frag.expected tests/real/ohanami.frag --no-renaming --format indented -o tests/real/terrarium.frag.expected tests/real/terrarium.frag --no-renaming --format indented -o tests/real/monjori.frag.expected tests/real/monjori.frag diff --git a/tests/compression_results.log b/tests/compression_results.log new file mode 100644 index 00000000..482994f2 --- /dev/null +++ b/tests/compression_results.log @@ -0,0 +1,14 @@ +from-the-seas-to-the-stars.frag 32480 => 2797.928 +the_real_party_is_in_your_pocket.frag 17782 => 2279.606 +ed-209.frag 11197 => 1479.056 +valley_ball.glsl 5837 => 942.129 +lunaquatic.frag 7237 => 1175.040 +slisesix.frag 7115 => 1116.704 +yx_long_way_from_home.frag 4494 => 712.244 +oscars_chair.frag 6588 => 1166.886 +kinder_painter.frag 4085 => 503.991 +ohanami.frag 5019 => 846.307 +terrarium.frag 5313 => 841.249 +leizex.frag 3121 => 541.299 +elevated.hlsl 4366 => 671.319 +Total: 114634 => 15073.758 From cbd8071768dbb5b19af94486e225f41b8af9d1b3 Mon Sep 17 00:00:00 2001 From: Laurent Le Brun Date: Tue, 3 Jan 2023 00:56:54 +0100 Subject: [PATCH 03/32] pass "--format text" --- Checker/compression_test.fs | 5 +++-- tests/compression_results.log | 28 ++++++++++++++-------------- 2 files changed, 17 insertions(+), 16 deletions(-) diff --git a/Checker/compression_test.fs b/Checker/compression_test.fs index b12d9765..bd0d4966 100644 --- a/Checker/compression_test.fs +++ b/Checker/compression_test.fs @@ -40,8 +40,9 @@ let log fmt = Printf.ksprintf logger fmt let testFile (file: string) = - let args = if file.EndsWith("hlsl") then [|"--hlsl"|] else [||] - Options.init(args) + let langArg = if file.EndsWith("hlsl") then [|"--hlsl"|] else [||] + let extraArgs = [|"--format"; "text"|] + Options.init(Array.append langArg extraArgs) let minified = use out = new StringWriter() let shaders, exportedNames = ShaderMinifier.minifyFiles [|"tests/real/" + file|] diff --git a/tests/compression_results.log b/tests/compression_results.log index 482994f2..513b4b68 100644 --- a/tests/compression_results.log +++ b/tests/compression_results.log @@ -1,14 +1,14 @@ -from-the-seas-to-the-stars.frag 32480 => 2797.928 -the_real_party_is_in_your_pocket.frag 17782 => 2279.606 -ed-209.frag 11197 => 1479.056 -valley_ball.glsl 5837 => 942.129 -lunaquatic.frag 7237 => 1175.040 -slisesix.frag 7115 => 1116.704 -yx_long_way_from_home.frag 4494 => 712.244 -oscars_chair.frag 6588 => 1166.886 -kinder_painter.frag 4085 => 503.991 -ohanami.frag 5019 => 846.307 -terrarium.frag 5313 => 841.249 -leizex.frag 3121 => 541.299 -elevated.hlsl 4366 => 671.319 -Total: 114634 => 15073.758 +from-the-seas-to-the-stars.frag 14347 => 2353.607 +the_real_party_is_in_your_pocket.frag 12214 => 1829.362 +ed-209.frag 7899 => 1359.091 +valley_ball.glsl 4419 => 896.357 +lunaquatic.frag 5232 => 1056.700 +slisesix.frag 4546 => 957.481 +yx_long_way_from_home.frag 2993 => 614.607 +oscars_chair.frag 4649 => 982.393 +kinder_painter.frag 2901 => 456.603 +ohanami.frag 3293 => 746.366 +terrarium.frag 3646 => 748.815 +leizex.frag 2308 => 515.785 +elevated.hlsl 3406 => 611.302 +Total: 71853 => 13128.467 From a08180895c2a8a17e4682a107194628bb287e1e6 Mon Sep 17 00:00:00 2001 From: Laurent Le Brun Date: Tue, 3 Jan 2023 01:00:05 +0100 Subject: [PATCH 04/32] Add commented line for running compression tests --- Checker/main.fs | 4 +++- Shader Minifier.fsproj | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/Checker/main.fs b/Checker/main.fs index 3541d360..541d30b6 100644 --- a/Checker/main.fs +++ b/Checker/main.fs @@ -117,7 +117,9 @@ let testGolden () = [] let main argv = - //ignore(runCommand("--no-renaming --format c-array -o tests/unit/minus-zero.expected tests/unit/minus-zero.frag".Split([|' '|]))); exit 0 + // Manually run compression tests by enabling this line: + // CompressionTests.run () + initOpenTK() let mutable failures = testGolden() Options.init([|"--format"; "text"; "fake.frag"|]) diff --git a/Shader Minifier.fsproj b/Shader Minifier.fsproj index da580087..0392f73b 100644 --- a/Shader Minifier.fsproj +++ b/Shader Minifier.fsproj @@ -32,7 +32,7 @@ true bin\Release\ TRACE - 3 + 4 -o "" ../../tests\unit\empty_block.frag --smoothstep --standalone From 778ddf49940aed4a812f1fe05a908d865182942b Mon Sep 17 00:00:00 2001 From: Laurent Le Brun Date: Wed, 4 Jan 2023 00:34:39 +0100 Subject: [PATCH 05/32] tests/real: remove many unused files; clarify purpose (#204) --- tests/real/README.md | 37 ++ tests/real/extatique/blit.frag | 7 - tests/real/extatique/blit.vs | 6 - tests/real/extatique/blit2.frag | 12 - tests/real/extatique/blit2.vs | 5 - tests/real/extatique/blitcorner.frag | 13 - tests/real/extatique/blitcorner.vs | 6 - tests/real/extatique/blitgirl.frag | 26 - tests/real/extatique/blitgirl.vs | 6 - tests/real/extatique/blitsquare.frag | 18 - tests/real/extatique/blitsquare.vs | 6 - tests/real/extatique/distort.frag | 23 - tests/real/extatique/distort.vs | 6 - tests/real/extatique/final.frag | 33 -- tests/real/extatique/final.vs | 5 - tests/real/extatique/font.frag | 11 - tests/real/extatique/font.vs | 7 - tests/real/extatique/glow.frag | 9 - tests/real/extatique/glow.vs | 8 - tests/real/extatique/graindo12.frag | 110 ---- tests/real/extatique/graindo12.vs | 6 - tests/real/extatique/lambert.frag | 93 ---- tests/real/extatique/lambert.vs | 27 - tests/real/extatique/lambert2.frag | 91 ---- tests/real/extatique/lambert2.vs | 27 - tests/real/extatique/loading.frag | 31 -- tests/real/extatique/loading.vs | 5 - tests/real/extatique/log.frag | 20 - tests/real/extatique/log.vs | 6 - tests/real/extatique/particle.frag | 8 - tests/real/extatique/particle.vs | 17 - tests/real/extatique/progress.frag | 58 -- tests/real/extatique/progress.vs | 6 - tests/real/extatique/put.frag | 4 - tests/real/extatique/put.vs | 5 - tests/real/extatique/raymarch.frag | 59 --- tests/real/extatique/raymarch.vs | 9 - tests/real/extatique/scene30.frag | 41 -- tests/real/extatique/scene30.vs | 11 - tests/real/extatique/scene40.frag | 177 ------- tests/real/extatique/scene40.vs | 13 - tests/real/extatique/scene45.frag | 14 - tests/real/extatique/scene45.vs | 6 - tests/real/extatique/skybox.frag | 32 -- tests/real/extatique/skybox.vs | 7 - tests/real/extatique/skybox2.frag | 142 ----- tests/real/extatique/skybox2.vs | 13 - tests/real/extatique/snake.frag | 18 - tests/real/extatique/snake.vs | 12 - tests/real/extatique/water.frag | 84 --- tests/real/extatique/water.vs | 6 - tests/real/fly.frag | 20 - tests/real/gfx monitor/ambiantocclusion.vs | 9 - .../gfx monitor/distancefieldRaytrace.frag | 99 ---- .../real/gfx monitor/distancefieldRaytrace.vs | 9 - tests/real/gfx monitor/gradation.frag | 10 - tests/real/gfx monitor/gradation.gs | 10 - tests/real/gfx monitor/raytrace.vs | 10 - tests/real/multitexture.frag | 21 - tests/real/relief_tunnel.frag | 34 -- tests/real/square_tunnel.frag | 20 - tests/real/the orange guy/ball_pixel.glsl | 56 -- tests/real/the orange guy/ball_vertex.glsl | 5 - tests/real/the orange guy/bloom2_pixel.glsl | 35 -- tests/real/the orange guy/bloom2_vertex.glsl | 5 - tests/real/the orange guy/bloom_pixel.glsl | 40 -- tests/real/the orange guy/bloom_vertex.glsl | 5 - tests/real/the orange guy/dfc_pixel.glsl | 67 --- tests/real/the orange guy/dfc_vertex.glsl | 6 - tests/real/the orange guy/final_pixel.glsl | 18 - tests/real/the orange guy/final_vertex.glsl | 5 - tests/real/the orange guy/font_pixel.glsl | 11 - tests/real/the orange guy/font_vertex.glsl | 7 - .../real/the orange guy/logofinal_pixel.glsl | 8 - .../real/the orange guy/logofinal_vertex.glsl | 7 - tests/real/the orange guy/orange_pixel.glsl | 38 -- tests/real/the orange guy/orange_vertex.glsl | 6 - tests/real/the orange guy/particle_pixel.glsl | 15 - .../real/the orange guy/particle_vertex.glsl | 8 - tests/real/the orange guy/put_pixel.glsl | 4 - tests/real/the orange guy/put_vertex.glsl | 7 - .../real/the orange guy/puttexture_pixel.glsl | 20 - .../the orange guy/puttexture_vertex.glsl | 7 - tests/real/the orange guy/scene10_pixel.hlsl | 30 -- tests/real/the orange guy/scene10_vertex.glsl | 6 - .../the orange guy/tonemapping_pixel.glsl | 18 - .../the orange guy/tonemapping_vertex.glsl | 5 - tests/real/the orange guy/tunnel_pixel.glsl | 20 - tests/real/the orange guy/tunnel_vertex.glsl | 13 - .../f_blurhighlights.cpp | 186 ------- .../the wind under my wings/f_blurpass.cpp | 498 ------------------ .../the wind under my wings/f_blurpass2.cpp | 264 ---------- .../the wind under my wings/f_combineSSAO.cpp | 316 ----------- .../the wind under my wings/f_godrays.cpp | 229 -------- .../the wind under my wings/f_simpleblur.cpp | 175 ------ .../the wind under my wings/f_velocities.cpp | 39 -- .../the wind under my wings/v_velocities.cpp | 114 ---- tests/real/tunnel.frag | 22 - tests/real/twist.frag | 22 - tests/real/z_invert.frag | 22 - 100 files changed, 37 insertions(+), 3966 deletions(-) create mode 100644 tests/real/README.md delete mode 100644 tests/real/extatique/blit.frag delete mode 100644 tests/real/extatique/blit.vs delete mode 100644 tests/real/extatique/blit2.frag delete mode 100644 tests/real/extatique/blit2.vs delete mode 100644 tests/real/extatique/blitcorner.frag delete mode 100644 tests/real/extatique/blitcorner.vs delete mode 100644 tests/real/extatique/blitgirl.frag delete mode 100644 tests/real/extatique/blitgirl.vs delete mode 100644 tests/real/extatique/blitsquare.frag delete mode 100644 tests/real/extatique/blitsquare.vs delete mode 100644 tests/real/extatique/distort.frag delete mode 100644 tests/real/extatique/distort.vs delete mode 100644 tests/real/extatique/final.frag delete mode 100644 tests/real/extatique/final.vs delete mode 100644 tests/real/extatique/font.frag delete mode 100644 tests/real/extatique/font.vs delete mode 100644 tests/real/extatique/glow.frag delete mode 100644 tests/real/extatique/glow.vs delete mode 100644 tests/real/extatique/graindo12.frag delete mode 100644 tests/real/extatique/graindo12.vs delete mode 100644 tests/real/extatique/lambert.frag delete mode 100644 tests/real/extatique/lambert.vs delete mode 100644 tests/real/extatique/lambert2.frag delete mode 100644 tests/real/extatique/lambert2.vs delete mode 100644 tests/real/extatique/loading.frag delete mode 100644 tests/real/extatique/loading.vs delete mode 100644 tests/real/extatique/log.frag delete mode 100644 tests/real/extatique/log.vs delete mode 100644 tests/real/extatique/particle.frag delete mode 100644 tests/real/extatique/particle.vs delete mode 100644 tests/real/extatique/progress.frag delete mode 100644 tests/real/extatique/progress.vs delete mode 100644 tests/real/extatique/put.frag delete mode 100644 tests/real/extatique/put.vs delete mode 100644 tests/real/extatique/raymarch.frag delete mode 100644 tests/real/extatique/raymarch.vs delete mode 100644 tests/real/extatique/scene30.frag delete mode 100644 tests/real/extatique/scene30.vs delete mode 100644 tests/real/extatique/scene40.frag delete mode 100644 tests/real/extatique/scene40.vs delete mode 100644 tests/real/extatique/scene45.frag delete mode 100644 tests/real/extatique/scene45.vs delete mode 100644 tests/real/extatique/skybox.frag delete mode 100644 tests/real/extatique/skybox.vs delete mode 100644 tests/real/extatique/skybox2.frag delete mode 100644 tests/real/extatique/skybox2.vs delete mode 100644 tests/real/extatique/snake.frag delete mode 100644 tests/real/extatique/snake.vs delete mode 100644 tests/real/extatique/water.frag delete mode 100644 tests/real/extatique/water.vs delete mode 100644 tests/real/fly.frag delete mode 100644 tests/real/gfx monitor/ambiantocclusion.vs delete mode 100644 tests/real/gfx monitor/distancefieldRaytrace.frag delete mode 100644 tests/real/gfx monitor/distancefieldRaytrace.vs delete mode 100644 tests/real/gfx monitor/gradation.frag delete mode 100644 tests/real/gfx monitor/gradation.gs delete mode 100644 tests/real/gfx monitor/raytrace.vs delete mode 100644 tests/real/multitexture.frag delete mode 100644 tests/real/relief_tunnel.frag delete mode 100644 tests/real/square_tunnel.frag delete mode 100644 tests/real/the orange guy/ball_pixel.glsl delete mode 100644 tests/real/the orange guy/ball_vertex.glsl delete mode 100644 tests/real/the orange guy/bloom2_pixel.glsl delete mode 100644 tests/real/the orange guy/bloom2_vertex.glsl delete mode 100644 tests/real/the orange guy/bloom_pixel.glsl delete mode 100644 tests/real/the orange guy/bloom_vertex.glsl delete mode 100644 tests/real/the orange guy/dfc_pixel.glsl delete mode 100644 tests/real/the orange guy/dfc_vertex.glsl delete mode 100644 tests/real/the orange guy/final_pixel.glsl delete mode 100644 tests/real/the orange guy/final_vertex.glsl delete mode 100644 tests/real/the orange guy/font_pixel.glsl delete mode 100644 tests/real/the orange guy/font_vertex.glsl delete mode 100644 tests/real/the orange guy/logofinal_pixel.glsl delete mode 100644 tests/real/the orange guy/logofinal_vertex.glsl delete mode 100644 tests/real/the orange guy/orange_pixel.glsl delete mode 100644 tests/real/the orange guy/orange_vertex.glsl delete mode 100644 tests/real/the orange guy/particle_pixel.glsl delete mode 100644 tests/real/the orange guy/particle_vertex.glsl delete mode 100644 tests/real/the orange guy/put_pixel.glsl delete mode 100644 tests/real/the orange guy/put_vertex.glsl delete mode 100644 tests/real/the orange guy/puttexture_pixel.glsl delete mode 100644 tests/real/the orange guy/puttexture_vertex.glsl delete mode 100644 tests/real/the orange guy/scene10_pixel.hlsl delete mode 100644 tests/real/the orange guy/scene10_vertex.glsl delete mode 100644 tests/real/the orange guy/tonemapping_pixel.glsl delete mode 100644 tests/real/the orange guy/tonemapping_vertex.glsl delete mode 100644 tests/real/the orange guy/tunnel_pixel.glsl delete mode 100644 tests/real/the orange guy/tunnel_vertex.glsl delete mode 100644 tests/real/the wind under my wings/f_blurhighlights.cpp delete mode 100644 tests/real/the wind under my wings/f_blurpass.cpp delete mode 100644 tests/real/the wind under my wings/f_blurpass2.cpp delete mode 100644 tests/real/the wind under my wings/f_combineSSAO.cpp delete mode 100644 tests/real/the wind under my wings/f_godrays.cpp delete mode 100644 tests/real/the wind under my wings/f_simpleblur.cpp delete mode 100644 tests/real/the wind under my wings/f_velocities.cpp delete mode 100644 tests/real/the wind under my wings/v_velocities.cpp delete mode 100644 tests/real/tunnel.frag delete mode 100644 tests/real/twist.frag delete mode 100644 tests/real/z_invert.frag diff --git a/tests/real/README.md b/tests/real/README.md new file mode 100644 index 00000000..59957807 --- /dev/null +++ b/tests/real/README.md @@ -0,0 +1,37 @@ +This is a third-party directory. Files in this directory do not have the same +license as the main repository. These files are used only for testing purposes. +Do not use them in any other way without their author first. + +## How we use the files + +1. Parser coverage. We need to ensure that Shader Minifier can parse a variety + of shader files. These files help us improve the coverage and be more + confident when we make changes to the parser. + +2. AST transformation coverage. When we implement AST transformations, we run + them on the test shaders. We call a shader compiler to ensure the output + still compiles. Additionally, we manually review the changes to the minified + shaders to spot potential issues. + +3. Compression tests. We use these tests to check that Shader Minifier output + stays small and compresses well. We need a variety of test files that are + "realistic" (synthetic files wouldn't have the same compression profile). + +4. Performance tests. We check the performance of Shader Minifier on real + shaders and make sure it remains fast enough. + + +## Updating the files + +- `.expected` files are generated by Shader Minifier. They are updated when we + run the tests. +- If you own any of these files, you can reach out to update the file, clarify + the attribution, or have it deleted. +- If you want to contribute new files, you can send a pull request. We prefer + files that increase the code coverage or are representative of the modern + demoscene. + +Note: When the project started, it was not open-source and shaders were +collected from various sources. They are not always well attributed; sorry about +that, we're more careful from now on. We add files that have a compatible +license and add attribution in the file header. diff --git a/tests/real/extatique/blit.frag b/tests/real/extatique/blit.frag deleted file mode 100644 index fdfcd1fb..00000000 --- a/tests/real/extatique/blit.frag +++ /dev/null @@ -1,7 +0,0 @@ -uniform sampler2D tex; - -void main() -{ - vec2 p = gl_TexCoord[0].xy; - gl_FragColor = gl_Color * texture2D(tex, p); -} \ No newline at end of file diff --git a/tests/real/extatique/blit.vs b/tests/real/extatique/blit.vs deleted file mode 100644 index e56b9174..00000000 --- a/tests/real/extatique/blit.vs +++ /dev/null @@ -1,6 +0,0 @@ -void main() -{ - gl_TexCoord[0] = gl_MultiTexCoord0; - gl_FrontColor = gl_Color; - gl_Position = ftransform(); -} \ No newline at end of file diff --git a/tests/real/extatique/blit2.frag b/tests/real/extatique/blit2.frag deleted file mode 100644 index eb8c49e8..00000000 --- a/tests/real/extatique/blit2.frag +++ /dev/null @@ -1,12 +0,0 @@ -uniform sampler2D tex1; -uniform sampler2D tex2; - -uniform float tex1Amount; -uniform float tex2Amount; - -void main() -{ - vec2 p = gl_TexCoord[0].xy; - - gl_FragColor = vec4(tex1Amount) * texture2D(tex1, p) + vec4(tex2Amount) * texture2D(tex2, p); -} \ No newline at end of file diff --git a/tests/real/extatique/blit2.vs b/tests/real/extatique/blit2.vs deleted file mode 100644 index 0112e5c6..00000000 --- a/tests/real/extatique/blit2.vs +++ /dev/null @@ -1,5 +0,0 @@ -void main() -{ - gl_TexCoord[0] = gl_MultiTexCoord0; - gl_Position = ftransform(); -} \ No newline at end of file diff --git a/tests/real/extatique/blitcorner.frag b/tests/real/extatique/blitcorner.frag deleted file mode 100644 index 326906b7..00000000 --- a/tests/real/extatique/blitcorner.frag +++ /dev/null @@ -1,13 +0,0 @@ -uniform sampler2D tex; -uniform float ratio; -uniform float factor; - -void main() -{ - vec2 p = gl_TexCoord[0].xy; - - vec2 dist = (p - vec2(0.5, 0.5)) * vec2(1.0,ratio); - vec4 darkF = vec4(max(0.0, 1.0 - factor * dot(dist,dist))); - - gl_FragColor = gl_Color * darkF * texture2D(tex, p); -} diff --git a/tests/real/extatique/blitcorner.vs b/tests/real/extatique/blitcorner.vs deleted file mode 100644 index e56b9174..00000000 --- a/tests/real/extatique/blitcorner.vs +++ /dev/null @@ -1,6 +0,0 @@ -void main() -{ - gl_TexCoord[0] = gl_MultiTexCoord0; - gl_FrontColor = gl_Color; - gl_Position = ftransform(); -} \ No newline at end of file diff --git a/tests/real/extatique/blitgirl.frag b/tests/real/extatique/blitgirl.frag deleted file mode 100644 index 0db56994..00000000 --- a/tests/real/extatique/blitgirl.frag +++ /dev/null @@ -1,26 +0,0 @@ -uniform sampler2D tex; -uniform sampler2D noise; -uniform vec2 size; -uniform float border; - - -void main() -{ - vec2 p = gl_TexCoord[0].xy; - - vec2 realP = p * size; - - float alphaX = smoothstep(0.0, border, realP.x) - smoothstep(size.x - border, size.x, realP.x); - float alphaY = smoothstep(0.0, border, realP.y) - smoothstep(size.y - border, size.y, realP.y); - - float border2 = border * 3.0; - float alphaX2 = smoothstep(0.0, border2, realP.x) - smoothstep(size.x - border2, size.x, realP.x); - float alphaY2 = smoothstep(0.0, border2, realP.y) - smoothstep(size.y - border2, size.y, realP.y); - - - float noise = texture2D(noise, realP).r; - - float alpha = max(0.0, alphaX * alphaY - (noise * (1.0 - alphaX2 * alphaY2))); - - gl_FragColor = vec4(gl_Color.rgb, alpha) * texture2D(tex, p); -} \ No newline at end of file diff --git a/tests/real/extatique/blitgirl.vs b/tests/real/extatique/blitgirl.vs deleted file mode 100644 index e56b9174..00000000 --- a/tests/real/extatique/blitgirl.vs +++ /dev/null @@ -1,6 +0,0 @@ -void main() -{ - gl_TexCoord[0] = gl_MultiTexCoord0; - gl_FrontColor = gl_Color; - gl_Position = ftransform(); -} \ No newline at end of file diff --git a/tests/real/extatique/blitsquare.frag b/tests/real/extatique/blitsquare.frag deleted file mode 100644 index 97a3186d..00000000 --- a/tests/real/extatique/blitsquare.frag +++ /dev/null @@ -1,18 +0,0 @@ -uniform sampler2D tex; -uniform vec2 size; -uniform float border; - - -void main() -{ - vec2 p = gl_TexCoord[0].xy; - - vec2 realP = p * size; - - float alphaX = smoothstep(0.0, border, realP.x) - smoothstep(size.x - border, size.x, realP.x); - float alphaY = smoothstep(0.0, border, realP.y) - smoothstep(size.y - border, size.y, realP.y); - - float alpha = alphaX * alphaY; - - gl_FragColor = vec4(gl_Color.rgb, alpha) * texture2D(tex, p); -} \ No newline at end of file diff --git a/tests/real/extatique/blitsquare.vs b/tests/real/extatique/blitsquare.vs deleted file mode 100644 index e56b9174..00000000 --- a/tests/real/extatique/blitsquare.vs +++ /dev/null @@ -1,6 +0,0 @@ -void main() -{ - gl_TexCoord[0] = gl_MultiTexCoord0; - gl_FrontColor = gl_Color; - gl_Position = ftransform(); -} \ No newline at end of file diff --git a/tests/real/extatique/distort.frag b/tests/real/extatique/distort.frag deleted file mode 100644 index f673075b..00000000 --- a/tests/real/extatique/distort.frag +++ /dev/null @@ -1,23 +0,0 @@ -uniform sampler2D tex; -uniform float amount; -uniform float colorSep; -uniform vec4 glow; - - -void main() -{ - vec2 p = (gl_TexCoord[0].xy - vec2(0.5,0.5)); - vec2 p2 = p + vec2(colorSep, 0.0); - vec2 p3 = p - vec2(colorSep, 0.0); - - float distortion = amount / (1.0 + length(p * 5.0)); - - float cosd = cos(distortion); - float sind = sin(distortion); - - mat2 tranfo = mat2(cosd, -sind, sind, cosd); - - vec4 color1 = vec4(1.0,0.5,0.0,0.5) * texture2D(tex, (vec2(0.5) + tranfo * p2)); - vec4 color2 = vec4(0.0,0.5,1.0,0.5) * texture2D(tex, (vec2(0.5) + tranfo * p3)); - gl_FragColor = gl_Color * (color1 + color2) + glow; -} \ No newline at end of file diff --git a/tests/real/extatique/distort.vs b/tests/real/extatique/distort.vs deleted file mode 100644 index e56b9174..00000000 --- a/tests/real/extatique/distort.vs +++ /dev/null @@ -1,6 +0,0 @@ -void main() -{ - gl_TexCoord[0] = gl_MultiTexCoord0; - gl_FrontColor = gl_Color; - gl_Position = ftransform(); -} \ No newline at end of file diff --git a/tests/real/extatique/final.frag b/tests/real/extatique/final.frag deleted file mode 100644 index 764c7a43..00000000 --- a/tests/real/extatique/final.frag +++ /dev/null @@ -1,33 +0,0 @@ -uniform sampler2D tex; -uniform sampler3D gammaRamp; - -uniform float blurType; -uniform float blurAmount; -uniform float invHeight; -uniform float invWidth; - - -void main() -{ - vec2 p = gl_TexCoord[0].xy; - - vec4 blur = ( texture2DLod(tex, p, 7.0) - + texture2DLod(tex, p, 6.0) - + texture2DLod(tex, p, 5.0) - + texture2DLod(tex, p, 4.0) - + texture2DLod(tex, p, 3.0) - + texture2DLod(tex, p, 2.0) - + texture2DLod(tex, p, 1.0)) * vec4(0.142857); /* 1/7 */ - - vec4 center = texture2D(tex, p); - - - vec4 blurred = (vec4(1.0) - (vec4(1.0) - blur) * (vec4(1.0) - center)); - vec4 blurred2 = blurred * mix( blurred, vec4(1.0), blurType); - - vec4 uncorrected = mix(center, blurred2, blurAmount); - - /* gamma correction */ - - gl_FragColor = texture3D(gammaRamp, uncorrected.xyz); -} diff --git a/tests/real/extatique/final.vs b/tests/real/extatique/final.vs deleted file mode 100644 index 623bdcb4..00000000 --- a/tests/real/extatique/final.vs +++ /dev/null @@ -1,5 +0,0 @@ -void main() -{ - gl_TexCoord[0] = gl_MultiTexCoord0; - gl_Position = gl_Vertex; -} \ No newline at end of file diff --git a/tests/real/extatique/font.frag b/tests/real/extatique/font.frag deleted file mode 100644 index b35af764..00000000 --- a/tests/real/extatique/font.frag +++ /dev/null @@ -1,11 +0,0 @@ -uniform sampler2D tex; -uniform sampler2D fill; - -void main() -{ - vec2 p = gl_TexCoord[0].xy; - vec4 letter = texture2D(tex, p); - vec4 fillColor = texture2D(fill, p * 3.0); - - gl_FragColor = letter * fillColor * gl_Color; -} \ No newline at end of file diff --git a/tests/real/extatique/font.vs b/tests/real/extatique/font.vs deleted file mode 100644 index 1320daa3..00000000 --- a/tests/real/extatique/font.vs +++ /dev/null @@ -1,7 +0,0 @@ - -void main() -{ - gl_TexCoord[0] = gl_MultiTexCoord0; - gl_Position = ftransform(); - gl_FrontColor = gl_Color; -} \ No newline at end of file diff --git a/tests/real/extatique/glow.frag b/tests/real/extatique/glow.frag deleted file mode 100644 index a1a5c6a5..00000000 --- a/tests/real/extatique/glow.frag +++ /dev/null @@ -1,9 +0,0 @@ -uniform sampler1D tex; - - -void main() -{ - vec2 p = gl_TexCoord[0].xy; - float a = length(p) / 2.04; - gl_FragColor = gl_Color * vec4(1.0,1.0,1.0, texture1D(tex, a)); -} \ No newline at end of file diff --git a/tests/real/extatique/glow.vs b/tests/real/extatique/glow.vs deleted file mode 100644 index eb6c497a..00000000 --- a/tests/real/extatique/glow.vs +++ /dev/null @@ -1,8 +0,0 @@ - -void main() -{ - gl_FrontColor = gl_Color; - gl_TexCoord[0] = gl_MultiTexCoord0; - - gl_Position = ftransform(); -} \ No newline at end of file diff --git a/tests/real/extatique/graindo12.frag b/tests/real/extatique/graindo12.frag deleted file mode 100644 index 97163ae0..00000000 --- a/tests/real/extatique/graindo12.frag +++ /dev/null @@ -1,110 +0,0 @@ -uniform float time; -uniform float param1; - - -uniform sampler1D distRamp; -uniform vec3 matColor; -uniform vec3 ambientColor; - - - -float gausa( float a ) -{ - return texture1D(distRamp, abs(a) * 0.125 ).r; /* pow(0.5f, abs(a)); */ -} - -float gausb( float a ) -{ - return pow(0.5, abs(a)); -} - -mat3 rotationMatrix( float a , float b , float c ) -{ - float xvs = sin(a); - float yvs = sin(b); - float zvs = sin(c); - - float xvc = cos(a); - float yvc = cos(b); - float zvc = cos(c); - - float Ox1 = yvc * zvc; - float Ox2 = xvc * yvs * zvc + xvs * zvs; - float Ox3 = xvc * zvs - xvs * yvs * zvc; - - float Oy1 = xvc * zvc + xvs * yvs * zvs; - float Oy2 = xvs * zvc - xvc * yvs * zvs; - float Oy3 = -yvc * zvs; - - float Oz1 = xvc * yvc; - float Oz2 = -xvs * yvc; - float Oz3 = -yvs; - - return mat3( Ox1 , Ox3 , Ox2 , - Oy3 , Oy1 , Oy2 , - Oz3 , Oz2 , Oz1 ); -} - - - - - -vec3 objet(vec3 c , vec3 v , float t ) -{ - vec3 vt = vec3(8.0,2.0,2.0); - - float ti = cos(t * 3.0); - float to = cos(t * 0.2) * 0.02 + 0.5; - - vec3 co = vec3(0.0); - - - mat3 disto = rotationMatrix( v.z , v.x , -v.y ); - - vec3 vi = v * disto; - float lvi = length(vi); - - float gg = gausa((lvi - 12.0 * to)) - * gausa((8.485 - 12.0 * to)) - * gausa((lvi - 8.485)); - - vec3 col = c * vec3(1.0 - gg); - - vt.x = vi.x + 3.0; - - - float size = param1; - float gg2 = gausa(size * (lvi - 6.0 * to)) - * gausa(size * (lvi - length(vt))); - - vec3 material = matColor; - - return mix(col, material , gg2 * param1); -} - -void main(void) -{ - float t = time; - - vec2 xy = gl_TexCoord[0].xy; - - - vec3 coll = vec3(0.0); - - const int iter = 3; - - mat3 rotation = rotationMatrix( t, t, -t); - - vec3 d = rotation * vec3(xy, float(iter)); - vec3 a = rotation * vec3(xy * vec2(2.0), -float(iter)); - - - for (int z = 0; z <= iter; ++z) - { - float fr = float(z) / float(iter); - vec3 posi = mix(d, a, fr); - coll = objet(coll, posi, t); - - } - gl_FragColor = vec4 (coll, 1.0); -} diff --git a/tests/real/extatique/graindo12.vs b/tests/real/extatique/graindo12.vs deleted file mode 100644 index e56b9174..00000000 --- a/tests/real/extatique/graindo12.vs +++ /dev/null @@ -1,6 +0,0 @@ -void main() -{ - gl_TexCoord[0] = gl_MultiTexCoord0; - gl_FrontColor = gl_Color; - gl_Position = ftransform(); -} \ No newline at end of file diff --git a/tests/real/extatique/lambert.frag b/tests/real/extatique/lambert.frag deleted file mode 100644 index c86ddfcb..00000000 --- a/tests/real/extatique/lambert.frag +++ /dev/null @@ -1,93 +0,0 @@ -varying vec3 N; -varying vec3 pos; -varying vec3 wpos; - -varying vec3 l1_pos; -varying vec3 l2_pos; -varying vec3 l3_pos; - -uniform vec3 light1Color; -uniform vec3 light2Color; -uniform vec3 light3Color; -uniform vec3 ambientColor; - - -uniform float light1Specular; -uniform float light2Specular; -uniform float light3Specular; -uniform float light1Diffuse; -uniform float light2Diffuse; -uniform float light3Diffuse; -uniform float thresholdZ; - -const float linAtt = 0.20; -const float quadAtt = 0.1; -const float fogNear = 1.0; -const float fogFar = 10.0; - -uniform sampler2D noise; - - -float AO(vec3 p) -{ - return 1.0 / (1.0 + 0.012 * dot(p,p)); -} - -vec3 desaturate(vec3 c, float s) -{ - return mix( c, vec3(dot(vec3(0.3), c)), s); -} - -void main() -{ - - vec2 p = gl_TexCoord[0].xy; - - vec3 perturb = vec3(texture2D(noise, p + vec2(0.13,0.46)).x, texture2D(noise, p).x, texture2D(noise, p + vec2(-0.33,0.14)).x); - - perturb = (perturb - vec3(0.5)) * 5.0; - - vec3 nml = normalize(N + perturb); - - if (nml.z < thresholdZ) discard; - - vec3 l1dist = l1_pos - pos; - vec3 l2dist = l2_pos - pos; - vec3 l3dist = l3_pos - pos; - - float dist1 = length(l1dist); - float dist2 = length(l2dist); - float dist3 = length(l3dist); - - vec3 lv1 = l1dist / dist1; - vec3 lv2 = l2dist / dist2; - vec3 lv3 = l3dist / dist3; - - vec3 eye = normalize(-pos); - - vec3 re1 = reflect(lv1, N); - vec3 re2 = reflect(lv2, N); - vec3 re3 = reflect(lv3, N); - - float diffl1 = max(0.0, dot(nml,lv1) ); - float diffl2 = max(0.0, dot(nml,lv2) ); - float diffl3 = max(0.0, dot(nml,lv3) ); - - float specl1 = light1Specular * pow(max(0.0, dot(eye, re1)), 10.0); - float specl2 = light2Specular * pow(max(0.0, dot(eye, re2)), 10.0); - float specl3 = light3Specular * pow(max(0.0, dot(eye, re3)), 10.0); - - - float ql1 = (diffl1 + specl1) / (1.0 + dist1 * (linAtt + quadAtt * dist1)); - float ql2 = (diffl2 + specl2) / (1.0 + dist2 * (linAtt + quadAtt * dist2)); - float ql3 = (diffl3 + specl3) / (1.0 + dist3 * (linAtt + quadAtt * dist3)); - - vec3 light = ambientColor + light1Color * vec3(ql1) + light2Color * vec3(ql2) + light3Color * vec3(ql3); - - - float fogAmount = clamp( (pos.z - fogNear) / (fogFar - fogNear) , 0.0, 1.0); - vec3 lightAO = desaturate(light * vec3(AO(wpos)), fogAmount); - - - gl_FragColor = gl_Color * vec4(lightAO, 1.0); -} diff --git a/tests/real/extatique/lambert.vs b/tests/real/extatique/lambert.vs deleted file mode 100644 index 074f235d..00000000 --- a/tests/real/extatique/lambert.vs +++ /dev/null @@ -1,27 +0,0 @@ -uniform vec3 light1Pos; -uniform vec3 light2Pos; -uniform vec3 light3Pos; -uniform mat4 invCamMat; - -varying vec3 N; -varying vec3 pos; -varying vec3 wpos; -varying vec3 l1_pos; -varying vec3 l2_pos; -varying vec3 l3_pos; - -void main() -{ - - N = gl_NormalMatrix * gl_Normal; - vec4 epos = gl_ModelViewMatrix * gl_Vertex; - wpos = (invCamMat * epos).xyz; - pos = epos.xyz; - l1_pos = (gl_ModelViewMatrix * vec4(light1Pos,1.0)).xyz; - l2_pos = (gl_ModelViewMatrix * vec4(light2Pos,1.0)).xyz; - l3_pos = (gl_ModelViewMatrix * vec4(light3Pos,1.0)).xyz; - - gl_TexCoord[0] = gl_MultiTexCoord0; - gl_FrontColor = gl_Color; - gl_Position = ftransform(); -} \ No newline at end of file diff --git a/tests/real/extatique/lambert2.frag b/tests/real/extatique/lambert2.frag deleted file mode 100644 index bbcc7656..00000000 --- a/tests/real/extatique/lambert2.frag +++ /dev/null @@ -1,91 +0,0 @@ -varying vec3 N; -varying vec3 pos; - - -varying vec3 l1_pos; -varying vec3 l2_pos; -varying vec3 l3_pos; - -uniform vec3 light1Color; -uniform vec3 light2Color; -uniform vec3 light3Color; -uniform vec3 ambientColor; - - -uniform float light1Specular; -uniform float light2Specular; -uniform float light3Specular; -uniform float light1Diffuse; -uniform float light2Diffuse; -uniform float light3Diffuse; - -const float linAtt = 0.30; -const float quadAtt = 0.2; -const float fogNear = 1.0; -const float fogFar = 5.0; - -uniform sampler2D noise; -uniform sampler2D tex; - - - -vec3 desaturate(vec3 c, float s) -{ - return mix( c, vec3(dot(vec3(0.3), c)), s); -} - -void main() -{ - - vec2 p = gl_TexCoord[0].xy; - - vec3 perturb = vec3(texture2D(noise, p + vec2(0.13,0.46)).x, texture2D(noise, p).x, texture2D(noise, p + vec2(-0.33,0.14)).x); - - vec4 texColor = texture2D(tex,p); - - perturb = (perturb - vec3(0.5)) * 10.0; - - vec3 nml = normalize(N + perturb); - - - - vec3 l1dist = l1_pos - pos; - vec3 l2dist = l2_pos - pos; - vec3 l3dist = l3_pos - pos; - - float dist1 = length(l1dist); - float dist2 = length(l2dist); - float dist3 = length(l3dist); - - vec3 lv1 = l1dist / dist1; - vec3 lv2 = l2dist / dist2; - vec3 lv3 = l3dist / dist3; - - vec3 eye = normalize(-pos); - - vec3 re1 = reflect(lv1, N); - vec3 re2 = reflect(lv2, N); - vec3 re3 = reflect(lv3, N); - - float diffl1 = max(0.0, dot(nml,lv1) ); - float diffl2 = max(0.0, dot(nml,lv2) ); - float diffl3 = max(0.0, dot(nml,lv3) ); - - float specl1 = light1Specular * pow(max(0.0, dot(eye, re1)), 10.0); - float specl2 = light2Specular * pow(max(0.0, dot(eye, re2)), 10.0); - float specl3 = light3Specular * pow(max(0.0, dot(eye, re3)), 10.0); - - - float ql1 = (diffl1 + specl1) / (1.0 + dist1 * (linAtt + quadAtt * dist1)); - float ql2 = (diffl2 + specl2) / (1.0 + dist2 * (linAtt + quadAtt * dist2)); - float ql3 = (diffl3 + specl3) / (1.0 + dist3 * (linAtt + quadAtt * dist3)); - - vec3 light = ambientColor + light1Color * vec3(ql1) + light2Color * vec3(ql2) + light3Color * vec3(ql3); - - - float fogAmount = clamp( (pos.z - fogNear) / (fogFar - fogNear) , 0.0, 1.0); - vec3 lightAO = desaturate(light , fogAmount); - - - gl_FragColor = texColor * gl_Color * vec4(lightAO, 1.0); -} diff --git a/tests/real/extatique/lambert2.vs b/tests/real/extatique/lambert2.vs deleted file mode 100644 index 671188aa..00000000 --- a/tests/real/extatique/lambert2.vs +++ /dev/null @@ -1,27 +0,0 @@ -uniform vec3 light1Pos; -uniform vec3 light2Pos; -uniform vec3 light3Pos; -uniform mat4 invCamMat; - -varying vec3 N; -varying vec3 pos; - -varying vec3 l1_pos; -varying vec3 l2_pos; -varying vec3 l3_pos; - -void main() -{ - - N = gl_NormalMatrix * gl_Normal; - vec4 epos = gl_ModelViewMatrix * gl_Vertex; - - pos = epos.xyz; - l1_pos = (gl_ModelViewMatrix * vec4(light1Pos,1.0)).xyz; - l2_pos = (gl_ModelViewMatrix * vec4(light2Pos,1.0)).xyz; - l3_pos = (gl_ModelViewMatrix * vec4(light3Pos,1.0)).xyz; - - gl_TexCoord[0] = gl_MultiTexCoord0; - gl_FrontColor = gl_Color; - gl_Position = ftransform(); -} \ No newline at end of file diff --git a/tests/real/extatique/loading.frag b/tests/real/extatique/loading.frag deleted file mode 100644 index 5620ffda..00000000 --- a/tests/real/extatique/loading.frag +++ /dev/null @@ -1,31 +0,0 @@ -uniform sampler2D tex; -uniform sampler3D gammaRamp; - -uniform float blurType; -uniform float blurAmount; - - -void main() -{ - vec2 p = gl_TexCoord[0].xy; - - vec4 blur = ( texture2DLod(tex, p, 7.0) - + texture2DLod(tex, p, 6.0) - + texture2DLod(tex, p, 5.0) - + texture2DLod(tex, p, 4.0) - + texture2DLod(tex, p, 3.0) - + texture2DLod(tex, p, 2.0) - + texture2DLod(tex, p, 1.0)) * vec4(0.142857); /* 1/7 */ - - vec4 center = texture2D(tex, p); - - - vec4 blurred = (vec4(1.0) - (vec4(1.0) - blur) * (vec4(1.0) - center)); - vec4 blurred2 = blurred * mix( blurred, vec4(1.0), blurType); - - vec4 uncorrected = mix(center, blurred2, blurAmount); - - /* gamma correction */ - - gl_FragColor = texture3D(gammaRamp, uncorrected.xyz); -} diff --git a/tests/real/extatique/loading.vs b/tests/real/extatique/loading.vs deleted file mode 100644 index 623bdcb4..00000000 --- a/tests/real/extatique/loading.vs +++ /dev/null @@ -1,5 +0,0 @@ -void main() -{ - gl_TexCoord[0] = gl_MultiTexCoord0; - gl_Position = gl_Vertex; -} \ No newline at end of file diff --git a/tests/real/extatique/log.frag b/tests/real/extatique/log.frag deleted file mode 100644 index f3591887..00000000 --- a/tests/real/extatique/log.frag +++ /dev/null @@ -1,20 +0,0 @@ -uniform sampler2D tex; -uniform float invGamma; - -const vec3 LUMINANCECONV = vec3(0.11,0.6,0.29); -void main() -{ - vec2 p = gl_TexCoord[0].xy; - - - - vec3 sample = texture2D(tex, p).xyz; - - - sample = log2(sample + vec3(1.0)); - float luminance = dot(LUMINANCECONV, sample); - - vec3 sampleC = sample * vec3(pow(luminance,invGamma)); - - gl_FragColor = gl_Color * vec4(sampleC,1.0); -} \ No newline at end of file diff --git a/tests/real/extatique/log.vs b/tests/real/extatique/log.vs deleted file mode 100644 index e56b9174..00000000 --- a/tests/real/extatique/log.vs +++ /dev/null @@ -1,6 +0,0 @@ -void main() -{ - gl_TexCoord[0] = gl_MultiTexCoord0; - gl_FrontColor = gl_Color; - gl_Position = ftransform(); -} \ No newline at end of file diff --git a/tests/real/extatique/particle.frag b/tests/real/extatique/particle.frag deleted file mode 100644 index 226798f1..00000000 --- a/tests/real/extatique/particle.frag +++ /dev/null @@ -1,8 +0,0 @@ -uniform sampler2D tex; -uniform float intensity; - -void main() -{ - vec2 p = gl_TexCoord[0].xy; - gl_FragColor = vec4(vec3(intensity), 1.0) * gl_Color * texture2D(tex, p); -} \ No newline at end of file diff --git a/tests/real/extatique/particle.vs b/tests/real/extatique/particle.vs deleted file mode 100644 index 1733b96c..00000000 --- a/tests/real/extatique/particle.vs +++ /dev/null @@ -1,17 +0,0 @@ -uniform float minDist; -uniform float maxDist; -uniform float minSize; -uniform float maxSize; - -void main() -{ - gl_TexCoord[0] = gl_MultiTexCoord0; - - vec4 pos = ftransform(); - gl_Position = pos; - - float f = (pos.z - minDist) / (maxDist - minDist); - - gl_FrontColor = gl_Color * vec4(vec3(1), f); - gl_PointSize = minSize + maxSize * f; -} \ No newline at end of file diff --git a/tests/real/extatique/progress.frag b/tests/real/extatique/progress.frag deleted file mode 100644 index 12e5dfdc..00000000 --- a/tests/real/extatique/progress.frag +++ /dev/null @@ -1,58 +0,0 @@ -uniform sampler2D tex; -uniform float progression; - -vec3 desaturate(vec3 c, float s) -{ - return mix( c, vec3(dot(vec3(0.33), c)), s); -} - -void main() -{ - float A = 3.1415 * 0.5; - float TOUR = 13.0; - - float t = gl_TexCoord[0].y; - float s = gl_TexCoord[0].x + 0.15 * sin(t * 2.0 * 3.1415); - - float v = smoothstep(0.0,0.1,t) - smoothstep(0.9,1.0,t); - - float center1 = 0.5 + 0.5 * sin(TOUR * t); - float distu1 = abs(center1 - s); - float value1 = sqrt(max(0.0, 2.5 - (9.0 - 3.0 * abs(cos(TOUR * t))) * distu1)); - float alpha1 = value1 *max(0.0,-cos(TOUR * t)); - - float center2 = 0.5 + 0.5 * sin(TOUR * t + A); - float distu2 = abs(center2 - s); - float value2 = sqrt(max(0.0, 2.5 - (9.0 - 3.0 * abs(cos(TOUR * t + A))) * distu2)); - float alpha2 = value2 *max(0.0,-cos(TOUR * t + A)); - - float center3 = 0.5 + 0.5 * sin(TOUR * t + A * 2.0); - float distu3 = abs(center3 - s); - float value3 = sqrt(max(0.0, 2.5 - (9.0 - 3.0 * abs(cos(TOUR * t + A * 2.0))) * distu3)); - float alpha3 = value3 *max(0.0,-cos(TOUR * t + A * 2.0)); - - float center4 = 0.5 + 0.5 * sin(TOUR * t + A * 3.0); - float distu4 = abs(center4 - s); - float value4 = sqrt(max(0.0, 2.5 - (9.0 - 3.0 * abs(cos(TOUR * t + A * 3.0))) * distu4)); - float alpha4 = value4 * max(0.0, -cos(TOUR * t + A * 3.0)); - - const float desat = 0.3; - float refs1 = (gl_TexCoord[0].x + 0.51) / 2.0; - float refs2 = (gl_TexCoord[0].x + 0.44) / 2.0; - float refs3 = (gl_TexCoord[0].x + 0.55) / 2.0; - float refs4 = (gl_TexCoord[0].x + 0.48) / 2.0; - vec3 c1 = (refs1 < progression) ? desaturate(vec3(1.0, 0.59, 1.0), desat) : vec3(0.3,0.3,0.3); - vec3 c2 = (refs2 < progression) ? desaturate(vec3(0.6,0.18,0.19), desat) : vec3(0.4,0.4,0.4); - vec3 c3 = (refs3 < progression) ? desaturate(vec3(0.97,0.62,118.0/255.0), desat) : vec3(0.6,0.6,0.6); - vec3 c4 = (refs4 < progression) ? desaturate(vec3(254.0/255.0,79.0/255.0,138.0/255.0), desat) : vec3(0.5,0.5,0.5); - - vec4 final_color = vec4(alpha1 * c1 - + alpha2 * c2 - + alpha3 * c3 - + alpha4 * c4, v * (alpha1 + alpha2 + alpha3 + alpha4)); - - vec2 p = gl_TexCoord[0].xy; - gl_FragColor = gl_Color * final_color * mix(texture2D(tex, p * vec2(1.5, 4.5)), vec4(1.0,1.0,1.0,1.0), 0.5); -} - - diff --git a/tests/real/extatique/progress.vs b/tests/real/extatique/progress.vs deleted file mode 100644 index e56b9174..00000000 --- a/tests/real/extatique/progress.vs +++ /dev/null @@ -1,6 +0,0 @@ -void main() -{ - gl_TexCoord[0] = gl_MultiTexCoord0; - gl_FrontColor = gl_Color; - gl_Position = ftransform(); -} \ No newline at end of file diff --git a/tests/real/extatique/put.frag b/tests/real/extatique/put.frag deleted file mode 100644 index c7855f3d..00000000 --- a/tests/real/extatique/put.frag +++ /dev/null @@ -1,4 +0,0 @@ -void main() -{ - gl_FragColor = gl_Color; -} \ No newline at end of file diff --git a/tests/real/extatique/put.vs b/tests/real/extatique/put.vs deleted file mode 100644 index c7e0c31b..00000000 --- a/tests/real/extatique/put.vs +++ /dev/null @@ -1,5 +0,0 @@ -void main() -{ - gl_FrontColor = gl_Color; - gl_Position = ftransform(); -} \ No newline at end of file diff --git a/tests/real/extatique/raymarch.frag b/tests/real/extatique/raymarch.frag deleted file mode 100644 index 2d3ff5bf..00000000 --- a/tests/real/extatique/raymarch.frag +++ /dev/null @@ -1,59 +0,0 @@ -varying vec3 dir; - - -float flr(vec3 p, float f) -{ - return abs(f - p.y); -} - -float sph(vec3 p, vec4 spr) -{ - return length(spr.xyz - p) - spr.w; -} - -float iso_tore(vec3 p, vec3 center, float r1, float r2) -{ - p -= center; - float xx = sqrt(p.x * p.x + p.z * p.z) - r1; - float dist = sqrt(xx * xx + p.y * p.y) - r2; - return mix(dist, dist, 0.9); -} - -float scene(vec3 p) -{ - float d = iso_tore(p, vec3(0,0,15), 2.0, 0.5); - return d; -} - -vec3 getN(vec3 p) -{ - float eps = 0.01; - return normalize(vec3( - scene(p+vec3(eps,0,0))-scene(p-vec3(eps,0,0)), - scene(p+vec3(0,eps,0))-scene(p-vec3(0,eps,0)), - scene(p+vec3(0,0,eps))-scene(p-vec3(0,0,eps)) - )); -} - - -void main() -{ - float g,d = 0.0; - vec3 p = vec3(0); - vec3 ndir = normalize(dir); - - for(int i = 0; i < 64; i++) - { - d = scene(p); - p = p + d * ndir; - } - if(d > 1.0) - { - gl_FragColor = vec4(1.0,0.0,0.0,1.0); - - return; - } - - vec3 n = getN(p); - gl_FragColor = vec4(n, 1.0); -} diff --git a/tests/real/extatique/raymarch.vs b/tests/real/extatique/raymarch.vs deleted file mode 100644 index 32080f06..00000000 --- a/tests/real/extatique/raymarch.vs +++ /dev/null @@ -1,9 +0,0 @@ -varying vec3 dir; - -void main() -{ - vec4 pos = ftransform(); - gl_Position = pos; - dir = pos.xyz; - -} diff --git a/tests/real/extatique/scene30.frag b/tests/real/extatique/scene30.frag deleted file mode 100644 index 53e8becc..00000000 --- a/tests/real/extatique/scene30.frag +++ /dev/null @@ -1,41 +0,0 @@ -uniform sampler2D tex; -uniform float angle; -uniform float time; -varying vec3 pos; -varying vec3 N; - - -vec4 getEnvColor(vec3 p) -{ - float az = atan(p.x, p.y + 0.01); - float ax = -pos.z; - - vec4 sample = vec4(0.0); - - for (int i = 0; i < 8; ++i) - { - float fi = float(i); - float s = ax * 2.0 / (1.0 + fi) + time * 0.01 * (2.0 + fi); - float t = angle + (2.5) * az / 3.14159; - - sample += texture2D(tex, vec2(s,t)) / (1.0 + 0.3 * fi); - } - return sample; -} - -vec3 diffuseLighting(vec3 pos, vec3 nml) -{ - float df1 = 0.8 * max(0.0, dot(nml, vec3(1.0,0.2, 0.0))); - float df2 = 0.2 * max(0.0, dot(nml, vec3(-1.0,-0.1, 0.0))); - vec3 diffuse = vec3(df1) * vec3(0.8,0.7,0.6) + vec3(df2) * vec3(0.6,0.7,0.8); - return diffuse; -} - -void main() -{ - vec3 nml = normalize(N); - vec3 R = reflect(-pos, normalize(nml)); - vec3 envColor = getEnvColor(R).xyz * mix(vec3(1.0), gl_Color.xyz, 0.4); - vec3 diffuseColor = getEnvColor(pos).xyz * gl_Color.xyz; - gl_FragColor = vec4( diffuseColor + envColor, 1.0); -} \ No newline at end of file diff --git a/tests/real/extatique/scene30.vs b/tests/real/extatique/scene30.vs deleted file mode 100644 index a38f6f0f..00000000 --- a/tests/real/extatique/scene30.vs +++ /dev/null @@ -1,11 +0,0 @@ -varying vec3 pos; -varying vec3 N; - -void main() -{ - pos = (gl_ModelViewMatrix * gl_Vertex).xyz; - gl_Position = ftransform(); - gl_FrontColor = gl_Color; - N = gl_NormalMatrix * gl_Normal; - -} \ No newline at end of file diff --git a/tests/real/extatique/scene40.frag b/tests/real/extatique/scene40.frag deleted file mode 100644 index 4c8325c8..00000000 --- a/tests/real/extatique/scene40.frag +++ /dev/null @@ -1,177 +0,0 @@ -uniform sampler2D tex; -varying vec3 wpos; -varying vec3 N; -uniform vec3 eyePos; -uniform float radius; -uniform float medium; -uniform vec3 center; -uniform vec3 light1; -uniform vec3 light2; -uniform vec3 light3; -uniform vec3 light4; - - -vec3 getEnvColor(vec3 pos, vec2 coord) -{ - vec3 color = texture2D(tex, coord * 0.05).xyz; - - vec3 light1_dist = pos * 0.1 - vec3(-0.5,-0.5,-0.5); - vec3 light2_dist = pos * 0.1 - vec3(+0.5,+0.5,-0.5); - vec3 light3_dist = pos * 0.1 - vec3(-0.5,+0.5,+0.5); - vec3 light4_dist = pos * 0.1 - vec3(+0.5,-0.5,+0.5); - - vec3 clight1 = light1 * vec3(max(0.0, 1.25 - 1.0 * dot(light1_dist, light1_dist))); - vec3 clight2 = light2 * vec3(max(0.0, 1.25 - 1.0 * dot(light2_dist, light2_dist))); - vec3 clight3 = light3 * vec3(max(0.0, 1.25 - 1.0 * dot(light3_dist, light3_dist))); - vec3 clight4 = light4 * vec3(max(0.0, 1.25 - 1.0 * dot(light4_dist, light4_dist))); - - - return color + clight1 + clight2 + clight3 + clight4; -} - -float exp3(float x) -{ - float y = max(-1.15365, x); - return 1.0 + y * (1.0 + y * (0.5 + y * 0.33333333)); -} - -vec3 rayColor(vec3 startPos, vec3 startDir) -{ - vec3 total = vec3(0.0); - vec3 p = startPos; - vec3 dir = startDir; - vec3 blend = vec3(0.5); - vec3 dpos; - vec3 color = vec3(0.0); - - vec3 ray; - vec3 nml; - vec2 coord; - vec3 newdir; - vec3 sample; - - for (int i = 0; i < 1; ++i) - { - ray = 40.0 * dir; - nml = vec3(0.0); - coord = vec2(0.0); - dpos = p + ray; - - if (abs(dpos.x) > 10.0) - { - if (dpos.x > 10.0) - { - ray *= ((9.99 - p.x) / ray.x); - nml = vec3(-1.0,0.0,0.0); - dpos = ray + p; - coord = dpos.yz; - color = getEnvColor(dpos, coord); - } - else - { - ray *= ((-9.99 - p.x) / ray.x); - nml = vec3(1.0,0.0,0.0); - - - dpos = ray + p; - coord = dpos.yz * vec2(-1.0,1.0); - color = getEnvColor(dpos, coord); - } - } - - if (abs(dpos.y) > 10.0) - { - if (dpos.y > 10.0) - { - ray *= ((9.99 - p.y) / ray.y); - nml = vec3(0.0,-1.0,0.0); - - - dpos = ray + p; - coord = dpos.xz * vec2(-1.0,1.0); - color = getEnvColor(dpos, coord); - } - else - { - ray *= ((-9.99 - p.y) / ray.y); - nml = vec3(0.0,1.0,0.0); - - dpos = ray + p; - coord = dpos.xz; - color = getEnvColor(dpos, coord); - } - } - - if (abs(dpos.z) > 10.0) - { - if (dpos.z > 10.0) - { - ray *= ((9.99 - p.z) / ray.z); - nml = vec3(0.0,0.0,-1.0); - dpos = ray + p; - coord = dpos.xy * vec2(-1.0,1.0); - color = getEnvColor(dpos, coord); - } - else - { - ray *= ((-9.99 - p.z) / ray.z); - nml = vec3(0.0,0.0,1.0); - dpos = ray + p; - coord = dpos.xy; - color = getEnvColor(dpos, coord); - } - } - - sample = color * vec3(exp3(-length(ray) * 0.04)); - - total += sample * blend; - blend *= sample; - - newdir = reflect(dir, nml); - - p = dpos; - dir = newdir; - } - return total; -} - - - -void snell(vec3 dir, vec3 normal, float n1, float n2, out vec3 reflectionDir, out vec3 refractionDir, out float cost2) -{ - float n1n2 = n1 / n2; - float cost1 = dot(-dir, normal); - cost2 = sqrt(1.0 - n1n2 * n1n2 * (1.0 - cost1 * cost1)); - - reflectionDir = dir + normal * (2.0 * cost1); - refractionDir = dir * n1n2 + normal * (cost2 + n1n2 * cost1); -} - -void main() -{ - vec3 nml = normalize(N); - vec3 dir = normalize(wpos - eyePos); - - - vec3 R; - vec3 RE; - float cost2, fdummy; - - - snell(dir, nml, 1.0, medium + 0.1, R, RE, cost2); - - float dist = 2.0 * cost2 * radius; - vec3 p2 = wpos + RE * vec3(dist); - vec3 nml2 = -(p2 - center) / radius; - vec3 Rdummy, Rout; - snell(RE, nml2, medium + 0.3, 1.0, Rdummy, Rout, fdummy); - float fact = 2.0 * exp3(-dot(dist,dist) * 0.2); - vec3 diffracted = rayColor(p2, Rout) * vec3(fact); - - - vec3 specular = rayColor(wpos, R) * gl_Color.xyz; - - - - gl_FragColor = gl_Color * vec4( specular + diffracted, 1.0); -} \ No newline at end of file diff --git a/tests/real/extatique/scene40.vs b/tests/real/extatique/scene40.vs deleted file mode 100644 index 6487b04c..00000000 --- a/tests/real/extatique/scene40.vs +++ /dev/null @@ -1,13 +0,0 @@ - -varying vec3 wpos; -varying vec3 N; -uniform vec3 eyePos; - -void main() -{ - wpos = gl_Vertex.xyz; - gl_Position = ftransform(); - gl_FrontColor = gl_Color; - N = gl_Normal; - -} \ No newline at end of file diff --git a/tests/real/extatique/scene45.frag b/tests/real/extatique/scene45.frag deleted file mode 100644 index a2193cd0..00000000 --- a/tests/real/extatique/scene45.frag +++ /dev/null @@ -1,14 +0,0 @@ -uniform sampler2D tex; -uniform float time; - - -void main() -{ - vec2 p = gl_TexCoord[0].xy; - float u = atan(p.y, p.x + 0.0001) * 1.0 / 3.1415926; - float v = 0.002 / (0.01 + length(p)) - time * 0.1; - vec4 space = texture2D(tex, vec2(u,v)) - + vec4(0.5) * texture2D(tex, vec2(u,v * 4.0)) - + vec4(0.25) * texture2D(tex, vec2(u,v * 16.0)); - gl_FragColor = gl_Color * space; -} \ No newline at end of file diff --git a/tests/real/extatique/scene45.vs b/tests/real/extatique/scene45.vs deleted file mode 100644 index e56b9174..00000000 --- a/tests/real/extatique/scene45.vs +++ /dev/null @@ -1,6 +0,0 @@ -void main() -{ - gl_TexCoord[0] = gl_MultiTexCoord0; - gl_FrontColor = gl_Color; - gl_Position = ftransform(); -} \ No newline at end of file diff --git a/tests/real/extatique/skybox.frag b/tests/real/extatique/skybox.frag deleted file mode 100644 index 7da9bd7c..00000000 --- a/tests/real/extatique/skybox.frag +++ /dev/null @@ -1,32 +0,0 @@ -uniform sampler2D tex; -uniform float angle; -uniform float time; -varying vec3 pos; - - - -vec4 getEnvColor(vec3 p) -{ - float az = atan(p.x, p.y + 0.01); - float ax = -pos.z; - - vec4 sample = vec4(0.0); - - for (int i = 0; i < 8; ++i) - { - float fi = float(i); - float s = ax * 1.0 / (1.0 + fi) + time * 0.01 * (2.0 + fi); - float t = angle + (2.5) * az / 3.14159; - - sample += texture2D(tex, vec2(s,t)) / (1.0 + 0.3 * fi); - } - return sample; -} - - - -void main() -{ - vec4 env = getEnvColor(pos); - gl_FragColor = vec4(env.xyz, 1.0); -} \ No newline at end of file diff --git a/tests/real/extatique/skybox.vs b/tests/real/extatique/skybox.vs deleted file mode 100644 index 3655c481..00000000 --- a/tests/real/extatique/skybox.vs +++ /dev/null @@ -1,7 +0,0 @@ -varying vec3 pos; - -void main() -{ - pos = (gl_ModelViewMatrix * gl_Vertex).xyz; - gl_Position = ftransform(); -} \ No newline at end of file diff --git a/tests/real/extatique/skybox2.frag b/tests/real/extatique/skybox2.frag deleted file mode 100644 index 62b24b83..00000000 --- a/tests/real/extatique/skybox2.frag +++ /dev/null @@ -1,142 +0,0 @@ -varying vec3 wpos; - -uniform vec3 eyePos; - -uniform sampler2D tex; -uniform vec3 light1; -uniform vec3 light2; -uniform vec3 light3; -uniform vec3 light4; - - -vec3 getEnvColor(vec3 pos, vec2 coord) -{ - vec3 color = texture2D(tex, coord * 0.05).xyz; - - vec3 light1_dist = pos * 0.1 - vec3(-0.5,-0.5,-0.5); - vec3 light2_dist = pos * 0.1 - vec3(+0.5,+0.5,-0.5); - vec3 light3_dist = pos * 0.1 - vec3(-0.5,+0.5,+0.5); - vec3 light4_dist = pos * 0.1 - vec3(+0.5,-0.5,+0.5); - - vec3 clight1 = light1 * vec3(max(0.0, 1.25 - 1.0 * dot(light1_dist, light1_dist))); - vec3 clight2 = light2 * vec3(max(0.0, 1.25 - 1.0 * dot(light2_dist, light2_dist))); - vec3 clight3 = light3 * vec3(max(0.0, 1.25 - 1.0 * dot(light3_dist, light3_dist))); - vec3 clight4 = light4 * vec3(max(0.0, 1.25 - 1.0 * dot(light4_dist, light4_dist))); - - - return color + clight1 + clight2 + clight3 + clight4; -} - -float exp3(float x) -{ - float y = max(-1.15365, x); - return 1.0 + y * (1.0 + y * (0.5 + y * 0.33333333)); -} - -vec3 rayColor(vec3 startPos, vec3 startDir) -{ - vec3 total = vec3(0.0); - vec3 p = startPos; - vec3 dir = startDir; - vec3 blend = vec3(0.5); - vec3 dpos; - vec3 color = vec3(0.0); - - vec3 ray; - vec3 nml; - vec2 coord; - vec3 newdir; - vec3 sample; - - for (int i = 0; i < 3; ++i) - { - ray = 50.0 * dir; - nml = vec3(0.0); - coord = vec2(0.0); - dpos = p + ray; - - if (abs(dpos.x) > 10.0) - { - if (dpos.x > 10.0) - { - ray *= ((9.99 - p.x) / ray.x); - nml = vec3(-1.0,0.0,0.0); - dpos = ray + p; - coord = dpos.yz; - color = getEnvColor(dpos, coord); - } - else - { - ray *= ((-9.99 - p.x) / ray.x); - nml = vec3(1.0,0.0,0.0); - - - dpos = ray + p; - coord = dpos.yz * vec2(-1.0,1.0); - color = getEnvColor(dpos, coord); - } - } - - if (abs(dpos.y) > 10.0) - { - if (dpos.y > 10.0) - { - ray *= ((9.99 - p.y) / ray.y); - nml = vec3(0.0,-1.0,0.0); - - - dpos = ray + p; - coord = dpos.xz * vec2(-1.0,1.0); - color = getEnvColor(dpos, coord); - } - else - { - ray *= ((-9.99 - p.y) / ray.y); - nml = vec3(0.0,1.0,0.0); - - dpos = ray + p; - coord = dpos.xz; - color = getEnvColor(dpos, coord); - } - } - - if (abs(dpos.z) > 10.0) - { - if (dpos.z > 10.0) - { - ray *= ((9.99 - p.z) / ray.z); - nml = vec3(0.0,0.0,-1.0); - dpos = ray + p; - coord = dpos.xy * vec2(-1.0,1.0); - color = getEnvColor(dpos, coord); - } - else - { - ray *= ((-9.99 - p.z) / ray.z); - nml = vec3(0.0,0.0,1.0); - dpos = ray + p; - coord = dpos.xy; - color = getEnvColor(dpos, coord); - } - } - - sample = color * vec3(exp3(-length(ray) * 0.04)); - - total += sample * blend; - blend *= sample; - - newdir = reflect(dir, nml); - - p = dpos; - dir = newdir; - } - return total; -} - - -void main() -{ - vec3 env = rayColor(eyePos, normalize(wpos - eyePos)); - - gl_FragColor = gl_Color * vec4(env, 1.0); -} \ No newline at end of file diff --git a/tests/real/extatique/skybox2.vs b/tests/real/extatique/skybox2.vs deleted file mode 100644 index 6e7e3412..00000000 --- a/tests/real/extatique/skybox2.vs +++ /dev/null @@ -1,13 +0,0 @@ -varying vec3 wpos; - -uniform vec3 eyePos; - -void main() -{ - wpos = gl_Vertex.xyz; - /* pos = (gl_ModelViewMatrix * gl_Vertex).xyz; */ - gl_FrontColor = gl_Color; - /* gl_TexCoord[0] = gl_MultiTexCoord0; */ - - gl_Position = ftransform(); -} \ No newline at end of file diff --git a/tests/real/extatique/snake.frag b/tests/real/extatique/snake.frag deleted file mode 100644 index 9d1989f7..00000000 --- a/tests/real/extatique/snake.frag +++ /dev/null @@ -1,18 +0,0 @@ -varying vec3 normal; -varying float profondeur; - -vec4 desaturate(vec4 color, float t) -{ - vec3 grey = vec3(dot(vec3(0.33), color.rgb)); - return vec4(mix(color.rgb, grey, t), color.a); -} - -void main() -{ - vec3 N = normal; - - vec3 e = vec3(0.0,0.0,-1.0); - float diffuse = max(0.0, dot(N, e)); - vec4 C = gl_Color * vec4(0.1 + 0.9 * vec3(diffuse), diffuse); - gl_FragColor = C * exp( -profondeur * 0.1 ); -} \ No newline at end of file diff --git a/tests/real/extatique/snake.vs b/tests/real/extatique/snake.vs deleted file mode 100644 index 90e19bd1..00000000 --- a/tests/real/extatique/snake.vs +++ /dev/null @@ -1,12 +0,0 @@ -varying vec3 normal; -varying float profondeur; - -void main() -{ - gl_FrontColor = gl_Color; - - normal = normalize(gl_Normal); - gl_Position = ftransform(); - - profondeur = gl_Position.z; -} \ No newline at end of file diff --git a/tests/real/extatique/water.frag b/tests/real/extatique/water.frag deleted file mode 100644 index c3b6dcf0..00000000 --- a/tests/real/extatique/water.frag +++ /dev/null @@ -1,84 +0,0 @@ -uniform sampler2D tex; -uniform sampler2D texu; -uniform sampler2D texv; -uniform float spacing; -uniform float ratio; - -void main() -{ - vec2 p0 = gl_TexCoord[0].xy; - - vec4 total = texture2D(tex, p0 * 2.5); - vec2 v0 = vec2(spacing) * (vec2(texture2D(texu, p0).x, texture2D(texv, p0).x)); - - vec2 p1 = p0 - v0; - total = texture2D(tex, p1) * 0.9755297; - vec2 v1 = vec2(spacing) *(vec2(texture2D(texu, p1).x, texture2D(texv, p1).x)); - - vec2 p2 = p1 - v1; - total += texture2D(tex, p2) * 0.9045139; - vec2 v2 = vec2(spacing) *(vec2(texture2D(texu, p2).x, texture2D(texv, p2).x)); - - vec2 p3 = p2 - v2; - total += texture2D(tex, p1) * 0.7939039; - vec2 v3 = vec2(spacing) *(vec2(texture2D(texu, p3).x, texture2D(texv, p3).x)); - - vec2 p4 = p3 - v3; - total += texture2D(tex, p2) * 0.6545261; - vec2 v4 = vec2(spacing) *(vec2(texture2D(texu, p4).x, texture2D(texv, p4).x)); - - vec2 p5 = p4 - v4; - total += texture2D(tex, p1) * 0.5000232; - vec2 v5 = vec2(spacing) *(vec2(texture2D(texu, p5).x, texture2D(texv, p5).x)); - - vec2 p6 = p5 - v5; - total += texture2D(tex, p2) * 0.3455179; - vec2 v6 = vec2(spacing) *(vec2(texture2D(texu, p6).x, texture2D(texv, p6).x)); - - vec2 p7 = p6 - v6; - total += texture2D(tex, p1) * 0.2061336; - vec2 v7 = vec2(spacing) *(vec2(texture2D(texu, p7).x, texture2D(texv, p7).x)); - - vec2 p8 = p7 - v7; - total += texture2D(tex, p2) * 0.0955133; - - - - vec2 p12 = p0 + v0; - total += texture2D(tex, p12) * 0.9755297; - vec2 v12 = vec2(spacing) *(vec2(texture2D(texu, p12).x, texture2D(texv, p12).x)); - - vec2 p22 = p12 + v12; - total += texture2D(tex, p22) * 0.9045139; - vec2 v22 = vec2(spacing) *(vec2(texture2D(texu, p22).x, texture2D(texv, p22).x)); - - vec2 p32 = p22 + v22; - total += texture2D(tex, p12) * 0.7939039; - vec2 v32 = vec2(spacing) *(vec2(texture2D(texu, p32).x, texture2D(texv, p32).x)); - - vec2 p42 = p32 + v32; - total += texture2D(tex, p22) * 0.6545261; - vec2 v42 = vec2(spacing) *(vec2(texture2D(texu, p42).x, texture2D(texv, p42).x)); - - vec2 p52 = p42 + v42; - total += texture2D(tex, p12) * 0.5000232; - vec2 v52 = vec2(spacing) *(vec2(texture2D(texu, p52).x, texture2D(texv, p52).x)); - - vec2 p62 = p52 + v52; - total += texture2D(tex, p22) * 0.3455179; - vec2 v62 = vec2(spacing) *(vec2(texture2D(texu, p62).x, texture2D(texv, p62).x)); - - vec2 p72 = p62 + v62; - total += texture2D(tex, p12) * 0.2061336; - vec2 v72 = vec2(spacing) *(vec2(texture2D(texu, p72).x, texture2D(texv, p72).x)); - - vec2 p82 = p72 + v72; - total += texture2D(tex, p22) * 0.0955133; - - vec2 dist = (p0 - vec2(0.5, 0.5)) * vec2(1.0,ratio); - vec4 darkF = vec4(max(0.0, 1.0 - 2.5 * dot(dist,dist))); - - vec4 finalColor = gl_Color * total * vec4(0.1) * darkF; - - gl_FragColor = finalColor; -} diff --git a/tests/real/extatique/water.vs b/tests/real/extatique/water.vs deleted file mode 100644 index e56b9174..00000000 --- a/tests/real/extatique/water.vs +++ /dev/null @@ -1,6 +0,0 @@ -void main() -{ - gl_TexCoord[0] = gl_MultiTexCoord0; - gl_FrontColor = gl_Color; - gl_Position = ftransform(); -} \ No newline at end of file diff --git a/tests/real/fly.frag b/tests/real/fly.frag deleted file mode 100644 index 7991ac02..00000000 --- a/tests/real/fly.frag +++ /dev/null @@ -1,20 +0,0 @@ -uniform vec2 resolution; -uniform float time; -uniform sampler2D tex0; -uniform sampler2D tex1; -uniform sampler2D tex2; -void main(void) -{ - vec2 p = -1.0 + 2.0 * gl_FragCoord.xy / resolution.xy; - vec2 uv; - - float an = time*.25; - - float x = p.x*cos(an)-p.y*sin(an); - float y = p.x*sin(an)+p.y*cos(an); - - uv.x = .25*x/abs(y); - uv.y = .20*time + .25/abs(y); - - gl_FragColor = vec4(texture2D(tex0,uv).xyz * y*y, 1.0); -} diff --git a/tests/real/gfx monitor/ambiantocclusion.vs b/tests/real/gfx monitor/ambiantocclusion.vs deleted file mode 100644 index b0705e06..00000000 --- a/tests/real/gfx monitor/ambiantocclusion.vs +++ /dev/null @@ -1,9 +0,0 @@ -// VertexProgram -// This program is for 16:10 aspect ratio -varying vec3 org,dir; -void main() -{ - gl_Position=gl_Vertex; - org=vec3(0,0,0); - dir=normalize(-vec3(-gl_Vertex.x*1.6,-gl_Vertex.y,1)); -} \ No newline at end of file diff --git a/tests/real/gfx monitor/distancefieldRaytrace.frag b/tests/real/gfx monitor/distancefieldRaytrace.frag deleted file mode 100644 index d3e2583c..00000000 --- a/tests/real/gfx monitor/distancefieldRaytrace.frag +++ /dev/null @@ -1,99 +0,0 @@ -// FragmentProgram -// based on iq/rgba 's seminar -// "Rendering Worlds with Two Triangles with raytracing on the GPU in 4096 bytes" -// at NVSCENE 08 -// I have watched this great seminar, I have coded the below test program. ;) -// [http://www.rgba.org/iq/] - -varying vec3 org,dir; -float flr(vec3 p, float f) -{ - return abs(f - p.y); -} - -float sph(vec3 p, vec4 spr) -{ - return length(spr.xyz-p) - spr.w; -} - -float cly(vec3 p, vec4 cld) -{ - return length(vec2(cld.x + 0.5 * sin(p.y + p.z * 2.0), cld.z) - p.xz) - cld.w; -} - -float scene(vec3 p) -{ - float d = flr(p, -5.0); - d = min(d, flr(p, 5.0)); - d = min(d, sph(p, vec4( 0,-2, 15, 1.5))); - d = min(d, sph(p, vec4(-8, 0, 20, 2.0))); - d = min(d, sph(p, vec4(-5, 4, 15, 0.5))); - d = min(d, sph(p, vec4(-1, 3, 15, 2.0))); - d = min(d, sph(p, vec4( 2,-3, 15, 0.5))); - d = min(d, cly(p, vec4(10, 0, 20, 1.0))); - d = min(d, cly(p, vec4( 4, 0, 15, 1.0))); - d = min(d, cly(p, vec4( 0, 0, 20, 1.0))); - d = min(d, cly(p, vec4(-2, 0, 25, 1.0))); - d = min(d, cly(p, vec4(-6, 0, 30, 1.0))); - d = min(d, cly(p, vec4(-12,0, 35, 1.0))); - return d; -} - -vec3 getN(vec3 p) -{ - float eps = 0.01; - return normalize(vec3( - scene(p+vec3(eps,0,0))-scene(p-vec3(eps,0,0)), - scene(p+vec3(0,eps,0))-scene(p-vec3(0,eps,0)), - scene(p+vec3(0,0,eps))-scene(p-vec3(0,0,eps)) - )); -} - -float AO(vec3 p,vec3 n) -{ - float dlt = 0.5; - float oc = 0.0, d = 1.0; - for(int i = 0; i < 6; i++) - { - oc += (float(i) * dlt - scene(p + n * float(i) * dlt)) / d; - d *= 2.0; - } - return 1.0 - oc; -} - -void main() -{ - float g,d = 0.0; - vec3 p = org; - for(int i = 0; i < 64; i++) - { - d = scene(p); - p = p + d * dir; - } - if(d > 1.0) - { - gl_FragColor = vec4(0,0,0,1); - return; - } - vec3 n = getN(p); - float a = AO(p,n); - vec3 s = vec3(0,0,0); - vec3 lp[3],lc[3]; - lp[0] = vec3(-4,0,4); - lp[1] = vec3(2,3,8); - lp[2] = vec3(4,-2,24); - lc[0] = vec3(1.0,0.5,0.4); - lc[1] = vec3(0.4,0.5,1.0); - lc[2] = vec3(0.2,1.0,0.5); - for(int i = 0; i < 3; i++) - { - vec3 l,lv; - lv = lp[i] - p; - l = normalize(lv); - g = length(lv); - g = max(0.0,dot(l,n)) / g * float(10); - s += g * lc[i]; - } - float fg = min(1.0,20.0 / length(p - org)); - gl_FragColor = vec4(s * a,1) * fg * fg; -} diff --git a/tests/real/gfx monitor/distancefieldRaytrace.vs b/tests/real/gfx monitor/distancefieldRaytrace.vs deleted file mode 100644 index a3751b72..00000000 --- a/tests/real/gfx monitor/distancefieldRaytrace.vs +++ /dev/null @@ -1,9 +0,0 @@ -// VertexProgram - -varying vec3 org,dir; -void main() -{ - gl_Position=gl_Vertex; - org=vec3(0,0,0); - dir=normalize(vec3(gl_Vertex.x*1.6,gl_Vertex.y,2)); -} diff --git a/tests/real/gfx monitor/gradation.frag b/tests/real/gfx monitor/gradation.frag deleted file mode 100644 index f454129e..00000000 --- a/tests/real/gfx monitor/gradation.frag +++ /dev/null @@ -1,10 +0,0 @@ -// FragmentProgram - -varying vec4 p; - -void main() -{ - float g = p.y * 0.5 + 0.5; - gl_FragColor = vec4(g,g,g,0); - return; -} \ No newline at end of file diff --git a/tests/real/gfx monitor/gradation.gs b/tests/real/gfx monitor/gradation.gs deleted file mode 100644 index d42b065a..00000000 --- a/tests/real/gfx monitor/gradation.gs +++ /dev/null @@ -1,10 +0,0 @@ -// VertexProgram - -varying vec4 p; - -void main() -{ - gl_Position = gl_Vertex; - p = gl_Vertex; -} - diff --git a/tests/real/gfx monitor/raytrace.vs b/tests/real/gfx monitor/raytrace.vs deleted file mode 100644 index 0a4cc99b..00000000 --- a/tests/real/gfx monitor/raytrace.vs +++ /dev/null @@ -1,10 +0,0 @@ -// VertexProgram -// This program is 16:10 ratio - -varying vec3 org,dir; -void main() -{ - gl_Position=gl_Vertex; - org=vec3(0,0,0); - dir=normalize(-vec3(-gl_Vertex.x*1.6,-gl_Vertex.y,1)); -} \ No newline at end of file diff --git a/tests/real/multitexture.frag b/tests/real/multitexture.frag deleted file mode 100644 index 1436113f..00000000 --- a/tests/real/multitexture.frag +++ /dev/null @@ -1,21 +0,0 @@ -uniform vec2 resolution; -uniform float time; -uniform sampler2D tex0; -uniform sampler2D tex1; - -void main(void) -{ - vec2 p = -1.0 + 2.0 * gl_FragCoord.xy / resolution.xy; - // a rotozoom - vec2 cst = vec2( cos(.5*time), sin(.5*time) ); - mat2 rot = 0.5*cst.x*mat2(cst.x,-cst.y,cst.y,cst.x); - vec3 col1 = texture2D(tex0,rot*p).xyz; - - // scroll - vec3 col2 = texture2D(tex1,0.5*p+sin(0.1*time)).xyz; - - // blend layers - vec3 col = col2*col1; - - gl_FragColor = vec4(col,1.0); -} diff --git a/tests/real/relief_tunnel.frag b/tests/real/relief_tunnel.frag deleted file mode 100644 index c9d3ec2d..00000000 --- a/tests/real/relief_tunnel.frag +++ /dev/null @@ -1,34 +0,0 @@ -uniform vec2 resolution; -uniform float time; -uniform sampler2D tex0; -uniform sampler2D tex1; -uniform sampler2D tex2; -uniform sampler2D tex3; - -void main(void) -{ - vec2 p = -1.0 + 2.0 * gl_FragCoord.xy / resolution.xy; - vec2 uv; - - float r = sqrt( dot(p,p) ); - float a = atan(p.y,p.x) + 0.5*sin(0.5*r-0.5*time); - - float s = 0.5 + 0.5*cos(7.0*a); - s = smoothstep(0.0,1.0,s); - s = smoothstep(0.0,1.0,s); - s = smoothstep(0.0,1.0,s); - s = smoothstep(0.0,1.0,s); - - uv.x = time + 1.0/( r + .2*s); - uv.y = 3.0*a/3.1416; - - float w = (0.5 + 0.5*s)*r*r; - - vec3 col = texture2D(tex0,uv).xyz; - - float ao = 0.5 + 0.5*cos(7.0*a); - ao = smoothstep(0.0,0.4,ao)-smoothstep(0.4,0.7,ao); - ao = 1.0-0.5*ao*r; - - gl_FragColor = vec4(col*w*ao,1.0); -} diff --git a/tests/real/square_tunnel.frag b/tests/real/square_tunnel.frag deleted file mode 100644 index d4710f23..00000000 --- a/tests/real/square_tunnel.frag +++ /dev/null @@ -1,20 +0,0 @@ -uniform vec2 resolution; -uniform float time; -uniform sampler2D tex0; -uniform sampler2D tex1; -uniform sampler2D tex2; -uniform sampler2D tex3; - -void main(void) -{ - vec2 p = -1.0 + 2.0 * gl_FragCoord.xy / resolution.xy; - vec2 uv; - - float r = pow( pow(p.x*p.x,16.0) + pow(p.y*p.y,16.0), 1.0/32.0 ); - uv.x = .5*time + 0.5/r; - uv.y = 1.0*atan(p.y,p.x)/3.1416; - - vec3 col = texture2D(tex0,uv).xyz; - - gl_FragColor = vec4(col*r*r*r,1.0); -} diff --git a/tests/real/the orange guy/ball_pixel.glsl b/tests/real/the orange guy/ball_pixel.glsl deleted file mode 100644 index a1a03a45..00000000 --- a/tests/real/the orange guy/ball_pixel.glsl +++ /dev/null @@ -1,56 +0,0 @@ -const int N_BALLS = 8; /* le nombre de points spirales */ - -uniform vec4 col[N_BALLS]; /* couleurs des points spirales */ -uniform vec3 pos[N_BALLS]; /* position des points spirales */ -uniform float intensity[N_BALLS]; /* "taille" des points spirales */ - - -uniform float localTime; -uniform float progression; - -/* renvoie la couleur de l'image en ce point. - On l'appelle plusieurs fois pour faire des symétries (bourrin !) */ -vec3 coul(vec2 p) -{ - float prog = progression; - float p2 = prog * prog; - float time = localTime; - - vec3 couleur = vec3(0.0,0.0,0.0); - - - float l = min(0.0, 1.5 * progression - 0.5); - - float dist_factor = (6.0 + 3.0 * sin(time)); - - - for (int i = 0; i < N_BALLS; ++i) - { - vec2 diff = (pos[i].xy - p); - float d = dot(diff, diff); /* d = distance entre le pixel et le point spirale i */ - - float angle = atan(diff.y, diff.x); - - /* on accumule la contribution de chaque spirale */ - - float s = cos(5.0 * (angle - (1.0 + float(i) * 0.05 - prog * 1.5 ) * time) + d * dist_factor ); - - s *= min(1.0, abs(0.7 + prog * 0.3 - s) * 15.0); - - float spiral_factor = max(0.0, s * (1.0 - p2) ); - float contrib = spiral_factor * intensity[i] * exp(-0.02 * d) + l; - - couleur += col[i].rgb * contrib; - - } - return couleur; -} - -void main() -{ - vec2 p = gl_TexCoord[0].xy * 0.7; - - vec3 couleur = coul(p); - - gl_FragColor = vec4( couleur * 1.1, 1.0 ); -} \ No newline at end of file diff --git a/tests/real/the orange guy/ball_vertex.glsl b/tests/real/the orange guy/ball_vertex.glsl deleted file mode 100644 index 8778fedf..00000000 --- a/tests/real/the orange guy/ball_vertex.glsl +++ /dev/null @@ -1,5 +0,0 @@ -void main() -{ - gl_TexCoord[0] = gl_MultiTexCoord0; - gl_Position = ftransform(); -} \ No newline at end of file diff --git a/tests/real/the orange guy/bloom2_pixel.glsl b/tests/real/the orange guy/bloom2_pixel.glsl deleted file mode 100644 index 0547975e..00000000 --- a/tests/real/the orange guy/bloom2_pixel.glsl +++ /dev/null @@ -1,35 +0,0 @@ -uniform sampler2D tex; -uniform float invTexWidth; - - -void main() -{ - vec2 p = gl_TexCoord[0].xy; - vec2 dp = vec2(invTexWidth, 0.0); - - /* - vec3 a = texture2D(tex, p - 3.0 * dp).rgb; - vec3 b = texture2D(tex, p - 2.0 * dp).rgb; - vec3 c = texture2D(tex, p - 1.0 * dp).rgb; - vec3 d = texture2D(tex, p ).rgb; - vec3 e = texture2D(tex, p + 1.0 * dp).rgb; - vec3 f = texture2D(tex, p + 2.0 * dp).rgb; - vec3 g = texture2D(tex, p + 3.0 * dp).rgb; - vec3 final = 0.015625 * (a + g) - + 0.09375 * (b + f) - + 0.234375 * (c + e) - + 0.3125 * d; - - gl_FragColor = vec4( final, 1.0 ); - */ - - - vec3 a = texture2D(tex, p - 2.1428571 * dp).rgb; - vec3 b = texture2D(tex, p - 0.6 * dp).rgb; - vec3 c = texture2D(tex, p + 0.6 * dp).rgb; - vec3 d = texture2D(tex, p + 2.1428571 * dp).rgb; - vec3 final = (2.0 * 0.21875) * (a + d) - + (2.0 * 0.78125) * (b + c); - gl_FragColor = vec4( final, 1.0 ); - -} \ No newline at end of file diff --git a/tests/real/the orange guy/bloom2_vertex.glsl b/tests/real/the orange guy/bloom2_vertex.glsl deleted file mode 100644 index 8778fedf..00000000 --- a/tests/real/the orange guy/bloom2_vertex.glsl +++ /dev/null @@ -1,5 +0,0 @@ -void main() -{ - gl_TexCoord[0] = gl_MultiTexCoord0; - gl_Position = ftransform(); -} \ No newline at end of file diff --git a/tests/real/the orange guy/bloom_pixel.glsl b/tests/real/the orange guy/bloom_pixel.glsl deleted file mode 100644 index 7bb6e39b..00000000 --- a/tests/real/the orange guy/bloom_pixel.glsl +++ /dev/null @@ -1,40 +0,0 @@ -uniform sampler2D tex; -uniform float invTexHeight; - - -void main() -{ - vec2 p = gl_TexCoord[0].xy; - vec2 dp = vec2(0.0, invTexHeight); - - const vec3 limit = vec3(0.5,0.5,0.5); - const vec3 mini = vec3(0.0,0.0,0.0); - - /* first version (7 samples) */ - /* - vec3 a = max(mini, texture2D(tex, p - 3.0 * dp).rgb - limit); - vec3 b = max(mini, texture2D(tex, p - 2.0 * dp).rgb - limit); - vec3 c = max(mini, texture2D(tex, p - 1.0 * dp).rgb - limit); - vec3 d = max(mini, texture2D(tex, p ).rgb - limit); - vec3 e = max(mini, texture2D(tex, p + 1.0 * dp).rgb - limit); - vec3 f = max(mini, texture2D(tex, p + 2.0 * dp).rgb - limit); - vec3 g = max(mini, texture2D(tex, p + 3.0 * dp).rgb - limit); - vec3 final = 0.015625 * (a + g) - + 0.09375 * (b + f) - + 0.234375 * (c + e) - + 0.3125 * d; - - gl_FragColor = vec4( final * 2.0, 1.0 ); - */ - - /* second version (4 samples) */ - - vec3 a = max(mini, texture2D(tex, p - 2.1428571 * dp).rgb - limit); - vec3 b = max(mini, texture2D(tex, p - 0.6 * dp).rgb - limit); - vec3 c = max(mini, texture2D(tex, p + 0.6 * dp).rgb - limit); - vec3 d = max(mini, texture2D(tex, p + 2.1428571 * dp).rgb - limit); - vec3 final = (2.0 * 0.21875) * (a + d) - + (2.0 * 0.78125) * (b + c); - gl_FragColor = vec4( final, 1.0 ); - -} \ No newline at end of file diff --git a/tests/real/the orange guy/bloom_vertex.glsl b/tests/real/the orange guy/bloom_vertex.glsl deleted file mode 100644 index 8778fedf..00000000 --- a/tests/real/the orange guy/bloom_vertex.glsl +++ /dev/null @@ -1,5 +0,0 @@ -void main() -{ - gl_TexCoord[0] = gl_MultiTexCoord0; - gl_Position = ftransform(); -} \ No newline at end of file diff --git a/tests/real/the orange guy/dfc_pixel.glsl b/tests/real/the orange guy/dfc_pixel.glsl deleted file mode 100644 index ac990f9a..00000000 --- a/tests/real/the orange guy/dfc_pixel.glsl +++ /dev/null @@ -1,67 +0,0 @@ -const float PI = 3.1415926; - - -uniform float localTime; - -vec3 coul2(float x, float y) -{ - float h = (x + 1.0) * 350.0; - float w = (y + 1.0) * 350.0; - - float hi = (h - 350.0) / 20.0; - float wi = (w - 350.0) / 20.0; - - float xo = hi; - float yo = wi + localTime;/*cos(hi/5.0) + wi + 0.1; */ - - float xa = cos(hi/5.0); - float ya = cos(wi/5.0); - - float cosxa = cos(xa); - float sinxa = sin(xa); - float cosya = cos(ya); - float sinya = sin(ya); - - vec3 res = vec3(0.0,0.0,0.0); - - for (int l = 0; l <= 30; l++) - { - float li = (float(l) - 15.0) * 2.0; - - float zo = li; - - float za = cos(li / 20.0); - - float tmp = yo * cosxa + zo * sinxa; - zo = zo * cosxa - yo * sinxa; - yo = tmp; - - float tmp2 = xo * cosya + zo * sinya; - zo = zo * cosya - xo * sinya; - xo = tmp2; - /* - float tmp3 = xo * cos(za) + yo * sin(za); - yo = yo * cos(za) - xo * sin(za); - xo = tmp3; - */ - vec3 color = vec3(128.0) + vec3(128.0) * vec3(cos(zo), cos(zo + PI * 2.0 / 3.0), cos(zo - PI * 2.0 / 3.0)); - - float length = sqrt( xo * xo + yo * yo + zo * zo ) - 30.0; - float contrib = 0.25 / (1.0 + 400.0 * length * length); - - res = res * (1.0 - contrib) + color * contrib; - /* res += contrib * color; */ - } - - return res; - } - -void main() -{ - vec2 p = 0.5 * gl_TexCoord[0].xy + vec2(0.1,0.1); - - - gl_FragColor = vec4( 0.15 * coul2(p.x, p.y) , 1.0); -} - - diff --git a/tests/real/the orange guy/dfc_vertex.glsl b/tests/real/the orange guy/dfc_vertex.glsl deleted file mode 100644 index 88eb6b1d..00000000 --- a/tests/real/the orange guy/dfc_vertex.glsl +++ /dev/null @@ -1,6 +0,0 @@ - -void main() -{ - gl_TexCoord[0] = gl_MultiTexCoord0; - gl_Position = ftransform(); -} \ No newline at end of file diff --git a/tests/real/the orange guy/final_pixel.glsl b/tests/real/the orange guy/final_pixel.glsl deleted file mode 100644 index 69573fa7..00000000 --- a/tests/real/the orange guy/final_pixel.glsl +++ /dev/null @@ -1,18 +0,0 @@ -uniform sampler2D tonemappedTexture; -uniform sampler2D bloomTexture; -uniform sampler2D paperTexture; -uniform int paper; -uniform float paperInvSize; - - -void main() -{ - vec2 p = gl_TexCoord[0].xy; - - vec4 main = texture2D(tonemappedTexture, p); - vec4 bloom = texture2D(bloomTexture, p); - - vec4 paper = float(paper) * 1.8 * texture2D(paperTexture, gl_FragCoord.xy * paperInvSize) + vec4(1.0,1.0,1.0,1.0) * (1.0 - float(paper)); - - gl_FragColor = paper * (main * 0.8 + 0.2 * bloom); -} \ No newline at end of file diff --git a/tests/real/the orange guy/final_vertex.glsl b/tests/real/the orange guy/final_vertex.glsl deleted file mode 100644 index 8778fedf..00000000 --- a/tests/real/the orange guy/final_vertex.glsl +++ /dev/null @@ -1,5 +0,0 @@ -void main() -{ - gl_TexCoord[0] = gl_MultiTexCoord0; - gl_Position = ftransform(); -} \ No newline at end of file diff --git a/tests/real/the orange guy/font_pixel.glsl b/tests/real/the orange guy/font_pixel.glsl deleted file mode 100644 index 15673791..00000000 --- a/tests/real/the orange guy/font_pixel.glsl +++ /dev/null @@ -1,11 +0,0 @@ -uniform sampler2D tex; -uniform sampler2D fill; - -void main() -{ - vec2 p = gl_TexCoord[0].xy; - vec4 letter = texture2D(tex, p); - vec4 fill = texture2D(fill, p * 3.0); - - gl_FragColor = letter * fill * gl_Color; -} \ No newline at end of file diff --git a/tests/real/the orange guy/font_vertex.glsl b/tests/real/the orange guy/font_vertex.glsl deleted file mode 100644 index 1320daa3..00000000 --- a/tests/real/the orange guy/font_vertex.glsl +++ /dev/null @@ -1,7 +0,0 @@ - -void main() -{ - gl_TexCoord[0] = gl_MultiTexCoord0; - gl_Position = ftransform(); - gl_FrontColor = gl_Color; -} \ No newline at end of file diff --git a/tests/real/the orange guy/logofinal_pixel.glsl b/tests/real/the orange guy/logofinal_pixel.glsl deleted file mode 100644 index e5707aab..00000000 --- a/tests/real/the orange guy/logofinal_pixel.glsl +++ /dev/null @@ -1,8 +0,0 @@ -uniform sampler2D tex; - -void main() -{ - vec2 p = gl_TexCoord[0].xy; - vec4 sample0 = texture2D(tex, p); - gl_FragColor = gl_Color * sample0; -} \ No newline at end of file diff --git a/tests/real/the orange guy/logofinal_vertex.glsl b/tests/real/the orange guy/logofinal_vertex.glsl deleted file mode 100644 index 1320daa3..00000000 --- a/tests/real/the orange guy/logofinal_vertex.glsl +++ /dev/null @@ -1,7 +0,0 @@ - -void main() -{ - gl_TexCoord[0] = gl_MultiTexCoord0; - gl_Position = ftransform(); - gl_FrontColor = gl_Color; -} \ No newline at end of file diff --git a/tests/real/the orange guy/orange_pixel.glsl b/tests/real/the orange guy/orange_pixel.glsl deleted file mode 100644 index de661e29..00000000 --- a/tests/real/the orange guy/orange_pixel.glsl +++ /dev/null @@ -1,38 +0,0 @@ -uniform sampler2D tex; -uniform sampler2D grain; - -const int NPOINTS = 5; - -uniform float env; - -uniform vec3 pos[NPOINTS]; -uniform float intensity[NPOINTS]; -uniform float localTime; -uniform float zoom; - - -const float PI = 3.14159265; - -void main() -{ - float x = gl_TexCoord[0].s * zoom; - float y = gl_TexCoord[0].t * zoom; - float u = localTime * 0.25; - - vec4 color = vec4(0.0); - - for (int i = 0; i < 5; i++) - { - vec3 diff = vec3(x, y, 0.0) - pos[i]; - float angle = atan(diff.y, diff.x); - float d = env * 1.0; /* length(pos[i]);*/ - float t = (d + localTime) * 0.03 ; - float s = u + angle / PI + (float(i) * 0.1); - float dist = length(diff); - vec4 grain = texture2D(grain, vec2(0.5, 0.3 * dist)); - - color += (texture2D(tex, vec2(s,t)) * grain) * (intensity[i] / (1.0 + 0.2 * dist)); - } - - gl_FragColor = vec4(color.rgb * 0.6 + 0.4 * env, 1.0); -} diff --git a/tests/real/the orange guy/orange_vertex.glsl b/tests/real/the orange guy/orange_vertex.glsl deleted file mode 100644 index 88eb6b1d..00000000 --- a/tests/real/the orange guy/orange_vertex.glsl +++ /dev/null @@ -1,6 +0,0 @@ - -void main() -{ - gl_TexCoord[0] = gl_MultiTexCoord0; - gl_Position = ftransform(); -} \ No newline at end of file diff --git a/tests/real/the orange guy/particle_pixel.glsl b/tests/real/the orange guy/particle_pixel.glsl deleted file mode 100644 index ab69325a..00000000 --- a/tests/real/the orange guy/particle_pixel.glsl +++ /dev/null @@ -1,15 +0,0 @@ -uniform sampler2D tex; - -uniform float intensity; -uniform float alpha; - -void main() -{ - vec4 color = texture2D(tex, gl_TexCoord[0].xy); - float opacity = dot(color.rgb, vec3(0.33,0.33,0.33)) * color.a * alpha; - - - if (opacity < 0.05) discard; - - gl_FragData[0] = vec4(color.rgb * intensity, opacity); -} \ No newline at end of file diff --git a/tests/real/the orange guy/particle_vertex.glsl b/tests/real/the orange guy/particle_vertex.glsl deleted file mode 100644 index 4c125181..00000000 --- a/tests/real/the orange guy/particle_vertex.glsl +++ /dev/null @@ -1,8 +0,0 @@ -void main() -{ - gl_TexCoord[0] = gl_MultiTexCoord0; - - gl_Position = ftransform(); - - gl_FrontColor = gl_Color; -} \ No newline at end of file diff --git a/tests/real/the orange guy/put_pixel.glsl b/tests/real/the orange guy/put_pixel.glsl deleted file mode 100644 index c7855f3d..00000000 --- a/tests/real/the orange guy/put_pixel.glsl +++ /dev/null @@ -1,4 +0,0 @@ -void main() -{ - gl_FragColor = gl_Color; -} \ No newline at end of file diff --git a/tests/real/the orange guy/put_vertex.glsl b/tests/real/the orange guy/put_vertex.glsl deleted file mode 100644 index 1320daa3..00000000 --- a/tests/real/the orange guy/put_vertex.glsl +++ /dev/null @@ -1,7 +0,0 @@ - -void main() -{ - gl_TexCoord[0] = gl_MultiTexCoord0; - gl_Position = ftransform(); - gl_FrontColor = gl_Color; -} \ No newline at end of file diff --git a/tests/real/the orange guy/puttexture_pixel.glsl b/tests/real/the orange guy/puttexture_pixel.glsl deleted file mode 100644 index 206e02ae..00000000 --- a/tests/real/the orange guy/puttexture_pixel.glsl +++ /dev/null @@ -1,20 +0,0 @@ -uniform sampler2D tex0; -uniform sampler2D tex1; -uniform sampler2D tex2; -uniform sampler2D tex3; - -uniform float amountTex0; -uniform float amountTex1; -uniform float amountTex2; -uniform float amountTex3; - -void main() -{ - vec2 p = gl_TexCoord[0].xy; - vec4 sample0 = texture2D(tex0, p); - vec4 sample1 = texture2D(tex1, p); - vec4 sample2 = texture2D(tex2, p); - vec4 sample3 = texture2D(tex3, p); - gl_FragColor = gl_Color * (amountTex0 * sample0 + sample1 * amountTex1 - + amountTex2 * sample2 + sample3 * amountTex3 ); -} \ No newline at end of file diff --git a/tests/real/the orange guy/puttexture_vertex.glsl b/tests/real/the orange guy/puttexture_vertex.glsl deleted file mode 100644 index 1320daa3..00000000 --- a/tests/real/the orange guy/puttexture_vertex.glsl +++ /dev/null @@ -1,7 +0,0 @@ - -void main() -{ - gl_TexCoord[0] = gl_MultiTexCoord0; - gl_Position = ftransform(); - gl_FrontColor = gl_Color; -} \ No newline at end of file diff --git a/tests/real/the orange guy/scene10_pixel.hlsl b/tests/real/the orange guy/scene10_pixel.hlsl deleted file mode 100644 index 95a5ad21..00000000 --- a/tests/real/the orange guy/scene10_pixel.hlsl +++ /dev/null @@ -1,30 +0,0 @@ -const int N_SPIRALES = 12; /* le nombre de points spirales */ - -uniform vec4 pos[N_SPIRALES]; /* position des points spirales, rayon, intensite */ -uniform float musicVolume; - -static const vec3 WHITE = vec3(1.0,1.0,1.0); - -vec3 coul(vec2 p) -{ - float f = 0.0; - for (int i = 0; i < N_SPIRALES; ++i) - { - vec2 diff = pos[i].xy - p; - float dist = pow(dot(diff, diff), 1.0 / 4.0); - float s = abs(dist - pos[i].z); - - f = f + pos[i].w * exp(-s * (50.0 - musicVolume * 20.0)); - } - - return WHITE * max(0.0, 1.2 - f); -} - -void main() -{ - vec2 p = gl_TexCoord[0].xy; - - vec3 couleur = coul(p); - - gl_FragColor = vec4( couleur * (1.0 + musicVolume), 1.0 ); -} \ No newline at end of file diff --git a/tests/real/the orange guy/scene10_vertex.glsl b/tests/real/the orange guy/scene10_vertex.glsl deleted file mode 100644 index 88eb6b1d..00000000 --- a/tests/real/the orange guy/scene10_vertex.glsl +++ /dev/null @@ -1,6 +0,0 @@ - -void main() -{ - gl_TexCoord[0] = gl_MultiTexCoord0; - gl_Position = ftransform(); -} \ No newline at end of file diff --git a/tests/real/the orange guy/tonemapping_pixel.glsl b/tests/real/the orange guy/tonemapping_pixel.glsl deleted file mode 100644 index bb5bd3ed..00000000 --- a/tests/real/the orange guy/tonemapping_pixel.glsl +++ /dev/null @@ -1,18 +0,0 @@ -uniform sampler2D tex; - -void main() -{ - vec3 color = texture2D(tex, gl_TexCoord[0].xy).rgb; - float luminance = dot( vec3(0.3, 0.59, 0.11), color); - - /*float luminance = dot( vec3(0.33, 0.33, 0.33), color);*/ - - /* [0 .. infinity] is mapped to [0 .. 1] */ - - float factor = luminance / (1.0 + luminance); - - /* interesting bug : make black area */ - /* float factor = sin((luminance * 3.141596 * 0.5) / (1.0 + luminance));*/ - - gl_FragColor = vec4( factor * color, 1.0 ); -} \ No newline at end of file diff --git a/tests/real/the orange guy/tonemapping_vertex.glsl b/tests/real/the orange guy/tonemapping_vertex.glsl deleted file mode 100644 index 8778fedf..00000000 --- a/tests/real/the orange guy/tonemapping_vertex.glsl +++ /dev/null @@ -1,5 +0,0 @@ -void main() -{ - gl_TexCoord[0] = gl_MultiTexCoord0; - gl_Position = ftransform(); -} \ No newline at end of file diff --git a/tests/real/the orange guy/tunnel_pixel.glsl b/tests/real/the orange guy/tunnel_pixel.glsl deleted file mode 100644 index 7f847f8b..00000000 --- a/tests/real/the orange guy/tunnel_pixel.glsl +++ /dev/null @@ -1,20 +0,0 @@ - -varying vec2 st; -uniform float alpha; -uniform sampler2D tex; -uniform float time; -uniform vec4 color; -varying float prof; - -void main() -{ - - vec3 texcolor = texture2D(tex, st).rgb; - - float opacity = alpha < 0.9 ? 1.0 : 1.0 - 0.7 * dot(vec3(0.33,0.33,0.33), texcolor); - - opacity *= exp(-0.10 * abs(prof)); - - gl_FragData[0] = color * vec4(texcolor * 1.6, opacity); - -} \ No newline at end of file diff --git a/tests/real/the orange guy/tunnel_vertex.glsl b/tests/real/the orange guy/tunnel_vertex.glsl deleted file mode 100644 index 0f0cba38..00000000 --- a/tests/real/the orange guy/tunnel_vertex.glsl +++ /dev/null @@ -1,13 +0,0 @@ -varying vec2 st; -varying float prof; - - -void main() -{ - st = gl_MultiTexCoord0.xy; - - vec4 p = ftransform(); - prof = gl_Color.x * 50.0; - - gl_Position = p; -} \ No newline at end of file diff --git a/tests/real/the wind under my wings/f_blurhighlights.cpp b/tests/real/the wind under my wings/f_blurhighlights.cpp deleted file mode 100644 index ab4f8a18..00000000 --- a/tests/real/the wind under my wings/f_blurhighlights.cpp +++ /dev/null @@ -1,186 +0,0 @@ -#version 110 -#define float4 vec4 -#define float3 vec3 -#define float2 vec2 -#define oUV gl_TexCoord[0] -#define tex3D texture3D -#define tex2D texture2D -#define tex1D texture1D - - uniform sampler2D texture2d_1; -/* uniform sampler1D texture_transfer_function; - uniform sampler1D texture_palette_function; - - - uniform float3 VolumeSize; - uniform float3 RelativeSize; - uniform float3 Registration_Offset; - uniform float pet_alpha_blending; - uniform float3 MousePos; - uniform int Projection_mode; -uniform float3 InVolumePosition; - uniform float3 Windowing_Levels; - - uniform float isosurface; -uniform float Sharpening; - -*/ - - uniform float Limit; - - - - - - - -void main (void) -{ - - - -float4 cl; -cl=vec4 (0.0); -int count=0; - -// loop, highlight speculars (>0.9) -for (int y=-8;y<9;y++) { - for (int x=-8;x<9;x++){ -count++; -float2 dd=float2 (x,y)*1.02; - -//dd=ray.xy*5.0; -float2 Dist=dd*0.0015; -float4 res=tex2D(texture2d_1,oUV.xy+Dist); -//res*=res; -//if (res.w<0.9) {res*=res*0.35+0.05; } -cl+=res; -} -} -cl/=float (count); - - - -//cl=tex2D(texture2d_1,oUV.xy)*vec4 (1.0,0.0,0.0,1.0)+vec4 (0.2,0.0,0.0,0.0); - -//cl*=1.2; -//cl+=float4 (0.0,0.02,0.05,1); -//cl=vec4 (0.0); - - -//cl=tex2D(texture2d_1,oUV.xy)*1.0; - -/* -//Depth blurring - -float dpth=0; -int count=0; -for (int y=-4;y<5;y++) { - for (int x=-4;x<5;x++){ -count++; -float2 dd=float2 (x,y)*0.7; - -//dd=ray.xy*5.0; - -float2 Dist=dd*0.0015; -dpth+=tex2D(texture2d_2,UV.xy+Dist).x; -} -} -dpth/=float (count); -//dpth=sin(dpth*3.14159); -dpth+=0.1; -dpth=pow(dpth,6.0); -//dpth+=Limit; -dpth=1.1-dpth; -//if (dpth<0.7) dpth=0.0; -count=0; -cl=vec4(0.0); -dpth=clamp(dpth,0.0,1.0); - -dpth=Limit+((1.0-Limit)-(Limit))*dpth; - -if (dpth>0.02) { -for (int y=-4;y<5;y++) { - for (int x=-4;x<5;x++){ -count++; - -float2 dd=float2 (x,y); - -//if ( (x)==(y)) { dd*=120.0;} - -float2 Dist=dd*0.0015*dpth; -cl+=tex2D(texture2d_1,UV.xy+Dist); -} -} - -cl/=float (count); -} -else -cl=tex2D(texture2d_1,UV.xy); - - - -*/ - - - - - - - - - -gl_FragData[0]=cl; - gl_FragData[1]=cl; - -/* -float3 currentuv; - - - -if (Projection_mode==0) { -currentuv.xy=oUV.st; -currentuv.z=0.0+InVolumePosition.z; -} -else -if (Projection_mode==1) { -currentuv.xz=oUV.st; -currentuv.y=0.0+InVolumePosition.y; -} -else -if (Projection_mode==2) { -currentuv.zy=oUV.ts; -currentuv.x=0.0+InVolumePosition.x; -} -float4 original= tex3D (texture3d,currentuv); -float divisor=1.0/(Windowing_Levels.y-Windowing_Levels.x); - - - - -original-=Windowing_Levels.x*float4 (1,1,1,1); -original*=divisor; - - -//original.x=max (0.0,min (1.0,original.x)); - - -gl_FragColor=currentuv.xyzz; -//gl_FragColor=float4 (1.0,0.0,0.0,1.0); -//gl_FragColor*=Sharpening; -*/ -} - - - - - - - - - - - - - - diff --git a/tests/real/the wind under my wings/f_blurpass.cpp b/tests/real/the wind under my wings/f_blurpass.cpp deleted file mode 100644 index f6b1f434..00000000 --- a/tests/real/the wind under my wings/f_blurpass.cpp +++ /dev/null @@ -1,498 +0,0 @@ -#version 110 -#define float4 vec4 -#define float3 vec3 -#define float2 vec2 -#define oUV gl_TexCoord[0] -#define tex3D texture3D -#define tex2D texture2D -#define tex1D texture1D - - uniform sampler2D texture2d_1; - uniform sampler2D texture2d_s; - uniform sampler2D texture2d_velocities; - uniform sampler2D texture2d_2; - uniform sampler2D texture2d_random; -/* uniform sampler1D texture_transfer_function; - uniform sampler1D texture_palette_function; - - - uniform float3 VolumeSize; - uniform float3 RelativeSize; - uniform float3 Registration_Offset; - uniform float pet_alpha_blending; - uniform float3 MousePos; - uniform int Projection_mode; -uniform float3 InVolumePosition; - uniform float3 Windowing_Levels; - - uniform float isosurface; -uniform float Sharpening; - -*/ - - uniform float Limit; - uniform float Flo; - -uniform float PosY; -uniform float ttime; -uniform float fttime; -uniform float DSP; -uniform float DSP2; - - - - - -void main (void) -{ - - - - -//float ff=tex2D (texture2d_1,oUV.xy).x; -//ff=abs (ff-cl.x); -//ff=0.5+0.5*sin(ff*10000.0); -//cl=ff*vec4 (1.0); - - - -/* - - -float PI=3.1415926535; -float2 UV=oUV.xy; - -UV-=float2 (0.5,0.5); -UV*=2.0; - - -float3 DirV =float3 (UV.x,UV.y,0.6); -float lgn=length (DirV); -DirV/=lgn; - -UV.xy=UV.xy+(DirV.xy-UV.xy)*-0.0; -UV*=0.5; -UV+=float2 (0.5,0.5); -*/ - float2 UV=oUV.xy; -float4 cl=tex2D (texture2d_1,UV.xy); - -cl=float4 (0.0); -float3 Direction=tex2D (texture2d_velocities,UV.xy).xyz; -//Direction.xy=float2 (0.5); -Direction.xyz-=float3 (0.5); -Direction*=2.0; - -float alpha=1.0*length (Direction.xyz); -alpha=clamp (alpha,0.0,1.0); -//alpha=1-alpha; -//alpha*=alpha; -//alpha=1-alpha; - -//alpha*=alpha; -//alpha=0.1; -//Direction*=0.01; -//Direction=vec3 (0.0,0.01,0.0); -if (alpha>0.01) -{ - for (int t=0;t<10;t++) { -UV.xy-=Direction.xy*0.01; - cl+=tex2D (texture2d_1,UV.xy); -}; - - cl*=1.0/10.0; -//Direction=tex2D (texture2d_velocities,UV.xy).xyz; -//cl=Direction.xyzz*1.0+vec4 (0.5); -//cl.x+=0.15*alpha; -//=float4 (1.0,0.0,0.0,1.0)*alpha; -} -else cl=tex2D (texture2d_1,UV.xy); - -//float4 clnow=tex2D( texture2d_1,oUV.xy); -//cl=cl+(clnow-cl)*0.5; - -UV=oUV.xy; -if (fttime>186.0) if (fttime<242.0) if (UV.x>0.5) UV.x=1.0-UV.x; - -float fx=tex2D (texture2d_1,UV.xy).x; - - -if (ttime>169.0) -if (ttime<184.0){ - - if (UV.y>0.5) UV.y=1.0-UV.y; -} - -if (ttime<197.0) -if (ttime>184.0){ -if (UV.x>0.5) UV.x=1.0-UV.x; -} - - - - -if (ttime<86.0) -if (ttime>26.5) -if (UV.x>0.5) UV.x=1.0-UV.x; - - - - - -if (ttime>98.0) -if (ttime<106.0) { - -float fft=((UV.x-0.5) / (UV.y-0.5)); -fft=1.0*atan (fft); - -//fft=mod (fft,1.4); - - -float dist=length (UV.xy-vec2 (0.5)); - -vec2 UVn; -UVn.x=dist * sin(fft)+0.5; -UVn.y=dist * cos(fft)+0.5; - -UV=UVn; -} - - - - - - - - - -//1.0-UV.x; - - -//if (UV.y>0.5) UV.y=1.0-UV.y; -//if (UV.x>fx) UV.x=1.0-UV.x; -//+(fx-0.5); -cl=1.0*tex2D (texture2d_1,UV.xy); -cl+=1.0*tex2D (texture2d_s,UV.xy); - -vec4 cln=cl; - -if ((ttime>86.0) && (ttime<104.0)){ - - -float cll2=cl.y; -// if (UV.y>0.8) UV.y=1.0-UV.y+0.6; - -cl=1.0*tex2D (texture2d_1,UV.xy); -cl+=1.0*tex2D (texture2d_s,UV.xy); - -vec4 cln=vec4(tex2D(texture2d_1,UV.xy).x)+vec4(tex2D(texture2d_s,UV.xy).x); -if (cll2>0.9) cl*=100.0; -//vec4 (1.7,0.8,1.0,0.0); -float fl=(ttime-92.0)*0.125; -fl=clamp (fl,0.0,1.0); -cl=cl+(cln-cl)*fl; - -} - - - - - - -if (ttime>104.0) { - - -float cll2=cl.y; -float cll3=cl.z; - -float fl2=(ttime-123.0)*0.25; - -fl2=clamp (fl2,0.0,1.0); -fl2=0.0; -float ff=UV.x; - -if (fttime<186.0) -if (UV.x>0.5+fl2) UV.x=1.0-UV.x; - -//UV.x=UV.x+(ff-UV.x)*fl2; - - - - -cl=vec4(tex2D(texture2d_1,UV.xy).x)+vec4(tex2D(texture2d_s,UV.xy).x); -if (cll2>0.9) -cl*=1.7*vec4 (0.7,0.8,1.0,0.0); - -fl2=(ttime-131.0)*0.3; - -if (fttime>186.0); -fl2=(ttime-129.0)*0.25; - -fl2=clamp (fl2,0.0,1.0); -cl=cl+(cln-cl)*fl2; -//if (cll3>0.6) cl*=1.7*vec4 (0.7,0.9,1.0,0.0); -} - - - - -cl+=vec4(DSP*DSP*oUV.y)*0.25; - - -float flx=1.9; -if (ttime>140.0) flx=1.2; - - -if (cl.z>flx) -{ -float ures=pow(sin(UV.x*5.0),5.0); -if (ures>0.5) ures=-1.0; else ures=1.0; - float uu=pow(1.1*sin(5.0*ttime+2000.0*UV.x)*sin(2000.0*UV.y),8.0); -uu*=pow(1.1*sin(ures*-15.0*ttime+200.0*UV.x)*sin(ures*-10.0*ttime+200.0*UV.y),8.0); - -if (uu>0.0) -cl*=0.0; - - -} - - - - -if (ttime<250.0) -if (length (cl)<0.1) { -float ures=pow(sin(UV.x*15.0),5.0); -if (ures>0.5) ures=-1.0; else ures=1.0; - float uu=pow(1.1*sin(5.0*ttime+2000.0*UV.x)*sin(2000.0*UV.y),8.0); -uu*=pow(1.1*sin(ures*-5.0*ttime+400.0*UV.x)*sin(ures*-10.0*ttime+400.0*UV.y),8.0); - - -float fl2=(ttime-32.0)*0.125; -fl2=clamp (fl2,0.0,1.0); - -if (uu>0.04) -cl+=fl2*vec4 (0.43)*vec4 (0.7,1.0,1.0,1.0)*pow((1.0-oUV.y),2.0); - - -} - -/* -if (ttime>230.0) -if (sin(oUV.y*100.0)>0.0) -cl=vec4 (cl.x); -*/ - - -float ffade=ttime-230.0; -ffade=clamp (ffade,0.0,1.0); -if (fttime>230.0) -cl*=ffade; - - - - - -//cl*=0.5+DSP2; - - -float fls= -min (length (vec2 (2.0,0.5)*(oUV.xy-vec2 (0.5,0.4))), -length (vec2 (0.5,2.0)*(oUV.xy-vec2 (0.5,0.4)))); -fls=1.0-fls; -fls=clamp (fls,0.0,1.0); -fls=pow (fls,2.0); -//float fls2=length (oUV.xy-vec2 (0.5)); - -fls= -length (vec2 (2.0,0.5)*(oUV.xy-vec2 (0.5,0.4))); -fls=1.0-fls; -fls=clamp (fls,0.0,1.0); -fls=pow (fls,3.0); -//fls*=clamp (10.0*sin(oUV.y*1200.0),0.0,1.0); - - -if (fttime<130.0) -cl*=1.0+2.0*DSP2*fls*vec4 (0.5,0.7,1.0,1.0); - -if (fttime>190.0) -cl*=1.0+2.0*DSP2*fls*vec4 (0.5,0.7,1.0,1.0); - - - -//fls=(oUV.x-0.5)+(oUV.y-0.5); -//fls=1.0-fls; -//cl*=1.0+1.5*vec4 (0.6,0.8,0.9,1.0)*5.0*vec4 (pow(fls,8.0)); -//cl=tex2D (texture2d_1,vec2 (sin(oUV.x),sin(oUV.y))); - - -vec4 clnn=vec4 (pow (cl.x*1.1,3.0),pow (cl.y*1.1,3.0),pow (cl.z*1.1,3.0),pow (cl.z*1.1,2.0)); - - - -if (ttime>86.0) -cl=vec4 (cl.x)+(clnn-vec4 (cl.x))*0.3; -else -cl=vec4 (cl.y)+(0.8*clnn-vec4 (cl.y))*0.25; - - - - - - - - -//cl=clnn; - - - - -//*vec4 (0.2,0.5,1.0,1.0); - - -//cl=vec4(tex2D(texture2d_1,UV.xy).x)+vec4(tex2D(texture2d_s,UV.xy).x); - -/* - - -// blur effect -float lgn2=length (float2 (1.0,2.0)*(UV.xy-float2 (0.5))); -lgn2*=lgn2; -//pow(lgn2,1.8); -int count=0; -for (int y=-5;y<6;y++) { - for (int x=-5;x<6;x++){ -count++; - -float2 dd=float2 (x,y); -if ( (x)==(y)) { - dd*=2.0; -} - -float2 Dist=float2 (x,y)*0.0025*lgn2; -Dist=dd*0.0025*lgn2; -cl+=tex2D(texture2d_1,UV.xy+Dist); - -} -} -cl/=float (count)*(lgn2+(1.0-lgn2)*0.85); - - -vec4 cll=cl; - -cl=tex2D (texture2d_1,oUV.xy); - - - - - - - - -//Depth blurring - -float dpth=0.0; - count=0; - float Limit2=1.0-Limit; -for (int y=-4;y<5;y++) { - for (int x=-4;x<5;x++){ -count++; -float2 dd=float2 (x,y)*0.7*Limit2; - -//dd=ray.xy*5.0; - -float2 Dist=dd*0.0018; -dpth+=tex2D(texture2d_2,UV.xy+Dist).x; -} -} -dpth/=float (count); -//dpth=sin(dpth*3.14159); -//dpth+=0.1; -dpth=pow(dpth,126.0); -//dpth+=Limit; -dpth=1.0-1.0*dpth; -//if (dpth<0.7) dpth=0.0; -count=0; -cl=vec4(0.0); -dpth=clamp(dpth,0.0,1.0); - -dpth=Limit+((1.0-Limit)-(Limit))*dpth; -dpth*=Flo; -//dpth=1.0; - -float vel=tex2D(texture2d_velocities,UV.xy).x; -if (dpth>0.02) -{ -for (int y=-4;y<5;y++) { - for (int x=-4;x<5;x++){ -count++; - -float2 dd=float2 (x,y)*0.7;//;*vec2 (3.0,3.0); - -//float2 dd2=float((x+4)*9+(y+4))*float2 (-1.0,1.0)*0.4; -//dd=dd+(dd2-dd)*-vel*0.4; - - -float2 Dist=dd*0.0018*dpth; -cl+=tex2D(texture2d_1,UV.xy+Dist); -//cl.x=dpth; - } -} - -cl/=float (count); -} -else -cl=tex2D(texture2d_1,UV.xy); - - - -if (vel>0.01) { -vec4 newcl=vec4 (0.0); -for (int x=0;x<15;x++){ -float2 dd2=float(x)*float2 (-1.0,1.0)*0.003*vel; -newcl+=tex2D(texture2d_1,UV.xy+dd2); -} -newcl*=1.0/15.0; - -cl=cl+(newcl-cl)*0.5; -} - - - -//cl*=0.4; - -//cl+=tex2D(texture2d_velocities,UV.xy)*0.5; - - -//cl=tex2D(texture2d_1,UV.xy); -//cl=vec4 (dpth); -*/ - -//cl=vec4 (tex2D(texture2d_1,UV.xy)); -//cl=vec4 (tex2D(texture2d_velocities,UV.xy)); - - - - - -//cl=cll; - - - -gl_FragData[0]=cl; - gl_FragData[1]=cl; - -} - - - - - - - - - - - - - - diff --git a/tests/real/the wind under my wings/f_blurpass2.cpp b/tests/real/the wind under my wings/f_blurpass2.cpp deleted file mode 100644 index 7995ec0d..00000000 --- a/tests/real/the wind under my wings/f_blurpass2.cpp +++ /dev/null @@ -1,264 +0,0 @@ -#version 110 -#define float4 vec4 -#define float3 vec3 -#define float2 vec2 -#define oUV gl_TexCoord[0] -#define tex3D texture3D -#define tex2D texture2D -#define tex1D texture1D - - uniform sampler2D texture2d_1; - uniform sampler2D texture2d_velocities; - uniform sampler2D texture2d_2; - uniform sampler2D texture2d_random; -/* uniform sampler1D texture_transfer_function; - uniform sampler1D texture_palette_function; - - - uniform float3 VolumeSize; - uniform float3 RelativeSize; - uniform float3 Registration_Offset; - uniform float pet_alpha_blending; - uniform float3 MousePos; - uniform int Projection_mode; -uniform float3 InVolumePosition; - uniform float3 Windowing_Levels; - - uniform float isosurface; -uniform float Sharpening; - -*/ - - uniform float Limit; - uniform float Flo; - -uniform float PosY; -uniform vec3 MotionBlur; - - - - - -void main (void) -{ - -vec2 MotionBlurPos=vec2 (0.0,0.0); - - - -//float ff=tex2D (texture2d_1,oUV.xy).x; -//ff=abs (ff-cl.x); -//ff=0.5+0.5*sin(ff*10000.0); -//cl=ff*vec4 (1.0); - - - -/* - - -float PI=3.1415926535; -float2 UV=oUV.xy; - -UV-=float2 (0.5,0.5); -UV*=2.0; - - -float3 DirV =float3 (UV.x,UV.y,0.6); -float lgn=length (DirV); -DirV/=lgn; - -UV.xy=UV.xy+(DirV.xy-UV.xy)*-0.0; -UV*=0.5; -UV+=float2 (0.5,0.5); -*/ - float2 UV=oUV.xy; -float4 cl=tex2D (texture2d_1,UV.xy); - -cl=float4 (0.0); -float3 Direction=tex2D (texture2d_velocities,UV.xy).xyz; -//Direction.xy=float2 (0.5); -Direction.xyz-=float3 (0.5); -Direction*=2.0; - -float alpha=1.0*length (Direction.xyz); -alpha=clamp (alpha,0.0,1.0); -//alpha=1-alpha; -//alpha*=alpha; -//alpha=1-alpha; - -//alpha*=alpha; -//alpha=0.1; -Direction*=0.01; -if (alpha>0.01) -{ - for (int t=0;t<10;t++) { -UV.xy-=Direction.xy; - cl+=tex2D (texture2d_1,UV.xy); -}; -cl*=1.0/10.0; -//cl.x+=0.15*alpha; -//=float4 (1.0,0.0,0.0,1.0)*alpha; -} -else -cl=tex2D (texture2d_1,UV.xy); - -float4 clnow=tex2D( texture2d_1,oUV.xy); - -cl=cl+(clnow-cl)*0.5; - -UV=oUV.xy; - - - - - - -// blur effect -float lgn2=length (float2 (1.0,2.0)*(UV.xy-float2 (0.5))); -lgn2*=lgn2; -float xxx=1.0+(gl_Color.x)*5.0; -//xxx=1.0; -xxx=clamp (xxx,1.0,100.0); -//pow(lgn2,1.8); -int count=0; -{ - for (int y=-3;y<3;y++) { - for (int x=-3;x<3;x++){ -count++; - -float2 dd=float2 (x,y); -if ( (x)==(y)) { - //dd*=2.0; -} - -float2 Dist=float2 (x,y)*0.0025*lgn2; -Dist=dd*0.0018*lgn2*xxx; - -Dist+=MotionBlurPos; -MotionBlurPos+=MotionBlur.xy*0.01; - -cl+=tex2D(texture2d_1,UV.xy+Dist); - -} -} -cl/=float (count)*(lgn2+(1.0-lgn2)*0.85); -} - -vec4 cll=cl*1.03; -cll+=gl_Color; -//cll=tex2D (texture2d_1,oUV.xy); - - - -/* - - - - -//Depth blurring - -float dpth=0.0; - count=0; - float Limit2=1.0-Limit; -for (int y=-4;y<5;y++) { - for (int x=-4;x<5;x++){ -count++; -float2 dd=float2 (x,y)*0.7*Limit2; - -//dd=ray.xy*5.0; - -float2 Dist=dd*0.0018; -dpth+=tex2D(texture2d_2,UV.xy+Dist).x; -} -} -dpth/=float (count); -//dpth=sin(dpth*3.14159); -//dpth+=0.1; -dpth=pow(dpth,126.0); -//dpth+=Limit; -dpth=1.0-1.0*dpth; -//if (dpth<0.7) dpth=0.0; -count=0; -cl=vec4(0.0); -dpth=clamp(dpth,0.0,1.0); - -dpth=Limit+((1.0-Limit)-(Limit))*dpth; -dpth*=Flo; -//dpth=1.0; - -float vel=tex2D(texture2d_velocities,UV.xy).x; -if (dpth>0.02) -{ -for (int y=-4;y<5;y++) { - for (int x=-4;x<5;x++){ -count++; - -float2 dd=float2 (x,y)*0.7;//;*vec2 (3.0,3.0); - -//float2 dd2=float((x+4)*9+(y+4))*float2 (-1.0,1.0)*0.4; -//dd=dd+(dd2-dd)*-vel*0.4; - - -float2 Dist=dd*0.0018*dpth; -cl+=tex2D(texture2d_1,UV.xy+Dist); -//cl.x=dpth; - } -} - -cl/=float (count); -} -else -cl=tex2D(texture2d_1,UV.xy); - - - -if (vel>0.01) { -vec4 newcl=vec4 (0.0); -for (int x=0;x<15;x++){ -float2 dd2=float(x)*float2 (-1.0,1.0)*0.003*vel; -newcl+=tex2D(texture2d_1,UV.xy+dd2); -} -newcl*=1.0/15.0; - -cl=cl+(newcl-cl)*0.5; -} - - - -//cl*=0.4; - -//cl+=tex2D(texture2d_velocities,UV.xy)*0.5; - - -//cl=tex2D(texture2d_1,UV.xy); -//cl=vec4 (dpth); - -//cl=vec4 (tex2D(texture2d_2,UV.xy).x); - - - - -*/ - -cl=cll; - - - -gl_FragData[0]=cl; - gl_FragData[1]=cl; - -} - - - - - - - - - - - - - - diff --git a/tests/real/the wind under my wings/f_combineSSAO.cpp b/tests/real/the wind under my wings/f_combineSSAO.cpp deleted file mode 100644 index e5cb7c32..00000000 --- a/tests/real/the wind under my wings/f_combineSSAO.cpp +++ /dev/null @@ -1,316 +0,0 @@ -#version 110 -#define float4 vec4 -#define float3 vec3 -#define float2 vec2 -#define oUV gl_TexCoord[0] -#define tex3D texture3D -#define tex2D texture2D -#define tex1D texture1D - -#define SSAO se= ep+ddd*sign (dot (ray,norm))*ray; \ -occluderFragment = tex2D(texture2d_1,se.xy); \ -shadow=occluderFragment.w;\ -occluderFragment.a=tex2D (texture2d_2,se.xy).x;\ -occNorm = (occluderFragment.xyz*2.0)-vec3 (1.0);\ -depthDifference = depth-occluderFragment.a;\ -normDiff = 1.0-1.0*dot(occNorm,norm);\ -addition=step(0.00002,depthDifference)*normDiff*(1.0-smoothstep(0.000002,0.20,depthDifference));\ - bl += addition; - - - - - - - - uniform sampler2D texture2d_1; - uniform sampler2D texture2d_2; - uniform sampler2D texture2d_3; - uniform sampler2D texture2d_projected; - uniform sampler2D texture2d_random; - uniform float Limit; - uniform float fttime; -uniform mat4 ProjectionMatrix; - - - - - - - - - - - -void main (void) -{ -float4 cl; -float depth; - - - -// random vector -vec3 fres = normalize((texture2D(texture2d_random,oUV.xy*2.0+float2 (Limit*1.0)).xyz*2.0) - vec3(1.0)); - -// depth -depth=tex2D (texture2d_2,oUV.xy).x; - -vec3 ep=vec3 (oUV.xy,depth); -float bl=0.0; -vec3 ray; -vec3 se; -vec3 occNorm; -float depthDifference,normDiff; -float3 norm=((tex2D (texture2d_1,oUV.xy).xyz-0.5)*2.0); -float4 GlobalIllumination=float4 (0.0); -bl=1.0; - - - -float ddd=0.002; -float shadow; -float addition; -vec4 occluderFragment; - - //for (int i=0;i<24;i++) - -bool occluder; -occluder=true; -//if (tex2D(texture2d_1,oUV.xy).w<0.9) occluder=false; - -if (occluder) { - - -//1 -ray= reflect (vec3(0.53812504, 0.18565957, -0.43192),fres); -SSAO -//2 -ray= reflect (vec3(0.13790712, 0.24864247, 0.44301823),fres); -SSAO -//3 -ray= reflect (vec3(0.33715037, 0.56794053, -0.005789503),fres); -SSAO -//4 -ray= reflect ( vec3(-0.6999805, -0.04511441, -0.0019965635),fres); -SSAO -//5 -ray= reflect ( vec3(0.06896307, -0.15983082, -0.85477847),fres); -SSAO -//6 -ray= reflect (vec3(0.056099437, 0.006954967, -0.1843352),fres); -SSAO -//7 -ray= reflect ( vec3(-0.014653638, 0.14027752, 0.0762037),fres); -SSAO -//8 -ray= reflect ( vec3(0.010019933, -0.1924225, -0.034443386),fres); -SSAO -//9 -ray= reflect ( vec3(-0.35775623, -0.5301969, -0.43581226),fres); -SSAO -//10 -ray= reflect ( vec3(-0.3169221, 0.106360726, 0.015860917),fres); -SSAO -//11 -ray= reflect ( vec3(0.010350345, -0.58698344, 0.0046293875),fres); -SSAO -//12 - -ray= reflect ( vec3(-0.08972908, -0.49408212, 0.3287904),fres); -SSAO -//13 -ray= reflect ( vec3(0.7119986, -0.0154690035, -0.09183723),fres); -SSAO -//14 -ray= reflect ( vec3(-0.053382345, 0.059675813, -0.5411899),fres); -SSAO -//15 -ray= reflect ( vec3(0.035267662, -0.063188605, 0.54602677),fres); -SSAO -//16 -/* -ray= reflect ( vec3(-0.47761092, 0.2847911, -0.0271716),fres); -SSAO -//17 -ray= reflect ( vec3 ( -0.559644, -0.554896, -0.61554),fres); -SSAO -//18 -ray= reflect (vec3 ( 0.65487, 0.496541, -0.569729),fres); -SSAO -//19 -ray= reflect (vec3 ( 0.382319, -0.719566, 0.579705),fres); -SSAO -//20 -ray= reflect ( vec3 ( 0.800123, 0.344357, 0.491142),fres); -SSAO -//21 -ray= reflect ( vec3 ( 0.426191, -0.414526, 0.804071),fres); -SSAO -*/ - - - -bl=1.0-bl*0.09*5.10; -//bl=1.0-bl*0.09*0.80; - - - -//bl=1.0-clamp (bl,0.0,1.0); -//bl*=2.0; -//bl+=0.02; -} - -//bl=0.0; -norm=normalize(norm); -// SS lighting -float ccl=1.0-0.0*pow(dot (norm,float3 (0.0,0.0,1.0)),2.0); - -// shadow - -//bl=1.0; -//bl*=1.0-tex2D(texture2d_1,oUV.xy).w*0.5; - - -// SS Reflections -//float4 NormMot=norm.xyzz; -///float2 DiffusedUV=norm.xy*0.025+oUV.xy; -///float4 Refl=2.5*tex2D (texture2d_3,DiffusedUV); - - -gl_FragData[0]=bl*ccl*tex2D(texture2d_3,oUV.xy); - -gl_FragData[0]=tex2D(texture2d_1,oUV.xy); -gl_FragData[1]=tex2D(texture2d_3,oUV.xy); - - -int count=0; -vec4 Comp=vec4 (0.0); -vec4 Comp2=vec4 (0.0); -for (int y=-3;y<4;y++) { - for (int x=-3;x<4;x++){ -count++; -float2 dd=float2 (x,y)*0.0005+oUV.xy; -Comp+=tex2D (texture2d_1,dd); - } -} - -Comp/=float (count); -Comp2/=float (count); -vec4 ResDP=tex2D (texture2d_1,oUV.xy); - -Comp*=2.0; -Comp-=vec4 (1.0); - -ResDP*=2.0; -ResDP-=vec4 (1.0); - - -float dt=1.0*length (Comp.xyz-ResDP.xyz); -dt=4.0+3.8*(1.0-max (dt,1.0*(abs(dot (Comp,ResDP))))); -//dt=10.0*(max (dt,(abs(dot (Comp,ResDP))))); -//dt=0.2*abs(dot (Comp,ResDP)); -//dt=(3.0+3.0*(abs(dot (Comp,ResDP)))); -//dt=1.0; -//dt=1.0; -dt+=0.4; - -gl_FragData[0]=tex2D (texture2d_3,oUV.xy)*1.0*vec4 (dt); - -// fogging -gl_FragData[0]*=1.0-vec4 (pow (tex2D (texture2d_2,oUV.xy).x,30.0)); - -if (fttime>260.0) -gl_FragData[0]=tex2D (texture2d_3,oUV.xy); - - -//if (sin (oUV.y*1100.0)<0.0) gl_FragData[0]*=2.8*vec4 (0.6,0.6,0.6,0.6); -//if (sin (oUV.x*1200.0)<0.0) gl_FragData[0]*=vec4 (1.0,0.6,0.6,0.6); -//if (int(oUV.y*100.0)%2==0) gl_FragData[0]=vec4 (0.0); - -//gl_FragData[0]+=1.3*vec4 (pow(tex2D (texture2d_3,oUV.xy).x,3.0)); - -//gl_FragData[0]*=0.3; -//tex2D (texture2d_3,oUV.xy); - - -//dt=10.0*length (Comp.xyz-ResDP.xyz); -//gl_FragData[0]=vec4 (dt); - -//gl_FragData[0]=tex2D (texture2d_3,oUV.xy); -//gl_FragData[0]=vec4 (dt); -//gl_FragData[0]=tex2D (texture2d_3,oUV.xy)*vec4 (bl); - -//gl_FragData[0]=vec4(bl)*tex2D(texture2d_3,oUV.xy)+0.0*vec4 (0.0,0.05,0.1,0.0);; - -/* -if (oUV.y<0.5) -{ -if (oUV.x>0.5) -gl_FragData[0]=tex2D(texture2d_3,vec2 (1.0-oUV.x,oUV.y)); -else -gl_FragData[0]=tex2D(texture2d_3,oUV.xy); -} -else -{ - -if (oUV.x>0.5) -gl_FragData[0]=tex2D(texture2d_3,vec2 (1.0-oUV.x,1.0-oUV.y)); -else -gl_FragData[0]=tex2D(texture2d_3,vec2 (oUV.x,1.0-oUV.y)); -} -*/ - -/* -float ff=0.5*3.1515926535+atan ((oUV.x-0.5)/(oUV.y-0.5)); -ff=sin (0.5*ff); -float fd=length (oUV.xy-vec2 (0.5)); -///ff*=2.0; -//ff*=0.1; -vec2 Res=fd*vec2 (sin(ff),cos(ff)); - -gl_FragData[0]=tex2D (texture2d_3,Res); -//0.5+0.5*vec4(ff); - -*/ - - - -//gl_FragData[0]=tex2D(texture2d_3,oUV.xy)*1.2; - -//gl_FragData[0]=5.0*vec4 (pow(tex2D(texture2d_2,oUV.xy).x-0.7,4.0)); -//gl_FragData[0]=vec4(bl)*0.2+0.1*tex2D(texture2d_2,oUV.xy); - -//gl_FragData[0]=vec4(bl); -/* -if (occluder) -gl_FragData[0]=vec4(1.0); -else -gl_FragData[0]=vec4(0.0); -*/ - -// Highlights -//if (tex2D (texture2d_1,oUV.xy).w>0.9) gl_FragData[0]=tex2D (texture2d_3,oUV.xy); -//gl_FragData[0].w=tex2D (texture2d_1,oUV.xy).w; - -//gl_FragData[1]=tex2D(texture2d_3,oUV.xy); - -//gl_FragData[0]=tex2D (texture2d_2,oUV.xy); - - - - -} - - - - - - - - - - - - - - diff --git a/tests/real/the wind under my wings/f_godrays.cpp b/tests/real/the wind under my wings/f_godrays.cpp deleted file mode 100644 index 24b2fe6e..00000000 --- a/tests/real/the wind under my wings/f_godrays.cpp +++ /dev/null @@ -1,229 +0,0 @@ -#version 110 -#define float4 vec4 -#define float3 vec3 -#define float2 vec2 -#define oUV gl_TexCoord[0] -#define tex3D texture3D -#define tex2D texture2D -#define tex1D texture1D - - uniform sampler2D texture2d_1; -/* uniform sampler1D texture_transfer_function; - uniform sampler1D texture_palette_function; - - - uniform float3 VolumeSize; - uniform float3 RelativeSize; - uniform float3 Registration_Offset; - uniform float pet_alpha_blending; - uniform float3 MousePos; - uniform int Projection_mode; -uniform float3 InVolumePosition; - uniform float3 Windowing_Levels; - - uniform float isosurface; -uniform float Sharpening; - -*/ - - uniform float Limit; - - - - - - - -void main (void) -{ - - - - -float v=0.102; - -float dss=1.0-pow(length(oUV.xy-float2 (0.5,0.5)),1.0); -float2 dirr=float2 (0.5,0.5); -//dss=1; -//dss*=1.5; - -v*=dss*dss; -//v=0.002; -float2 MX=float2 (v,0.0); -float2 MU=float2 (0.0,v); -dirr.y*=1.0; - vec4 cl=float4 (0.0); -/* -for (int t=0;t<7;t++) { -float ff=float (t)/(20.0f); -// cl+=0.11*(1-ff)*tex2D (texture2d_1,ff*dirr+(1-ff)*oUV.st); -cl+=0.19*(1-ff)*tex2D (texture2d_1,ff*dirr+(1-ff)*oUV.st); - -} - -0.05,0.1,0.15,0.2,0.25,0.3 -*/ -//float cl=0.3; -float4 sti=tex2D (texture2d_1,oUV.st); -cl+=0.191*tex2D (texture2d_1,oUV.st); - -cl+=0.191*(0.95)*tex2D (texture2d_1,0.93*0.075*dirr+(1.0-0.93*0.075)*oUV.st); -cl+=0.191*(0.9)*tex2D (texture2d_1,0.93*0.15*dirr+(1.0-0.93*0.015)*oUV.st); -cl+=0.191*(0.85)*tex2D (texture2d_1,0.93*0.225*dirr+(1.0-0.93*0.225)*oUV.st); - -cl+=0.191*(0.8)*tex2D (texture2d_1,0.93*0.300*dirr+(1.0-0.93*0.300)*oUV.st); -cl+=0.191*(0.75)*tex2D (texture2d_1,0.93*0.375*dirr+(1.0-0.93*0.375)*oUV.st); -cl+=0.191*(0.7)*tex2D (texture2d_1,0.93*0.450*dirr+(1.0-0.93*0.450)*oUV.st); - -cl=tex2D(texture2d_1,oUV.st)+cl*0.7*float4 (0.4,0.6,1.0,0.0); -//cl*=dss*sti; - - - - - - - - - - - -//float4 cl; -//cl=tex2D (texture2d_1,oUV.xy)*1.0*vec4 (0.0,0.0,1.0,0.0); -cl=vec4 (0.0); -int count=0; -float2 DirV=oUV.xy-float2 (0.5,0.5); -//DirV=-normalize (DirV); -DirV*=-1.0; - for (int x=0;x<18;x++){ -count++; - -float2 Dist=DirV*float(x)*0.05; -float4 res=tex2D(texture2d_1,oUV.xy+Dist); -res*=res*1.5; -//res*=1.0+0.5*sin(oUV.x*12.0); -//res*=1.0+0.7*sin(oUV.y*24.0); -cl+=res; -} - -cl/=float (count); -cl=tex2D(texture2d_1,oUV.st)*0.9+cl*3.5; -//*float4 (0.4,0.6,1.0,0.0); -//cl*=float4 (1.0,1.0,1.0,1.0); - - - -/* -//Depth blurring - -float dpth=0; -int count=0; -for (int y=-4;y<5;y++) { - for (int x=-4;x<5;x++){ -count++; -float2 dd=float2 (x,y)*0.7; - -//dd=ray.xy*5.0; - -float2 Dist=dd*0.0015; -dpth+=tex2D(texture2d_2,UV.xy+Dist).x; -} -} -dpth/=float (count); -//dpth=sin(dpth*3.14159); -dpth+=0.1; -dpth=pow(dpth,6.0); -//dpth+=Limit; -dpth=1.1-dpth; -//if (dpth<0.7) dpth=0.0; -count=0; -cl=vec4(0.0); -dpth=clamp(dpth,0.0,1.0); - -dpth=Limit+((1.0-Limit)-(Limit))*dpth; - -if (dpth>0.02) { -for (int y=-4;y<5;y++) { - for (int x=-4;x<5;x++){ -count++; - -float2 dd=float2 (x,y); - -//if ( (x)==(y)) { dd*=120.0;} - -float2 Dist=dd*0.0015*dpth; -cl+=tex2D(texture2d_1,UV.xy+Dist); -} -} - -cl/=float (count); -} -else -cl=tex2D(texture2d_1,UV.xy); - - - -*/ - - - - - - - - - -gl_FragData[0]=cl; - gl_FragData[1]=cl; - -/* -float3 currentuv; - - - -if (Projection_mode==0) { -currentuv.xy=oUV.st; -currentuv.z=0.0+InVolumePosition.z; -} -else -if (Projection_mode==1) { -currentuv.xz=oUV.st; -currentuv.y=0.0+InVolumePosition.y; -} -else -if (Projection_mode==2) { -currentuv.zy=oUV.ts; -currentuv.x=0.0+InVolumePosition.x; -} -float4 original= tex3D (texture3d,currentuv); -float divisor=1.0/(Windowing_Levels.y-Windowing_Levels.x); - - - - -original-=Windowing_Levels.x*float4 (1,1,1,1); -original*=divisor; - - -//original.x=max (0.0,min (1.0,original.x)); - - -gl_FragColor=currentuv.xyzz; -//gl_FragColor=float4 (1.0,0.0,0.0,1.0); -//gl_FragColor*=Sharpening; -*/ -} - - - - - - - - - - - - - - diff --git a/tests/real/the wind under my wings/f_simpleblur.cpp b/tests/real/the wind under my wings/f_simpleblur.cpp deleted file mode 100644 index 23024b4c..00000000 --- a/tests/real/the wind under my wings/f_simpleblur.cpp +++ /dev/null @@ -1,175 +0,0 @@ -#version 110 -#define float4 vec4 -#define float3 vec3 -#define float2 vec2 -#define oUV gl_TexCoord[0] -#define tex3D texture3D -#define tex2D texture2D -#define tex1D texture1D - - uniform sampler2D texture2d_1; -/* uniform sampler1D texture_transfer_function; - uniform sampler1D texture_palette_function; - - - uniform float3 VolumeSize; - uniform float3 RelativeSize; - uniform float3 Registration_Offset; - uniform float pet_alpha_blending; - uniform float3 MousePos; - uniform int Projection_mode; -uniform float3 InVolumePosition; - uniform float3 Windowing_Levels; - - uniform float isosurface; -uniform float Sharpening; - -*/ - - uniform float Limit; - - - - - - - -void main (void) -{ - - - -float4 cl; -//cl=tex2D (texture2d_1,oUV.xy)*1.0*vec4 (0.0,0.0,1.0,0.0); -cl=vec4 (0.0); -int count=0; -for (int y=-6;y<7;y++) { - for (int x=-6;x<7;x++){ -count++; -float2 dd=float2 (x,y)*1.5; - -//dd=ray.xy*5.0; -float2 Dist=dd*0.15; -float4 res=tex2D(texture2d_1,oUV.xy+Dist); -cl+=res; -} -} -cl/=float (count); -//cl*=0.0; -cl=float4 (1.0,0.0,0.0,0.0); - -cl.w=tex2D (texture2d_1,oUV.xy).w; -/* -//Depth blurring - -float dpth=0; -int count=0; -for (int y=-4;y<5;y++) { - for (int x=-4;x<5;x++){ -count++; -float2 dd=float2 (x,y)*0.7; - -//dd=ray.xy*5.0; - -float2 Dist=dd*0.0015; -dpth+=tex2D(texture2d_2,UV.xy+Dist).x; -} -} -dpth/=float (count); -//dpth=sin(dpth*3.14159); -dpth+=0.1; -dpth=pow(dpth,6.0); -//dpth+=Limit; -dpth=1.1-dpth; -//if (dpth<0.7) dpth=0.0; -count=0; -cl=vec4(0.0); -dpth=clamp(dpth,0.0,1.0); - -dpth=Limit+((1.0-Limit)-(Limit))*dpth; - -if (dpth>0.02) { -for (int y=-4;y<5;y++) { - for (int x=-4;x<5;x++){ -count++; - -float2 dd=float2 (x,y); - -//if ( (x)==(y)) { dd*=120.0;} - -float2 Dist=dd*0.0015*dpth; -cl+=tex2D(texture2d_1,UV.xy+Dist); -} -} - -cl/=float (count); -} -else -cl=tex2D(texture2d_1,UV.xy); - - - -*/ - - - - - - - - - -gl_FragData[0]=cl; - gl_FragData[1]=cl; - -/* -float3 currentuv; - - - -if (Projection_mode==0) { -currentuv.xy=oUV.st; -currentuv.z=0.0+InVolumePosition.z; -} -else -if (Projection_mode==1) { -currentuv.xz=oUV.st; -currentuv.y=0.0+InVolumePosition.y; -} -else -if (Projection_mode==2) { -currentuv.zy=oUV.ts; -currentuv.x=0.0+InVolumePosition.x; -} -float4 original= tex3D (texture3d,currentuv); -float divisor=1.0/(Windowing_Levels.y-Windowing_Levels.x); - - - - -original-=Windowing_Levels.x*float4 (1,1,1,1); -original*=divisor; - - -//original.x=max (0.0,min (1.0,original.x)); - - -gl_FragColor=currentuv.xyzz; -//gl_FragColor=float4 (1.0,0.0,0.0,1.0); -//gl_FragColor*=Sharpening; -*/ -} - - - - - - - - - - - - - - diff --git a/tests/real/the wind under my wings/f_velocities.cpp b/tests/real/the wind under my wings/f_velocities.cpp deleted file mode 100644 index 383da003..00000000 --- a/tests/real/the wind under my wings/f_velocities.cpp +++ /dev/null @@ -1,39 +0,0 @@ -#version 110 -#define float4 vec4 -#define float3 vec3 -#define float2 vec2 -#define oUV gl_TexCoord[0] -#define tex3D texture3D -#define tex2D texture2D -#define tex1D texture1D - -varying vec3 normal; -varying vec4 position; -varying vec4 thecolor; - -varying vec2 texture_coordinate_1; - - - -void main (void) -{ - - - float4 TheNormal=float4 (1.0,0.0,0.0,0.0); -//TheNormal.w=shadow; -gl_FragData[0]=thecolor; -} - - - - - - - - - - - - - - diff --git a/tests/real/the wind under my wings/v_velocities.cpp b/tests/real/the wind under my wings/v_velocities.cpp deleted file mode 100644 index 0abe947d..00000000 --- a/tests/real/the wind under my wings/v_velocities.cpp +++ /dev/null @@ -1,114 +0,0 @@ -#define float4 vec4 -#define float3 vec3 -#define float2 vec2 - - - - -varying vec3 normal; -varying vec2 texture_coordinate_1; -varying vec4 position; -varying vec4 thecolor; - -uniform mat4 ProjectionMatrix; - - -void main() -{ -mat4 Billboard; - -vec4 glVertex=gl_Vertex; - -vec4 Next_Position; - -//gl_Position = gl_TextureMatrix[0] * gl_Vertex; - - - float4 MotionBlurPos_current=gl_TextureMatrix[0]*gl_Vertex; - float4 MotionBlurPos_previous=gl_TextureMatrix[1]*gl_Vertex; - - - -float3 MotionBlurmotionVector=MotionBlurPos_current.xyz-MotionBlurPos_previous.xyz; - - -float4 MotionBlurNormalDirection=float4 (0.0,0.0,0.0,0.0)-gl_Vertex.xyzz; -MotionBlurNormalDirection= -gl_Normal.xyzz*1.0; - - ///MotionBlurNormalDirection=gl_TextureMatrix[0]*MotionBlurNormalDirection; - // normalize (MotionBlurNormalDirection); - - - -float MotionBlurflag=dot (MotionBlurmotionVector.xyz,MotionBlurNormalDirection.xyz); -float4 MotionBlurstretch; - -float smm=0.0; -if (MotionBlurflag>-0.0) -{ - MotionBlurstretch = MotionBlurPos_current+(MotionBlurPos_previous-MotionBlurPos_current)*1.0; -smm=1.0; -} -else -{ -smm=0.3; - MotionBlurstretch= MotionBlurPos_current; -} - - - - //MotionBlurstretch = MotionBlurPos_current+(MotionBlurPos_previous-MotionBlurPos_current)*1.0; - - - - -//MotionBlurPos_current.xyz=MotionBlurPos_current.xyz/MotionBlurPos_current.w; -//MotionBlurstretch.xyz=MotionBlurstretch.xyz/MotionBlurstretch.w; -//MotionBlurstretch=MotionBlurPos_previous; -gl_Position = gl_ModelViewProjectionMatrix* MotionBlurstretch; - -float3 MotionBlur_dP=MotionBlurstretch.xyz-MotionBlurPos_current.xyz; - -float4 Mot=MotionBlur_dP.xyzz; -Mot=gl_ModelViewProjectionMatrix*Mot; -MotionBlur_dP.xyz=Mot.xyz; - -MotionBlur_dP+=float3 (1.0); -MotionBlur_dP*=0.5; - - -thecolor =MotionBlur_dP.xyzz; -//thecolor =MotionBlurNormalDirection.xyzz; -//thecolor=float4 (smm); -//thecolor=(MotionBlurPos_previous-MotionBlurPos_current).xyzz+float4 (0.5,0.5,0.5,0.5); -//thecolor=gl_TextureMatrix[0]*gl_Normal.xyzz; -//gl_Position= gl_ModelViewProjectionMatrix*gl_TextureMatrix[0]*gl_Vertex; - -//thecolor=MotionBlurstretch.xyzz; - - -// Transforming The Normal To ModelView-Space -// normal = gl_NormalMatrix * gl_Normal; - //normal = gl_Normal; -//texture_coordinate_1 = vec2(gl_MultiTexCoord0); - -//position=(glVertex).xyzw; -//ShadowPosZ= ProjectionMatrix * gl_TextureMatrix[0]*gl_Vertex; -//position=g -// Transforming The Vertex Position To ModelView-Space -// vec4 vertex_in_modelview_space = gl_ModelViewMatrx * gl_Vertex; - - // Calculating The Vector From The Vertex Position To The Light Position -// vertex_to_light_vector = vec3(gl_LightSource[0].position – vertex_in_modelview_space); -} - - - - - - - - - - - diff --git a/tests/real/tunnel.frag b/tests/real/tunnel.frag deleted file mode 100644 index 1ab25c20..00000000 --- a/tests/real/tunnel.frag +++ /dev/null @@ -1,22 +0,0 @@ -uniform vec2 resolution; -uniform float time; -uniform sampler2D tex0; -uniform sampler2D tex1; -uniform sampler2D tex2; -uniform sampler2D tex3; - -void main(void) -{ - vec2 p = -1.0 + 2.0 * gl_FragCoord.xy / resolution.xy; - vec2 uv; - - float a = atan(p.y,p.x); - float r = sqrt(dot(p,p)); - - uv.x = .75*time+.1/r; - uv.y = a/3.1416; - - vec3 col = texture2D(tex0,uv).xyz; - - gl_FragColor = vec4(col*r,1.0); -} diff --git a/tests/real/twist.frag b/tests/real/twist.frag deleted file mode 100644 index 82b4bea3..00000000 --- a/tests/real/twist.frag +++ /dev/null @@ -1,22 +0,0 @@ -uniform vec2 resolution; -uniform float time; -uniform sampler2D tex0; -uniform sampler2D tex1; -uniform sampler2D tex2; -uniform sampler2D tex3; - -void main(void) -{ - vec2 p = -1.0 + 2.0 * gl_FragCoord.xy / resolution.xy; - vec2 uv; - - float a = atan(p.y,p.x); - float r = sqrt(dot(p,p)); - - uv.x = r - .25*time; - uv.y = cos(a*5.0 + 2.0*sin(time+7.0*r)) ; - - vec3 col = (.5+.5*uv.y)*texture2D(tex0,uv).xyz; - - gl_FragColor = vec4(col,1.0); -} diff --git a/tests/real/z_invert.frag b/tests/real/z_invert.frag deleted file mode 100644 index b9092315..00000000 --- a/tests/real/z_invert.frag +++ /dev/null @@ -1,22 +0,0 @@ -uniform vec2 resolution; -uniform float time; -uniform sampler2D tex0; -uniform sampler2D tex1; -uniform sampler2D tex2; -uniform sampler2D tex3; - -void main(void) -{ - vec2 p = -1.0 + 2.0 * gl_FragCoord.xy / resolution.xy; - vec2 uv; - - float a = atan(p.y,p.x); - float r = sqrt(dot(p,p)); - - uv.x = cos(0.6+time) + cos(cos(1.2+time)+a)/r; - uv.y = cos(0.3+time) + sin(cos(2.0+time)+a)/r; - - vec3 col = texture2D(tex0,uv*.25).xyz; - - gl_FragColor = vec4(col*r*r,1.0); -} From beb23667ca16bd2aae85017f24dafc3f8e31b891 Mon Sep 17 00:00:00 2001 From: Laurent Le Brun Date: Wed, 4 Jan 2023 00:57:53 +0100 Subject: [PATCH 06/32] Add 3 more real shaders for testing (#205) --- Checker/compression_test.fs | 3 + tests/compression_results.log | 5 +- tests/real/buoy.frag | 424 ++++++++++++++++++++++++ tests/real/orchard.frag | 606 ++++++++++++++++++++++++++++++++++ tests/real/robin.frag | 459 +++++++++++++++++++++++++ 5 files changed, 1496 insertions(+), 1 deletion(-) create mode 100644 tests/real/buoy.frag create mode 100644 tests/real/orchard.frag create mode 100644 tests/real/robin.frag diff --git a/Checker/compression_test.fs b/Checker/compression_test.fs index bd0d4966..e853b5d8 100644 --- a/Checker/compression_test.fs +++ b/Checker/compression_test.fs @@ -28,6 +28,9 @@ let testFiles = [ "terrarium.frag" "leizex.frag" "elevated.hlsl" + "buoy.frag" + "orchard.frag" + "robin.frag" ] let writer = new StringWriter() diff --git a/tests/compression_results.log b/tests/compression_results.log index 513b4b68..521294cb 100644 --- a/tests/compression_results.log +++ b/tests/compression_results.log @@ -11,4 +11,7 @@ ohanami.frag 3293 => 746.366 terrarium.frag 3646 => 748.815 leizex.frag 2308 => 515.785 elevated.hlsl 3406 => 611.302 -Total: 71853 => 13128.467 +buoy.frag 4237 => 630.724 +orchard.frag 5618 => 1058.054 +robin.frag 6298 => 1067.719 +Total: 88006 => 15884.964 diff --git a/tests/real/buoy.frag b/tests/real/buoy.frag new file mode 100644 index 00000000..89ffb8a1 --- /dev/null +++ b/tests/real/buoy.frag @@ -0,0 +1,424 @@ +// Source: https://www.shadertoy.com/view/XdsGDB +// Created by TekF +// License Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License. + +const float tau = 6.28318530717958647692; + +// Gamma correction +#define GAMMA (2.2) + +vec3 ToLinear( in vec3 col ) +{ + // simulate a monitor, converting colour values into light values + return pow( col, vec3(GAMMA) ); +} + +vec3 ToGamma( in vec3 col ) +{ + // convert back into colour values, so the correct light will come out of the monitor + return pow( col, vec3(1.0/GAMMA) ); +} + +vec3 localRay; + +// Set up a camera looking at the scene. +// origin - camera is positioned relative to, and looking at, this point +// distance - how far camera is from origin +// rotation - about x & y axes, by left-hand screw rule, relative to camera looking along +z +// zoom - the relative length of the lens +void CamPolar( out vec3 pos, out vec3 ray, in vec3 origin, in vec2 rotation, in float distance, in float zoom, in vec2 fragCoord ) +{ + // get rotation coefficients + vec2 c = vec2(cos(rotation.x),cos(rotation.y)); + vec4 s; + s.xy = vec2(sin(rotation.x),sin(rotation.y)); // worth testing if this is faster as sin or sqrt(1.0-cos); + s.zw = -s.xy; + + // ray in view space + ray.xy = fragCoord.xy - iResolution.xy*.5; + ray.z = iResolution.y*zoom; + ray = normalize(ray); + localRay = ray; + + // rotate ray + ray.yz = ray.yz*c.xx + ray.zy*s.zx; + ray.xz = ray.xz*c.yy + ray.zx*s.yw; + + // position camera + pos = origin - distance*vec3(c.x*s.y,s.z,c.x*c.y); +} + + +// Noise functions, distinguished by variable types + +vec2 Noise( in vec3 x ) +{ + vec3 p = floor(x); + vec3 f = fract(x); + f = f*f*(3.0-2.0*f); +// vec3 f2 = f*f; f = f*f2*(10.0-15.0*f+6.0*f2); + + vec2 uv = (p.xy+vec2(37.0,17.0)*p.z); + + vec4 rg = textureLod( iChannel0, (uv+f.xy+0.5)/256.0, 0.0 ); + + return mix( rg.yw, rg.xz, f.z ); +} + +vec2 NoisePrecise( in vec3 x ) +{ + vec3 p = floor(x); + vec3 f = fract(x); + f = f*f*(3.0-2.0*f); +// vec3 f2 = f*f; f = f*f2*(10.0-15.0*f+6.0*f2); + + vec2 uv = (p.xy+vec2(37.0,17.0)*p.z); + + vec4 rg = mix( mix( + textureLod( iChannel0, (uv+0.5)/256.0, 0.0 ), + textureLod( iChannel0, (uv+vec2(1,0)+0.5)/256.0, 0.0 ), + f.x ), + mix( + textureLod( iChannel0, (uv+vec2(0,1)+0.5)/256.0, 0.0 ), + textureLod( iChannel0, (uv+1.5)/256.0, 0.0 ), + f.x ), + f.y ); + + + return mix( rg.yw, rg.xz, f.z ); +} + +vec4 Noise( in vec2 x ) +{ + vec2 p = floor(x.xy); + vec2 f = fract(x.xy); + f = f*f*(3.0-2.0*f); +// vec3 f2 = f*f; f = f*f2*(10.0-15.0*f+6.0*f2); + + vec2 uv = p.xy + f.xy; + return textureLod( iChannel0, (uv+0.5)/256.0, 0.0 ); +} + +vec4 Noise( in ivec2 x ) +{ + return textureLod( iChannel0, (vec2(x)+0.5)/256.0, 0.0 ); +} + +vec2 Noise( in ivec3 x ) +{ + vec2 uv = vec2(x.xy)+vec2(37.0,17.0)*float(x.z); + return textureLod( iChannel0, (uv+0.5)/256.0, 0.0 ).xz; +} + + +float Waves( vec3 pos ) +{ + pos *= .2*vec3(1,1,1); + + const int octaves = 5; + float f = 0.0; + + // need to do the octaves from large to small, otherwise things don't line up + // (because I rotate by 45 degrees on each octave) + pos += iTime*vec3(0,.1,.1); + for ( int i=0; i < octaves; i++ ) + { + pos = (pos.yzx + pos.zyx*vec3(1,-1,1))/sqrt(2.0); + f = f*2.0+abs(Noise(pos).x-.5)*2.0; + pos *= 2.0; + } + f /= exp2(float(octaves)); + + return (.5-f)*1.0; +} + +float WavesDetail( vec3 pos ) +{ + pos *= .2*vec3(1,1,1); + + const int octaves = 8; + float f = 0.0; + + // need to do the octaves from large to small, otherwise things don't line up + // (because I rotate by 45 degrees on each octave) + pos += iTime*vec3(0,.1,.1); + for ( int i=0; i < octaves; i++ ) + { + pos = (pos.yzx + pos.zyx*vec3(1,-1,1))/sqrt(2.0); + f = f*2.0+abs(NoisePrecise(pos).x-.5)*2.0; + pos *= 2.0; + } + f /= exp2(float(octaves)); + + return (.5-f)*1.0; +} + +float WavesSmooth( vec3 pos ) +{ + pos *= .2*vec3(1,1,1); + + const int octaves = 2; + float f = 0.0; + + // need to do the octaves from large to small, otherwise things don't line up + // (because I rotate by 45 degrees on each octave) + pos += iTime*vec3(0,.1,.1); + for ( int i=0; i < octaves; i++ ) + { + pos = (pos.yzx + pos.zyx*vec3(1,-1,1))/sqrt(2.0); + //f = f*2.0+abs(Noise(pos).x-.5)*2.0; + f = f*2.0+sqrt(pow(NoisePrecise(pos).x-.5,2.0)+.01)*2.0; + pos *= 2.0; + } + f /= exp2(float(octaves)); + + return (.5-f)*1.0; +} + +float WaveCrests( vec3 ipos, in vec2 fragCoord ) +{ + vec3 pos = ipos; + pos *= .2*vec3(1,1,1); + + const int octaves1 = 6; + const int octaves2 = 16; + float f = 0.0; + + // need to do the octaves from large to small, otherwise things don't line up + // (because I rotate by 45 degrees on each octave) + pos += iTime*vec3(0,.1,.1); + vec3 pos2 = pos; + for ( int i=0; i < octaves1; i++ ) + { + pos = (pos.yzx + pos.zyx*vec3(1,-1,1))/sqrt(2.0); + f = f*1.5+abs(Noise(pos).x-.5)*2.0; + pos *= 2.0; + } + pos = pos2 * exp2(float(octaves1)); + pos.y = -.05*iTime; + for ( int i=octaves1; i < octaves2; i++ ) + { + pos = (pos.yzx + pos.zyx*vec3(1,-1,1))/sqrt(2.0); + f = f*1.5+pow(abs(Noise(pos).x-.5)*2.0,1.0); + pos *= 2.0; + } + f /= 1500.0; + + f -= Noise(ivec2(fragCoord.xy)).x*.01; + + return pow(smoothstep(.4,-.1,f),6.0); +} + + +vec3 Sky( vec3 ray ) +{ + return vec3(.4,.45,.5); +} + + +vec3 boatRight, boatUp, boatForward; +vec3 boatPosition; + +void ComputeBoatTransform( void ) +{ + vec3 samples[5]; + + samples[0] = vec3(0,0, 0); + samples[1] = vec3(0,0, .5); + samples[2] = vec3(0,0,-.5); + samples[3] = vec3( .5,0,0); + samples[4] = vec3(-.5,0,0); + + samples[0].y = WavesSmooth(samples[0]); + samples[1].y = WavesSmooth(samples[1]); + samples[2].y = WavesSmooth(samples[2]); + samples[3].y = WavesSmooth(samples[3]); + samples[4].y = WavesSmooth(samples[4]); + + boatPosition = (samples[0]+samples[1]+samples[2]+samples[3]+samples[4])/5.0; + + boatRight = samples[3]-samples[4]; + boatForward = samples[1]-samples[2]; + boatUp = normalize(cross(boatForward,boatRight)); + boatRight = normalize(cross(boatUp,boatForward)); + boatForward = normalize(boatForward); + + boatPosition += .0*boatUp; +} + +vec3 BoatToWorld( vec3 dir ) +{ + return dir.x*boatRight+dir.x*boatUp+dir.x*boatForward; +} + +vec3 WorldToBoat( vec3 dir ) +{ + return vec3( dot(dir,boatRight), dot(dir,boatUp), dot(dir,boatForward) ); +} + +float TraceBoat( vec3 pos, vec3 ray ) +{ + vec3 c = boatPosition; + float r = 1.0; + + c -= pos; + + float t = dot(c,ray); + + float p = length(c-t*ray); + if ( p > r ) + return 0.0; + + return t-sqrt(r*r-p*p); +} + + +vec3 ShadeBoat( vec3 pos, vec3 ray ) +{ + pos -= boatPosition; + vec3 norm = normalize(pos); + pos = WorldToBoat(pos); + + vec3 lightDir = normalize(vec3(-2,3,1)); + float ndotl = dot(norm,lightDir); + + // allow some light bleed, as if it's subsurface scattering through plastic + vec3 light = smoothstep(-.1,1.0,ndotl)*vec3(1.0,.9,.8)+vec3(.06,.1,.1); + + // anti-alias the albedo + float aa = 4.0/iResolution.x; + + //vec3 albedo = ((fract(pos.x)-.5)*(fract(pos.y)-.5)*(fract(pos.z)-.5) < 0.0) ? vec3(0) : vec3(1); + vec3 albedo = vec3(1,.01,0); + albedo = mix( vec3(.04), albedo, smoothstep( .25-aa, .25, abs(pos.y) ) ); + albedo = mix( mix( vec3(1), vec3(.04), smoothstep(-aa*4.0,aa*4.0,cos(atan(pos.x,pos.z)*6.0)) ), albedo, smoothstep( .2-aa*1.5, .2, abs(pos.y) ) ); + albedo = mix( vec3(.04), albedo, smoothstep( .05-aa*1.0, .05, abs(abs(pos.y)-.6) ) ); + albedo = mix( vec3(1,.8,.08), albedo, smoothstep( .05-aa*1.0, .05, abs(abs(pos.y)-.65) ) ); + + vec3 col = albedo*light; + + // specular + vec3 h = normalize(lightDir-ray); + float s = pow(max(0.0,dot(norm,h)),100.0)*100.0/32.0; + + vec3 specular = s*vec3(1,1,1); + + vec3 rr = reflect(ray,norm); + specular += mix( vec3(0,.04,.04), Sky(rr), smoothstep( -.1, .1, rr.y ) ); + + float ndotr = dot(norm,ray); + float fresnel = pow(1.0-abs(ndotr),5.0); + fresnel = mix( .001, 1.0, fresnel ); + + col = mix( col, specular, fresnel ); + + return col; +} + + +float OceanDistanceField( vec3 pos ) +{ + return pos.y - Waves(pos); +} + +float OceanDistanceFieldDetail( vec3 pos ) +{ + return pos.y - WavesDetail(pos); +} + +vec3 OceanNormal( vec3 pos ) +{ + vec3 norm; + vec2 d = vec2(.01*length(pos),0); + + norm.x = OceanDistanceFieldDetail( pos+d.xyy )-OceanDistanceFieldDetail( pos-d.xyy ); + norm.y = OceanDistanceFieldDetail( pos+d.yxy )-OceanDistanceFieldDetail( pos-d.yxy ); + norm.z = OceanDistanceFieldDetail( pos+d.yyx )-OceanDistanceFieldDetail( pos-d.yyx ); + + return normalize(norm); +} + +float TraceOcean( vec3 pos, vec3 ray ) +{ + float h = 1.0; + float t = 0.0; + for ( int i=0; i < 100; i++ ) + { + if ( h < .01 || t > 100.0 ) + break; + h = OceanDistanceField( pos+t*ray ); + t += h; + } + + if ( h > .1 ) + return 0.0; + + return t; +} + + +vec3 ShadeOcean( vec3 pos, vec3 ray, in vec2 fragCoord ) +{ + vec3 norm = OceanNormal(pos); + float ndotr = dot(ray,norm); + + float fresnel = pow(1.0-abs(ndotr),5.0); + + vec3 reflectedRay = ray-2.0*norm*ndotr; + vec3 refractedRay = ray+(-cos(1.33*acos(-ndotr))-ndotr)*norm; + refractedRay = normalize(refractedRay); + + const float crackFudge = .0; + + // reflection + vec3 reflection = Sky(reflectedRay); + float t=TraceBoat( pos-crackFudge*reflectedRay, reflectedRay ); + + if ( t > 0.0 ) + { + reflection = ShadeBoat( pos+(t-crackFudge)*reflectedRay, reflectedRay ); + } + + + // refraction + t=TraceBoat( pos-crackFudge*refractedRay, refractedRay ); + + vec3 col = vec3(0,.04,.04); // under-sea colour + if ( t > 0.0 ) + { + col = mix( col, ShadeBoat( pos+(t-crackFudge)*refractedRay, refractedRay ), exp(-t) ); + } + + col = mix( col, reflection, fresnel ); + + // foam + col = mix( col, vec3(1), WaveCrests(pos,fragCoord) ); + + return col; +} + + +void mainImage( out vec4 fragColor, in vec2 fragCoord ) +{ + ComputeBoatTransform(); + + vec2 camRot = vec2(.5,.5)+vec2(-.35,4.5)*(iMouse.yx/iResolution.yx); + vec3 pos, ray; + CamPolar( pos, ray, vec3(0), camRot, 3.0, 1.0, fragCoord ); + + float to = TraceOcean( pos, ray ); + float tb = TraceBoat( pos, ray ); + + vec3 result; + if ( to > 0.0 && ( to < tb || tb == 0.0 ) ) + result = ShadeOcean( pos+ray*to, ray, fragCoord ); + else if ( tb > 0.0 ) + result = ShadeBoat( pos+ray*tb, ray ); + else + result = Sky( ray ); + + // vignette effect + result *= 1.1*smoothstep( .35, 1.0, localRay.z ); + + fragColor = vec4(ToGamma(result),1.0); +} diff --git a/tests/real/orchard.frag b/tests/real/orchard.frag new file mode 100644 index 00000000..e836d18c --- /dev/null +++ b/tests/real/orchard.frag @@ -0,0 +1,606 @@ +// Copied from https://www.shadertoy.com/view/wlVSz3 +// Orchard (Alternative Projection) +// by Dave Hoskins. March 2020 +// License Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License. + +// This breaks the effect a little... +//#define MOVE_CAMERA + + +int spointer; +vec3 sunLight; +#define SUN_COLOUR vec3(1., .9, .8) +#define FOG_COLOUR vec3(1., .7, .7) + +struct Stack +{ + vec3 pos; + float alpha; + float dist; + int mat; + +}; + +#define STACK_SIZE 8 +Stack stack[STACK_SIZE]; + +//============================================================================== +//-------------------------------------------------------------------------- +float getGroundHeight(vec2 p) +{ + float y =(sin(p.y*.23)+cos(p.x*.18))*.8; + return y; +} +//-------------------------------------------------------------------------- +mat3 getCamMat( in vec3 ro, in vec3 ta, float cr ) +{ + vec3 cw = normalize(ta-ro); + vec3 cp = vec3(sin(cr), cos(cr),0.0); + vec3 cu = normalize( cross(cw,cp) ); + vec3 cv = normalize( cross(cu,cw) ); + return mat3( cu, cv, cw ); +} + +//-------------------------------------------------------------------------- +// Loop the camposition around a uneven sine and cosine, and default the time 0 +// to be steep at a loop point by adding 140... +vec3 getCamPos(float t) +{ + //t = sin(t*.01)*200.; + t+=140.; + vec3 p = vec3(3.0+50.0*sin(t*.03), + 1.5, + 4.0 + 50.0*cos(t*.044)); + p.y-=getGroundHeight(p.xz); + return p; +} + +//---------------------------------------------------------------------------------------- +// 1 out, 1 in... +float hash11(float p) +{ + p = fract(p * .1031); + p *= p + 33.33; + p *= p + p; + return fract(p); +} +//---------------------------------------------------------------------------------------- +// 1 out, 2 in... +float hash12(vec2 p) +{ + vec3 p3 = fract(vec3(p.xyx) * .1031); + p3 += dot(p3, p3.yzx + 33.33); + return fract((p3.x + p3.y) * p3.z); +} + +// 1 out, 3 in... +vec3 hash31(float p) +{ + vec3 p3 = fract(vec3(p) * vec3(.1031, .1030, .0973)); + p3 += dot(p3, p3.yzx+33.33); + return fract((p3.xxy+p3.yzz)*p3.zyx); +} + +// 3 out, 3 in... +vec3 hash33(vec3 p3) +{ + p3 = fract(p3 * vec3(.1031, .1030, .0973)); + p3 += dot(p3, p3.yxz+33.33); + return fract((p3.xxy + p3.yxx)*p3.zyx); +} + + +//------------------------------------------------------------------------------ +float randomTint(vec3 pos) +{ + float r = texture(iChannel1, pos.xz*.0027).x; + return r+.5; +} + +//---------------------------------------------------------------------------------------- +vec3 texCube(sampler2D sam, in vec3 p, in vec3 n ) +{ + vec3 x = texture(sam, p.yz).xyz; + vec3 y = texture(sam, p.zx).xyz; + vec3 z = texture(sam, p.xy).xyz; + return (x*abs(n.x) + y*abs(n.y) + z*abs(n.z))/(abs(n.x)+abs(n.y)+abs(n.z)); +} + +//------------------------------------------------------------------------------ +vec4 grassTexture(vec3 pos, vec3 nor) +{ + + float g = texture(iChannel1, pos.xz*.5).x; + float s = texture(iChannel1, pos.xz*.015).x*.2; + + + vec3 flower = texture(iChannel2, pos.xz*.15).xyz; + float rand = texture(iChannel1, pos.xz*.003).x; + rand *= rand*rand; + + flower =pow(flower,vec3(8, 15, 5)) *10. * rand; + vec4 mat = vec4(g*.05+s, g*.65, 0, g*.1); + mat.xyz += flower; + + // Do the red ground lines... + pos = fract(pos); + mat = mix(mat, vec4(.2, 0,0,0), smoothstep(.05, .0,min(pos.x, pos.z)) + + smoothstep(.95, 1.,max(pos.x, pos.z))); + + + return min(mat, 1.0); +} + +//------------------------------------------------------------------------------ +vec4 barkTexture(vec3 p, vec3 nor) +{ + vec2 r = floor(p.xz / 5.0) * 0.02; + float br = texture(iChannel1, r).x; + vec3 mat = texCube(iChannel3, p*.4, nor) * vec3(.4, .3, .1*br) *br; + mat += texCube(iChannel3, p*.53, nor)*smoothstep(0.0,.3, mat.x)*br; + return vec4(mat, .1); +} + +//------------------------------------------------------------------------------ +vec4 leavesTexture(vec3 p, vec3 nor) +{ + + vec3 rand = texCube(iChannel2, p*.15,nor); + vec3 mat = vec3(0.4,1.2,0) *rand; + return vec4(mat, .0); +} + +//------------------------------------------------------------------------------ +vec4 fruitTexture(vec3 p, vec3 nor, float i) +{ + + + float rand = texCube(iChannel2, p*.1 ,nor).x; + float t = dot(nor, normalize(vec3(.8, .1, .1))); + vec3 mat = vec3(1.,abs(t)*rand,0); + mat = mix(vec3(0,1,0), mat, i/10.); + + return vec4(mat, .5); +} + + + +//------------------------------------------------------------------------------ +float distanceRayPoint(vec3 ro, vec3 rd, vec3 p, out float h) +{ + h = dot(p-ro,rd); + return length(p-ro-rd*h); +} + +//------------------------------------------------------------------------------ +const int SEEDS = 8 ; +const float STEP_SIZE = 2.; +#define SIZE .03 + + +// This seed code is the starfield stuff from iapafoto +// I've just removed the alpha part... +// https://www.shadertoy.com/view/Xl2BRR +mat2 rotMat2D(float a) +{ + float si = sin(a); + float co = cos(a); + return mat2(si, co, -co, si); +} + +vec3 floatingSeeds(in vec3 ro, in vec3 rd, in float tmax) +{ + + float d = 0.; + ro /= STEP_SIZE; + vec3 pos = floor(ro), + ri = 1./rd, + rs = sign(rd), + dis = (pos-ro + .5 + rs*0.5) * ri; + + float dint; + vec3 offset, id; + vec3 col = vec3(0); + vec3 sum = vec3(0); + //float size = .04; + + for( int i=0; i< SEEDS; i++ ) + { + id = hash33(pos); + + offset = clamp(id+.2*cos(id*iTime),SIZE, 1.-SIZE); + d = distanceRayPoint(ro, rd, pos+offset, dint); + + if (dint > 0. && dint * STEP_SIZE < tmax) + { + col = vec3(.4)*smoothstep(SIZE, 0.0,d); + sum += col; + } + vec3 mm = step(dis.xyz, dis.yxy) * step(dis.xyz, dis.zzx); + dis += mm * rs * ri; + pos += mm * rs; + } + + return sum * .7; +} + +//-------------------------------------------------------------------------- +float findClouds2D(in vec2 p) +{ + float a = 1.5, r = 0.0; + p*= .000001; + for (int i = 0; i < 5; i++) + { + r+= texture(iChannel1,p*=2.2).x*a; + a*=.5; + } + return max(r-1.5, 0.0); +} +//------------------------------------------------------------------------------ +// Use the difference between two cloud densities to light clouds in the direction of the sun. +vec4 getClouds(vec3 pos, vec3 dir) +{ + if (dir.y < 0.0) return vec4(0.0); + float d = (4000. / dir.y); + vec2 p = pos.xz+dir.xz*d; + float r = findClouds2D(p); + float t = findClouds2D(p+normalize(sunLight.xz)*30.); + t = sqrt(max((r-t)*20., .2))*2.; + vec3 col = vec3(t) * SUN_COLOUR; + // returns colour and alpha... + return vec4(col, r); +} + + +//------------------------------------------------------------------------------ +// Thanks to Fizzer for the space-folded tree idea... +/// https://www.shadertoy.com/view/4tVcWR +vec2 map(vec3 p, float t) +{ + + float matID, f; + p.y += getGroundHeight(p.xz); + float num = (floor(p.z/5.))*5.+(floor(p.x/5.0))*19.; + p.xz = mod(p.xz, 5.0)-2.5; + //p.xz *= rotMat2D(p.y*num/300.); // ... No, just too expensive. :) + + float d = p.y; + matID = 0.0; + + float s=1.,ss=1.6; + + // Tangent vectors for the branch local coordinate system. + vec3 w=normalize(vec3(-1.5+abs(hash11(num*4.)*.8),1,-1.)); + vec3 u=normalize(cross(w,vec3(0,1.,0.))); + + float scale=3.5; + p/=scale; + vec3 q = p; + // Make the iterations lessen over distance for speed up... + int it = 10-int(min(t*.03, 9.0)); + + float h = hash11(num*7.)*.3+.3; + vec3 uwc = normalize(cross(u,w)); + int dontFold = int(hash11(num*23.0) * 9.0)+3; + + float thick = .2/(h-.24); + for (int i = 0; i < it; i++) + { + f = scale*max(p.y-h,max(-p.y,length(p.xz)-.06/(p.y+thick)))/s; + if (f <= d) + { + d = f; + matID = 1.0; + } + + // Randomly don't fold the space to give more branch types... + if (i != dontFold) + p.xz = abs(p.xz); + + p.y-=h; + p*=mat3(u,uwc,w); + p*=ss; + s*=ss; + } + + float fr = .2; + f = (length(p)-fr)/s; + if (f <= d) + { + d = f; + matID = 2.0; + } + + q.y -= h*1.84; + h *= 1.1; + for (int i = 0; i < it; i++) + { + p = (normalize(hash31(num+float(i+19))-.5))*vec3(h, 0.1, h); + p+=q; + float ds =length(p)-.015; + if (ds <= d) + { + matID = 3.0+float(i); + d = ds; + } + } + + return vec2(d, matID); +} + +//------------------------------------------------------------------------------ +float sphereRadius(float t) +{ + t = abs(t-.0); + t *= 0.003; + return clamp(t, 1.0/iResolution.y, 3000.0/iResolution.y); +} + +//------------------------------------------------------------------------------ +float shadow( in vec3 ro, in vec3 rd, float dis) +{ + float res = 1.0; + float t = .1; + float h; + + for (int i = 0; i < 15; i++) + { + vec3 p = ro + rd*t; + + h = map(p,dis).x; + res = min(3.*h / t, res); + t += h; + } + res += t*t*.08; // Dim over distance + return clamp(res, .6, 1.0); +} + +//------------------------------------------------------------------------------------------- +// Taken almost straight from Inigo's shaders, thanks man! +// But I've changed a few things like the for-loop is now a float, +// which removes the need for the extra multiply and divide in GL2 +float calcOcc( in vec3 pos, in vec3 nor, float d ) +{ + float occ = 0.0; + float sca = 1.0; + for(float h= 0.05; h < .3; h+= .07) + { + vec3 opos = pos + h*nor; + float d = map( opos, d ).x; + occ += (h-d)*sca; + sca *= 0.95; + } + return clamp( 1.0 - 2.0*occ, 0.0, 1.0 ); +} + +//------------------------------------------------------------------------------------------- +float marchScene(in vec3 rO, in vec3 rD, vec2 co) +{ + float t = hash12(co)*.5; + vec4 normal = vec4(0.0); + vec3 p; + float alphaAcc = 0.0; + + spointer = 0; + for( int j=min(0,iFrame); j < 140; j++ ) + { + // Check if it's full or too far... + if (spointer == STACK_SIZE || alphaAcc >= 1.) break; + p = rO + t*rD; + float sphereR = sphereRadius(t); + vec2 h = map(p, t); + if( h.x <= sphereR) + { + //h = max(h,0.0); + float alpha = (1.0 - alphaAcc) * min(((sphereR-h.x+.01) / sphereR), 1.0); + stack[spointer].pos = p; + stack[spointer].alpha = alpha; + stack[spointer].dist = t; + stack[spointer].mat = int(h.y); + alphaAcc += alpha; + spointer++; + } + t += h.x+t*0.007; + } + return alphaAcc; +} + +//------------------------------------------------------------------------------------------- +vec3 lighting(in vec4 mat, in vec3 pos, in vec3 normal, in vec3 eyeDir, in float d) +{ + + float sh = shadow(pos+sunLight*.01, sunLight, d); + float occ = calcOcc(pos, normal, d); + // Light surface with 'sun'... + vec3 col = mat.xyz * SUN_COLOUR*(max(dot(sunLight,normal)*.5+.2, 0.0))*sh; + // Ambient... + + float fre = clamp(1.0+dot(normal,eyeDir),0.0,1.0)*.3; + float bac = clamp(.8*dot( normal, normalize(vec3(-sunLight.x,0.0,-sunLight.z))), 0.0, 1.0 ); + normal = reflect(eyeDir, normal); // Specular... + col += pow(max(dot(sunLight, normal), 0.0), 16.0) * SUN_COLOUR * sh * mat.w * occ; + col += bac*mat.xyz * occ; + col += mat.xyz * abs(normal.y)*.3*occ; + col += SUN_COLOUR * fre *.2*occ; + + return min(col, 1.0); +} + +//------------------------------------------------------------------------------ +vec3 getNormal2(vec3 p, float e) +{ + return normalize( vec3( map(p+vec3(e,0.0,0.0), 0.).x - map(p-vec3(e,0.0,0.0), 0.).x, + map(p+vec3(0.0,e,0.0), 0.).x - map(p-vec3(0.0,e,0.0), 0.).x, + map(p+vec3(0.0,0.0,e), 0.).x - map(p-vec3(0.0,0.0,e), 0.).x)); +} + +vec3 getNormal(vec3 pos, float ds) +{ + + float c = map(pos, 0.).x; + // Use offset samples to compute gradient / normal + vec2 eps_zero = vec2(ds, 0.0); + return normalize(vec3(map(pos + eps_zero.xyy, 0.0).x, map(pos + eps_zero.yxy, 0.0).x, + map(pos + eps_zero.yyx, 0.0).x) - c); +} + + +//------------------------------------------------------------------------------ +vec3 getSky(vec3 dir) +{ + vec3 col = mix(vec3(FOG_COLOUR), vec3(.0, 0.4,0.6),(abs(dir.y))); + return col; +} + +vec2 rot2D(inout vec2 p, float a) +{ + return cos(a)*p - sin(a) * vec2(p.y, -p.x); +} + +/* quaternions */ + +vec4 qmult(vec4 p, vec4 q) { + vec3 pv = p.xyz, qv = q.xyz; + return vec4(p.w * qv + q.w * pv + cross(pv, qv), p.w * q.w - dot(pv, qv)); +} + +vec4 qrotor(vec3 axis, float phi) { + phi *= 0.5; + return vec4(sin(phi) * normalize(axis), cos(phi)); +} + +vec3 rotate(vec3 point, vec4 rotor) { + vec3 rotv = rotor.xyz; + return qmult(rotor, vec4(point * rotor.w - cross(point, rotv), dot(point, rotv))).xyz; +} + +vec4 slerp(vec3 u0, vec3 u1, float t) { + return qrotor(cross(u0, u1), t * acos(dot(u0, u1))); +} +// Thaanks to DR2 for this matrix code... +mat3 viewMat (float ay, float az) +{ + vec2 o, ca, sa; + o = vec2 (ay, az); + ca = cos (o); + sa = sin (o); + return mat3 (ca.y, 0., - sa.y, 0., 1., 0., sa.y, 0., ca.y) * + mat3 (1., 0., 0., 0., ca.x, - sa.x, 0., sa.x, ca.x); +} + +//============================================================================== +void mainImage( out vec4 fragColour, in vec2 fragCoord ) +{ + vec2 mouseXY = iMouse.xy / iResolution.xy; + vec2 uv = (-iResolution.xy + 2.0 * fragCoord ) / iResolution.y; + sunLight = normalize(vec3(-.8,1.8,-1.5)); + + // Camera stuff... + // A simple cylindrical projection with normal Y + float time = iTime*1.+mouseXY.x*10.0; + + #ifdef MOVE_CAMERA + + vec3 camera = getCamPos(time*.2); + vec3 lookat = getCamPos(time*.2+10.); + + #else + + // Don't move the camera bodge... + vec3 camera = getCamPos(0.0); + vec3 lookat = getCamPos(0.0); + lookat += vec3(40.0*sin(time * 5.28), 0., 40.0*cos(time * .28) ); + + #endif + + float ride = sin(time*.5)*.4; + + + //mat3 camMat = getCamMat(camera, lookat, 0.0); + //uv *= .7; + // I didn't want to normalize here because it'll distort across the vertical slightly... + // But it looks like it's needed for a unit ray length... +// vec3 seedDir = camMat * normalize(vec3(0.0, uv.y, 1.)); +// seedDir.xz = rot2D(seedDir.xz, uv.x*1.13); // Adjusted for rotation PI (roughly!) :) + + + // Now using Quaternions, thanks to munrocket for the Quat code. + // https://www.shadertoy.com/view/3stXR2 +// Quarternion version.. +// vec3 seedDir = normalize(vec3(0,0, 1.)); +// vec2 rotXY = vec2(uv.x+time*.5, -uv.y+ride); +// vec4 rotor = qrotor(vec3(0., 1., 0.), rotXY.x); +// rotor = qmult(rotor, qrotor(vec3(1., 0., 0.), rotXY.y)); + //seedDir = rotate(seedDir, rotor); + + vec3 seedDir = normalize(vec3(0,0, 1.)); + seedDir = viewMat (uv.y+ride, uv.x+time*.5)*seedDir; + + + + vec3 rd = seedDir; + + vec3 col = vec3(0); + + vec3 sky = getSky(rd); + + + // Build the stack returning the final alpha value... + float alpha = marchScene(camera, rd, fragCoord); + vec4 mat; + // Render the stack... + if (alpha > .0) + { + for (int i = 0; i < spointer; i++) + { + vec3 pos = stack[i].pos; + float d = stack[i].dist; + + vec3 nor = getNormal(pos, sphereRadius(d)); + int matID = stack[i].mat; + if (matID == 0) mat = grassTexture(pos, nor); + else + if (matID == 1) mat = barkTexture(pos, nor); + else + if (matID == 2) mat = leavesTexture(pos, nor); + else + mat = fruitTexture(pos, nor, float(matID - 3)); + + mat *= randomTint(pos); + + vec3 temp = lighting(mat, pos, nor, rd, d); + if (matID == 3) temp=temp*.4+vec3(.15, .01,0); + + temp = mix(sky, temp , exp(-d*.01)); + col += temp * stack[i].alpha; + } + } + vec4 cc = getClouds(camera, rd); + sky+= pow(max(dot(sunLight, rd), 0.0), 20.0)*SUN_COLOUR*.03; + //sky = clamp(sky, 0.0,1.); + sky = mix(sky, cc.xyz, cc.w); + col += sky * (1.0-alpha); + + float d = stack[0].dist; + col+= floatingSeeds(camera, rd, d); + + + // Sun glow effect... + col+=pow(max(dot(sunLight, rd), 0.0), 6.0)*SUN_COLOUR*.2; + + // Clamp and contrast... + //col = col * vec3(1.1, 1.1,.9); + col = clamp(col,0.,1.); + col = col*col*(3.0-2.0*col); + + + // The usual vignette...which manages to add more vibrancy... + vec2 q = fragCoord / iResolution.xy; + col *= 0.3 + 0.7*pow(90.0*q.x*q.y*(1.0-q.x)*(1.0-q.y), 0.5); + // A nice fade in start... + + + col *= smoothstep(0.0, 5.0, time); + fragColour = vec4(sqrt(col), 1.0); + +} diff --git a/tests/real/robin.frag b/tests/real/robin.frag new file mode 100644 index 00000000..b71aa3f6 --- /dev/null +++ b/tests/real/robin.frag @@ -0,0 +1,459 @@ +// Copied from https://www.shadertoy.com/view/4tl3RM +// Robin +// License Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License. +// Created by David Hoskins. + +// The winter Robin - a UK resident bird. +// They occasionally sing at night next to street lights. +// Despite their cute appearance, they are aggressively territorial. + +// Sphere tracing based on eiffie's circle-of-confusion ideas. +// Distance estimation shapes, like 'Segment' - thanks to iq. + +//-------------------------------------------------------------------------- +#define SUN_COLOUR vec3(1., .76, .6) + +vec4 animParts; // .x = Puff Chest, head tilt, head nod, .w = tweet! +vec4 body; // .x = Tilt down, wings, jump, .w = crouching. +vec2 zoomTurn; // Zoom and turn hacked into a vec2 to keep the global vars low. + +vec4 aStack[2]; +vec4 dStack[2]; + +// CubeMap OpenGL clamping fix, thanks to w23/reinder... +vec3 CubeMap(in samplerCube sam, in vec3 v, float size) +{ + float M = max(max(abs(v.x), abs(v.y)), abs(v.z)); + float scale = (float(size) - 1.) / float(size); + if (abs(v.x) != M) v.x *= scale; + if (abs(v.y) != M) v.y *= scale; + if (abs(v.z) != M) v.z *= scale; + return texture(sam, v).xyz; +} + +//---------------------------------------------------------------------------------------- +float Hash(float p) +{ + vec2 p2 = fract(vec2(p * 5.3983, p * 5.4427)); + p2 += dot(p2.yx, p2.xy + vec2(21.5351, 14.3137)); + return fract(p2.x * p2.y * 95.4337); +} + +float Hash(vec2 p) +{ + p = fract(p * vec2(5.3983, 5.4427)); + p += dot(p.yx, p.xy + vec2(21.5351, 14.3137)); + return fract(p.x * p.y * 95.4337); +} + +//---------------------------------------------------------------------- +float noise( in vec3 x ) +{ + vec3 p = floor(x); + vec3 f = fract(x); + f = f*f*(3.0-2.0*f); + + vec2 uv = (p.xy+vec2(37.0,17.0)*p.z) + f.xy; + vec2 rg = textureLod( iChannel1, (uv+ 0.5)/256.0, 0.0 ).yx; + return mix( rg.x, rg.y, f.z ); +} + +//---------------------------------------------------------------------- +float fbm( vec3 p ) +{ + float f; + f = 1.600*noise( p ); p = p*2.02; + f += 0.3500*noise( p ); p = p*2.33; + f += 0.2250*noise( p ); p = p*2.01; + return f; +} + +vec2 Rot2(vec2 p, float a) +{ + float si = sin(a); + float co = cos(a); + return mat2(co, si, -si, co) * p; +} +float Noise(float n) +{ + float f = fract(n); + n = floor(n); + f = f*f*(3.0-2.0*f); + return mix(Hash(n), Hash(n+1.0), f); + +} + +float NoiseSlope(float n, float loc) +{ + float f = fract(n); + n = floor(n); + f = smoothstep(0.0, loc, f); + return mix(Hash(n), Hash(n+1.0), f); + +} +//---------------------------------------------------------------------------------------- +float Sphere( vec3 p, float s ) +{ + return length(p)-s; +} + +//-------------------------------------------------------------------------- +vec3 TexCube(in vec3 p, in vec3 n ) +{ + vec3 x = texture(iChannel0, p.yz ).xzy; + vec3 y = texture(iChannel0, p.zx ).xyz; + //y = y*y; + vec3 z = texture(iChannel1, p.xy, 2.0).yyy; + return (x*abs(n.x) + y*abs(n.y) + z*abs(n.z))/(abs(n.x)+abs(n.y)+abs(n.z))*.9; +} + +float Cylinder( vec3 p, vec2 h ) +{ + vec2 d = abs(vec2(length(p.xz),p.y)) - h; + return min(max(d.x,d.y),0.0) + length(max(d,0.0)); +} + +//---------------------------------------------------------------------------------------- +float Segment(vec3 p, vec3 a, vec3 b, float r1, float r2) +{ + vec3 pa = p - a; + vec3 ba = b - a; + float h = clamp( dot(pa,ba)/dot(ba,ba), 0.0, 1.0 ); + return length( pa - ba*h ) - r1 + r2*h; +} + +//---------------------------------------------------------------------------------------- +float RoundBox( vec3 p, vec3 b, float r ) +{ + return length(max(abs(p)-b,0.0))-r; +} + +//---------------------------------------------------------------------------------------- +float sMin( float a, float b, float k ) +{ + + float h = clamp(0.5 + 0.5*(b-a)/k, 0.0, 1.0 ); + return mix( b, a, h ) - k*h*(1.-h); +} +//---------------------------------------------------------------------------------------- +vec3 Colour( vec3 p, vec3 nor, out float spec) +{ + vec3 post = p; + p.xz = Rot2(p.xz, zoomTurn.x); + vec3 orig = p; + p.y-=body.z; + p.yz = Rot2(p.yz, body.x); + vec3 mat = TexCube(p*.5, nor).zxy * .45; + + spec = 0.0; + + // Body + float d = RoundBox(p-vec3(0.0, -1.4,-.3),vec3(.3+.1*animParts.x, .0, .1+.3*animParts.x), .3); + d = sMin(d, Sphere(p-vec3(0.0, -.25,0.0), 1.33), 2.2); + + // Wings... + vec3 p2 = p; + p2.x = abs(p2.x); + d = sMin(d,Segment(p2,vec3(1.5, -.2,1.7), vec3(1.5, -1.,-1.6), .3, .3), .4); + vec3 wing = vec3(.4, 0.32, 0.2)*texture(iChannel1, p2.zy*vec2(.05, .3)).x; + mat = mix(wing*wing, mat, clamp(Segment(p2,vec3(1.3, 0.2,.2), vec3(1.5+body.y, -1.,-1.6), .4, .4), 0., 1.0)); + + // Tail... + vec3 tail = vec3(.4)*texture(iChannel1, p.zy*vec2(.05, .3)).x; + mat = mix(tail*tail, mat, clamp(Segment(p2,vec3(.1, -.5, -1.5), vec3(.15, -1.2, -8.0), .2, .2), 0.0, 1.0)); + + p2 = p; + p2.xy = Rot2(p2.xy, animParts.y); // Tilt head + p2.zy = Rot2(p2.zy, animParts.z); // Nod + + // Red Breast and head... + d = sMin(d, Sphere(p2-vec3(0.0, 1.,1.4), .8), 1.0); + float f = Sphere(p-vec3(0.0, -.9, 2.1), 1.5); + f = min(f, Sphere(p2-vec3(0.0, .5, 1.9),1.2)); + f += fbm(p*20.0)*.2; + f = max(f, -Sphere(p2-vec3(0.0, 2.0, 1.2), 1.1)); + mat = mix(mat,vec3(.4, .1, 0.0) * (.8+fbm(p*12.)*.2), clamp((d-f)*3.0 - (1.0-step(-3.0, orig.y))*3.0,0.0, 1.0)); + + // Beak... + if (d > Segment(p2-vec3(0.0, .9,2.5),vec3(0.0, 0.0,-.4), vec3(.0, animParts.w*.2,.4), .15, .1)) + { + spec = .2; + mat = vec3(0.02, 0.01, 0.); + } + // Black shiny eyes + p2.x = abs(p2.x); + if (Sphere(p2-vec3(.35, 1.1,2.05), .11) < d) + { + mat = vec3(0.); + spec = .25; + } + // Post... + vec3 pCol = mix(vec3(.2), vec3(.05,.04, .0),fbm(post*2.0)*.5); + pCol = mix( pCol,vec3(.05), abs(sin( length(post.xz-vec2(0.2, .4))*34.0))*abs(nor.y)); + mat = mix(pCol,mat, step(-3.4, post.y)); + + // Legs... + orig.y-=body.w; + orig.x = abs(orig.x); + f = 1.0-clamp(Segment(orig,vec3(0.5, -2.0-body.z,-.5), vec3(.8, -3.5,0.6), .53, .03)+(1.0-step(-3.5,orig.y))*50.0, .0, 1.0); + mat = mix( mat, vec3(.05,.02, .02), f); + spec = mix(spec, .1, f); + + return mat; + + +} + +//-------------------------------------------------------------------------- + +float Map( vec3 p ) +{ + float d; + vec3 post = p; + + p.xz = Rot2(p.xz, zoomTurn.x); + vec3 o = p; + + p.y-=body.z; + p.yz = Rot2(p.yz, body.x); + // Body + d = RoundBox(p-vec3(0.0, -1.4,-.3),vec3(.3+.1*animParts.x, .0, .1+.3*animParts.x), .3); + d = sMin(d, Sphere(p-vec3(0.0, -.25,0.0), 1.33), 2.2); + + //Wings... + vec3 p2 = p; + p2.x = abs(p2.x); + d = sMin(d,Segment(p2,vec3(1.3, 0.2,.2), vec3(1.5+body.y, -.5,-1.6), .2, .2), .4); + + + // Tail... + d = sMin(d,Segment(p2,vec3(.6, -.5, -1.5), vec3(.15, -1.2, -8.0), .2, .2), 2.4); + + // Rotate head.. + p.xy = Rot2(p.xy, animParts.y); + p.zy = Rot2(p.zy, animParts.z); + + // Head... + d = sMin(d, Sphere(p-vec3(0.0, 1.,1.4), .8), 1.0); + //animParts.w = .1; + // Beak... + d = sMin(d,Segment(p-vec3(0.0, 1.,2.5),vec3(0.0, 0.0,-.4), vec3(.0, animParts.w*.2,.15), .1, .096), .2); + d = sMin(d,Segment(p-vec3(0.0, 1.05,2.5),vec3(0.0, -animParts.w*.25,-1.5), vec3(.0, -animParts.w,.16), .1, .1), .05); + // Eyes... + p.x = abs(p.x); + d = min(d, Sphere(p-vec3(.35, 1.1,2.05), .11)); + // Post... + d = min(d, Cylinder(post-vec3(0.2, -12.0, .4), vec2(1.8, 8.5)- fbm(post*5.0)*.1)); + // Legs... + o.x = abs(o.x); + o.y-=body.w; + d = min(d, Segment(o,vec3(0.5, -2.+body.z+body.w,-.5), vec3(.8, -3.5,0.5), .09, .1)); + d = min(d, Segment(o,vec3(.8, -3.5,0.5), vec3(.8, -3.5,1.2), .04, .04)); + d = min(d, Segment(o,vec3(.8, -3.5,0.5), vec3(1.4, -3.5,0.8), .04, .04)); + d = min(d, Segment(o,vec3(.8, -3.5,0.5), vec3(.1, -3.5,0.8), .04, .04)); + + return d; +} + + +//-------------------------------------------------------------------------- +float Shadow( in vec3 ro, in vec3 rd) +{ + float res = 1.0; + float t = 0.01; + float h; + + for (int i = 0; i < 8; i++) + { + h = Map( ro + rd*t ); + res = min(2.5*h / t, res); + t += h*.5+.05; + } + return max(res, 0.0); +} + +////-------------------------------------------------------------------------- +vec3 DoLighting(in vec3 mat, in vec3 pos, in vec3 normal, in vec3 eyeDir, in float d, in float specular) +{ + vec3 sunLight = normalize( vec3( -.1, 0.4, 0.3 ) ); + float sh = Shadow(pos, sunLight); + // Light surface with 'sun'... + vec3 col = mat * SUN_COLOUR*(max(dot(sunLight,normal), 0.0)) *sh; + // Ambient... + col += mat * CubeMap(iChannel3, normal, 64.0)*.5; + + normal = reflect(eyeDir, normal); // Specular... + col += pow(max(dot(sunLight, normal), 0.0), 1.0) * SUN_COLOUR* texture(iChannel3, normal).xyz * specular *sh; + return col; +} + + +//-------------------------------------------------------------------------- +vec3 GetNormal(vec3 p, float sphereR) +{ + vec2 eps = vec2(.01, 0.0); + return normalize( vec3( + Map(p+eps.xyy) - Map(p-eps.xyy), + Map(p+eps.yxy) - Map(p-eps.yxy), + Map(p+eps.yyx) - Map(p-eps.yyx) ) ); +} + +//-------------------------------------------------------------------------- +float SphereRadius(in float t) +{ + return t*.012; + //return max(t, 4.0/iResolution.x); +} + +//-------------------------------------------------------------------------- +float Scene(in vec3 rO, in vec3 rD, in vec2 fragCoord) +{ + //float t = 0.0; + float t = 2.+.1 * Hash(fragCoord.xy*fract(iTime)); + float alphaAcc = 0.0; + vec3 p = vec3(0.0); + int hits = 0; + + for( int j=0; j < 40; j++ ) + { + if (hits == 8 || alphaAcc >=1.0 || t > 45.0) break; + p = rO + t*rD; + float sphereR = SphereRadius(t); + float h = Map(p); + // Is it within the sphere?... + if( h < sphereR) + { + // Accumulate the alphas with the scoop of geometry from the sphere... + // Think of it as filling up an expanding ice-cream scoop flying out of the camera! + float alpha = max((1.0 - alphaAcc) * min(((sphereR-h) / sphereR), 1.0),0.0); + // put it on the 2 stacks, alpha and distance... + aStack[1].yzw = aStack[1].xyz; aStack[1].x = aStack[0].w; aStack[0].yzw = aStack[0].xyz; aStack[0].x = alpha; + dStack[1].yzw = dStack[1].xyz; dStack[1].x = dStack[0].w; dStack[0].yzw = dStack[0].xyz; dStack[0].x = t; + alphaAcc += alpha; + hits++; + } + t += h*.8; + } + return clamp(alphaAcc, 0.0, 1.0); +} + + +//-------------------------------------------------------------------------- +vec3 PostEffects(vec3 rgb, vec2 xy) +{ + // Gamma first... + rgb = sqrt(rgb); + + // Then... + #define CONTRAST 1.1 + #define SATURATION 1.2 + #define BRIGHTNESS 1.15 + rgb = mix(vec3(.5), mix(vec3(dot(vec3(.2125, .7154, .0721), rgb*BRIGHTNESS)), rgb*BRIGHTNESS, SATURATION), CONTRAST); + + // Vignette... + + rgb *= .5 +.5* pow(100.0*xy.x*xy.y*(1.0-xy.x)* (1.0-xy.y), 0.4); + + + return clamp(rgb, 0.0, 1.0); +} + + +//-------------------------------------------------------------------------- +vec3 CameraPath( float t ) +{ + //t = sin(t*.3); + t+= 5.0; + vec3 p = vec3(1.4+sin(t)*3.5, -.2, 5.0-+sin(t)*2.5); + return p; +} + +float TweetVolume(float t) +{ + float n = NoiseSlope(t*11.0, .1) * abs(sin(t*14.0))*.5; + n = (n*smoothstep(0.4, 0.9, NoiseSlope(t*.5+4.0, .1))); + return n; +} + + +//-------------------------------------------------------------------------- +void mainImage( out vec4 fragColor, in vec2 fragCoord ) +{ + float m = (iMouse.x/iResolution.x)*20.0; + float gTime = iTime; + vec2 xy = fragCoord.xy / iResolution.xy; + vec2 uv = (-1.0 + 2.0 * xy) * vec2(iResolution.x/iResolution.y,1.0); + + float t = mod(gTime, 40.0); + zoomTurn.y = smoothstep(6.0, 0.0, t)+smoothstep(39.0, 40.0, t); + + vec3 cameraPos = CameraPath(gTime*.2); + cameraPos.z += zoomTurn.y*8.0; + + vec3 camTarget = vec3(Noise(gTime*1.9-30.0)*.5-.25,Noise(gTime*2.0)*.5-.3,.0); + + + vec3 cw = normalize(camTarget-cameraPos); + vec3 cp = vec3(0.0, 1.0, 0.0); + vec3 cu = normalize(cross(cw,cp)); + vec3 cv = cross(cu,cw); + vec3 dir = normalize(uv.x*cu + uv.y*cv + (1.0- zoomTurn.y*.4)*cw); + + // Puff Chest... + animParts.x = Noise(gTime*2.0)+1.0; + // head tilt... + animParts.y = (NoiseSlope(gTime*1.2+sin(gTime*.3)*.7+.7, .05)-.5)* 1.5; + // Nod... + animParts.z = (NoiseSlope(gTime*.4-33.0, .05))* .5; + // Tweet... + + animParts.w = TweetVolume(gTime)*.8+.02; + body.x = sin(NoiseSlope(gTime*.5, .3)*4.14) *.25+.25; + body.y = NoiseSlope(gTime*.73, .3); + t = mod(gTime*2., 15.0); + body.z = -(smoothstep(0.0, .5, t)* smoothstep(.6,.5, t )) * .5; + animParts.z -= body.z; + body.y = body.z; + float jump = smoothstep(0.4, .6, t)* smoothstep(.8,.6, t ) * .8; + body.z += jump; + body.w = jump; + zoomTurn.x = smoothstep(0.4, .8, t); + if (mod(gTime*2.0, 30.0) >= 15.0) + { + zoomTurn.x = 1.0- zoomTurn.x; + } + vec3 col = vec3(.0); + + for (int i = 0; i <2; i++) + { + dStack[i] = vec4(-20.0); + aStack[i] = vec4(0.0); + } + float alpha = Scene(cameraPos, dir, fragCoord); + + // Render both stacks... + for (int s = 0; s < 2; s++) + { + for (int i = 0; i < 4; i++) + { + float specular = 0.0; + + float d = dStack[s][i]; + if (d < 0.0) continue; + float sphereR = SphereRadius(d); + vec3 pos = cameraPos + dir * d; + vec3 normal = GetNormal(pos, sphereR); + vec3 alb = Colour(pos, normal, specular); + col += DoLighting(alb, pos, normal, dir, d, specular)* aStack[s][i]; + } + } + // Fill in the rest with woodland background... + float mi = smoothstep(1.9, .0, zoomTurn.y); + vec3 back = mix(CubeMap(iChannel2, dir, 128.0), CubeMap(iChannel3, dir, 64.0)*.7, mi); + col += back* back*SUN_COLOUR* (1.0-alpha); + + + col = PostEffects(col, xy) * smoothstep(.0, 2.0, iTime); + + fragColor=vec4(col,1.0); +} From edfe6164980c49e141db5764e84ce9506a8e65f8 Mon Sep 17 00:00:00 2001 From: Laurent Le Brun Date: Wed, 4 Jan 2023 02:29:26 +0100 Subject: [PATCH 07/32] Augmented operators: x=x+... becomes x+= (#206) Data point: this saves 28 bytes before compression, but not even a byte after compression --- README.md | 23 +++++++++++++++++++ src/rewriter.fs | 8 +++++++ tests/commands.txt | 1 + tests/compression_results.log | 12 +++++----- tests/real/kinder_painter.expected | 14 +++++------ tests/real/mandelbulb.expected | 10 ++++---- tests/real/slisesix.frag.expected | 6 ++--- tests/real/terrarium.frag.expected | 18 +++++++-------- ...real_party_is_in_your_pocket.frag.expected | 2 +- tests/unit/augmented.frag | 13 +++++++++++ tests/unit/augmented.frag.expected | 14 +++++++++++ 11 files changed, 90 insertions(+), 31 deletions(-) create mode 100644 tests/unit/augmented.frag create mode 100644 tests/unit/augmented.frag.expected diff --git a/README.md b/README.md index f65d435d..0eb4a029 100644 --- a/README.md +++ b/README.md @@ -467,6 +467,29 @@ be an issue. Disable this transformation with the flag `--no-move-declarations`. +### Augmented operators + +We use the augmented operators (e.g. `+=`) where possible. + +Input: +```glsl +spe=spe*spe; +x=x-.5; +a=a+(a<<3); +a=a^a>>15; +``` + +Output: +```glsl +spe*=spe; +x-=.5; +a+=a<<3; +a^=a>>15; +``` + +This transformation always reduces the size of the output. However, this seems +to have negligible impact on the size after compression. + ### Rename vector fields To access fields of a vector, it is possible to use `.rgba` fields, or `.xyzw`, diff --git a/src/rewriter.fs b/src/rewriter.fs index b7c56fca..9a1052f6 100644 --- a/src/rewriter.fs +++ b/src/rewriter.fs @@ -97,6 +97,9 @@ let (|Number|_|) = function | Float (f, _) -> Some f | _ -> None +let augmentableOperators = set ["+"; "-"; "*"; "/"; "%"; "<<"; ">>"; "&"; "^"; "|"] + + let private simplifyOperator env = function | FunCall(Op "-", [Int (i1, su)]) -> Int (-i1, su) | FunCall(Op "-", [FunCall(Op "-", [e])]) -> e @@ -173,6 +176,11 @@ let private simplifyOperator env = function // x-(y-z) -> x-y+z | FunCall(Op "-", [x; FunCall(Op "-", [y; z])]) -> FunCall(Op "+", [FunCall(Op "-", [x; y]); z]) |> env.fExpr env + + // Match: x = x + ... + | FunCall(Op "=", [Var x; FunCall(Op op, [Var y; e])]) + when x.Name = y.Name && augmentableOperators.Contains op -> + FunCall(Op (op + "="), [Var x; e]) | e -> e diff --git a/tests/commands.txt b/tests/commands.txt index db549dc4..9e73185e 100644 --- a/tests/commands.txt +++ b/tests/commands.txt @@ -21,6 +21,7 @@ --no-renaming --no-inlining --format indented -o tests/unit/pi.frag.expected tests/unit/pi.frag --no-renaming --no-inlining --format indented -o tests/unit/vectors.frag.expected tests/unit/vectors.frag --no-renaming --format indented -o tests/unit/deadcode.frag.expected tests/unit/deadcode.frag +--no-renaming --no-inlining --format indented -o tests/unit/augmented.frag.expected tests/unit/augmented.frag # Inlining unit tests diff --git a/tests/compression_results.log b/tests/compression_results.log index 521294cb..f3424abc 100644 --- a/tests/compression_results.log +++ b/tests/compression_results.log @@ -1,17 +1,17 @@ from-the-seas-to-the-stars.frag 14347 => 2353.607 -the_real_party_is_in_your_pocket.frag 12214 => 1829.362 +the_real_party_is_in_your_pocket.frag 12213 => 1829.362 ed-209.frag 7899 => 1359.091 valley_ball.glsl 4419 => 896.357 lunaquatic.frag 5232 => 1056.700 -slisesix.frag 4546 => 957.481 +slisesix.frag 4543 => 958.065 yx_long_way_from_home.frag 2993 => 614.607 oscars_chair.frag 4649 => 982.393 -kinder_painter.frag 2901 => 456.603 +kinder_painter.frag 2894 => 456.030 ohanami.frag 3293 => 746.366 -terrarium.frag 3646 => 748.815 +terrarium.frag 3633 => 749.292 leizex.frag 2308 => 515.785 elevated.hlsl 3406 => 611.302 buoy.frag 4237 => 630.724 orchard.frag 5618 => 1058.054 -robin.frag 6298 => 1067.719 -Total: 88006 => 15884.964 +robin.frag 6294 => 1066.421 +Total: 87978 => 15884.156 diff --git a/tests/real/kinder_painter.expected b/tests/real/kinder_painter.expected index 21ac0d8a..b460a112 100644 --- a/tests/real/kinder_painter.expected +++ b/tests/real/kinder_painter.expected @@ -54,12 +54,12 @@ "{" "vec3 nor;" "if(col.w>2.5)" - "nor.xz=inter.xz-obj.xz,nor.y=0.,nor=nor/obj.w,uv=vec2(nor.x,inter.y);" + "nor.xz=inter.xz-obj.xz,nor.y=0.,nor/=obj.w,uv=vec2(nor.x,inter.y);" "else" " if(col.w>1.5)" "nor=obj.xyz,uv=inter.xz*.2;" "else" - " nor=inter-obj.xyz,nor=nor/obj.w,uv=nor.xy;" + " nor=inter-obj.xyz,nor/=obj.w,uv=nor.xy;" "return nor;" "}" "vec4 cmov(vec4 a,vec4 b,bool cond)" @@ -131,8 +131,8 @@ "ref.xyz=reflect(rd,nor);" "spe=dot(ref.xyz,luz.xyz);" "spe=max(spe,0.);" - "spe=spe*spe;" - "spe=spe*spe;" + "spe*=spe;" + "spe*=spe;" "if(intersectShadow(inter,luz.xyz,luz.w))" "dif=0.;" "col*=texture2D(tex0,uv);" @@ -141,8 +141,8 @@ "dif=dot(nor,-rd);" "ref.w=dif;" "dif=1.-dif*dif;" - "dif=dif*dif;" - "col=col+.35*vec4(dif);" + "dif*=dif;" + "col+=.35*vec4(dif);" "return col;" "}" "void main()" @@ -174,7 +174,7 @@ "luz.xyz=luz.xyz/luz.w;" "col=basicShade(inter,obj,col,rd,luz,ref);" "tmin=intersect(inter,ref.xyz,obj,col2);" - "inter=inter+ref.xyz*tmin;" + "inter+=ref.xyz*tmin;" "luz.xyz=vec3(0,1.5,-1)-inter;" "luz.w=length(luz.xyz);" "luz.xyz=luz.xyz/luz.w;" diff --git a/tests/real/mandelbulb.expected b/tests/real/mandelbulb.expected index e977b683..7b959b31 100644 --- a/tests/real/mandelbulb.expected +++ b/tests/real/mandelbulb.expected @@ -28,11 +28,11 @@ const char *mandelbulb_frag = "for(int t=1;t<7;t++)" "{" "\n#if 0\n" - "float z=sqrt(dot(i,i)),c=acos(i.y/z),o=atan(i.x,i.z);" + "float z=sqrt(dot(i,i)),o=acos(i.y/z),c=atan(i.x,i.z);" "z=pow(z,8.);" - "c=c*8.;" - "o=o*8.;" - "i=v+z*vec3(sin(c)*sin(o),cos(c),sin(c)*cos(o));" + "o*=8.;" + "c*=8.;" + "i=v+z*vec3(sin(o)*sin(c),cos(o),sin(o)*cos(c));" "\n#else\n" "float s=i.x,d=s*s,n=d*d,m=i.y,l=m*m,p=i.z,w=p*p,r=w*w,g=d+w,a=inversesqrt(g*g*g*g*g*g*g),u=n+l*l+r-6.*l*w-6.*d*l+2.*w*d,q=d-l+w;" "i.x=v.x+64.*s*m*p*(d-w)*q*(n-6.*d*w+r)*u*a;" @@ -100,7 +100,7 @@ const char *mandelbulb_frag = "{" "vec3 m=c+u*s,a;" "float q=clamp(.2+.8*dot(f,n),0.,1.),b,F,C;" - "q=q*q;" + "q*=q;" "b=clamp(.3+.7*dot(o,n),0.,1.);" "F=clamp(1.25*g.w-.4,0.,1.);" "F=F*F*.5+.5*F;" diff --git a/tests/real/slisesix.frag.expected b/tests/real/slisesix.frag.expected index abb368dd..2dd0cdad 100644 --- a/tests/real/slisesix.frag.expected +++ b/tests/real/slisesix.frag.expected @@ -30,7 +30,7 @@ float techo(float x,float y) y=1.-y; if(x<.1||x>.9) return y; - x=x-.5; + x-=.5; return-(sqrt(x*x+y*y)-.4); } float distToBox(vec3 p,vec3 abc) @@ -190,7 +190,7 @@ void main() lig=vec3(.5-pos.x,.8-pos.y,1.5-pos.z); llig=dot(lig,lig); im=inversesqrt(llig); - lig=lig*im; + lig*=im; dif=dot(nor,lig); if(matID==4) dif=.5+.5*dif; @@ -264,7 +264,7 @@ void main() } dif*=clamp((so-.4)*1.5,0.,1.); rgb=vec3(spe)+rgb*(ao*vec3(.25,.3,.35)+dif*vec3(1.95,1.65,1.05)); - rgb=rgb*exp2(-.4*t); + rgb*=exp2(-.4*t); } rgb=(sqrt(rgb)*.7+.3*rgb)*vec3(.83,1,.83)*1.2; rgb*=.25+.75*clamp(.6*abs(pixel.x-1.)*abs(pixel.x+1.),0.,1.); diff --git a/tests/real/terrarium.frag.expected b/tests/real/terrarium.frag.expected index 315add74..bd27e1af 100644 --- a/tests/real/terrarium.frag.expected +++ b/tests/real/terrarium.frag.expected @@ -10,19 +10,19 @@ float time=float(m)/44100.; int IH(int a) { a=a^61^a>>16; - a=a+(a<<3); - a=a^a>>4; - a=a*668265261; - a=a^a>>15; + a+=a<<3; + a^=a>>4; + a*=668265261; + a^=a>>15; return a; } float H(int a) { a=a^61^a>>16; - a=a+(a<<3); - a=a^a>>4; - a=a*668265261; - a=a^a>>15; + a+=a<<3; + a^=a>>4; + a*=668265261; + a^=a>>15; return float(a)/2147483647; } vec2 rand2(int a) @@ -131,7 +131,7 @@ void main() u=sqrt(1-u*u); x=vec3(cos(phi)*u,sin(phi)*u,w.y*2-1)*pow(w.z,1./3)*3; q=mix(q,q+x*.5,.1*pow(H(seed),16.)); - q=q+x*.2*(1.-min(time/30.,1.)+max(0.,time-130)/20.); + q+=x*.2*(1.-min(time/30.,1.)+max(0.,time-130)/20.); u=time/8.+199.*step(.5,H(int(floor(time/60.*64.))))*step(60.,time)*step(time,120); q.xy=mat2(cos(u),sin(u),-sin(u),cos(u))*q.xy; u=.4+time/9.; diff --git a/tests/real/the_real_party_is_in_your_pocket.frag.expected b/tests/real/the_real_party_is_in_your_pocket.frag.expected index a7ca9e23..09739df3 100644 --- a/tests/real/the_real_party_is_in_your_pocket.frag.expected +++ b/tests/real/the_real_party_is_in_your_pocket.frag.expected @@ -288,7 +288,7 @@ const char *the_real_party_is_in_your_pocket_frag = "break;" "k=.02;" "if(m()>k)" - "l=c-z*2e-4*-sign(v.z),v=v+(vec3(m(),m(),m())-.5)*.1;" + "l=c-z*2e-4*-sign(v.z),v+=(vec3(m(),m(),m())-.5)*.1;" "else" " l=c+z*2e-4,v=reflect(v,z)+(vec3(m(),m(),m())-.5)*.3;" "}" diff --git a/tests/unit/augmented.frag b/tests/unit/augmented.frag new file mode 100644 index 00000000..6c5366a7 --- /dev/null +++ b/tests/unit/augmented.frag @@ -0,0 +1,13 @@ +int foo(int x, int y) { + int a=x; + a=a+x; + a=a*y; + a=a>>x; + a=a^y; + a=a|y; + return a; +} + +void main() { + foo(0, 0); +} diff --git a/tests/unit/augmented.frag.expected b/tests/unit/augmented.frag.expected new file mode 100644 index 00000000..a8be711d --- /dev/null +++ b/tests/unit/augmented.frag.expected @@ -0,0 +1,14 @@ +int foo(int x,int y) +{ + int a=x; + a+=x; + a*=y; + a>>=x; + a^=y; + a|=y; + return a; +} +void main() +{ + foo(0,0); +} From 79bbee826ea16432a0ed2fd69881df2aa71c3347 Mon Sep 17 00:00:00 2001 From: Eldritch Conundrum Date: Sun, 8 Jan 2023 18:47:04 +0100 Subject: [PATCH 08/32] Change if statements to if expressions (#207) --- Checker/compression_test.fs | 2 +- README.md | 18 +++++++++++ src/rewriter.fs | 6 +++- tests/compression_results.log | 10 +++--- tests/real/disco.expected | 2 +- tests/real/slisesix.frag.expected | 5 +-- tests/real/sult.expected | 45 +++++++++++++-------------- tests/real/valley_ball.glsl.expected | 5 +-- tests/unit/blocks.expected | 8 +---- tests/unit/conditionals.frag | 15 +++++++++ tests/unit/conditionals.frag.expected | 7 +++++ 11 files changed, 76 insertions(+), 47 deletions(-) diff --git a/Checker/compression_test.fs b/Checker/compression_test.fs index e853b5d8..86439b2e 100644 --- a/Checker/compression_test.fs +++ b/Checker/compression_test.fs @@ -60,7 +60,7 @@ let testFile (file: string) = minified.Length, float compressedSize let run () = - Crinkler.InitCompressor() + Crinkler.InitCompressor() // Platform must be set to x64 writer.GetStringBuilder().Clear() |> ignore let sizes = List.map testFile testFiles diff --git a/README.md b/README.md index 0eb4a029..fe1ea3ee 100644 --- a/README.md +++ b/README.md @@ -414,6 +414,24 @@ if (x) y = 123,x++; **Note**: This transformation doesn't always decrease the compressed file size. Use `--no-sequence` to disable it and see how it performs. +### Ternary operator + +When a if+else statement only assigns to a variable, it is changed into a ternary operator. + +Input: +```glsl +if (c) { + x = f(); +} else { + x = 1.0; +} +``` + +Output: +```glsl +x = c ? f() : 1.0; +``` + ### Merge declarations If multiple values of the same type are declared next to each other, we can merge diff --git a/src/rewriter.fs b/src/rewriter.fs index 9a1052f6..06b68835 100644 --- a/src/rewriter.fs +++ b/src/rewriter.fs @@ -339,9 +339,9 @@ let squeezeBlockWithComma = function | Jump(JumpKeyword.Return, Some _) -> true | _ -> false) // Try to remove blocks by using the comma operator - let returnExp = b |> Seq.tryPick (function Jump(JumpKeyword.Return, e) -> e | _ -> None) if canOptimize then let li = List.choose (function Expr e -> Some e | _ -> None) b + let returnExp = b |> Seq.tryPick (function Jump(JumpKeyword.Return, e) -> e | _ -> None) match returnExp with | None -> if li.IsEmpty then Block [] @@ -386,6 +386,10 @@ let private simplifyStmt = function | If (False, _, Some e2) -> squeezeBlockWithComma e2 | If (False, _, None) -> Block [] | If (c, b, Some (Block [])) -> If(c, b, None) + | If (cond, Expr (FunCall (Op "=", [Var name1; initT])), + Some (Expr (FunCall (Op "=", [Var name2; initF])))) + when name1.Name = name2.Name -> // if(c)x=y;else x=z; -> x=c?y:z; + Expr (FunCall (Op "=", [Var name1; FunCall(Op "?:", [cond; initT; initF])])) | If (cond, body1, body2) -> If (cond, squeezeBlockWithComma body1, Option.map squeezeBlockWithComma body2) | Verbatim s -> Verbatim (stripSpaces s) diff --git a/tests/compression_results.log b/tests/compression_results.log index f3424abc..4957c14d 100644 --- a/tests/compression_results.log +++ b/tests/compression_results.log @@ -1,9 +1,9 @@ from-the-seas-to-the-stars.frag 14347 => 2353.607 the_real_party_is_in_your_pocket.frag 12213 => 1829.362 ed-209.frag 7899 => 1359.091 -valley_ball.glsl 4419 => 896.357 +valley_ball.glsl 4409 => 889.171 lunaquatic.frag 5232 => 1056.700 -slisesix.frag 4543 => 958.065 +slisesix.frag 4533 => 956.567 yx_long_way_from_home.frag 2993 => 614.607 oscars_chair.frag 4649 => 982.393 kinder_painter.frag 2894 => 456.030 @@ -11,7 +11,7 @@ ohanami.frag 3293 => 746.366 terrarium.frag 3633 => 749.292 leizex.frag 2308 => 515.785 elevated.hlsl 3406 => 611.302 -buoy.frag 4237 => 630.724 -orchard.frag 5618 => 1058.054 +buoy.frag 4217 => 628.605 +orchard.frag 5588 => 1051.886 robin.frag 6294 => 1066.421 -Total: 87978 => 15884.156 +Total: 87908 => 15867.186 diff --git a/tests/real/disco.expected b/tests/real/disco.expected index ec9da769..a01322bf 100644 --- a/tests/real/disco.expected +++ b/tests/real/disco.expected @@ -2,4 +2,4 @@ * http://www.ctrl-alt-test.fr */ -var disco_frag = `uniform vec2 resolution;uniform float time;uniform sampler2D tex0,tex1,tex2,tex3;vec4 s(vec2 px,float z){float l=3.1415,k=time*sign(z),x=px.x*320.*.0065*z,y=px.y*240.*.006*z,c=sqrt(x*x+y*y);if(c>1.)return vec4(0);else{float u=-.4*sign(z)+sin(k*.05),v=sqrt(1.-x*x-y*y),q=y*sin(u)-v*cos(u);y=y*cos(u)+v*sin(u);v=acos(y);u=acos(x/sin(v))/(2.*l)*120.*sign(q)-k;v=v*60./l;q=cos(floor(v/l));c=pow(abs(cos(u)*sin(v)),.2)*.1/(q+sin(float(int((u+l/2.)/l))+k*.6+cos(q*25.)))*pow(1.-c,.9);vec4 res;if(c<0.)res=vec4(-c/2.*abs(cos(k*.1)),0,-c*2.*abs(sin(k*.04)),1);else res=vec4(c,c*2.,c*2.,1);return res;}}void main(){vec2 p=-1.+2.*gl_FragCoord.xy/resolution.xy;vec4 c=vec4(0),d;for(int i=80;i>0;i--)c+=s(p,1.-float(i)/80.)*(.008-float(i)*5e-5);d=s(p,1.);gl_FragColor=(d.w==0.?s(p,-.2)*.02:d)+sqrt(c);}` +var disco_frag = `uniform vec2 resolution;uniform float time;uniform sampler2D tex0,tex1,tex2,tex3;vec4 s(vec2 px,float z){float l=3.1415,k=time*sign(z),x=px.x*320.*.0065*z,y=px.y*240.*.006*z,c=sqrt(x*x+y*y);if(c>1.)return vec4(0);else{float u=-.4*sign(z)+sin(k*.05),v=sqrt(1.-x*x-y*y),q=y*sin(u)-v*cos(u);y=y*cos(u)+v*sin(u);v=acos(y);u=acos(x/sin(v))/(2.*l)*120.*sign(q)-k;v=v*60./l;q=cos(floor(v/l));c=pow(abs(cos(u)*sin(v)),.2)*.1/(q+sin(float(int((u+l/2.)/l))+k*.6+cos(q*25.)))*pow(1.-c,.9);vec4 res;res=c<0.?vec4(-c/2.*abs(cos(k*.1)),0,-c*2.*abs(sin(k*.04)),1):vec4(c,c*2.,c*2.,1);return res;}}void main(){vec2 p=-1.+2.*gl_FragCoord.xy/resolution.xy;vec4 c=vec4(0),d;for(int i=80;i>0;i--)c+=s(p,1.-float(i)/80.)*(.008-float(i)*5e-5);d=s(p,1.);gl_FragColor=(d.w==0.?s(p,-.2)*.02:d)+sqrt(c);}` diff --git a/tests/real/slisesix.frag.expected b/tests/real/slisesix.frag.expected index 2dd0cdad..aafa9bbe 100644 --- a/tests/real/slisesix.frag.expected +++ b/tests/real/slisesix.frag.expected @@ -192,10 +192,7 @@ void main() im=inversesqrt(llig); lig*=im; dif=dot(nor,lig); - if(matID==4) - dif=.5+.5*dif; - else - dif=.1+.9*dif; + dif=matID==4?.5+.5*dif:.1+.9*dif; dif=clamp(dif,0.,1.); dif*=2.5*exp2(-1.75*llig); dif2=(nor[0]+nor[1])*.075; diff --git a/tests/real/sult.expected b/tests/real/sult.expected index 97fdc42a..6c9617cd 100644 --- a/tests/real/sult.expected +++ b/tests/real/sult.expected @@ -4,39 +4,36 @@ #ifndef SULT_EXPECTED_ # define SULT_EXPECTED_ # define VAR_resolution "r" -# define VAR_time "m" +# define VAR_time "c" const char *sult_frag = - "float y=5.,z=.9,x=0.,a=90.,s=0.;" - "vec3 v=vec3(1),n=vec3(0,0,1),f=vec3(0,0,1.5);" + "float v=5.,z=.9,y=0.,a=90.,x=0.;" + "vec3 m=vec3(1),n=vec3(0,0,1),s=vec3(0,0,1.5);" "uniform vec2 r;" - "uniform float m;" - "vec3 rotatey(vec3 v,float y)" + "uniform float c;" + "vec3 rotatey(vec3 v,float m)" "{" - "return vec3(v.x*cos(y)+v.z*sin(y),v.y,v.z*cos(y)-v.x*sin(y));" + "return vec3(v.x*cos(m)+v.z*sin(m),v.y,v.z*cos(m)-v.x*sin(m));" "}" - "float c=0.,w=10.;" - "float e(vec3 v)" + "float f=0.,w=10.;" + "float e(vec3 m)" "{" - "float z=m,w,a=0.,g,o,f;" + "float y=c,w,z=0.,g,o,a;" "vec3 r;" - "v+=(sin(v.zxy*1.7+z)+sin(v.yzx+z*3.))*.2;" - "if(y<6.)" - "a=length(v.xyz*vec3(1,1,.1)-vec3(0,-.1,z*.15-.3))-.34;" - "else" - " a=length(v.xy+vec2(0,.7))-.3+(sin(v.z*17.+z*.6)+sin(v.z*2.)*6.)*.01;" - "v.xy=vec2(atan(v.x,v.y)*1.113,1.6-length(v.xy)-sin(z*2.)*.3);" - "r=fract(v.xzz+.5).xyz-.5;" - "r.y=(v.y-.35)*1.3;" - "w=max(abs(v.y-.3)-.05,abs(length(fract(v.xz)-.5)-.4)-.03);" - "c=step(a,w);" - "return min(min(w,a),v.y-.2);" + "m+=(sin(m.zxy*1.7+y)+sin(m.yzx+y*3.))*.2;" + "z=v<6.?length(m.xyz*vec3(1,1,.1)-vec3(0,-.1,y*.15-.3))-.34:length(m.xy+vec2(0,.7))-.3+(sin(m.z*17.+y*.6)+sin(m.z*2.)*6.)*.01;" + "m.xy=vec2(atan(m.x,m.y)*1.113,1.6-length(m.xy)-sin(y*2.)*.3);" + "r=fract(m.xzz+.5).xyz-.5;" + "r.y=(m.y-.35)*1.3;" + "w=max(abs(m.y-.3)-.05,abs(length(fract(m.xz)-.5)-.4)-.03);" + "f=step(z,w);" + "return min(min(w,z),m.y-.2);" "}" - "vec3 d=vec3(.19,.2,.24),o=vec3(1),l=vec3(.45,.01,0),g=vec3(.17,0,0);" + "vec3 d=vec3(.19,.2,.24),o=vec3(1),t=vec3(.45,.01,0),g=vec3(.17,0,0);" "void main()" "{" - "vec2 t=-1.+2.*gl_FragCoord.xy/r.xy;" - "vec3 i=normalize(rotatey(rotatey(vec3(t.y*z,t.x*z*1.33,1),-x*.035).yxz,(a+s*m)*.035)),p=n+f*m,u,h,F;" + "vec2 l=-1.+2.*gl_FragCoord.xy/r.xy;" + "vec3 i=normalize(rotatey(rotatey(vec3(l.y*z,l.x*z*1.33,1),-y*.035).yxz,(a+x*c)*.035)),p=n+s*c,u,h,F;" "float C=1.,b=0.,Z,Y,X=0.,W,V,U,T;" "u=vec3(.01,0,0);" "h=u.yyy;" @@ -45,7 +42,7 @@ const char *sult_frag = "for(Z=X,Y=1.;Z.005;Z+=Y)" "Y=e(p+i*Z);" "if(Z22&&scene<27) - spherePos=ro+.1*vec3(mm*vec4(0,0,1,1)); - else - spherePos=ro+.02*vec3(sin(Y.y),0,5.+cos(Y.y)); + spherePos=scene>22&&scene<27?ro+.1*vec3(mm*vec4(0,0,1,1)):ro+.02*vec3(sin(Y.y),0,5.+cos(Y.y)); spherePos.y+=.01+height(spherePos.xz); sphereRadius=scene<14?0.:bigeps*.5+bigeps*Y.z; spherePos+=2.*bigeps*getTerrainNormal(spherePos); diff --git a/tests/unit/blocks.expected b/tests/unit/blocks.expected index 47b19bcc..4a58d11a 100644 --- a/tests/unit/blocks.expected +++ b/tests/unit/blocks.expected @@ -11,13 +11,7 @@ const char *blocks_frag = "float bar;" "if(foo==2)" "foo++;" - "if(foo<5)" - "if(foo==3)" - "bar=.2;" - "else" - " bar=.3;" - "else" - " bar=.4;" + "bar=foo<5?foo==3?.2:.3:.4;" "return bar;" "}" "int k=5;" diff --git a/tests/unit/conditionals.frag b/tests/unit/conditionals.frag index 5aa8afd9..fecdafa2 100644 --- a/tests/unit/conditionals.frag +++ b/tests/unit/conditionals.frag @@ -46,3 +46,18 @@ int foo() { } return a; } + +float ifStmtToExpr(float f) { + float r; + if (f > 0) + r = 1.0; + else + r = 2.0; + float r2; + if (f > 1) { + r2 = 1.0; + } else { + r2 = 2.0; + } + return r+r2; +} \ No newline at end of file diff --git a/tests/unit/conditionals.frag.expected b/tests/unit/conditionals.frag.expected index 02144c5c..f316bd04 100644 --- a/tests/unit/conditionals.frag.expected +++ b/tests/unit/conditionals.frag.expected @@ -43,3 +43,10 @@ int foo() int a=1; return a; } +float ifStmtToExpr(float f) +{ + float r,r2; + r=f>0?1.:2.; + r2=f>1?1.:2.; + return r+r2; +} From fbe05a73d84525a4ae9e7594b55264562a7a92e6 Mon Sep 17 00:00:00 2001 From: Eldritch Conundrum Date: Mon, 9 Jan 2023 20:14:51 +0100 Subject: [PATCH 09/32] Improve opportunities for if-else to ternary transformation (#208) After blocks are changed into comma-expressions, comma-expressions ending with assignments can be turned into an assignment of a comma-expression. That creates more opportunities for turning if statements into if expressions. --- README.md | 6 ++++-- src/rewriter.fs | 26 +++++++++++++++++++++----- tests/compression_results.log | 4 ++-- tests/real/kinder_painter.expected | 8 +------- tests/unit/conditionals.frag | 1 + tests/unit/conditionals.frag.expected | 2 +- 6 files changed, 30 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index fe1ea3ee..daf9ce00 100644 --- a/README.md +++ b/README.md @@ -416,20 +416,22 @@ Use `--no-sequence` to disable it and see how it performs. ### Ternary operator -When a if+else statement only assigns to a variable, it is changed into a ternary operator. +When both branches of a if+else are only expressions and they end with +an assignment to the same variable, the if is changed into a ternary operator. Input: ```glsl if (c) { x = f(); } else { + a = g(); x = 1.0; } ``` Output: ```glsl -x = c ? f() : 1.0; +x = c ? f() : a = g(), 1.0; ``` ### Merge declarations diff --git a/src/rewriter.fs b/src/rewriter.fs index 06b68835..40109108 100644 --- a/src/rewriter.fs +++ b/src/rewriter.fs @@ -386,12 +386,28 @@ let private simplifyStmt = function | If (False, _, Some e2) -> squeezeBlockWithComma e2 | If (False, _, None) -> Block [] | If (c, b, Some (Block [])) -> If(c, b, None) - | If (cond, Expr (FunCall (Op "=", [Var name1; initT])), - Some (Expr (FunCall (Op "=", [Var name2; initF])))) - when name1.Name = name2.Name -> // if(c)x=y;else x=z; -> x=c?y:z; - Expr (FunCall (Op "=", [Var name1; FunCall(Op "?:", [cond; initT; initF])])) | If (cond, body1, body2) -> - If (cond, squeezeBlockWithComma body1, Option.map squeezeBlockWithComma body2) + let (body1, body2) = squeezeBlockWithComma body1, Option.map squeezeBlockWithComma body2 + + // turn if-else into ternary + match (body1, body2) with + | (Expr eT, Some (Expr eF)) -> + let tryCollapseToAssignment : Expr -> (Ident * Expr) option = function + | FunCall (Op "=", [Var name; init]) -> Some (name, init) + | FunCall (Op ",", list) -> // f(),c=d -> c=f(),d + match List.last list with + | FunCall (Op "=", [Var name; init]) -> + let mutableList = new System.Collections.Generic.List(list) + mutableList[mutableList.Count - 1] <- init + Some (name, FunCall (Op ",", Seq.toList(mutableList))) + | _ -> None + | _ -> None + match (tryCollapseToAssignment eT, tryCollapseToAssignment eF) with + | Some (nameT, initT), Some (nameF, initF) when nameT.Name = nameF.Name -> + // if(c)x=y;else x=z; -> x=c?y:z; + Expr (FunCall (Op "=", [Var nameT; FunCall(Op "?:", [cond; initT; initF])])) + | _ -> If (cond, body1, body2) + | _ -> If (cond, body1, body2) | Verbatim s -> Verbatim (stripSpaces s) | e -> e diff --git a/tests/compression_results.log b/tests/compression_results.log index 4957c14d..a3243d62 100644 --- a/tests/compression_results.log +++ b/tests/compression_results.log @@ -6,7 +6,7 @@ lunaquatic.frag 5232 => 1056.700 slisesix.frag 4533 => 956.567 yx_long_way_from_home.frag 2993 => 614.607 oscars_chair.frag 4649 => 982.393 -kinder_painter.frag 2894 => 456.030 +kinder_painter.frag 2880 => 450.617 ohanami.frag 3293 => 746.366 terrarium.frag 3633 => 749.292 leizex.frag 2308 => 515.785 @@ -14,4 +14,4 @@ elevated.hlsl 3406 => 611.302 buoy.frag 4217 => 628.605 orchard.frag 5588 => 1051.886 robin.frag 6294 => 1066.421 -Total: 87908 => 15867.186 +Total: 87894 => 15861.773 diff --git a/tests/real/kinder_painter.expected b/tests/real/kinder_painter.expected index b460a112..9f3e88a7 100644 --- a/tests/real/kinder_painter.expected +++ b/tests/real/kinder_painter.expected @@ -53,13 +53,7 @@ "vec3 calcnor(vec4 obj,vec4 col,vec3 inter,out vec2 uv)" "{" "vec3 nor;" - "if(col.w>2.5)" - "nor.xz=inter.xz-obj.xz,nor.y=0.,nor/=obj.w,uv=vec2(nor.x,inter.y);" - "else" - " if(col.w>1.5)" - "nor=obj.xyz,uv=inter.xz*.2;" - "else" - " nor=inter-obj.xyz,nor/=obj.w,uv=nor.xy;" + "uv=col.w>2.5?(nor.xz=inter.xz-obj.xz,nor.y=0.,nor/=obj.w,vec2(nor.x,inter.y)):col.w>1.5?(nor=obj.xyz,inter.xz*.2):(nor=inter-obj.xyz,nor/=obj.w,nor.xy);" "return nor;" "}" "vec4 cmov(vec4 a,vec4 b,bool cond)" diff --git a/tests/unit/conditionals.frag b/tests/unit/conditionals.frag index fecdafa2..b76bd8cd 100644 --- a/tests/unit/conditionals.frag +++ b/tests/unit/conditionals.frag @@ -57,6 +57,7 @@ float ifStmtToExpr(float f) { if (f > 1) { r2 = 1.0; } else { + foo(); r2 = 2.0; } return r+r2; diff --git a/tests/unit/conditionals.frag.expected b/tests/unit/conditionals.frag.expected index f316bd04..78a2112f 100644 --- a/tests/unit/conditionals.frag.expected +++ b/tests/unit/conditionals.frag.expected @@ -47,6 +47,6 @@ float ifStmtToExpr(float f) { float r,r2; r=f>0?1.:2.; - r2=f>1?1.:2.; + r2=f>1?1.:(foo(),2.); return r+r2; } From 10b7048b6381ea2106e722e93ff9d265859ea715 Mon Sep 17 00:00:00 2001 From: Eldritch Conundrum Date: Thu, 12 Jan 2023 23:36:15 +0100 Subject: [PATCH 10/32] Fix float minification (#210) --- src/printer.fs | 21 ++++++++----------- tests/compression_results.log | 20 +++++++++--------- tests/real/ed-209.frag.expected | 2 +- tests/real/lunaquatic.frag.expected | 14 ++++++------- tests/real/mandelbulb.expected | 4 ++-- tests/real/monjori.frag.expected | 8 +++---- tests/real/oscars_chair.frag.expected | 2 +- tests/real/terrarium.frag.expected | 2 +- ...real_party_is_in_your_pocket.frag.expected | 6 +++--- tests/real/valley_ball.glsl.expected | 2 +- .../real/yx_long_way_from_home.frag.expected | 2 +- tests/unit/inline-aggro.aggro.expected | 6 +++--- tests/unit/inline-aggro.expected | 6 +++--- 13 files changed, 46 insertions(+), 49 deletions(-) diff --git a/src/printer.fs b/src/printer.fs index d68f32c9..437f7d1f 100644 --- a/src/printer.fs +++ b/src/printer.fs @@ -47,19 +47,16 @@ module private PrinterImpl = List.map toS li |> String.concat "," let floatToS f = - let si = if f < 0.M then "-" else "" - let f = abs (float f) - - let str1 = f.ToString("#.################", System.Globalization.CultureInfo.InvariantCulture) - let str2 = f.ToString("0.################e0", System.Globalization.CultureInfo.InvariantCulture) + let a = abs (float f) + let str1 = a.ToString("#.################", System.Globalization.CultureInfo.InvariantCulture) + let str1 = if str1 = "" then "0." + elif Regex.Match(str1, "^\\d+$").Success then str1 + "." + else str1 + let str2 = a.ToString("0.################e0", System.Globalization.CultureInfo.InvariantCulture) let str = [str1; str2] |> List.minBy(fun x -> x.Length) - - if str = "" then - "0." - elif Regex.Match(str, "^\\d+$").Success then - si + str + "." // display "3." instead of "3" - else - si + str + + let sign = if f < 0.M then "-" else "" + sign + str let rec exprToS exp = exprToSLevel 0 exp diff --git a/tests/compression_results.log b/tests/compression_results.log index a3243d62..3c897436 100644 --- a/tests/compression_results.log +++ b/tests/compression_results.log @@ -1,17 +1,17 @@ from-the-seas-to-the-stars.frag 14347 => 2353.607 -the_real_party_is_in_your_pocket.frag 12213 => 1829.362 -ed-209.frag 7899 => 1359.091 -valley_ball.glsl 4409 => 889.171 -lunaquatic.frag 5232 => 1056.700 +the_real_party_is_in_your_pocket.frag 12210 => 1830.170 +ed-209.frag 7898 => 1361.011 +valley_ball.glsl 4408 => 888.397 +lunaquatic.frag 5224 => 1058.755 slisesix.frag 4533 => 956.567 -yx_long_way_from_home.frag 2993 => 614.607 -oscars_chair.frag 4649 => 982.393 +yx_long_way_from_home.frag 2992 => 615.970 +oscars_chair.frag 4648 => 982.231 kinder_painter.frag 2880 => 450.617 ohanami.frag 3293 => 746.366 -terrarium.frag 3633 => 749.292 +terrarium.frag 3632 => 749.375 leizex.frag 2308 => 515.785 elevated.hlsl 3406 => 611.302 -buoy.frag 4217 => 628.605 +buoy.frag 4214 => 626.887 orchard.frag 5588 => 1051.886 -robin.frag 6294 => 1066.421 -Total: 87894 => 15861.773 +robin.frag 6293 => 1066.421 +Total: 87874 => 15865.348 diff --git a/tests/real/ed-209.frag.expected b/tests/real/ed-209.frag.expected index a777470d..c40971de 100644 --- a/tests/real/ed-209.frag.expected +++ b/tests/real/ed-209.frag.expected @@ -149,7 +149,7 @@ MarchData gunPod(vec3 p) { d=sdCappedCylinder(pp,.01+pp.z*.05,fract(fs*3322.423)*.5+.9); if(d0.) { - dist=length(planetPos-ro)-dist*800.; + dist=length(planetPos-ro)-dist*8e2; vec3 p=ro+rd*dist,n=normalize(planetPos-p); vec2 uv=.5+.5*vec2(atan(n.z,n.x),acos(n.y))/pi*vec2(5,50); color.xyz=max(0.,.2+dot(normalize(p-lightPos),n))*(caustic(uv.x*.5+Y.z*.1,uv.y*.5,0.)+.5)*.15*vec3(1,0,1); @@ -95,7 +95,7 @@ vec4 calcPlanet(vec3 ro,vec3 rd) { float d=length(planetPos-ro-rd*t); if(d>52.&&d<80.) - color.xyz=mix(color.xyz,vec3(.8,.64,.4),t/200.*norm(sin((d-50.)/30.*smoothrnd(vec2(d,3))))); + color.xyz=mix(color.xyz,vec3(.8,.64,.4),t/2e2*norm(sin((d-50.)/30.*smoothrnd(vec2(d,3))))); color.w=color.w<1.?3.*length(color):color.w; } return vec4(max(vec3(0),color.xyz*.3)*clamp(dot(rd,vec3(0,1,0))*8.,0.,1.),color.w); @@ -103,7 +103,7 @@ vec4 calcPlanet(vec3 ro,vec3 rd) vec3 calculateSky(vec3 ro,vec3 rd,int addPlanet) { vec3 color=max(vec3(0),(max(vec3(0),pow(dot(lightDir,rd),6.))*.7-rd.y)*mix(vec3(1,.5,0),vec3(1),min(1.,lightDir.y*1.5))+lightDir.y*3.); - float phi=atan(rd.x,rd.z),theta=acos(rd.y/length(rd)),coeff=smoothstep(0.,.5,norm(.5*smoothrnd(300.*vec2(phi,theta)))+norm(.75*smoothrnd(500.*vec2(phi,theta)))-1.25)*saturate(1.-lightDir.y*5.); + float phi=atan(rd.x,rd.z),theta=acos(rd.y/length(rd)),coeff=smoothstep(0.,.5,norm(.5*smoothrnd(3e2*vec2(phi,theta)))+norm(.75*smoothrnd(5e2*vec2(phi,theta)))-1.25)*saturate(1.-lightDir.y*5.); if(addPlanet>0) { vec4 p=calcPlanet(ro,rd); @@ -162,7 +162,7 @@ void calcBurn(vec2 x,vec3 normal,inout vec3 color) } vec3 calcScene(vec3 ro,vec3 rd) { - float upperPlane=(.1-ro.y)/rd.y,finalDepth=200.; + float upperPlane=(.1-ro.y)/rd.y,finalDepth=2e2; vec3 color=calculateSky(ro,rd,1); if(rd.y<-.01&&traceTerrain(ro+rd*upperPlane,rd,finalDepth,finalDepth)>0) { @@ -186,10 +186,10 @@ void main() ro=vec3(0,.25,0); float t=Y.z,dist,isoDistance; if(t<16.) - t=ftime(t,0.,16.),t=1.-pow(1.-t,2.),lightPos=vec3(-400,100.-t*450.,1000),t=(t-1.)*.7,rd=rotateX(rd,-t); + t=ftime(t,0.,16.),t=1.-pow(1.-t,2.),lightPos=vec3(-400,1e2-t*450.,1000),t=(t-1.)*.7,rd=rotateX(rd,-t); else if(t<32.) - t=ftime(t,16.,32.),t=1.-pow(1.-t,2.),lightPos=vec3(-400,-350.+t*600.,1000),ro.y-=t*.1; + t=ftime(t,16.,32.),t=1.-pow(1.-t,2.),lightPos=vec3(-400,-350.+t*6e2,1000),ro.y-=t*.1; else if(t<40.) lightPos=vec3(-400,250,1000),ro.y-=.1; @@ -199,7 +199,7 @@ void main() int scene=int((t-40.)/6.); if(scene>=3) artifactPos.w=1.; - lightPos=vec3(-400,min(250.,norm(rnd(vec2(scene,2)))*400.),1000); + lightPos=vec3(-400,min(250.,norm(rnd(vec2(scene,2)))*4e2),1000); ro.xz+=vec2(.1,20)*vec2(rnd(vec2(scene,5)),rnd(vec2(scene,7))); ro=mix(ro+vec3(.008)*abs(vec3(rnd(vec2(scene,8)),0,rnd(vec2(scene,10)))),ro+vec3(.75)*abs(vec3(rnd(vec2(scene,11)),0,rnd(vec2(scene,13)))),t-40.-float(scene)); ro.y=.2; diff --git a/tests/real/mandelbulb.expected b/tests/real/mandelbulb.expected index 7b959b31..37903ab2 100644 --- a/tests/real/mandelbulb.expected +++ b/tests/real/mandelbulb.expected @@ -23,7 +23,7 @@ const char *mandelbulb_frag = "vec4 e=vec4(100);" "vec3 i=v;" "float x=dot(i,i);" - "if(x>100.)" + "if(x>1e2)" "return f=.5*log(x)/pow(8.,0.),y=vec4(1),false;" "for(int t=1;t<7;t++)" "{" @@ -41,7 +41,7 @@ const char *mandelbulb_frag = "\n#endif\n" "x=dot(i,i);" "e=min(e,vec4(i.xyz*i.xyz,x));" - "if(x>100.)" + "if(x>1e2)" "return y=e,f=.5*log(x)/pow(8.,float(t)),false;" "}" "y=e;" diff --git a/tests/real/monjori.frag.expected b/tests/real/monjori.frag.expected index 74e426c1..fb0fee2d 100644 --- a/tests/real/monjori.frag.expected +++ b/tests/real/monjori.frag.expected @@ -5,10 +5,10 @@ void main() { vec2 p=-1.+2.*gl_FragCoord.xy/resolution.xy; float a=time*40.,d,e,f,g=.025,h,i,r,q; - e=400.*(p.x*.5+.5); - f=400.*(p.y*.5+.5); - i=200.+sin(e*g+a/150.)*20.; - d=200.+cos(f*g/2.)*18.+cos(e*g)*7.; + e=4e2*(p.x*.5+.5); + f=4e2*(p.y*.5+.5); + i=2e2+sin(e*g+a/150.)*20.; + d=2e2+cos(f*g/2.)*18.+cos(e*g)*7.; r=sqrt(pow(i-e,2.)+pow(d-f,2.)); q=f/r; e=r*cos(q)-a/2.; diff --git a/tests/real/oscars_chair.frag.expected b/tests/real/oscars_chair.frag.expected index 4b580743..5295f317 100644 --- a/tests/real/oscars_chair.frag.expected +++ b/tests/real/oscars_chair.frag.expected @@ -138,7 +138,7 @@ const char *oscars_chair_frag = "o=reflect(u,f);" "d=m;" "r=2;" - "i=100.;" + "i=1e2;" "u=normalize(g-x);" "h(x+u*.01,u);" "C*=.4+.6*smoothstep(0,n(x)/5,i);" diff --git a/tests/real/terrarium.frag.expected b/tests/real/terrarium.frag.expected index bd27e1af..43ad028b 100644 --- a/tests/real/terrarium.frag.expected +++ b/tests/real/terrarium.frag.expected @@ -58,7 +58,7 @@ void main() if(coord.x<1280&&coord.y<720) { uint x=imageLoad(d0,coord).x; - vec3 sc=mix(vec3(1),vec3(0,.35,.9),smoothstep(0.,23.,-time)),ec=mix(vec3(1,1.3,.28),vec3(.9,.2,.3),smoothstep(100.,138.,-time)); + vec3 sc=mix(vec3(1),vec3(0,.35,.9),smoothstep(0.,23.,-time)),ec=mix(vec3(1,1.3,.28),vec3(.9,.2,.3),smoothstep(1e2,138.,-time)); p=mix(sc,ec,sqrt(clamp(float(x>>20)/1024,0,1)))*(x&1048575)/100; p*=smoothstep(0,14,-time); vec2 q=abs(vec2(coord)/vec2(1280,720)-.5); diff --git a/tests/real/the_real_party_is_in_your_pocket.frag.expected b/tests/real/the_real_party_is_in_your_pocket.frag.expected index 09739df3..4e3f3dd4 100644 --- a/tests/real/the_real_party_is_in_your_pocket.frag.expected +++ b/tests/real/the_real_party_is_in_your_pocket.frag.expected @@ -115,7 +115,7 @@ const char *the_real_party_is_in_your_pocket_frag = "a=-l.z-.09-(1.-x(.9,l.y+.3+.1)-x(.55,-(l.y+.3+.17)))*.17;" "z=m(m(c.x-.48,length(c-vec2(0,2.5))-2.5,117.),c.y-.87,80.);" "if(l.z>.01)" - "i+=mix(.02,pow(max(0.,v(l.xy-vec2(0,.25+pow(abs(l.x),3.)),vec2(.32,.94))-.05)*100.,1.3)/1500.,1.-x(-.001,z));" + "i+=mix(.02,pow(max(0.,v(l.xy-vec2(0,.25+pow(abs(l.x),3.)),vec2(.32,.94))-.05)*1e2,1.3)/1500.,1.-x(-.001,z));" "if(l.z<0.)" "a=v(a,m(l-vec3(0,0,-.1),vec3(.5,.5,.055))-.04,64.);" "c.x-=.09;" @@ -130,7 +130,7 @@ const char *the_real_party_is_in_your_pocket_frag = "f=m(m(f,min(l.z,-s+.003),256.),min(l.z,-abs(z)-.001),448.);" "f=m(f,min(l.z-.13,-v(l.xy-vec2(0,-.118))),512.);" "f=m(f,min(l.z-.13,-abs(length(vec2(max(abs(l.x)-.12,0.),l.y+.117))-.035)+.003),512.);" - "f=m(m(f,min(1.,-min(1.,max(m(abs(l.x)-.31,abs(l.y-.49)-.29,500.),abs(l.z-.185)-.1))+.004),576.),-abs(l.z-.01)-1e-4,384.);" + "f=m(m(f,min(1.,-min(1.,max(m(abs(l.x)-.31,abs(l.y-.49)-.29,5e2),abs(l.z-.185)-.1))+.004),576.),-abs(l.z-.01)-1e-4,384.);" "if(l.y<0.)" "{" "if(l.y<-.5)" @@ -415,7 +415,7 @@ const char *the_real_party_is_in_your_pocket_frag = "l+=h(vec3(0,0,4.8),vec3((gl_FragCoord.xy-vec2(960,540)+f)/540.,-3.5))/48.;" "}" "l/=(l+1.)/2.;" - "gl_FragColor.xyz=pow(l+.01*vec3(1,1,.5),vec3(1./2.2))+m()/100.;" + "gl_FragColor.xyz=pow(l+.01*vec3(1,1,.5),vec3(1./2.2))+m()/1e2;" "}"; #endif // THE_REAL_PARTY_IS_IN_YOUR_POCKET_FRAG_EXPECTED_ diff --git a/tests/real/valley_ball.glsl.expected b/tests/real/valley_ball.glsl.expected index a1100ccc..8d9e18e4 100644 --- a/tests/real/valley_ball.glsl.expected +++ b/tests/real/valley_ball.glsl.expected @@ -175,7 +175,7 @@ void main() p=-1.+2.*gl_FragCoord.xy/resolution.xy; float angle=1.570796*Y.y-1.570796,seed; mat4 mm=mat4(cos(angle),0.,sin(angle),0.,0.,1.,0.,0.,-sin(angle),0.,cos(angle),0.,0.,0.,0.,1.); - gf_DetailLevel=100.; + gf_DetailLevel=1e2; pi=3.1416; interlacing=vec3(1.2,.9,.9); eps=1e-4; diff --git a/tests/real/yx_long_way_from_home.frag.expected b/tests/real/yx_long_way_from_home.frag.expected index 887cb18a..23679030 100644 --- a/tests/real/yx_long_way_from_home.frag.expected +++ b/tests/real/yx_long_way_from_home.frag.expected @@ -30,7 +30,7 @@ const char *yx_long_way_from_home_frag = "}" "float f(vec2 v)" "{" - "return smoothstep(.5,1.,cos(v.x*10.))*1.5+sin(v.x*100.)*.5+.5;" + "return smoothstep(.5,1.,cos(v.x*10.))*1.5+sin(v.x*1e2)*.5+.5;" "}" "float t(vec3 y)" "{" diff --git a/tests/unit/inline-aggro.aggro.expected b/tests/unit/inline-aggro.aggro.expected index 6d7b547b..02e101f5 100644 --- a/tests/unit/inline-aggro.aggro.expected +++ b/tests/unit/inline-aggro.aggro.expected @@ -5,7 +5,7 @@ float inl1() float inl2(float x) { if(x>246913578.) - return 100.; + return 1e2; if(x>123456789.) return 101.; return 102.; @@ -76,7 +76,7 @@ float noinl5() float noinl6(float x) { float f=x+1.; - x=100.; + x=1e2; return f+2.; } float noinl7(const float x) @@ -91,7 +91,7 @@ float noinl8() float noinl9(float x) { float bar=x+1.; - x=100.; + x=1e2; return bar+2.; } void evil(inout float x) diff --git a/tests/unit/inline-aggro.expected b/tests/unit/inline-aggro.expected index 26aad01a..bcd0d9a6 100644 --- a/tests/unit/inline-aggro.expected +++ b/tests/unit/inline-aggro.expected @@ -7,7 +7,7 @@ float inl2(float x) { float f=123456789.; if(x>2.*f) - return 100.; + return 1e2; if(x>f) return 101.; return 102.; @@ -83,7 +83,7 @@ float noinl5() float noinl6(float x) { float f=x+1.; - x=100.; + x=1e2; return f+2.; } float noinl7(const float x) @@ -98,7 +98,7 @@ float noinl8() float noinl9(float x) { float bar=x+1.; - x=100.; + x=1e2; return bar+2.; } void evil(inout float x) From 2774fc78da8c4e83f22a52dbd216e94d6f6ea82a Mon Sep 17 00:00:00 2001 From: Eldritch Conundrum Date: Sat, 14 Jan 2023 11:27:02 +0100 Subject: [PATCH 11/32] Fix constant ">=" simplification (#211) --- src/rewriter.fs | 2 +- tests/unit/operators.expected | 3 ++- tests/unit/operators.frag | 8 ++++++++ 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/src/rewriter.fs b/src/rewriter.fs index 40109108..33a75708 100644 --- a/src/rewriter.fs +++ b/src/rewriter.fs @@ -117,7 +117,7 @@ let private simplifyOperator env = function | FunCall(Op "<", [Number n1; Number n2]) -> bool(n1 < n2) | FunCall(Op ">", [Number n1; Number n2]) -> bool(n1 > n2) | FunCall(Op "<=", [Number n1; Number n2]) -> bool(n1 <= n2) - | FunCall(Op ">=", [Number n1; Number n2]) -> bool(n1 <= n2) + | FunCall(Op ">=", [Number n1; Number n2]) -> bool(n1 >= n2) | FunCall(Op "==", [Number n1; Number n2]) -> bool(n1 = n2) | FunCall(Op "!=", [Number n1; Number n2]) -> bool(n1 <> n2) diff --git a/tests/unit/operators.expected b/tests/unit/operators.expected index 9de2c8ec..e5694701 100644 --- a/tests/unit/operators.expected +++ b/tests/unit/operators.expected @@ -7,10 +7,11 @@ "void main()" "{" "int a=11,b=7,c=2;" - "float f=2.621464704,g;" + "float f=2.621464704,g,z;" "f=.7;" "f=1.4/3.;" "g=mod(8.,3.);" + "z=122121;" "}" "int no_parens(int a,int b,int c)" "{" diff --git a/tests/unit/operators.frag b/tests/unit/operators.frag index 777a68e8..9d3c7bb7 100644 --- a/tests/unit/operators.frag +++ b/tests/unit/operators.frag @@ -10,6 +10,14 @@ void main() f = 1.4 / 2.; f = 1.4 / 3.; float g = mod(8., 3.); + + float z = + (1. < 2. ? 1 : 2) + + (1. > 2. ? 1 : 2) * 10 + + (1. <= 2. ? 1 : 2) * 100 + + (1. >= 2. ? 1 : 2) * 1000 + + (1. == 2. ? 1 : 2) * 10000 + + (1. != 2. ? 1 : 2) * 100000; } int no_parens(int a, int b, int c) { From 451c5a229aff7e364924c2cc64808308f3545e35 Mon Sep 17 00:00:00 2001 From: Eldritch Conundrum Date: Sat, 14 Jan 2023 14:30:01 +0100 Subject: [PATCH 12/32] if+return optimizations (#209) --- README.md | 29 ++++++ src/rewriter.fs | 90 +++++++++++++------ tests/compression_results.log | 12 +-- tests/real/disco.expected | 2 +- tests/real/ed-209.frag.expected | 4 +- tests/real/ohanami.frag.expected | 4 +- ...real_party_is_in_your_pocket.frag.expected | 4 +- tests/real/valley_ball.glsl.expected | 12 +-- tests/unit/blocks.expected | 37 +++++++- tests/unit/blocks.frag | 29 ++++++ tests/unit/conditionals.frag | 9 +- tests/unit/conditionals.frag.expected | 8 +- tests/unit/inline-aggro.aggro.expected | 6 +- tests/unit/inline-aggro.expected | 6 +- 14 files changed, 182 insertions(+), 70 deletions(-) diff --git a/README.md b/README.md index daf9ce00..d01e6aff 100644 --- a/README.md +++ b/README.md @@ -414,6 +414,20 @@ if (x) y = 123,x++; **Note**: This transformation doesn't always decrease the compressed file size. Use `--no-sequence` to disable it and see how it performs. +### Useless else after return + +When a if always ends in a return, the else can be omitted entirely. + +Input: +``` +if(c)return a();else b(); +``` + +Output: +``` +if(c)return a();b(); +``` + ### Ternary operator When both branches of a if+else are only expressions and they end with @@ -434,6 +448,21 @@ Output: x = c ? f() : a = g(), 1.0; ``` +When both branches of a if return immediately, the if is changed into a return +that uses a ternary operator. + +Input: +```glsl +if (y) + return z; +return w; +``` + +Output: +```glsl +return y ? z : w; +``` + ### Merge declarations If multiple values of the same type are declared next to each other, we can merge diff --git a/src/rewriter.fs b/src/rewriter.fs index 33a75708..7dfa6d51 100644 --- a/src/rewriter.fs +++ b/src/rewriter.fs @@ -249,7 +249,7 @@ let private simplifyExpr (didInline: bool ref) env = function let sub1 = FunCall(Op "-", [x; a]) let sub2 = FunCall(Op "-", [b; a]) let div = FunCall(Op "/", [sub1; sub2]) |> mapExpr env - FunCall(Var (Ident "smoothstep"), [Float (0.M,""); Float (1.M,""); div]) + FunCall(Var (Ident "smoothstep"), [Float (0.M,""); Float (1.M,""); div]) | Dot(e, field) when options.canonicalFieldNames <> "" -> Dot(e, renameField field) @@ -306,11 +306,11 @@ let groupDeclarations stmts = List.collect replacements stmts // Squeeze declarations: "float a=2.; float b;" => "float a=2.,b;" -let rec private squeezeDeclarations = function +let rec private squeezeConsecutiveDeclarations = function | []-> [] | Decl(ty1, li1) :: Decl(ty2, li2) :: l when ty1 = ty2 -> - squeezeDeclarations (Decl(ty1, li1 @ li2) :: l) - | e::l -> e :: squeezeDeclarations l + squeezeConsecutiveDeclarations (Decl(ty1, li1 @ li2) :: l) + | e::l -> e :: squeezeConsecutiveDeclarations l // Squeeze top-level declarations, e.g. uniforms let rec private squeezeTLDeclarations = function @@ -352,31 +352,65 @@ let squeezeBlockWithComma = function else stmt | stmt -> stmt +let private simplifyBlock stmts = + let b = stmts + // Avoid some optimizations when there are preprocessor directives. + let hasPreprocessor = Seq.exists (function Verbatim _ -> true | _ -> false) b + + // Remove dead code after return/break/... + let endOfCode = Seq.tryFindIndex (function Jump _ -> true | _ -> false) b + let b = match endOfCode with + | Some x when not hasPreprocessor -> List.truncate (x+1) b + | _ -> b + + // Remove "empty" declarations of vars that were inlined. This is mandatory for correctness, not an optional optimization. + let b = b |> List.filter (function + | Decl (_, []) -> false + | _ -> true) + + let hasNoDecl = List.forall (function Decl _ -> false | _ -> true) + + // Inline inner decl-less blocks. (Presence of decl could lead to redefinitions.) a();{b();}c(); -> a();b();c(); + let b = b |> List.collect (function + | Block b when hasNoDecl b -> b + | e -> [e]) + + // Remove useless else after a if that returns. + // if(c)return a();else b(); -> if(c)return a();b(); + let rec endsWithReturn = function + | Jump(JumpKeyword.Return, _) -> true + | Block stmts when not stmts.IsEmpty -> stmts |> List.last |> endsWithReturn + | _ -> false + let removeUselessElseAfterReturn = List.collect (function + | If (cond, bodyT, Some bodyF) when endsWithReturn bodyT -> + let bodyF = match bodyF with + | Block b when hasNoDecl b -> b // inline inner empty blocks without variable + | Decl _ as d -> [Block [d]] // a decl must stay isolated in a block, for the same reason + | s -> [s] + If (cond, bodyT, None) :: bodyF + | e -> [e]) + let b = removeUselessElseAfterReturn b + + // if(a)return b;return c; -> return a?b:c; + let rec replaceIfReturnsByReturnTernary = function + | If (cond, Jump(JumpKeyword.Return, Some retT), None) :: Jump(JumpKeyword.Return, Some retF) :: _rest -> + [Jump(JumpKeyword.Return, Some (FunCall(Op "?:", [cond; retT; retF])))] + | stmt :: rest -> stmt :: replaceIfReturnsByReturnTernary rest + | stmts -> stmts + let b = replaceIfReturnsByReturnTernary b + + // Consecutive declarations of the same type become one. float a;float b; -> float a,b; + let b = squeezeConsecutiveDeclarations b + + // Group declarations, optionally (may compress poorly). float a,f();float b=4.; -> float a,b;f();b=4.; + let b = if hasPreprocessor || options.noMoveDeclarations then b else groupDeclarations b + b + let private simplifyStmt = function | Block [] as e -> e - | Block b -> - // Avoid some optimizations when there are preprocessor directives. - let hasPreprocessor = Seq.exists (function Verbatim _ -> true | _ -> false) b - - // Remove dead code after return/break/... - let endOfCode = Seq.tryFindIndex (function Jump _ -> true | _ -> false) b - let b = match endOfCode with - | Some x when not hasPreprocessor -> List.truncate (x+1) b - | _ -> b - - // Inline inner empty blocks without variable - let b = b |> List.collect (function - | Block b when List.forall (function Decl _ -> false | _ -> true) b -> - b - | Decl (_, []) -> [] - | e -> [e]) - - // Reduce the number of declaration statements. - let b = squeezeDeclarations b - let b = if hasPreprocessor || options.noMoveDeclarations then b else groupDeclarations b - match b with - | [stmt] -> stmt - | stmts -> Block stmts + | Block b -> match simplifyBlock b with + | [stmt] -> stmt + | stmts -> Block stmts | Decl (ty, li) -> Decl (rwType ty, declsNotToInline li) | ForD ((ty, d), cond, inc, body) -> ForD((rwType ty, declsNotToInline d), cond, inc, squeezeBlockWithComma body) | ForE (init, cond, inc, body) -> ForE(init, cond, inc, squeezeBlockWithComma body) @@ -385,7 +419,7 @@ let private simplifyStmt = function | If (True, e1, _) -> squeezeBlockWithComma e1 | If (False, _, Some e2) -> squeezeBlockWithComma e2 | If (False, _, None) -> Block [] - | If (c, b, Some (Block [])) -> If(c, b, None) + | If (c, b, Some (Block [])) -> If(c, b, None) // "else{}" -> "" | If (cond, body1, body2) -> let (body1, body2) = squeezeBlockWithComma body1, Option.map squeezeBlockWithComma body2 diff --git a/tests/compression_results.log b/tests/compression_results.log index 3c897436..4f1d4252 100644 --- a/tests/compression_results.log +++ b/tests/compression_results.log @@ -1,17 +1,17 @@ from-the-seas-to-the-stars.frag 14347 => 2353.607 -the_real_party_is_in_your_pocket.frag 12210 => 1830.170 -ed-209.frag 7898 => 1361.011 -valley_ball.glsl 4408 => 888.397 +the_real_party_is_in_your_pocket.frag 12200 => 1829.607 +ed-209.frag 7888 => 1361.583 +valley_ball.glsl 4379 => 889.602 lunaquatic.frag 5224 => 1058.755 slisesix.frag 4533 => 956.567 yx_long_way_from_home.frag 2992 => 615.970 oscars_chair.frag 4648 => 982.231 kinder_painter.frag 2880 => 450.617 -ohanami.frag 3293 => 746.366 +ohanami.frag 3283 => 750.856 terrarium.frag 3632 => 749.375 leizex.frag 2308 => 515.785 elevated.hlsl 3406 => 611.302 -buoy.frag 4214 => 626.887 +buoy.frag 4194 => 622.602 orchard.frag 5588 => 1051.886 robin.frag 6293 => 1066.421 -Total: 87874 => 15865.348 +Total: 87795 => 15866.766 diff --git a/tests/real/disco.expected b/tests/real/disco.expected index a01322bf..7af50966 100644 --- a/tests/real/disco.expected +++ b/tests/real/disco.expected @@ -2,4 +2,4 @@ * http://www.ctrl-alt-test.fr */ -var disco_frag = `uniform vec2 resolution;uniform float time;uniform sampler2D tex0,tex1,tex2,tex3;vec4 s(vec2 px,float z){float l=3.1415,k=time*sign(z),x=px.x*320.*.0065*z,y=px.y*240.*.006*z,c=sqrt(x*x+y*y);if(c>1.)return vec4(0);else{float u=-.4*sign(z)+sin(k*.05),v=sqrt(1.-x*x-y*y),q=y*sin(u)-v*cos(u);y=y*cos(u)+v*sin(u);v=acos(y);u=acos(x/sin(v))/(2.*l)*120.*sign(q)-k;v=v*60./l;q=cos(floor(v/l));c=pow(abs(cos(u)*sin(v)),.2)*.1/(q+sin(float(int((u+l/2.)/l))+k*.6+cos(q*25.)))*pow(1.-c,.9);vec4 res;res=c<0.?vec4(-c/2.*abs(cos(k*.1)),0,-c*2.*abs(sin(k*.04)),1):vec4(c,c*2.,c*2.,1);return res;}}void main(){vec2 p=-1.+2.*gl_FragCoord.xy/resolution.xy;vec4 c=vec4(0),d;for(int i=80;i>0;i--)c+=s(p,1.-float(i)/80.)*(.008-float(i)*5e-5);d=s(p,1.);gl_FragColor=(d.w==0.?s(p,-.2)*.02:d)+sqrt(c);}` +var disco_frag = `uniform vec2 resolution;uniform float time;uniform sampler2D tex0,tex1,tex2,tex3;vec4 s(vec2 px,float z){float l=3.1415,k=time*sign(z),x=px.x*320.*.0065*z,y=px.y*240.*.006*z,c=sqrt(x*x+y*y);if(c>1.)return vec4(0);{float u=-.4*sign(z)+sin(k*.05),v=sqrt(1.-x*x-y*y),q=y*sin(u)-v*cos(u);y=y*cos(u)+v*sin(u);v=acos(y);u=acos(x/sin(v))/(2.*l)*120.*sign(q)-k;v=v*60./l;q=cos(floor(v/l));c=pow(abs(cos(u)*sin(v)),.2)*.1/(q+sin(float(int((u+l/2.)/l))+k*.6+cos(q*25.)))*pow(1.-c,.9);vec4 res;res=c<0.?vec4(-c/2.*abs(cos(k*.1)),0,-c*2.*abs(sin(k*.04)),1):vec4(c,c*2.,c*2.,1);return res;}}void main(){vec2 p=-1.+2.*gl_FragCoord.xy/resolution.xy;vec4 c=vec4(0),d;for(int i=80;i>0;i--)c+=s(p,1.-float(i)/80.)*(.008-float(i)*5e-5);d=s(p,1.);gl_FragColor=(d.w==0.?s(p,-.2)*.02:d)+sqrt(c);}` diff --git a/tests/real/ed-209.frag.expected b/tests/real/ed-209.frag.expected index c40971de..a15c9d3c 100644 --- a/tests/real/ed-209.frag.expected +++ b/tests/real/ed-209.frag.expected @@ -65,9 +65,7 @@ vec3 getRayDir(vec3 ro,vec3 lookAt,vec2 uv) } MarchData minResult(MarchData a,MarchData b) { - if(a.d5.||abs(u.y)>2.5||abs(u.z)>3.3)" - "return vec4(-1);" - "return vec4(m,0,0,0);" + "return abs(u.x)>5.||abs(u.y)>2.5||abs(u.z)>3.3?vec4(-1):vec4(m,0,0,0);" "}" "float y;" "float m()" diff --git a/tests/real/valley_ball.glsl.expected b/tests/real/valley_ball.glsl.expected index 8d9e18e4..0a3ef412 100644 --- a/tests/real/valley_ball.glsl.expected +++ b/tests/real/valley_ball.glsl.expected @@ -108,9 +108,7 @@ float traceAttractor(vec3 ro,vec3 rd) if(B>0.) return 9.; D=B*B-dot(dst,dst)+sphereRadius*sphereRadius; - if(D>0.) - return-B-sqrt(D); - return 9.; + return D>0.?-B-sqrt(D):9.; } float traceWater(vec3 ro,vec3 rd) { @@ -143,9 +141,7 @@ vec3 shade(vec4 hitPoint,vec3 newRo,vec3 rd) return mix(shadeTerrain(hitPoint.xyz,rd),myFog,distance); if(hitPoint.w==2.) return mix(waterColor,myFog,distance); - if(hitPoint.w==3.) - return mix(shadeAttractor(hitPoint.xyz,rd),myFog,distance); - return myFog; + return hitPoint.w==3.?mix(shadeAttractor(hitPoint.xyz,rd),myFog,distance):myFog; } vec3 shadeWaterRefl(vec3 p,vec3 newrd) { @@ -162,9 +158,7 @@ vec3 shadeRefl(vec4 hitPoint,vec3 newRo,vec3 rd) return mix(shadeTerrain(hitPoint.xyz,rd),myFog,distance); if(hitPoint.w==2.) return mix(shadeWaterRefl(hitPoint.xyz,rd),myFog,distance); - if(hitPoint.w==3.) - return mix(mix(shadeAttractor(hitPoint.xyz,rd),shade(traceRay(hitPoint.xyz,reflect(rd,normalize(hitPoint.xyz-spherePos)),3),hitPoint.xyz,rd),.5),myFog,distance); - return shadeSky(newRo,rd); + return hitPoint.w==3.?mix(mix(shadeAttractor(hitPoint.xyz,rd),shade(traceRay(hitPoint.xyz,reflect(rd,normalize(hitPoint.xyz-spherePos)),3),hitPoint.xyz,rd),.5),myFog,distance):shadeSky(newRo,rd); } void main() { diff --git a/tests/unit/blocks.expected b/tests/unit/blocks.expected index 4a58d11a..d01aef5f 100644 --- a/tests/unit/blocks.expected +++ b/tests/unit/blocks.expected @@ -32,15 +32,44 @@ const char *blocks_frag = "if(k==0)" ";" "for(int i=0;i<2;i++)" - "if(k==1)" - "return k++,2;" - "else" - " break;" + "{" + "if(k==1)" + "return k++,2;" + "break;" + "}" + "}" + "float removeUselessElseAfterReturn1(float f)" + "{" + "if(f<2.)" + "return 1.;" + "f=4.;" + "return 5.;" + "}" + "float removeUselessElseAfterReturn2(float f)" + "{" + "float a=2.;" + "if(f 1) { + r3 = 1.0; + } else { + r3 = 2.0; + foo(); + } + return r+r2+r3; } \ No newline at end of file diff --git a/tests/unit/conditionals.frag.expected b/tests/unit/conditionals.frag.expected index 78a2112f..be4f0dba 100644 --- a/tests/unit/conditionals.frag.expected +++ b/tests/unit/conditionals.frag.expected @@ -45,8 +45,12 @@ int foo() } float ifStmtToExpr(float f) { - float r,r2; + float r,r2,r3; r=f>0?1.:2.; r2=f>1?1.:(foo(),2.); - return r+r2; + if(f>1) + r3=1.; + else + r3=2.,foo(); + return r+r2+r3; } diff --git a/tests/unit/inline-aggro.aggro.expected b/tests/unit/inline-aggro.aggro.expected index 02e101f5..580b996f 100644 --- a/tests/unit/inline-aggro.aggro.expected +++ b/tests/unit/inline-aggro.aggro.expected @@ -4,11 +4,7 @@ float inl1() } float inl2(float x) { - if(x>246913578.) - return 1e2; - if(x>123456789.) - return 101.; - return 102.; + return x>246913578.?1e2:x>123456789.?101.:102.; } float inl3() { diff --git a/tests/unit/inline-aggro.expected b/tests/unit/inline-aggro.expected index bcd0d9a6..62c1b232 100644 --- a/tests/unit/inline-aggro.expected +++ b/tests/unit/inline-aggro.expected @@ -6,11 +6,7 @@ float inl1() float inl2(float x) { float f=123456789.; - if(x>2.*f) - return 1e2; - if(x>f) - return 101.; - return 102.; + return x>2.*f?1e2:x>f?101.:102.; } float inl3() { From d53034d562089645c34d5d9bc627ebbf67e24ce3 Mon Sep 17 00:00:00 2001 From: Eldritch Conundrum Date: Sat, 14 Jan 2023 15:30:02 +0100 Subject: [PATCH 13/32] Change if to ternary even when no common assignment exists (#212) Relatedly, use indentation for ternaries. --- README.md | 4 +- src/printer.fs | 102 +++++++++--------- src/rewriter.fs | 13 ++- tests/compression_results.log | 14 +-- tests/real/clod.expected | 2 +- tests/real/ed-209.frag.expected | 20 +++- .../from-the-seas-to-the-stars.frag.expected | 59 +++------- tests/real/kinder_painter.expected | 18 +++- tests/real/lunaquatic.frag.expected | 26 +++-- tests/real/ohanami.frag.expected | 8 +- tests/real/oscars_chair.frag.expected | 66 ++++++------ tests/real/slisesix.frag.expected | 4 +- tests/real/sult.expected | 19 ++-- tests/real/terrarium.frag.expected | 58 +++++----- ...real_party_is_in_your_pocket.frag.expected | 55 ++++++---- tests/real/valley_ball.glsl.expected | 74 +++++++++---- .../real/yx_long_way_from_home.frag.expected | 8 +- tests/unit/blocks.expected | 10 +- tests/unit/conditionals.frag.expected | 15 +-- tests/unit/function_comma.expected | 6 +- tests/unit/inline-aggro.aggro.expected | 6 +- tests/unit/inline-aggro.expected | 6 +- 22 files changed, 331 insertions(+), 262 deletions(-) diff --git a/README.md b/README.md index d01e6aff..9a41b850 100644 --- a/README.md +++ b/README.md @@ -430,8 +430,8 @@ if(c)return a();b(); ### Ternary operator -When both branches of a if+else are only expressions and they end with -an assignment to the same variable, the if is changed into a ternary operator. +When both branches of a if+else are an expression, the if is changed into a ternary operator. +Additionally, if they end with an assignment to the same variable, the variable is extracted from the ternary operator. Input: ```glsl diff --git a/src/printer.fs b/src/printer.fs index 437f7d1f..43c49330 100644 --- a/src/printer.fs +++ b/src/printer.fs @@ -58,13 +58,26 @@ module private PrinterImpl = let sign = if f < 0.M then "-" else "" sign + str - let rec exprToS exp = exprToSLevel 0 exp + let mutable ignoreFirstNewLine = true + let nl indent = // newline and optionally indent + if ignoreFirstNewLine then + ignoreFirstNewLine <- false + "" + else + let spaces = new string(' ', indent * 2 + 1) + match outputFormat with + | Options.IndentedText -> Environment.NewLine + new string(' ', indent * 2) + | Options.Text | Options.JS -> "" + | Options.CHeader | Options.CList -> out "\"%s%s\"" Environment.NewLine spaces + | Options.Nasm -> out "'%s\tdb%s'" Environment.NewLine spaces + + let rec exprToS indent exp = exprToSLevel indent 0 exp // Convert Expr option to string, with default value. - and exprToSOpt def exp = - defaultArg (Option.map exprToS exp) def + and exprToSOpt indent def exp = + defaultArg (Option.map (exprToS indent) exp) def - and exprToSLevel level = function + and exprToSLevel indent level = function | Int (i, suf) -> (out "%d%s" i suf) | Float (f, suf) -> out "%s%s" (floatToS f) suf | Var s -> idToS s @@ -73,37 +86,39 @@ module private PrinterImpl = match f, args with | Op "?:", [a1; a2; a3] -> let prec = precedence.["?:"] - let res = out "%s?%s:%s" (exprToSLevel prec a1) (exprToSLevel prec a2) (exprToSLevel prec a3) + let res = out "%s?%s%s:%s%s" (exprToSLevel indent prec a1) + (nl (indent+1)) (exprToSLevel (indent+1) prec a2) + (nl (indent+1)) (exprToSLevel (indent+1) prec a3) if prec < level then out "(%s)" res else res // Function calls. | Var op, _ -> // We set level to 1 in case in case a comma operator is used in the argument list. - out "%s(%s)" (idToS op) (commaListToS (exprToSLevel 1) args) + out "%s(%s)" (idToS op) (commaListToS (exprToSLevel indent 1) args) // Unary operators. _++ is prefix and $++ is postfix - | Op op, [a1] when op.[0] = '$' -> out "%s%s" (exprToSLevel precedence.[op] a1) op.[1..] - | Op op, [a1] -> out "%s%s" op (exprToSLevel precedence.["_" + op] a1) + | Op op, [a1] when op.[0] = '$' -> out "%s%s" (exprToSLevel indent precedence.[op] a1) op.[1..] + | Op op, [a1] -> out "%s%s" op (exprToSLevel indent precedence.["_" + op] a1) // Binary operators. | Op op, [a1; a2] -> let prec = precedence.[op] let res = if prec = 1 then // "=", "+=", or other operator with right-associativity - out "%s%s%s" (exprToSLevel (prec+1) a1) op (exprToSLevel prec a2) + out "%s%s%s" (exprToSLevel indent (prec+1) a1) op (exprToSLevel indent prec a2) else - out "%s%s%s" (exprToSLevel prec a1) op (exprToSLevel (prec+1) a2) + out "%s%s%s" (exprToSLevel indent prec a1) op (exprToSLevel indent (prec+1) a2) if prec < level then out "(%s)" res else res - | _ -> out "%s(%s)" (exprToS f) (commaListToS exprToS args) + | _ -> out "%s(%s)" (exprToS indent f) (commaListToS (exprToS indent) args) | Subscript(arr, ind) -> - out "%s[%s]" (exprToS arr) (exprToSOpt "" ind) + out "%s[%s]" (exprToS indent arr) (exprToSOpt indent "" ind) | Cast(id, e) -> // Cast seems to have the same precedence as unary minus - out "(%s)%s" id.Name (exprToSLevel precedence.["_-"] e) + out "(%s)%s" id.Name (exprToSLevel indent precedence.["_-"] e) | VectorExp(li) -> - out "{%s}" (commaListToS exprToS li) + out "{%s}" (commaListToS (exprToS indent) li) | Dot(e, field) -> - out "%s.%s" (exprToSLevel precedence.["."] e) field + out "%s.%s" (exprToSLevel indent precedence.["."] e) field | VerbatimExp s -> s // Add a space if needed @@ -124,12 +139,12 @@ module private PrinterImpl = // Print HLSL semantics let semToS sem = - let res = sem |> List.map exprToS |> String.concat ":" + let res = sem |> List.map (exprToS 0) |> String.concat ":" if res = "" then res else ":" + res let rec structToS prefix id decls = let name = match id with None -> "" | Some (s: Ident) -> " " + s.Name - let d = decls |> List.map (fun s -> declToS s + ";") |> String.concat "" + let d = decls |> List.map (fun s -> declToS 0 s + ";") |> String.concat "" out "%s{%s}" (sp2 prefix name) d and typeSpecToS = function @@ -143,36 +158,23 @@ module private PrinterImpl = let typeSpec = typeSpecToS ty.name out "%s%s" (get ty.typeQ) typeSpec - and declToS (ty, vars) = + and declToS indent (ty, vars) = let out1 decl = let size = match decl.size with | None -> "" | Some (Int (0, _)) -> "[]" - | Some n -> out "[%s]" (exprToS n) + | Some n -> out "[%s]" (exprToS indent n) let init = match decl.init with | None -> "" - | Some i -> out "=%s" (exprToS i) + | Some i -> out "=%s" (exprToS indent i) out "%s%s%s%s" (idToS decl.name) size (semToS decl.semantics) init if vars.IsEmpty then "" else out "%s %s" (typeToS ty) (vars |> commaListToS out1) - let mutable ignoreFirstNewLine = true - let nl indent = // newline and optionally indent - if ignoreFirstNewLine then - ignoreFirstNewLine <- false - "" - else - let spaces = new string(' ', indent * 2 + 1) - match outputFormat with - | Options.IndentedText -> Environment.NewLine + new string(' ', indent * 2) - | Options.Text | Options.JS -> "" - | Options.CHeader | Options.CList -> out "\"%s%s\"" Environment.NewLine spaces - | Options.Nasm -> out "'%s\tdb%s'" Environment.NewLine spaces - let escape (s: string) = match outputFormat with | Options.IndentedText -> s @@ -203,29 +205,29 @@ module private PrinterImpl = let body = List.map (stmtToS (indent+1)) b |> String.concat "" out "{%s%s}" body (nl indent) | Decl (_, []) -> "" - | Decl d -> out "%s;" (declToS d) - | Expr e -> out "%s;" (exprToS e) + | Decl d -> out "%s;" (declToS indent d) + | Expr e -> out "%s;" (exprToS indent e) | If(cond, th, el) -> let th = if el <> None && hasDanglingElseProblem th then Block [th] else th let el = match el with | None -> "" | Some el -> out "%selse%s%s" (nl indent) (nl (indent+1)) (stmtToS' (indent+1) el |> sp) - out "if(%s)%s%s" (exprToS cond) (stmtToSInd indent th) el + out "if(%s)%s%s" (exprToS indent cond) (stmtToSInd indent th) el | ForD(init, cond, inc, body) -> - let cond = exprToSOpt "" cond - let inc = exprToSOpt "" inc - out "%s(%s;%s;%s)%s" "for" (declToS init) cond inc (stmtToSInd indent body) + let cond = exprToSOpt indent "" cond + let inc = exprToSOpt indent "" inc + out "%s(%s;%s;%s)%s" "for" (declToS indent init) cond inc (stmtToSInd indent body) | ForE(init, cond, inc, body) -> - let cond = exprToSOpt "" cond - let inc = exprToSOpt "" inc - let init = exprToSOpt "" init + let cond = exprToSOpt indent "" cond + let inc = exprToSOpt indent "" inc + let init = exprToSOpt indent "" init out "%s(%s;%s;%s)%s" "for" init cond inc (stmtToSInd indent body) | While(cond, body) -> - out "%s(%s)%s" "while" (exprToS cond) (stmtToSInd indent body) + out "%s(%s)%s" "while" (exprToS indent cond) (stmtToSInd indent body) | DoWhile(cond, body) -> - out "%s%s%s(%s)" "do" "while" (exprToS cond |> sp) (stmtToS indent body) + out "%s%s%s(%s)" "do" "while" (exprToS indent cond |> sp) (stmtToS indent body) | Jump(k, None) -> out "%s;" (jumpKeywordToString k) - | Jump(k, Some exp) -> out "%s%s;" (jumpKeywordToString k) (exprToS exp |> sp) + | Jump(k, Some exp) -> out "%s%s;" (jumpKeywordToString k) (exprToS indent exp |> sp) | Verbatim s -> // add a space at end when it seems to be needed let s = if s.Length > 0 && System.Char.IsLetterOrDigit s.[s.Length - 1] then s + " " else s @@ -233,13 +235,13 @@ module private PrinterImpl = else escape s | Switch(e, cl) -> let labelToS = function - | Case e -> out "case %s:" (exprToS e) + | Case e -> out "case %s:" (exprToS indent e) | Default -> out "default:" let caseToS (l, sl) = let stmts = List.map (stmtToS (indent+2)) sl |> String.concat "" out "%s%s%s" (nl (indent+1)) (labelToS l) stmts let body = List.map caseToS cl |> String.concat "" - out "%s(%s){%s%s}" "switch" (exprToS e) body (nl indent) + out "%s(%s){%s%s}" "switch" (exprToS indent e) body (nl indent) and stmtToS indent i = out "%s%s" (nl indent) (stmtToS' indent i) @@ -248,7 +250,7 @@ module private PrinterImpl = and stmtToSInd indent i = stmtToS (indent+1) i let funToS (f: FunctionType) = - out "%s %s(%s)%s" (typeToS f.retType) (idToS f.fName) (commaListToS declToS f.args) (semToS f.semantics) + out "%s %s(%s)%s" (typeToS f.retType) (idToS f.fName) (commaListToS (declToS 0) f.args) (semToS f.semantics) let topLevelToS = function | TLVerbatim s -> @@ -260,7 +262,7 @@ module private PrinterImpl = | Function (fct, body) -> out "%s%s%s{%s%s}" (nl 0) (funToS fct) (nl 0) (stmtToS 1 body) (nl 0) | Precision ty -> out "precision %s;" (typeToS ty); | TLDecl (_, []) -> "" - | TLDecl decl -> out "%s%s;" (nl 0) (declToS decl) + | TLDecl decl -> out "%s%s;" (nl 0) (declToS 0 decl) | TypeDecl t -> out "%s;" (typeSpecToS t) let print tl = @@ -286,7 +288,7 @@ let printText tl = let exprToS x = PrinterImpl.outputFormat <- Options.Text - PrinterImpl.exprToS x + PrinterImpl.exprToS 0 x let typeToS ty = PrinterImpl.outputFormat <- Options.Text diff --git a/src/rewriter.fs b/src/rewriter.fs index 7dfa6d51..16582859 100644 --- a/src/rewriter.fs +++ b/src/rewriter.fs @@ -392,12 +392,12 @@ let private simplifyBlock stmts = let b = removeUselessElseAfterReturn b // if(a)return b;return c; -> return a?b:c; - let rec replaceIfReturnsByReturnTernary = function + let rec replaceIfReturnsWithReturnTernary = function | If (cond, Jump(JumpKeyword.Return, Some retT), None) :: Jump(JumpKeyword.Return, Some retF) :: _rest -> [Jump(JumpKeyword.Return, Some (FunCall(Op "?:", [cond; retT; retF])))] - | stmt :: rest -> stmt :: replaceIfReturnsByReturnTernary rest + | stmt :: rest -> stmt :: replaceIfReturnsWithReturnTernary rest | stmts -> stmts - let b = replaceIfReturnsByReturnTernary b + let b = replaceIfReturnsWithReturnTernary b // Consecutive declarations of the same type become one. float a;float b; -> float a,b; let b = squeezeConsecutiveDeclarations b @@ -423,7 +423,6 @@ let private simplifyStmt = function | If (cond, body1, body2) -> let (body1, body2) = squeezeBlockWithComma body1, Option.map squeezeBlockWithComma body2 - // turn if-else into ternary match (body1, body2) with | (Expr eT, Some (Expr eF)) -> let tryCollapseToAssignment : Expr -> (Ident * Expr) option = function @@ -437,10 +436,14 @@ let private simplifyStmt = function | _ -> None | _ -> None match (tryCollapseToAssignment eT, tryCollapseToAssignment eF) with + // turn if-else of assignments into assignment of ternary | Some (nameT, initT), Some (nameF, initF) when nameT.Name = nameF.Name -> // if(c)x=y;else x=z; -> x=c?y:z; Expr (FunCall (Op "=", [Var nameT; FunCall(Op "?:", [cond; initT; initF])])) - | _ -> If (cond, body1, body2) + // turn if-else of expressions into ternary statement + | _ -> + // if(c)x();else y(); -> c?x():y(); + Expr (FunCall(Op "?:", [cond; eT; eF])) | _ -> If (cond, body1, body2) | Verbatim s -> Verbatim (stripSpaces s) | e -> e diff --git a/tests/compression_results.log b/tests/compression_results.log index 4f1d4252..172723ae 100644 --- a/tests/compression_results.log +++ b/tests/compression_results.log @@ -1,17 +1,17 @@ -from-the-seas-to-the-stars.frag 14347 => 2353.607 -the_real_party_is_in_your_pocket.frag 12200 => 1829.607 +from-the-seas-to-the-stars.frag 14313 => 2358.823 +the_real_party_is_in_your_pocket.frag 12196 => 1829.311 ed-209.frag 7888 => 1361.583 -valley_ball.glsl 4379 => 889.602 -lunaquatic.frag 5224 => 1058.755 +valley_ball.glsl 4369 => 890.945 +lunaquatic.frag 5218 => 1058.675 slisesix.frag 4533 => 956.567 yx_long_way_from_home.frag 2992 => 615.970 -oscars_chair.frag 4648 => 982.231 +oscars_chair.frag 4626 => 981.611 kinder_painter.frag 2880 => 450.617 ohanami.frag 3283 => 750.856 -terrarium.frag 3632 => 749.375 +terrarium.frag 3576 => 737.588 leizex.frag 2308 => 515.785 elevated.hlsl 3406 => 611.302 buoy.frag 4194 => 622.602 orchard.frag 5588 => 1051.886 robin.frag 6293 => 1066.421 -Total: 87795 => 15866.766 +Total: 87663 => 15860.542 diff --git a/tests/real/clod.expected b/tests/real/clod.expected index a3243b44..006a09db 100644 --- a/tests/real/clod.expected +++ b/tests/real/clod.expected @@ -1 +1 @@ -uniform vec2 resolution;uniform float time;uniform sampler2D tex0,tex1,tex2,tex3;float f(vec3 o){float a=(sin(o.x)+o.y*.25)*.35;o=vec3(cos(a)*o.x-sin(a)*o.y,sin(a)*o.x+cos(a)*o.y,o.z);return dot(cos(o)*cos(o),vec3(1))-1.2;}vec3 s(vec3 o,vec3 d){float t=0.,a,b;for(int i=0;i<75;i++){if(f(o+d*t)<0.){a=t-.125;b=t;for(int i=0;i<10;i++){t=(a+b)*.5;if(f(o+d*t)<0.)b=t;else a=t;}vec3 e=vec3(.1,0,0),p=o+d*t,n=-normalize(vec3(f(p+e),f(p+e.yxy),f(p+e.yyx))+vec3(sin(p*75.))*.01);return vec3(mix((max(-dot(n,vec3(.577)),0.)+.125*max(-dot(n,vec3(-.707,-.707,0)),0.))*(mod(length(p.xy)*20.,2.)<1.?vec3(.71,.85,.25):vec3(.79,.93,.4)),vec3(.93,.94,.85),vec3(pow(t/9.,5.))));}t+=.125;}return vec3(.93,.94,.85);}void main(){vec2 p=-1.+2.*gl_FragCoord.xy/resolution.xy;gl_FragColor=vec4(s(vec3(sin(time*1.5)*.5,cos(time)*.5,time),normalize(vec3(p.xy,1))),1);} +uniform vec2 resolution;uniform float time;uniform sampler2D tex0,tex1,tex2,tex3;float f(vec3 o){float a=(sin(o.x)+o.y*.25)*.35;o=vec3(cos(a)*o.x-sin(a)*o.y,sin(a)*o.x+cos(a)*o.y,o.z);return dot(cos(o)*cos(o),vec3(1))-1.2;}vec3 s(vec3 o,vec3 d){float t=0.,a,b;for(int i=0;i<75;i++){if(f(o+d*t)<0.){a=t-.125;b=t;for(int i=0;i<10;i++)t=(a+b)*.5,f(o+d*t)<0.?(b=t):(a=t);vec3 e=vec3(.1,0,0),p=o+d*t,n=-normalize(vec3(f(p+e),f(p+e.yxy),f(p+e.yyx))+vec3(sin(p*75.))*.01);return vec3(mix((max(-dot(n,vec3(.577)),0.)+.125*max(-dot(n,vec3(-.707,-.707,0)),0.))*(mod(length(p.xy)*20.,2.)<1.?vec3(.71,.85,.25):vec3(.79,.93,.4)),vec3(.93,.94,.85),vec3(pow(t/9.,5.))));}t+=.125;}return vec3(.93,.94,.85);}void main(){vec2 p=-1.+2.*gl_FragCoord.xy/resolution.xy;gl_FragColor=vec4(s(vec3(sin(time*1.5)*.5,cos(time)*.5,time),normalize(vec3(p.xy,1))),1);} diff --git a/tests/real/ed-209.frag.expected b/tests/real/ed-209.frag.expected index a15c9d3c..d682ace2 100644 --- a/tests/real/ed-209.frag.expected +++ b/tests/real/ed-209.frag.expected @@ -35,8 +35,12 @@ float sdTriPrism(vec3 p,vec2 h) } float sdCappedCone(vec3 p,vec3 a,vec3 b,float ra,float rb) { - float rba=rb-ra,baba=dot(b-a,b-a),papa=dot(p-a,p-a),paba=dot(p-a,b-a)/baba,x=sqrt(papa-paba*paba*baba),cax=max(0.,x-(paba<.5?ra:rb)),cay=abs(paba-.5)-.5,f=clamp((rba*(x-ra)+paba*baba)/(rba*rba+baba),0.,1.),cbx=x-ra-f*rba,cby=paba-f; - return(cbx<0.&&cay<0.?-1.:1.)*sqrt(min(cax*cax+cay*cay*baba,cbx*cbx+cby*cby*baba)); + float rba=rb-ra,baba=dot(b-a,b-a),papa=dot(p-a,p-a),paba=dot(p-a,b-a)/baba,x=sqrt(papa-paba*paba*baba),cax=max(0.,x-(paba<.5? + ra: + rb)),cay=abs(paba-.5)-.5,f=clamp((rba*(x-ra)+paba*baba)/(rba*rba+baba),0.,1.),cbx=x-ra-f*rba,cby=paba-f; + return(cbx<0.&&cay<0.? + -1.: + 1.)*sqrt(min(cax*cax+cay*cay*baba,cbx*cbx+cby*cby*baba)); } float sdCappedCylinder(vec3 p,float h,float r) { @@ -65,7 +69,9 @@ vec3 getRayDir(vec3 ro,vec3 lookAt,vec2 uv) } MarchData minResult(MarchData a,MarchData b) { - return a.dc) - w.w=R(),p.x=pow(abs(w.x),1.)*sign(w.x)*8.,p.z=pow(abs(w.y),1.)*sign(w.y)*8.,p.y=.2+fbm(p.xz-time/8.)*.2-pow(w.z*.5+.5,8.)*5.,col=vec3(.3,.5,1)/2,col=mix(col,vec3(1,.25,1),pow(w.w,4.)),col=mix(col,vec3(1),pow(1.-w.z*.5-.5,32.)),col*=1.-pow(w.z*.5+.5,1.),col+=pow(1-abs(fbm(p.xz*3.+time/8.+p.y)*.7-.6),32.)*.4,col/=2,p.x+=cos(p.x*8.)*.01,col*=.2,p.y+=.5; - else - if(w.w>1e-4) - w.x=R()*2-1,w.y=R()*2-1,w.z=R(),p.xz=w.xy*7,p.y=-1.+fbm(p.zx+19.)*.02*pow(length(p.xz),2.)-pow(w.z,8),p.z+=2.,col=vec3(.1,.06,.05)/1.5*smoothstep(-1.5,-.2,p.y),w.w=R(),col+=vec3(pow(w.w,80))*.1,col*=1.+pow(max(0.,1.-abs(fbm(p.xz*2+time/2)-.8)),16)/2; - else - p=w.xyz,p.x=fract(p.x+time/4.*.1)*2-1,p*=2.,w.w=R(),col=vec3(w.w)*.3; + w.w>c? + (w.w=R(),p.x=pow(abs(w.x),1.)*sign(w.x)*8.,p.z=pow(abs(w.y),1.)*sign(w.y)*8.,p.y=.2+fbm(p.xz-time/8.)*.2-pow(w.z*.5+.5,8.)*5.,col=vec3(.3,.5,1)/2,col=mix(col,vec3(1,.25,1),pow(w.w,4.)),col=mix(col,vec3(1),pow(1.-w.z*.5-.5,32.)),col*=1.-pow(w.z*.5+.5,1.),col+=pow(1-abs(fbm(p.xz*3.+time/8.+p.y)*.7-.6),32.)*.4,col/=2,p.x+=cos(p.x*8.)*.01,col*=.2,p.y+=.5): + w.w>1e-4? + (w.x=R()*2-1,w.y=R()*2-1,w.z=R(),p.xz=w.xy*7,p.y=-1.+fbm(p.zx+19.)*.02*pow(length(p.xz),2.)-pow(w.z,8),p.z+=2.,col=vec3(.1,.06,.05)/1.5*smoothstep(-1.5,-.2,p.y),w.w=R(),col+=vec3(pow(w.w,80))*.1,col*=1.+pow(max(0.,1.-abs(fbm(p.xz*2+time/2)-.8)),16)/2): + (p=w.xyz,p.x=fract(p.x+time/4.*.1)*2-1,p*=2.,w.w=R(),col=vec3(w.w)*.3); } void ammonite() { @@ -529,16 +527,11 @@ void main() { p.z+=sin(p.x); if(!bigkoi) - { - w.w=R(); - if(w.w<.33) - col=vec3(1,.25,.1); - else - if(w.w<.66) - col=vec3(.01),p.xz*=rotmat(1.8846); - else - col=vec3(.5),p.xz*=rotmat(3.7692); - } + w.w=R(),w.w<.33? + (col=vec3(1,.25,.1)): + w.w<.66? + (col=vec3(.01),p.xz*=rotmat(1.8846)): + (col=vec3(.5),p.xz*=rotmat(3.7692)); else { p.x*=2.; @@ -604,33 +597,11 @@ void main() op.x-=mod(op.x,.1)/3.; float d=koi(op.xy); if(max(d,abs(op.z)-.1*pow(-clamp(d,-1,0),.5))<0.) - { - p=op; - w.x=R(); - w.y=R(); - w.z=R(); - w.w=R(); - w.w=R(); - w.x=R(); - w.y=R(); - p.z+=.2; - p+=fp; - p.z+=sin(p.x*3.)*.1; - w.w=R(); - if(w.w<.33) - col=vec3(1,.25,.1); - else - if(w.w<.66) - col=vec3(.01),p.xz*=rotmat(3.141),p.z+=3.; - else - col=vec3(.5),p.xz*=rotmat(3.141),p.x+=2.,p.z+=6.; - w.x=R(); - col+=pow(w.x,32.)*vec3(.2); - w.x=R(); - w.y=R(); - w.z=R(); - w.w=R(); - } + p=op,w.x=R(),w.y=R(),w.z=R(),w.w=R(),w.w=R(),w.x=R(),w.y=R(),p.z+=.2,p+=fp,p.z+=sin(p.x*3.)*.1,w.w=R(),w.w<.33? + (col=vec3(1,.25,.1)): + w.w<.66? + (col=vec3(.01),p.xz*=rotmat(3.141),p.z+=3.): + (col=vec3(.5),p.xz*=rotmat(3.141),p.x+=2.,p.z+=6.),w.x=R(),col+=pow(w.x,32.)*vec3(.2),w.x=R(),w.y=R(),w.z=R(),w.w=R(); else { w.w=R(); diff --git a/tests/real/kinder_painter.expected b/tests/real/kinder_painter.expected index 9f3e88a7..61b2a6da 100644 --- a/tests/real/kinder_painter.expected +++ b/tests/real/kinder_painter.expected @@ -53,20 +53,30 @@ "vec3 calcnor(vec4 obj,vec4 col,vec3 inter,out vec2 uv)" "{" "vec3 nor;" - "uv=col.w>2.5?(nor.xz=inter.xz-obj.xz,nor.y=0.,nor/=obj.w,vec2(nor.x,inter.y)):col.w>1.5?(nor=obj.xyz,inter.xz*.2):(nor=inter-obj.xyz,nor/=obj.w,nor.xy);" + "uv=col.w>2.5?" + "(nor.xz=inter.xz-obj.xz,nor.y=0.,nor/=obj.w,vec2(nor.x,inter.y)):" + "col.w>1.5?" + "(nor=obj.xyz,inter.xz*.2):" + "(nor=inter-obj.xyz,nor/=obj.w,nor.xy);" "return nor;" "}" "vec4 cmov(vec4 a,vec4 b,bool cond)" "{" - "return cond?b:a;" + "return cond?" + "b:" + "a;" "}" "float cmov(float a,float b,bool cond)" "{" - "return cond?b:a;" + "return cond?" + "b:" + "a;" "}" "int cmov(int a,int b,bool cond)" "{" - "return cond?b:a;" + "return cond?" + "b:" + "a;" "}" "float intersect(vec3 ro,vec3 rd,out vec4 obj,out vec4 col)" "{" diff --git a/tests/real/lunaquatic.frag.expected b/tests/real/lunaquatic.frag.expected index 3471fccb..27fffc8f 100644 --- a/tests/real/lunaquatic.frag.expected +++ b/tests/real/lunaquatic.frag.expected @@ -46,7 +46,9 @@ float smoothrnd(vec2 x) } float height(vec2 x) { - float maxV=Y.z-EXPLOSIONTIME,l=mix(1.,max(0.,artifactPos.w-artifactPos.y),1.-(maxV>0.&&length(x-artifactPos.xz)0.&&length(x-artifactPos.xz)52.&&d<80.) color.xyz=mix(color.xyz,vec3(.8,.64,.4),t/2e2*norm(sin((d-50.)/30.*smoothrnd(vec2(d,3))))); - color.w=color.w<1.?3.*length(color):color.w; + color.w=color.w<1.? + 3.*length(color): + color.w; } return vec4(max(vec3(0),color.xyz*.3)*clamp(dot(rd,vec3(0,1,0))*8.,0.,1.),color.w); } @@ -115,7 +119,9 @@ vec3 calculateSky(vec3 ro,vec3 rd,int addPlanet) } float isoSurface(vec3 p) { - float b=Y.z>80.&&Y.z<112.?1.:0.; + float b=Y.z>80.&&Y.z<112.? + 1.: + 0.; p=rotateX(rotateY(rotateX(rotateY(p-artifactPos.xyz,3.*Y.z),3.*Y.z),b*sin(3.*Y.z+3.*p.y)),b*sin(3.*Y.z+3.*p.x)); p*=4.+10.*max(0.,Y.z-EXPLOSIONTIME); return-.4+p.x*p.x*p.x*p.x*p.x*p.x*p.x*p.x+p.y*p.y*p.y*p.y*p.y*p.y*p.y*p.y+p.z*p.z*p.z*p.z*p.z*p.z*p.z*p.z; @@ -130,13 +136,9 @@ float traceIso(vec3 ro,vec3 rd,float mint,float maxt,float s) if(iso<=0.) { for(int i=0;i<9;i++) - { - exact=(lt+t)/2.; - if(isoSurface(ro+exact*rd)<0.) - t=exact; - else - lt=exact; - } + exact=(lt+t)/2.,isoSurface(ro+exact*rd)<0.? + (t=exact): + (lt=exact); return exact; } lt=t; @@ -217,7 +219,9 @@ void main() } lightDir=normalize(lightPos-ro); dist=length(ro-artifactPos.xyz)-1.; - isoDistance=artifactPos.w==1.?traceIso(ro,rd,dist,dist+2.,99.):FAR; + isoDistance=artifactPos.w==1.? + traceIso(ro,rd,dist,dist+2.,99.): + FAR; if(isoDistance81?-1.4:-2.827;" + "float x=y>81?" + "-1.4:" + "-2.827;" "v-=z;" "v.y+=(n(v.xz*=mat2(cos(x),sin(x),-sin(x),cos(x)),2.5)/2+.5)*clamp(y/3-29,0,5)+c.y-1.25;" "v.x+=n(v.yz,2.5)*clamp(y/3-29,0,5)-max(0,v.y)/10;" "v.z=abs(v.z);" "return min(min(min(max(length(max(abs(v.xz)-vec2(.45,.41),0))-.25,abs(v.y)-.02),length(v-vec3(clamp(v.x,-.6,.6),-.1,.6))-.025),length(vec3(abs(v.x)-.6+min(0,v.y)/5,v.y-clamp(v.y,-1.24,1.5*step(0,v.x)),v.z-.6))-.025),max(length(max(abs(v.yz-vec2(1,0))-vec2(.5,.35),0))-.25,abs(v.x-.6)-.03));" "}" - "float h(vec3 v,vec3 y)" + "float e(vec3 v,vec3 y)" "{" "float x=0,f=0;" "for(;f<200&&x<30;++f)" "i=min(i,m=n(v+y*x)),x+=m/2;" "return x;" "}" - "vec3 w(vec3 v,vec3 a)" + "vec3 h(vec3 v,vec3 a)" "{" "vec3 r;" "x=v+a*(m=min((sign(a.x)*c.x-v.x)/a.x,min((sign(a.y)*c.y-v.y)/a.y,(sign(a.z)*c.z-v.z)/a.z)));" @@ -81,7 +83,7 @@ const char *oscars_chair_frag = "r*=mix(vec3(1,1,.5),vec3(1),min((-abs(x.y)+c.y)/4,1))*sqrt(min((-abs(x.y)+c.y)*8+.4,1));" "}" "r*=mix(4,1,smoothstep(1,2,length(x/c)))*max(0,1+3*dot(f,normalize(g-x)))/16*(1-smoothstep(0,2.5,length(max(abs(x)-c+1,0))));" - "r=(r+pow(clamp(dot(normalize(normalize(g-x)-a),f),0,1),64)*(r*.8+.2))*exp2(-length(g-x)/1.2)*s*20*mix(.02,2,smoothstep(.6,.7,dot(normalize(g-x),e)));" + "r=(r+pow(clamp(dot(normalize(normalize(g-x)-a),f),0,1),64)*(r*.8+.2))*exp2(-length(g-x)/1.2)*s*20*mix(.02,2,smoothstep(.6,.7,dot(normalize(g-x),l)));" "if(y<=97)" "r+=pow(vec3(2.2,.7,.3)*exp(-abs(n(x.xz/2+x.y/4-y/2,1.5))*10*n(-x.xy+y-x.z,1.5)+n(x.xy-y/3,2)*6-x.y-c.y-x.z-c.z+(y-88)/4+x.x/9),vec3(2))/70;" "return r;" @@ -105,50 +107,48 @@ const char *oscars_chair_frag = "vec3 t=vec3(0);" "for(int p=0;p<8;++p)" "{" - "float l=2.7,d;" - "vec3 o=vec3(10+y/4,-4,-1),b=vec3(-7,-2,0),u,C;" + "float o=2.7,d;" + "vec3 w=vec3(10+y/4,-4,-1),b=vec3(-7,-2,0),u,C;" "m=0;" - "if(y>97)" - "b=o=vec3(0,-4,y-97),b.z-=1,g=vec3(0,3,-22),s=.4,c=vec3(3,7,28),z=vec3(-4,0,13);" - "else" - " if(y>81)" - "b=o=vec3(0,-3.6,97-y),b.z-=1,g=vec3(0,5,-5),s=.01,l=1.7,c=vec3(7,5,9),z=vec3(0,0,-2);" - "else" - " if(y>60)" - "o=vec3((y-60)/5-1,-2,13),b=vec3(-7,-5,-7),g=vec3(0,5,-3),m=sin(y-60)/10-.9,c=vec3(7,5,9),z=vec3(-4,0,2);" - "else" - " if(y>25)" - "o=vec3(0,0,25-y/2.7),b=vec3(0,-4,18-y/2.7),g=vec3(-2,5,-7),c=vec3(9,5,14),z=vec3(3.5,0,-6);" - "else" - " m=-.9;" + "y>97?" + "(b=w=vec3(0,-4,y-97),b.z-=1,g=vec3(0,3,-22),s=.4,c=vec3(3,7,28),z=vec3(-4,0,13)):" + "y>81?" + "(b=w=vec3(0,-3.6,97-y),b.z-=1,g=vec3(0,5,-5),s=.01,o=1.7,c=vec3(7,5,9),z=vec3(0,0,-2)):" + "y>60?" + "(w=vec3((y-60)/5-1,-2,13),b=vec3(-7,-5,-7),g=vec3(0,5,-3),m=sin(y-60)/10-.9,c=vec3(7,5,9),z=vec3(-4,0,2)):" + "y>25?" + "(w=vec3(0,0,25-y/2.7),b=vec3(0,-4,18-y/2.7),g=vec3(-2,5,-7),c=vec3(9,5,14),z=vec3(3.5,0,-6)):" + "(m=-.9);" "r=7;" - "e=vec3(0,cos(m),sin(m));" - "u=normalize(b-o);" + "l=vec3(0,cos(m),sin(m));" + "u=normalize(b-w);" "C=normalize(vec3(-u.z,0,u.x));" "if(y>81&&y<=97)" "u.y+=n(vec2(y+6)/2,2)*.05,C.y+=n(vec2(y)/3,2)*.08;" - "u=mat3(C,cross(C,u),u)*normalize(vec3(v*2+vec2(p&1,p/2)/1200-1,l));" - "d=h(o,u);" + "u=mat3(C,cross(C,u),u)*normalize(vec3(v*2+vec2(p&1,p/2)/1200-1,o));" + "d=e(w,u);" "if(d<30)" - "x=o+u*d,f=vec3(.02,0,0),f=normalize(vec3(n(x+f.xyy)-m,n(x+f.yxy)-m,n(x+f.yyx)-m)),r=2,C=w(x,reflect(u,f))*pow(1+dot(u,f),3);" + "x=w+u*d,f=vec3(.02,0,0),f=normalize(vec3(n(x+f.xyy)-m,n(x+f.yxy)-m,n(x+f.yyx)-m)),r=2,C=h(x,reflect(u,f))*pow(1+dot(u,f),3);" "else" "{" - "C=w(o,u);" - "l=(.3+.7*pow(1+dot(u,f),2)/4)*(.1+.9*step(x.y,-c.y+.01));" - "o=reflect(u,f);" + "C=h(w,u);" + "o=(.3+.7*pow(1+dot(u,f),2)/4)*(.1+.9*step(x.y,-c.y+.01));" + "w=reflect(u,f);" "d=m;" "r=2;" "i=1e2;" "u=normalize(g-x);" - "h(x+u*.01,u);" + "e(x+u*.01,u);" "C*=.4+.6*smoothstep(0,n(x)/5,i);" "if(x.y<-c.y+.01)" - "if(h(x,o)<30)" - "l*=.2,C*=.7;" - "C+=w(x,o)*l*mix(vec3(1),C,.8);" + "if(e(x,w)<30)" + "o*=.2,C*=.7;" + "C+=h(x,w)*o*mix(vec3(1),C,.8);" "}" "if(y>60&&y<=97)" - "gl_FragColor.w=y<=81?(d-15)/6:d/15;" + "gl_FragColor.w=y<=81?" + "(d-15)/6:" + "d/15;" "C*=smoothstep(0,2,abs(y-60))*smoothstep(0,3,abs(y-112))*(1-(pow(abs(v.x*2-1),4)+pow(abs(v.y*2-1)*2.5,4))*.4);" "C=pow(.003+C*40,vec3(1,1.1,1.2));" "t+=C/(C+.4)*1.1;" diff --git a/tests/real/slisesix.frag.expected b/tests/real/slisesix.frag.expected index aafa9bbe..44cd3fa5 100644 --- a/tests/real/slisesix.frag.expected +++ b/tests/real/slisesix.frag.expected @@ -192,7 +192,9 @@ void main() im=inversesqrt(llig); lig*=im; dif=dot(nor,lig); - dif=matID==4?.5+.5*dif:.1+.9*dif; + dif=matID==4? + .5+.5*dif: + .1+.9*dif; dif=clamp(dif,0.,1.); dif*=2.5*exp2(-1.75*llig); dif2=(nor[0]+nor[1])*.075; diff --git a/tests/real/sult.expected b/tests/real/sult.expected index 6c9617cd..621aa51a 100644 --- a/tests/real/sult.expected +++ b/tests/real/sult.expected @@ -18,16 +18,18 @@ const char *sult_frag = "float f=0.,w=10.;" "float e(vec3 m)" "{" - "float y=c,w,z=0.,g,o,a;" + "float y=c,z,a=0.,g,o,t;" "vec3 r;" "m+=(sin(m.zxy*1.7+y)+sin(m.yzx+y*3.))*.2;" - "z=v<6.?length(m.xyz*vec3(1,1,.1)-vec3(0,-.1,y*.15-.3))-.34:length(m.xy+vec2(0,.7))-.3+(sin(m.z*17.+y*.6)+sin(m.z*2.)*6.)*.01;" + "a=v<6.?" + "length(m.xyz*vec3(1,1,.1)-vec3(0,-.1,y*.15-.3))-.34:" + "length(m.xy+vec2(0,.7))-.3+(sin(m.z*17.+y*.6)+sin(m.z*2.)*6.)*.01;" "m.xy=vec2(atan(m.x,m.y)*1.113,1.6-length(m.xy)-sin(y*2.)*.3);" "r=fract(m.xzz+.5).xyz-.5;" "r.y=(m.y-.35)*1.3;" - "w=max(abs(m.y-.3)-.05,abs(length(fract(m.xz)-.5)-.4)-.03);" - "f=step(z,w);" - "return min(min(w,z),m.y-.2);" + "z=max(abs(m.y-.3)-.05,abs(length(fract(m.xz)-.5)-.4)-.03);" + "f=step(a,z);" + "return min(min(z,a),m.y-.2);" "}" "vec3 d=vec3(.19,.2,.24),o=vec3(1),t=vec3(.45,.01,0),g=vec3(.17,0,0);" "void main()" @@ -41,10 +43,9 @@ const char *sult_frag = "{" "for(Z=X,Y=1.;Z.005;Z+=Y)" "Y=e(p+i*Z);" - "if(Z48.) p.z=mix(p.z,mod(p.z+time/2.+2,4.)-2,smoothstep(48.,49.,time)); } @@ -111,16 +104,13 @@ void main() { float s=H(seed=IH(seed)); p.y-=.8; - if(s<.93) - p.xy=(mat3(.860671,-.402177,0,.401487,.860992,0,.108537,.075138,1)*vec3(p.xy,1)).xy; - else - if(s<.95) - p.xy=(mat3(.094957,.237023,0,-.000995,.002036,0,-.746911,.047343,1)*vec3(p.xy,1)).xy; - else - if(s<.98) - p.xy=(mat3(.150288,0,0,0,.146854,0,-.563199,.032007,1)*vec3(p.xy,1)).xy; - else - p.xy=(mat3(.324279,.005846,0,-.002163,.001348,0,-.557936,-.139735,1)*vec3(p.xy,1)).xy; + s<.93? + (p.xy=(mat3(.860671,-.402177,0,.401487,.860992,0,.108537,.075138,1)*vec3(p.xy,1)).xy): + s<.95? + (p.xy=(mat3(.094957,.237023,0,-.000995,.002036,0,-.746911,.047343,1)*vec3(p.xy,1)).xy): + s<.98? + (p.xy=(mat3(.150288,0,0,0,.146854,0,-.563199,.032007,1)*vec3(p.xy,1)).xy): + (p.xy=(mat3(.324279,.005846,0,-.002163,.001348,0,-.557936,-.139735,1)*vec3(p.xy,1)).xy); p.y+=.8; } p*=1.+max(0.,time-130)/6.; @@ -139,6 +129,8 @@ void main() q.xz*=1.+H(seed=IH(seed))*max(0.,time-120)/20.; q.xz=400*q.xz+vec2(640,360)+randc(rand2(seed))*q.y*15.; if(q.x>0&&q.z>0&&q.x<1280&&q.z<720) - imageAtomicAdd(d0,ivec2(q.x,q.z),1|int(col>.5?1:0)<<20); + imageAtomicAdd(d0,ivec2(q.x,q.z),1|int(col>.5? + 1: + 0)<<20); } } diff --git a/tests/real/the_real_party_is_in_your_pocket.frag.expected b/tests/real/the_real_party_is_in_your_pocket.frag.expected index b32a69e5..f0ed28c4 100644 --- a/tests/real/the_real_party_is_in_your_pocket.frag.expected +++ b/tests/real/the_real_party_is_in_your_pocket.frag.expected @@ -87,12 +87,16 @@ const char *the_real_party_is_in_your_pocket_frag = "vec2 n=vec2(.04,.05),r=i.xy;" "i.xy=mod(i.xy,n)-n/2.;" "f=v(vec2(length(i.xy),i.z),vec2(x,l))-z;" - "f=max(f,abs(r.y-.05)-(a?.3:.15));" + "f=max(f,abs(r.y-.05)-(a?" + ".3:" + ".15));" "if(a)" "f=max(f,abs(r.x-.04)-.13);" "r.xy=m(-s)*r.xy;" "f=max(f,abs(r.x-.12+n.x)-.125);" - "f=max(f,abs(r.y-r.x*.2+.015+(a?-.03:0.))-.1265);" + "f=max(f,abs(r.y-r.x*.2+.015+(a?" + "-.03:" + "0.))-.1265);" "return f;" "}" "float x(float l,float m)" @@ -198,7 +202,7 @@ const char *the_real_party_is_in_your_pocket_frag = "vec4 s(vec3 l,vec3 v,out vec3 y)" "{" "float m=10.,f,a;" - "vec2 z,i,c,r;" + "vec2 z,c,i,r;" "vec3 g,u;" "vec4 d=vec4(-1);" "{" @@ -229,13 +233,13 @@ const char *the_real_party_is_in_your_pocket_frag = "if(d.x>0.)" "return y=g,d;" "m=-1.;" - "i=vec2(-1,-3);" - "f=(i.x-l.y)/v.y;" - "a=(i.y-l.z)/v.z;" - "c=s((l-vec3(0,i+2.))*vec3(0,.5,.5),v*vec3(0,.5,.5));" - "r=l.yz+v.yz*c.y-i-2.;" - "if(c.x0.&&r.x<0.&&r.y<0.)" - "y=vec3(-r*.5,0).zxy,m=c.y;" + "c=vec2(-1,-3);" + "f=(c.x-l.y)/v.y;" + "a=(c.y-l.z)/v.z;" + "i=s((l-vec3(0,c+2.))*vec3(0,.5,.5),v*vec3(0,.5,.5));" + "r=l.yz+v.yz*i.y-c-2.;" + "if(i.x0.&&r.x<0.&&r.y<0.)" + "y=vec3(-r*.5,0).zxy,m=i.y;" "else" " if(f>0.&&(f5.||abs(u.y)>2.5||abs(u.z)>3.3?vec4(-1):vec4(m,0,0,0);" + "return abs(u.x)>5.||abs(u.y)>2.5||abs(u.z)>3.3?" + "vec4(-1):" + "vec4(m,0,0,0);" "}" "float y;" "float m()" @@ -270,7 +276,11 @@ const char *the_real_party_is_in_your_pocket_frag = "c=l+v*d;" "vec2 o=vec2(6.28319*m(),m()*2.-1.);" "r=z+vec3(sqrt(1.-o.y*o.y)*vec2(cos(o.x),sin(o.x)),o.y);" - "k=u.y>1.5?mix(c.x>0.?.1:.05,.5,pow(1.-clamp(dot(-v,z),0.,1.),2.)):mix(.2,.8,pow(1.-clamp(dot(-v,z),0.,1.),1.5));" + "k=u.y>1.5?" + "mix(c.x>0.?" + ".1:" + ".05,.5,pow(1.-clamp(dot(-v,z),0.,1.),2.)):" + "mix(.2,.8,pow(1.-clamp(dot(-v,z),0.,1.),1.5));" "if(u.y>5.5&&u.y<6.5)" "{" "if(y)" @@ -285,15 +295,16 @@ const char *the_real_party_is_in_your_pocket_frag = "if(y)" "break;" "k=.02;" - "if(m()>k)" - "l=c-z*2e-4*-sign(v.z),v+=(vec3(m(),m(),m())-.5)*.1;" - "else" - " l=c+z*2e-4,v=reflect(v,z)+(vec3(m(),m(),m())-.5)*.3;" + "m()>k?" + "(l=c-z*2e-4*-sign(v.z),v+=(vec3(m(),m(),m())-.5)*.1):" + "(l=c+z*2e-4,v=reflect(v,z)+(vec3(m(),m(),m())-.5)*.3);" "}" "else" " if(u.y<.5||u.y>2.5)" "{" - "vec3 b=u.y>2.5?vec3(.08):vec3(.7);" + "vec3 b=u.y>2.5?" + "vec3(.08):" + "vec3(.7);" "if(u.y>3.5)" "{" "b=vec3(.008);" @@ -376,7 +387,11 @@ const char *the_real_party_is_in_your_pocket_frag = "}" "else" "{" - "vec3 w=g>1.5?vec3(1,.02,.2):g>.5?vec3(.2,1,.02):vec3(.02,.2,1);" + "vec3 w=g>1.5?" + "vec3(1,.02,.2):" + "g>.5?" + "vec3(.2,1,.02):" + "vec3(.02,.2,1);" "if(m()>mix(.2,1.,k))" "{" "if(u.y>1.5)" @@ -390,7 +405,9 @@ const char *the_real_party_is_in_your_pocket_frag = "{" "if(y)" "break;" - "a*=u.y>1.5?vec3(.5):.9*mix(w,vec3(1),.25);" + "a*=u.y>1.5?" + "vec3(.5):" + ".9*mix(w,vec3(1),.25);" "l=c+z*2e-4;" "v=reflect(v,z)+(vec3(m(),m(),m())-.5)*.4;" "}" diff --git a/tests/real/valley_ball.glsl.expected b/tests/real/valley_ball.glsl.expected index 0a3ef412..443e52cd 100644 --- a/tests/real/valley_ball.glsl.expected +++ b/tests/real/valley_ball.glsl.expected @@ -71,7 +71,9 @@ vec3 shadeTerrain(vec3 p,vec3 rd) } vec3 shadeSky(vec3 ro,vec3 rd) { - return ro.y<=-eps*eps?waterColor:(1.+Y.z*.3)*mix(vec3(-.5,-.25,0),vec3(2),1.-rd.y*.5-.5); + return ro.y<=-eps*eps? + waterColor: + (1.+Y.z*.3)*mix(vec3(-.5,-.25,0),vec3(2),1.-rd.y*.5-.5); } vec3 shadeAttractor(vec3 p,vec3 rd) { @@ -108,19 +110,29 @@ float traceAttractor(vec3 ro,vec3 rd) if(B>0.) return 9.; D=B*B-dot(dst,dst)+sphereRadius*sphereRadius; - return D>0.?-B-sqrt(D):9.; + return D>0.? + -B-sqrt(D): + 9.; } float traceWater(vec3 ro,vec3 rd) { float tPlane=-ro.y/rd.y; - return tPlane>=eps?tPlane:9.; + return tPlane>=eps? + tPlane: + 9.; } vec4 traceRay(vec3 ro,vec3 rd,int ignore) { float water,attractor,terrain,minDist; - water=ignore!=2?traceWater(ro,rd):9.; - attractor=ignore!=3?traceAttractor(ro,rd):9.; - terrain=ignore!=1?traceTerrain(ro,rd,min(.5,.002+min(water,attractor))):9.; + water=ignore!=2? + traceWater(ro,rd): + 9.; + attractor=ignore!=3? + traceAttractor(ro,rd): + 9.; + terrain=ignore!=1? + traceTerrain(ro,rd,min(.5,.002+min(water,attractor))): + 9.; gf_DetailLevel/=20.; minDist=min(terrain,min(water,min(attractor,9.))); if(minDist==9.) @@ -135,30 +147,46 @@ vec4 traceRay(vec3 ro,vec3 rd,int ignore) } vec3 shade(vec4 hitPoint,vec3 newRo,vec3 rd) { - vec3 myFog=newRo.y22&&scene<27) - seed=min(1.,sin((Y.y-23.)*pi*.25)*12.),ro=vec3(.12,.005,Y.y*.08),rd=vec3(mm*vec4(rd,1)),rd.y+=.1*cos(Y.y*4.); - else - if(scene>14&&scene<23) - seed=min(1.,sin((Y.y-15.)*pi*.125)*24.),rd+=vec3(0,.1*cos(Y.y*4.),0),ro=vec3(.08,.01*sin(Y.y*4.)+.002,Y.y*.11); - else - ro=vec3(.1,.004,0)+vec3(.1,.005,20)*vec3(rnd(vec2(scene,seed++)),rnd(vec2(scene,seed++)),rnd(vec2(scene,seed++))),ro=mix(ro+vec3(.008)*vec3(rnd(vec2(scene,seed++)),rnd(vec2(scene,seed++)),rnd(vec2(scene,seed++))),ro+vec3(.008)*vec3(rnd(vec2(scene,seed++)),rnd(vec2(scene,seed++)),rnd(vec2(scene,seed++))),Y.y-float(scene)),ro.y+=height(ro.xz)+.02,ro+=.02*getTerrainNormal(ro),seed=min(1.,step(-28.,-Y.y)*sin((Y.y-float(scene))*pi)*3.); + scene>22&&scene<27? + (seed=min(1.,sin((Y.y-23.)*pi*.25)*12.),ro=vec3(.12,.005,Y.y*.08),rd=vec3(mm*vec4(rd,1)),rd.y+=.1*cos(Y.y*4.)): + scene>14&&scene<23? + (seed=min(1.,sin((Y.y-15.)*pi*.125)*24.),rd+=vec3(0,.1*cos(Y.y*4.),0),ro=vec3(.08,.01*sin(Y.y*4.)+.002,Y.y*.11)): + (ro=vec3(.1,.004,0)+vec3(.1,.005,20)*vec3(rnd(vec2(scene,seed++)),rnd(vec2(scene,seed++)),rnd(vec2(scene,seed++))),ro=mix(ro+vec3(.008)*vec3(rnd(vec2(scene,seed++)),rnd(vec2(scene,seed++)),rnd(vec2(scene,seed++))),ro+vec3(.008)*vec3(rnd(vec2(scene,seed++)),rnd(vec2(scene,seed++)),rnd(vec2(scene,seed++))),Y.y-float(scene)),ro.y+=height(ro.xz)+.02,ro+=.02*getTerrainNormal(ro),seed=min(1.,step(-28.,-Y.y)*sin((Y.y-float(scene))*pi)*3.)); rd=normalize(rd); - spherePos=scene>22&&scene<27?ro+.1*vec3(mm*vec4(0,0,1,1)):ro+.02*vec3(sin(Y.y),0,5.+cos(Y.y)); + spherePos=scene>22&&scene<27? + ro+.1*vec3(mm*vec4(0,0,1,1)): + ro+.02*vec3(sin(Y.y),0,5.+cos(Y.y)); spherePos.y+=.01+height(spherePos.xz); - sphereRadius=scene<14?0.:bigeps*.5+bigeps*Y.z; + sphereRadius=scene<14? + 0.: + bigeps*.5+bigeps*Y.z; spherePos+=2.*bigeps*getTerrainNormal(spherePos); lightDir=vec3(.58,.58,-.58); lightColor=vec3(1.2)+Y.z; diff --git a/tests/real/yx_long_way_from_home.frag.expected b/tests/real/yx_long_way_from_home.frag.expected index 23679030..4e7477a8 100644 --- a/tests/real/yx_long_way_from_home.frag.expected +++ b/tests/real/yx_long_way_from_home.frag.expected @@ -66,7 +66,9 @@ const char *yx_long_way_from_home_frag = "s.xz=mod(s.xz-.5,1.)-.5;" "}" "y.y-=.25;" - "i=n=0.?m:vec4(0);" + "gl_FragColor=!isnan(m.x)&&m.x>=0.?" + "m:" + "vec4(0);" "}"; #endif // YX_LONG_WAY_FROM_HOME_FRAG_EXPECTED_ diff --git a/tests/unit/blocks.expected b/tests/unit/blocks.expected index d01aef5f..eaff26cb 100644 --- a/tests/unit/blocks.expected +++ b/tests/unit/blocks.expected @@ -11,7 +11,11 @@ const char *blocks_frag = "float bar;" "if(foo==2)" "foo++;" - "bar=foo<5?foo==3?.2:.3:.4;" + "bar=foo<5?" + "foo==3?" + ".2:" + ".3:" + ".4;" "return bar;" "}" "int k=5;" @@ -57,7 +61,9 @@ const char *blocks_frag = "}" "float replaceIfReturnsByReturnTernary1(float f)" "{" - "return f<2.?b:c;" + "return f<2.?" + "b:" + "c;" "}" "void main()" "{" diff --git a/tests/unit/conditionals.frag.expected b/tests/unit/conditionals.frag.expected index be4f0dba..0e0bfd17 100644 --- a/tests/unit/conditionals.frag.expected +++ b/tests/unit/conditionals.frag.expected @@ -46,11 +46,14 @@ int foo() float ifStmtToExpr(float f) { float r,r2,r3; - r=f>0?1.:2.; - r2=f>1?1.:(foo(),2.); - if(f>1) - r3=1.; - else - r3=2.,foo(); + r=f>0? + 1.: + 2.; + r2=f>1? + 1.: + (foo(),2.); + f>1? + (r3=1.): + (r3=2.,foo()); return r+r2+r3; } diff --git a/tests/unit/function_comma.expected b/tests/unit/function_comma.expected index 8a8b4d6a..49fa9fa6 100644 --- a/tests/unit/function_comma.expected +++ b/tests/unit/function_comma.expected @@ -1,4 +1,4 @@ -/* File generated with Shader Minifier 1.3 +/* File generated with * http://www.ctrl-alt-test.fr */ #ifndef FUNCTION_COMMA_EXPECTED_ @@ -7,7 +7,9 @@ const char *function_comma_frag = "float min(float a,float b)" "{" - "return a246913578.?1e2:x>123456789.?101.:102.; + return x>246913578.? + 1e2: + x>123456789.? + 101.: + 102.; } float inl3() { diff --git a/tests/unit/inline-aggro.expected b/tests/unit/inline-aggro.expected index 62c1b232..db9f4a65 100644 --- a/tests/unit/inline-aggro.expected +++ b/tests/unit/inline-aggro.expected @@ -6,7 +6,11 @@ float inl1() float inl2(float x) { float f=123456789.; - return x>2.*f?1e2:x>f?101.:102.; + return x>2.*f? + 1e2: + x>f? + 101.: + 102.; } float inl3() { From 25de42a76ef6201291eed0888e78d81d05fff5ce Mon Sep 17 00:00:00 2001 From: Eldritch Conundrum Date: Sat, 14 Jan 2023 23:43:13 +0100 Subject: [PATCH 14/32] Rewrite while into for, take opportunities to save semi-colons (#213) --- README.md | 20 ++++++++ src/rewriter.fs | 43 ++++++++++++++++- tests/commands.txt | 1 + tests/compression_results.log | 4 +- .../from-the-seas-to-the-stars.frag.expected | 6 +-- tests/real/sult.expected | 23 ++++----- tests/unit/blocks.expected | 9 ++-- tests/unit/inline-aggro.aggro.expected | 2 +- tests/unit/inline-aggro.expected | 2 +- tests/unit/loop.frag | 48 +++++++++++++++++++ tests/unit/loop.frag.expected | 47 ++++++++++++++++++ 11 files changed, 176 insertions(+), 29 deletions(-) create mode 100644 tests/unit/loop.frag create mode 100644 tests/unit/loop.frag.expected diff --git a/README.md b/README.md index 9a41b850..4a147fed 100644 --- a/README.md +++ b/README.md @@ -463,6 +463,26 @@ Output: return y ? z : w; ``` +### Loops + +`while` loops are rewritten as `for` loops. This sometimes enable removing semi-colons or braces, +either by moving the preceding statement into the initialization of the `for`, +or by moving the last statement of the loop body into the increment part of the `for`. + +Input: +```glsl +i = 0.; +while (i < 50) { + f(i); + i++; +} +``` + +Output: +```glsl +for(i=0.;i<50;i++)f(i); +``` + ### Merge declarations If multiple values of the same type are declared next to each other, we can merge diff --git a/src/rewriter.fs b/src/rewriter.fs index 16582859..71377ff8 100644 --- a/src/rewriter.fs +++ b/src/rewriter.fs @@ -352,6 +352,14 @@ let squeezeBlockWithComma = function else stmt | stmt -> stmt +let hasNoDecl = List.forall (function Decl _ -> false | _ -> true) + +let rec hasNoContinue stmts = stmts |> List.forall (function + | Jump (JumpKeyword.Continue, _) -> false + | If (_cond, bodyT, bodyF) -> hasNoContinue [bodyT] && hasNoContinue (Option.toList bodyF) + | Switch (_e, cases) -> cases |> List.forall (fun (_label, stmts) -> hasNoContinue stmts) + | _ -> true) + let private simplifyBlock stmts = let b = stmts // Avoid some optimizations when there are preprocessor directives. @@ -368,7 +376,22 @@ let private simplifyBlock stmts = | Decl (_, []) -> false | _ -> true) - let hasNoDecl = List.forall (function Decl _ -> false | _ -> true) + // Merge two consecutive items into one, everywhere possible in a list. + let rec squeeze (f : 'a * 'a -> 'a option) = function + | h1 :: h2 :: t -> + match f (h1, h2) with + | Some x -> squeeze f (x :: t) + | None -> h1 :: (squeeze f (h2 :: t)) + | h :: t -> h :: t + | [] -> [] + + // Merge preceding expression into a for's init. + let b = b |> squeeze (function + | (Expr e, ForE (None, cond, inc, body)) -> // a=0;for(;i<5;++i); -> for(a=0;i<5;++i); + Some (ForE (Some e, cond, inc, body)) + | (Expr e, While (cond, body)) -> // a=0;while(i<5); -> for(a=0;i<5;); + Some (ForE(Some e, Some cond, None, body)) + | _ -> None) // Inline inner decl-less blocks. (Presence of decl could lead to redefinitions.) a();{b();}c(); -> a();b();c(); let b = b |> List.collect (function @@ -414,11 +437,27 @@ let private simplifyStmt = function | Decl (ty, li) -> Decl (rwType ty, declsNotToInline li) | ForD ((ty, d), cond, inc, body) -> ForD((rwType ty, declsNotToInline d), cond, inc, squeezeBlockWithComma body) | ForE (init, cond, inc, body) -> ForE(init, cond, inc, squeezeBlockWithComma body) - | While (cond, body) -> While (cond, squeezeBlockWithComma body) + | While (cond, body) -> + match body with + | Expr e -> ForE (None, Some cond, Some e, Block []) // while(c)b(); -> for(;c;b()); + | Block stmts -> + match List.rev stmts with + | Expr last :: revBody when hasNoContinue stmts && hasNoDecl stmts -> + // This rewrite is only valid if: + // * continue is never used in this loop, and + // * the last expression of the body does not use any Decl from the body. + let block = match (List.rev revBody) with + | [stmt] -> stmt + | stmts -> Block stmts + ForE (None, Some cond, Some last, block) // while(c){a();b();} -> for(;c;b())a(); + | _ -> ForE (None, Some cond, None, squeezeBlockWithComma (Block stmts)) + | _ -> ForE (None, Some cond, None, squeezeBlockWithComma body) | DoWhile (cond, body) -> DoWhile (cond, squeezeBlockWithComma body) | If (True, e1, _) -> squeezeBlockWithComma e1 | If (False, _, Some e2) -> squeezeBlockWithComma e2 | If (False, _, None) -> Block [] + | If (cond, Block [], None) -> Expr cond // if(c); -> c; + | If (cond, Block [], Some (Block [])) -> Expr cond // if(c)else{}; -> c; | If (c, b, Some (Block [])) -> If(c, b, None) // "else{}" -> "" | If (cond, body1, body2) -> let (body1, body2) = squeezeBlockWithComma body1, Option.map squeezeBlockWithComma body2 diff --git a/tests/commands.txt b/tests/commands.txt index 9e73185e..f2e018e1 100644 --- a/tests/commands.txt +++ b/tests/commands.txt @@ -22,6 +22,7 @@ --no-renaming --no-inlining --format indented -o tests/unit/vectors.frag.expected tests/unit/vectors.frag --no-renaming --format indented -o tests/unit/deadcode.frag.expected tests/unit/deadcode.frag --no-renaming --no-inlining --format indented -o tests/unit/augmented.frag.expected tests/unit/augmented.frag +--no-remove-unused --no-renaming -o tests/unit/loop.frag.expected tests/unit/loop.frag # Inlining unit tests diff --git a/tests/compression_results.log b/tests/compression_results.log index 172723ae..94179913 100644 --- a/tests/compression_results.log +++ b/tests/compression_results.log @@ -1,4 +1,4 @@ -from-the-seas-to-the-stars.frag 14313 => 2358.823 +from-the-seas-to-the-stars.frag 14305 => 2358.450 the_real_party_is_in_your_pocket.frag 12196 => 1829.311 ed-209.frag 7888 => 1361.583 valley_ball.glsl 4369 => 890.945 @@ -14,4 +14,4 @@ elevated.hlsl 3406 => 611.302 buoy.frag 4194 => 622.602 orchard.frag 5588 => 1051.886 robin.frag 6293 => 1066.421 -Total: 87663 => 15860.542 +Total: 87655 => 15860.170 diff --git a/tests/real/from-the-seas-to-the-stars.frag.expected b/tests/real/from-the-seas-to-the-stars.frag.expected index 10cea3f3..ad3cd07b 100644 --- a/tests/real/from-the-seas-to-the-stars.frag.expected +++ b/tests/real/from-the-seas-to-the-stars.frag.expected @@ -432,8 +432,7 @@ void main() w.y=R(); w.z=R(); w.w=R(); - if(w.w<.5) - ; + w.w<.5; } } p.xyz+=(w.xyz*2-1)*pow(length(p),2)*.001; @@ -485,8 +484,7 @@ void main() w.y=R(); w.z=R(); w.w=R(); - if(w.w<.5) - ; + w.w<.5; } } p.xyz+=(w.xyz*2-1)*pow(length(p),2)*.001; diff --git a/tests/real/sult.expected b/tests/real/sult.expected index 621aa51a..35c5a9cc 100644 --- a/tests/real/sult.expected +++ b/tests/real/sult.expected @@ -18,18 +18,18 @@ const char *sult_frag = "float f=0.,w=10.;" "float e(vec3 m)" "{" - "float y=c,z,a=0.,g,o,t;" + "float y=c,g,z=0.,o,a,t;" "vec3 r;" "m+=(sin(m.zxy*1.7+y)+sin(m.yzx+y*3.))*.2;" - "a=v<6.?" + "z=v<6.?" "length(m.xyz*vec3(1,1,.1)-vec3(0,-.1,y*.15-.3))-.34:" "length(m.xy+vec2(0,.7))-.3+(sin(m.z*17.+y*.6)+sin(m.z*2.)*6.)*.01;" "m.xy=vec2(atan(m.x,m.y)*1.113,1.6-length(m.xy)-sin(y*2.)*.3);" "r=fract(m.xzz+.5).xyz-.5;" "r.y=(m.y-.35)*1.3;" - "z=max(abs(m.y-.3)-.05,abs(length(fract(m.xz)-.5)-.4)-.03);" - "f=step(a,z);" - "return min(min(z,a),m.y-.2);" + "g=max(abs(m.y-.3)-.05,abs(length(fract(m.xz)-.5)-.4)-.03);" + "f=step(z,g);" + "return min(min(g,z),m.y-.2);" "}" "vec3 d=vec3(.19,.2,.24),o=vec3(1),t=vec3(.45,.01,0),g=vec3(.17,0,0);" "void main()" @@ -39,14 +39,11 @@ const char *sult_frag = "float C=1.,b=0.,Z,Y,X=0.,W,V,U,T;" "u=vec3(.01,0,0);" "h=u.yyy;" - "while(C>.1)" - "{" - "for(Z=X,Y=1.;Z.005;Z+=Y)" - "Y=e(p+i*Z);" - "Z.1;Z.005;Z+=Y)" + "Y=e(p+i*Z);" "gl_FragColor.xyz=h;" "gl_FragColor.w=1.;" "}"; diff --git a/tests/unit/blocks.expected b/tests/unit/blocks.expected index eaff26cb..6514e124 100644 --- a/tests/unit/blocks.expected +++ b/tests/unit/blocks.expected @@ -33,8 +33,7 @@ const char *blocks_frag = "}" "int test_block()" "{" - "if(k==0)" - ";" + "k==0;" "for(int i=0;i<2;i++)" "{" "if(k==1)" @@ -72,10 +71,8 @@ const char *blocks_frag = "removeUselessElseAfterReturn2(0.);" "replaceIfReturnsByReturnTernary1(0.);" "gl_FragColor=vec4(.2,a,b,0);" - "if(a0) + for(;--i>0;) ; return 1; } diff --git a/tests/unit/inline-aggro.expected b/tests/unit/inline-aggro.expected index db9f4a65..db16cdd9 100644 --- a/tests/unit/inline-aggro.expected +++ b/tests/unit/inline-aggro.expected @@ -120,7 +120,7 @@ int noinl11(ivec3 x) int noinl12() { int i=10; - while(--i>0) + for(;--i>0;) ; return 1; } diff --git a/tests/unit/loop.frag b/tests/unit/loop.frag new file mode 100644 index 00000000..b5df06f9 --- /dev/null +++ b/tests/unit/loop.frag @@ -0,0 +1,48 @@ +float f(){return 0.;} +void main() +{ + float c; + for (float a=0; a<50.; ++a) + { + c+=cos(a); + } + float b; + for (b=0; b<50.; ++b) + { + c+=cos(c); + } + b = a; + while (b<50.) + { + c+=cos(c); + b++; + } + b = a; + while (b<50.) + { + b++; + } + b = a; + while (b<50.) + { + c+=cos(c); + float d=f(); // d prevents moving b+=d to a for + b+=d; + } + b = a; + while (b<50.) + { + if (a < b) continue; // continue prevents moving b++ to a for + b++; + } + b = a; + while (b<50.) + { + if (a < b) a=b; else continue; // continue prevents moving b++ to a for + b++; + } + for (; b<50.; ++b) + { + c+=cos(b); + } +} \ No newline at end of file diff --git a/tests/unit/loop.frag.expected b/tests/unit/loop.frag.expected new file mode 100644 index 00000000..ffb683e7 --- /dev/null +++ b/tests/unit/loop.frag.expected @@ -0,0 +1,47 @@ +/* File generated with + * http://www.ctrl-alt-test.fr + */ +#ifndef LOOP_FRAG_EXPECTED_ +# define LOOP_FRAG_EXPECTED_ + +const char *loop_frag = + "float f()" + "{" + "return 0.;" + "}" + "void main()" + "{" + "float c,b;" + "for(float a=0;a<50.;++a)" + "c+=cos(a);" + "for(b=0;b<50.;++b)" + "c+=cos(c);" + "for(b=a;b<50.;b++)" + "c+=cos(c);" + "for(b=a;b<50.;b++)" + ";" + "for(b=a;b<50.;)" + "{" + "c+=cos(c);" + "float d=f();" + "b+=d;" + "}" + "for(b=a;b<50.;)" + "{" + "if(a Date: Sun, 15 Jan 2023 00:17:04 +0100 Subject: [PATCH 15/32] Fix shader compilation errors in unit tests (#214) --- tests/unit/augmented.frag | 2 ++ tests/unit/augmented.frag.expected | 2 ++ tests/unit/blocks.expected | 4 ++-- tests/unit/blocks.frag | 4 ++-- tests/unit/conditionals.frag | 6 +++--- tests/unit/conditionals.frag.expected | 6 +++--- tests/unit/loop.frag | 8 +++++--- tests/unit/loop.frag.expected | 7 ++++--- 8 files changed, 23 insertions(+), 16 deletions(-) diff --git a/tests/unit/augmented.frag b/tests/unit/augmented.frag index 6c5366a7..67ff64f5 100644 --- a/tests/unit/augmented.frag +++ b/tests/unit/augmented.frag @@ -1,3 +1,5 @@ +#extension GL_EXT_gpu_shader4 : enable + int foo(int x, int y) { int a=x; a=a+x; diff --git a/tests/unit/augmented.frag.expected b/tests/unit/augmented.frag.expected index a8be711d..4a5e2bed 100644 --- a/tests/unit/augmented.frag.expected +++ b/tests/unit/augmented.frag.expected @@ -1,3 +1,5 @@ +#extension GL_EXT_gpu_shader4:enable + int foo(int x,int y) { int a=x; diff --git a/tests/unit/blocks.expected b/tests/unit/blocks.expected index 6514e124..45b60ae2 100644 --- a/tests/unit/blocks.expected +++ b/tests/unit/blocks.expected @@ -61,8 +61,8 @@ const char *blocks_frag = "float replaceIfReturnsByReturnTernary1(float f)" "{" "return f<2.?" - "b:" - "c;" + "f:" + "f+1.;" "}" "void main()" "{" diff --git a/tests/unit/blocks.frag b/tests/unit/blocks.frag index eefc93b2..13ad8a54 100644 --- a/tests/unit/blocks.frag +++ b/tests/unit/blocks.frag @@ -60,8 +60,8 @@ float removeUselessElseAfterReturn2(float f) float replaceIfReturnsByReturnTernary1(float f) { if (f < 2.) - return b; - return c; + return f; + return f + 1.; } void main() diff --git a/tests/unit/conditionals.frag b/tests/unit/conditionals.frag index 03f36565..6d291f55 100644 --- a/tests/unit/conditionals.frag +++ b/tests/unit/conditionals.frag @@ -49,19 +49,19 @@ int foo() { float ifStmtToExpr(float f) { float r; - if (f > 0) + if (f > 0.0) r = 1.0; else r = 2.0; float r2; - if (f > 1) { + if (f > 1.0) { r2 = 1.0; } else { foo(); r2 = 2.0; } float r3; - if (f > 1) { + if (f > 1.0) { r3 = 1.0; } else { r3 = 2.0; diff --git a/tests/unit/conditionals.frag.expected b/tests/unit/conditionals.frag.expected index 0e0bfd17..5957d975 100644 --- a/tests/unit/conditionals.frag.expected +++ b/tests/unit/conditionals.frag.expected @@ -46,13 +46,13 @@ int foo() float ifStmtToExpr(float f) { float r,r2,r3; - r=f>0? + r=f>0.? 1.: 2.; - r2=f>1? + r2=f>1.? 1.: (foo(),2.); - f>1? + f>1.? (r3=1.): (r3=2.,foo()); return r+r2+r3; diff --git a/tests/unit/loop.frag b/tests/unit/loop.frag index b5df06f9..d615f641 100644 --- a/tests/unit/loop.frag +++ b/tests/unit/loop.frag @@ -1,13 +1,15 @@ float f(){return 0.;} + +float a; void main() { float c; - for (float a=0; a<50.; ++a) + for (float d=0.; d<50.; ++d) { - c+=cos(a); + c+=cos(d); } float b; - for (b=0; b<50.; ++b) + for (b=0.; b<50.; ++b) { c+=cos(c); } diff --git a/tests/unit/loop.frag.expected b/tests/unit/loop.frag.expected index ffb683e7..65d334e8 100644 --- a/tests/unit/loop.frag.expected +++ b/tests/unit/loop.frag.expected @@ -9,12 +9,13 @@ const char *loop_frag = "{" "return 0.;" "}" + "float a;" "void main()" "{" "float c,b;" - "for(float a=0;a<50.;++a)" - "c+=cos(a);" - "for(b=0;b<50.;++b)" + "for(float d=0.;d<50.;++d)" + "c+=cos(d);" + "for(b=0.;b<50.;++b)" "c+=cos(c);" "for(b=a;b<50.;b++)" "c+=cos(c);" From 4aac4fb0acd8e2eef06e5cdd8dc22ffd924e72cd Mon Sep 17 00:00:00 2001 From: Laurent Le Brun Date: Sun, 15 Jan 2023 00:20:11 +0100 Subject: [PATCH 16/32] Add more real test files - Audio Flight v2 (strobes) by byt3_m3chanic - Controllable Machinery by dr2 - Endeavor by Team210 - Frozen wasteland by Dave Hoskins --- Checker/compression_test.fs | 27 +- tests/commands.txt | 4 + tests/compression_results.log | 29 +- tests/real/audio-flight-v2.frag | 350 +++++++++++ tests/real/audio-flight-v2.frag.expected | 287 +++++++++ tests/real/controllable-machinery.frag | 543 ++++++++++++++++++ .../real/controllable-machinery.frag.expected | 496 ++++++++++++++++ tests/real/endeavour.frag | 234 ++++++++ tests/real/endeavour.frag.expected | 142 +++++ tests/real/frozen-wasteland.frag | 360 ++++++++++++ tests/real/frozen-wasteland.frag.expected | 286 +++++++++ 11 files changed, 2735 insertions(+), 23 deletions(-) create mode 100644 tests/real/audio-flight-v2.frag create mode 100644 tests/real/audio-flight-v2.frag.expected create mode 100644 tests/real/controllable-machinery.frag create mode 100644 tests/real/controllable-machinery.frag.expected create mode 100644 tests/real/endeavour.frag create mode 100644 tests/real/endeavour.frag.expected create mode 100644 tests/real/frozen-wasteland.frag create mode 100644 tests/real/frozen-wasteland.frag.expected diff --git a/Checker/compression_test.fs b/Checker/compression_test.fs index 86439b2e..56230001 100644 --- a/Checker/compression_test.fs +++ b/Checker/compression_test.fs @@ -15,22 +15,27 @@ module Crinkler = let testFiles = [ - "from-the-seas-to-the-stars.frag" - "the_real_party_is_in_your_pocket.frag" + "audio-flight-v2.frag" + "buoy.frag" + "controllable-machinery.frag" "ed-209.frag" - "valley_ball.glsl" - "lunaquatic.frag" - "slisesix.frag" - "yx_long_way_from_home.frag" - "oscars_chair.frag" + "elevated.hlsl" + "endeavour.frag" + "from-the-seas-to-the-stars.frag" + "frozen-wasteland.frag" "kinder_painter.frag" - "ohanami.frag" - "terrarium.frag" "leizex.frag" - "elevated.hlsl" - "buoy.frag" + "lunaquatic.frag" + "mandelbulb.frag" + "ohanami.frag" "orchard.frag" + "oscars_chair.frag" "robin.frag" + "slisesix.frag" + "terrarium.frag" + "the_real_party_is_in_your_pocket.frag" + "valley_ball.glsl" + "yx_long_way_from_home.frag" ] let writer = new StringWriter() diff --git a/tests/commands.txt b/tests/commands.txt index f2e018e1..8fb7f717 100644 --- a/tests/commands.txt +++ b/tests/commands.txt @@ -70,3 +70,7 @@ --no-renaming --format indented -o tests/real/slisesix.frag.expected tests/real/slisesix.frag --no-renaming --format indented -o tests/real/from-the-seas-to-the-stars.frag.expected tests/real/from-the-seas-to-the-stars.frag --no-renaming --format indented -o tests/real/lunaquatic.frag.expected tests/real/lunaquatic.frag +--no-renaming --format indented -o tests/real/frozen-wasteland.frag.expected tests/real/frozen-wasteland.frag +--no-renaming --format indented -o tests/real/controllable-machinery.frag.expected tests/real/controllable-machinery.frag +--no-renaming --format indented -o tests/real/endeavour.frag.expected tests/real/endeavour.frag +--no-renaming --format indented -o tests/real/audio-flight-v2.frag.expected tests/real/audio-flight-v2.frag diff --git a/tests/compression_results.log b/tests/compression_results.log index 94179913..b93ed310 100644 --- a/tests/compression_results.log +++ b/tests/compression_results.log @@ -1,17 +1,22 @@ -from-the-seas-to-the-stars.frag 14305 => 2358.450 -the_real_party_is_in_your_pocket.frag 12196 => 1829.311 +audio-flight-v2.frag 4620 => 919.722 +buoy.frag 4194 => 622.602 +controllable-machinery.frag 7767 => 1230.786 ed-209.frag 7888 => 1361.583 -valley_ball.glsl 4369 => 890.945 -lunaquatic.frag 5218 => 1058.675 -slisesix.frag 4533 => 956.567 -yx_long_way_from_home.frag 2992 => 615.970 -oscars_chair.frag 4626 => 981.611 +elevated.hlsl 3406 => 611.302 +endeavour.frag 2623 => 544.176 +from-the-seas-to-the-stars.frag 14305 => 2358.450 +frozen-wasteland.frag 4588 => 805.076 kinder_painter.frag 2880 => 450.617 -ohanami.frag 3283 => 750.856 -terrarium.frag 3576 => 737.588 leizex.frag 2308 => 515.785 -elevated.hlsl 3406 => 611.302 -buoy.frag 4194 => 622.602 +lunaquatic.frag 5218 => 1058.675 +mandelbulb.frag 2369 => 549.088 +ohanami.frag 3283 => 750.856 orchard.frag 5588 => 1051.886 +oscars_chair.frag 4626 => 981.611 robin.frag 6293 => 1066.421 -Total: 87655 => 15860.170 +slisesix.frag 4533 => 956.567 +terrarium.frag 3576 => 737.588 +the_real_party_is_in_your_pocket.frag 12196 => 1829.311 +valley_ball.glsl 4369 => 890.945 +yx_long_way_from_home.frag 2992 => 615.970 +Total: 109622 => 19909.017 diff --git a/tests/real/audio-flight-v2.frag b/tests/real/audio-flight-v2.frag new file mode 100644 index 00000000..e9a465fa --- /dev/null +++ b/tests/real/audio-flight-v2.frag @@ -0,0 +1,350 @@ +/** + Copied from https://www.shadertoy.com/view/7tfyRl + License: Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License + + AudioFlight 🚀 v2 - music Boris Brejcha - Gravity + 4/14/22 | @byt3_m3chanic + + Path shader based around @Shane's stuff - he has a ton of amazing ones. + https://www.shadertoy.com/view/MlXSWX + + Music EQ based around @blackle's domain rep tricks + + Lots of fo + +*/ + + +#define R iResolution +#define T iTime +#define M iMouse + +#define PI2 6.28318530718 +#define PI 3.14159265358 + +#define MINDIST .0001 +#define MAXDIST 125. + +#define r2(a) mat2(cos(a),sin(a),-sin(a),cos(a)) + +float hash21(vec2 p){ return fract(sin(dot(p, vec2(27.609, 57.583)))*43758.5453); } +float sampleFreq(float freq) { + return texture(iChannel0, vec2(freq, 0.1)).x; +} + +//http://mercury.sexy/hg_sdf/ +float pMod(inout float p, float size) { + float c = floor((p + size*0.5)/size); + p = mod(p + size*0.5, size) - size*0.5; + return c; +} +vec2 pMod(inout vec2 p, float size) { + vec2 c = floor((p + size*0.5)/size); + p = mod(p + size*0.5, size) - size*0.5; + return c; +} +vec3 pMod(inout vec3 p, float size) { + vec3 c = floor((p + size*0.5)/size); + p = mod(p + size*0.5, size) - size*0.5; + return c; +} +float pModPolar(inout vec2 p, float repetitions) { + float angle = 2.*PI/repetitions; + float a = atan(p.y, p.x) + angle/2., + r = length(p), + c = floor(a/angle); + a = mod(a,angle) - angle/2.; + p = vec2(cos(a), sin(a))*r; + if (abs(c) >= (repetitions/2.)) c = abs(c); + return c; +} +float vmax(vec2 v) { return max(v.x, v.y); } +float vmax(vec3 v) { return max(max(v.x, v.y), v.z); } +float fBox(vec3 p, vec3 b) { + vec3 d = abs(p) - b; + return length(max(d, vec3(0))) + vmax(min(d, vec3(0))); +} +float fBox2(vec2 p, vec2 b) { + vec2 d = abs(p) - b; + return length(max(d, vec2(0))) + vmax(min(d, vec2(0))); +} +//@iq +float sdCap( vec3 p, float h, float r ){ + p.y -= clamp( p.y, 0.0, h ); + return length( p ) - r; +} +// @Shane - https://www.shadertoy.com/view/MlXSWX +vec2 path(in float z){ + vec2 p1 =vec2(2.35*sin(z * .125)+2.38*cos(z * .25), 3.5*cos(z * .0945)); + vec2 p2 =vec2(3.2*sin(z * .19), 4.31*sin(z * .125)-2.38*cos(z * .115)); + return (p1 - p2)*.3; +} + +// globals +float time,tm,travelSpeed; + +// globals and stuff +float glow,iqd,flight,beams,gcolor,objglow,offWobble,boxsize; +float ga,sa,slp; +vec3 g_hp,s_hp; +mat2 r4,r5; + +const vec3 cxz = vec3(3.15,4.75,3.); +const float scale = 3.0; + +vec2 fragtail(vec3 pos) { + float ss=1.15; + float r = 1e5; + + for (int i = 0;i<2;i++) { + pos=abs(pos); + if ( pos.x- pos.y<0.) pos.yx = pos.xy; + if ( pos.x- pos.z<0.) pos.zx = pos.xz; + if ( pos.y- pos.z<0.) pos.zy = pos.yz; + + pos.x=scale * pos.x-cxz.x*(scale-1.); + pos.y=scale * pos.y-cxz.y*(scale-1.); + pos.z=scale * pos.z; + + if (pos.z>0.5*cxz.z*(scale-1.)) pos.z-=cxz.z*(scale-1.); + + r = fBox2(pos.xy,vec2(5,1.5+.25*sin(pos.x*5.)))-.0015; + ss*=1./scale; + } + + return vec2(r*ss,1.); +} + +//@blackle domain rep https://www.shadertoy.com/view/Wl3fD2 +vec2 edge(vec2 p) { + vec2 p2 = abs(p); + if (p2.x > p2.y) return vec2((p.x < 0.) ? -1. : 1., 0.); + else return vec2(0., (p.y < 0.) ? -1. : 1.); +} +float ths= 13.25; +// scene map +vec2 map (in vec3 p, float sg) { + + vec2 res = vec2(100.,-1.); + float msize = 7.25; + + // set path(s) vector(s) + vec2 tun = p.xy - path(p.z); + vec3 q = vec3(tun,p.z); + vec3 o = vec3(tun+vec2(0.,.0),p.z+travelSpeed+4.25); + + vec3 s = q; + + o.zx*=r5; + o.yz*=r4; + o = abs(o)-(offWobble*.25); + float obj = fBox(o,vec3(.15*offWobble))-.015; + if(objMAXDIST)break; + d += i<42? t.x*.35 : t.x; + m = t.y; + } + return vec2(d,m); +} + +vec3 normal(vec3 p, float t) { + float e = MINDIST*t; + vec2 h = vec2(1,-1)*.5773; + return normalize( + h.xyy*map( p + h.xyy*e,0.).x + + h.yyx*map( p + h.yyx*e,0.).x + + h.yxy*map( p + h.yxy*e,0.).x + + h.xxx*map( p + h.xxx*e,0.).x ); +} + +//iq of hsv2rgb +vec3 hsv2rgb( in vec3 c ) { + vec3 rgb = clamp( abs(mod(c.x*6.0+vec3(0.0,4.0,2.0),6.0)-3.0)-1.0, 0.0, 1.0 ); + return c.z * mix( vec3(1.0), rgb, c.y); +} + +void mainImage( out vec4 O, in vec2 F ) { + // precal + time = iTime; + tm = mod(time*.3, 18.); + travelSpeed = (time * 5.); + + offWobble = 1.5+1.15*sin(tm+time*.1); + + r4 =r2(time); + r5 =r2(time); + + // pixel screen coordinates + vec2 uv = (F.xy - R.xy*0.5)/max(R.x,R.y); + vec3 C = vec3(0.), + FC = vec3(.03); + + float crop = clamp((-.05)+(T*.05),0.,.18); + if(uv.y-crop){ + vec3 lp = vec3(0.,0.,0.-travelSpeed); + vec3 ro = vec3(0.,0,.15); + + // mouse + float x = M.xy==vec2(0) || M.z<0. ? 0.:(M.y/R.y*1.-.5)*PI; + float y = M.xy==vec2(0) || M.z<0. ? 0.:-(M.x/R.x*2.-1.)*PI; + + ro.zy*=r2(x); + + ro +=lp; + + lp.xy += path(lp.z); + ro.xy += path(ro.z); + + // set camera + vec3 f=normalize(lp-ro), + r=normalize(cross(vec3(0,1,0),f)), + u=normalize(cross(f,r)), + c=ro+f*.183, + i=c+uv.x*r+uv.y*u, + rd=i-ro; + + // center tracking + rd.xy = r2( (.2*sin(time*.3))-path(lp.z).x/ 24. )*rd.xy; + rd.xz = r2( y-path(lp.z+1.).y/ 14. )*rd.xz; + + // march + vec2 t = marcher(ro,rd, 164,1.); + float d = t.x, + m = t.y; + s_hp=g_hp; + + // if visible + if(dths) { + C =(h * diff + spec); + } else { + if(m==3.||m==4.) C =(hsv2rgb(vec3(s_hp.z*.01,.8,.6)) * diff); + } + + } + + if(tm>ths) { + if(mod(T,.1)<.05)FC=vec3(.8); + }else{ + + C += abs(glow*.7)*hsv2rgb(vec3(s_hp.z*.01,.8,.6)); + C += abs(objglow*.65)*vec3(1,1,1); + } + C = mix( C, FC, 1.-exp(-0.000075*t.x*t.x*t.x)); + C += abs(beams*.65)*hsv2rgb(vec3(s_hp.z*.025,.8,.6)); + C += abs(flight*.75)*vec3(.5,1,.2); + } + + + float px = 1./R.x; + + + float d1 = fBox2(uv+vec2(-.485,.2675),vec2(.005))-.002; + d1=smoothstep(px,-px,d1); + C=mix(C,vec3(0.212,0.671,0.576),d1); + + d1 = fBox2(uv+vec2(-.465,.2675),vec2(.005))-.002; + d1=smoothstep(px,-px,d1); + C=mix(C,vec3(0.757,0.686,0.341),d1); + + d1 = fBox2(uv+vec2(-.445,.2675),vec2(.005))-.002; + d1=smoothstep(px,-px,d1); + C=mix(C,vec3(0.882,0.459,0.867),d1); + + C=pow(C, vec3(0.4545)); + O = vec4(C,1.0); +} diff --git a/tests/real/audio-flight-v2.frag.expected b/tests/real/audio-flight-v2.frag.expected new file mode 100644 index 00000000..6133448d --- /dev/null +++ b/tests/real/audio-flight-v2.frag.expected @@ -0,0 +1,287 @@ +#define R iResolution + +#define T iTime + +#define M iMouse + +#define PI2 6.28318530718 + +#define PI 3.14159265358 + +#define MINDIST.0001 + +#define MAXDIST 125. + +#define r2(a)mat2(cos(a),sin(a),-sin(a),cos(a)) + +float sampleFreq(float freq) +{ + return texture(iChannel0,vec2(freq,.1)).x; +} +float pMod(inout float p,float size) +{ + float c=floor((p+size*.5)/size); + p=mod(p+size*.5,size)-size*.5; + return c; +} +vec2 pMod(inout vec2 p,float size) +{ + vec2 c=floor((p+size*.5)/size); + p=mod(p+size*.5,size)-size*.5; + return c; +} +vec3 pMod(inout vec3 p,float size) +{ + vec3 c=floor((p+size*.5)/size); + p=mod(p+size*.5,size)-size*.5; + return c; +} +float pModPolar(inout vec2 p,float repetitions) +{ + float angle=2.*PI/repetitions,a=atan(p.y,p.x)+angle/2.,r=length(p),c=floor(a/angle); + a=mod(a,angle)-angle/2.; + p=vec2(cos(a),sin(a))*r; + if(abs(c)>=repetitions/2.) + c=abs(c); + return c; +} +float vmax(vec2 v) +{ + return max(v.x,v.y); +} +float vmax(vec3 v) +{ + return max(max(v.x,v.y),v.z); +} +float fBox(vec3 p,vec3 b) +{ + vec3 d=abs(p)-b; + return length(max(d,vec3(0)))+vmax(min(d,vec3(0))); +} +float fBox2(vec2 p,vec2 b) +{ + vec2 d=abs(p)-b; + return length(max(d,vec2(0)))+vmax(min(d,vec2(0))); +} +float sdCap(vec3 p,float h,float r) +{ + p.y-=clamp(p.y,0.,h); + return length(p)-r; +} +vec2 path(float z) +{ + vec2 p1=vec2(2.35*sin(z*.125)+2.38*cos(z*.25),3.5*cos(z*.0945)),p2=vec2(3.2*sin(z*.19),4.31*sin(z*.125)-2.38*cos(z*.115)); + return(p1-p2)*.3; +} +float time,tm,travelSpeed,glow,iqd,flight,beams,gcolor,objglow,offWobble,boxsize,ga,sa,slp; +vec3 g_hp,s_hp; +mat2 r4,r5; +const vec3 cxz=vec3(3.15,4.75,3); +vec2 fragtail(vec3 pos) +{ + float ss=1.15,r=1e5; + for(int i=0;i<2;i++) + { + pos=abs(pos); + if(pos.x-pos.y<0.) + pos.yx=pos.xy; + if(pos.x-pos.z<0.) + pos.zx=pos.xz; + if(pos.y-pos.z<0.) + pos.zy=pos.yz; + pos.x=3.*pos.x-cxz.x*2.; + pos.y=3.*pos.y-cxz.y*2.; + pos.z=3.*pos.z; + if(pos.z>.5*cxz.z*2.) + pos.z-=cxz.z*2.; + r=fBox2(pos.xy,vec2(5,1.5+.25*sin(pos.x*5.)))-.0015; + ss*=1./3.; + } + return vec2(r*ss,1); +} +vec2 edge(vec2 p) +{ + vec2 p2=abs(p); + return p2.x>p2.y? + vec2(p.x<0.? + -1.: + 1.,0): + vec2(0,p.y<0.? + -1.: + 1.); +} +float ths=13.25; +vec2 map(vec3 p,float sg) +{ + vec2 res=vec2(100,-1),tun,center,neighbour,d1; + float msize=7.25,obj,pid,trackmod,deg,chs,bmod,height,ids,lq,zprs,d4a,d4,blt,me,next,dlt; + tun=p.xy-path(p.z); + vec3 q=vec3(tun,p.z),o=vec3(tun+vec2(0),p.z+travelSpeed+4.25),s=q,r,fs,qid; + o.zx*=r5; + o.yz*=r4; + o=abs(o)-offWobble*.25; + obj=fBox(o,vec3(.15*offWobble))-.015; + if(objMAXDIST) + break; + d+=i<42? + t.x*.35: + t.x; + m=t.y; + } + return vec2(d,m); +} +vec3 normal(vec3 p,float t) +{ + float e=MINDIST*t; + vec2 h=vec2(1,-1)*.5773; + return normalize(h.xyy*map(p+h.xyy*e,0.).x+h.yyx*map(p+h.yyx*e,0.).x+h.yxy*map(p+h.yxy*e,0.).x+h.xxx*map(p+h.xxx*e,0.).x); +} +vec3 hsv2rgb(vec3 c) +{ + vec3 rgb=clamp(abs(mod(c.x*6.+vec3(0,4,2),6.)-3.)-1.,0.,1.); + return c.z*mix(vec3(1),rgb,c.y); +} +void mainImage(out vec4 O,vec2 F) +{ + time=iTime; + tm=mod(time*.3,18.); + travelSpeed=time*5.; + offWobble=1.5+1.15*sin(tm+time*.1); + r4=r2(time); + r5=r2(time); + vec2 uv=(F.xy-R.xy*.5)/max(R.x,R.y); + vec3 C=vec3(0),FC=vec3(.03); + float crop=clamp(-.05+T*.05,0.,.18),px,d1; + if(uv.y-crop) + { + vec3 lp=vec3(0,0,-travelSpeed),ro=vec3(0,0,.15),f,r,u,c,i,rd; + float x=M.xy==vec2(0)||M.z<0.? + 0.: + (M.y/R.y-.5)*PI,y=M.xy==vec2(0)||M.z<0.? + 0.: + -(M.x/R.x*2.-1.)*PI,d,m; + ro.zy*=r2(x); + ro+=lp; + lp.xy+=path(lp.z); + ro.xy+=path(ro.z); + f=normalize(lp-ro); + r=normalize(cross(vec3(0,1,0),f)); + u=normalize(cross(f,r)); + c=ro+f*.183; + i=c+uv.x*r+uv.y*u; + rd=i-ro; + rd.xy=r2(.2*sin(time*.3)-path(lp.z).x/24.)*rd.xy; + rd.xz=r2(y-path(lp.z+1.).y/14.)*rd.xz; + vec2 t=marcher(ro,rd,164,1.); + d=t.x; + m=t.y; + s_hp=g_hp; + if(dths) + C=h*diff+spec; + else + if(m==3.||m==4.) + C=hsv2rgb(vec3(s_hp.z*.01,.8,.6))*diff; + } + if(tm>ths) + { + if(mod(T,.1)<.05) + FC=vec3(.8); + } + else + C+=abs(glow*.7)*hsv2rgb(vec3(s_hp.z*.01,.8,.6)),C+=abs(objglow*.65)*vec3(1); + C=mix(C,FC,1.-exp(-7.5e-5*t.x*t.x*t.x)); + C+=abs(beams*.65)*hsv2rgb(vec3(s_hp.z*.025,.8,.6)); + C+=abs(flight*.75)*vec3(.5,1,.2); + } + px=1./R.x; + d1=fBox2(uv+vec2(-.485,.2675),vec2(.005))-.002; + d1=smoothstep(px,-px,d1); + C=mix(C,vec3(.212,.671,.576),d1); + d1=fBox2(uv+vec2(-.465,.2675),vec2(.005))-.002; + d1=smoothstep(px,-px,d1); + C=mix(C,vec3(.757,.686,.341),d1); + d1=fBox2(uv+vec2(-.445,.2675),vec2(.005))-.002; + d1=smoothstep(px,-px,d1); + C=mix(C,vec3(.882,.459,.867),d1); + C=pow(C,vec3(.4545)); + O=vec4(C,1); +} diff --git a/tests/real/controllable-machinery.frag b/tests/real/controllable-machinery.frag new file mode 100644 index 00000000..1f38e68e --- /dev/null +++ b/tests/real/controllable-machinery.frag @@ -0,0 +1,543 @@ +// Copied from https://www.shadertoy.com/view/fsXyDj +// "Controllable Machinery" by dr2 - 2022 +// License: Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License + +// (Extension of "Machinery"; control widget in world space - as in "Maze Ball Solved 2") + +#define AA 0 // (= 0/1) optional antialiasing + +#if 0 +#define VAR_ZERO min (iFrame, 0) +#else +#define VAR_ZERO 0 +#endif + +float PrBoxDf (vec3 p, vec3 b); +float PrRoundBoxDf (vec3 p, vec3 b, float r); +float PrCylDf (vec3 p, float r, float h); +float PrRoundCylDf (vec3 p, float r, float rt, float h); +float PrCaps2Df (vec2 p, float r, float h); +float Minv3 (vec3 p); +float Maxv3 (vec3 p); +float Minv2 (vec2 p); +float Maxv2 (vec2 p); +float SmoothMax (float a, float b, float r); +float SmoothBump (float lo, float hi, float w, float x); +vec2 Rot2D (vec2 q, float a); +mat3 StdVuMat (float el, float az); +vec3 HsvToRgb (vec3 c); +vec4 Loadv4 (int idVar); + +vec4 wgObj; +vec3 ltDir, vnBlk; +vec2 qBlk; +float dstFar, tCur, tMov, angRot, bEdge, tCyc, cnPos, hitBlk; +int idObj; +const int idGr = 1, idPln = 2, idConv = 3, idSup = 4, idAx = 5, idBas = 6, + idWhl = 7, idSpl = 8, idCon = 9, idBlk = 10; +const float pi = 3.1415927; +const float nBlk = 13.; + +#define DMIN(id) if (d < dMin) { dMin = d; idObj = id; } + +float GearWlDf (vec3 p, float rad, float wlThk, float tWid, float nt, float aRot, + bool bev, float dMin) +{ + vec3 q; + float d, s; + q = p; + d = max (length (q.xy) - rad, abs (q.z) - wlThk); + if (d < dMin) { + q.xy = Rot2D (q.xy, aRot); + q.xy = Rot2D (q.xy, floor (nt * atan (q.y, - q.x) / (2. * pi) + 0.5) * 2. * pi / nt); + if (bev) q.xy *= 1.2 - 0.2 * q.z / wlThk; + s = q.x - 2. * clamp (1.5 * tWid + 0.5 * q.x * step (0., q.x) - abs (q.y), 0., tWid); + d = max (d, - rad - 0.95 * s); + } + return min (dMin, d); +} + +vec4 BPos (float t) +{ + vec3 p; + float a; + t = mod (t, tCyc); + if (t < 5.) { + a = 0.; + p = vec3 (-1.018 + 2.118 * t / 5., bEdge, 0.); + } else if (t < 10.) { + a = 0.5 * pi * (t - 5.) / 5.; + p = vec3 (1.1, bEdge + 1. * sin (a), 1. - 1. * cos (a)); + } else if ( t < 15.) { + a = 0.5 * pi; + p = vec3 (1.1 - 2.118 * (t - 10.) / 5., 1. + bEdge, 1.); + } else if (t < 17.5) { + a = 0.5 * pi; + p = vec3 (-1.018, 1. + bEdge, 1. - 1. * (t - 15.) / 2.5); + } else { + t -= 17.5; + a = -0.5 * pi * t; + p = vec3 (-1.018, 1. + bEdge - t * t, 0.); + } + return vec4 (p, a); +} + +float GearDf (vec3 p) +{ + vec3 q; + float dMin, wlThk, tWid, nt, rad, gRat; + dMin = dstFar / 0.3; + gRat = 2.; + rad = 0.3; + wlThk = rad / 7.; + tWid = rad / 10.; + nt = 20.; + q = p - vec3 (-1.05, -0.21, 1.3); + dMin = GearWlDf (- q, rad, wlThk, tWid, nt, angRot * gRat, true, dMin); + dMin = GearWlDf ((q - vec3 (0.85 * rad, 0., 0.85 * rad)).yzx, + rad, wlThk, tWid, nt, angRot * gRat + pi / nt, true, dMin); + rad = 0.43; + wlThk = rad / 15.; + tWid = rad / 16.; + nt = 32.; + q = p -vec3 (0.1, 0., 1.); + dMin = GearWlDf ((q - vec3 (0., bEdge, 0.)).yzx, rad, wlThk, tWid, nt, + - angRot - 0.3 * pi / nt, false, dMin); + dMin = GearWlDf (- (q - vec3 (0., -0.21, 0.555)).zyx, rad / gRat, wlThk, tWid, + nt / gRat, - angRot * gRat, false, dMin); + rad = 0.32; + wlThk = rad / 15.; + tWid = rad / 12.; + nt = 24.; + q = p - vec3 (-1.05, -0.21, 0.6); + dMin = GearWlDf ((q - vec3 (0., 0., 0.1)), rad, wlThk, tWid, nt, + angRot * gRat + pi / nt, false, dMin); + dMin = GearWlDf ((q - vec3 (0., -0.47, 0.1)), rad / gRat, wlThk, tWid, nt / gRat, + - angRot * gRat * gRat, false, dMin); + dMin = GearWlDf ((q - vec3 (0., -0.47, -0.1)), rad, wlThk, tWid, nt, + - angRot * gRat * gRat - pi / nt, false, dMin); + dMin = GearWlDf ((q - vec3 (0., 0., -0.1)), rad / gRat, wlThk, tWid, nt / gRat, + angRot * gRat * gRat * gRat, false, dMin); + return dMin * 0.3; +} + +float ObjDf (vec3 p) +{ + vec4 a4; + vec3 q, bPos; + float dMin, d, r, a; + dMin = dstFar; + q = p - vec3 (1.13 + bEdge, bEdge, 1.); + r = length (q.yz); + q.yz = Rot2D (q.yz, - angRot); + a = (r > 0.) ? atan (q.z, - q.y) / (2. * pi) : 0.; + q.yz = Rot2D (q.yz, 2. * pi * (floor (8. * a + 0.5)) / 8.); + q.z = abs (q.z); + d = SmoothMax (min (min (abs (r - 1.01) - 0.1, r - 0.3), + max (r - 1., dot (q.yz, vec2 (sin (0.8 * 2. * pi / 32.), + cos (0.8 * 2. * pi / 32.))))), abs (q.x) - 0.02, 0.01); + DMIN (idWhl); + d = min (PrBoxDf (p - vec3 (0., 0.98, 1.), vec3 (1.12, 0.02, 0.1)), + PrBoxDf (p - vec3 (-1.018, 0.98, 0.5), vec3 (0.1, 0.02, 0.5 - bEdge))); + DMIN (idPln); + d = SmoothMax (abs (PrCaps2Df ((p - vec3 (-0.05, -0.21, 0.)).yx, 0.2, 1.)) - 0.01, + abs (p.z) - 0.1, 0.02); + DMIN (idConv); + q = p - vec3 (-0.05, -0.21, 0.); + q.x = abs (q.x) - 1.; + d = PrRoundCylDf (q, 0.18, 0.01, 0.11); + DMIN (idSpl); + q = p - vec3 (0.65, -0.14, 1.); + q.x = abs (q.x) - 0.3; + d = PrRoundBoxDf (q, vec3 (0.01, 1.08, 0.06), 0.02); + q = p - vec3 (-0.05, -0.68, 0.); + q.xz = abs (q.xz) - vec2 (1., 0.2); + d = min (d, PrRoundBoxDf (q, vec3 (0.04, 0.55, 0.01), 0.02)); + q = p - vec3 (-1.05, -0.14, 1.); + d = min (d, PrRoundBoxDf (q, vec3 (0.04, 1.08, 0.01), 0.02)); + q = p - vec3 (-1.05, -0.68, 0.6); + q.z = abs (q.z) - 0.2; + d = min (d, PrRoundBoxDf (q, vec3 (0.04, 0.55, 0.01), 0.02)); + q = p - vec3 (-0.33, -0.68, 1.555); + q.x = abs (q.x) - 0.3; + d = min (d, PrRoundBoxDf (q, vec3 (0.01, 0.55, 0.04), 0.02)); + DMIN (idSup); + q = p - vec3 (0.65, bEdge, 1.); + d = PrCylDf (q.yzx, 0.04, 0.62); + q = p - vec3 (-0.36, -0.21, 1.555); + d = min (d, PrCylDf (q.yzx, 0.03, 0.51)); + q = p - vec3 (-0.05, -0.21, 0.); + q.x -= 1.; + d = min (d, PrCylDf (q, 0.03, 0.27)); + q.xz -= vec2 (-2., 0.14); + d = min (d, PrCylDf (q, 0.03, 0.4)); + q.z -= 0.87; + d = min (d, PrCylDf (q, 0.03, 0.36)); + q = p - vec3 (-1.05, -0.68, 0.6); + d = min (d, PrCylDf (q, 0.03, 0.25)); + DMIN (idAx); + q = p - vec3 (0., -1.2, 0.9); + d = PrRoundBoxDf (q, vec3 (1.7, 0.03, 1.5), 0.02); + DMIN (idBas); + q = p - wgObj.xyz; + d = PrRoundCylDf (q.xzy, wgObj.w, 0.02, 0.02); + DMIN (idCon); + return dMin; +} + +float ObjRay (vec3 ro, vec3 rd) +{ + float dHit, d; + dHit = 0.; + for (int j = VAR_ZERO; j < 150; j ++) { + d = ObjDf (ro + dHit * rd); + dHit += d; + if (d < 0.0005 || dHit > dstFar) break; + } + return dHit; +} + +float GearRay (vec3 ro, vec3 rd) +{ + float dHit, d; + dHit = 0.; + for (int j = VAR_ZERO; j < 250; j ++) { + d = GearDf (ro + dHit * rd); + dHit += d; + if (d < 0.0005 || dHit > dstFar) break; + } + return dHit; +} + +vec3 GearNf (vec3 p) +{ + vec4 v; + vec2 e; + e = vec2 (0.0005, -0.0005); + for (int j = VAR_ZERO; j < 4; j ++) { + v[j] = GearDf (p + ((j < 2) ? ((j == 0) ? e.xxx : e.xyy) : ((j == 2) ? e.yxy : e.yyx))); + } + v.x = - v.x; + return normalize (2. * v.yzw - dot (v, vec4 (1.))); +} + +vec3 ObjNf (vec3 p) +{ + vec4 v; + vec2 e; + e = vec2 (0.0005, -0.0005); + for (int j = VAR_ZERO; j < 4; j ++) { + v[j] = ObjDf (p + ((j < 2) ? ((j == 0) ? e.xxx : e.xyy) : ((j == 2) ? e.yxy : e.yyx))); + } + v.x = - v.x; + return normalize (2. * v.yzw - dot (v, vec4 (1.))); +} + +float BlkHit (vec3 ro, vec3 rd) +{ + vec4 a4; + vec3 rm, rdm, u, v, tm, tp; + float dMin, dn, df; + dMin = dstFar; + for (float k = float (VAR_ZERO); k < nBlk; k ++) { + a4 = BPos (tMov + tCyc * k / nBlk); + rm = ro - a4.xyz; + rdm = rd; + rm.zy = Rot2D (rm.zy, a4.w); + rdm.zy = Rot2D (rdm.zy, a4.w); + v = rm / rdm; + tp = bEdge / abs (rdm) - v; + tm = - tp - 2. * v; + dn = Maxv3 (tm); + df = Minv3 (tp); + if (df > 0. && dn < min (df, dMin)) { + dMin = dn; + hitBlk = k; + vnBlk = - sign (rdm) * step (tm.zxy, tm) * step (tm.yzx, tm); + u = (v + dn) * rdm; + qBlk = vec2 (dot (u.zxy, vnBlk), dot (u.yzx, vnBlk)); + vnBlk.zy = Rot2D (vnBlk.zy, - a4.w); + } + } + return dMin; +} + +float BlkHitSh (vec3 ro, vec3 rd, float rng) +{ + vec4 a4; + vec3 rm, rdm, v, tm, tp; + float dMin, dn, df; + dMin = dstFar; + for (float k = float (VAR_ZERO); k < nBlk; k ++) { + a4 = BPos (tMov + tCyc * k / nBlk); + rm = ro - a4.xyz; + rdm = rd; + rm.zy = Rot2D (rm.zy, a4.w); + rdm.zy = Rot2D (rdm.zy, a4.w); + v = rm / rdm; + tp = bEdge / abs (rdm) - v; + tm = - tp - 2. * v; + dn = Maxv3 (tm); + df = Minv3 (tp); + if (df > 0. && dn < min (df, dMin)) dMin = dn; + } + return smoothstep (0., rng, dMin); +} + +float ObjSShadow (vec3 ro, vec3 rd) +{ + float sh, d, h; + sh = 1.; + d = 0.02; + for (int j = VAR_ZERO; j < 30; j ++) { + h = ObjDf (ro + rd * d); + sh = min (sh, smoothstep (0., 0.05 * d, h)); + d += h; + if (sh < 0.05) break; + } + return sh; +} + +float GearSShadow (vec3 ro, vec3 rd) +{ + float sh, d, h; + sh = 1.; + d = 0.02; + for (int j = VAR_ZERO; j < 30; j ++) { + h = GearDf (ro + rd * d); + sh = min (sh, smoothstep (0., 0.05 * d, h)); + d += h; + if (sh < 0.05) break; + } + return sh; +} + +vec3 ShowScene (vec3 ro, vec3 rd) +{ + vec4 col4; + vec3 vn, col, q; + float dstObj, dstGear, dstBlk, sh, s, r, a, nDotL; + int idObjT; + bool isMet; + tCyc = 18.5; + bEdge = 0.08; + isMet = false; + angRot = 0.1 * pi * tMov; + dstObj = ObjRay (ro, rd); + idObjT = idObj; + dstGear = GearRay (ro, rd); + if (dstGear < min (dstObj, dstFar)) { + dstObj = dstGear; + idObj = idGr; + } else idObj = idObjT; + dstBlk = BlkHit (ro, rd); + if (min (dstBlk, dstObj) < dstFar) { + if (dstBlk < dstObj) { + dstObj = dstBlk; + ro += dstObj * rd; + idObj = idBlk; + vn = vnBlk; + col4 = vec4 (HsvToRgb (vec3 (hitBlk / nBlk, 1., 1.)), 0.2) * + (1. - 0.4 * step (0.8 * bEdge, Maxv2 (abs (qBlk)))); + } else { + ro += dstObj * rd; + vn = (idObj == idGr) ? GearNf (ro) : ObjNf (ro); + if (idObj == idWhl) { + col4 = vec4 (0.9, 0.7, 0.3, 0.2); + q = ro - vec3 (1.1 + bEdge + 0.03, bEdge, 1.); + r = length (q.yz); + q.yz = Rot2D (q.yz, - angRot); + a = fract (64. * atan (q.z, - q.y) / (2. * pi) + 0.5); + if (r > 0.99) vn.yz = Rot2D (vn.yz, - sin (a - 0.5)); + if (r > 0.92) col4 *= 0.7 + 0.3 * SmoothBump (0.05, 0.95, 0.01, a); + isMet = true; + } else if (idObj == idGr) { + col4 = vec4 (0.9, 0.8, 0.4, 0.2); + isMet = true; + } else if (idObj == idSpl) { + col4 = vec4 (0.8, 0.8, 0.85, 0.2) * (1. - 0.4 * step (abs (ro.z), 0.1)); + isMet = true; + } else if (idObj == idAx) { + col4 = vec4 (0.8, 0.8, 0.85, 0.2); + isMet = true; + } else if (idObj == idPln) { + col4 = (abs (vn.y) > 0.99) ? vec4 (0.5, 0.6, 0.2, 0.05) : vec4 (0.7, 0.5, 0.4, 0.1); + } else if (idObj == idConv) { + q = ro - vec3 (-0.05, -0.21, 0.); + col4 = vec4 (0.8, 0.8, 0.4, 0.); + if (sign (vn.y) != sign (q.y)) { + if (abs (q.x) < 1. && abs (vn.y) > 0.5) col4 *= 1. - 0.1 * SmoothBump (0.45, 0.55, 0.03, + fract (10. * (q.x - sign (q.y) * mod (tMov, 20.) * 2.1 / 5.))); + } else col4 *= 0.8 + 0.2 * smoothstep (0., 0.01, abs (abs (q.z) - 0.07)); + } else if (idObj == idSup) { + col4 = vec4 (0.7, 0.5, 0.4, 0.1); + isMet = true; + } else if (idObj == idBas) { + q = ro; + q.z -= 0.9; + if (Maxv2 (abs (q.xz) - vec2 (1.65, 1.45)) > 0.) { + col4 = vec4 (0.9, 0.9, 0.9, 0.2); + isMet = true; + } else { + col4 = vec4 (0.3, 0.5, 0.4, 0.); + } + col4 *= (0.5 + 0.5 * step (0., Maxv2 (abs (vec2 (q.x, q.z + 1.3)) - vec2 (0.4, 0.02)))) * + (0.7 + 0.3 * step (0., abs (PrCaps2Df (vec2 (q.z + 1.3, q.x), 0.08, 0.5)) - 0.01)); + } else if (idObj == idCon) { + col4 = vec4 (0., 1., 1., 0.2); + if (length (ro.xz - wgObj.xz) < 0.6 * wgObj.w) + col4 = mix (0.8 * col4, vec4 (1., 0., 1., 0.2), step (0., sin (2. * pi * tCur))); + } + } + sh = min (ObjSShadow (ro, ltDir), GearSShadow (ro, ltDir)); + sh = 0.6 + 0.4 * min (sh, BlkHitSh (ro + 0.01 * ltDir, ltDir, 6.)); + nDotL = max (dot (vn, ltDir), 0.); + if (isMet) nDotL *= nDotL; + col = col4.rgb * (0.1 + 0.1 * max (- dot (vn, ltDir), 0.) + 0.9 * sh * nDotL) + + col4.a * step (0.95, sh) * sh * pow (max (0., dot (ltDir, reflect (rd, vn))), 32.); + if (isMet) { + rd = reflect (rd, vn); + col = mix (col, vec3 (1.), 0.01 * step (0.1, Minv2 (fract (8. * vec2 (atan (rd.z, rd.x), + 2. * asin (rd.y)) + 0.5) - 0.5))); + } + } else col = vec3 (0., 0., 0.1) * (1. + 0.9 * rd.y); + return clamp (col, 0., 1.); +} + +void mainImage (out vec4 fragColor, in vec2 fragCoord) +{ + mat3 vuMat; + vec4 stDat; + vec3 ro, rd, col; + vec2 canvas, uv; + float el, az, zmFac, sr; + canvas = iResolution.xy; + uv = 2. * fragCoord.xy / canvas - 1.; + uv.x *= canvas.x / canvas.y; + tCur = iTime; + dstFar = 30.; + stDat = Loadv4 (0); + tMov = stDat.x; + cnPos = stDat.y; + wgObj = vec4 (cnPos - 0.5, -1.12, -0.4, 0.08); + stDat = Loadv4 (1); + az = stDat.x; + el = stDat.y; + vuMat = StdVuMat (el, az); + zmFac = 4.; + ro = vuMat * vec3 (0., 0., -8.); + ro.z += 0.9; + rd = vuMat * normalize (vec3 (uv, zmFac)); + ltDir = vuMat * normalize (vec3 (-0.5, 1., -1.)); +#if ! AA + const float naa = 1.; +#else + const float naa = 3.; +#endif + col = vec3 (0.); + sr = 2. * mod (dot (mod (floor (0.5 * (uv + 1.) * canvas), 2.), vec2 (1.)), 2.) - 1.; + for (float a = float (VAR_ZERO); a < naa; a ++) { + rd = vuMat * normalize (vec3 (uv + step (1.5, naa) * Rot2D (vec2 (0.5 / canvas.y, 0.), + sr * (0.667 * a + 0.5) * pi), zmFac)); + col += (1. / naa) * ShowScene (ro, rd); + } + fragColor = vec4 (col, 1.); +} + +float PrBoxDf (vec3 p, vec3 b) +{ + vec3 d; + d = abs (p) - b; + return min (max (d.x, max (d.y, d.z)), 0.) + length (max (d, 0.)); +} + +float PrRoundBoxDf (vec3 p, vec3 b, float r) +{ + return length (max (abs (p) - b, 0.)) - r; +} + +float PrCylDf (vec3 p, float r, float h) +{ + return max (length (p.xy) - r, abs (p.z) - h); +} + +float PrRoundCylDf (vec3 p, float r, float rt, float h) +{ + return length (max (vec2 (length (p.xy) - r, abs (p.z) - h), 0.)) - rt; +} + +float PrCaps2Df (vec2 p, float r, float h) +{ + return length (p - vec2 (0., clamp (p.y, - h, h))) - r; +} + +float Minv3 (vec3 p) +{ + return min (p.x, min (p.y, p.z)); +} + +float Maxv3 (vec3 p) +{ + return max (p.x, max (p.y, p.z)); +} + +float Minv2 (vec2 p) +{ + return min (p.x, p.y); +} + +float Maxv2 (vec2 p) +{ + return max (p.x, p.y); +} + +float SmoothMin (float a, float b, float r) +{ + float h; + h = clamp (0.5 + 0.5 * (b - a) / r, 0., 1.); + return mix (b - h * r, a, h); +} + +float SmoothMax (float a, float b, float r) +{ + return - SmoothMin (- a, - b, r); +} + +float SmoothBump (float lo, float hi, float w, float x) +{ + return (1. - smoothstep (hi - w, hi + w, x)) * smoothstep (lo - w, lo + w, x); +} + +mat3 StdVuMat (float el, float az) +{ + vec2 ori, ca, sa; + ori = vec2 (el, az); + ca = cos (ori); + sa = sin (ori); + return mat3 (ca.y, 0., - sa.y, 0., 1., 0., sa.y, 0., ca.y) * + mat3 (1., 0., 0., 0., ca.x, - sa.x, 0., sa.x, ca.x); +} + +vec2 Rot2D (vec2 q, float a) +{ + vec2 cs; + cs = sin (a + vec2 (0.5 * pi, 0.)); + return vec2 (dot (q, vec2 (cs.x, - cs.y)), dot (q.yx, cs)); +} + +vec3 HsvToRgb (vec3 c) +{ + return c.z * mix (vec3 (1.), clamp (abs (fract (c.xxx + vec3 (1., 2./3., 1./3.)) * 6. - 3.) - 1., 0., 1.), c.y); +} + +#define txBuf iChannel0 +#define txSize iChannelResolution[0].xy + +const float txRow = 128.; + +vec4 Loadv4 (int idVar) +{ + float fi; + fi = float (idVar); + return texture (txBuf, (vec2 (mod (fi, txRow), floor (fi / txRow)) + 0.5) / txSize); +} diff --git a/tests/real/controllable-machinery.frag.expected b/tests/real/controllable-machinery.frag.expected new file mode 100644 index 00000000..f0abc15b --- /dev/null +++ b/tests/real/controllable-machinery.frag.expected @@ -0,0 +1,496 @@ +#define AA 0 + +#if 0 + +#define VAR_ZERO min (iFrame,0) + +#else + +#define VAR_ZERO 0 + +#endif + +vec4 wgObj; +vec3 ltDir,vnBlk; +vec2 qBlk; +float dstFar,tCur,tMov,angRot,bEdge,tCyc,cnPos,hitBlk; +int idObj; + +#define DMIN(id)if (d0.? + atan(q.z,-q.y)/6.2831854: + 0.; + q.yz=Rot2D(q.yz,6.2831854*floor(8.*a+.5)/8.); + q.z=abs(q.z); + d=SmoothMax(min(min(abs(r-1.01)-.1,r-.3),max(r-1.,dot(q.yz,vec2(sin(.157079635),cos(.157079635))))),abs(q.x)-.02,.01); + DMIN(7); + d=min(PrBoxDf(p-vec3(0,.98,1),vec3(1.12,.02,.1)),PrBoxDf(p-vec3(-1.018,.98,.5),vec3(.1,.02,.5-bEdge))); + DMIN(2); + d=SmoothMax(abs(PrCaps2Df((p-vec3(-.05,-.21,0)).yx,.2,1.))-.01,abs(p.z)-.1,.02); + DMIN(3); + q=p-vec3(-.05,-.21,0); + q.x=abs(q.x)-1.; + d=PrRoundCylDf(q,.18,.01,.11); + DMIN(8); + q=p-vec3(.65,-.14,1); + q.x=abs(q.x)-.3; + d=PrRoundBoxDf(q,vec3(.01,1.08,.06),.02); + q=p-vec3(-.05,-.68,0); + q.xz=abs(q.xz)-vec2(1,.2); + d=min(d,PrRoundBoxDf(q,vec3(.04,.55,.01),.02)); + q=p-vec3(-1.05,-.14,1); + d=min(d,PrRoundBoxDf(q,vec3(.04,1.08,.01),.02)); + q=p-vec3(-1.05,-.68,.6); + q.z=abs(q.z)-.2; + d=min(d,PrRoundBoxDf(q,vec3(.04,.55,.01),.02)); + q=p-vec3(-.33,-.68,1.555); + q.x=abs(q.x)-.3; + d=min(d,PrRoundBoxDf(q,vec3(.01,.55,.04),.02)); + DMIN(4); + q=p-vec3(.65,bEdge,1); + d=PrCylDf(q.yzx,.04,.62); + q=p-vec3(-.36,-.21,1.555); + d=min(d,PrCylDf(q.yzx,.03,.51)); + q=p-vec3(-.05,-.21,0); + q.x-=1.; + d=min(d,PrCylDf(q,.03,.27)); + q.xz-=vec2(-2,.14); + d=min(d,PrCylDf(q,.03,.4)); + q.z-=.87; + d=min(d,PrCylDf(q,.03,.36)); + q=p-vec3(-1.05,-.68,.6); + d=min(d,PrCylDf(q,.03,.25)); + DMIN(5); + q=p-vec3(0,-1.2,.9); + d=PrRoundBoxDf(q,vec3(1.7,.03,1.5),.02); + DMIN(6); + q=p-wgObj.xyz; + d=PrRoundCylDf(q.xzy,wgObj.w,.02,.02); + DMIN(9); + return dMin; +} +float ObjRay(vec3 ro,vec3 rd) +{ + float dHit,d; + dHit=0.; + for(int j=VAR_ZERO;j<150;j++) + { + d=ObjDf(ro+dHit*rd); + dHit+=d; + if(d<5e-4||dHit>dstFar) + break; + } + return dHit; +} +float GearRay(vec3 ro,vec3 rd) +{ + float dHit,d; + dHit=0.; + for(int j=VAR_ZERO;j<250;j++) + { + d=GearDf(ro+dHit*rd); + dHit+=d; + if(d<5e-4||dHit>dstFar) + break; + } + return dHit; +} +vec3 GearNf(vec3 p) +{ + vec4 v; + vec2 e; + e=vec2(5e-4,-5e-4); + for(int j=VAR_ZERO;j<4;j++) + v[j]=GearDf(p+(j<2? + j==0? + e.xxx: + e.xyy: + j==2? + e.yxy: + e.yyx)); + v.x=-v.x; + return normalize(2.*v.yzw-dot(v,vec4(1))); +} +vec3 ObjNf(vec3 p) +{ + vec4 v; + vec2 e; + e=vec2(5e-4,-5e-4); + for(int j=VAR_ZERO;j<4;j++) + v[j]=ObjDf(p+(j<2? + j==0? + e.xxx: + e.xyy: + j==2? + e.yxy: + e.yyx)); + v.x=-v.x; + return normalize(2.*v.yzw-dot(v,vec4(1))); +} +float BlkHit(vec3 ro,vec3 rd) +{ + vec4 a4; + vec3 rm,rdm,u,v,tm,tp; + float dMin,dn,df; + dMin=dstFar; + for(float k=float(VAR_ZERO);k<13.;k++) + { + a4=BPos(tMov+tCyc*k/13.); + rm=ro-a4.xyz; + rdm=rd; + rm.zy=Rot2D(rm.zy,a4.w); + rdm.zy=Rot2D(rdm.zy,a4.w); + v=rm/rdm; + tp=bEdge/abs(rdm)-v; + tm=-tp-2.*v; + dn=Maxv3(tm); + df=Minv3(tp); + if(df>0.&&dn0.&&dn.99) + vn.yz=Rot2D(vn.yz,-sin(a-.5)); + if(r>.92) + col4*=.7+.3*SmoothBump(.05,.95,.01,a); + isMet=true; + } + else + if(idObj==1) + col4=vec4(.9,.8,.4,.2),isMet=true; + else + if(idObj==8) + col4=vec4(.8,.8,.85,.2)*(1.-.4*step(abs(ro.z),.1)),isMet=true; + else + if(idObj==5) + col4=vec4(.8,.8,.85,.2),isMet=true; + else + if(idObj==2) + col4=abs(vn.y)>.99? + vec4(.5,.6,.2,.05): + vec4(.7,.5,.4,.1); + else + if(idObj==3) + { + q=ro-vec3(-.05,-.21,0); + col4=vec4(.8,.8,.4,0); + if(sign(vn.y)!=sign(q.y)) + { + if(abs(q.x)<1.&&abs(vn.y)>.5) + col4*=1.-.1*SmoothBump(.45,.55,.03,fract(10.*(q.x-sign(q.y)*mod(tMov,20.)*2.1/5.))); + } + else + col4*=.8+.2*smoothstep(0.,.01,abs(abs(q.z)-.07)); + } + else + if(idObj==4) + col4=vec4(.7,.5,.4,.1),isMet=true; + else + if(idObj==6) + q=ro,q.z-=.9,Maxv2(abs(q.xz)-vec2(1.65,1.45))>0.? + (col4=vec4(.9,.9,.9,.2),isMet=true): + (col4=vec4(.3,.5,.4,0)),col4*=(.5+.5*step(0.,Maxv2(abs(vec2(q.x,q.z+1.3))-vec2(.4,.02))))*(.7+.3*step(0.,abs(PrCaps2Df(vec2(q.z+1.3,q.x),.08,.5))-.01)); + else + if(idObj==9) + { + col4=vec4(0,1,1,.2); + if(length(ro.xz-wgObj.xz)<.6*wgObj.w) + col4=mix(.8*col4,vec4(1,0,1,.2),step(0.,sin(6.2831854*tCur))); + } + } + sh=min(ObjSShadow(ro,ltDir),GearSShadow(ro,ltDir)); + sh=.6+.4*min(sh,BlkHitSh(ro+.01*ltDir,ltDir,6.)); + nDotL=max(dot(vn,ltDir),0.); + if(isMet) + nDotL*=nDotL; + col=col4.xyz*(.1+.1*max(-dot(vn,ltDir),0.)+.9*sh*nDotL)+col4.w*step(.95,sh)*sh*pow(max(0.,dot(ltDir,reflect(rd,vn))),32.); + if(isMet) + rd=reflect(rd,vn),col=mix(col,vec3(1),.01*step(.1,Minv2(fract(8.*vec2(atan(rd.z,rd.x),2.*asin(rd.y))+.5)-.5))); + } + else + col=vec3(0,0,.1)*(1.+.9*rd.y); + return clamp(col,0.,1.); +} +vec4 Loadv4(int idVar) +{ + float fi; + fi=float(idVar); + return texture(txBuf,(vec2(mod(fi,128.),floor(fi/128.))+.5)/txSize); +} +void mainImage(out vec4 fragColor,vec2 fragCoord) +{ + mat3 vuMat; + vec4 stDat; + vec3 ro,rd,col; + vec2 canvas,uv; + float el,az,zmFac,sr; + canvas=iResolution.xy; + uv=2.*fragCoord.xy/canvas-1.; + uv.x*=canvas.x/canvas.y; + tCur=iTime; + dstFar=30.; + stDat=Loadv4(0); + tMov=stDat.x; + cnPos=stDat.y; + wgObj=vec4(cnPos-.5,-1.12,-.4,.08); + stDat=Loadv4(1); + az=stDat.x; + el=stDat.y; + vuMat=StdVuMat(el,az); + zmFac=4.; + ro=vuMat*vec3(0,0,-8); + ro.z+=.9; + rd=vuMat*normalize(vec3(uv,zmFac)); + ltDir=vuMat*normalize(vec3(-.5,1,-1)); + +#if!AA + + +#else + + +#endif + + col=vec3(0); + sr=2.*mod(dot(mod(floor(.5*(uv+1.)*canvas),2.),vec2(1)),2.)-1.; + for(float a=float(VAR_ZERO);a<3.;a++) + rd=vuMat*normalize(vec3(uv+step(1.5,3.)*Rot2D(vec2(.5/canvas.y,0),sr*(.667*a+.5)*3.1415927),zmFac)),col+=1./3.*ShowScene(ro,rd); + fragColor=vec4(col,1); +} diff --git a/tests/real/endeavour.frag b/tests/real/endeavour.frag new file mode 100644 index 00000000..deb1adee --- /dev/null +++ b/tests/real/endeavour.frag @@ -0,0 +1,234 @@ +/* + * Copied from https://www.shadertoy.com/view/3d2XWt + * Endeavor by Team210 - 64k intro by Team210 at Revision 2k19 + * Copyright (C) 2019 Alexander Kraus + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +// Global constants +const float pi = acos(-1.); +const vec3 c = vec3(1.0, 0.0, -1.0); +float a = 1.0; + +// Hash function +void rand(in vec2 x, out float num) +{ + x += 400.; + num = fract(sin(dot(sign(x)*abs(x) ,vec2(12.9898,78.233)))*43758.5453); +} + +// Arbitrary-frequency 2D noise +void lfnoise(in vec2 t, out float num) +{ + vec2 i = floor(t); + t = fract(t); + //t = ((6.*t-15.)*t+10.)*t*t*t; // TODO: add this for slower perlin noise + t = smoothstep(c.yy, c.xx, t); // TODO: add this for faster value noise + vec2 v1, v2; + rand(i, v1.x); + rand(i+c.xy, v1.y); + rand(i+c.yx, v2.x); + rand(i+c.xx, v2.y); + v1 = c.zz+2.*mix(v1, v2, t.y); + num = mix(v1.x, v1.y, t.x); +} + +// Multi-frequency 2D noise +void mfnoise(in vec2 x, in float fmin, in float fmax, in float alpha, out float num) +{ + num = 0.; + float a = 1., nf = 0., buf; + for(float f = fmin; f-.05) + { + float n2; + mfnoise(x.xy, 30., 500., .47, n2); + vec2 sda = vec2(x.z+.05+.01*n2, 1.); + add(sdf, sda, sdf); + } + + float R = .07+.1*sdf.x, dis; + lfnoise(.5*x.y*c.xx, dis); + vec2 sdb; + vec2 ya = abs(x.xz-.4*dis*c.xy)+.045*c.yx - .065*c.xy; + zextrude(x.y, -length(ya)+R, 1.e4, sdb.x); + float da; + stroke(sdb.x, .003, da); + sdb.y = 2.; + + vec2 ind; + float phi = atan(ya.y, ya.x); + dhexagonpattern(vec2(56.,12.)*vec2(x.y, phi), dis, ind); + stroke(dis, .2, dis); + stroke(sdb.x, .003*step(dis,0.), sdb.x); + sdf.x = max(sdf.x,-da); + add(sdf, sdb, sdf); + + // Add guard objects for debugging + float dr = .1; + vec3 y = mod(x,dr)-.5*dr; + float guard = -length(max(abs(y)-vec3(.5*dr*c.xx, .6),0.)); + guard = abs(guard)+dr*.1; + sdf.x = min(sdf.x, guard); +} + +void normal(in vec3 x, out vec3 n) +{ + const float dx = 5.e-4; + vec2 s, na; + + scene(x,s); + scene(x+dx*c.xyy, na); + n.x = na.x; + scene(x+dx*c.yxy, na); + n.y = na.x; + scene(x+dx*c.yyx, na); + n.z = na.x; + n = normalize(n-s.x); +} + +void planet_texture(in vec2 x, out vec3 col) +{ + vec3 light_orange = vec3(1.00,0.69,0.05), + orange = vec3(0.95,0.45,0.01), + dark_orange = vec3(0.98,0.73,0.01); + + //rock like appearance + float d; + mfnoise(x, 1.,400.,.65,d); + col = mix(vec3(0.19,0.02,0.00), vec3(0.91,0.45,0.02), .5+.5*d); + + // big structures + stroke(d,.01, d); + col = mix(mix(.8*vec3(0.99,0.49,0.02),c.yyy,d*clamp(.2-.5*x.y/12.,0.,1.)), col, smoothstep(-.05,.05,d)); + col = mix(col, vec3(0.15,0.05,0.00), clamp(.2-.5*x.y/12.,0.,1.)); +} + +void mainImage( out vec4 fragColor, in vec2 fragCoord ) +{ + a = iResolution.x/iResolution.y; + vec2 uv = fragCoord/iResolution.yy-0.5*vec2(a, 1.0), + s; + vec3 col = c.yyy, + o = .5*c.yyx + .3*iTime*c.yxy, + t = vec3(uv,0.) + .3*iTime*c.yxy + c.yxy, + dir = normalize(t-o), + x; + float d = (.04-o.z)/dir.z; + + int N = 450, i; + for(i=0; i-.05) + { + float n2; + mfnoise(x.xy,30.,5e2,.47,n2); + vec2 sda=vec2(x.z+.05+.01*n2,1); + add(sdf,sda,sdf); + } + float R=.07+.1*sdf.x,dis,da,phi,dr,guard; + lfnoise(.5*x.y*c.xx,dis); + vec2 sdb,ya=abs(x.xz-.4*dis*c.xy)+.045*c.yx-.065*c.xy,ind; + zextrude(x.y,-length(ya)+R,1e4,sdb.x); + stroke(sdb.x,.003,da); + sdb.y=2.; + phi=atan(ya.y,ya.x); + dhexagonpattern(vec2(56,12)*vec2(x.y,phi),dis,ind); + stroke(dis,.2,dis); + stroke(sdb.x,.003*step(dis,0.),sdb.x); + sdf.x=max(sdf.x,-da); + add(sdf,sdb,sdf); + dr=.1; + vec3 y=mod(x,dr)-.5*dr; + guard=-length(max(abs(y)-vec3(.5*dr*c.xx,.6),0.)); + guard=abs(guard)+dr*.1; + sdf.x=min(sdf.x,guard); +} +void normal(vec3 x,out vec3 n) +{ + vec2 s,na; + scene(x,s); + scene(x+5e-4*c.xyy,na); + n.x=na.x; + scene(x+5e-4*c.yxy,na); + n.y=na.x; + scene(x+5e-4*c.yyx,na); + n.z=na.x; + n=normalize(n-s.x); +} +void planet_texture(vec2 x,out vec3 col) +{ + float d; + mfnoise(x,1.,4e2,.65,d); + col=mix(vec3(.19,.02,0),vec3(.91,.45,.02),.5+.5*d); + stroke(d,.01,d); + col=mix(mix(.8*vec3(.99,.49,.02),c.yyy,d*clamp(.2-.5*x.y/12.,0.,1.)),col,smoothstep(-.05,.05,d)); + col=mix(col,vec3(.15,.05,0),clamp(.2-.5*x.y/12.,0.,1.)); +} +void mainImage(out vec4 fragColor,vec2 fragCoord) +{ + a=iResolution.x/iResolution.y; + vec2 uv=fragCoord/iResolution.yy-.5*vec2(a,1),s; + vec3 col=c.yyy,o=.5*c.yyx+.3*iTime*c.yxy,t=vec3(uv,0)+.3*iTime*c.yxy+c.yxy,dir=normalize(t-o),x; + float d=(.04-o.z)/dir.z; + int N=450,i; + for(i=0;i FAR) break; + drift += fogmap(p, d); + d += h*mul; + mul+=.004; + //precis +=.001; + } + drift = min(drift, 1.0); + return d; +} + +vec3 normal( in vec3 pos, in float d ) +{ + vec2 eps = vec2( d *d* .003+.01, 0.0); + vec3 nor = vec3( + map(pos+eps.xyy) - map(pos-eps.xyy), + map(pos+eps.yxy) - map(pos-eps.yxy), + map(pos+eps.yyx) - map(pos-eps.yyx) ); + return normalize(nor); +} + +float bnoise(in vec3 p) +{ + p.xz*=.4; + float n = Noise3d(p*3.)*0.4; + n += Noise3d(p*1.5)*0.2; + return n*n*.2; +} + +vec3 bump(in vec3 p, in vec3 n, in float ds) +{ + p.xz *= .4; + //p *= 1.0; + vec2 e = vec2(.01,0); + float n0 = bnoise(p); + vec3 d = vec3(bnoise(p+e.xyy)-n0, bnoise(p+e.yxy)-n0, bnoise(p+e.yyx)-n0)/e.x; + n = normalize(n-d*10./(ds)); + return n; +} + +float shadow(in vec3 ro, in vec3 rd, in float mint) +{ + float res = 1.0; + + float t = mint; + for( int i=0; i<12; i++ ) + { + float h = map(ro + rd*t); + res = min( res, 4.*h/t ); + t += clamp( h, 0.1, 1.5 ); + } + return clamp( res, 0., 1.0 ); +} + +vec3 Clouds(vec3 sky, vec3 rd) +{ + + rd.y = max(rd.y, 0.0); + float ele = rd.y; + float v = (200.0)/(abs(rd.y)+.01); + + rd.y = v; + rd.xz = rd.xz * v - time*8.0; + rd.xz *= .0004; + + float f = Noise3d(rd.xzz*3.) * Noise3d(rd.zxx*1.3)*2.5; + f = f*pow(ele, .5)*2.; + f = clamp(f-.15, 0.01, 1.0); + + return mix(sky, vec3(1),f ); +} + + +vec3 Sky(vec3 rd, vec3 ligt) +{ + rd.y = max(rd.y, 0.0); + + vec3 sky = mix(vec3(.1, .15, .25), vec3(.8), pow(.8-rd.y, 3.0)); + return mix(sky, SUN_COLOUR, min(pow(max(dot(rd,ligt), 0.0), 4.5)*1.2, 1.0)); +} +float Occ(vec3 p) +{ + float h = 0.0; + h = clamp(map(p), 0.5, 1.0); + return sqrt(h); +} + + +void mainImage( out vec4 fragColor, in vec2 fragCoord ) +{ + vec2 p = fragCoord.xy/iResolution.xy-0.5; + vec2 q = fragCoord.xy/iResolution.xy; + p.x*=iResolution.x/iResolution.y; + vec2 mo = iMouse.xy / iResolution.xy-.5; + mo = (mo==vec2(-.5))?mo=vec2(-0.1,0.07):mo; + mo.x *= iResolution.x/iResolution.y; + + vec3 ro = vec3(0.+smoothstep(0.,1.,tri(time*1.5)*.3)*1.5, smoothstep(0.,1.,tri(time*3.)*3.)*0.08, -time*3.5-130.0); + ro.y -= camHeight(ro.zx)-.4; + mo.x += smoothstep(0.7,1.,sin(time*.35))*.5-1.5 - smoothstep(-.7,-1.,sin(time*.35))*.5; + + vec3 eyedir = normalize(vec3(cos(mo.x),mo.y*2.-.05+sin(time*.5)*0.1,sin(mo.x))); + vec3 rightdir = normalize(vec3(cos(mo.x+1.5708),0.,sin(mo.x+1.5708))); + vec3 updir = normalize(cross(rightdir,eyedir)); + vec3 rd=normalize((p.x*rightdir+p.y*updir)*1.+eyedir); + + vec3 ligt = normalize( vec3(1.5, .9, -.5) ); + float fg; + float rz = march(ro,rd, fg, fragCoord); + vec3 sky = Sky(rd, ligt); + + vec3 col = sky; + + if ( rz < FAR ) + { + vec3 pos = ro+rz*rd; + vec3 nor= normal( pos, rz); + float d = distance(pos,ro); + nor = bump(pos,nor,d); + float shd = (shadow(pos,ligt,.04)); + + float dif = clamp( dot( nor, ligt ), 0.0, 1.0 ); + vec3 ref = reflect(rd,nor); + float spe = pow(clamp( dot( ref, ligt ), 0.0, 1.0 ),5.)*2.; + + float fre = pow( clamp(1.+dot(rd, nor),0.0,1.0), 3. ); + col = vec3(.75); + col = col*dif*shd + fre*spe*shd*SUN_COLOUR +abs(nor.y)*vec3(.12, .13, .13); + // Fake the red absorption of ice... + d = Occ(pos+nor*3.); + col *= vec3(d, d, min(d*1.2, 1.0)); + // Fog from ice storm... + col = mix(col, sky, smoothstep(FAR-25.,FAR,rz)); + + } + else + { + col = Clouds(col, rd); + } + + + // Fog mix... + col = mix(col, vec3(0.6, .65, .7), fg); + + // Post... + col = mix(col, vec3(.5), -.3); + //col = col*col * (3.0-2.0*col); + //col = clamp(pow(col,vec3(1.5)),0.0, 1.0); + + col = sqrt(col); + + + // Borders... + float f = smoothstep(0.0, 3.0, iTime)*.5; + col *= f+f*pow(70. *q.x*q.y*(1.0-q.x)*(1.0-q.y), .2); + + + fragColor = vec4( col, 1.0 ); +} diff --git a/tests/real/frozen-wasteland.frag.expected b/tests/real/frozen-wasteland.frag.expected new file mode 100644 index 00000000..ffcf9215 --- /dev/null +++ b/tests/real/frozen-wasteland.frag.expected @@ -0,0 +1,286 @@ +#define ITR 90 + +#define FAR 110. + +#define time iTime + +#define MOD3 vec3(.16532,.17369,.15787) + +#define SUN_COLOUR vec3(1.,.95,.85) + +#define TRIANGLE_NOISE + +float height(vec2 p) +{ + float h=sin(p.x*.1+p.y*.2)+sin(p.y*.1-p.x*.2)*.5; + h+=sin(p.x*.04+p.y*.01+3.)*4.; + h-=sin(h*10.)*.1; + return h; +} +float camHeight(vec2 p) +{ + float h=sin(p.x*.1+p.y*.2)+sin(p.y*.1-p.x*.2)*.5; + h+=sin(p.x*.04+p.y*.01+3.)*4.; + return h; +} +float smin(float a,float b) +{ + float h=clamp(.5+.5*(b-a)/2.7,0.,1.); + return mix(b,a,h)-2.7*h*(1.-h); +} + +#define MOD2 vec2(.16632,.17369) + +#define MOD3 vec3(.16532,.17369,.15787) + +float tri(float x) +{ + return abs(fract(x)-.5); +} +float hash12(vec2 p) +{ + p=fract(p*MOD2); + p+=dot(p.xy,p.yx+19.19); + return fract(p.x*p.y); +} +float vine(vec3 p,float c,float h) +{ + p.y+=sin(p.z*.5625+1.3)*3.5-.5; + p.x+=cos(p.z*2.); + vec2 q=vec2(mod(p.x,c)-c/2.,p.y); + return length(q)-h*1.4-sin(p.z*3.+sin(p.x*7.)*.5)*.1; +} + +#ifdef TRIANGLE_NOISE + +vec3 tri3(vec3 p) +{ + return vec3(tri(p.z+tri(p.y)),tri(p.z+tri(p.x)),tri(p.y+tri(p.x))); +} +float Noise3d(vec3 p) +{ + float z=1.4,rz=0.; + vec3 bp=p; + for(float i=0.;i<=2.;i++) + { + vec3 dg=tri3(bp); + p+=dg; + bp*=2.; + z*=1.5; + p*=1.3; + rz+=tri(p.z+tri(p.x+tri(p.y)))/z; + bp+=.14; + } + return rz; +} + +#endif + +#ifdef FOUR_D_NOISE + +vec4 quad(vec4 p) +{ + return abs(fract(p.yzwx+p.wzxy)-.5); +} +float Noise3d(vec3 q) +{ + float z=1.4,rz; + vec4 p=vec4(q,iTime*.1),bp; + rz=0.; + bp=p; + for(float i=0.;i<=2.;i++) + { + vec4 dg=quad(bp); + p+=dg; + z*=1.5; + p*=1.3; + rz+=tri(p.z+tri(p.w+tri(p.y+tri(p.x))))/z; + bp=bp.yxzw*2.+.14; + } + return rz; +} + +#endif + +#ifdef TEXTURE_NOISE + +float Noise3d(vec3 x) +{ + x*=10.; + float h=0.,a=.28; + for(int i=0;i<4;i++) + { + vec3 p=floor(x),f=fract(x); + f=f*f*(3.-2.*f); + vec2 uv=p.xy+vec2(37,17)*p.z+f.xy,rg=textureLod(iChannel0,(uv+.5)/256.,0.).yx; + h+=mix(rg.x,rg.y,f.z)*a; + a*=.5; + x+=x; + } + return h; +} + +#endif + +#ifdef VALUE_NOISE + +float Hash(vec3 p) +{ + p=fract(p*MOD3); + p+=dot(p.xyz,p.yzx+19.19); + return fract(p.x*p.y*p.z); +} +float Noise3d(vec3 p) +{ + vec2 add=vec2(1,0); + p*=10.; + float h=0.,a=.3; + for(int n=0;n<4;n++) + { + vec3 i=floor(p),f=fract(p); + f*=f*(3.-2.*f); + h+=mix(mix(mix(Hash(i),Hash(i+add.xyy),f.x),mix(Hash(i+add.yxy),Hash(i+add.xxy),f.x),f.y),mix(mix(Hash(i+add.yyx),Hash(i+add.xyx),f.x),mix(Hash(i+add.yxx),Hash(i+add.xxx),f.x),f.y),f.z)*a; + a*=.5; + p+=p; + } + return h; +} + +#endif + +float map(vec3 p) +{ + p.y+=height(p.zx); + float d=p.y+.5; + d=smin(d,vine(p+vec3(.8,0,0),30.,3.3)); + d=smin(d,vine(p.zyx+vec3(0,0,17),33.,1.4)); + d+=p.y*1.2*Noise3d(p*.05); + p.xz*=.3; + d+=Noise3d(p*.3); + return d; +} +float fogmap(vec3 p,float d) +{ + p.xz-=time*7.+sin(p.z*.3)*3.; + p.y-=time*.5; + return max(Noise3d(p*.008+.1)-.1,0.)*Noise3d(p*.1)*.3; +} +float march(vec3 ro,vec3 rd,out float drift,vec2 scUV) +{ + float precis=.1,mul=.34,h,d=hash12(scUV)*1.5; + drift=0.; + for(int i=0;iFAR) + break; + drift+=fogmap(p,d); + d+=h*mul; + mul+=.004; + } + drift=min(drift,1.); + return d; +} +vec3 normal(vec3 pos,float d) +{ + vec2 eps=vec2(d*d*.003+.01,0); + vec3 nor=vec3(map(pos+eps.xyy)-map(pos-eps.xyy),map(pos+eps.yxy)-map(pos-eps.yxy),map(pos+eps.yyx)-map(pos-eps.yyx)); + return normalize(nor); +} +float bnoise(vec3 p) +{ + p.xz*=.4; + float n=Noise3d(p*3.)*.4; + n+=Noise3d(p*1.5)*.2; + return n*n*.2; +} +vec3 bump(vec3 p,vec3 n,float ds) +{ + p.xz*=.4; + vec2 e=vec2(.01,0); + float n0=bnoise(p); + vec3 d=vec3(bnoise(p+e.xyy)-n0,bnoise(p+e.yxy)-n0,bnoise(p+e.yyx)-n0)/e.x; + n=normalize(n-d*10./ds); + return n; +} +float shadow(vec3 ro,vec3 rd,float mint) +{ + float res=1.,t=mint; + for(int i=0;i<12;i++) + { + float h=map(ro+rd*t); + res=min(res,4.*h/t); + t+=clamp(h,.1,1.5); + } + return clamp(res,0.,1.); +} +vec3 Clouds(vec3 sky,vec3 rd) +{ + rd.y=max(rd.y,0.); + float ele=rd.y,v=2e2/(abs(rd.y)+.01),f; + rd.y=v; + rd.xz=rd.xz*v-time*8.; + rd.xz*=4e-4; + f=Noise3d(rd.xzz*3.)*Noise3d(rd.zxx*1.3)*2.5; + f=f*pow(ele,.5)*2.; + f=clamp(f-.15,.01,1.); + return mix(sky,vec3(1),f); +} +vec3 Sky(vec3 rd,vec3 ligt) +{ + rd.y=max(rd.y,0.); + vec3 sky=mix(vec3(.1,.15,.25),vec3(.8),pow(.8-rd.y,3.)); + return mix(sky,SUN_COLOUR,min(pow(max(dot(rd,ligt),0.),4.5)*1.2,1.)); +} +float Occ(vec3 p) +{ + float h=0.; + h=clamp(map(p),.5,1.); + return sqrt(h); +} +void mainImage(out vec4 fragColor,vec2 fragCoord) +{ + vec2 p=fragCoord.xy/iResolution.xy-.5,q=fragCoord.xy/iResolution.xy,mo; + p.x*=iResolution.x/iResolution.y; + mo=iMouse.xy/iResolution.xy-.5; + mo=mo==vec2(-.5)? + (mo=vec2(-.1,.07)): + mo; + mo.x*=iResolution.x/iResolution.y; + vec3 ro=vec3(smoothstep(0.,1.,tri(time*1.5)*.3)*1.5,smoothstep(0.,1.,tri(time*3.)*3.)*.08,-time*3.5-130.),eyedir,rightdir,updir,rd,ligt,sky,col; + ro.y-=camHeight(ro.zx)-.4; + mo.x+=smoothstep(.7,1.,sin(time*.35))*.5-1.5-smoothstep(-.7,-1.,sin(time*.35))*.5; + eyedir=normalize(vec3(cos(mo.x),mo.y*2.-.05+sin(time*.5)*.1,sin(mo.x))); + rightdir=normalize(vec3(cos(mo.x+1.5708),0,sin(mo.x+1.5708))); + updir=normalize(cross(rightdir,eyedir)); + rd=normalize(p.x*rightdir+p.y*updir+eyedir); + ligt=normalize(vec3(1.5,.9,-.5)); + float fg,rz=march(ro,rd,fg,fragCoord),f; + sky=Sky(rd,ligt); + col=sky; + if(rz Date: Sun, 15 Jan 2023 22:37:45 +0100 Subject: [PATCH 17/32] Disable the if to ternary transformation (#215) It is unsafe when the types don't match. --- src/rewriter.fs | 4 +- tests/compression_results.log | 16 ++--- tests/real/clod.expected | 2 +- .../real/controllable-machinery.frag.expected | 12 +++- .../from-the-seas-to-the-stars.frag.expected | 59 ++++++++++++++----- tests/real/lunaquatic.frag.expected | 10 +++- tests/real/oscars_chair.frag.expected | 58 +++++++++--------- tests/real/sult.expected | 24 ++++---- tests/real/terrarium.frag.expected | 54 ++++++++++------- ...real_party_is_in_your_pocket.frag.expected | 23 ++++---- tests/real/valley_ball.glsl.expected | 12 ++-- tests/unit/conditionals.frag.expected | 7 ++- 12 files changed, 172 insertions(+), 109 deletions(-) diff --git a/src/rewriter.fs b/src/rewriter.fs index 71377ff8..1d0e609a 100644 --- a/src/rewriter.fs +++ b/src/rewriter.fs @@ -482,7 +482,9 @@ let private simplifyStmt = function // turn if-else of expressions into ternary statement | _ -> // if(c)x();else y(); -> c?x():y(); - Expr (FunCall(Op "?:", [cond; eT; eF])) + // This transformation is not legal when x() and y() have different types. + // Expr (FunCall(Op "?:", [cond; eT; eF])) + If (cond, body1, body2) | _ -> If (cond, body1, body2) | Verbatim s -> Verbatim (stripSpaces s) | e -> e diff --git a/tests/compression_results.log b/tests/compression_results.log index b93ed310..dafde291 100644 --- a/tests/compression_results.log +++ b/tests/compression_results.log @@ -1,22 +1,22 @@ audio-flight-v2.frag 4620 => 919.722 buoy.frag 4194 => 622.602 -controllable-machinery.frag 7767 => 1230.786 +controllable-machinery.frag 7773 => 1230.829 ed-209.frag 7888 => 1361.583 elevated.hlsl 3406 => 611.302 endeavour.frag 2623 => 544.176 -from-the-seas-to-the-stars.frag 14305 => 2358.450 +from-the-seas-to-the-stars.frag 14339 => 2353.070 frozen-wasteland.frag 4588 => 805.076 kinder_painter.frag 2880 => 450.617 leizex.frag 2308 => 515.785 -lunaquatic.frag 5218 => 1058.675 +lunaquatic.frag 5224 => 1058.755 mandelbulb.frag 2369 => 549.088 ohanami.frag 3283 => 750.856 orchard.frag 5588 => 1051.886 -oscars_chair.frag 4626 => 981.611 +oscars_chair.frag 4648 => 982.231 robin.frag 6293 => 1066.421 slisesix.frag 4533 => 956.567 -terrarium.frag 3576 => 737.588 -the_real_party_is_in_your_pocket.frag 12196 => 1829.311 -valley_ball.glsl 4369 => 890.945 +terrarium.frag 3632 => 749.375 +the_real_party_is_in_your_pocket.frag 12200 => 1829.607 +valley_ball.glsl 4379 => 889.602 yx_long_way_from_home.frag 2992 => 615.970 -Total: 109622 => 19909.017 +Total: 109760 => 19915.120 diff --git a/tests/real/clod.expected b/tests/real/clod.expected index 006a09db..a3243b44 100644 --- a/tests/real/clod.expected +++ b/tests/real/clod.expected @@ -1 +1 @@ -uniform vec2 resolution;uniform float time;uniform sampler2D tex0,tex1,tex2,tex3;float f(vec3 o){float a=(sin(o.x)+o.y*.25)*.35;o=vec3(cos(a)*o.x-sin(a)*o.y,sin(a)*o.x+cos(a)*o.y,o.z);return dot(cos(o)*cos(o),vec3(1))-1.2;}vec3 s(vec3 o,vec3 d){float t=0.,a,b;for(int i=0;i<75;i++){if(f(o+d*t)<0.){a=t-.125;b=t;for(int i=0;i<10;i++)t=(a+b)*.5,f(o+d*t)<0.?(b=t):(a=t);vec3 e=vec3(.1,0,0),p=o+d*t,n=-normalize(vec3(f(p+e),f(p+e.yxy),f(p+e.yyx))+vec3(sin(p*75.))*.01);return vec3(mix((max(-dot(n,vec3(.577)),0.)+.125*max(-dot(n,vec3(-.707,-.707,0)),0.))*(mod(length(p.xy)*20.,2.)<1.?vec3(.71,.85,.25):vec3(.79,.93,.4)),vec3(.93,.94,.85),vec3(pow(t/9.,5.))));}t+=.125;}return vec3(.93,.94,.85);}void main(){vec2 p=-1.+2.*gl_FragCoord.xy/resolution.xy;gl_FragColor=vec4(s(vec3(sin(time*1.5)*.5,cos(time)*.5,time),normalize(vec3(p.xy,1))),1);} +uniform vec2 resolution;uniform float time;uniform sampler2D tex0,tex1,tex2,tex3;float f(vec3 o){float a=(sin(o.x)+o.y*.25)*.35;o=vec3(cos(a)*o.x-sin(a)*o.y,sin(a)*o.x+cos(a)*o.y,o.z);return dot(cos(o)*cos(o),vec3(1))-1.2;}vec3 s(vec3 o,vec3 d){float t=0.,a,b;for(int i=0;i<75;i++){if(f(o+d*t)<0.){a=t-.125;b=t;for(int i=0;i<10;i++){t=(a+b)*.5;if(f(o+d*t)<0.)b=t;else a=t;}vec3 e=vec3(.1,0,0),p=o+d*t,n=-normalize(vec3(f(p+e),f(p+e.yxy),f(p+e.yyx))+vec3(sin(p*75.))*.01);return vec3(mix((max(-dot(n,vec3(.577)),0.)+.125*max(-dot(n,vec3(-.707,-.707,0)),0.))*(mod(length(p.xy)*20.,2.)<1.?vec3(.71,.85,.25):vec3(.79,.93,.4)),vec3(.93,.94,.85),vec3(pow(t/9.,5.))));}t+=.125;}return vec3(.93,.94,.85);}void main(){vec2 p=-1.+2.*gl_FragCoord.xy/resolution.xy;gl_FragColor=vec4(s(vec3(sin(time*1.5)*.5,cos(time)*.5,time),normalize(vec3(p.xy,1))),1);} diff --git a/tests/real/controllable-machinery.frag.expected b/tests/real/controllable-machinery.frag.expected index f0abc15b..54d36f5b 100644 --- a/tests/real/controllable-machinery.frag.expected +++ b/tests/real/controllable-machinery.frag.expected @@ -424,9 +424,15 @@ vec3 ShowScene(vec3 ro,vec3 rd) col4=vec4(.7,.5,.4,.1),isMet=true; else if(idObj==6) - q=ro,q.z-=.9,Maxv2(abs(q.xz)-vec2(1.65,1.45))>0.? - (col4=vec4(.9,.9,.9,.2),isMet=true): - (col4=vec4(.3,.5,.4,0)),col4*=(.5+.5*step(0.,Maxv2(abs(vec2(q.x,q.z+1.3))-vec2(.4,.02))))*(.7+.3*step(0.,abs(PrCaps2Df(vec2(q.z+1.3,q.x),.08,.5))-.01)); + { + q=ro; + q.z-=.9; + if(Maxv2(abs(q.xz)-vec2(1.65,1.45))>0.) + col4=vec4(.9,.9,.9,.2),isMet=true; + else + col4=vec4(.3,.5,.4,0); + col4*=(.5+.5*step(0.,Maxv2(abs(vec2(q.x,q.z+1.3))-vec2(.4,.02))))*(.7+.3*step(0.,abs(PrCaps2Df(vec2(q.z+1.3,q.x),.08,.5))-.01)); + } else if(idObj==9) { diff --git a/tests/real/from-the-seas-to-the-stars.frag.expected b/tests/real/from-the-seas-to-the-stars.frag.expected index ad3cd07b..673f9b85 100644 --- a/tests/real/from-the-seas-to-the-stars.frag.expected +++ b/tests/real/from-the-seas-to-the-stars.frag.expected @@ -93,11 +93,13 @@ void makeBG(float c) w.y=R()*2-1; w.z=R()*2-1; w.w=R(); - w.w>c? - (w.w=R(),p.x=pow(abs(w.x),1.)*sign(w.x)*8.,p.z=pow(abs(w.y),1.)*sign(w.y)*8.,p.y=.2+fbm(p.xz-time/8.)*.2-pow(w.z*.5+.5,8.)*5.,col=vec3(.3,.5,1)/2,col=mix(col,vec3(1,.25,1),pow(w.w,4.)),col=mix(col,vec3(1),pow(1.-w.z*.5-.5,32.)),col*=1.-pow(w.z*.5+.5,1.),col+=pow(1-abs(fbm(p.xz*3.+time/8.+p.y)*.7-.6),32.)*.4,col/=2,p.x+=cos(p.x*8.)*.01,col*=.2,p.y+=.5): - w.w>1e-4? - (w.x=R()*2-1,w.y=R()*2-1,w.z=R(),p.xz=w.xy*7,p.y=-1.+fbm(p.zx+19.)*.02*pow(length(p.xz),2.)-pow(w.z,8),p.z+=2.,col=vec3(.1,.06,.05)/1.5*smoothstep(-1.5,-.2,p.y),w.w=R(),col+=vec3(pow(w.w,80))*.1,col*=1.+pow(max(0.,1.-abs(fbm(p.xz*2+time/2)-.8)),16)/2): - (p=w.xyz,p.x=fract(p.x+time/4.*.1)*2-1,p*=2.,w.w=R(),col=vec3(w.w)*.3); + if(w.w>c) + w.w=R(),p.x=pow(abs(w.x),1.)*sign(w.x)*8.,p.z=pow(abs(w.y),1.)*sign(w.y)*8.,p.y=.2+fbm(p.xz-time/8.)*.2-pow(w.z*.5+.5,8.)*5.,col=vec3(.3,.5,1)/2,col=mix(col,vec3(1,.25,1),pow(w.w,4.)),col=mix(col,vec3(1),pow(1.-w.z*.5-.5,32.)),col*=1.-pow(w.z*.5+.5,1.),col+=pow(1-abs(fbm(p.xz*3.+time/8.+p.y)*.7-.6),32.)*.4,col/=2,p.x+=cos(p.x*8.)*.01,col*=.2,p.y+=.5; + else + if(w.w>1e-4) + w.x=R()*2-1,w.y=R()*2-1,w.z=R(),p.xz=w.xy*7,p.y=-1.+fbm(p.zx+19.)*.02*pow(length(p.xz),2.)-pow(w.z,8),p.z+=2.,col=vec3(.1,.06,.05)/1.5*smoothstep(-1.5,-.2,p.y),w.w=R(),col+=vec3(pow(w.w,80))*.1,col*=1.+pow(max(0.,1.-abs(fbm(p.xz*2+time/2)-.8)),16)/2; + else + p=w.xyz,p.x=fract(p.x+time/4.*.1)*2-1,p*=2.,w.w=R(),col=vec3(w.w)*.3; } void ammonite() { @@ -525,11 +527,16 @@ void main() { p.z+=sin(p.x); if(!bigkoi) - w.w=R(),w.w<.33? - (col=vec3(1,.25,.1)): - w.w<.66? - (col=vec3(.01),p.xz*=rotmat(1.8846)): - (col=vec3(.5),p.xz*=rotmat(3.7692)); + { + w.w=R(); + if(w.w<.33) + col=vec3(1,.25,.1); + else + if(w.w<.66) + col=vec3(.01),p.xz*=rotmat(1.8846); + else + col=vec3(.5),p.xz*=rotmat(3.7692); + } else { p.x*=2.; @@ -595,11 +602,33 @@ void main() op.x-=mod(op.x,.1)/3.; float d=koi(op.xy); if(max(d,abs(op.z)-.1*pow(-clamp(d,-1,0),.5))<0.) - p=op,w.x=R(),w.y=R(),w.z=R(),w.w=R(),w.w=R(),w.x=R(),w.y=R(),p.z+=.2,p+=fp,p.z+=sin(p.x*3.)*.1,w.w=R(),w.w<.33? - (col=vec3(1,.25,.1)): - w.w<.66? - (col=vec3(.01),p.xz*=rotmat(3.141),p.z+=3.): - (col=vec3(.5),p.xz*=rotmat(3.141),p.x+=2.,p.z+=6.),w.x=R(),col+=pow(w.x,32.)*vec3(.2),w.x=R(),w.y=R(),w.z=R(),w.w=R(); + { + p=op; + w.x=R(); + w.y=R(); + w.z=R(); + w.w=R(); + w.w=R(); + w.x=R(); + w.y=R(); + p.z+=.2; + p+=fp; + p.z+=sin(p.x*3.)*.1; + w.w=R(); + if(w.w<.33) + col=vec3(1,.25,.1); + else + if(w.w<.66) + col=vec3(.01),p.xz*=rotmat(3.141),p.z+=3.; + else + col=vec3(.5),p.xz*=rotmat(3.141),p.x+=2.,p.z+=6.; + w.x=R(); + col+=pow(w.x,32.)*vec3(.2); + w.x=R(); + w.y=R(); + w.z=R(); + w.w=R(); + } else { w.w=R(); diff --git a/tests/real/lunaquatic.frag.expected b/tests/real/lunaquatic.frag.expected index 27fffc8f..16803f28 100644 --- a/tests/real/lunaquatic.frag.expected +++ b/tests/real/lunaquatic.frag.expected @@ -136,9 +136,13 @@ float traceIso(vec3 ro,vec3 rd,float mint,float maxt,float s) if(iso<=0.) { for(int i=0;i<9;i++) - exact=(lt+t)/2.,isoSurface(ro+exact*rd)<0.? - (t=exact): - (lt=exact); + { + exact=(lt+t)/2.; + if(isoSurface(ro+exact*rd)<0.) + t=exact; + else + lt=exact; + } return exact; } lt=t; diff --git a/tests/real/oscars_chair.frag.expected b/tests/real/oscars_chair.frag.expected index 4532f3e6..632cc134 100644 --- a/tests/real/oscars_chair.frag.expected +++ b/tests/real/oscars_chair.frag.expected @@ -10,7 +10,7 @@ const char *oscars_chair_frag = "vec2 v=gl_FragCoord.xy/1280;" "uniform sampler2D a;" "float y=gl_TexCoord[0].x/44100,i,m,s=1,r;" - "vec3 c=vec3(7,5,19),z=vec3(-4,0,3),f,x,g=vec3(0,5,-7),l;" + "vec3 c=vec3(7,5,19),z=vec3(-4,0,3),f,x,g=vec3(0,5,-7),e;" "float n(vec2 x,float v)" "{" "float y=0,c=1,m=1;" @@ -61,14 +61,14 @@ const char *oscars_chair_frag = "v.z=abs(v.z);" "return min(min(min(max(length(max(abs(v.xz)-vec2(.45,.41),0))-.25,abs(v.y)-.02),length(v-vec3(clamp(v.x,-.6,.6),-.1,.6))-.025),length(vec3(abs(v.x)-.6+min(0,v.y)/5,v.y-clamp(v.y,-1.24,1.5*step(0,v.x)),v.z-.6))-.025),max(length(max(abs(v.yz-vec2(1,0))-vec2(.5,.35),0))-.25,abs(v.x-.6)-.03));" "}" - "float e(vec3 v,vec3 y)" + "float h(vec3 v,vec3 y)" "{" "float x=0,f=0;" "for(;f<200&&x<30;++f)" "i=min(i,m=n(v+y*x)),x+=m/2;" "return x;" "}" - "vec3 h(vec3 v,vec3 a)" + "vec3 w(vec3 v,vec3 a)" "{" "vec3 r;" "x=v+a*(m=min((sign(a.x)*c.x-v.x)/a.x,min((sign(a.y)*c.y-v.y)/a.y,(sign(a.z)*c.z-v.z)/a.z)));" @@ -83,7 +83,7 @@ const char *oscars_chair_frag = "r*=mix(vec3(1,1,.5),vec3(1),min((-abs(x.y)+c.y)/4,1))*sqrt(min((-abs(x.y)+c.y)*8+.4,1));" "}" "r*=mix(4,1,smoothstep(1,2,length(x/c)))*max(0,1+3*dot(f,normalize(g-x)))/16*(1-smoothstep(0,2.5,length(max(abs(x)-c+1,0))));" - "r=(r+pow(clamp(dot(normalize(normalize(g-x)-a),f),0,1),64)*(r*.8+.2))*exp2(-length(g-x)/1.2)*s*20*mix(.02,2,smoothstep(.6,.7,dot(normalize(g-x),l)));" + "r=(r+pow(clamp(dot(normalize(normalize(g-x)-a),f),0,1),64)*(r*.8+.2))*exp2(-length(g-x)/1.2)*s*20*mix(.02,2,smoothstep(.6,.7,dot(normalize(g-x),e)));" "if(y<=97)" "r+=pow(vec3(2.2,.7,.3)*exp(-abs(n(x.xz/2+x.y/4-y/2,1.5))*10*n(-x.xy+y-x.z,1.5)+n(x.xy-y/3,2)*6-x.y-c.y-x.z-c.z+(y-88)/4+x.x/9),vec3(2))/70;" "return r;" @@ -107,43 +107,47 @@ const char *oscars_chair_frag = "vec3 t=vec3(0);" "for(int p=0;p<8;++p)" "{" - "float o=2.7,d;" - "vec3 w=vec3(10+y/4,-4,-1),b=vec3(-7,-2,0),u,C;" + "float l=2.7,d;" + "vec3 o=vec3(10+y/4,-4,-1),b=vec3(-7,-2,0),u,C;" "m=0;" - "y>97?" - "(b=w=vec3(0,-4,y-97),b.z-=1,g=vec3(0,3,-22),s=.4,c=vec3(3,7,28),z=vec3(-4,0,13)):" - "y>81?" - "(b=w=vec3(0,-3.6,97-y),b.z-=1,g=vec3(0,5,-5),s=.01,o=1.7,c=vec3(7,5,9),z=vec3(0,0,-2)):" - "y>60?" - "(w=vec3((y-60)/5-1,-2,13),b=vec3(-7,-5,-7),g=vec3(0,5,-3),m=sin(y-60)/10-.9,c=vec3(7,5,9),z=vec3(-4,0,2)):" - "y>25?" - "(w=vec3(0,0,25-y/2.7),b=vec3(0,-4,18-y/2.7),g=vec3(-2,5,-7),c=vec3(9,5,14),z=vec3(3.5,0,-6)):" - "(m=-.9);" + "if(y>97)" + "b=o=vec3(0,-4,y-97),b.z-=1,g=vec3(0,3,-22),s=.4,c=vec3(3,7,28),z=vec3(-4,0,13);" + "else" + " if(y>81)" + "b=o=vec3(0,-3.6,97-y),b.z-=1,g=vec3(0,5,-5),s=.01,l=1.7,c=vec3(7,5,9),z=vec3(0,0,-2);" + "else" + " if(y>60)" + "o=vec3((y-60)/5-1,-2,13),b=vec3(-7,-5,-7),g=vec3(0,5,-3),m=sin(y-60)/10-.9,c=vec3(7,5,9),z=vec3(-4,0,2);" + "else" + " if(y>25)" + "o=vec3(0,0,25-y/2.7),b=vec3(0,-4,18-y/2.7),g=vec3(-2,5,-7),c=vec3(9,5,14),z=vec3(3.5,0,-6);" + "else" + " m=-.9;" "r=7;" - "l=vec3(0,cos(m),sin(m));" - "u=normalize(b-w);" + "e=vec3(0,cos(m),sin(m));" + "u=normalize(b-o);" "C=normalize(vec3(-u.z,0,u.x));" "if(y>81&&y<=97)" "u.y+=n(vec2(y+6)/2,2)*.05,C.y+=n(vec2(y)/3,2)*.08;" - "u=mat3(C,cross(C,u),u)*normalize(vec3(v*2+vec2(p&1,p/2)/1200-1,o));" - "d=e(w,u);" + "u=mat3(C,cross(C,u),u)*normalize(vec3(v*2+vec2(p&1,p/2)/1200-1,l));" + "d=h(o,u);" "if(d<30)" - "x=w+u*d,f=vec3(.02,0,0),f=normalize(vec3(n(x+f.xyy)-m,n(x+f.yxy)-m,n(x+f.yyx)-m)),r=2,C=h(x,reflect(u,f))*pow(1+dot(u,f),3);" + "x=o+u*d,f=vec3(.02,0,0),f=normalize(vec3(n(x+f.xyy)-m,n(x+f.yxy)-m,n(x+f.yyx)-m)),r=2,C=w(x,reflect(u,f))*pow(1+dot(u,f),3);" "else" "{" - "C=h(w,u);" - "o=(.3+.7*pow(1+dot(u,f),2)/4)*(.1+.9*step(x.y,-c.y+.01));" - "w=reflect(u,f);" + "C=w(o,u);" + "l=(.3+.7*pow(1+dot(u,f),2)/4)*(.1+.9*step(x.y,-c.y+.01));" + "o=reflect(u,f);" "d=m;" "r=2;" "i=1e2;" "u=normalize(g-x);" - "e(x+u*.01,u);" + "h(x+u*.01,u);" "C*=.4+.6*smoothstep(0,n(x)/5,i);" "if(x.y<-c.y+.01)" - "if(e(x,w)<30)" - "o*=.2,C*=.7;" - "C+=h(x,w)*o*mix(vec3(1),C,.8);" + "if(h(x,o)<30)" + "l*=.2,C*=.7;" + "C+=w(x,o)*l*mix(vec3(1),C,.8);" "}" "if(y>60&&y<=97)" "gl_FragColor.w=y<=81?" diff --git a/tests/real/sult.expected b/tests/real/sult.expected index 35c5a9cc..7d7ef18e 100644 --- a/tests/real/sult.expected +++ b/tests/real/sult.expected @@ -18,18 +18,18 @@ const char *sult_frag = "float f=0.,w=10.;" "float e(vec3 m)" "{" - "float y=c,g,z=0.,o,a,t;" + "float y=c,z,a=0.,g,o,t;" "vec3 r;" "m+=(sin(m.zxy*1.7+y)+sin(m.yzx+y*3.))*.2;" - "z=v<6.?" + "a=v<6.?" "length(m.xyz*vec3(1,1,.1)-vec3(0,-.1,y*.15-.3))-.34:" "length(m.xy+vec2(0,.7))-.3+(sin(m.z*17.+y*.6)+sin(m.z*2.)*6.)*.01;" "m.xy=vec2(atan(m.x,m.y)*1.113,1.6-length(m.xy)-sin(y*2.)*.3);" "r=fract(m.xzz+.5).xyz-.5;" "r.y=(m.y-.35)*1.3;" - "g=max(abs(m.y-.3)-.05,abs(length(fract(m.xz)-.5)-.4)-.03);" - "f=step(z,g);" - "return min(min(g,z),m.y-.2);" + "z=max(abs(m.y-.3)-.05,abs(length(fract(m.xz)-.5)-.4)-.03);" + "f=step(a,z);" + "return min(min(z,a),m.y-.2);" "}" "vec3 d=vec3(.19,.2,.24),o=vec3(1),t=vec3(.45,.01,0),g=vec3(.17,0,0);" "void main()" @@ -39,11 +39,15 @@ const char *sult_frag = "float C=1.,b=0.,Z,Y,X=0.,W,V,U,T;" "u=vec3(.01,0,0);" "h=u.yyy;" - "for(;C>.1;Z.005;Z+=Y)" - "Y=e(p+i*Z);" + "for(;C>.1;)" + "{" + "for(Z=X,Y=1.;Z.005;Z+=Y)" + "Y=e(p+i*Z);" + "if(Z48.) p.z=mix(p.z,mod(p.z+time/2.+2,4.)-2,smoothstep(48.,49.,time)); } @@ -104,13 +111,16 @@ void main() { float s=H(seed=IH(seed)); p.y-=.8; - s<.93? - (p.xy=(mat3(.860671,-.402177,0,.401487,.860992,0,.108537,.075138,1)*vec3(p.xy,1)).xy): - s<.95? - (p.xy=(mat3(.094957,.237023,0,-.000995,.002036,0,-.746911,.047343,1)*vec3(p.xy,1)).xy): - s<.98? - (p.xy=(mat3(.150288,0,0,0,.146854,0,-.563199,.032007,1)*vec3(p.xy,1)).xy): - (p.xy=(mat3(.324279,.005846,0,-.002163,.001348,0,-.557936,-.139735,1)*vec3(p.xy,1)).xy); + if(s<.93) + p.xy=(mat3(.860671,-.402177,0,.401487,.860992,0,.108537,.075138,1)*vec3(p.xy,1)).xy; + else + if(s<.95) + p.xy=(mat3(.094957,.237023,0,-.000995,.002036,0,-.746911,.047343,1)*vec3(p.xy,1)).xy; + else + if(s<.98) + p.xy=(mat3(.150288,0,0,0,.146854,0,-.563199,.032007,1)*vec3(p.xy,1)).xy; + else + p.xy=(mat3(.324279,.005846,0,-.002163,.001348,0,-.557936,-.139735,1)*vec3(p.xy,1)).xy; p.y+=.8; } p*=1.+max(0.,time-130)/6.; diff --git a/tests/real/the_real_party_is_in_your_pocket.frag.expected b/tests/real/the_real_party_is_in_your_pocket.frag.expected index f0ed28c4..2a5720d7 100644 --- a/tests/real/the_real_party_is_in_your_pocket.frag.expected +++ b/tests/real/the_real_party_is_in_your_pocket.frag.expected @@ -202,7 +202,7 @@ const char *the_real_party_is_in_your_pocket_frag = "vec4 s(vec3 l,vec3 v,out vec3 y)" "{" "float m=10.,f,a;" - "vec2 z,c,i,r;" + "vec2 z,i,c,r;" "vec3 g,u;" "vec4 d=vec4(-1);" "{" @@ -233,13 +233,13 @@ const char *the_real_party_is_in_your_pocket_frag = "if(d.x>0.)" "return y=g,d;" "m=-1.;" - "c=vec2(-1,-3);" - "f=(c.x-l.y)/v.y;" - "a=(c.y-l.z)/v.z;" - "i=s((l-vec3(0,c+2.))*vec3(0,.5,.5),v*vec3(0,.5,.5));" - "r=l.yz+v.yz*i.y-c-2.;" - "if(i.x0.&&r.x<0.&&r.y<0.)" - "y=vec3(-r*.5,0).zxy,m=i.y;" + "i=vec2(-1,-3);" + "f=(i.x-l.y)/v.y;" + "a=(i.y-l.z)/v.z;" + "c=s((l-vec3(0,i+2.))*vec3(0,.5,.5),v*vec3(0,.5,.5));" + "r=l.yz+v.yz*c.y-i-2.;" + "if(c.x0.&&r.x<0.&&r.y<0.)" + "y=vec3(-r*.5,0).zxy,m=c.y;" "else" " if(f>0.&&(fk?" - "(l=c-z*2e-4*-sign(v.z),v+=(vec3(m(),m(),m())-.5)*.1):" - "(l=c+z*2e-4,v=reflect(v,z)+(vec3(m(),m(),m())-.5)*.3);" + "if(m()>k)" + "l=c-z*2e-4*-sign(v.z),v+=(vec3(m(),m(),m())-.5)*.1;" + "else" + " l=c+z*2e-4,v=reflect(v,z)+(vec3(m(),m(),m())-.5)*.3;" "}" "else" " if(u.y<.5||u.y>2.5)" diff --git a/tests/real/valley_ball.glsl.expected b/tests/real/valley_ball.glsl.expected index 443e52cd..4534685c 100644 --- a/tests/real/valley_ball.glsl.expected +++ b/tests/real/valley_ball.glsl.expected @@ -205,11 +205,13 @@ void main() seed=10.; int scene=int(Y.y); rd=vec3(p.xy-.5,1); - scene>22&&scene<27? - (seed=min(1.,sin((Y.y-23.)*pi*.25)*12.),ro=vec3(.12,.005,Y.y*.08),rd=vec3(mm*vec4(rd,1)),rd.y+=.1*cos(Y.y*4.)): - scene>14&&scene<23? - (seed=min(1.,sin((Y.y-15.)*pi*.125)*24.),rd+=vec3(0,.1*cos(Y.y*4.),0),ro=vec3(.08,.01*sin(Y.y*4.)+.002,Y.y*.11)): - (ro=vec3(.1,.004,0)+vec3(.1,.005,20)*vec3(rnd(vec2(scene,seed++)),rnd(vec2(scene,seed++)),rnd(vec2(scene,seed++))),ro=mix(ro+vec3(.008)*vec3(rnd(vec2(scene,seed++)),rnd(vec2(scene,seed++)),rnd(vec2(scene,seed++))),ro+vec3(.008)*vec3(rnd(vec2(scene,seed++)),rnd(vec2(scene,seed++)),rnd(vec2(scene,seed++))),Y.y-float(scene)),ro.y+=height(ro.xz)+.02,ro+=.02*getTerrainNormal(ro),seed=min(1.,step(-28.,-Y.y)*sin((Y.y-float(scene))*pi)*3.)); + if(scene>22&&scene<27) + seed=min(1.,sin((Y.y-23.)*pi*.25)*12.),ro=vec3(.12,.005,Y.y*.08),rd=vec3(mm*vec4(rd,1)),rd.y+=.1*cos(Y.y*4.); + else + if(scene>14&&scene<23) + seed=min(1.,sin((Y.y-15.)*pi*.125)*24.),rd+=vec3(0,.1*cos(Y.y*4.),0),ro=vec3(.08,.01*sin(Y.y*4.)+.002,Y.y*.11); + else + ro=vec3(.1,.004,0)+vec3(.1,.005,20)*vec3(rnd(vec2(scene,seed++)),rnd(vec2(scene,seed++)),rnd(vec2(scene,seed++))),ro=mix(ro+vec3(.008)*vec3(rnd(vec2(scene,seed++)),rnd(vec2(scene,seed++)),rnd(vec2(scene,seed++))),ro+vec3(.008)*vec3(rnd(vec2(scene,seed++)),rnd(vec2(scene,seed++)),rnd(vec2(scene,seed++))),Y.y-float(scene)),ro.y+=height(ro.xz)+.02,ro+=.02*getTerrainNormal(ro),seed=min(1.,step(-28.,-Y.y)*sin((Y.y-float(scene))*pi)*3.); rd=normalize(rd); spherePos=scene>22&&scene<27? ro+.1*vec3(mm*vec4(0,0,1,1)): diff --git a/tests/unit/conditionals.frag.expected b/tests/unit/conditionals.frag.expected index 5957d975..fe878ed1 100644 --- a/tests/unit/conditionals.frag.expected +++ b/tests/unit/conditionals.frag.expected @@ -52,8 +52,9 @@ float ifStmtToExpr(float f) r2=f>1.? 1.: (foo(),2.); - f>1.? - (r3=1.): - (r3=2.,foo()); + if(f>1.) + r3=1.; + else + r3=2.,foo(); return r+r2+r3; } From d2dbaf33ee54fa3a97dc1de41c80e4ef23e0968b Mon Sep 17 00:00:00 2001 From: Laurent Le Brun Date: Sun, 15 Jan 2023 23:27:18 +0100 Subject: [PATCH 18/32] Vector constructor: use float when it's shorter than the int (#216) --- src/rewriter.fs | 7 ++++++- tests/compression_results.log | 4 ++-- tests/real/lunaquatic.frag.expected | 10 +++++----- tests/unit/vectors.frag | 6 +++++- tests/unit/vectors.frag.expected | 5 +++++ 5 files changed, 23 insertions(+), 9 deletions(-) diff --git a/src/rewriter.fs b/src/rewriter.fs index 1d0e609a..94c55d65 100644 --- a/src/rewriter.fs +++ b/src/rewriter.fs @@ -201,7 +201,12 @@ let private simplifyVec constr args = // basic type of the object being constructed, the scalar construction rules (above) are used to convert // the parameters." let useInts = function - | Float (f, _) when Decimal.Round(f) = f -> Int (int f, "") + | Float (f, _) as e when Decimal.Round(f) = f -> + let candidate = Int (int f, "") + if (Printer.exprToS candidate).Length <= (Printer.exprToS e).Length then + candidate + else + e | e -> e // vec3(1,1,1) => vec3(1) diff --git a/tests/compression_results.log b/tests/compression_results.log index dafde291..79f65300 100644 --- a/tests/compression_results.log +++ b/tests/compression_results.log @@ -8,7 +8,7 @@ from-the-seas-to-the-stars.frag 14339 => 2353.070 frozen-wasteland.frag 4588 => 805.076 kinder_painter.frag 2880 => 450.617 leizex.frag 2308 => 515.785 -lunaquatic.frag 5224 => 1058.755 +lunaquatic.frag 5219 => 1058.700 mandelbulb.frag 2369 => 549.088 ohanami.frag 3283 => 750.856 orchard.frag 5588 => 1051.886 @@ -19,4 +19,4 @@ terrarium.frag 3632 => 749.375 the_real_party_is_in_your_pocket.frag 12200 => 1829.607 valley_ball.glsl 4379 => 889.602 yx_long_way_from_home.frag 2992 => 615.970 -Total: 109760 => 19915.120 +Total: 109755 => 19915.064 diff --git a/tests/real/lunaquatic.frag.expected b/tests/real/lunaquatic.frag.expected index 16803f28..014545c8 100644 --- a/tests/real/lunaquatic.frag.expected +++ b/tests/real/lunaquatic.frag.expected @@ -192,20 +192,20 @@ void main() ro=vec3(0,.25,0); float t=Y.z,dist,isoDistance; if(t<16.) - t=ftime(t,0.,16.),t=1.-pow(1.-t,2.),lightPos=vec3(-400,1e2-t*450.,1000),t=(t-1.)*.7,rd=rotateX(rd,-t); + t=ftime(t,0.,16.),t=1.-pow(1.-t,2.),lightPos=vec3(-400,1e2-t*450.,1e3),t=(t-1.)*.7,rd=rotateX(rd,-t); else if(t<32.) - t=ftime(t,16.,32.),t=1.-pow(1.-t,2.),lightPos=vec3(-400,-350.+t*6e2,1000),ro.y-=t*.1; + t=ftime(t,16.,32.),t=1.-pow(1.-t,2.),lightPos=vec3(-400,-350.+t*6e2,1e3),ro.y-=t*.1; else if(t<40.) - lightPos=vec3(-400,250,1000),ro.y-=.1; + lightPos=vec3(-400,250,1e3),ro.y-=.1; else if(t<64.) { int scene=int((t-40.)/6.); if(scene>=3) artifactPos.w=1.; - lightPos=vec3(-400,min(250.,norm(rnd(vec2(scene,2)))*4e2),1000); + lightPos=vec3(-400,min(250.,norm(rnd(vec2(scene,2)))*4e2),1e3); ro.xz+=vec2(.1,20)*vec2(rnd(vec2(scene,5)),rnd(vec2(scene,7))); ro=mix(ro+vec3(.008)*abs(vec3(rnd(vec2(scene,8)),0,rnd(vec2(scene,10)))),ro+vec3(.75)*abs(vec3(rnd(vec2(scene,11)),0,rnd(vec2(scene,13)))),t-40.-float(scene)); ro.y=.2; @@ -214,7 +214,7 @@ void main() else { artifactPos.w=1.; - lightPos=vec3(-400,norm(sin(t+10.))*250.,1000); + lightPos=vec3(-400,norm(sin(t+10.))*250.,1e3); float i=smoothstep(118.,120.,t); ro.xz=artifactPos.xz+mix(vec2(sin(t*.6),cos(t*.6))*mix(sin(t*1.5+10.)+2.,2.,i),vec2(0,2.+.75*(t-EXPLOSIONTIME)),smoothstep(-1.,1.,t-EXPLOSIONTIME)); ro.y=mix(norm(sin(t*3.)*(1.-i))*.3,0.,smoothstep(-1.,1.,t-EXPLOSIONTIME))+.2; diff --git a/tests/unit/vectors.frag b/tests/unit/vectors.frag index 5b2d66c9..2464500d 100644 --- a/tests/unit/vectors.frag +++ b/tests/unit/vectors.frag @@ -8,4 +8,8 @@ float swizzles() { return v1.x + v2.x + v3.x + v4.x + v5.x + v6.x; } -void main() { swizzles(); } +vec4 constructor() { + return vec4(1., 1e2, 2e3, 3e4); +} + +void main() { swizzles(); constructor(); } diff --git a/tests/unit/vectors.frag.expected b/tests/unit/vectors.frag.expected index 515a6145..53ae6f41 100644 --- a/tests/unit/vectors.frag.expected +++ b/tests/unit/vectors.frag.expected @@ -5,7 +5,12 @@ float swizzles() vec4 v4=v1.xxyx,v5=vec4(1,v2.zy,2),v6=vec4(v1.xy,v2.xy); return v1.x+v2.x+v3.x+v4.x+v5.x+v6.x; } +vec4 constructor() +{ + return vec4(1,100,2e3,3e4); +} void main() { swizzles(); + constructor(); } From 9e5aaec48d07e4e872fc6e8dc002d01ccce6e296 Mon Sep 17 00:00:00 2001 From: Laurent Le Brun Date: Mon, 16 Jan 2023 00:06:35 +0100 Subject: [PATCH 19/32] NoMoveDeclarations is the default (#217) --- README.md | 11 +- src/options.fs | 8 +- src/rewriter.fs | 2 +- tests/commands.txt | 8 +- tests/compression_results.log | 42 +- tests/real/audio-flight-v2.frag.expected | 69 ++- tests/real/disco.expected | 2 +- tests/real/ed-209.frag.expected | 40 +- tests/real/elevated.hlsl.expected | 28 +- tests/real/endeavour.frag.expected | 27 +- .../from-the-seas-to-the-stars.frag.expected | 31 +- tests/real/frozen-wasteland.frag.expected | 43 +- tests/real/heart.frag.expected | 18 +- tests/real/kinder_painter.expected | 23 +- tests/real/leizex.expected | 32 +- tests/real/lunaquatic.frag.expected | 17 +- tests/real/mandelbulb.expected | 169 ++++---- tests/real/ohanami.frag.expected | 41 +- tests/real/oscars_chair.frag.expected | 127 +++--- tests/real/slisesix.frag.expected | 90 ++-- tests/real/sult.expected | 21 +- tests/real/terrarium.frag.expected | 5 +- ...real_party_is_in_your_pocket.frag.expected | 399 +++++++++--------- tests/real/to_the_road_of_ribbon.expected | 26 +- tests/real/valley_ball.glsl.expected | 8 +- .../real/yx_long_way_from_home.frag.expected | 220 +++++----- tests/unit/loop.frag.expected | 3 +- 27 files changed, 719 insertions(+), 791 deletions(-) diff --git a/README.md b/README.md index 4a147fed..269003e9 100644 --- a/README.md +++ b/README.md @@ -101,7 +101,7 @@ USAGE: Shader Minifier [--help] [-o ] [-v] [--hlsl] [--aggressive-inlining] [--no-renaming] [--no-renaming-list ] [--no-sequence] [--smoothstep] [--no-remove-unused] - [--no-move-declarations] [...] + [--move-declarations] [...] FILENAMES: @@ -135,8 +135,8 @@ OPTIONS: --no-sequence Do not use the comma operator trick --smoothstep Use IQ's smoothstep trick --no-remove-unused Do not remove unused code - --no-move-declarations - Do not move declarations to group them + --move-declarations + Move declarations to group them --help display this list of options. ``` @@ -531,10 +531,9 @@ c = 4; As shown in the example, the variable name will appear twice (`c` above) while the type will be written only once (`int` above). In some cases, this might make -the shader slightly longer. When the variables are renamed, this should rarely -be an issue. +the shader slightly longer. -Disable this transformation with the flag `--no-move-declarations`. +Enable this transformation with the flag `--move-declarations`. ### Augmented operators diff --git a/src/options.fs b/src/options.fs index 29e51a3d..27059155 100644 --- a/src/options.fs +++ b/src/options.fs @@ -36,7 +36,7 @@ type CliArguments = | [] NoSequence | [] Smoothstep | [] NoRemoveUnused - | [] NoMoveDeclarations + | [] MoveDeclarations | [] Filenames of filename:string list interface IArgParserTemplate with @@ -56,7 +56,7 @@ type CliArguments = | NoSequence -> "Do not use the comma operator trick" | Smoothstep -> "Use IQ's smoothstep trick" | NoRemoveUnused -> "Do not remove unused code" - | NoMoveDeclarations -> "Do not move declarations to group them" + | MoveDeclarations -> "Move declarations to group them" | Filenames _ -> "List of files to minify" type Options() = @@ -74,7 +74,7 @@ type Options() = member val noRenaming = false with get, set member val noRenamingList = ["main"; "mainImage"] with get, set member val noRemoveUnused = false with get, set - member val noMoveDeclarations = false with get, set + member val moveDeclarations = false with get, set member val filenames = [||]: string[] with get, set module Globals = @@ -116,7 +116,7 @@ let private initPrivate argv needFiles = options.noSequence <- args.Contains(NoSequence) options.noRenaming <- args.Contains(NoRenaming) options.noRemoveUnused <- args.Contains(NoRemoveUnused) - options.noMoveDeclarations <- args.Contains(NoMoveDeclarations) + options.moveDeclarations <- args.Contains(MoveDeclarations) options.noRenamingList <- noRenamingList options.filenames <- filenames true diff --git a/src/rewriter.fs b/src/rewriter.fs index 94c55d65..a79701e9 100644 --- a/src/rewriter.fs +++ b/src/rewriter.fs @@ -431,7 +431,7 @@ let private simplifyBlock stmts = let b = squeezeConsecutiveDeclarations b // Group declarations, optionally (may compress poorly). float a,f();float b=4.; -> float a,b;f();b=4.; - let b = if hasPreprocessor || options.noMoveDeclarations then b else groupDeclarations b + let b = if hasPreprocessor || not options.moveDeclarations then b else groupDeclarations b b let private simplifyStmt = function diff --git a/tests/commands.txt b/tests/commands.txt index 8fb7f717..20ea9099 100644 --- a/tests/commands.txt +++ b/tests/commands.txt @@ -10,14 +10,14 @@ --no-remove-unused --no-renaming --format c-variables -o tests/unit/blocks.expected tests/unit/blocks.frag --no-remove-unused --hlsl --no-inlining --no-renaming --format c-variables -o tests/unit/geometry.hlsl.expected tests/unit/geometry.hlsl ---no-remove-unused --no-renaming --no-inlining --format c-array -o tests/unit/operators.expected tests/unit/operators.frag +--no-remove-unused --no-renaming --no-inlining --move-declarations --format c-array -o tests/unit/operators.expected tests/unit/operators.frag --no-renaming --no-inlining --format c-array -o tests/unit/minus-zero.expected tests/unit/minus-zero.frag --no-remove-unused --no-renaming --format c-array --no-inlining -o tests/unit/float.frag.expected tests/unit/float.frag --no-remove-unused --no-renaming --format indented --no-inlining -o tests/unit/nested_if.frag.expected tests/unit/nested_if.frag --format indented -o tests/unit/precision.frag.expected tests/unit/precision.frag --no-remove-unused --format c-array --no-inlining --no-renaming -o tests/unit/verbatim.frag.expected tests/unit/verbatim.frag --no-remove-unused --format indented --no-renaming -o tests/unit/forward_declaration.frag.expected tests/unit/forward_declaration.frag ---no-remove-unused --format indented --no-renaming -o tests/unit/conditionals.frag.expected tests/unit/conditionals.frag +--no-remove-unused --format indented --no-renaming --move-declarations -o tests/unit/conditionals.frag.expected tests/unit/conditionals.frag --no-renaming --no-inlining --format indented -o tests/unit/pi.frag.expected tests/unit/pi.frag --no-renaming --no-inlining --format indented -o tests/unit/vectors.frag.expected tests/unit/vectors.frag --no-renaming --format indented -o tests/unit/deadcode.frag.expected tests/unit/deadcode.frag @@ -44,11 +44,11 @@ # Multifile tests ---no-remove-unused --format c-array -o tests/unit/inout.expected tests/unit/inout.frag tests/unit/inout2.frag +--no-remove-unused --move-declarations --format c-array -o tests/unit/inout.expected tests/unit/inout.frag tests/unit/inout2.frag # Tests with full renaming ---no-remove-unused --no-move-declarations --format c-array --no-inlining -o tests/unit/many_variables.expected tests/unit/many_variables.frag +--no-remove-unused --format c-array --no-inlining -o tests/unit/many_variables.expected tests/unit/many_variables.frag --hlsl -o tests/real/elevated.hlsl.expected tests/real/elevated.hlsl -o tests/real/yx_long_way_from_home.frag.expected tests/real/yx_long_way_from_home.frag -o tests/real/oscars_chair.frag.expected tests/real/oscars_chair.frag diff --git a/tests/compression_results.log b/tests/compression_results.log index 79f65300..bd9237eb 100644 --- a/tests/compression_results.log +++ b/tests/compression_results.log @@ -1,22 +1,22 @@ -audio-flight-v2.frag 4620 => 919.722 -buoy.frag 4194 => 622.602 +audio-flight-v2.frag 4650 => 904.201 +buoy.frag 4239 => 629.709 controllable-machinery.frag 7773 => 1230.829 -ed-209.frag 7888 => 1361.583 -elevated.hlsl 3406 => 611.302 -endeavour.frag 2623 => 544.176 -from-the-seas-to-the-stars.frag 14339 => 2353.070 -frozen-wasteland.frag 4588 => 805.076 -kinder_painter.frag 2880 => 450.617 -leizex.frag 2308 => 515.785 -lunaquatic.frag 5219 => 1058.700 -mandelbulb.frag 2369 => 549.088 -ohanami.frag 3283 => 750.856 -orchard.frag 5588 => 1051.886 -oscars_chair.frag 4648 => 982.231 -robin.frag 6293 => 1066.421 -slisesix.frag 4533 => 956.567 -terrarium.frag 3632 => 749.375 -the_real_party_is_in_your_pocket.frag 12200 => 1829.607 -valley_ball.glsl 4379 => 889.602 -yx_long_way_from_home.frag 2992 => 615.970 -Total: 109755 => 19915.064 +ed-209.frag 7926 => 1363.517 +elevated.hlsl 3416 => 608.543 +endeavour.frag 2661 => 545.443 +from-the-seas-to-the-stars.frag 14371 => 2348.037 +frozen-wasteland.frag 4609 => 815.278 +kinder_painter.frag 2905 => 451.105 +leizex.frag 2327 => 518.373 +lunaquatic.frag 5231 => 1047.616 +mandelbulb.frag 2419 => 548.489 +ohanami.frag 3292 => 739.505 +orchard.frag 5643 => 1036.998 +oscars_chair.frag 4653 => 988.137 +robin.frag 6343 => 1058.401 +slisesix.frag 4587 => 934.011 +terrarium.frag 3634 => 749.630 +the_real_party_is_in_your_pocket.frag 12248 => 1815.725 +valley_ball.glsl 4386 => 888.815 +yx_long_way_from_home.frag 3030 => 615.535 +Total: 110343 => 19837.896 diff --git a/tests/real/audio-flight-v2.frag.expected b/tests/real/audio-flight-v2.frag.expected index 6133448d..f3a2e55b 100644 --- a/tests/real/audio-flight-v2.frag.expected +++ b/tests/real/audio-flight-v2.frag.expected @@ -113,62 +113,52 @@ vec2 edge(vec2 p) float ths=13.25; vec2 map(vec3 p,float sg) { - vec2 res=vec2(100,-1),tun,center,neighbour,d1; - float msize=7.25,obj,pid,trackmod,deg,chs,bmod,height,ids,lq,zprs,d4a,d4,blt,me,next,dlt; - tun=p.xy-path(p.z); - vec3 q=vec3(tun,p.z),o=vec3(tun+vec2(0),p.z+travelSpeed+4.25),s=q,r,fs,qid; + vec2 res=vec2(100,-1); + float msize=7.25; + vec2 tun=p.xy-path(p.z); + vec3 q=vec3(tun,p.z),o=vec3(tun+vec2(0),p.z+travelSpeed+4.25),s=q; o.zx*=r5; o.yz*=r4; o=abs(o)-offWobble*.25; - obj=fBox(o,vec3(.15*offWobble))-.015; + float obj=fBox(o,vec3(.15*offWobble))-.015; if(obj-crop) { - vec3 lp=vec3(0,0,-travelSpeed),ro=vec3(0,0,.15),f,r,u,c,i,rd; + vec3 lp=vec3(0,0,-travelSpeed),ro=vec3(0,0,.15); float x=M.xy==vec2(0)||M.z<0.? 0.: (M.y/R.y-.5)*PI,y=M.xy==vec2(0)||M.z<0.? 0.: - -(M.x/R.x*2.-1.)*PI,d,m; + -(M.x/R.x*2.-1.)*PI; ro.zy*=r2(x); ro+=lp; lp.xy+=path(lp.z); ro.xy+=path(ro.z); - f=normalize(lp-ro); - r=normalize(cross(vec3(0,1,0),f)); - u=normalize(cross(f,r)); - c=ro+f*.183; - i=c+uv.x*r+uv.y*u; - rd=i-ro; + vec3 f=normalize(lp-ro),r=normalize(cross(vec3(0,1,0),f)),u=normalize(cross(f,r)),c=ro+f*.183,i=c+uv.x*r+uv.y*u,rd=i-ro; rd.xy=r2(.2*sin(time*.3)-path(lp.z).x/24.)*rd.xy; rd.xz=r2(y-path(lp.z+1.).y/14.)*rd.xz; vec2 t=marcher(ro,rd,164,1.); - d=t.x; - m=t.y; + float d=t.x,m=t.y; s_hp=g_hp; if(d1.)return vec4(0);{float u=-.4*sign(z)+sin(k*.05),v=sqrt(1.-x*x-y*y),q=y*sin(u)-v*cos(u);y=y*cos(u)+v*sin(u);v=acos(y);u=acos(x/sin(v))/(2.*l)*120.*sign(q)-k;v=v*60./l;q=cos(floor(v/l));c=pow(abs(cos(u)*sin(v)),.2)*.1/(q+sin(float(int((u+l/2.)/l))+k*.6+cos(q*25.)))*pow(1.-c,.9);vec4 res;res=c<0.?vec4(-c/2.*abs(cos(k*.1)),0,-c*2.*abs(sin(k*.04)),1):vec4(c,c*2.,c*2.,1);return res;}}void main(){vec2 p=-1.+2.*gl_FragCoord.xy/resolution.xy;vec4 c=vec4(0),d;for(int i=80;i>0;i--)c+=s(p,1.-float(i)/80.)*(.008-float(i)*5e-5);d=s(p,1.);gl_FragColor=(d.w==0.?s(p,-.2)*.02:d)+sqrt(c);}` +var disco_frag = `uniform vec2 resolution;uniform float time;uniform sampler2D tex0,tex1,tex2,tex3;vec4 s(vec2 px,float z){float l=3.1415,k=time*sign(z),x=px.x*320.*.0065*z,y=px.y*240.*.006*z,c=sqrt(x*x+y*y);if(c>1.)return vec4(0);{float u=-.4*sign(z)+sin(k*.05),v=sqrt(1.-x*x-y*y),q=y*sin(u)-v*cos(u);y=y*cos(u)+v*sin(u);v=acos(y);u=acos(x/sin(v))/(2.*l)*120.*sign(q)-k;v=v*60./l;q=cos(floor(v/l));c=pow(abs(cos(u)*sin(v)),.2)*.1/(q+sin(float(int((u+l/2.)/l))+k*.6+cos(q*25.)))*pow(1.-c,.9);vec4 res;res=c<0.?vec4(-c/2.*abs(cos(k*.1)),0,-c*2.*abs(sin(k*.04)),1):vec4(c,c*2.,c*2.,1);return res;}}void main(){vec2 p=-1.+2.*gl_FragCoord.xy/resolution.xy;vec4 c=vec4(0);for(int i=80;i>0;i--)c+=s(p,1.-float(i)/80.)*(.008-float(i)*5e-5);vec4 d=s(p,1.);gl_FragColor=(d.w==0.?s(p,-.2)*.02:d)+sqrt(c);}` diff --git a/tests/real/ed-209.frag.expected b/tests/real/ed-209.frag.expected index d682ace2..198051ac 100644 --- a/tests/real/ed-209.frag.expected +++ b/tests/real/ed-209.frag.expected @@ -108,7 +108,7 @@ MarchData headLower(vec3 p) { vec3 op=p; MarchData r=headVisor(p*vec3(.95,-1.4,.95),1.,0.); - float roof=max(max(headVisor((p+vec3(0,.01,0))*vec3(.95),1.,0.).d,p.y-.35),p.y*.625-p.z-.66),cheeks; + float roof=max(max(headVisor((p+vec3(0,.01,0))*vec3(.95),1.,0.).d,p.y-.35),p.y*.625-p.z-.66); r.d=min(r.d,roof); p.xy*=rot(.075*(gunsUp-1.)*sign(p.x)); p.x=abs(p.x)-1.33; @@ -120,7 +120,7 @@ MarchData headLower(vec3 p) p=op; p.y=abs(p.y+.16)-.06; p.z-=-1.1; - cheeks=max(sdCappedCylinder(p.xzy,1.,.03),-sdCappedCylinder(p.xzy,.55,1.)); + float cheeks=max(sdCappedCylinder(p.xzy,1.,.03),-sdCappedCylinder(p.xzy,.55,1.)); cheeks=max(cheeks,p.z+.2); r.d=max(r.d,-cheeks); setBodyMaterial(r); @@ -140,7 +140,7 @@ MarchData gunPod(vec3 p) pp=p; pp.x=abs(p.x); pp.xy*=rot(.78525); - float bump=sign(sin(pp.z*33.3))*.003,d=sdBox(pp,vec3(.1-bump,.38-bump,.34))-.02,fs; + float bump=sign(sin(pp.z*33.3))*.003,d=sdBox(pp,vec3(.1-bump,.38-bump,.34))-.02; pp=p-vec3(0,0,-.6); pp.x=abs(pp.x)-.1; d=min(d,sdCappedCylinder(pp,.06,.15)); @@ -148,7 +148,7 @@ MarchData gunPod(vec3 p) d=min(d,sdBox(p+vec3(0,0,.54),vec3(.1,.06,.04))); if(d.5) { d=sdCappedCylinder(pp,.01+pp.z*.05,fract(fs*3322.423)*.5+.9); @@ -191,13 +191,12 @@ MarchData waist(vec3 p) setBodyMaterial(r); p.y+=.65; p.yz*=rot(-.2); - float legAngle=legWalkAngle(1.),bump,d,pistons; + float legAngle=legWalkAngle(1.); p.xy*=rot(legAngle*.3); vec3 pp=p; pp.y+=.3; r.d=max(sdCappedCylinder(pp.zyx,.5,.5),p.y+.15); - bump=.5-abs(sin(p.y*40.))*.03; - d=sdBox(p,vec3(bump,.15,bump)); + float bump=.5-abs(sin(p.y*40.))*.03,d=sdBox(p,vec3(bump,.15,bump)); bump=.3-abs(sin(p.x*40.))*.03; pp.y+=.18; d=min(d,sdCappedCylinder(pp.zyx,bump,.75)); @@ -208,7 +207,7 @@ MarchData waist(vec3 p) r.d=min(r.d,sdBox(pp,vec3(.24,.2,.14+.2*pp.y))); p=pp; pp.xz=abs(pp.xz)-vec2(.12,.25); - pistons=min(sdCappedCylinder(pp.xzy,.1,.325),sdCappedCylinder(pp.xzy,.05,.5)); + float pistons=min(sdCappedCylinder(pp.xzy,.1,.325),sdCappedCylinder(pp.xzy,.05,.5)); r.d=min(r.d,max(pistons,pp.y)); p.y+=.68; r.d=min(r.d,sdBox(p,vec3(sign(abs(p.y)-.04)*.005+.26,.2,.34))); @@ -220,24 +219,24 @@ MarchData legs(vec3 p) { MarchData r; setBodyMaterial(r); - float legAngle=legWalkAngle(1.),silver; + float legAngle=legWalkAngle(1.); p.z+=.27; p.yz*=rot(legAngle*sign(p.x)); p.z-=.27; p.y+=.65; p.yz*=rot(-.2); p.xy*=rot(legAngle*.3); - vec3 pp=p,cp; + vec3 pp=p; pp.x=abs(pp.x); pp.y+=.48; pp.yz*=rot(-.58525); pp.x-=.98; - cp=pp; + vec3 cp=pp; p=pp; pp.xz=abs(pp.xz)-vec2(.12,.25); p.y+=.68; p.xy=abs(p.xy)-.12; - silver=sdBox(p,vec3(.07,.05,1.2)); + float silver=sdBox(p,vec3(.07,.05,1.2)); cp-=vec3(0,-.7,0); r.d=sdBox(cp-vec3(0,0,1.15),vec3(.17,.17,.07))-.04; cp.z+=1.; @@ -273,7 +272,7 @@ MarchData room(vec3 p) vec2 xy=p.xy-vec2(0,2); p.x=abs(p.x); p.yz+=vec2(.5,-3.4); - float doorHole=sdBox(p,frameInner+vec3(0,0,1)),backWall=length(p.z-8.),doorFrame,doorWidth,door,d; + float doorHole=sdBox(p,frameInner+vec3(0,0,1)),backWall=length(p.z-8.); r.d=min(backWall,max(length(p.z),-doorHole+.1)); if(r.d==backWall) { @@ -284,15 +283,14 @@ MarchData room(vec3 p) if(ocp<.3) r.mat=vec3(.39,.57,.71); } - doorFrame=max(sdBox(p,frameInner+vec3(.4,.4,.1)),-doorHole); - doorWidth=frameInner.x*.5; + float doorFrame=max(sdBox(p,frameInner+vec3(.4,.4,.1)),-doorHole),doorWidth=frameInner.x*.5; p.x-=frameInner.x; p.xz*=rot(doorOpen*2.1); p.x+=doorWidth; - door=sdBox(p,vec3(doorWidth,frameInner.yz)); + float door=sdBox(p,vec3(doorWidth,frameInner.yz)); p=abs(p)-vec3(doorWidth*.5,1.1,.14); door=max(door,-max(sdBox(p,vec3(.45,.9,.1)),-sdBox(p,vec3(.35,.8,1)))); - d=min(doorFrame,door); + float d=min(doorFrame,door); if(d.5)" + "float2 x=f+.5/1280;" + "float4 z=tex2D(y,x);" + "float3 w=normalize(mul(m,float4(f.x*2-1,-f.y*2+1,1,1)));" + "float2 s=w.xz/w.y;" + "float c=(2*s.y+1000)%8;" + "float3 r=float3(.55,.65,.75)+.1*D(s+t[3].w*.2,10)+.5*pow(1-w.y,8)+pow(saturate(mul(w,t[3])),16)*float3(.4,.3,.1)+float4(1+.4*c,2,3+.5*c,0)*(1-cos(12.5664*s.y))*saturate(1-abs(s.y)/10-abs(s.x+t[5+c].x*.0012-8)/20)*exp(-t[5+c].x*2e-4);" + "if(z.w>.5)" "{" - "float p=length(s.xyz-t[4].xyz),d=t[1].w-s.y;" + "float p=length(z.xyz-t[4].xyz),d=t[1].w-z.y;" "if(d<0)" "{" - "float3 e=D(s.xz,.001*p,12-log2(p));" - "float o=D(3*s.xz,3),a=D(666*s.xz);" + "float3 e=D(z.xz,.001*p,12-log2(p));" + "float o=D(3*z.xz,3),a=D(666*z.xz);" "r=(.1+.75*t[2].x)*(.8+.2*a);" "r=lerp(r,lerp(float3(.8,.85,.9),float3(.45,.45,.2)*(.8+.2*a),t[2].x),smoothstep(.5-.8*e.y,1-1.1*e.y,o*.15));" "r=lerp(r,lerp(float3(.37,.23,.08),float3(.42,.4,.2),t[2].x)*(.5+.5*a),smoothstep(0,1,50*(e.y-1)+(o+t[2].x)/.4));" - "r*=l(s,e,D(s.xz,.001*p,5));" + "r*=l(z,e,D(z.xz,.001*p,5));" "}" "else" "{" "p=(t[1].w-t[4].y)/w.y;" - "s=t[4]+w.xyzz*p;" - "float3 e=normalize(D(float2(512,32)*s.xz+saturate(d*60)*float2(t[3].w,0),.001*p,4)*float3(1,6,1));" + "z=t[4]+w.xyzz*p;" + "float3 e=normalize(D(float2(512,32)*z.xz+saturate(d*60)*float2(t[3].w,0),.001*p,4)*float3(1,6,1));" "r=.12*(float3(.4,1,1)-float3(.2,.6,.4)*saturate(d*16));" "r*=.3+.7*t[2].x;" "r+=pow(1-mul(-w,e),4)*(pow(mul(t[3],reflect(-w,e)),32)*float3(.32,.31,.3)+.1);" - "r=lerp(r,l(s,e,e),smoothstep(1,0,t[2].x+d*60-D(666*s.xz+saturate(d*60)*float2(t[3].w,0)*2,5))*.5);" + "r=lerp(r,l(z,e,e),smoothstep(1,0,t[2].x+d*60-D(666*z.xz+saturate(d*60)*float2(t[3].w,0)*2,5))*.5);" "}" "r*=.7+.3*smoothstep(0,1,256*abs(d));" "r*=exp(-.042*p);" diff --git a/tests/real/endeavour.frag.expected b/tests/real/endeavour.frag.expected index 635ad031..30f64e24 100644 --- a/tests/real/endeavour.frag.expected +++ b/tests/real/endeavour.frag.expected @@ -8,9 +8,10 @@ void rand(vec2 x,out float num) } void lfnoise(vec2 t,out float num) { - vec2 i=floor(t),v1,v2; + vec2 i=floor(t); t=fract(t); t=smoothstep(c.yy,c.xx,t); + vec2 v1,v2; rand(i,v1.x); rand(i+c.xy,v1.y); rand(i+c.yx,v2.x); @@ -41,9 +42,9 @@ void add(vec2 sda,vec2 sdb,out vec2 dst) } void dhexagonpattern(vec2 p,out float d,out vec2 ind) { - vec2 q=vec2(p.x*1.2,p.y+p.x*.6),pi=floor(q),pf=fract(q),ma; + vec2 q=vec2(p.x*1.2,p.y+p.x*.6),pi=floor(q),pf=fract(q); float v=mod(pi.x+pi.y,3.),ca=step(1.,v),cb=step(2.,v); - ma=step(pf.xy,pf.yx); + vec2 ma=step(pf.xy,pf.yx); d=dot(ma,1.-pf.yx+ca*(pf.x+pf.y-1.)+cb*(pf.yx-2.*pf.xy)); ind=pi+ca-cb*ma; ind=vec2(ind.x/1.2,ind.y); @@ -62,21 +63,23 @@ void scene(vec3 x,out vec2 sdf) vec2 sda=vec2(x.z+.05+.01*n2,1); add(sdf,sda,sdf); } - float R=.07+.1*sdf.x,dis,da,phi,dr,guard; + float R=.07+.1*sdf.x,dis; lfnoise(.5*x.y*c.xx,dis); - vec2 sdb,ya=abs(x.xz-.4*dis*c.xy)+.045*c.yx-.065*c.xy,ind; + vec2 sdb,ya=abs(x.xz-.4*dis*c.xy)+.045*c.yx-.065*c.xy; zextrude(x.y,-length(ya)+R,1e4,sdb.x); + float da; stroke(sdb.x,.003,da); sdb.y=2.; - phi=atan(ya.y,ya.x); + vec2 ind; + float phi=atan(ya.y,ya.x); dhexagonpattern(vec2(56,12)*vec2(x.y,phi),dis,ind); stroke(dis,.2,dis); stroke(sdb.x,.003*step(dis,0.),sdb.x); sdf.x=max(sdf.x,-da); add(sdf,sdb,sdf); - dr=.1; + float dr=.1; vec3 y=mod(x,dr)-.5*dr; - guard=-length(max(abs(y)-vec3(.5*dr*c.xx,.6),0.)); + float guard=-length(max(abs(y)-vec3(.5*dr*c.xx,.6),0.)); guard=abs(guard)+dr*.1; sdf.x=min(sdf.x,guard); } @@ -118,18 +121,18 @@ void mainImage(out vec4 fragColor,vec2 fragCoord) } if(i.5) return 1.; - vec2 p=t.xy*1.8,oop=p,op; + vec2 p=t.xy*1.8,oop=p; p.y*=.8; p.x*=.9; p.y+=pow(clamp(p.x-.7,0,1),2)*.2; - op=p; + vec2 op=p; if(p.y<0) p.y*=mix(1.5,1.6,clamp(p.x,0,1)); p.y*=mix(1.6,1.,.5+.5*cos(clamp((p.x-.6)*11,0.,6.2831852))); p.y-=p.x*.02; p.x=mix(p.x,-.4,pow(clamp((p.x-.6)*1.1,0,1),1.4)); - float d=abs(p.y)+p.x*p.x*.35-.34,oopx; + float d=abs(p.y)+p.x*p.x*.35-.34; p.x-=.9; op.y-=.05; op.y=abs(op.y); @@ -72,7 +72,7 @@ float koi(vec2 t) d=min(d,max(-oop.y,max(oop.x,oop.x*oop.x*4+oop.y-.7))); oop.x+=oop.y*.3+.25; d=min(d,max(oop.y,max(oop.x,oop.x*oop.x*4-oop.y-.5))); - oopx=oop.x+.4; + float oopx=oop.x+.4; d=min(d,max(oop.y,max(oopx,oopx*oopx*4-oop.y-.3))); oop.x+=oop.y*.6-.7; d=min(d,max(oop.y,max(oop.x,oop.x*oop.x*4-oop.y-.3))); @@ -193,7 +193,7 @@ void main() w.y=R(); w.z=R(); w.w=R(); - vec3 camtarget,campos,r,s,t; + vec3 camtarget,campos; if(time>=180+3.5) { makeBG(0.); @@ -388,10 +388,11 @@ void main() ammonite(); time/=3; p=p.zyx; - float t=time-10,c; + float t=time-10; w.x=R(); w.y=R(); w.z=R(); + float c; if(w.x<.1) c=mod(t+w.y,1.+w.z*2),t-=c,col=mix(col,vec3(1,.25,1),c/3.); p.x=-p.x-10+t; @@ -415,10 +416,11 @@ void main() w.z=R(); w.w=R(); w.w=R(); - float t=time,c; + float t=time; w.x=R(); w.y=R(); w.z=R(); + float c; if(w.x<.1) c=mod(t+w.y,1.+w.z*2),t-=c,col=mix(col,vec3(1,.25,1),w.y/3.); p*=vec3(1.7,2,3); @@ -468,10 +470,11 @@ void main() w.z=R(); w.w=R(); w.w=R(); - float t=time,c; + float t=time; w.x=R(); w.y=R(); w.z=R(); + float c; if(w.x<.1) c=mod(t+w.y,1.+w.z*2),t-=c,col=mix(col,vec3(1,.25,1),w.y/3.); p*=vec3(1.7,2,3); @@ -502,14 +505,14 @@ void main() w.y=R(); w.z=R(); w.w=R(); - float t=time,d; + float t=time; if(R()<.1) t-=mod(t+R()*3.,3.); bool bigkoi=w.w0.) { dist=length(planetPos-ro)-dist*8e2; @@ -91,8 +91,8 @@ vec4 calcPlanet(vec3 ro,vec3 rd) } else dist=FAR*99.; - pN=vec3(-.96,.96,-.2); - t=dot(pN,planetPos-ro)/dot(pN,rd); + vec3 pN=vec3(-.96,.96,-.2); + float t=dot(pN,planetPos-ro)/dot(pN,rd); if(t>0.&&t1e2)" - "return f=.5*log(x)/pow(8.,0.),y=vec4(1),false;" - "for(int t=1;t<7;t++)" + "vec4 i=vec4(100);" + "vec3 c=v;" + "float o=dot(c,c);" + "if(o>1e2)" + "return f=.5*log(o)/pow(8.,0.),y=vec4(1),false;" + "for(int x=1;x<7;x++)" "{" "\n#if 0\n" - "float z=sqrt(dot(i,i)),o=acos(i.y/z),c=atan(i.x,i.z);" - "z=pow(z,8.);" - "o*=8.;" - "c*=8.;" - "i=v+z*vec3(sin(o)*sin(c),cos(o),sin(o)*cos(c));" + "float t=sqrt(dot(c,c)),s=acos(c.y/t),z=atan(c.x,c.z);" + "t=pow(t,8.);" + "s*=8.;" + "z*=8.;" + "c=v+t*vec3(sin(s)*sin(z),cos(s),sin(s)*cos(z));" "\n#else\n" - "float s=i.x,d=s*s,n=d*d,m=i.y,l=m*m,p=i.z,w=p*p,r=w*w,g=d+w,a=inversesqrt(g*g*g*g*g*g*g),u=n+l*l+r-6.*l*w-6.*d*l+2.*w*d,q=d-l+w;" - "i.x=v.x+64.*s*m*p*(d-w)*q*(n-6.*d*w+r)*u*a;" - "i.y=v.y+-16.*l*g*q*q+u*u;" - "i.z=v.z+-8.*m*q*(n*n-28.*n*d*w+70.*n*r-28.*d*w*r+r*r)*u*a;" + "float n=c.x,d=n*n,m=d*d,p=c.y,e=p*p,l=c.z,w=l*l,r=w*w,g=d+w,a=inversesqrt(g*g*g*g*g*g*g),u=m+e*e+r-6.*e*w-6.*d*e+2.*w*d,q=d-e+w;" + "c.x=v.x+64.*n*p*l*(d-w)*q*(m-6.*d*w+r)*u*a;" + "c.y=v.y+-16.*e*g*q*q+u*u;" + "c.z=v.z+-8.*p*q*(m*m-28.*m*d*w+70.*m*r-28.*d*w*r+r*r)*u*a;" "\n#endif\n" - "x=dot(i,i);" - "e=min(e,vec4(i.xyz*i.xyz,x));" - "if(x>1e2)" - "return y=e,f=.5*log(x)/pow(8.,float(t)),false;" + "o=dot(c,c);" + "i=min(i,vec4(c.xyz*c.xyz,o));" + "if(o>1e2)" + "return y=i,f=.5*log(o)/pow(8.,float(x)),false;" "}" - "y=e;" + "y=i;" "f=0.;" "return true;" "}" - "bool t(vec3 v,vec3 f,out float y,float e,out vec3 o,out vec4 i,float g)" + "bool t(vec3 v,vec3 f,out float y,float c,out vec3 o,out vec4 x,float g)" "{" - "vec4 x=vec4(0,0,0,1.25),c;" - "vec2 n;" - "if(!t(x,v,f,n))" + "vec4 i=vec4(0,0,0,1.25);" + "vec2 e;" + "if(!t(i,v,f,e))" "return false;" - "if(n.y<.001)" + "if(e.y<.001)" "return false;" - "if(n.x<.001)" - "n.x=.001;" - "if(n.y>e)" - "n.y=e;" - "float d,s;" + "if(e.x<.001)" + "e.x=.001;" + "if(e.y>c)" + "e.y=c;" + "float n;" "vec3 z;" - "s=1./sqrt(1.+g*g);" - "for(float w=n.x;w.001)" - "if(t(m,f,C,1e20,a,h,p))" - "q=.1;" - "r=vec3(1);" - "r=mix(r,vec3(.8,.6,.2),sqrt(g.x)*1.25);" - "r=mix(r,vec3(.8,.3,.3),sqrt(g.y)*1.25);" - "r=mix(r,vec3(.7,.4,.3),sqrt(g.z)*1.25);" - "r*=(.5+.5*n.y)*vec3(.14,.15,.16)*.8+q*vec3(1,.85,.4)+.5*b*vec3(.08,.1,.14);" - "r*=vec3(pow(F,.8),pow(F,1.),pow(F,1.1));" - "r=1.5*(r*.15+.85*sqrt(r));" + "vec3 m=x+u*e;" + "float r=clamp(.2+.8*dot(f,g),0.,1.);" + "r*=r;" + "float q=clamp(.3+.7*dot(o,g),0.,1.),n=clamp(1.25*l.w-.4,0.,1.);" + "n=n*n*.5+.5*n;" + "float b;" + "vec3 F;" + "vec4 C;" + "if(r>.001)" + "if(t(m,f,b,1e20,F,C,y))" + "r=.1;" + "i=vec3(1);" + "i=mix(i,vec3(.8,.6,.2),sqrt(l.x)*1.25);" + "i=mix(i,vec3(.8,.3,.3),sqrt(l.y)*1.25);" + "i=mix(i,vec3(.7,.4,.3),sqrt(l.z)*1.25);" + "i*=(.5+.5*g.y)*vec3(.14,.15,.16)*.8+r*vec3(1,.85,.4)+.5*q*vec3(.08,.1,.14);" + "i*=vec3(pow(n,.8),pow(n,1.),pow(n,1.1));" + "i=1.5*(i*.15+.85*sqrt(i));" "}" - "e=v*.5+.5;" - "r*=.7+4.8*e.x*e.y*(1.-e.x)*(1.-e.y);" - "r=clamp(r,0.,1.);" - "gl_FragColor=vec4(r,1);" + "vec2 r=v*.5+.5;" + "i*=.7+4.8*r.x*r.y*(1.-r.x)*(1.-r.y);" + "i=clamp(i,0.,1.);" + "gl_FragColor=vec4(i,1);" "}"; #endif // MANDELBULB_EXPECTED_ diff --git a/tests/real/ohanami.frag.expected b/tests/real/ohanami.frag.expected index 0df387db..c836c9a9 100644 --- a/tests/real/ohanami.frag.expected +++ b/tests/real/ohanami.frag.expected @@ -11,14 +11,14 @@ float ti,col=1e3,col2=1e3,col3=1e3; float f(vec3 p) { col3=p.y-(.5+.5*cos(p.x*2))*.1; - float d=max(col3,length(p.xz)-5.5),s=1,ss=1.6,scale; + float d=max(col3,length(p.xz)-5.5),s=1,ss=1.6; if(ti<1) return d; vec3 w=normalize(vec3(-1,1.2,-1)),u=normalize(cross(w,vec3(0,1,0))); if(ti>12&&ti<18) col2=(length(mod(p*2-1.02+ti/2,2)-1)-mix(.001,.06,(ti-12)/5))/2,d=min(d,col2); int j=int(min(floor(ti-1),7)); - scale=min(.3+ti/6,1); + float scale=min(.3+ti/6,1); p/=scale; for(int i=0;d=min(d,scale*max(p.y-1,max(-p.y,length(p.xz)-.1/(p.y+.7)))/s),p.xz=abs(p.xz),p.y-=1,i8&&ti<12) zoom=ti-6,filmoffset=vec2(cos(ti*2),sin(ti*3))/3; if(ti>25&&ti<29) zoom=5.5,filmoffset=vec2(cos(ti*2),sin(ti*3))/3; - vec3 ro=vec3(-2.5,.5+cos(ti*17)*.1,3),rd=normalize(vec3(t.xy+filmoffset,zoom)),camtarget,w,u,v,ld,ld,rp; + vec3 ro=vec3(-2.5,.5+cos(ti*17)*.1,3),rd=normalize(vec3(t.xy+filmoffset,zoom)); if(ti==10) ro.y+=2; - camtarget=vec3(0,1.3,0); - w=normalize(camtarget-ro); - u=normalize(cross(w,vec3(0,1,0))); - v=normalize(cross(w,-u)); + vec3 camtarget=vec3(0,1.3,0),w=normalize(camtarget-ro),u=normalize(cross(w,vec3(0,1,0))),v=normalize(cross(w,-u)); rd=mat3(u,v,w)*rd; gl_FragColor.xyz=vec3(.8,.8,1)/6; - t=0.; - d=0.; + float t=0.,d=0.; for(int i=0;i<100;++i) { d=f(ro+rd*t); @@ -82,33 +78,25 @@ void main() gl_FragColor.xyz=vec3(1,.7,.8); if(col3<.02&&(ti<17||ti>22)) gl_FragColor.xyz=vec3(.5,1,.6)/3; - ld=normalize(vec3(1,3+cos(ti)/2,1+sin(ti*3)/2)); - e=.01; - d2=f(ro+rd*t+ld*e); - l=max(0,(d2-d)/e); - d3=f(ro+rd*t+vec3(0,1,0)*e); - l2=max(0,.5+.5*(d3-d)/e); + vec3 ld=normalize(vec3(1,3+cos(ti)/2,1+sin(ti*3)/2)); + float e=.01,d2=f(ro+rd*t+ld*e),l=max(0,(d2-d)/e),d3=f(ro+rd*t+vec3(0,1,0)*e),l2=max(0,.5+.5*(d3-d)/e); { vec3 rp=ro+rd*t; if(ti>12&&ti<22) if(col2<.01||d3+d2/7>.0017&&pow(valnoise(rp.xz*8),2)>abs(ti-18)/5.) gl_FragColor.xyz=vec3(.65); } - ld=normalize(vec3(1,3+cos(ti)/2,1+sin(ti*3)/2)); - e=.01; - d2=f(ro+rd*t+ld*e); - l=max(0,(d2-d)/e); - d3=f(ro+rd*t+vec3(0,1,0)*e); - l2=max(0,.5+.5*(d3-d)/e); + vec3 ld=normalize(vec3(1,3+cos(ti)/2,1+sin(ti*3)/2)); + float e=.01,d2=f(ro+rd*t+ld*e),l=max(0,(d2-d)/e),d3=f(ro+rd*t+vec3(0,1,0)*e),l2=max(0,.5+.5*(d3-d)/e); { vec3 rp=ro+rd*t; if(ti>12&&ti<17) if(col2<.01||d3+d2/7>.0017&&valnoise(rp.xz*8)<(ti-12)/3.) gl_FragColor.xyz=vec3(.65); } - rp=ro+rd*(t-.001); + vec3 rp=ro+rd*(t-.001); t=.1; - sh=1.; + float sh=1.; for(int i=0;i<30;++i) { d=f(rp+ld*t)+.01; @@ -122,7 +110,7 @@ void main() else { vec3 c=vec3(.8,.8,1)/6; - vec2 p=t.xy,e,p2; + vec2 p=t.xy; for(int n=0;n<2;++n) { float maxr=mix(1./22.,.25,1.-n)*.4; @@ -146,8 +134,7 @@ void main() } } } - e=vec2(.001,0); - p2=p+(valnoise(p*18)-.5)*.01; + vec2 e=vec2(.001,0),p2=p+(valnoise(p*18)-.5)*.01; float c0=dot(vec3(1./3.),samp(p2).xyz),c1=dot(vec3(1./3.),samp(p2+e.xy).xyz),c2=dot(vec3(1./3.),samp(p2+e.yx*1.8).xyz); c*=vec3(mix(.1,1,1.-clamp(max(abs(c2-c0),abs(c1-c0))*4,0,.13))); c=(c-.5)*1.1+.5; diff --git a/tests/real/oscars_chair.frag.expected b/tests/real/oscars_chair.frag.expected index 632cc134..4a22ea9a 100644 --- a/tests/real/oscars_chair.frag.expected +++ b/tests/real/oscars_chair.frag.expected @@ -9,16 +9,16 @@ const char *oscars_chair_frag = "#version 130\n" "vec2 v=gl_FragCoord.xy/1280;" "uniform sampler2D a;" - "float y=gl_TexCoord[0].x/44100,i,m,s=1,r;" - "vec3 c=vec3(7,5,19),z=vec3(-4,0,3),f,x,g=vec3(0,5,-7),e;" - "float n(vec2 x,float v)" + "float y=gl_TexCoord[0].x/44100,i,m,s=1,f;" + "vec3 c=vec3(7,5,19),z=vec3(-4,0,3),x,r,g=vec3(0,5,-7),e;" + "float n(vec2 r,float v)" "{" "float y=0,c=1,m=1;" - "for(int f=0;f25&&y<=60&&a.y<1)" - "f=mix(f,vec3(1,.01,.01)/9,smoothstep(.2,.204,n(a,2.3)));" - "m=.15+.017*n(v*vec2(.12,12)+n(v,2)/2,1.4)+f.x/2;" - "f*=pow(m,4)*168;" + "x=mix(x,vec3(1,.01,.01)/9,smoothstep(.2,.204,n(a,2.3)));" + "m=.15+.017*n(v*vec2(.12,12)+n(v,2)/2,1.4)+x.x/2;" + "x*=pow(m,4)*168;" "return m;" "}" - "if(abs(v.x)<1.5&&abs(v.y-3)<3&&x.z<-c.z+.1)" + "if(abs(v.x)<1.5&&abs(v.y-3)<3&&r.z<-c.z+.1)" "{" - "f=vec3(n(v*vec2(1,.2),2)+2)/4;" + "x=vec3(n(v*vec2(1,.2),2)+2)/4;" "v=abs(v+n(v,2)/60-vec2(0,3));" "if(v.x>1.475||v.y>2.975)" - "f*=.3;" + "x*=.3;" "return 11-clamp(abs(max(abs(v.x-.7)+.3,abs(v.y-1.4)-.3)-.7),.05,.14)*11+n(v*vec2(1,.2),2.5);" "}" "m=1-smoothstep(.1,.12,n(v/2+10,2.5)-.1);" - "f=mix(vec3(.7),mix(vec3(1,1,.5)/1.4+n(v*8,1.2)/15,vec3(.65,1,.5),m)/4*min(v.y*3-1.5+.8,1),step(.5,v.y))-step(.4,n(v*3,1.6))/140;" - "return n(v,2)/2-f.y*4;" + "x=mix(vec3(.7),mix(vec3(1,1,.5)/1.4+n(v*8,1.2)/15,vec3(.65,1,.5),m)/4*min(v.y*3-1.5+.8,1),step(.5,v.y))-step(.4,n(v*3,1.6))/140;" + "return n(v,2)/2-x.y*4;" "}" "vec3 t(vec2 v,out vec3 y)" "{" - "f=vec3(.004,0,0);" - "return normalize(vec3(p(v+f.xy,y)-p(v-f.xy,y),.16,p(v+f.yx,y)-p(v-f.yx,y)));" + "x=vec3(.004,0,0);" + "return normalize(vec3(p(v+x.xy,y)-p(v-x.xy,y),.16,p(v+x.yx,y)-p(v-x.yx,y)));" "}" "float n(vec3 v)" "{" - "float x=y>81?" + "float r=y>81?" "-1.4:" "-2.827;" "v-=z;" - "v.y+=(n(v.xz*=mat2(cos(x),sin(x),-sin(x),cos(x)),2.5)/2+.5)*clamp(y/3-29,0,5)+c.y-1.25;" + "v.y+=(n(v.xz*=mat2(cos(r),sin(r),-sin(r),cos(r)),2.5)/2+.5)*clamp(y/3-29,0,5)+c.y-1.25;" "v.x+=n(v.yz,2.5)*clamp(y/3-29,0,5)-max(0,v.y)/10;" "v.z=abs(v.z);" "return min(min(min(max(length(max(abs(v.xz)-vec2(.45,.41),0))-.25,abs(v.y)-.02),length(v-vec3(clamp(v.x,-.6,.6),-.1,.6))-.025),length(vec3(abs(v.x)-.6+min(0,v.y)/5,v.y-clamp(v.y,-1.24,1.5*step(0,v.x)),v.z-.6))-.025),max(length(max(abs(v.yz-vec2(1,0))-vec2(.5,.35),0))-.25,abs(v.x-.6)-.03));" "}" "float h(vec3 v,vec3 y)" "{" - "float x=0,f=0;" - "for(;f<200&&x<30;++f)" + "float x=0,r=0;" + "for(;r<200&&x<30;++r)" "i=min(i,m=n(v+y*x)),x+=m/2;" "return x;" "}" "vec3 w(vec3 v,vec3 a)" "{" - "vec3 r;" - "x=v+a*(m=min((sign(a.x)*c.x-v.x)/a.x,min((sign(a.y)*c.y-v.y)/a.y,(sign(a.z)*c.z-v.z)/a.z)));" - "if(abs(x.y)>c.y-.001)" - "i=0,f=t(x.xz/2,r),r*=min(vec3(.75,1,.75)+min(c.x-abs(x.x),c.z-abs(x.z))/4,1)*smoothstep(0,2.2,length(x-z-vec3(0,-c.y+1.25,0)));" + "vec3 f;" + "r=v+a*(m=min((sign(a.x)*c.x-v.x)/a.x,min((sign(a.y)*c.y-v.y)/a.y,(sign(a.z)*c.z-v.z)/a.z)));" + "if(abs(r.y)>c.y-.001)" + "i=0,x=t(r.xz/2,f),f*=min(vec3(.75,1,.75)+min(c.x-abs(r.x),c.z-abs(r.z))/4,1)*smoothstep(0,2.2,length(r-z-vec3(0,-c.y+1.25,0)));" "else" "{" "i=1;" - "f=t(vec2(x.x-x.z-c.z,x.y+c.y),r).xzy;" - "if(abs((x/c).x)>abs((x/c).z)&&abs((x/c).x)>abs((x/c).y))" - "f=f.zyx*vec3(-sign(x.x),1,-1);" - "r*=mix(vec3(1,1,.5),vec3(1),min((-abs(x.y)+c.y)/4,1))*sqrt(min((-abs(x.y)+c.y)*8+.4,1));" + "x=t(vec2(r.x-r.z-c.z,r.y+c.y),f).xzy;" + "if(abs((r/c).x)>abs((r/c).z)&&abs((r/c).x)>abs((r/c).y))" + "x=x.zyx*vec3(-sign(r.x),1,-1);" + "f*=mix(vec3(1,1,.5),vec3(1),min((-abs(r.y)+c.y)/4,1))*sqrt(min((-abs(r.y)+c.y)*8+.4,1));" "}" - "r*=mix(4,1,smoothstep(1,2,length(x/c)))*max(0,1+3*dot(f,normalize(g-x)))/16*(1-smoothstep(0,2.5,length(max(abs(x)-c+1,0))));" - "r=(r+pow(clamp(dot(normalize(normalize(g-x)-a),f),0,1),64)*(r*.8+.2))*exp2(-length(g-x)/1.2)*s*20*mix(.02,2,smoothstep(.6,.7,dot(normalize(g-x),e)));" + "f*=mix(4,1,smoothstep(1,2,length(r/c)))*max(0,1+3*dot(x,normalize(g-r)))/16*(1-smoothstep(0,2.5,length(max(abs(r)-c+1,0))));" + "f=(f+pow(clamp(dot(normalize(normalize(g-r)-a),x),0,1),64)*(f*.8+.2))*exp2(-length(g-r)/1.2)*s*20*mix(.02,2,smoothstep(.6,.7,dot(normalize(g-r),e)));" "if(y<=97)" - "r+=pow(vec3(2.2,.7,.3)*exp(-abs(n(x.xz/2+x.y/4-y/2,1.5))*10*n(-x.xy+y-x.z,1.5)+n(x.xy-y/3,2)*6-x.y-c.y-x.z-c.z+(y-88)/4+x.x/9),vec3(2))/70;" - "return r;" + "f+=pow(vec3(2.2,.7,.3)*exp(-abs(n(r.xz/2+r.y/4-y/2,1.5))*10*n(-r.xy+y-r.z,1.5)+n(r.xy-y/3,2)*6-r.y-c.y-r.z-c.z+(y-88)/4+r.x/9),vec3(2))/70;" + "return f;" "}" "void main()" "{" @@ -107,55 +107,54 @@ const char *oscars_chair_frag = "vec3 t=vec3(0);" "for(int p=0;p<8;++p)" "{" - "float l=2.7,d;" - "vec3 o=vec3(10+y/4,-4,-1),b=vec3(-7,-2,0),u,C;" + "float l=2.7;" + "vec3 o=vec3(10+y/4,-4,-1),d=vec3(-7,-2,0);" "m=0;" "if(y>97)" - "b=o=vec3(0,-4,y-97),b.z-=1,g=vec3(0,3,-22),s=.4,c=vec3(3,7,28),z=vec3(-4,0,13);" + "d=o=vec3(0,-4,y-97),d.z-=1,g=vec3(0,3,-22),s=.4,c=vec3(3,7,28),z=vec3(-4,0,13);" "else" " if(y>81)" - "b=o=vec3(0,-3.6,97-y),b.z-=1,g=vec3(0,5,-5),s=.01,l=1.7,c=vec3(7,5,9),z=vec3(0,0,-2);" + "d=o=vec3(0,-3.6,97-y),d.z-=1,g=vec3(0,5,-5),s=.01,l=1.7,c=vec3(7,5,9),z=vec3(0,0,-2);" "else" " if(y>60)" - "o=vec3((y-60)/5-1,-2,13),b=vec3(-7,-5,-7),g=vec3(0,5,-3),m=sin(y-60)/10-.9,c=vec3(7,5,9),z=vec3(-4,0,2);" + "o=vec3((y-60)/5-1,-2,13),d=vec3(-7,-5,-7),g=vec3(0,5,-3),m=sin(y-60)/10-.9,c=vec3(7,5,9),z=vec3(-4,0,2);" "else" " if(y>25)" - "o=vec3(0,0,25-y/2.7),b=vec3(0,-4,18-y/2.7),g=vec3(-2,5,-7),c=vec3(9,5,14),z=vec3(3.5,0,-6);" + "o=vec3(0,0,25-y/2.7),d=vec3(0,-4,18-y/2.7),g=vec3(-2,5,-7),c=vec3(9,5,14),z=vec3(3.5,0,-6);" "else" " m=-.9;" - "r=7;" + "f=7;" "e=vec3(0,cos(m),sin(m));" - "u=normalize(b-o);" - "C=normalize(vec3(-u.z,0,u.x));" + "vec3 u=normalize(d-o),b=normalize(vec3(-u.z,0,u.x));" "if(y>81&&y<=97)" - "u.y+=n(vec2(y+6)/2,2)*.05,C.y+=n(vec2(y)/3,2)*.08;" - "u=mat3(C,cross(C,u),u)*normalize(vec3(v*2+vec2(p&1,p/2)/1200-1,l));" - "d=h(o,u);" - "if(d<30)" - "x=o+u*d,f=vec3(.02,0,0),f=normalize(vec3(n(x+f.xyy)-m,n(x+f.yxy)-m,n(x+f.yyx)-m)),r=2,C=w(x,reflect(u,f))*pow(1+dot(u,f),3);" + "u.y+=n(vec2(y+6)/2,2)*.05,b.y+=n(vec2(y)/3,2)*.08;" + "u=mat3(b,cross(b,u),u)*normalize(vec3(v*2+vec2(p&1,p/2)/1200-1,l));" + "float C=h(o,u);" + "if(C<30)" + "r=o+u*C,x=vec3(.02,0,0),x=normalize(vec3(n(r+x.xyy)-m,n(r+x.yxy)-m,n(r+x.yyx)-m)),f=2,b=w(r,reflect(u,x))*pow(1+dot(u,x),3);" "else" "{" - "C=w(o,u);" - "l=(.3+.7*pow(1+dot(u,f),2)/4)*(.1+.9*step(x.y,-c.y+.01));" - "o=reflect(u,f);" - "d=m;" - "r=2;" + "b=w(o,u);" + "l=(.3+.7*pow(1+dot(u,x),2)/4)*(.1+.9*step(r.y,-c.y+.01));" + "o=reflect(u,x);" + "C=m;" + "f=2;" "i=1e2;" - "u=normalize(g-x);" - "h(x+u*.01,u);" - "C*=.4+.6*smoothstep(0,n(x)/5,i);" - "if(x.y<-c.y+.01)" - "if(h(x,o)<30)" - "l*=.2,C*=.7;" - "C+=w(x,o)*l*mix(vec3(1),C,.8);" + "u=normalize(g-r);" + "h(r+u*.01,u);" + "b*=.4+.6*smoothstep(0,n(r)/5,i);" + "if(r.y<-c.y+.01)" + "if(h(r,o)<30)" + "l*=.2,b*=.7;" + "b+=w(r,o)*l*mix(vec3(1),b,.8);" "}" "if(y>60&&y<=97)" "gl_FragColor.w=y<=81?" - "(d-15)/6:" - "d/15;" - "C*=smoothstep(0,2,abs(y-60))*smoothstep(0,3,abs(y-112))*(1-(pow(abs(v.x*2-1),4)+pow(abs(v.y*2-1)*2.5,4))*.4);" - "C=pow(.003+C*40,vec3(1,1.1,1.2));" - "t+=C/(C+.4)*1.1;" + "(C-15)/6:" + "C/15;" + "b*=smoothstep(0,2,abs(y-60))*smoothstep(0,3,abs(y-112))*(1-(pow(abs(v.x*2-1),4)+pow(abs(v.y*2-1)*2.5,4))*.4);" + "b=pow(.003+b*40,vec3(1,1.1,1.2));" + "t+=b/(b+.4)*1.1;" "}" "m=0;" "for(int p=0;p<64;++p)" diff --git a/tests/real/slisesix.frag.expected b/tests/real/slisesix.frag.expected index 44cd3fa5..b717cf0f 100644 --- a/tests/real/slisesix.frag.expected +++ b/tests/real/slisesix.frag.expected @@ -41,64 +41,47 @@ float distToBox(vec3 p,vec3 abc) float columna(float x,float y,float z,float mindist,float offx) { vec3 p=vec3(x,y,z); - float di0=distToBox(p,vec3(.14,1,.14)),y2,y3,y4,di1,di2,di3,di4,di9,di5,di6,di7,di8,di; + float di0=distToBox(p,vec3(.14,1,.14)); if(di0>mindist*mindist) return mindist+1.; - y2=y-.4; - y3=y-.35; - y4=y-1.; - di1=distToBox(p,vec3(.1,1,.1)); - di2=distToBox(p,vec3(.12,.4,.12)); - di3=distToBox(p,vec3(.05,.35,.14)); - di4=distToBox(p,vec3(.14,.35,.05)); - di9=distToBox(vec3(x,y4,z),vec3(.14,.02,.14)); - di5=distToBox(vec3((x-y2)*.7071,(y2+x)*.7071,z),vec3(.07071,.07071,.12)); - di6=distToBox(vec3(x,(y2+z)*.7071,(z-y2)*.7071),vec3(.12,.07071,.07071)); - di7=distToBox(vec3((x-y3)*.7071,(y3+x)*.7071,z),vec3(.07071,.07071,.14)); - di8=distToBox(vec3(x,(y3+z)*.7071,(z-y3)*.7071),vec3(.14,.07071,.07071)); - di=min(min(min(di1,di2),min(di3,di4)),min(min(di5,di6),min(di7,di8))); + float y2=y-.4,y3=y-.35,y4=y-1.,di1=distToBox(p,vec3(.1,1,.1)),di2=distToBox(p,vec3(.12,.4,.12)),di3=distToBox(p,vec3(.05,.35,.14)),di4=distToBox(p,vec3(.14,.35,.05)),di9=distToBox(vec3(x,y4,z),vec3(.14,.02,.14)),di5=distToBox(vec3((x-y2)*.7071,(y2+x)*.7071,z),vec3(.07071,.07071,.12)),di6=distToBox(vec3(x,(y2+z)*.7071,(z-y2)*.7071),vec3(.12,.07071,.07071)),di7=distToBox(vec3((x-y3)*.7071,(y3+x)*.7071,z),vec3(.07071,.07071,.14)),di8=distToBox(vec3(x,(y3+z)*.7071,(z-y3)*.7071),vec3(.14,.07071,.07071)),di=min(min(min(di1,di2),min(di3,di4)),min(min(di5,di6),min(di7,di8))); di=min(di,di9); return di; } float bicho(vec3 x,float mindist) { x-=vec3(.64,.5,1.5); - float r2=dot(x,x),sa=smoothstep(0.,.5,r2),fax=.75+.25*sa,r,a1,si1,co1,mindist2,rr,ca,c,a; + float r2=dot(x,x),sa=smoothstep(0.,.5,r2),fax=.75+.25*sa; x.x*=fax; x.y*=.8+.2*sa; x.z*=fax; r2=dot(x,x); - r=sqrt(r2); - a1=1.-smoothstep(0.,.75,r); + float r=sqrt(r2),a1=1.-smoothstep(0.,.75,r); a1*=.4; - si1=sin(a1); - co1=cos(a1); + float si1=sin(a1),co1=cos(a1); x.xy=mat2(co1,si1,-si1,co1)*x.xy; - mindist2=1e5; - rr=.05+sqrt(dot(x.xz,x.xz)); - ca=.46625-6.*rr*exp2(-10.*rr); + float mindist2=1e5,rr=.05+sqrt(dot(x.xz,x.xz)),ca=.46625-6.*rr*exp2(-10.*rr); for(int j=1;j<7;j++) { - float an=6.2831/7.*float(j),aa=an+.4*rr*noise3f(vec3(4.*rr,2.5,an))+.29,rc=cos(aa),rs=sin(aa),dd; + float an=6.2831/7.*float(j),aa=an+.4*rr*noise3f(vec3(4.*rr,2.5,an))+.29,rc=cos(aa),rs=sin(aa); vec3 q=vec3(x.x*rc-x.z*rs,x.y+ca,x.x*rs+x.z*rc); - dd=dot(q.yz,q.yz); + float dd=dot(q.yz,q.yz); if(q.x>0.&&q.x<1.5&&dd>10&7)>6) peld=1.; dis+=.005*peld; @@ -106,8 +89,7 @@ float map(vec3 pos,out int sid,out int submat) sid=0; if(peld>1e-7) sid=2; - fx=fract(pos.x+128.); - fz=fract(pos.z+128.); + float fx=fract(pos.x+128.),fz=fract(pos.z+128.); if(pos.y>1.) { dis=max(techo(fx,pos.y),techo(fz,pos.y)); @@ -174,41 +156,40 @@ void main() if(matID!=666) { - vec3 nor=calcNormal(pos),lig; - float kke=1e-4,bumpa=.0075,kk,spe,llig,im,dif,dif2,ao,totao,sca,so; + vec3 nor=calcNormal(pos); + float kke=1e-4,bumpa=.0075; if(matID!=5) bumpa*=.75; if(matID==4) bumpa*=.5; bumpa/=kke; - kk=fbm(32.*pos); + float kk=fbm(32.*pos); nor.x+=bumpa*(fbm(32.*vec3(pos.x+kke,pos.yz))-kk); nor.y+=bumpa*(fbm(32.*vec3(pos.x,pos.y+kke,pos.z))-kk); nor.z+=bumpa*(fbm(32.*vec3(pos.xy,pos.z+kke))-kk); nor=normalize(nor); - spe=0.; - lig=vec3(.5-pos.x,.8-pos.y,1.5-pos.z); - llig=dot(lig,lig); - im=inversesqrt(llig); + float spe=0.; + vec3 lig=vec3(.5-pos.x,.8-pos.y,1.5-pos.z); + float llig=dot(lig,lig),im=inversesqrt(llig); lig*=im; - dif=dot(nor,lig); + float dif=dot(nor,lig); dif=matID==4? .5+.5*dif: .1+.9*dif; dif=clamp(dif,0.,1.); dif*=2.5*exp2(-1.75*llig); - dif2=(nor[0]+nor[1])*.075; + float dif2=(nor[0]+nor[1])*.075; if(matID==0) { - float xoff=13.1*float(subMatID&255),fb=fbm(16.*vec3(pos.x+xoff,pos.yz)),baldscale,fx,m; + float xoff=13.1*float(subMatID&255),fb=fbm(16.*vec3(pos.x+xoff,pos.yz)); rgb=vec3(.7)+fb*vec3(.2,.22,.25); - baldscale=float(subMatID>>9&15)/14.; + float baldscale=float(subMatID>>9&15)/14.; baldscale=.51+.34*baldscale; rgb*=baldscale; - fx=1.; + float fx=1.; if((subMatID&256)!=0) fx=-1.; - m=sin(64.*pos.z*fx+64.*pos.x+4.*fb); + float m=sin(64.*pos.z*fx+64.*pos.x+4.*fb); m=smoothstep(.25,.5,m)-smoothstep(.5,.75,m); rgb+=m*vec3(.15); } @@ -225,11 +206,11 @@ void main() else if(matID==4) { - float ft=fbm(16.*pos),fs,fre; + float ft=fbm(16.*pos); rgb=vec3(.82,.73,.65)+ft*vec3(.1); - fs=.9+.1*fbm(32.*pos); + float fs=.9+.1*fbm(32.*pos); rgb*=fs; - fre=max(-dot(nor,rd),0.); + float fre=max(-dot(nor,rd),0.); rgb-=vec3(fre*fre*.45); spe=clamp((nor.y-nor.z)*.707,0.,1.); spe=.2*pow(spe,32.); @@ -239,26 +220,25 @@ void main() float fb=fbm(16.*pos); rgb=vec3(.64,.61,.59)+fb*vec3(.21,.19,.19)+dif2; } - totao=0.; - sca=10.; + float ao,totao=0.,sca=10.; for(int aoi=0;aoi<5;aoi++) { - float hr=.01+.015*float(aoi*aoi),dd; + float hr=.01+.015*float(aoi*aoi); vec3 aopos=nor*hr+pos; int kk,kk2; - dd=map(aopos,kk,kk2); + float dd=map(aopos,kk,kk2); ao=-(dd-hr); totao+=ao*sca; sca*=.5; } ao=1.-clamp(totao,0.,1.); - so=0.; + float so=0.; for(int i=0;i<6;i++) { - float h=float(i)/6.,dd; + float h=float(i)/6.; vec3 aopos=lig*(.01+h)+pos; int kk,kk2; - dd=map(aopos,kk,kk2); + float dd=map(aopos,kk,kk2); so+=(1.-h)*dd*2.*(10./6.); } dif*=clamp((so-.4)*1.5,0.,1.); diff --git a/tests/real/sult.expected b/tests/real/sult.expected index 7d7ef18e..fc3253c3 100644 --- a/tests/real/sult.expected +++ b/tests/real/sult.expected @@ -35,20 +35,19 @@ const char *sult_frag = "void main()" "{" "vec2 l=-1.+2.*gl_FragCoord.xy/r.xy;" - "vec3 i=normalize(rotatey(rotatey(vec3(l.y*z,l.x*z*1.33,1),-y*.035).yxz,(a+x*c)*.035)),p=n+s*c,u,h,F;" - "float C=1.,b=0.,Z,Y,X=0.,W,V,U,T;" - "u=vec3(.01,0,0);" - "h=u.yyy;" - "for(;C>.1;)" + "vec3 i=normalize(rotatey(rotatey(vec3(l.y*z,l.x*z*1.33,1),-y*.035).yxz,(a+x*c)*.035)),p=n+s*c;" + "float u=1.,h=0.,F,C,b=0.,Z,Y,X,W;" + "vec3 V=vec3(.01,0,0),U=V.yyy,T;" + "for(;u>.1;)" "{" - "for(Z=X,Y=1.;Z.005;Z+=Y)" - "Y=e(p+i*Z);" - "if(Z.005;F+=C)" + "C=e(p+i*F);" + "if(F.01)" - "i+=mix(.02,pow(max(0.,v(l.xy-vec2(0,.25+pow(abs(l.x),3.)),vec2(.32,.94))-.05)*1e2,1.3)/1500.,1.-x(-.001,z));" + "z+=mix(.02,pow(max(0.,v(l.xy-vec2(0,.25+pow(abs(l.x),3.)),vec2(.32,.94))-.05)*1e2,1.3)/1500.,1.-x(-.001,i));" "if(l.z<0.)" - "a=v(a,m(l-vec3(0,0,-.1),vec3(.5,.5,.055))-.04,64.);" - "c.x-=.09;" - "c.y+=.635;" - "f=m(f,i,192.);" - "r=f;" - "s=.001+v(length(c)-.01,v(length(c-vec2(.036,0))-.01,length(c-vec2(-.036,0))-.01,40.),40.);" - "f=m(f,-l.z-.09,64.);" + "s=v(s,m(l-vec3(0,0,-.1),vec3(.5,.5,.055))-.04,64.);" + "f.x-=.09;" + "f.y+=.635;" + "a=m(a,z,192.);" + "float r=a,c=.001+v(length(f)-.01,v(length(f-vec2(.036,0))-.01,length(f-vec2(-.036,0))-.01,40.),40.);" + "a=m(a,-l.z-.09,64.);" "if(l.z<0.)" - "f=v(f,m(r+.03,a,64.),256.);" + "a=v(a,m(r+.03,s,64.),256.);" "r=1.;" - "f=m(m(f,min(l.z,-s+.003),256.),min(l.z,-abs(z)-.001),448.);" - "f=m(f,min(l.z-.13,-v(l.xy-vec2(0,-.118))),512.);" - "f=m(f,min(l.z-.13,-abs(length(vec2(max(abs(l.x)-.12,0.),l.y+.117))-.035)+.003),512.);" - "f=m(m(f,min(1.,-min(1.,max(m(abs(l.x)-.31,abs(l.y-.49)-.29,5e2),abs(l.z-.185)-.1))+.004),576.),-abs(l.z-.01)-1e-4,384.);" + "a=m(m(a,min(l.z,-c+.003),256.),min(l.z,-abs(i)-.001),448.);" + "a=m(a,min(l.z-.13,-v(l.xy-vec2(0,-.118))),512.);" + "a=m(a,min(l.z-.13,-abs(length(vec2(max(abs(l.x)-.12,0.),l.y+.117))-.035)+.003),512.);" + "a=m(m(a,min(1.,-min(1.,max(m(abs(l.x)-.31,abs(l.y-.49)-.29,5e2),abs(l.z-.185)-.1))+.004),576.),-abs(l.z-.01)-1e-4,384.);" "if(l.y<0.)" "{" "if(l.y<-.5)" - "f+=(1.-smoothstep(-.001,.002,m(l+vec3(0,.03,-.2),.13,.007,.001,true)))*.005,f=m(f,-m(l+vec3(0,0,-.2),.13,.007,.001,false),1024.);" + "a+=(1.-smoothstep(-.001,.002,m(l+vec3(0,.03,-.2),.13,.007,.001,true)))*.005,a=m(a,-m(l+vec3(0,0,-.2),.13,.007,.001,false),1024.);" "vec2 d=vec2(-.32,-.314),p=vec2(.124,.033);" - "float h=length(l.xy-vec2(.405,-.28))-.07,t=length(l.xy-vec2(.202,-.345))-.07,e=v(v(l.xy-d,p)-.005,v(l.xy-d,p.yx)-.005,512.),b,w,k,g,o;" - "f=m(f,min(l.z,-h+.004),320.);" - "f=m(f,min(l.z,-t+.004),320.);" - "f=m(f,min(l.z,-min(1.,e)+.006),192.);" + "float h=length(l.xy-vec2(.405,-.28))-.07,t=length(l.xy-vec2(.202,-.345))-.07,e=v(v(l.xy-d,p)-.005,v(l.xy-d,p.yx)-.005,512.);" + "a=m(a,min(l.z,-h+.004),320.);" + "a=m(a,min(l.z,-t+.004),320.);" + "a=m(a,min(l.z,-min(1.,e)+.006),192.);" "l.xy-=vec2(.405,-.28);" - "b=(1.-x(.002,min(min(n(l.xy,vec2(0,-.035),vec2(-.014,.024)),n(l.xy,vec2(-.03,-.035),vec2(-.014,.024))),n(l.xy,vec2(-.02),vec2(-.01,-.02)))-.0025))*.002;" + "float g=(1.-x(.002,min(min(n(l.xy,vec2(0,-.035),vec2(-.014,.024)),n(l.xy,vec2(-.03,-.035),vec2(-.014,.024))),n(l.xy,vec2(-.02),vec2(-.01,-.02)))-.0025))*.002;" "l.xy+=vec2(.405,-.28);" "l.xy-=vec2(.202,-.345);" - "w=min(min(min(n(l.xy,vec2(-.03,-.035),vec2(-.03,.024)),n(l.xy,vec2(-.03,-.035),vec2(-.018,-.035))),n(l.xy,vec2(-.03,.024),vec2(-.018,.024))),n(l.xy,vec2(-.03,-.0055),vec2(-.018,-.0055)));" + "float w=min(min(min(n(l.xy,vec2(-.03,-.035),vec2(-.03,.024)),n(l.xy,vec2(-.03,-.035),vec2(-.018,-.035))),n(l.xy,vec2(-.03,.024),vec2(-.018,.024))),n(l.xy,vec2(-.03,-.0055),vec2(-.018,-.0055)));" "if(l.x>-.018)" "w=min(min(w,abs(length(l.xy-vec2(-.018,-.02025))-.01475)),abs(length(l.xy-vec2(-.018,.00925))-.01475));" "w=(1.-x(.002,w-.0025))*.002;" "l.xy+=vec2(.202,-.345);" - "k=max(-l.z,m(abs(l.z)-.17,max(-.015,s),96.));" - "g=min(max(-l.z,m(abs(l.z)-.17+w,t,128.)),max(-l.z,m(abs(l.z)-.17+b,h,128.)));" - "vec3 u=l;" - "u.z-=pow(length(l.xy-d),2.)/2.-.01;" - "g=m(min(g,max(-l.z,m(abs(u.z)-.18,e,768.))),-(length(u-vec3(d,.19))-.026),512.);" - "u.xy-=d;" - "u.xy=abs(u.xy);" - "if(u.x0.)" - "c=vec2(c.x-o*c.y,-o*c.x-c.y)/2.;" - "c.x-=clamp(c.x,-2.,0.);" - "g=m(g,-max(-u.z,-length(c)*sign(c.y)+.565),512.);" - "if(g0.)" + "f=vec2(f.x-u*f.y,-u*f.x-f.y)/2.;" + "f.x-=clamp(f.x,-2.,0.);" + "b=m(b,-max(-o.z,-length(f)*sign(f.y)+.565),512.);" + "if(b0.&&o.x0.&&o.xo.y||abs(k)<1e-5)" + "k=x(r+p*b);" + "d=k.x;" + "if(b>o.y||abs(d)<1e-5)" "break;" - "e+=k;" + "b+=d;" "}" - "if(e0.)" - "return y=g,d;" + "if(i.x>0.)" + "return y=f,i;" "m=-1.;" - "i=vec2(-1,-3);" - "f=(i.x-l.y)/v.y;" - "a=(i.y-l.z)/v.z;" - "c=s((l-vec3(0,i+2.))*vec3(0,.5,.5),v*vec3(0,.5,.5));" - "r=l.yz+v.yz*c.y-i-2.;" - "if(c.x0.&&r.x<0.&&r.y<0.)" - "y=vec3(-r*.5,0).zxy,m=c.y;" + "vec2 o=vec2(-1,-3);" + "float r=(o.x-l.y)/v.y,b=(o.y-l.z)/v.z;" + "vec2 d=s((l-vec3(0,o+2.))*vec3(0,.5,.5),v*vec3(0,.5,.5)),p=l.yz+v.yz*d.y-o-2.;" + "if(d.x0.&&p.x<0.&&p.y<0.)" + "y=vec3(-p*.5,0).zxy,m=d.y;" "else" - " if(f>0.&&(f0.&&(r0.&&(a5.||abs(u.y)>2.5||abs(u.z)>3.3?" + " if(b>0.&&(b5.||abs(w.y)>2.5||abs(w.z)>3.3?" "vec4(-1):" "vec4(m,0,0,0);" "}" @@ -258,165 +251,165 @@ const char *the_real_party_is_in_your_pocket_frag = "}" "vec3 h(vec3 l,vec3 v)" "{" - "vec3 f=vec3(0),a=vec3(1);" - "bool y=false;" + "vec3 y=vec3(0),f=vec3(1);" + "bool a=false;" "for(int i=0;i<4;++i)" "{" "v=normalize(v);" - "vec3 z,p,e,c,r;" - "vec4 u=s(l,v,z);" - "float d=u.x,g,k;" - "if(d<0.)" + "vec3 z,p,k;" + "vec4 r=s(l,v,z);" + "float b=r.x;" + "if(b<0.)" "{" - "f+=max(a*vec3(.9)*(.5+.5*dot(v,normalize(vec3(-2,4,1))))*.4*1.3*vec3(1,.9,.65)+a*vec3(.9)*step(.9,dot(v,normalize(vec3(6,2,1))))*10.4*2.3+a*vec3(.9)*step(.95,dot(v,normalize(vec3(-2,1,3))))*10.4*1.5,0.)*pow(max(.5+.5*-v.z,0.),.2);" + "y+=max(f*vec3(.9)*(.5+.5*dot(v,normalize(vec3(-2,4,1))))*.4*1.3*vec3(1,.9,.65)+f*vec3(.9)*step(.9,dot(v,normalize(vec3(6,2,1))))*10.4*2.3+f*vec3(.9)*step(.95,dot(v,normalize(vec3(-2,1,3))))*10.4*1.5,0.)*pow(max(.5+.5*-v.z,0.),.2);" "break;" "}" - "g=floor(u.y/8.);" - "u.y=mod(u.y,8.);" - "c=l+v*d;" - "vec2 o=vec2(6.28319*m(),m()*2.-1.);" - "r=z+vec3(sqrt(1.-o.y*o.y)*vec2(cos(o.x),sin(o.x)),o.y);" - "k=u.y>1.5?" - "mix(c.x>0.?" + "float w=floor(r.y/8.);" + "r.y=mod(r.y,8.);" + "vec3 o=l+v*b;" + "vec2 d=vec2(6.28319*m(),m()*2.-1.);" + "vec3 c=z+vec3(sqrt(1.-d.y*d.y)*vec2(cos(d.x),sin(d.x)),d.y);" + "float e=r.y>1.5?" + "mix(o.x>0.?" ".1:" ".05,.5,pow(1.-clamp(dot(-v,z),0.,1.),2.)):" "mix(.2,.8,pow(1.-clamp(dot(-v,z),0.,1.),1.5));" - "if(u.y>5.5&&u.y<6.5)" + "if(r.y>5.5&&r.y<6.5)" "{" - "if(y)" + "if(a)" "break;" - "l=c+z*2e-4;" - "a*=mix(.1,.8,pow(1.-clamp(dot(-v,z),0.,1.),3.))*mix(vec3(1),vec3(1,.9,.5),.5);" + "l=o+z*2e-4;" + "f*=mix(.1,.8,pow(1.-clamp(dot(-v,z),0.,1.),3.))*mix(vec3(1),vec3(1,.9,.5),.5);" "v=reflect(v,z)+(vec3(m(),m(),m())-.5)*.3;" "}" "else" - " if(u.y>4.5&&u.y<5.5)" + " if(r.y>4.5&&r.y<5.5)" "{" - "if(y)" + "if(a)" "break;" - "k=.02;" - "if(m()>k)" - "l=c-z*2e-4*-sign(v.z),v+=(vec3(m(),m(),m())-.5)*.1;" + "e=.02;" + "if(m()>e)" + "l=o-z*2e-4*-sign(v.z),v+=(vec3(m(),m(),m())-.5)*.1;" "else" - " l=c+z*2e-4,v=reflect(v,z)+(vec3(m(),m(),m())-.5)*.3;" + " l=o+z*2e-4,v=reflect(v,z)+(vec3(m(),m(),m())-.5)*.3;" "}" "else" - " if(u.y<.5||u.y>2.5)" + " if(r.y<.5||r.y>2.5)" "{" - "vec3 b=u.y>2.5?" + "vec3 t=r.y>2.5?" "vec3(.08):" "vec3(.7);" - "if(u.y>3.5)" + "if(r.y>3.5)" "{" - "b=vec3(.008);" - "if(!y)" + "t=vec3(.008);" + "if(!a)" "{" - "if(c.y>.5)" + "if(o.y>.5)" "{" - "vec2 w=u.zw-vec2(-.38,.6);" - "float h=min(min(min(min(min(min(max(length(w-vec2(.005))-.0125,-(length(w-vec2(-.012,.005))-.025)),max(length(w-vec2(-.02,.005))-.0125,-(length(w-vec2(-.045,.005))-.03))),max(length(w-vec2(.005))-.0125,-(length(w-vec2(-.012,.005))-.025))),max(length(w-vec2(.03,.005))-.0125,-(length(w-vec2(.02,.005))-.02))),abs(length(w-vec2(-.037,-.0398))-.0104)),n(w,vec2(-.064,-.05),vec2(-.064,-.03))),max(-w.x-.063,abs(length(vec2(max(0.,w.x+.06),w.y+.035))-.006)));" - "w.x-=.091;" - "h=min(h,n(w,vec2(-.064,-.05),vec2(-.064,-.03)));" - "h=min(h,max(-w.x-.063,abs(length(vec2(max(0.,w.x+.06),w.y+.035))-.006)));" - "h=min(h,n(w,vec2(-.054,-.05),vec2(-.059,-.041)));" - "w.x+=.091;" - "h=min(h,n(w,vec2(.009,-.05),vec2(.009,-.03)));" - "h=min(h,n(w,vec2(.009,-.05),vec2(.018,-.05)));" - "h=min(h,n(w,vec2(.009,-.03),vec2(.018,-.03)));" - "h=min(h,n(w,vec2(.009,-.039),vec2(.018,-.039)));" - "w.x=abs(w.x+.01);" - "w.x=abs(w.x-.006);" - "h=min(h,n(w,vec2(0,-.05),vec2(.006,-.03)));" - "b=mix(b,vec3(.3),step(h-.0018,0.));" + "vec2 h=r.zw-vec2(-.38,.6);" + "float g=min(min(min(min(min(min(max(length(h-vec2(.005))-.0125,-(length(h-vec2(-.012,.005))-.025)),max(length(h-vec2(-.02,.005))-.0125,-(length(h-vec2(-.045,.005))-.03))),max(length(h-vec2(.005))-.0125,-(length(h-vec2(-.012,.005))-.025))),max(length(h-vec2(.03,.005))-.0125,-(length(h-vec2(.02,.005))-.02))),abs(length(h-vec2(-.037,-.0398))-.0104)),n(h,vec2(-.064,-.05),vec2(-.064,-.03))),max(-h.x-.063,abs(length(vec2(max(0.,h.x+.06),h.y+.035))-.006)));" + "h.x-=.091;" + "g=min(g,n(h,vec2(-.064,-.05),vec2(-.064,-.03)));" + "g=min(g,max(-h.x-.063,abs(length(vec2(max(0.,h.x+.06),h.y+.035))-.006)));" + "g=min(g,n(h,vec2(-.054,-.05),vec2(-.059,-.041)));" + "h.x+=.091;" + "g=min(g,n(h,vec2(.009,-.05),vec2(.009,-.03)));" + "g=min(g,n(h,vec2(.009,-.05),vec2(.018,-.05)));" + "g=min(g,n(h,vec2(.009,-.03),vec2(.018,-.03)));" + "g=min(g,n(h,vec2(.009,-.039),vec2(.018,-.039)));" + "h.x=abs(h.x+.01);" + "h.x=abs(h.x-.006);" + "g=min(g,n(h,vec2(0,-.05),vec2(.006,-.03)));" + "t=mix(t,vec3(.3),step(g-.0018,0.));" "}" - "if(length(u.zw-vec2(-.43,.605))<.014)" - "f+=a*3.*vec3(1,.01,.01)*(.8+8.*(1.-x(.01,length(u.zw-vec2(-.43,.605)))));" - "if(u.w>0.&&c.y<.2)" + "if(length(r.zw-vec2(-.43,.605))<.014)" + "y+=f*3.*vec3(1,.01,.01)*(.8+8.*(1.-x(.01,length(r.zw-vec2(-.43,.605)))));" + "if(r.w>0.&&o.y<.2)" "{" - "b=mix(b,vec3(.3),step(n(u.zw-vec2(0,.103)),0.));" + "t=mix(t,vec3(.3),step(n(r.zw-vec2(0,.103)),0.));" "{" - "vec2 h=vec2(-.07,.02),w=vec2(-.09,.03),t=vec2(-.1,0),q=t+normalize(t-w)*.03,C=vec2(-.065,-.026);" - "b=mix(b,vec3(.520661,.00153787,.064975),step(min(m(u.zw-vec2(.16,.103),t,q,C),m(u.zw-vec2(.16,.103),h,w,t))-.007,0.));" + "vec2 g=vec2(-.07,.02),h=vec2(-.09,.03),u=vec2(-.1,0),q=u+normalize(u-h)*.03,C=vec2(-.065,-.026);" + "t=mix(t,vec3(.520661,.00153787,.064975),step(min(m(r.zw-vec2(.16,.103),u,q,C),m(r.zw-vec2(.16,.103),g,h,u))-.007,0.));" "}" "{" - "vec2 w=u.zw-vec2(.16,.103);" - "w-=vec2(-.029,-.015);" - "w.x+=cos(w.y*30.)*.01;" - "w.y-=cos(w.x*20.)*.01;" - "b=mix(b,vec3(.093564,.0865052,.434048),step(abs(length(w)-.02)-.007,0.));" + "vec2 h=r.zw-vec2(.16,.103);" + "h-=vec2(-.029,-.015);" + "h.x+=cos(h.y*30.)*.01;" + "h.y-=cos(h.x*20.)*.01;" + "t=mix(t,vec3(.093564,.0865052,.434048),step(abs(length(h)-.02)-.007,0.));" "}" "{" - "vec2 w=u.zw-vec2(.16,.103),h=vec2(-.01,.02),t=vec2(-.007,0),C=vec2(-.007,-.0205),q=C+normalize(C-t)*.01,F=vec2(.02,-.02);" - "b=mix(b,vec3(.186082,.481799,.0177778),step(min(m(w,C,q,F),m(w,h,t,C))-.007,0.));" + "vec2 h=r.zw-vec2(.16,.103),g=vec2(-.01,.02),u=vec2(-.007,0),q=vec2(-.007,-.0205),C=q+normalize(q-u)*.01,F=vec2(.02,-.02);" + "t=mix(t,vec3(.186082,.481799,.0177778),step(min(m(h,q,C,F),m(h,g,u,q))-.007,0.));" "}" "{" - "vec2 w=u.zw-vec2(.16,.103);" - "w-=vec2(.045,-.015);" - "w.x+=cos(w.y*20.+1.)*.005;" - "w.y-=cos(w.x*20.+25.)*.01;" - "b=mix(b,vec3(.730857,.454964,.000553633),step(abs(length(w)-.02)-.007,0.));" + "vec2 h=r.zw-vec2(.16,.103);" + "h-=vec2(.045,-.015);" + "h.x+=cos(h.y*20.+1.)*.005;" + "h.y-=cos(h.x*20.+25.)*.01;" + "t=mix(t,vec3(.730857,.454964,.000553633),step(abs(length(h)-.02)-.007,0.));" "}" "{" - "vec2 w=u.zw-vec2(.24,.103),h=vec2(-.006,-.026),t=vec2(-.002,0),C=vec2(-.007,.016),q=C+normalize(C-t)*.012,F=vec2(.02),T=q+normalize(F-q)*.05,Z=vec2(.002,-.007),Y=vec2(.025,-.028);" - "b=mix(b,vec3(0,.332318,.292872),step(min(min(min(m(w,C,q,F),m(w,h,t,C)),m(w,F,T,Z)),m(w,Z,(Z+Y)/2.+vec2(.001),Y))-.007,0.));" + "vec2 h=r.zw-vec2(.24,.103),g=vec2(-.006,-.026),u=vec2(-.002,0),q=vec2(-.007,.016),C=q+normalize(q-u)*.012,F=vec2(.02),T=C+normalize(F-C)*.05,Z=vec2(.002,-.007),Y=vec2(.025,-.028);" + "t=mix(t,vec3(0,.332318,.292872),step(min(min(min(m(h,q,C,F),m(h,g,u,q)),m(h,F,T,Z)),m(h,Z,(Z+Y)/2.+vec2(.001),Y))-.007,0.));" "}" "}" "{" - "vec2 w=vec2(160,144)/1.5,h=(u.zw-vec2(-.001,.486))*3.75*vec2(w.y/w.x,1)*.5+.5,t=fract(h*w);" - "h=floor(h*w)/w;" - "if(max(abs(h.x-.5),abs(h.y-.5))<.5)" + "vec2 h=vec2(160,144)/1.5,g=(r.zw-vec2(-.001,.486))*3.75*vec2(h.y/h.x,1)*.5+.5,u=fract(g*h);" + "g=floor(g*h)/h;" + "if(max(abs(g.x-.5),abs(g.y-.5))<.5)" "{" "vec3 q=vec3(0);" - "vec2 C=(h*2.-1.)*vec2(w.x/w.y,1);" - "float F=min(min(min(min(min(min(min(min(min(min(min(min(min(min(min(min(min(n(vec4(1.54,.53,.91,.72),C),n(vec4(.63,.78,.91,.72),C)),n(vec4(.61,1.675,.72,.64),C)),n(vec4(2.7,3.11,.72,.64),C)),n(vec4(3.45,3.65,.72,.64),C)),n(vec4(4.71,5.02,.72,.64),C)),n(vec4(5.3,5.51,.72,.64),C)),n(vec4(5.96,6.43,.72,.64),C)),n(vec4(3.2,1.27,.45,.35),C)),n(vec4(1.3,2.3,.45,.35),C)),n(vec4(2.58,4.2,.45,.35),C)),n(vec4(3.2,3.95,.35,.25),C)),n(vec4(5.2,5.93,.35,.25),C)),n(vec4(7.9,8.15,.35,.25),C)),n(vec4(.2,1.16,.32,.17),C)),max(length(C)-.84,-length(C)+.72)),max(length(C)-.52,-length(C)+.45)),max(length(C)-.17,-length(C)+.08)),Z=floor(h.y*8.);" + "vec2 C=(g*2.-1.)*vec2(h.x/h.y,1);" + "float F=min(min(min(min(min(min(min(min(min(min(min(min(min(min(min(min(min(n(vec4(1.54,.53,.91,.72),C),n(vec4(.63,.78,.91,.72),C)),n(vec4(.61,1.675,.72,.64),C)),n(vec4(2.7,3.11,.72,.64),C)),n(vec4(3.45,3.65,.72,.64),C)),n(vec4(4.71,5.02,.72,.64),C)),n(vec4(5.3,5.51,.72,.64),C)),n(vec4(5.96,6.43,.72,.64),C)),n(vec4(3.2,1.27,.45,.35),C)),n(vec4(1.3,2.3,.45,.35),C)),n(vec4(2.58,4.2,.45,.35),C)),n(vec4(3.2,3.95,.35,.25),C)),n(vec4(5.2,5.93,.35,.25),C)),n(vec4(7.9,8.15,.35,.25),C)),n(vec4(.2,1.16,.32,.17),C)),max(length(C)-.84,-length(C)+.72)),max(length(C)-.52,-length(C)+.45)),max(length(C)-.17,-length(C)+.08)),Z=floor(g.y*8.);" "q=.5+.5*cos(vec3(.8,.3,2)*(Z+1.));" "q=mix(q,vec3(1),step(F,0.));" "q*=vec3(1,1,.8);" - "q*=smoothstep(.1,.2,t.x)*smoothstep(.1,.2,t.y);" - "f+=a*3.*q;" - "b=vec3(.1);" + "q*=smoothstep(.1,.2,u.x)*smoothstep(.1,.2,u.y);" + "y+=f*3.*q;" + "t=vec3(.1);" "}" "}" "}" "}" - "if(u.y>3.&&u.y<3.2)" - "b=vec3(.4);" - "a*=b;" - "l=c+z*2e-4;" - "v=r;" - "y=true;" + "if(r.y>3.&&r.y<3.2)" + "t=vec3(.4);" + "f*=t;" + "l=o+z*2e-4;" + "v=c;" + "a=true;" "}" "else" "{" - "vec3 w=g>1.5?" + "vec3 h=w>1.5?" "vec3(1,.02,.2):" - "g>.5?" + "w>.5?" "vec3(.2,1,.02):" "vec3(.02,.2,1);" - "if(m()>mix(.2,1.,k))" + "if(m()>mix(.2,1.,e))" "{" - "if(u.y>1.5)" - "w=vec3(.02);" - "a*=w;" - "l=c+z*2e-4;" - "v=r;" - "y=true;" + "if(r.y>1.5)" + "h=vec3(.02);" + "f*=h;" + "l=o+z*2e-4;" + "v=c;" + "a=true;" "}" "else" "{" - "if(y)" + "if(a)" "break;" - "a*=u.y>1.5?" + "f*=r.y>1.5?" "vec3(.5):" - ".9*mix(w,vec3(1),.25);" - "l=c+z*2e-4;" + ".9*mix(h,vec3(1),.25);" + "l=o+z*2e-4;" "v=reflect(v,z)+(vec3(m(),m(),m())-.5)*.4;" "}" "}" - "if(max(a.x,max(a.y,a.z))<.001)" + "if(max(f.x,max(f.y,f.z))<.001)" "break;" "}" - "return f;" + "return y;" "}" "void main()" "{" @@ -424,11 +417,11 @@ const char *the_real_party_is_in_your_pocket_frag = "for(int v=0;v<16;++v)" "{" "y=float(v)+gl_TexCoord[0].x*16.;" - "float w=m()*6.28319;" - "vec2 f=vec2(cos(w),sin(w))*sqrt(1.-sqrt(1.-m()))*1.2;" + "float a=m()*6.28319;" + "vec2 x=vec2(cos(a),sin(a))*sqrt(1.-sqrt(1.-m()))*1.2;" "if(int(y)%4==0)" - "f*=15.*length(f);" - "l+=h(vec3(0,0,4.8),vec3((gl_FragCoord.xy-vec2(960,540)+f)/540.,-3.5))/48.;" + "x*=15.*length(x);" + "l+=h(vec3(0,0,4.8),vec3((gl_FragCoord.xy-vec2(960,540)+x)/540.,-3.5))/48.;" "}" "l/=(l+1.)/2.;" "gl_FragColor.xyz=pow(l+.01*vec3(1,1,.5),vec3(1./2.2))+m()/1e2;" diff --git a/tests/real/to_the_road_of_ribbon.expected b/tests/real/to_the_road_of_ribbon.expected index ea722071..88bfa319 100644 --- a/tests/real/to_the_road_of_ribbon.expected +++ b/tests/real/to_the_road_of_ribbon.expected @@ -28,22 +28,22 @@ const char *to_the_road_of_ribbon_frag = "{" "vec2 t=-1.+2.*gl_FragCoord.xy/resolution.xy;" "t.x*=resolution.x/resolution.y;" - "vec4 v=vec4(1),c;" - "vec3 o=vec3(sin(time)*.5,cos(time*.5)*.25+.25,time),m=normalize(vec3(t.x*1.6,t.y,1)),y=o,n;" - "float e=0.,f;" + "vec4 v=vec4(1);" + "vec3 o=vec3(sin(time)*.5,cos(time*.5)*.25+.25,time),c=normalize(vec3(t.x*1.6,t.y,1)),y=o,f;" + "float e=0.;" "for(int r=0;r<64;r++)" - "e=o(y),y+=e*m;" - "n=y;" - "f=length(y-o)*.02;" - "m=reflect(m,gn(y));" - "y+=m;" - "for(int r=0;r<64;r++)" - "e=o(y),y+=e*m;" + "e=o(y),y+=e*c;" + "f=y;" + "float r=length(y-o)*.02;" + "c=reflect(c,gn(y));" + "y+=c;" + "for(int m=0;m<64;m++)" + "e=o(y),y+=e*c;" "v=max(dot(gn(y),vec3(.1,.1,0)),0.)+vec4(.3,cos(time*.5)*.5+.5,sin(time*.5)*.5+.5,1)*min(length(y-o)*.04,1.);" - "if(oa(n)>ob(n))" + "if(oa(f)>ob(f))" "v=mix(v,vec4(cos(time*.3)*.5+.5,cos(time*.2)*.5+.5,sin(time*.3)*.5+.5,1),.3);" - "c=(v+vec4(f)+(1.-min(n.y+1.9,1.))*vec4(1,.8,.7,1))*min(time*.5,1.);" - "gl_FragColor=vec4(c.xyz,1);" + "vec4 m=(v+vec4(r)+(1.-min(f.y+1.9,1.))*vec4(1,.8,.7,1))*min(time*.5,1.);" + "gl_FragColor=vec4(m.xyz,1);" "}"; #endif // TO_THE_ROAD_OF_RIBBON_EXPECTED_ diff --git a/tests/real/valley_ball.glsl.expected b/tests/real/valley_ball.glsl.expected index 4534685c..64bdadd0 100644 --- a/tests/real/valley_ball.glsl.expected +++ b/tests/real/valley_ball.glsl.expected @@ -15,9 +15,9 @@ float rnd(vec2 x) float smoothrnd(vec2 x) { x=mod(x,1e3); - vec2 a=fract(x),u; + vec2 a=fract(x); x-=a; - u=a*a*(3.-2.*a); + vec2 u=a*a*(3.-2.*a); return mix(mix(rnd(x+vec2(0)),rnd(x+vec2(1,0)),u.x),mix(rnd(x+vec2(0,1)),rnd(x+vec2(1)),u.x),u.y); } float norm(float x) @@ -195,14 +195,14 @@ void main() Y.z=1.; Y.w=1.333; p=-1.+2.*gl_FragCoord.xy/resolution.xy; - float angle=1.570796*Y.y-1.570796,seed; + float angle=1.570796*Y.y-1.570796; mat4 mm=mat4(cos(angle),0.,sin(angle),0.,0.,1.,0.,0.,-sin(angle),0.,cos(angle),0.,0.,0.,0.,1.); gf_DetailLevel=1e2; pi=3.1416; interlacing=vec3(1.2,.9,.9); eps=1e-4; bigeps=.01; - seed=10.; + float seed=10.; int scene=int(Y.y); rd=vec3(p.xy-.5,1); if(scene>22&&scene<27) diff --git a/tests/real/yx_long_way_from_home.frag.expected b/tests/real/yx_long_way_from_home.frag.expected index 4e7477a8..49c1e41b 100644 --- a/tests/real/yx_long_way_from_home.frag.expected +++ b/tests/real/yx_long_way_from_home.frag.expected @@ -15,153 +15,154 @@ const char *yx_long_way_from_home_frag = "uniform sampler2D v;" "mat2 n(float v)" "{" - "float y=cos(v),x=sin(v);" - "return mat2(y,-x,x,y);" + "float x=cos(v),f=sin(v);" + "return mat2(x,-f,f,x);" "}" "vec2 s(const float v)" "{" "return fract(sin(vec2(v,v+1.))*vec2(43758.5453123));" "}" - "int i;" + "int f;" "float e(vec2 v)" "{" - "vec2 y=vec2(.125,0),x=v-clamp(v,-y,y);" - "return length(x.xy);" + "vec2 x=vec2(.125,0),f=v-clamp(v,-x,x);" + "return length(f.xy);" "}" - "float f(vec2 v)" + "float p(vec2 v)" "{" "return smoothstep(.5,1.,cos(v.x*10.))*1.5+sin(v.x*1e2)*.5+.5;" "}" - "float t(vec3 y)" + "float t(vec3 i)" "{" - "float x=1e9,n,r;" - "x=min(x,length(y-vec3(0,5,0))-2.5);" - "vec3 c=y,l;" + "float x=1e9;" + "x=min(x,length(i-vec3(0,5,0))-2.5);" + "vec3 c=i;" "c.x=abs(c.x-1.1)-.2;" - "n=max(length(c.xz+vec2(0,5))-.01,c.y-5.);" - "l=y;" - "if(y.y<.3)" + "float s=max(length(c.xz+vec2(0,5))-.01,c.y-5.);" + "vec3 n=i;" + "if(i.y<.3)" "{" - "y.y+=texture(v,y.xz*.125).x*9e-4;" - "y.y+=texture(v,y.xz*2.*.125).x*.0011;" - "y.y+=texture(v,y.xz*4.*.125).x*.0021;" - "y.y+=texture(v,y.xz*4.*.0625).x*.0051;" - "y.y+=texture(v,y.xz*4.*.03125).x*.01;" - "y.y+=sin(y.x*2.)*.05;" - "y.y-=length(sin(y.xz*.5))*.1;" - "y.z+=sin(y.x*.5)*.5;" - "y.z+=step(.5,mod(y.x,1.))*.3-.15;" - "y.x=mod(y.x,.5)-.25;" - "float s=e(y.xz),z=smoothstep(.1,.13,s);" - "y.y+=.1-z*.03;" - "y.y-=smoothstep(.05,0.,abs(s-.16))*.004;" - "y.y-=(1.-z)*.01*f(y.xz);" + "i.y+=texture(v,i.xz*.125).x*9e-4;" + "i.y+=texture(v,i.xz*2.*.125).x*.0011;" + "i.y+=texture(v,i.xz*4.*.125).x*.0021;" + "i.y+=texture(v,i.xz*4.*.0625).x*.0051;" + "i.y+=texture(v,i.xz*4.*.03125).x*.01;" + "i.y+=sin(i.x*2.)*.05;" + "i.y-=length(sin(i.xz*.5))*.1;" + "i.z+=sin(i.x*.5)*.5;" + "i.z+=step(.5,mod(i.x,1.))*.3-.15;" + "i.x=mod(i.x,.5)-.25;" + "float y=e(i.xz),z=smoothstep(.1,.13,y);" + "i.y+=.1-z*.03;" + "i.y-=smoothstep(.05,0.,abs(y-.16))*.004;" + "i.y-=(1.-z)*.01*p(i.xz);" "}" - "y.y-=smoothstep(2.,0.,length(l.xz+vec2(-1.5,3.5)))*.2;" - "y.y-=smoothstep(2.,0.,length(l.xz+vec2(1,-2)))*.2;" - "r=y.y;" - "x=min(x,r);" + "i.y-=smoothstep(2.,0.,length(n.xz+vec2(-1.5,3.5)))*.2;" + "i.y-=smoothstep(2.,0.,length(n.xz+vec2(1,-2)))*.2;" + "float y=i.y;" + "x=min(x,y);" "{" - "vec3 s=y;" - "s.xz=mod(s.xz-.5,1.)-.5;" + "vec3 r=i;" + "r.xz=mod(r.xz-.5,1.)-.5;" "}" - "y.y-=.25;" - "i=n0.&&!e(t+a*.002,b,u,d,k))" - "r+=z*o*l;" - "y=s(y.y);" + "vec3 o=d(y,1e-4);" + "float h=dot(l,o);" + "vec3 g,k;" + "float b;" + "if(h>0.&&!d(t+l*.002,o,g,k,b))" + "c+=n*h*z;" + "i=s(i.y);" "}" "else" - " if(abs(p)>.1)" - "return r+h(x)*z;" + " if(abs(a)>.1)" + "return c+d(x)*n;" "else" " break;" "}" "return vec3(0);" "}" - "vec2 e()" + "vec2 d()" "{" - "vec2 v=y;" + "vec2 v=i;" "if(v.y>v.x)" "v=1.-v;" "v.y*=pi*2./v.x;" @@ -169,29 +170,28 @@ const char *yx_long_way_from_home_frag = "}" "void main()" "{" - "vec2 v=gl_FragCoord.xy/iResolution.xy-.5,x;" - "float f=iTime+(v.x+iResolution.x*v.y)*1.51269341231,z,i;" - "y=s(f);" - "v+=(y-.5)/iResolution.xy;" + "vec2 v=gl_FragCoord.xy/iResolution.xy-.5;" + "float x=iTime+(v.x+iResolution.x*v.y)*1.51269341231;" + "i=s(x);" + "v+=(i-.5)/iResolution.xy;" "v.x*=iResolution.x/iResolution.y;" - "const vec3 c=vec3(-4,2,3),t=vec3(0);" - "const float l=distance(c,t);" + "const vec3 f=vec3(-4,2,3),y=vec3(0);" + "const float z=distance(f,y);" "const vec2 p=vec2(1,2)*.015;" - "vec3 r=vec3(0),o=normalize(vec3(v,2)),a;" - "x=e();" - "r.xy+=x*p;" - "o.xy-=x*p*o.z/l;" - "a=t-c;" - "z=-atan(a.y,length(a.xz));" - "i=-atan(a.x,a.z);" - "r.yz*=n(z);" - "o.yz*=n(z);" - "r.xz*=n(i);" - "o.xz*=n(i);" - "r+=c;" - "vec4 m=vec4(h(r,o),1);" - "gl_FragColor=!isnan(m.x)&&m.x>=0.?" - "m:" + "vec3 c=vec3(0),r=normalize(vec3(v,2));" + "vec2 m=d();" + "c.xy+=m*p;" + "r.xy-=m*p*r.z/z;" + "vec3 l=y-f;" + "float a=-atan(l.y,length(l.xz)),o=-atan(l.x,l.z);" + "c.yz*=n(a);" + "r.yz*=n(a);" + "c.xz*=n(o);" + "r.xz*=n(o);" + "c+=f;" + "vec4 t=vec4(h(c,r),1);" + "gl_FragColor=!isnan(t.x)&&t.x>=0.?" + "t:" "vec4(0);" "}"; diff --git a/tests/unit/loop.frag.expected b/tests/unit/loop.frag.expected index 65d334e8..e8addd46 100644 --- a/tests/unit/loop.frag.expected +++ b/tests/unit/loop.frag.expected @@ -12,9 +12,10 @@ const char *loop_frag = "float a;" "void main()" "{" - "float c,b;" + "float c;" "for(float d=0.;d<50.;++d)" "c+=cos(d);" + "float b;" "for(b=0.;b<50.;++b)" "c+=cos(c);" "for(b=a;b<50.;b++)" From 24011dbbea742fdda8cb647ac6350298f21b91a1 Mon Sep 17 00:00:00 2001 From: Laurent Le Brun Date: Mon, 16 Jan 2023 00:37:00 +0100 Subject: [PATCH 20/32] Add test for multifile minification & compression (#218) --- Checker/compression_test.fs | 25 ++++++++++++++++++------- tests/compression_results.log | 3 ++- 2 files changed, 20 insertions(+), 8 deletions(-) diff --git a/Checker/compression_test.fs b/Checker/compression_test.fs index 56230001..b26789bf 100644 --- a/Checker/compression_test.fs +++ b/Checker/compression_test.fs @@ -47,29 +47,40 @@ let log fmt = Printf.ksprintf logger fmt -let testFile (file: string) = - let langArg = if file.EndsWith("hlsl") then [|"--hlsl"|] else [||] - let extraArgs = [|"--format"; "text"|] - Options.init(Array.append langArg extraArgs) +let compressionTest args files = + Options.init(args) let minified = use out = new StringWriter() - let shaders, exportedNames = ShaderMinifier.minifyFiles [|"tests/real/" + file|] + let shaders, exportedNames = ShaderMinifier.minifyFiles [|for f in files -> "tests/real/" + f|] Formatter.print out shaders exportedNames Options.Text out.ToString().ToCharArray() let pointer = &&minified.[0] - log "%-40s " file + log "%-40s " (match files with [f] -> f | f::_ -> f + "...") log "%5d " minified.Length let compressedSize = Crinkler.ApproximateModels4k(pointer, minified.Length) log "=> %8.3f\n" compressedSize minified.Length, float compressedSize +let compressFile (file: string) = + let langArg = if file.EndsWith("hlsl") then [|"--hlsl"|] else [||] + let extraArgs = [|"--format"; "text"|] + compressionTest (Array.append langArg extraArgs) [file] + let run () = Crinkler.InitCompressor() // Platform must be set to x64 writer.GetStringBuilder().Clear() |> ignore - let sizes = List.map testFile testFiles + + // Tests for minifying multiple files together. + // We don't have good examples of files that fit together, but these files use the same uniforms (e.g. time, tex0). + let multifileInputs = ["clod.frag"; "leizex.frag"; "slisesix.frag"; "motion_blur.frag"; "mandel.frag"; "kaleidoscope.frag"] + let multifileOutput = compressionTest [|"--format"; "text"|] multifileInputs + + // Tests for individual files. + let sizes = multifileOutput :: List.map compressFile testFiles let minifiedSum = List.sumBy fst sizes let compressedSum = List.sumBy snd sizes log "Total: %5d => %9.3f\n" minifiedSum compressedSum + File.WriteAllText("tests/compression_results.log", writer.ToString()) diff --git a/tests/compression_results.log b/tests/compression_results.log index bd9237eb..edef3cc9 100644 --- a/tests/compression_results.log +++ b/tests/compression_results.log @@ -1,3 +1,4 @@ +clod.frag... 9414 => 1697.174 audio-flight-v2.frag 4650 => 904.201 buoy.frag 4239 => 629.709 controllable-machinery.frag 7773 => 1230.829 @@ -19,4 +20,4 @@ terrarium.frag 3634 => 749.630 the_real_party_is_in_your_pocket.frag 12248 => 1815.725 valley_ball.glsl 4386 => 888.815 yx_long_way_from_home.frag 3030 => 615.535 -Total: 110343 => 19837.896 +Total: 119757 => 21535.071 From ddfd9f74a82ecda9991fc898d0ac7f31fac1a517 Mon Sep 17 00:00:00 2001 From: Laurent Le Brun Date: Mon, 16 Jan 2023 01:00:16 +0100 Subject: [PATCH 21/32] Use context-based renaming when minifying multiple files (#219) --- Checker/compression_test.fs | 2 +- src/renamer.fs | 16 ++++++- tests/compression_results.log | 4 +- tests/unit/inout.expected | 82 +++++++++++++++++------------------ 4 files changed, 59 insertions(+), 45 deletions(-) diff --git a/Checker/compression_test.fs b/Checker/compression_test.fs index b26789bf..78439a1b 100644 --- a/Checker/compression_test.fs +++ b/Checker/compression_test.fs @@ -56,7 +56,7 @@ let compressionTest args files = out.ToString().ToCharArray() let pointer = &&minified.[0] - log "%-40s " (match files with [f] -> f | f::_ -> f + "...") + log "%-40s " (match files with [f] -> f | f::_ -> f + "..." | [] -> "?") log "%5d " minified.Length let compressedSize = Crinkler.ApproximateModels4k(pointer, minified.Length) log "=> %8.3f\n" compressedSize diff --git a/src/renamer.fs b/src/renamer.fs index 2fa1b023..ec7a9ff8 100644 --- a/src/renamer.fs +++ b/src/renamer.fs @@ -157,6 +157,17 @@ module private RenamerImpl = d.[id.OldName] <- newName env.Rename(id, newName) + // Renaming safe across multiple files (e.g. uniform/in/out variables are + // renamed in a consistent way) that tries to optimize based on the context + // and variable reuse. + let multiFileRenaming contextTable (exportRenames: IDictionary) (env: Env) (id: Ident) = + match exportRenames.TryGetValue(id.Name) with + | true, newName -> env.Rename(id, newName) + | false, _ -> + let cid = char (1000 + int id.Name) + let newName = chooseIdent contextTable cid env.availableNames + env.Rename(id, newName) + let dontRename (env: Env) (id: Ident) = env.Rename(id, id.Name) @@ -376,7 +387,10 @@ module private RenamerImpl = let mutable env = if Array.length shaders > 1 then - Env.Create(names, true, bijectiveRenaming names, shadowVariables) + // Env.Create(names, true, bijectiveRenaming names, shadowVariables) + let exportsRenames = Seq.zip [for export in exportedNames -> export.name] names |> dict + let contextTable = computeContextTable text + Env.Create(names, true, multiFileRenaming contextTable exportsRenames, shadowVariables) else let contextTable = computeContextTable text Env.Create(names, true, optimizeContext contextTable, shadowVariables) diff --git a/tests/compression_results.log b/tests/compression_results.log index edef3cc9..9e1151ab 100644 --- a/tests/compression_results.log +++ b/tests/compression_results.log @@ -1,4 +1,4 @@ -clod.frag... 9414 => 1697.174 +clod.frag... 8960 => 1549.730 audio-flight-v2.frag 4650 => 904.201 buoy.frag 4239 => 629.709 controllable-machinery.frag 7773 => 1230.829 @@ -20,4 +20,4 @@ terrarium.frag 3634 => 749.630 the_real_party_is_in_your_pocket.frag 12248 => 1815.725 valley_ball.glsl 4386 => 888.815 yx_long_way_from_home.frag 3030 => 615.535 -Total: 119757 => 21535.071 +Total: 119303 => 21387.626 diff --git a/tests/unit/inout.expected b/tests/unit/inout.expected index d9e31c7b..c9296a47 100644 --- a/tests/unit/inout.expected +++ b/tests/unit/inout.expected @@ -1,64 +1,64 @@ /* File generated with * http://www.ctrl-alt-test.fr */ -# define VAR_ambientLight "m" -# define VAR_diffuseColor "i" -# define VAR_emissiveColor "a" -# define VAR_fragmentColor "o" -# define VAR_mediumDensity "t" -# define VAR_normal "c" -# define VAR_specularColor "n" -# define VAR_texture0 "e" -# define VAR_viewVec "v" +# define VAR_ambientLight "f" +# define VAR_diffuseColor "n" +# define VAR_emissiveColor "z" +# define VAR_fragmentColor "r" +# define VAR_mediumDensity "s" +# define VAR_normal "m" +# define VAR_specularColor "e" +# define VAR_texture0 "v" +# define VAR_viewVec "d" // tests/unit/inout.frag "#version 330\n" - "uniform samplerCube e;" - "in vec3 c,v;" - "out vec4 o;" + "uniform samplerCube v;" + "in vec3 m,d;" + "out vec4 r;" "void main()" "{" - "vec3 l=normalize(v),u=normalize(c),f=vec3(.1,.2,.3),x=texture(e,reflect(-l,u)).xyz,p=texture(e,refract(-l,u,1./1.5)).xyz,z=mix(f*p,x,.1);" - "o=vec4(z,1);" + "vec3 f=normalize(d),z=normalize(m),c=vec3(.1,.2,.3),n=texture(v,reflect(-f,z)).xyz,e=texture(v,refract(-f,z,1./1.5)).xyz,p=mix(c*e,n,.1);" + "r=vec4(p,1);" "}" - "vec3 r(vec3 d,vec3 l,vec3 s)" + "vec3 t(vec3 v,vec3 m,vec3 f)" "{" - "float C=1.-clamp(dot(l,s),0.,1.);" - "return C*C*C*C*C*(1.-d)+d;" + "float r=1.-clamp(dot(m,f),0.,1.);" + "return r*r*r*r*r*(1.-v)+v;" "}" - "vec3 r(vec3 l,vec3 y,vec3 u,vec3 f,vec3 d,float w)" + "vec3 t(vec3 v,vec3 m,vec3 f,vec3 n,vec3 d,float r)" "{" - "vec3 s=normalize(l+y),b,Z,Y;" - "float X=1.+2048.*(1.-w)*(1.-w);" - "b=f;" - "Z=vec3(pow(clamp(dot(s,u),0.,1.),X)*(X+4.)/8.);" - "Y=r(d,l,s);" - "return mix(b,Z,Y);" + "vec3 z=normalize(v+m),p,e,c;" + "float s=1.+2048.*(1.-r)*(1.-r);" + "p=n;" + "e=vec3(pow(clamp(dot(z,f),0.,1.),s)*(s+4.)/8.);" + "c=t(d,v,z);" + "return mix(p,e,c);" "}", // tests/unit/inout2.frag "#version 330\n" - "uniform samplerCube e;" - "uniform float t;" - "uniform vec3 m,i,a,n;" - "in vec3 c,v;" - "out vec4 o;" - "vec3 r(vec3 d,vec3 l,vec3 s)" + "uniform samplerCube v;" + "uniform float s;" + "uniform vec3 f,n,z,e;" + "in vec3 m,d;" + "out vec4 r;" + "vec3 t(vec3 v,vec3 m,vec3 f)" "{" - "float C=1.-clamp(dot(l,s),0.,1.);" - "return C*C*C*C*C*(1.-d)+d;" + "float r=1.-clamp(dot(m,f),0.,1.);" + "return r*r*r*r*r*(1.-v)+v;" "}" "void main()" "{" - "vec3 f=i,z=a+mix(f*m,m,.5);" - "o=vec4(z,1);" + "vec3 v=n,p=z+mix(v*f,f,.5);" + "r=vec4(p,1);" "}" - "vec3 r(vec3 l,vec3 y,vec3 u,vec3 f,vec3 d,float w)" + "vec3 t(vec3 v,vec3 m,vec3 f,vec3 n,vec3 d,float r)" "{" - "vec3 s=normalize(l+y),b,Z,Y;" - "float X=1.+2048.*(1.-w)*(1.-w);" - "b=f;" - "Z=vec3(pow(clamp(dot(s,u),0.,1.),X)*(X+4.)/8.);" - "Y=r(d,l,s);" - "return mix(b,Z,Y);" + "vec3 z=normalize(v+m),p,e,c;" + "float s=1.+2048.*(1.-r)*(1.-r);" + "p=n;" + "e=vec3(pow(clamp(dot(z,f),0.,1.),s)*(s+4.)/8.);" + "c=t(d,v,z);" + "return mix(p,e,c);" "}", From 390eac07498a29b7a011e217c63778eb998b2278 Mon Sep 17 00:00:00 2001 From: Laurent Le Brun Date: Mon, 16 Jan 2023 01:14:37 +0100 Subject: [PATCH 22/32] Shorten the generated header (#220) --- src/formatter.fs | 11 +++-------- tests/real/chocolux.expected | 4 +--- tests/real/disco.expected | 4 +--- tests/real/elevated.hlsl.expected | 4 +--- tests/real/heart.frag.expected | 4 +--- tests/real/kinder_painter.expected | 4 +--- tests/real/leizex.expected | 3 +-- tests/real/mandelbulb.expected | 4 +--- tests/real/oscars_chair.frag.expected | 4 +--- tests/real/sult.expected | 4 +--- .../the_real_party_is_in_your_pocket.frag.expected | 4 +--- tests/real/to_the_road_of_ribbon.expected | 4 +--- tests/real/yx_long_way_from_home.frag.expected | 4 +--- tests/unit/blocks.expected | 4 +--- tests/unit/externals.expected | 4 +--- tests/unit/externals.preserved.expected | 4 +--- tests/unit/float.frag.expected | 4 +--- tests/unit/function_comma.expected | 4 +--- tests/unit/function_overload.expected | 4 +--- tests/unit/geometry.hlsl.expected | 4 +--- tests/unit/inout.expected | 4 +--- tests/unit/loop.frag.expected | 4 +--- tests/unit/macros.expected | 4 +--- tests/unit/many_variables.expected | 4 +--- tests/unit/minus-zero.expected | 4 +--- tests/unit/operators.expected | 4 +--- tests/unit/qualifiers.expected | 4 +--- tests/unit/verbatim.frag.expected | 4 +--- 28 files changed, 30 insertions(+), 88 deletions(-) diff --git a/src/formatter.fs b/src/formatter.fs index 5557aae6..f9e6aea3 100644 --- a/src/formatter.fs +++ b/src/formatter.fs @@ -10,9 +10,7 @@ let private printHeader out (shaders: Ast.Shader[]) asAList exportedNames = else Path.GetFileName options.outputName let macroName = fileName.Replace(".", "_").ToUpper() + "_" - fprintfn out "/* File generated with Shader Minifier %s" Options.version - fprintfn out " * http://www.ctrl-alt-test.fr" - fprintfn out " */" + fprintfn out "// Generated with Shader Minifier %s (https://github.com/laurentlb/Shader_Minifier/)" Options.version if not asAList then fprintfn out "#ifndef %s" macroName @@ -50,9 +48,7 @@ let private printIndented out (shaders: Ast.Shader[]) = |> fprintf out "%s" let private printJSHeader out (shaders: Ast.Shader[]) exportedNames = - fprintfn out "/* File generated with Shader Minifier %s" Options.version - fprintfn out " * http://www.ctrl-alt-test.fr" - fprintfn out " */" + fprintfn out "// Generated with Shader Minifier %s (https://github.com/laurentlb/Shader_Minifier/)" Options.version for value: Ast.ExportedName in List.sort exportedNames do if value.ty = "" then @@ -67,8 +63,7 @@ let private printJSHeader out (shaders: Ast.Shader[]) exportedNames = fprintfn out "" let private printNasmHeader out (shaders: Ast.Shader[]) exportedNames = - fprintfn out "; File generated with Shader Minifier %s" Options.version - fprintfn out "; http://www.ctrl-alt-test.fr" + fprintfn out "; Generated with Shader Minifier %s (https://github.com/laurentlb/Shader_Minifier/)" Options.version for value: Ast.ExportedName in List.sort exportedNames do if value.ty = "" then diff --git a/tests/real/chocolux.expected b/tests/real/chocolux.expected index d00f70eb..e16fa2b2 100644 --- a/tests/real/chocolux.expected +++ b/tests/real/chocolux.expected @@ -1,6 +1,4 @@ -/* File generated with - * http://www.ctrl-alt-test.fr - */ +// Generated with (https://github.com/laurentlb/Shader_Minifier/) #ifndef CHOCOLUX_EXPECTED_ # define CHOCOLUX_EXPECTED_ diff --git a/tests/real/disco.expected b/tests/real/disco.expected index 37f6693a..dfb6e8aa 100644 --- a/tests/real/disco.expected +++ b/tests/real/disco.expected @@ -1,5 +1,3 @@ -/* File generated with - * http://www.ctrl-alt-test.fr - */ +// Generated with (https://github.com/laurentlb/Shader_Minifier/) var disco_frag = `uniform vec2 resolution;uniform float time;uniform sampler2D tex0,tex1,tex2,tex3;vec4 s(vec2 px,float z){float l=3.1415,k=time*sign(z),x=px.x*320.*.0065*z,y=px.y*240.*.006*z,c=sqrt(x*x+y*y);if(c>1.)return vec4(0);{float u=-.4*sign(z)+sin(k*.05),v=sqrt(1.-x*x-y*y),q=y*sin(u)-v*cos(u);y=y*cos(u)+v*sin(u);v=acos(y);u=acos(x/sin(v))/(2.*l)*120.*sign(q)-k;v=v*60./l;q=cos(floor(v/l));c=pow(abs(cos(u)*sin(v)),.2)*.1/(q+sin(float(int((u+l/2.)/l))+k*.6+cos(q*25.)))*pow(1.-c,.9);vec4 res;res=c<0.?vec4(-c/2.*abs(cos(k*.1)),0,-c*2.*abs(sin(k*.04)),1):vec4(c,c*2.,c*2.,1);return res;}}void main(){vec2 p=-1.+2.*gl_FragCoord.xy/resolution.xy;vec4 c=vec4(0);for(int i=80;i>0;i--)c+=s(p,1.-float(i)/80.)*(.008-float(i)*5e-5);vec4 d=s(p,1.);gl_FragColor=(d.w==0.?s(p,-.2)*.02:d)+sqrt(c);}` diff --git a/tests/real/elevated.hlsl.expected b/tests/real/elevated.hlsl.expected index 5fb054f6..97d51b07 100644 --- a/tests/real/elevated.hlsl.expected +++ b/tests/real/elevated.hlsl.expected @@ -1,6 +1,4 @@ -/* File generated with - * http://www.ctrl-alt-test.fr - */ +// Generated with (https://github.com/laurentlb/Shader_Minifier/) #ifndef ELEVATED_HLSL_EXPECTED_ # define ELEVATED_HLSL_EXPECTED_ # define VAR_q "t" diff --git a/tests/real/heart.frag.expected b/tests/real/heart.frag.expected index 95ef482a..e7056acd 100644 --- a/tests/real/heart.frag.expected +++ b/tests/real/heart.frag.expected @@ -1,6 +1,4 @@ -/* File generated with - * http://www.ctrl-alt-test.fr - */ +// Generated with (https://github.com/laurentlb/Shader_Minifier/) #ifndef HEART_FRAG_EXPECTED_ # define HEART_FRAG_EXPECTED_ # define VAR_mouse "f" diff --git a/tests/real/kinder_painter.expected b/tests/real/kinder_painter.expected index 4b7e9b22..9e8eef55 100644 --- a/tests/real/kinder_painter.expected +++ b/tests/real/kinder_painter.expected @@ -1,6 +1,4 @@ -/* File generated with - * http://www.ctrl-alt-test.fr - */ +// Generated with (https://github.com/laurentlb/Shader_Minifier/) // tests/real/kinder_painter.frag "uniform vec2 resolution;" diff --git a/tests/real/leizex.expected b/tests/real/leizex.expected index 872f674d..91c20af8 100644 --- a/tests/real/leizex.expected +++ b/tests/real/leizex.expected @@ -1,5 +1,4 @@ -; File generated with -; http://www.ctrl-alt-test.fr +; Generated with (https://github.com/laurentlb/Shader_Minifier/) _leizex_frag: db '#extension GL_EXT_gpu_shader4:enable', 10, '' diff --git a/tests/real/mandelbulb.expected b/tests/real/mandelbulb.expected index e67f2f4c..1e39286f 100644 --- a/tests/real/mandelbulb.expected +++ b/tests/real/mandelbulb.expected @@ -1,6 +1,4 @@ -/* File generated with - * http://www.ctrl-alt-test.fr - */ +// Generated with (https://github.com/laurentlb/Shader_Minifier/) #ifndef MANDELBULB_EXPECTED_ # define MANDELBULB_EXPECTED_ diff --git a/tests/real/oscars_chair.frag.expected b/tests/real/oscars_chair.frag.expected index 4a22ea9a..8051feed 100644 --- a/tests/real/oscars_chair.frag.expected +++ b/tests/real/oscars_chair.frag.expected @@ -1,6 +1,4 @@ -/* File generated with - * http://www.ctrl-alt-test.fr - */ +// Generated with (https://github.com/laurentlb/Shader_Minifier/) #ifndef OSCARS_CHAIR_FRAG_EXPECTED_ # define OSCARS_CHAIR_FRAG_EXPECTED_ # define VAR_tex1 "a" diff --git a/tests/real/sult.expected b/tests/real/sult.expected index fc3253c3..bda95bcc 100644 --- a/tests/real/sult.expected +++ b/tests/real/sult.expected @@ -1,6 +1,4 @@ -/* File generated with - * http://www.ctrl-alt-test.fr - */ +// Generated with (https://github.com/laurentlb/Shader_Minifier/) #ifndef SULT_EXPECTED_ # define SULT_EXPECTED_ # define VAR_resolution "r" diff --git a/tests/real/the_real_party_is_in_your_pocket.frag.expected b/tests/real/the_real_party_is_in_your_pocket.frag.expected index 419de33d..d0ce7a41 100644 --- a/tests/real/the_real_party_is_in_your_pocket.frag.expected +++ b/tests/real/the_real_party_is_in_your_pocket.frag.expected @@ -1,6 +1,4 @@ -/* File generated with - * http://www.ctrl-alt-test.fr - */ +// Generated with (https://github.com/laurentlb/Shader_Minifier/) #ifndef THE_REAL_PARTY_IS_IN_YOUR_POCKET_FRAG_EXPECTED_ # define THE_REAL_PARTY_IS_IN_YOUR_POCKET_FRAG_EXPECTED_ diff --git a/tests/real/to_the_road_of_ribbon.expected b/tests/real/to_the_road_of_ribbon.expected index 88bfa319..7b23d324 100644 --- a/tests/real/to_the_road_of_ribbon.expected +++ b/tests/real/to_the_road_of_ribbon.expected @@ -1,6 +1,4 @@ -/* File generated with - * http://www.ctrl-alt-test.fr - */ +// Generated with (https://github.com/laurentlb/Shader_Minifier/) #ifndef TO_THE_ROAD_OF_RIBBON_EXPECTED_ # define TO_THE_ROAD_OF_RIBBON_EXPECTED_ diff --git a/tests/real/yx_long_way_from_home.frag.expected b/tests/real/yx_long_way_from_home.frag.expected index 49c1e41b..33d47fda 100644 --- a/tests/real/yx_long_way_from_home.frag.expected +++ b/tests/real/yx_long_way_from_home.frag.expected @@ -1,6 +1,4 @@ -/* File generated with - * http://www.ctrl-alt-test.fr - */ +// Generated with (https://github.com/laurentlb/Shader_Minifier/) #ifndef YX_LONG_WAY_FROM_HOME_FRAG_EXPECTED_ # define YX_LONG_WAY_FROM_HOME_FRAG_EXPECTED_ # define VAR_iChannel1 "v" diff --git a/tests/unit/blocks.expected b/tests/unit/blocks.expected index 45b60ae2..35eebd40 100644 --- a/tests/unit/blocks.expected +++ b/tests/unit/blocks.expected @@ -1,6 +1,4 @@ -/* File generated with - * http://www.ctrl-alt-test.fr - */ +// Generated with (https://github.com/laurentlb/Shader_Minifier/) #ifndef BLOCKS_EXPECTED_ # define BLOCKS_EXPECTED_ diff --git a/tests/unit/externals.expected b/tests/unit/externals.expected index 88532b01..8beaa2cb 100644 --- a/tests/unit/externals.expected +++ b/tests/unit/externals.expected @@ -1,6 +1,4 @@ -/* File generated with Shader Minifier 1.3 - * http://www.ctrl-alt-test.fr - */ +// Generated with (https://github.com/laurentlb/Shader_Minifier/) #ifndef EXTERNALS_EXPECTED_ # define EXTERNALS_EXPECTED_ # define VAR_e "t" diff --git a/tests/unit/externals.preserved.expected b/tests/unit/externals.preserved.expected index 78249489..ecc361a3 100644 --- a/tests/unit/externals.preserved.expected +++ b/tests/unit/externals.preserved.expected @@ -1,6 +1,4 @@ -/* File generated with Shader Minifier 1.3 - * http://www.ctrl-alt-test.fr - */ +// Generated with (https://github.com/laurentlb/Shader_Minifier/) #ifndef EXTERNALS_PRESERVED_EXPECTED_ # define EXTERNALS_PRESERVED_EXPECTED_ diff --git a/tests/unit/float.frag.expected b/tests/unit/float.frag.expected index 445f5590..61af4b05 100644 --- a/tests/unit/float.frag.expected +++ b/tests/unit/float.frag.expected @@ -1,6 +1,4 @@ -/* File generated with - * http://www.ctrl-alt-test.fr - */ +// Generated with (https://github.com/laurentlb/Shader_Minifier/) // tests/unit/float.frag "void precision()" diff --git a/tests/unit/function_comma.expected b/tests/unit/function_comma.expected index 49fa9fa6..0c2f8136 100644 --- a/tests/unit/function_comma.expected +++ b/tests/unit/function_comma.expected @@ -1,6 +1,4 @@ -/* File generated with - * http://www.ctrl-alt-test.fr - */ +// Generated with (https://github.com/laurentlb/Shader_Minifier/) #ifndef FUNCTION_COMMA_EXPECTED_ # define FUNCTION_COMMA_EXPECTED_ diff --git a/tests/unit/function_overload.expected b/tests/unit/function_overload.expected index 28395dd4..bc522c05 100644 --- a/tests/unit/function_overload.expected +++ b/tests/unit/function_overload.expected @@ -1,6 +1,4 @@ -/* File generated with Shader Minifier 1.3 - * http://www.ctrl-alt-test.fr - */ +// Generated with (https://github.com/laurentlb/Shader_Minifier/) #ifndef FUNCTION_OVERLOAD_EXPECTED_ # define FUNCTION_OVERLOAD_EXPECTED_ diff --git a/tests/unit/geometry.hlsl.expected b/tests/unit/geometry.hlsl.expected index 42467016..e39940a7 100644 --- a/tests/unit/geometry.hlsl.expected +++ b/tests/unit/geometry.hlsl.expected @@ -1,6 +1,4 @@ -/* File generated with - * http://www.ctrl-alt-test.fr - */ +// Generated with (https://github.com/laurentlb/Shader_Minifier/) #ifndef GEOMETRY_HLSL_EXPECTED_ # define GEOMETRY_HLSL_EXPECTED_ diff --git a/tests/unit/inout.expected b/tests/unit/inout.expected index c9296a47..03c5a4c9 100644 --- a/tests/unit/inout.expected +++ b/tests/unit/inout.expected @@ -1,6 +1,4 @@ -/* File generated with - * http://www.ctrl-alt-test.fr - */ +// Generated with (https://github.com/laurentlb/Shader_Minifier/) # define VAR_ambientLight "f" # define VAR_diffuseColor "n" # define VAR_emissiveColor "z" diff --git a/tests/unit/loop.frag.expected b/tests/unit/loop.frag.expected index e8addd46..ff784c3c 100644 --- a/tests/unit/loop.frag.expected +++ b/tests/unit/loop.frag.expected @@ -1,6 +1,4 @@ -/* File generated with - * http://www.ctrl-alt-test.fr - */ +// Generated with (https://github.com/laurentlb/Shader_Minifier/) #ifndef LOOP_FRAG_EXPECTED_ # define LOOP_FRAG_EXPECTED_ diff --git a/tests/unit/macros.expected b/tests/unit/macros.expected index dbc36787..ab0539c0 100644 --- a/tests/unit/macros.expected +++ b/tests/unit/macros.expected @@ -1,6 +1,4 @@ -/* File generated with Shader Minifier 1.3 - * http://www.ctrl-alt-test.fr - */ +// Generated with (https://github.com/laurentlb/Shader_Minifier/) #ifndef MACROS_EXPECTED_ # define MACROS_EXPECTED_ diff --git a/tests/unit/many_variables.expected b/tests/unit/many_variables.expected index 576eeff3..b674f897 100644 --- a/tests/unit/many_variables.expected +++ b/tests/unit/many_variables.expected @@ -1,6 +1,4 @@ -/* File generated with - * http://www.ctrl-alt-test.fr - */ +// Generated with (https://github.com/laurentlb/Shader_Minifier/) // tests/unit/many_variables.frag "int t(float t,float o,float l,float f,float a,float n,float i,float r,float u,float e,float Z,float Y)" diff --git a/tests/unit/minus-zero.expected b/tests/unit/minus-zero.expected index faf1681c..93e34b4e 100644 --- a/tests/unit/minus-zero.expected +++ b/tests/unit/minus-zero.expected @@ -1,6 +1,4 @@ -/* File generated with Shader Minifier 1.3 - * http://www.ctrl-alt-test.fr - */ +// Generated with (https://github.com/laurentlb/Shader_Minifier/) // tests/unit/minus-zero.frag "void main()" diff --git a/tests/unit/operators.expected b/tests/unit/operators.expected index e5694701..82ee338d 100644 --- a/tests/unit/operators.expected +++ b/tests/unit/operators.expected @@ -1,6 +1,4 @@ -/* File generated with - * http://www.ctrl-alt-test.fr - */ +// Generated with (https://github.com/laurentlb/Shader_Minifier/) // tests/unit/operators.frag "#version 330\n" diff --git a/tests/unit/qualifiers.expected b/tests/unit/qualifiers.expected index c0d44b90..93d607d1 100644 --- a/tests/unit/qualifiers.expected +++ b/tests/unit/qualifiers.expected @@ -1,6 +1,4 @@ -/* File generated with Shader Minifier 1.3 - * http://www.ctrl-alt-test.fr - */ +// Generated with (https://github.com/laurentlb/Shader_Minifier/) #ifndef QUALIFIERS_EXPECTED_ # define QUALIFIERS_EXPECTED_ # define VAR_foo "f" diff --git a/tests/unit/verbatim.frag.expected b/tests/unit/verbatim.frag.expected index e4d5c3bf..107b8e59 100644 --- a/tests/unit/verbatim.frag.expected +++ b/tests/unit/verbatim.frag.expected @@ -1,6 +1,4 @@ -/* File generated with - * http://www.ctrl-alt-test.fr - */ +// Generated with (https://github.com/laurentlb/Shader_Minifier/) // tests/unit/verbatim.frag "//Test case for https://github.com/laurentlb/Shader_Minifier/issues/168\n" From fe351e9f6cc5e41681b527571f3fc7847dae4d1f Mon Sep 17 00:00:00 2001 From: Eldritch Conundrum Date: Mon, 16 Jan 2023 22:51:45 +0100 Subject: [PATCH 23/32] Eliminate "!" in condition by swapping if and else (#223) --- src/rewriter.fs | 5 +++++ tests/compression_results.log | 4 ++-- .../from-the-seas-to-the-stars.frag.expected | 18 +++++++++--------- tests/real/mandelbulb.expected | 6 +++--- 4 files changed, 19 insertions(+), 14 deletions(-) diff --git a/src/rewriter.fs b/src/rewriter.fs index a79701e9..f4b92920 100644 --- a/src/rewriter.fs +++ b/src/rewriter.fs @@ -467,6 +467,11 @@ let private simplifyStmt = function | If (cond, body1, body2) -> let (body1, body2) = squeezeBlockWithComma body1, Option.map squeezeBlockWithComma body2 + let (cond, body1, body2) = // if(!c)a();else b(); -> if(c)b();else a(); + match (cond, body1, body2) with + | FunCall (Op "!", [e]), bodyT, Some bodyF -> e, bodyF, Some bodyT + | _ -> cond, body1, body2 + match (body1, body2) with | (Expr eT, Some (Expr eF)) -> let tryCollapseToAssignment : Expr -> (Ident * Expr) option = function diff --git a/tests/compression_results.log b/tests/compression_results.log index 9e1151ab..124b3924 100644 --- a/tests/compression_results.log +++ b/tests/compression_results.log @@ -5,7 +5,7 @@ controllable-machinery.frag 7773 => 1230.829 ed-209.frag 7926 => 1363.517 elevated.hlsl 3416 => 608.543 endeavour.frag 2661 => 545.443 -from-the-seas-to-the-stars.frag 14371 => 2348.037 +from-the-seas-to-the-stars.frag 14370 => 2347.919 frozen-wasteland.frag 4609 => 815.278 kinder_painter.frag 2905 => 451.105 leizex.frag 2327 => 518.373 @@ -20,4 +20,4 @@ terrarium.frag 3634 => 749.630 the_real_party_is_in_your_pocket.frag 12248 => 1815.725 valley_ball.glsl 4386 => 888.815 yx_long_way_from_home.frag 3030 => 615.535 -Total: 119303 => 21387.626 +Total: 119302 => 21387.508 diff --git a/tests/real/from-the-seas-to-the-stars.frag.expected b/tests/real/from-the-seas-to-the-stars.frag.expected index 94896c3e..ded8fa7a 100644 --- a/tests/real/from-the-seas-to-the-stars.frag.expected +++ b/tests/real/from-the-seas-to-the-stars.frag.expected @@ -529,7 +529,15 @@ void main() else { p.z+=sin(p.x); - if(!bigkoi) + if(bigkoi) + { + p.x*=2.; + p.x*=.5; + if(p.x<0.) + return; + p.xz*=rotmat(.78525); + } + else { w.w=R(); if(w.w<.33) @@ -540,14 +548,6 @@ void main() else col=vec3(.5),p.xz*=rotmat(3.7692); } - else - { - p.x*=2.; - p.x*=.5; - if(p.x<0.) - return; - p.xz*=rotmat(.78525); - } } w.x=R(); w.y=R(); diff --git a/tests/real/mandelbulb.expected b/tests/real/mandelbulb.expected index 1e39286f..a093068e 100644 --- a/tests/real/mandelbulb.expected +++ b/tests/real/mandelbulb.expected @@ -92,9 +92,7 @@ const char *mandelbulb_frag = "vec3 x=vec3(p*sin(6.28318*time/20.),.3-.4*sin(6.28318*time/20.),p*cos(6.28318*time/20.)),s=vec3(0,.1,0),z=normalize(s-x),a=vec3(0,1,0),w=normalize(cross(z,a)),d=normalize(cross(w,z)),e=normalize(c.x*w+c.y*d+1.5*z),g,i;" "vec4 l;" "float u;" - "if(!t(x,e,u,1e20,g,l,y))" - "i=1.3*vec3(1,.98,.9)*(.7+.3*e.y);" - "else" + "if(t(x,e,u,1e20,g,l,y))" "{" "vec3 m=x+u*e;" "float r=clamp(.2+.8*dot(f,g),0.,1.);" @@ -115,6 +113,8 @@ const char *mandelbulb_frag = "i*=vec3(pow(n,.8),pow(n,1.),pow(n,1.1));" "i=1.5*(i*.15+.85*sqrt(i));" "}" + "else" + " i=1.3*vec3(1,.98,.9)*(.7+.3*e.y);" "vec2 r=v*.5+.5;" "i*=.7+4.8*r.x*r.y*(1.-r.x)*(1.-r.y);" "i=clamp(i,0.,1.);" From 97817496bcaeba4e9d9c71b906006a838358d38b Mon Sep 17 00:00:00 2001 From: Eldritch Conundrum Date: Mon, 16 Jan 2023 23:44:15 +0100 Subject: [PATCH 24/32] Use -= rewrite trick to initialize to zero vec (#224) --- src/rewriter.fs | 3 +++ tests/compression_results.log | 12 ++++++------ tests/real/controllable-machinery.frag.expected | 2 +- tests/real/from-the-seas-to-the-stars.frag.expected | 10 +++++----- tests/real/slisesix.frag.expected | 2 +- tests/unit/float.frag.expected | 2 +- 6 files changed, 17 insertions(+), 14 deletions(-) diff --git a/src/rewriter.fs b/src/rewriter.fs index f4b92920..ee41927d 100644 --- a/src/rewriter.fs +++ b/src/rewriter.fs @@ -181,6 +181,9 @@ let private simplifyOperator env = function | FunCall(Op "=", [Var x; FunCall(Op op, [Var y; e])]) when x.Name = y.Name && augmentableOperators.Contains op -> FunCall(Op (op + "="), [Var x; e]) + | FunCall(Op "=", [Var x; FunCall(Var fctName, [Int (0, _)])]) + when List.contains fctName.Name ["vec2"; "vec3"; "vec4"; "ivec2"; "ivec3"; "ivec4"] -> + FunCall(Op "-=", [Var x; Var x]) // x=vec3(0); -> x-=x; | e -> e diff --git a/tests/compression_results.log b/tests/compression_results.log index 124b3924..4581eef2 100644 --- a/tests/compression_results.log +++ b/tests/compression_results.log @@ -1,11 +1,11 @@ -clod.frag... 8960 => 1549.730 +clod.frag... 8955 => 1547.663 audio-flight-v2.frag 4650 => 904.201 buoy.frag 4239 => 629.709 -controllable-machinery.frag 7773 => 1230.829 +controllable-machinery.frag 7768 => 1230.786 ed-209.frag 7926 => 1363.517 elevated.hlsl 3416 => 608.543 endeavour.frag 2661 => 545.443 -from-the-seas-to-the-stars.frag 14370 => 2347.919 +from-the-seas-to-the-stars.frag 14345 => 2346.807 frozen-wasteland.frag 4609 => 815.278 kinder_painter.frag 2905 => 451.105 leizex.frag 2327 => 518.373 @@ -14,10 +14,10 @@ mandelbulb.frag 2419 => 548.489 ohanami.frag 3292 => 739.505 orchard.frag 5643 => 1036.998 oscars_chair.frag 4653 => 988.137 -robin.frag 6343 => 1058.401 -slisesix.frag 4587 => 934.011 +robin.frag 6338 => 1059.267 +slisesix.frag 4582 => 932.831 terrarium.frag 3634 => 749.630 the_real_party_is_in_your_pocket.frag 12248 => 1815.725 valley_ball.glsl 4386 => 888.815 yx_long_way_from_home.frag 3030 => 615.535 -Total: 119302 => 21387.508 +Total: 119257 => 21383.972 diff --git a/tests/real/controllable-machinery.frag.expected b/tests/real/controllable-machinery.frag.expected index 54d36f5b..70b5d885 100644 --- a/tests/real/controllable-machinery.frag.expected +++ b/tests/real/controllable-machinery.frag.expected @@ -494,7 +494,7 @@ void mainImage(out vec4 fragColor,vec2 fragCoord) #endif - col=vec3(0); + col-=col; sr=2.*mod(dot(mod(floor(.5*(uv+1.)*canvas),2.),vec2(1)),2.)-1.; for(float a=float(VAR_ZERO);a<3.;a++) rd=vuMat*normalize(vec3(uv+step(1.5,3.)*Rot2D(vec2(.5/canvas.y,0),sr*(.667*a+.5)*3.1415927),zmFac)),col+=1./3.*ShowScene(ro,rd); diff --git a/tests/real/from-the-seas-to-the-stars.frag.expected b/tests/real/from-the-seas-to-the-stars.frag.expected index ded8fa7a..dd39ec7d 100644 --- a/tests/real/from-the-seas-to-the-stars.frag.expected +++ b/tests/real/from-the-seas-to-the-stars.frag.expected @@ -107,7 +107,7 @@ void ammonite() { float t=pow(w.z,.3)*2.,c=.5+.5*cos(t*300); col=mix(vec3(1,.5,.4),vec3(.3),c)/8.; - p=vec3(0); + p-=p; p.xy=(disc(w.xy)*mix(.8,1.,c)+vec2(0,1+t))*t*.05; p.yz*=rotmat(t*10.+2); w.w=R(); @@ -214,7 +214,7 @@ void main() w.w=R(); if(w.w<.25) { - of=vec3(0); + of-=of; w.x=R(); w.y=R(); w.z=R(); @@ -312,14 +312,14 @@ void main() if(ww<.3) { if(R()<.1) - w.x=R(),w.y=R(),w.z=R(),w.w=R(),of=vec3(0),jellyfish(),p.yz*=rotmat(.5),p*=.6,p.y+=.11,col=vec3(1); + w.x=R(),w.y=R(),w.z=R(),w.w=R(),of-=of,jellyfish(),p.yz*=rotmat(.5),p*=.6,p.y+=.11,col=vec3(1); p+=vec3(-.8,.3,0); } else if(ww<.6) { if(R()<.2) - w.x=R(),w.y=R(),w.z=R(),w.w=R(),of=vec3(0),ammonite(),p.yz*=rotmat(-.5),p*=.6,p=p.zyx,col=vec3(1); + w.x=R(),w.y=R(),w.z=R(),w.w=R(),of-=of,ammonite(),p.yz*=rotmat(-.5),p*=.6,p=p.zyx,col=vec3(1); p+=vec3(.6,-.6,0); } else @@ -379,7 +379,7 @@ void main() w.w=R(); if(w.w<.25) { - of=vec3(0); + of-=of; w.x=R(); w.y=R(); w.z=R(); diff --git a/tests/real/slisesix.frag.expected b/tests/real/slisesix.frag.expected index b717cf0f..f78c7e02 100644 --- a/tests/real/slisesix.frag.expected +++ b/tests/real/slisesix.frag.expected @@ -195,7 +195,7 @@ void main() } else if(matID==2) - rgb=vec3(0); + rgb-=rgb; else if(matID==1) { diff --git a/tests/unit/float.frag.expected b/tests/unit/float.frag.expected index 61af4b05..7ec1aa55 100644 --- a/tests/unit/float.frag.expected +++ b/tests/unit/float.frag.expected @@ -20,5 +20,5 @@ "void main()" "{" "float f1=1.5,f2=3e-7,f3=.42,f6=-.002,f7=2e-9,f8=2e6,f9=2e10;" - "gl_FragColor=vec4(0);" + "gl_FragColor-=gl_FragColor;" "}", From 3fbf7874ef2aca285587b559947f93c0ac740c04 Mon Sep 17 00:00:00 2001 From: Laurent Le Brun Date: Fri, 20 Jan 2023 01:00:27 +0100 Subject: [PATCH 25/32] Renamer: fix renaming bug when we minify multiple shaders (#225) The renaming of a variable inside the code didn't always match the global name. As a side-effect of the name renaming (introduced in the previous commit), similar functions in two different files won't necessarily be minified in the same way (see inout.expected). This can cause compression problems... however, the compression test shows that it compresses fine with Crinkler. kkrunchy may behave differently though. --- src/renamer.fs | 7 +++-- tests/compression_results.log | 4 +-- tests/unit/inout.expected | 48 +++++++++++++++++------------------ 3 files changed, 29 insertions(+), 30 deletions(-) diff --git a/src/renamer.fs b/src/renamer.fs index ec7a9ff8..fb384fa6 100644 --- a/src/renamer.fs +++ b/src/renamer.fs @@ -360,13 +360,12 @@ module private RenamerImpl = let renameAsts shaders env = let mutable env = env - // First, rename top-level values. for shader in shaders do + // Rename top-level and body at the same time (because the body + // needs the environment matching the top-level). env <- renList env renTopLevelName shader.code - - // Rename local variables. - for shader in shaders do List.iter (renTopLevelBody env) shader.code + env.exportedNames.Value let assignUniqueIds shaders = diff --git a/tests/compression_results.log b/tests/compression_results.log index 4581eef2..536014ca 100644 --- a/tests/compression_results.log +++ b/tests/compression_results.log @@ -1,4 +1,4 @@ -clod.frag... 8955 => 1547.663 +clod.frag... 8955 => 1540.822 audio-flight-v2.frag 4650 => 904.201 buoy.frag 4239 => 629.709 controllable-machinery.frag 7768 => 1230.786 @@ -20,4 +20,4 @@ terrarium.frag 3634 => 749.630 the_real_party_is_in_your_pocket.frag 12248 => 1815.725 valley_ball.glsl 4386 => 888.815 yx_long_way_from_home.frag 3030 => 615.535 -Total: 119257 => 21383.972 +Total: 119257 => 21377.131 diff --git a/tests/unit/inout.expected b/tests/unit/inout.expected index 03c5a4c9..870b0136 100644 --- a/tests/unit/inout.expected +++ b/tests/unit/inout.expected @@ -1,11 +1,11 @@ // Generated with (https://github.com/laurentlb/Shader_Minifier/) -# define VAR_ambientLight "f" -# define VAR_diffuseColor "n" -# define VAR_emissiveColor "z" +# define VAR_ambientLight "z" +# define VAR_diffuseColor "e" +# define VAR_emissiveColor "n" # define VAR_fragmentColor "r" -# define VAR_mediumDensity "s" +# define VAR_mediumDensity "f" # define VAR_normal "m" -# define VAR_specularColor "e" +# define VAR_specularColor "o" # define VAR_texture0 "v" # define VAR_viewVec "d" @@ -16,7 +16,7 @@ "out vec4 r;" "void main()" "{" - "vec3 f=normalize(d),z=normalize(m),c=vec3(.1,.2,.3),n=texture(v,reflect(-f,z)).xyz,e=texture(v,refract(-f,z,1./1.5)).xyz,p=mix(c*e,n,.1);" + "vec3 t=normalize(d),f=normalize(m),c=vec3(.1,.2,.3),z=texture(v,reflect(-t,f)).xyz,e=texture(v,refract(-t,f,1./1.5)).xyz,p=mix(c*e,z,.1);" "r=vec4(p,1);" "}" "vec3 t(vec3 v,vec3 m,vec3 f)" @@ -24,21 +24,21 @@ "float r=1.-clamp(dot(m,f),0.,1.);" "return r*r*r*r*r*(1.-v)+v;" "}" - "vec3 t(vec3 v,vec3 m,vec3 f,vec3 n,vec3 d,float r)" + "vec3 t(vec3 v,vec3 m,vec3 f,vec3 r,vec3 d,float c)" "{" - "vec3 z=normalize(v+m),p,e,c;" - "float s=1.+2048.*(1.-r)*(1.-r);" - "p=n;" - "e=vec3(pow(clamp(dot(z,f),0.,1.),s)*(s+4.)/8.);" - "c=t(d,v,z);" - "return mix(p,e,c);" + "vec3 p=normalize(v+m),z,e,o;" + "float s=1.+2048.*(1.-c)*(1.-c);" + "z=r;" + "e=vec3(pow(clamp(dot(p,f),0.,1.),s)*(s+4.)/8.);" + "o=t(d,v,p);" + "return mix(z,e,o);" "}", // tests/unit/inout2.frag "#version 330\n" "uniform samplerCube v;" - "uniform float s;" - "uniform vec3 f,n,z,e;" + "uniform float f;" + "uniform vec3 z,e,n,o;" "in vec3 m,d;" "out vec4 r;" "vec3 t(vec3 v,vec3 m,vec3 f)" @@ -48,15 +48,15 @@ "}" "void main()" "{" - "vec3 v=n,p=z+mix(v*f,f,.5);" - "r=vec4(p,1);" + "vec3 v=e,f=n+mix(v*z,z,.5);" + "r=vec4(f,1);" "}" - "vec3 t(vec3 v,vec3 m,vec3 f,vec3 n,vec3 d,float r)" + "vec3 t(vec3 v,vec3 m,vec3 f,vec3 r,vec3 z,float c)" "{" - "vec3 z=normalize(v+m),p,e,c;" - "float s=1.+2048.*(1.-r)*(1.-r);" - "p=n;" - "e=vec3(pow(clamp(dot(z,f),0.,1.),s)*(s+4.)/8.);" - "c=t(d,v,z);" - "return mix(p,e,c);" + "vec3 d=normalize(v+m),e,o,p;" + "float s=1.+2048.*(1.-c)*(1.-c);" + "e=r;" + "o=vec3(pow(clamp(dot(d,f),0.,1.),s)*(s+4.)/8.);" + "p=t(z,v,d);" + "return mix(e,o,p);" "}", From 05e28729f04e99a494102f1295027bf18b8e733a Mon Sep 17 00:00:00 2001 From: Laurent Le Brun Date: Fri, 20 Jan 2023 11:03:36 +0100 Subject: [PATCH 26/32] Make renaming a bit more consistent across files (#226) Avoid depending too much on the order in which variables are in the "candidates" set. Add more comments to document some recent findings. --- src/renamer.fs | 7 +- tests/compression_results.log | 44 ++-- tests/real/elevated.hlsl.expected | 84 +++---- tests/real/heart.frag.expected | 8 +- tests/real/mandelbulb.expected | 146 +++++------ tests/real/oscars_chair.frag.expected | 66 ++--- tests/real/sult.expected | 32 +-- ...real_party_is_in_your_pocket.frag.expected | 236 +++++++++--------- tests/real/to_the_road_of_ribbon.expected | 22 +- .../real/yx_long_way_from_home.frag.expected | 4 +- tests/unit/externals.expected | 22 +- tests/unit/externals.preserved.expected | 12 +- tests/unit/forbidden.expected | 4 +- tests/unit/function_overload.expected | 30 +-- tests/unit/inout.expected | 76 +++--- tests/unit/macros.expected | 6 +- tests/unit/many_variables.expected | 20 +- tests/unit/qualifiers.expected | 4 +- tests/unit/switch.expected | 6 +- 19 files changed, 417 insertions(+), 412 deletions(-) diff --git a/src/renamer.fs b/src/renamer.fs index fb384fa6..f1ca3cca 100644 --- a/src/renamer.fs +++ b/src/renamer.fs @@ -97,13 +97,18 @@ module private RenamerImpl = | true, occ -> score <- score + occ if score > fst best then best <- score, word + // If the score is equal, consistently pick the same string, to get a more deterministic behavior. + elif score = fst best && word < snd best then best <- score, word let best = snd best assert (best.Length > 0) let firstLetter = best.[0] let lastLetter = best.[best.Length - 1] - // update table + // Update the context table. Due to this side-effect, variables in two identical functions + // may get different names. Compression tests using Crinkler show that (on average) it's + // still worth updating the tables. Results might differ with kkrunchy, more testing + // will be useful. for c in allChars do match contextTable.TryGetValue((c, ident)), contextTable.TryGetValue((c, firstLetter)) with | (false, _), _ -> () diff --git a/tests/compression_results.log b/tests/compression_results.log index 536014ca..f2d3be4d 100644 --- a/tests/compression_results.log +++ b/tests/compression_results.log @@ -1,23 +1,23 @@ -clod.frag... 8955 => 1540.822 -audio-flight-v2.frag 4650 => 904.201 -buoy.frag 4239 => 629.709 -controllable-machinery.frag 7768 => 1230.786 -ed-209.frag 7926 => 1363.517 -elevated.hlsl 3416 => 608.543 -endeavour.frag 2661 => 545.443 -from-the-seas-to-the-stars.frag 14345 => 2346.807 -frozen-wasteland.frag 4609 => 815.278 -kinder_painter.frag 2905 => 451.105 -leizex.frag 2327 => 518.373 -lunaquatic.frag 5231 => 1047.616 -mandelbulb.frag 2419 => 548.489 -ohanami.frag 3292 => 739.505 -orchard.frag 5643 => 1036.998 -oscars_chair.frag 4653 => 988.137 -robin.frag 6338 => 1059.267 -slisesix.frag 4582 => 932.831 -terrarium.frag 3634 => 749.630 -the_real_party_is_in_your_pocket.frag 12248 => 1815.725 -valley_ball.glsl 4386 => 888.815 +clod.frag... 8955 => 1544.138 +audio-flight-v2.frag 4650 => 902.661 +buoy.frag 4239 => 632.427 +controllable-machinery.frag 7768 => 1227.323 +ed-209.frag 7926 => 1363.748 +elevated.hlsl 3416 => 603.918 +endeavour.frag 2661 => 541.942 +from-the-seas-to-the-stars.frag 14345 => 2344.104 +frozen-wasteland.frag 4609 => 812.410 +kinder_painter.frag 2905 => 450.888 +leizex.frag 2327 => 515.566 +lunaquatic.frag 5231 => 1055.816 +mandelbulb.frag 2419 => 546.857 +ohanami.frag 3292 => 736.461 +orchard.frag 5643 => 1034.091 +oscars_chair.frag 4653 => 984.586 +robin.frag 6338 => 1058.995 +slisesix.frag 4582 => 934.241 +terrarium.frag 3634 => 747.342 +the_real_party_is_in_your_pocket.frag 12248 => 1815.043 +valley_ball.glsl 4386 => 888.496 yx_long_way_from_home.frag 3030 => 615.535 -Total: 119257 => 21377.131 +Total: 119257 => 21356.587 diff --git a/tests/real/elevated.hlsl.expected b/tests/real/elevated.hlsl.expected index 97d51b07..45c39155 100644 --- a/tests/real/elevated.hlsl.expected +++ b/tests/real/elevated.hlsl.expected @@ -3,9 +3,9 @@ # define ELEVATED_HLSL_EXPECTED_ # define VAR_q "t" # define VAR_t0 "f" -# define VAR_t1 "y" -# define VAR_t2 "z" -# define VAR_v "m" +# define VAR_t1 "m" +# define VAR_t2 "y" +# define VAR_v "z" # define F_m0 "l" # define F_m1 "l" # define F_m2 "p" @@ -13,56 +13,56 @@ # define F_m4 "s" const char *elevated_hlsl = - "sampler f,y,z;" + "sampler f,m,y;" "float4 t[16];" - "float4x4 m:register(c16);" + "float4x4 z:register(c16);" "float3 D(float2 t)" "{" "float2 w=t-floor(t),s=w*w*w*(w*(w*6-15)+10);" - "float z=tex2Dlod(f,float4((floor(t)+float2(0,0))/256,0,0)),m=tex2Dlod(f,float4((floor(t)+float2(1,0))/256,0,0)),y=tex2Dlod(f,float4((floor(t)+float2(0,1))/256,0,0)),x=tex2Dlod(f,float4((floor(t)+float2(1,1))/256,0,0));" - "return float3(z+(m-z)*s.x+(y-z)*s.y+(z-m-y+x)*s.x*s.y,30*w*w*(w*(w-2)+1)*(float2(m-z,y-z)+(z-m-y+x)*s.yx));" + "float y=tex2Dlod(f,float4((floor(t)+float2(0,0))/256,0,0)),m=tex2Dlod(f,float4((floor(t)+float2(1,0))/256,0,0)),z=tex2Dlod(f,float4((floor(t)+float2(0,1))/256,0,0)),x=tex2Dlod(f,float4((floor(t)+float2(1,1))/256,0,0));" + "return float3(y+(m-y)*s.x+(z-y)*s.y+(y-m-z+x)*s.x*s.y,30*w*w*(w*(w-2)+1)*(float2(m-y,z-y)+(y-m-z+x)*s.yx));" "}" - "float D(float2 f,float z)" + "float D(float2 f,float y)" "{" - "float2 y=0;" + "float2 z=0;" "float x=0,w=3;" - "for(float r=0;r.5)" + "if(y.w>.5)" "{" - "float p=length(z.xyz-t[4].xyz),d=t[1].w-z.y;" + "float p=length(y.xyz-t[4].xyz),d=t[1].w-y.y;" "if(d<0)" "{" - "float3 e=D(z.xz,.001*p,12-log2(p));" - "float o=D(3*z.xz,3),a=D(666*z.xz);" + "float3 e=D(y.xz,.001*p,12-log2(p));" + "float n=D(3*y.xz,3),a=D(666*y.xz);" "r=(.1+.75*t[2].x)*(.8+.2*a);" - "r=lerp(r,lerp(float3(.8,.85,.9),float3(.45,.45,.2)*(.8+.2*a),t[2].x),smoothstep(.5-.8*e.y,1-1.1*e.y,o*.15));" - "r=lerp(r,lerp(float3(.37,.23,.08),float3(.42,.4,.2),t[2].x)*(.5+.5*a),smoothstep(0,1,50*(e.y-1)+(o+t[2].x)/.4));" - "r*=l(z,e,D(z.xz,.001*p,5));" + "r=lerp(r,lerp(float3(.8,.85,.9),float3(.45,.45,.2)*(.8+.2*a),t[2].x),smoothstep(.5-.8*e.y,1-1.1*e.y,n*.15));" + "r=lerp(r,lerp(float3(.37,.23,.08),float3(.42,.4,.2),t[2].x)*(.5+.5*a),smoothstep(0,1,50*(e.y-1)+(n+t[2].x)/.4));" + "r*=l(y,e,D(y.xz,.001*p,5));" "}" "else" "{" "p=(t[1].w-t[4].y)/w.y;" - "z=t[4]+w.xyzz*p;" - "float3 e=normalize(D(float2(512,32)*z.xz+saturate(d*60)*float2(t[3].w,0),.001*p,4)*float3(1,6,1));" + "y=t[4]+w.xyzz*p;" + "float3 a=normalize(D(float2(512,32)*y.xz+saturate(d*60)*float2(t[3].w,0),.001*p,4)*float3(1,6,1));" "r=.12*(float3(.4,1,1)-float3(.2,.6,.4)*saturate(d*16));" "r*=.3+.7*t[2].x;" - "r+=pow(1-mul(-w,e),4)*(pow(mul(t[3],reflect(-w,e)),32)*float3(.32,.31,.3)+.1);" - "r=lerp(r,l(z,e,e),smoothstep(1,0,t[2].x+d*60-D(666*z.xz+saturate(d*60)*float2(t[3].w,0)*2,5))*.5);" + "r+=pow(1-mul(-w,a),4)*(pow(mul(t[3],reflect(-w,a)),32)*float3(.32,.31,.3)+.1);" + "r=lerp(r,l(y,a,a),smoothstep(1,0,t[2].x+d*60-D(666*y.xz+saturate(d*60)*float2(t[3].w,0)*2,5))*.5);" "}" "r*=.7+.3*smoothstep(0,1,256*abs(d));" "r*=exp(-.042*p);" @@ -108,15 +108,15 @@ const char *elevated_hlsl = "float4 s(float2 x:texcoord):color" "{" "float2 s=x+.5/1280;" - "float4 r=tex2D(y,s);" - "float3 w=tex2D(z,s);" + "float4 r=tex2D(m,s);" + "float3 w=tex2D(y,s);" "if(r.w>.5)" "{" - "r=mul(m,float4(r.xyz,1));" + "r=mul(z,float4(r.xyz,1));" "r.y*=-1;" "w=0;" "for(float d=0;d<16;d++)" - "w.x+=tex2D(z,s+d*(.5+.5*r.xy/r.w-s)/16+float2(2,0)/1280).x,w.y+=tex2D(z,s+d*(.5+.5*r.xy/r.w-s)/16+float2(0,0)/1280).y,w.z+=tex2D(z,s+d*(.5+.5*r.xy/r.w-s)/16+float2(-2,0)/1280).z;" + "w.x+=tex2D(y,s+d*(.5+.5*r.xy/r.w-s)/16+float2(2,0)/1280).x,w.y+=tex2D(y,s+d*(.5+.5*r.xy/r.w-s)/16+float2(0,0)/1280).y,w.z+=tex2D(y,s+d*(.5+.5*r.xy/r.w-s)/16+float2(-2,0)/1280).z;" "w/=16;" "}" "w=pow(w,.45)*t[2].z+t[2].y;" diff --git a/tests/real/heart.frag.expected b/tests/real/heart.frag.expected index e7056acd..05071859 100644 --- a/tests/real/heart.frag.expected +++ b/tests/real/heart.frag.expected @@ -12,11 +12,11 @@ const char *heart_frag = "void main()" "{" "vec2 f=(2.*gl_FragCoord.xy-y)/y.y;" - "float r=mod(v,2.)/2.,a=pow(r,.2)*.5+.5;" - "a-=a*.2*sin(r*6.2831*5.)*exp(-r*6.);" + "float m=mod(v,2.)/2.,a=pow(m,.2)*.5+.5;" + "a-=a*.2*sin(m*6.2831*5.)*exp(-m*6.);" "f*=vec2(.5,1.5)+a*vec2(.5,-.5);" - "float m=atan(f.x,f.y)/3.141593,x=length(f),e=abs(m),o=(13.*e-22.*e*e+10.*e*e*e)/(6.-5.*e),n=step(x,o)*pow(1.-x/o,.25);" - "gl_FragColor=vec4(n,0,0,1);" + "float r=atan(f.x,f.y)/3.141593,x=length(f),e=abs(r),C=(13.*e-22.*e*e+10.*e*e*e)/(6.-5.*e),F=step(x,C)*pow(1.-x/C,.25);" + "gl_FragColor=vec4(F,0,0,1);" "}"; #endif // HEART_FRAG_EXPECTED_ diff --git a/tests/real/mandelbulb.expected b/tests/real/mandelbulb.expected index a093068e..f3892ce5 100644 --- a/tests/real/mandelbulb.expected +++ b/tests/real/mandelbulb.expected @@ -5,118 +5,118 @@ const char *mandelbulb_frag = "uniform vec2 resolution;" "uniform float time;" - "bool t(vec4 v,vec3 f,vec3 t,out vec2 i)" + "bool f(vec4 v,vec3 f,vec3 o,out vec2 i)" "{" "vec3 y=f-v.xyz;" - "float c=dot(y,t),e=dot(y,y)-v.w*v.w,o=c*c-e;" - "if(o<0.)" + "float c=dot(y,o),e=dot(y,y)-v.w*v.w,x=c*c-e;" + "if(x<0.)" "return false;" - "float x=sqrt(o);" - "i.x=-c-x;" - "i.y=-c+x;" + "float t=sqrt(x);" + "i.x=-c-t;" + "i.y=-c+t;" "return true;" "}" - "bool t(vec3 v,out float f,out vec4 y)" + "bool f(vec3 v,out float f,out vec4 y)" "{" "vec4 i=vec4(100);" "vec3 c=v;" - "float o=dot(c,c);" - "if(o>1e2)" - "return f=.5*log(o)/pow(8.,0.),y=vec4(1),false;" - "for(int x=1;x<7;x++)" + "float x=dot(c,c);" + "if(x>1e2)" + "return f=.5*log(x)/pow(8.,0.),y=vec4(1),false;" + "for(int t=1;t<7;t++)" "{" "\n#if 0\n" - "float t=sqrt(dot(c,c)),s=acos(c.y/t),z=atan(c.x,c.z);" - "t=pow(t,8.);" + "float z=sqrt(dot(c,c)),o=acos(c.y/z),s=atan(c.x,c.z);" + "z=pow(z,8.);" + "o*=8.;" "s*=8.;" - "z*=8.;" - "c=v+t*vec3(sin(s)*sin(z),cos(s),sin(s)*cos(z));" + "c=v+z*vec3(sin(o)*sin(s),cos(o),sin(o)*cos(s));" "\n#else\n" - "float n=c.x,d=n*n,m=d*d,p=c.y,e=p*p,l=c.z,w=l*l,r=w*w,g=d+w,a=inversesqrt(g*g*g*g*g*g*g),u=m+e*e+r-6.*e*w-6.*d*e+2.*w*d,q=d-e+w;" - "c.x=v.x+64.*n*p*l*(d-w)*q*(m-6.*d*w+r)*u*a;" - "c.y=v.y+-16.*e*g*q*q+u*u;" - "c.z=v.z+-8.*p*q*(m*m-28.*m*d*w+70.*m*r-28.*d*w*r+r*r)*u*a;" + "float d=c.x,n=d*d,m=n*n,p=c.y,e=p*p,a=c.z,w=a*a,l=w*w,g=n+w,r=inversesqrt(g*g*g*g*g*g*g),C=m+e*e+l-6.*e*w-6.*n*e+2.*w*n,F=n-e+w;" + "c.x=v.x+64.*d*p*a*(n-w)*F*(m-6.*n*w+l)*C*r;" + "c.y=v.y+-16.*e*g*F*F+C*C;" + "c.z=v.z+-8.*p*F*(m*m-28.*m*n*w+70.*m*l-28.*n*w*l+l*l)*C*r;" "\n#endif\n" - "o=dot(c,c);" - "i=min(i,vec4(c.xyz*c.xyz,o));" - "if(o>1e2)" - "return y=i,f=.5*log(o)/pow(8.,float(x)),false;" + "x=dot(c,c);" + "i=min(i,vec4(c.xyz*c.xyz,x));" + "if(x>1e2)" + "return y=i,f=.5*log(x)/pow(8.,float(t)),false;" "}" "y=i;" "f=0.;" "return true;" "}" - "bool t(vec3 v,vec3 f,out float y,float c,out vec3 o,out vec4 x,float g)" + "bool f(vec3 v,vec3 c,out float y,float e,out vec3 o,out vec4 x,float g)" "{" "vec4 i=vec4(0,0,0,1.25);" - "vec2 e;" - "if(!t(i,v,f,e))" + "vec2 n;" + "if(!f(i,v,c,n))" "return false;" - "if(e.y<.001)" + "if(n.y<.001)" "return false;" - "if(e.x<.001)" - "e.x=.001;" - "if(e.y>c)" - "e.y=c;" - "float n;" + "if(n.x<.001)" + "n.x=.001;" + "if(n.y>e)" + "n.y=e;" + "float t;" "vec3 z;" "vec4 s;" - "float d=1./sqrt(1.+g*g);" - "for(float w=e.x;w.001)" - "if(t(m,f,b,1e20,F,C,y))" + "if(f(d,y,E,1e20,D,B,o))" "r=.1;" "i=vec3(1);" - "i=mix(i,vec3(.8,.6,.2),sqrt(l.x)*1.25);" - "i=mix(i,vec3(.8,.3,.3),sqrt(l.y)*1.25);" - "i=mix(i,vec3(.7,.4,.3),sqrt(l.z)*1.25);" - "i*=(.5+.5*g.y)*vec3(.14,.15,.16)*.8+r*vec3(1,.85,.4)+.5*q*vec3(.08,.1,.14);" - "i*=vec3(pow(n,.8),pow(n,1.),pow(n,1.1));" + "i=mix(i,vec3(.8,.6,.2),sqrt(t.x)*1.25);" + "i=mix(i,vec3(.8,.3,.3),sqrt(t.y)*1.25);" + "i=mix(i,vec3(.7,.4,.3),sqrt(t.z)*1.25);" + "i*=(.5+.5*g.y)*vec3(.14,.15,.16)*.8+r*vec3(1,.85,.4)+.5*F*vec3(.08,.1,.14);" + "i*=vec3(pow(a,.8),pow(a,1.),pow(a,1.1));" "i=1.5*(i*.15+.85*sqrt(i));" "}" "else" - " i=1.3*vec3(1,.98,.9)*(.7+.3*e.y);" - "vec2 r=v*.5+.5;" - "i*=.7+4.8*r.x*r.y*(1.-r.x)*(1.-r.y);" + " i=1.3*vec3(1,.98,.9)*(.7+.3*p.y);" + "vec2 d=v*.5+.5;" + "i*=.7+4.8*d.x*d.y*(1.-d.x)*(1.-d.y);" "i=clamp(i,0.,1.);" "gl_FragColor=vec4(i,1);" "}"; diff --git a/tests/real/oscars_chair.frag.expected b/tests/real/oscars_chair.frag.expected index 8051feed..76ada657 100644 --- a/tests/real/oscars_chair.frag.expected +++ b/tests/real/oscars_chair.frag.expected @@ -59,12 +59,12 @@ const char *oscars_chair_frag = "v.z=abs(v.z);" "return min(min(min(max(length(max(abs(v.xz)-vec2(.45,.41),0))-.25,abs(v.y)-.02),length(v-vec3(clamp(v.x,-.6,.6),-.1,.6))-.025),length(vec3(abs(v.x)-.6+min(0,v.y)/5,v.y-clamp(v.y,-1.24,1.5*step(0,v.x)),v.z-.6))-.025),max(length(max(abs(v.yz-vec2(1,0))-vec2(.5,.35),0))-.25,abs(v.x-.6)-.03));" "}" - "float h(vec3 v,vec3 y)" + "float h(vec3 v,vec3 x)" "{" - "float x=0,r=0;" - "for(;r<200&&x<30;++r)" - "i=min(i,m=n(v+y*x)),x+=m/2;" - "return x;" + "float y=0,r=0;" + "for(;r<200&&y<30;++r)" + "i=min(i,m=n(v+x*y)),y+=m/2;" + "return y;" "}" "vec3 w(vec3 v,vec3 a)" "{" @@ -95,69 +95,69 @@ const char *oscars_chair_frag = "{" "gl_FragColor*=0;" "for(int p=-6;p<=6;++p)" - "for(int t=-6;t<=6;++t)" - "if(t*t+p*p<37)" - "gl_FragColor=mix(gl_FragColor,max(gl_FragColor,texelFetch(a,ivec2(gl_FragCoord.xy+vec2(t,p)*texelFetch(a,ivec2(gl_FragCoord.xy),0).w),0)),.06);" + "for(int d=-6;d<=6;++d)" + "if(d*d+p*p<37)" + "gl_FragColor=mix(gl_FragColor,max(gl_FragColor,texelFetch(a,ivec2(gl_FragCoord.xy+vec2(d,p)*texelFetch(a,ivec2(gl_FragCoord.xy),0).w),0)),.06);" "}" "else" " if(abs((v.y+=.22)-.5)<.2)" "{" - "vec3 t=vec3(0);" + "vec3 d=vec3(0);" "for(int p=0;p<8;++p)" "{" "float l=2.7;" - "vec3 o=vec3(10+y/4,-4,-1),d=vec3(-7,-2,0);" + "vec3 t=vec3(10+y/4,-4,-1),o=vec3(-7,-2,0);" "m=0;" "if(y>97)" - "d=o=vec3(0,-4,y-97),d.z-=1,g=vec3(0,3,-22),s=.4,c=vec3(3,7,28),z=vec3(-4,0,13);" + "o=t=vec3(0,-4,y-97),o.z-=1,g=vec3(0,3,-22),s=.4,c=vec3(3,7,28),z=vec3(-4,0,13);" "else" " if(y>81)" - "d=o=vec3(0,-3.6,97-y),d.z-=1,g=vec3(0,5,-5),s=.01,l=1.7,c=vec3(7,5,9),z=vec3(0,0,-2);" + "o=t=vec3(0,-3.6,97-y),o.z-=1,g=vec3(0,5,-5),s=.01,l=1.7,c=vec3(7,5,9),z=vec3(0,0,-2);" "else" " if(y>60)" - "o=vec3((y-60)/5-1,-2,13),d=vec3(-7,-5,-7),g=vec3(0,5,-3),m=sin(y-60)/10-.9,c=vec3(7,5,9),z=vec3(-4,0,2);" + "t=vec3((y-60)/5-1,-2,13),o=vec3(-7,-5,-7),g=vec3(0,5,-3),m=sin(y-60)/10-.9,c=vec3(7,5,9),z=vec3(-4,0,2);" "else" " if(y>25)" - "o=vec3(0,0,25-y/2.7),d=vec3(0,-4,18-y/2.7),g=vec3(-2,5,-7),c=vec3(9,5,14),z=vec3(3.5,0,-6);" + "t=vec3(0,0,25-y/2.7),o=vec3(0,-4,18-y/2.7),g=vec3(-2,5,-7),c=vec3(9,5,14),z=vec3(3.5,0,-6);" "else" " m=-.9;" "f=7;" "e=vec3(0,cos(m),sin(m));" - "vec3 u=normalize(d-o),b=normalize(vec3(-u.z,0,u.x));" + "vec3 u=normalize(o-t),C=normalize(vec3(-u.z,0,u.x));" "if(y>81&&y<=97)" - "u.y+=n(vec2(y+6)/2,2)*.05,b.y+=n(vec2(y)/3,2)*.08;" - "u=mat3(b,cross(b,u),u)*normalize(vec3(v*2+vec2(p&1,p/2)/1200-1,l));" - "float C=h(o,u);" - "if(C<30)" - "r=o+u*C,x=vec3(.02,0,0),x=normalize(vec3(n(r+x.xyy)-m,n(r+x.yxy)-m,n(r+x.yyx)-m)),f=2,b=w(r,reflect(u,x))*pow(1+dot(u,x),3);" + "u.y+=n(vec2(y+6)/2,2)*.05,C.y+=n(vec2(y)/3,2)*.08;" + "u=mat3(C,cross(C,u),u)*normalize(vec3(v*2+vec2(p&1,p/2)/1200-1,l));" + "float D=h(t,u);" + "if(D<30)" + "r=t+u*D,x=vec3(.02,0,0),x=normalize(vec3(n(r+x.xyy)-m,n(r+x.yxy)-m,n(r+x.yyx)-m)),f=2,C=w(r,reflect(u,x))*pow(1+dot(u,x),3);" "else" "{" - "b=w(o,u);" + "C=w(t,u);" "l=(.3+.7*pow(1+dot(u,x),2)/4)*(.1+.9*step(r.y,-c.y+.01));" - "o=reflect(u,x);" - "C=m;" + "t=reflect(u,x);" + "D=m;" "f=2;" "i=1e2;" "u=normalize(g-r);" "h(r+u*.01,u);" - "b*=.4+.6*smoothstep(0,n(r)/5,i);" + "C*=.4+.6*smoothstep(0,n(r)/5,i);" "if(r.y<-c.y+.01)" - "if(h(r,o)<30)" - "l*=.2,b*=.7;" - "b+=w(r,o)*l*mix(vec3(1),b,.8);" + "if(h(r,t)<30)" + "l*=.2,C*=.7;" + "C+=w(r,t)*l*mix(vec3(1),C,.8);" "}" "if(y>60&&y<=97)" "gl_FragColor.w=y<=81?" - "(C-15)/6:" - "C/15;" - "b*=smoothstep(0,2,abs(y-60))*smoothstep(0,3,abs(y-112))*(1-(pow(abs(v.x*2-1),4)+pow(abs(v.y*2-1)*2.5,4))*.4);" - "b=pow(.003+b*40,vec3(1,1.1,1.2));" - "t+=b/(b+.4)*1.1;" + "(D-15)/6:" + "D/15;" + "C*=smoothstep(0,2,abs(y-60))*smoothstep(0,3,abs(y-112))*(1-(pow(abs(v.x*2-1),4)+pow(abs(v.y*2-1)*2.5,4))*.4);" + "C=pow(.003+C*40,vec3(1,1.1,1.2));" + "d+=C/(C+.4)*1.1;" "}" "m=0;" "for(int p=0;p<64;++p)" "m+=texture(a,clamp((v-vec2(.4,.532)+vec2(p&7,p/8)/10000)*4*vec2(2.25,4),0,1)).x+texture(a,clamp((v-vec2(.38,.33)+vec2(p&7,p/8)/10000)*vec2(2.25,4),0,1)).y;" - "gl_FragColor.xyz=sqrt(t/8)+m/104*clamp((6-abs(y-10))/5,0,1);" + "gl_FragColor.xyz=sqrt(d/8)+m/104*clamp((6-abs(y-10))/5,0,1);" "}" "}"; diff --git a/tests/real/sult.expected b/tests/real/sult.expected index bda95bcc..4a3650cc 100644 --- a/tests/real/sult.expected +++ b/tests/real/sult.expected @@ -5,7 +5,7 @@ # define VAR_time "c" const char *sult_frag = - "float v=5.,z=.9,y=0.,a=90.,x=0.;" + "float v=5.,z=.9,x=0.,a=90.,y=0.;" "vec3 m=vec3(1),n=vec3(0,0,1),s=vec3(0,0,1.5);" "uniform vec2 r;" "uniform float c;" @@ -16,36 +16,36 @@ const char *sult_frag = "float f=0.,w=10.;" "float e(vec3 m)" "{" - "float y=c,z,a=0.,g,o,t;" + "float y=c,a,g=0.,C,z,F;" "vec3 r;" "m+=(sin(m.zxy*1.7+y)+sin(m.yzx+y*3.))*.2;" - "a=v<6.?" + "g=v<6.?" "length(m.xyz*vec3(1,1,.1)-vec3(0,-.1,y*.15-.3))-.34:" "length(m.xy+vec2(0,.7))-.3+(sin(m.z*17.+y*.6)+sin(m.z*2.)*6.)*.01;" "m.xy=vec2(atan(m.x,m.y)*1.113,1.6-length(m.xy)-sin(y*2.)*.3);" "r=fract(m.xzz+.5).xyz-.5;" "r.y=(m.y-.35)*1.3;" - "z=max(abs(m.y-.3)-.05,abs(length(fract(m.xz)-.5)-.4)-.03);" - "f=step(a,z);" - "return min(min(z,a),m.y-.2);" + "a=max(abs(m.y-.3)-.05,abs(length(fract(m.xz)-.5)-.4)-.03);" + "f=step(g,a);" + "return min(min(a,g),m.y-.2);" "}" - "vec3 d=vec3(.19,.2,.24),o=vec3(1),t=vec3(.45,.01,0),g=vec3(.17,0,0);" + "vec3 d=vec3(.19,.2,.24),C=vec3(1),F=vec3(.45,.01,0),g=vec3(.17,0,0);" "void main()" "{" "vec2 l=-1.+2.*gl_FragCoord.xy/r.xy;" - "vec3 i=normalize(rotatey(rotatey(vec3(l.y*z,l.x*z*1.33,1),-y*.035).yxz,(a+x*c)*.035)),p=n+s*c;" - "float u=1.,h=0.,F,C,b=0.,Z,Y,X,W;" - "vec3 V=vec3(.01,0,0),U=V.yyy,T;" + "vec3 I=normalize(rotatey(rotatey(vec3(l.y*z,l.x*z*1.33,1),-x*.035).yxz,(a+y*c)*.035)),H=n+s*c;" + "float u=1.,E=0.,i,B,A=0.,D,p,G,J;" + "vec3 K=vec3(.01,0,0),L=K.yyy,M;" "for(;u>.1;)" "{" - "for(F=b,C=1.;F.005;F+=C)" - "C=e(p+i*F);" - "if(F.005;i+=B)" + "B=e(H+I*i);" + "if(i0.)" - "f=vec2(f.x-u*f.y,-u*f.x-f.y)/2.;" + "f.y=f.y+1./C;" + "if(f.x+C*f.y>0.)" + "f=vec2(f.x-C*f.y,-C*f.x-f.y)/2.;" "f.x-=clamp(f.x,-2.,0.);" - "b=m(b,-max(-o.z,-length(f)*sign(f.y)+.565),512.);" - "if(b0.&&o.x0.&&h.xo.y||abs(d)<1e-5)" + "k=x(r+p*d);" + "e=k.x;" + "if(d>h.y||abs(e)<1e-5)" "break;" - "b+=d;" + "d+=e;" "}" - "if(b0.)" "return y=f,i;" "m=-1.;" - "vec2 o=vec2(-1,-3);" - "float r=(o.x-l.y)/v.y,b=(o.y-l.z)/v.z;" - "vec2 d=s((l-vec3(0,o+2.))*vec3(0,.5,.5),v*vec3(0,.5,.5)),p=l.yz+v.yz*d.y-o-2.;" - "if(d.x0.&&p.x<0.&&p.y<0.)" - "y=vec3(-p*.5,0).zxy,m=d.y;" + "vec2 h=vec2(-1,-3);" + "float r=(h.x-l.y)/v.y,d=(h.y-l.z)/v.z;" + "vec2 c=s((l-vec3(0,h+2.))*vec3(0,.5,.5),v*vec3(0,.5,.5)),p=l.yz+v.yz*c.y-h-2.;" + "if(c.x0.&&p.x<0.&&p.y<0.)" + "y=vec3(-p*.5,0).zxy,m=c.y;" "else" - " if(r>0.&&(r0.&&(r0.&&(b0.&&(d5.||abs(w.y)>2.5||abs(w.z)>3.3?" "vec4(-1):" @@ -254,21 +254,21 @@ const char *the_real_party_is_in_your_pocket_frag = "for(int i=0;i<4;++i)" "{" "v=normalize(v);" - "vec3 z,p,k;" + "vec3 z,p,e;" "vec4 r=s(l,v,z);" - "float b=r.x;" - "if(b<0.)" + "float d=r.x;" + "if(d<0.)" "{" "y+=max(f*vec3(.9)*(.5+.5*dot(v,normalize(vec3(-2,4,1))))*.4*1.3*vec3(1,.9,.65)+f*vec3(.9)*step(.9,dot(v,normalize(vec3(6,2,1))))*10.4*2.3+f*vec3(.9)*step(.95,dot(v,normalize(vec3(-2,1,3))))*10.4*1.5,0.)*pow(max(.5+.5*-v.z,0.),.2);" "break;" "}" - "float w=floor(r.y/8.);" + "float c=floor(r.y/8.);" "r.y=mod(r.y,8.);" - "vec3 o=l+v*b;" - "vec2 d=vec2(6.28319*m(),m()*2.-1.);" - "vec3 c=z+vec3(sqrt(1.-d.y*d.y)*vec2(cos(d.x),sin(d.x)),d.y);" - "float e=r.y>1.5?" - "mix(o.x>0.?" + "vec3 h=l+v*d;" + "vec2 w=vec2(6.28319*m(),m()*2.-1.);" + "vec3 k=z+vec3(sqrt(1.-w.y*w.y)*vec2(cos(w.x),sin(w.x)),w.y);" + "float t=r.y>1.5?" + "mix(h.x>0.?" ".1:" ".05,.5,pow(1.-clamp(dot(-v,z),0.,1.),2.)):" "mix(.2,.8,pow(1.-clamp(dot(-v,z),0.,1.),1.5));" @@ -276,7 +276,7 @@ const char *the_real_party_is_in_your_pocket_frag = "{" "if(a)" "break;" - "l=o+z*2e-4;" + "l=h+z*2e-4;" "f*=mix(.1,.8,pow(1.-clamp(dot(-v,z),0.,1.),3.))*mix(vec3(1),vec3(1,.9,.5),.5);" "v=reflect(v,z)+(vec3(m(),m(),m())-.5)*.3;" "}" @@ -285,112 +285,112 @@ const char *the_real_party_is_in_your_pocket_frag = "{" "if(a)" "break;" - "e=.02;" - "if(m()>e)" - "l=o-z*2e-4*-sign(v.z),v+=(vec3(m(),m(),m())-.5)*.1;" + "t=.02;" + "if(m()>t)" + "l=h-z*2e-4*-sign(v.z),v+=(vec3(m(),m(),m())-.5)*.1;" "else" - " l=o+z*2e-4,v=reflect(v,z)+(vec3(m(),m(),m())-.5)*.3;" + " l=h+z*2e-4,v=reflect(v,z)+(vec3(m(),m(),m())-.5)*.3;" "}" "else" " if(r.y<.5||r.y>2.5)" "{" - "vec3 t=r.y>2.5?" + "vec3 b=r.y>2.5?" "vec3(.08):" "vec3(.7);" "if(r.y>3.5)" "{" - "t=vec3(.008);" + "b=vec3(.008);" "if(!a)" "{" - "if(o.y>.5)" + "if(h.y>.5)" "{" - "vec2 h=r.zw-vec2(-.38,.6);" - "float g=min(min(min(min(min(min(max(length(h-vec2(.005))-.0125,-(length(h-vec2(-.012,.005))-.025)),max(length(h-vec2(-.02,.005))-.0125,-(length(h-vec2(-.045,.005))-.03))),max(length(h-vec2(.005))-.0125,-(length(h-vec2(-.012,.005))-.025))),max(length(h-vec2(.03,.005))-.0125,-(length(h-vec2(.02,.005))-.02))),abs(length(h-vec2(-.037,-.0398))-.0104)),n(h,vec2(-.064,-.05),vec2(-.064,-.03))),max(-h.x-.063,abs(length(vec2(max(0.,h.x+.06),h.y+.035))-.006)));" - "h.x-=.091;" - "g=min(g,n(h,vec2(-.064,-.05),vec2(-.064,-.03)));" - "g=min(g,max(-h.x-.063,abs(length(vec2(max(0.,h.x+.06),h.y+.035))-.006)));" - "g=min(g,n(h,vec2(-.054,-.05),vec2(-.059,-.041)));" - "h.x+=.091;" - "g=min(g,n(h,vec2(.009,-.05),vec2(.009,-.03)));" - "g=min(g,n(h,vec2(.009,-.05),vec2(.018,-.05)));" - "g=min(g,n(h,vec2(.009,-.03),vec2(.018,-.03)));" - "g=min(g,n(h,vec2(.009,-.039),vec2(.018,-.039)));" - "h.x=abs(h.x+.01);" - "h.x=abs(h.x-.006);" - "g=min(g,n(h,vec2(0,-.05),vec2(.006,-.03)));" - "t=mix(t,vec3(.3),step(g-.0018,0.));" + "vec2 o=r.zw-vec2(-.38,.6);" + "float g=min(min(min(min(min(min(max(length(o-vec2(.005))-.0125,-(length(o-vec2(-.012,.005))-.025)),max(length(o-vec2(-.02,.005))-.0125,-(length(o-vec2(-.045,.005))-.03))),max(length(o-vec2(.005))-.0125,-(length(o-vec2(-.012,.005))-.025))),max(length(o-vec2(.03,.005))-.0125,-(length(o-vec2(.02,.005))-.02))),abs(length(o-vec2(-.037,-.0398))-.0104)),n(o,vec2(-.064,-.05),vec2(-.064,-.03))),max(-o.x-.063,abs(length(vec2(max(0.,o.x+.06),o.y+.035))-.006)));" + "o.x-=.091;" + "g=min(g,n(o,vec2(-.064,-.05),vec2(-.064,-.03)));" + "g=min(g,max(-o.x-.063,abs(length(vec2(max(0.,o.x+.06),o.y+.035))-.006)));" + "g=min(g,n(o,vec2(-.054,-.05),vec2(-.059,-.041)));" + "o.x+=.091;" + "g=min(g,n(o,vec2(.009,-.05),vec2(.009,-.03)));" + "g=min(g,n(o,vec2(.009,-.05),vec2(.018,-.05)));" + "g=min(g,n(o,vec2(.009,-.03),vec2(.018,-.03)));" + "g=min(g,n(o,vec2(.009,-.039),vec2(.018,-.039)));" + "o.x=abs(o.x+.01);" + "o.x=abs(o.x-.006);" + "g=min(g,n(o,vec2(0,-.05),vec2(.006,-.03)));" + "b=mix(b,vec3(.3),step(g-.0018,0.));" "}" "if(length(r.zw-vec2(-.43,.605))<.014)" "y+=f*3.*vec3(1,.01,.01)*(.8+8.*(1.-x(.01,length(r.zw-vec2(-.43,.605)))));" - "if(r.w>0.&&o.y<.2)" + "if(r.w>0.&&h.y<.2)" "{" - "t=mix(t,vec3(.3),step(n(r.zw-vec2(0,.103)),0.));" + "b=mix(b,vec3(.3),step(n(r.zw-vec2(0,.103)),0.));" "{" - "vec2 g=vec2(-.07,.02),h=vec2(-.09,.03),u=vec2(-.1,0),q=u+normalize(u-h)*.03,C=vec2(-.065,-.026);" - "t=mix(t,vec3(.520661,.00153787,.064975),step(min(m(r.zw-vec2(.16,.103),u,q,C),m(r.zw-vec2(.16,.103),g,h,u))-.007,0.));" + "vec2 g=vec2(-.07,.02),o=vec2(-.09,.03),C=vec2(-.1,0),D=C+normalize(C-o)*.03,B=vec2(-.065,-.026);" + "b=mix(b,vec3(.520661,.00153787,.064975),step(min(m(r.zw-vec2(.16,.103),C,D,B),m(r.zw-vec2(.16,.103),g,o,C))-.007,0.));" "}" "{" - "vec2 h=r.zw-vec2(.16,.103);" - "h-=vec2(-.029,-.015);" - "h.x+=cos(h.y*30.)*.01;" - "h.y-=cos(h.x*20.)*.01;" - "t=mix(t,vec3(.093564,.0865052,.434048),step(abs(length(h)-.02)-.007,0.));" + "vec2 o=r.zw-vec2(.16,.103);" + "o-=vec2(-.029,-.015);" + "o.x+=cos(o.y*30.)*.01;" + "o.y-=cos(o.x*20.)*.01;" + "b=mix(b,vec3(.093564,.0865052,.434048),step(abs(length(o)-.02)-.007,0.));" "}" "{" - "vec2 h=r.zw-vec2(.16,.103),g=vec2(-.01,.02),u=vec2(-.007,0),q=vec2(-.007,-.0205),C=q+normalize(q-u)*.01,F=vec2(.02,-.02);" - "t=mix(t,vec3(.186082,.481799,.0177778),step(min(m(h,q,C,F),m(h,g,u,q))-.007,0.));" + "vec2 o=r.zw-vec2(.16,.103),g=vec2(-.01,.02),C=vec2(-.007,0),D=vec2(-.007,-.0205),B=D+normalize(D-C)*.01,A=vec2(.02,-.02);" + "b=mix(b,vec3(.186082,.481799,.0177778),step(min(m(o,D,B,A),m(o,g,C,D))-.007,0.));" "}" "{" - "vec2 h=r.zw-vec2(.16,.103);" - "h-=vec2(.045,-.015);" - "h.x+=cos(h.y*20.+1.)*.005;" - "h.y-=cos(h.x*20.+25.)*.01;" - "t=mix(t,vec3(.730857,.454964,.000553633),step(abs(length(h)-.02)-.007,0.));" + "vec2 o=r.zw-vec2(.16,.103);" + "o-=vec2(.045,-.015);" + "o.x+=cos(o.y*20.+1.)*.005;" + "o.y-=cos(o.x*20.+25.)*.01;" + "b=mix(b,vec3(.730857,.454964,.000553633),step(abs(length(o)-.02)-.007,0.));" "}" "{" - "vec2 h=r.zw-vec2(.24,.103),g=vec2(-.006,-.026),u=vec2(-.002,0),q=vec2(-.007,.016),C=q+normalize(q-u)*.012,F=vec2(.02),T=C+normalize(F-C)*.05,Z=vec2(.002,-.007),Y=vec2(.025,-.028);" - "t=mix(t,vec3(0,.332318,.292872),step(min(min(min(m(h,q,C,F),m(h,g,u,q)),m(h,F,T,Z)),m(h,Z,(Z+Y)/2.+vec2(.001),Y))-.007,0.));" + "vec2 o=r.zw-vec2(.24,.103),g=vec2(-.006,-.026),C=vec2(-.002,0),D=vec2(-.007,.016),B=D+normalize(D-C)*.012,A=vec2(.02),E=B+normalize(A-B)*.05,F=vec2(.002,-.007),G=vec2(.025,-.028);" + "b=mix(b,vec3(0,.332318,.292872),step(min(min(min(m(o,D,B,A),m(o,g,C,D)),m(o,A,E,F)),m(o,F,(F+G)/2.+vec2(.001),G))-.007,0.));" "}" "}" "{" - "vec2 h=vec2(160,144)/1.5,g=(r.zw-vec2(-.001,.486))*3.75*vec2(h.y/h.x,1)*.5+.5,u=fract(g*h);" - "g=floor(g*h)/h;" + "vec2 o=vec2(160,144)/1.5,g=(r.zw-vec2(-.001,.486))*3.75*vec2(o.y/o.x,1)*.5+.5,C=fract(g*o);" + "g=floor(g*o)/o;" "if(max(abs(g.x-.5),abs(g.y-.5))<.5)" "{" - "vec3 q=vec3(0);" - "vec2 C=(g*2.-1.)*vec2(h.x/h.y,1);" - "float F=min(min(min(min(min(min(min(min(min(min(min(min(min(min(min(min(min(n(vec4(1.54,.53,.91,.72),C),n(vec4(.63,.78,.91,.72),C)),n(vec4(.61,1.675,.72,.64),C)),n(vec4(2.7,3.11,.72,.64),C)),n(vec4(3.45,3.65,.72,.64),C)),n(vec4(4.71,5.02,.72,.64),C)),n(vec4(5.3,5.51,.72,.64),C)),n(vec4(5.96,6.43,.72,.64),C)),n(vec4(3.2,1.27,.45,.35),C)),n(vec4(1.3,2.3,.45,.35),C)),n(vec4(2.58,4.2,.45,.35),C)),n(vec4(3.2,3.95,.35,.25),C)),n(vec4(5.2,5.93,.35,.25),C)),n(vec4(7.9,8.15,.35,.25),C)),n(vec4(.2,1.16,.32,.17),C)),max(length(C)-.84,-length(C)+.72)),max(length(C)-.52,-length(C)+.45)),max(length(C)-.17,-length(C)+.08)),Z=floor(g.y*8.);" - "q=.5+.5*cos(vec3(.8,.3,2)*(Z+1.));" - "q=mix(q,vec3(1),step(F,0.));" - "q*=vec3(1,1,.8);" - "q*=smoothstep(.1,.2,u.x)*smoothstep(.1,.2,u.y);" - "y+=f*3.*q;" - "t=vec3(.1);" + "vec3 D=vec3(0);" + "vec2 B=(g*2.-1.)*vec2(o.x/o.y,1);" + "float A=min(min(min(min(min(min(min(min(min(min(min(min(min(min(min(min(min(n(vec4(1.54,.53,.91,.72),B),n(vec4(.63,.78,.91,.72),B)),n(vec4(.61,1.675,.72,.64),B)),n(vec4(2.7,3.11,.72,.64),B)),n(vec4(3.45,3.65,.72,.64),B)),n(vec4(4.71,5.02,.72,.64),B)),n(vec4(5.3,5.51,.72,.64),B)),n(vec4(5.96,6.43,.72,.64),B)),n(vec4(3.2,1.27,.45,.35),B)),n(vec4(1.3,2.3,.45,.35),B)),n(vec4(2.58,4.2,.45,.35),B)),n(vec4(3.2,3.95,.35,.25),B)),n(vec4(5.2,5.93,.35,.25),B)),n(vec4(7.9,8.15,.35,.25),B)),n(vec4(.2,1.16,.32,.17),B)),max(length(B)-.84,-length(B)+.72)),max(length(B)-.52,-length(B)+.45)),max(length(B)-.17,-length(B)+.08)),F=floor(g.y*8.);" + "D=.5+.5*cos(vec3(.8,.3,2)*(F+1.));" + "D=mix(D,vec3(1),step(A,0.));" + "D*=vec3(1,1,.8);" + "D*=smoothstep(.1,.2,C.x)*smoothstep(.1,.2,C.y);" + "y+=f*3.*D;" + "b=vec3(.1);" "}" "}" "}" "}" "if(r.y>3.&&r.y<3.2)" - "t=vec3(.4);" - "f*=t;" - "l=o+z*2e-4;" - "v=c;" + "b=vec3(.4);" + "f*=b;" + "l=h+z*2e-4;" + "v=k;" "a=true;" "}" "else" "{" - "vec3 h=w>1.5?" + "vec3 o=c>1.5?" "vec3(1,.02,.2):" - "w>.5?" + "c>.5?" "vec3(.2,1,.02):" "vec3(.02,.2,1);" - "if(m()>mix(.2,1.,e))" + "if(m()>mix(.2,1.,t))" "{" "if(r.y>1.5)" - "h=vec3(.02);" - "f*=h;" - "l=o+z*2e-4;" - "v=c;" + "o=vec3(.02);" + "f*=o;" + "l=h+z*2e-4;" + "v=k;" "a=true;" "}" "else" @@ -399,8 +399,8 @@ const char *the_real_party_is_in_your_pocket_frag = "break;" "f*=r.y>1.5?" "vec3(.5):" - ".9*mix(h,vec3(1),.25);" - "l=o+z*2e-4;" + ".9*mix(o,vec3(1),.25);" + "l=h+z*2e-4;" "v=reflect(v,z)+(vec3(m(),m(),m())-.5)*.4;" "}" "}" @@ -416,10 +416,10 @@ const char *the_real_party_is_in_your_pocket_frag = "{" "y=float(v)+gl_TexCoord[0].x*16.;" "float a=m()*6.28319;" - "vec2 x=vec2(cos(a),sin(a))*sqrt(1.-sqrt(1.-m()))*1.2;" + "vec2 o=vec2(cos(a),sin(a))*sqrt(1.-sqrt(1.-m()))*1.2;" "if(int(y)%4==0)" - "x*=15.*length(x);" - "l+=h(vec3(0,0,4.8),vec3((gl_FragCoord.xy-vec2(960,540)+x)/540.,-3.5))/48.;" + "o*=15.*length(o);" + "l+=h(vec3(0,0,4.8),vec3((gl_FragCoord.xy-vec2(960,540)+o)/540.,-3.5))/48.;" "}" "l/=(l+1.)/2.;" "gl_FragColor.xyz=pow(l+.01*vec3(1,1,.5),vec3(1./2.2))+m()/1e2;" diff --git a/tests/real/to_the_road_of_ribbon.expected b/tests/real/to_the_road_of_ribbon.expected index 7b23d324..786f6d68 100644 --- a/tests/real/to_the_road_of_ribbon.expected +++ b/tests/real/to_the_road_of_ribbon.expected @@ -27,21 +27,21 @@ const char *to_the_road_of_ribbon_frag = "vec2 t=-1.+2.*gl_FragCoord.xy/resolution.xy;" "t.x*=resolution.x/resolution.y;" "vec4 v=vec4(1);" - "vec3 o=vec3(sin(time)*.5,cos(time*.5)*.25+.25,time),c=normalize(vec3(t.x*1.6,t.y,1)),y=o,f;" + "vec3 m=vec3(sin(time)*.5,cos(time*.5)*.25+.25,time),o=normalize(vec3(t.x*1.6,t.y,1)),c=m,f;" "float e=0.;" "for(int r=0;r<64;r++)" - "e=o(y),y+=e*c;" - "f=y;" - "float r=length(y-o)*.02;" - "c=reflect(c,gn(y));" - "y+=c;" - "for(int m=0;m<64;m++)" - "e=o(y),y+=e*c;" - "v=max(dot(gn(y),vec3(.1,.1,0)),0.)+vec4(.3,cos(time*.5)*.5+.5,sin(time*.5)*.5+.5,1)*min(length(y-o)*.04,1.);" + "e=o(c),c+=e*o;" + "f=c;" + "float r=length(c-m)*.02;" + "o=reflect(o,gn(c));" + "c+=o;" + "for(int g=0;g<64;g++)" + "e=o(c),c+=e*o;" + "v=max(dot(gn(c),vec3(.1,.1,0)),0.)+vec4(.3,cos(time*.5)*.5+.5,sin(time*.5)*.5+.5,1)*min(length(c-m)*.04,1.);" "if(oa(f)>ob(f))" "v=mix(v,vec4(cos(time*.3)*.5+.5,cos(time*.2)*.5+.5,sin(time*.3)*.5+.5,1),.3);" - "vec4 m=(v+vec4(r)+(1.-min(f.y+1.9,1.))*vec4(1,.8,.7,1))*min(time*.5,1.);" - "gl_FragColor=vec4(m.xyz,1);" + "vec4 g=(v+vec4(r)+(1.-min(f.y+1.9,1.))*vec4(1,.8,.7,1))*min(time*.5,1.);" + "gl_FragColor=vec4(g.xyz,1);" "}"; #endif // TO_THE_ROAD_OF_RIBBON_EXPECTED_ diff --git a/tests/real/yx_long_way_from_home.frag.expected b/tests/real/yx_long_way_from_home.frag.expected index 33d47fda..f3c9f253 100644 --- a/tests/real/yx_long_way_from_home.frag.expected +++ b/tests/real/yx_long_way_from_home.frag.expected @@ -145,8 +145,8 @@ const char *yx_long_way_from_home_frag = "vec3 o=d(y,1e-4);" "float h=dot(l,o);" "vec3 g,k;" - "float b;" - "if(h>0.&&!d(t+l*.002,o,g,k,b))" + "float B;" + "if(h>0.&&!d(t+l*.002,o,g,k,B))" "c+=n*h*z;" "i=s(i.y);" "}" diff --git a/tests/unit/externals.expected b/tests/unit/externals.expected index 8beaa2cb..2f4e5207 100644 --- a/tests/unit/externals.expected +++ b/tests/unit/externals.expected @@ -1,26 +1,26 @@ // Generated with (https://github.com/laurentlb/Shader_Minifier/) #ifndef EXTERNALS_EXPECTED_ # define EXTERNALS_EXPECTED_ -# define VAR_e "t" +# define VAR_e "I" # define VAR_i "i" -# define VAR_n "n" +# define VAR_n "J" const char *externals_frag = - "uniform int i,n,t;" - "int r()" + "uniform int i,J,I;" + "int H()" "{" - "int n,t,r,u,e;" + "int J,I,F,G,H;" "return i;" "}" - "int u()" + "int G()" "{" - "int i,t,r,u,e;" - "return n;" + "int i,I,F,G,H;" + "return J;" "}" - "int e()" + "int F()" "{" - "int i,r,u,n,e;" - "return t;" + "int i,F,G,J,H;" + "return I;" "}"; #endif // EXTERNALS_EXPECTED_ diff --git a/tests/unit/externals.preserved.expected b/tests/unit/externals.preserved.expected index ecc361a3..34a2a5c7 100644 --- a/tests/unit/externals.preserved.expected +++ b/tests/unit/externals.preserved.expected @@ -4,19 +4,19 @@ const char *externals_frag = "uniform int i,n,e;" - "int t()" + "int H()" "{" - "int n,e,t,r,u;" + "int n,e,F,G,H;" "return i;" "}" - "int r()" + "int G()" "{" - "int i,e,t,r,u;" + "int i,e,F,G,H;" "return n;" "}" - "int u()" + "int F()" "{" - "int i,t,r,n,u;" + "int i,F,G,n,H;" "return e;" "}"; diff --git a/tests/unit/forbidden.expected b/tests/unit/forbidden.expected index 65e4fba0..4e775b3a 100644 --- a/tests/unit/forbidden.expected +++ b/tests/unit/forbidden.expected @@ -1,4 +1,4 @@ -struct f{float f;};float t() +struct f{float f;};float L() { return 42.; -} \ No newline at end of file +} diff --git a/tests/unit/function_overload.expected b/tests/unit/function_overload.expected index bc522c05..b61a4f92 100644 --- a/tests/unit/function_overload.expected +++ b/tests/unit/function_overload.expected @@ -3,37 +3,37 @@ # define FUNCTION_OVERLOAD_EXPECTED_ const char *function_overload_frag = - "int t()" + "int H()" "{" "return 0;" "}" - "int t(int n)" + "int H(int G)" "{" - "return t()+n;" + "return H()+G;" "}" - "int t(int i,int n)" + "int H(int i,int G)" "{" - "return t(i)+n;" + "return H(i)+G;" "}" - "int t(int i,int n,int r)" + "int H(int i,int G,int E)" "{" - "return t(i,n)+r;" + "return H(i,G)+E;" "}" - "int t(int i,int n,int r,int u)" + "int H(int i,int G,int E,int D)" "{" - "return t(i,n,r)+u;" + "return H(i,G,E)+D;" "}" - "int n(int n)" + "int G(int G)" "{" - "return n;" + "return G;" "}" - "int n(int i,int r)" + "int G(int i,int H)" "{" - "return n(i)*r;" + "return G(i)*H;" "}" - "int n(int i,int r,int u)" + "int G(int i,int H,int E)" "{" - "return n(i,r)*u;" + "return G(i,H)*E;" "}"; #endif // FUNCTION_OVERLOAD_EXPECTED_ diff --git a/tests/unit/inout.expected b/tests/unit/inout.expected index 870b0136..8701b7c1 100644 --- a/tests/unit/inout.expected +++ b/tests/unit/inout.expected @@ -1,62 +1,62 @@ // Generated with (https://github.com/laurentlb/Shader_Minifier/) -# define VAR_ambientLight "z" -# define VAR_diffuseColor "e" -# define VAR_emissiveColor "n" -# define VAR_fragmentColor "r" -# define VAR_mediumDensity "f" -# define VAR_normal "m" -# define VAR_specularColor "o" +# define VAR_ambientLight "f" +# define VAR_diffuseColor "z" +# define VAR_emissiveColor "r" +# define VAR_fragmentColor "m" +# define VAR_mediumDensity "s" +# define VAR_normal "d" +# define VAR_specularColor "C" # define VAR_texture0 "v" -# define VAR_viewVec "d" +# define VAR_viewVec "c" // tests/unit/inout.frag "#version 330\n" "uniform samplerCube v;" - "in vec3 m,d;" - "out vec4 r;" + "in vec3 d,c;" + "out vec4 m;" "void main()" "{" - "vec3 t=normalize(d),f=normalize(m),c=vec3(.1,.2,.3),z=texture(v,reflect(-t,f)).xyz,e=texture(v,refract(-t,f,1./1.5)).xyz,p=mix(c*e,z,.1);" - "r=vec4(p,1);" + "vec3 s=normalize(c),f=normalize(d),p=vec3(.1,.2,.3),r=texture(v,reflect(-s,f)).xyz,z=texture(v,refract(-s,f,1./1.5)).xyz,C=mix(p*z,r,.1);" + "m=vec4(C,1);" "}" - "vec3 t(vec3 v,vec3 m,vec3 f)" + "vec3 t(vec3 v,vec3 d,vec3 f)" "{" - "float r=1.-clamp(dot(m,f),0.,1.);" - "return r*r*r*r*r*(1.-v)+v;" + "float m=1.-clamp(dot(d,f),0.,1.);" + "return m*m*m*m*m*(1.-v)+v;" "}" - "vec3 t(vec3 v,vec3 m,vec3 f,vec3 r,vec3 d,float c)" + "vec3 t(vec3 v,vec3 m,vec3 f,vec3 d,vec3 s,float c)" "{" - "vec3 p=normalize(v+m),z,e,o;" - "float s=1.+2048.*(1.-c)*(1.-c);" - "z=r;" - "e=vec3(pow(clamp(dot(p,f),0.,1.),s)*(s+4.)/8.);" - "o=t(d,v,p);" - "return mix(z,e,o);" + "vec3 r=normalize(v+m),p,z,C;" + "float M=1.+2048.*(1.-c)*(1.-c);" + "p=d;" + "z=vec3(pow(clamp(dot(r,f),0.,1.),M)*(M+4.)/8.);" + "C=t(s,v,r);" + "return mix(p,z,C);" "}", // tests/unit/inout2.frag "#version 330\n" "uniform samplerCube v;" - "uniform float f;" - "uniform vec3 z,e,n,o;" - "in vec3 m,d;" - "out vec4 r;" - "vec3 t(vec3 v,vec3 m,vec3 f)" + "uniform float s;" + "uniform vec3 f,z,r,C;" + "in vec3 d,c;" + "out vec4 m;" + "vec3 t(vec3 v,vec3 d,vec3 f)" "{" - "float r=1.-clamp(dot(m,f),0.,1.);" - "return r*r*r*r*r*(1.-v)+v;" + "float m=1.-clamp(dot(d,f),0.,1.);" + "return m*m*m*m*m*(1.-v)+v;" "}" "void main()" "{" - "vec3 v=e,f=n+mix(v*z,z,.5);" - "r=vec4(f,1);" + "vec3 v=z,d=r+mix(v*f,f,.5);" + "m=vec4(d,1);" "}" - "vec3 t(vec3 v,vec3 m,vec3 f,vec3 r,vec3 z,float c)" + "vec3 t(vec3 v,vec3 f,vec3 d,vec3 m,vec3 s,float c)" "{" - "vec3 d=normalize(v+m),e,o,p;" - "float s=1.+2048.*(1.-c)*(1.-c);" - "e=r;" - "o=vec3(pow(clamp(dot(d,f),0.,1.),s)*(s+4.)/8.);" - "p=t(z,v,d);" - "return mix(e,o,p);" + "vec3 r=normalize(v+f),z,C,p;" + "float M=1.+2048.*(1.-c)*(1.-c);" + "z=m;" + "C=vec3(pow(clamp(dot(r,d),0.,1.),M)*(M+4.)/8.);" + "p=t(s,v,r);" + "return mix(z,C,p);" "}", diff --git a/tests/unit/macros.expected b/tests/unit/macros.expected index ab0539c0..025b6777 100644 --- a/tests/unit/macros.expected +++ b/tests/unit/macros.expected @@ -19,10 +19,10 @@ const char *macros_frag = "#define n$\n" "#define o$\n" "#define p$\n" - "int t()" + "int E()" "{" - "int t=1,r=2,u=3,Z=4,Y=5,X=6,W=7,V=8,U=9,T=10,S=11,R=12;" - "return t+Y+R;" + "int E=1,D=2,C=3,B=4,A=5,F=6,G=7,H=8,I=9,J=10,K=11,L=12;" + "return E+A+L;" "}"; #endif // MACROS_EXPECTED_ diff --git a/tests/unit/many_variables.expected b/tests/unit/many_variables.expected index b674f897..a850613d 100644 --- a/tests/unit/many_variables.expected +++ b/tests/unit/many_variables.expected @@ -1,15 +1,15 @@ // Generated with (https://github.com/laurentlb/Shader_Minifier/) // tests/unit/many_variables.frag -"int t(float t,float o,float l,float f,float a,float n,float i,float r,float u,float e,float Z,float Y)" +"int L(float L,float K,float J,float I,float H,float G,float F,float E,float D,float C,float B,float A)" "{" - "float X=t,W=o,V=l,U=f,T=a,S=n;" - "int R=1,Q=2,P=3,O=4,N=5,M=6,L=7,K=8;" - "float J=i,I=r,H=u,G=e,F=Z,E=Y;" - "int D=1,C=2,B=3,A=4,z=5,y=6,x=7,w=8;" - "float v=0.;" - "int s=1,q=2,p=3,m=4,k=5,j=6,h=7,g=8;" - "float d=0.;" - "int c=1,b=2,at=3,ab=4,ac=5,ad=6,ag=7,ah=8;" - "return K+w+g+ah;" + "float M=L,f=K,N=J,O=I,P=H,Q=G;" + "int R=1,S=2,T=3,U=4,V=5,W=6,X=7,Y=8;" + "float Z=F,a=E,b=D,c=C,d=B,e=A;" + "int g=1,h=2,i=3,j=4,k=5,l=6,m=7,n=8;" + "float o=0.;" + "int p=1,q=2,r=3,s=4,t=5,u=6,v=7,w=8;" + "float x=0.;" + "int y=1,z=2,at=3,aa=4,ab=5,ac=6,ad=7,aA=8;" + "return Y+n+w+aA;" "}", diff --git a/tests/unit/qualifiers.expected b/tests/unit/qualifiers.expected index 93d607d1..b6dec1ce 100644 --- a/tests/unit/qualifiers.expected +++ b/tests/unit/qualifiers.expected @@ -9,11 +9,11 @@ const char *qualifiers_frag = "{" "return f;" "}" - "float t(const float f)" + "float M(const float f)" "{" "return f;" "}" - "float o(inout float f)" + "float L(inout float f)" "{" "return f;" "}"; diff --git a/tests/unit/switch.expected b/tests/unit/switch.expected index a0f2d321..1043474e 100644 --- a/tests/unit/switch.expected +++ b/tests/unit/switch.expected @@ -29,7 +29,7 @@ void h(int G) break; } } -float e() +float D() { switch(42){ case 42: @@ -37,8 +37,8 @@ float e() float k=2.4; return G+k; case 43: - float h=4.3; - return h+3.4; + float D=4.3; + return D+3.4; default: return 0.; } From c479bc49dd5fd154a186b6a4901a67b154ef2d20 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jimmy=20Bergstr=C3=B6m?= Date: Sat, 21 Jan 2023 16:28:23 +0100 Subject: [PATCH 27/32] New output format: Rust (#227) I want to use this project from Rust, so I went ahead and added output support for it. I decided to generate a byte string literal (`[u8]`) with an added `\0` at the end instead of the usual Rust `str` because that makes it easier to pass on to the OpenGL functions, since `str` is unicode and not null-terminated either. [heart.frag](https://github.com/laurentlb/Shader_Minifier/blob/master/tests/real/heart.frag) generates the following output: ```rs // Generated with Shader Minifier 1.3.2 (https://github.com/laurentlb/Shader_Minifier/) pub const VAR_MOUSE: &'static [u8] = b"f\0"; pub const VAR_RESOLUTION: &'static [u8] = b"y\0"; pub const VAR_TIME: &'static [u8] = b"v\0"; pub const HEART_FRAG: &'static [u8] = b"\ uniform float v;\ uniform vec2 y;\ uniform vec4 f;\ void main()\ {\ vec2 f=(2.*gl_FragCoord.xy-y)/y.y;\ float r=mod(v,2.)/2.,a=pow(r,.2)*.5+.5;\ a-=a*.2*sin(r*6.2831*5.)*exp(-r*6.);\ f*=vec2(.5,1.5)+a*vec2(.5,-.5);\ float m=atan(f.x,f.y)/3.141593,x=length(f),e=abs(m),o=(13.*e-22.*e*e+10.*e*e*e)/(6.-5.*e),n=step(x,o)*pow(1.-x/o,.25);\ gl_FragColor=vec4(n,0,0,1);\ }\0"; ``` Leading whitespaces are ignored, so no special handling of the indentation is required, as can be seen here on the [Rust Playground](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=a6e89750d063690bf683f09b7273d841). --- src/formatter.fs | 15 +++++++++++++++ src/options.fs | 1 + src/printer.fs | 5 +++-- 3 files changed, 19 insertions(+), 2 deletions(-) diff --git a/src/formatter.fs b/src/formatter.fs index f9e6aea3..80a97b21 100644 --- a/src/formatter.fs +++ b/src/formatter.fs @@ -77,6 +77,20 @@ let private printNasmHeader out (shaders: Ast.Shader[]) exportedNames = fprintfn out "_%s:%s\tdb '%s', 0" name Environment.NewLine (Printer.print shader.code) fprintfn out "" +let private 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 + if value.ty = "" then + fprintfn out "pub const VAR_%s: &'static [u8] = b\"%s\\0\";" (value.name.ToUpper()) value.newName + else + fprintfn out "pub const %s_%s: &'static [u8] = b\"%s\\0\":" value.ty (value.name.ToUpper()) value.newName + + for shader in shaders do + fprintfn out "" + let name = (Path.GetFileName shader.filename).Replace(".", "_") + fprintfn out "pub const %s: &'static [u8] = b\"\\%s %s\\0\";" (name.ToUpper()) Environment.NewLine (Printer.print shader.code) + let print out shaders exportedNames = function | Options.IndentedText -> printIndented out shaders | Options.Text -> printNoHeader out shaders @@ -84,3 +98,4 @@ let print out shaders exportedNames = function | Options.CList -> printHeader out shaders true exportedNames | Options.JS -> printJSHeader out shaders exportedNames | Options.Nasm -> printNasmHeader out shaders exportedNames + | Options.Rust -> printRustHeader out shaders exportedNames diff --git a/src/options.fs b/src/options.fs index 27059155..6b1ade3c 100644 --- a/src/options.fs +++ b/src/options.fs @@ -13,6 +13,7 @@ type OutputFormat = | [] CList | [] JS | [] Nasm + | [] Rust let text() = Text diff --git a/src/printer.fs b/src/printer.fs index 43c49330..97b6d3a1 100644 --- a/src/printer.fs +++ b/src/printer.fs @@ -70,6 +70,7 @@ module private PrinterImpl = | Options.Text | Options.JS -> "" | Options.CHeader | Options.CList -> out "\"%s%s\"" Environment.NewLine spaces | Options.Nasm -> out "'%s\tdb%s'" Environment.NewLine spaces + | Options.Rust -> out "\\%s%s" Environment.NewLine spaces let rec exprToS indent exp = exprToSLevel indent 0 exp @@ -135,7 +136,7 @@ module private PrinterImpl = match outputFormat with | Options.Text | Options.JS | Options.IndentedText -> "\n" | Options.Nasm -> "', 10, '" - | Options.CHeader | Options.CList -> "\\n" + | Options.CHeader | Options.CList | Options.Rust -> "\\n" // Print HLSL semantics let semToS sem = @@ -180,7 +181,7 @@ module private PrinterImpl = | Options.IndentedText -> s | Options.Text -> s | Options.JS -> s - | Options.CHeader | Options.CList | Options.JS -> s.Replace("\"", "\\\"").Replace("\n", "\\n") + | Options.CHeader | Options.CList | Options.JS | Options.Rust -> s.Replace("\"", "\\\"").Replace("\n", "\\n") | Options.Nasm -> s.Replace("'", "\'").Replace("\n", "', 10, '") /// Detect if the current statement might accept a dangling else. From 7b4dcd565dcfff35359f53646119d4ae81b3c9cf Mon Sep 17 00:00:00 2001 From: Eldritch Conundrum Date: Sun, 22 Jan 2023 01:55:13 +0100 Subject: [PATCH 28/32] Add test for the rust output format (#228) And test exported names in all output formats --- tests/commands.txt | 11 +- tests/real/chocolux.expected | 52 ++--- tests/real/clod.expected | 2 +- tests/real/disco.expected | 8 +- tests/real/heart.expected | 18 ++ tests/real/kinder_painter.expected | 321 +++++++++++++++-------------- tests/real/leizex.expected | 162 ++++++++------- 7 files changed, 307 insertions(+), 267 deletions(-) create mode 100644 tests/real/heart.expected diff --git a/tests/commands.txt b/tests/commands.txt index 20ea9099..4bbf83f7 100644 --- a/tests/commands.txt +++ b/tests/commands.txt @@ -1,10 +1,11 @@ # Test output formats ---no-renaming --format c-variables -o tests/real/chocolux.expected tests/real/chocolux.frag ---no-renaming --format text -o tests/real/clod.expected tests/real/clod.frag ---no-renaming --format c-array -o tests/real/kinder_painter.expected tests/real/kinder_painter.frag ---no-renaming --format js -o tests/real/disco.expected tests/real/disco.frag ---no-renaming --format nasm -o tests/real/leizex.expected tests/real/leizex.frag +--format c-variables -o tests/real/chocolux.expected tests/real/chocolux.frag +--format text -o tests/real/clod.expected tests/real/clod.frag +--format c-array -o tests/real/kinder_painter.expected tests/real/kinder_painter.frag +--format js -o tests/real/disco.expected tests/real/disco.frag +--format nasm -o tests/real/leizex.expected tests/real/leizex.frag +--format rust -o tests/real/heart.expected tests/real/heart.frag # Unit tests diff --git a/tests/real/chocolux.expected b/tests/real/chocolux.expected index e16fa2b2..e0bd23a1 100644 --- a/tests/real/chocolux.expected +++ b/tests/real/chocolux.expected @@ -1,46 +1,48 @@ // Generated with (https://github.com/laurentlb/Shader_Minifier/) #ifndef CHOCOLUX_EXPECTED_ # define CHOCOLUX_EXPECTED_ +# define VAR_resolution "k" +# define VAR_time "v" const char *chocolux_frag = - "uniform vec2 resolution;" - "uniform float time;" - "float h(vec3 q)" + "uniform vec2 k;" + "uniform float v;" + "float s(vec3 y)" "{" - "float f=distance(q,vec3(cos(time)+sin(time*.2),.3,2.+cos(time*.5)*.5));" - "f*=distance(q,vec3(-cos(time*.7),.3,2.+sin(time*.5)));" - "f*=distance(q,vec3(-sin(time*.2)*.5,sin(time),2));" - "f*=cos(q.y)*cos(q.x)-.1-cos(q.z*7.+time*7.)*cos(q.x*3.)*cos(q.y*4.)*.1;" + "float f=distance(y,vec3(cos(v)+sin(v*.2),.3,2.+cos(v*.5)*.5));" + "f*=distance(y,vec3(-cos(v*.7),.3,2.+sin(v*.5)));" + "f*=distance(y,vec3(-sin(v*.2)*.5,sin(v),2));" + "f*=cos(y.y)*cos(y.x)-.1-cos(y.z*7.+v*7.)*cos(y.x*3.)*cos(y.y*4.)*.1;" "return f;" "}" "void main()" "{" - "vec2 p=-1.+2.*gl_FragCoord.xy/resolution.xy;" - "vec3 o=vec3(p.x,p.y*1.25-.3,0),d=vec3(p.x+cos(time)*.3,p.y,1)/64.;" - "vec4 c=vec4(0);" - "float t=0.;" - "for(int i=0;i<75;i++)" + "vec2 y=-1.+2.*gl_FragCoord.xy/k.xy;" + "vec3 f=vec3(y.x,y.y*1.25-.3,0),c=vec3(y.x+cos(v)*.3,y.y,1)/64.;" + "vec4 d=vec4(0);" + "float x=0.;" + "for(int r=0;r<75;r++)" "{" - "if(h(o+d*t)<.4)" + "if(s(f+c*x)<.4)" "{" - "t-=5.;" - "for(int j=0;j<5;j++)" + "x-=5.;" + "for(int b=0;b<5;b++)" "{" - "if(h(o+d*t)<.4)" + "if(s(f+c*x)<.4)" "break;" - "t+=1.;" + "x+=1.;" "}" - "vec3 e=vec3(.01,0,0),n=vec3(0);" - "n.x=h(o+d*t)-h(vec3(o+d*t+e.xyy));" - "n.y=h(o+d*t)-h(vec3(o+d*t+e.yxy));" - "n.z=h(o+d*t)-h(vec3(o+d*t+e.yyx));" - "n=normalize(n);" - "c+=max(dot(vec3(0,0,-.5),n),0.)+max(dot(vec3(0,-.5,.5),n),0.)*.5;" + "vec3 b=vec3(.01,0,0),i=vec3(0);" + "i.x=s(f+c*x)-s(vec3(f+c*x+b.xyy));" + "i.y=s(f+c*x)-s(vec3(f+c*x+b.yxy));" + "i.z=s(f+c*x)-s(vec3(f+c*x+b.yyx));" + "i=normalize(i);" + "d+=max(dot(vec3(0,0,-.5),i),0.)+max(dot(vec3(0,-.5,.5),i),0.)*.5;" "break;" "}" - "t+=5.;" + "x+=5.;" "}" - "gl_FragColor=c+t*.025*vec4(.1,.2,.5,1);" + "gl_FragColor=d+x*.025*vec4(.1,.2,.5,1);" "}"; #endif // CHOCOLUX_EXPECTED_ diff --git a/tests/real/clod.expected b/tests/real/clod.expected index a3243b44..0141317a 100644 --- a/tests/real/clod.expected +++ b/tests/real/clod.expected @@ -1 +1 @@ -uniform vec2 resolution;uniform float time;uniform sampler2D tex0,tex1,tex2,tex3;float f(vec3 o){float a=(sin(o.x)+o.y*.25)*.35;o=vec3(cos(a)*o.x-sin(a)*o.y,sin(a)*o.x+cos(a)*o.y,o.z);return dot(cos(o)*cos(o),vec3(1))-1.2;}vec3 s(vec3 o,vec3 d){float t=0.,a,b;for(int i=0;i<75;i++){if(f(o+d*t)<0.){a=t-.125;b=t;for(int i=0;i<10;i++){t=(a+b)*.5;if(f(o+d*t)<0.)b=t;else a=t;}vec3 e=vec3(.1,0,0),p=o+d*t,n=-normalize(vec3(f(p+e),f(p+e.yxy),f(p+e.yyx))+vec3(sin(p*75.))*.01);return vec3(mix((max(-dot(n,vec3(.577)),0.)+.125*max(-dot(n,vec3(-.707,-.707,0)),0.))*(mod(length(p.xy)*20.,2.)<1.?vec3(.71,.85,.25):vec3(.79,.93,.4)),vec3(.93,.94,.85),vec3(pow(t/9.,5.))));}t+=.125;}return vec3(.93,.94,.85);}void main(){vec2 p=-1.+2.*gl_FragCoord.xy/resolution.xy;gl_FragColor=vec4(s(vec3(sin(time*1.5)*.5,cos(time)*.5,time),normalize(vec3(p.xy,1))),1);} +uniform vec2 v;uniform float s;uniform sampler2D y,c,n,C;float m(vec3 v){float s=(sin(v.x)+v.y*.25)*.35;v=vec3(cos(s)*v.x-sin(s)*v.y,sin(s)*v.x+cos(s)*v.y,v.z);return dot(cos(v)*cos(v),vec3(1))-1.2;}vec3 m(vec3 v,vec3 s){float y=0.,c,f;for(int r=0;r<75;r++){if(m(v+s*y)<0.){c=y-.125;f=y;for(int u=0;u<10;u++){y=(c+f)*.5;if(m(v+s*y)<0.)f=y;else c=y;}vec3 d=vec3(.1,0,0),i=v+s*y,n=-normalize(vec3(m(i+d),m(i+d.yxy),m(i+d.yyx))+vec3(sin(i*75.))*.01);return vec3(mix((max(-dot(n,vec3(.577)),0.)+.125*max(-dot(n,vec3(-.707,-.707,0)),0.))*(mod(length(i.xy)*20.,2.)<1.?vec3(.71,.85,.25):vec3(.79,.93,.4)),vec3(.93,.94,.85),vec3(pow(y/9.,5.))));}y+=.125;}return vec3(.93,.94,.85);}void main(){vec2 i=-1.+2.*gl_FragCoord.xy/v.xy;gl_FragColor=vec4(m(vec3(sin(s*1.5)*.5,cos(s)*.5,s),normalize(vec3(i.xy,1))),1);} diff --git a/tests/real/disco.expected b/tests/real/disco.expected index dfb6e8aa..05c451ab 100644 --- a/tests/real/disco.expected +++ b/tests/real/disco.expected @@ -1,3 +1,9 @@ // Generated with (https://github.com/laurentlb/Shader_Minifier/) +var var_RESOLUTION = "s" +var var_TEX0 = "f" +var var_TEX1 = "C" +var var_TEX2 = "D" +var var_TEX3 = "y" +var var_TIME = "v" -var disco_frag = `uniform vec2 resolution;uniform float time;uniform sampler2D tex0,tex1,tex2,tex3;vec4 s(vec2 px,float z){float l=3.1415,k=time*sign(z),x=px.x*320.*.0065*z,y=px.y*240.*.006*z,c=sqrt(x*x+y*y);if(c>1.)return vec4(0);{float u=-.4*sign(z)+sin(k*.05),v=sqrt(1.-x*x-y*y),q=y*sin(u)-v*cos(u);y=y*cos(u)+v*sin(u);v=acos(y);u=acos(x/sin(v))/(2.*l)*120.*sign(q)-k;v=v*60./l;q=cos(floor(v/l));c=pow(abs(cos(u)*sin(v)),.2)*.1/(q+sin(float(int((u+l/2.)/l))+k*.6+cos(q*25.)))*pow(1.-c,.9);vec4 res;res=c<0.?vec4(-c/2.*abs(cos(k*.1)),0,-c*2.*abs(sin(k*.04)),1):vec4(c,c*2.,c*2.,1);return res;}}void main(){vec2 p=-1.+2.*gl_FragCoord.xy/resolution.xy;vec4 c=vec4(0);for(int i=80;i>0;i--)c+=s(p,1.-float(i)/80.)*(.008-float(i)*5e-5);vec4 d=s(p,1.);gl_FragColor=(d.w==0.?s(p,-.2)*.02:d)+sqrt(c);}` +var disco_frag = `uniform vec2 s;uniform float v;uniform sampler2D f,C,D,y;vec4 n(vec2 s,float f){float c=3.1415,y=v*sign(f),a=s.x*320.*.0065*f,i=s.y*240.*.006*f,C=sqrt(a*a+i*i);if(C>1.)return vec4(0);{float r=-.4*sign(f)+sin(y*.05),n=sqrt(1.-a*a-i*i),u=i*sin(r)-n*cos(r);i=i*cos(r)+n*sin(r);n=acos(i);r=acos(a/sin(n))/(2.*c)*120.*sign(u)-y;n=n*60./c;u=cos(floor(n/c));C=pow(abs(cos(r)*sin(n)),.2)*.1/(u+sin(float(int((r+c/2.)/c))+y*.6+cos(u*25.)))*pow(1.-C,.9);vec4 g;g=C<0.?vec4(-C/2.*abs(cos(y*.1)),0,-C*2.*abs(sin(y*.04)),1):vec4(C,C*2.,C*2.,1);return g;}}void main(){vec2 f=-1.+2.*gl_FragCoord.xy/s.xy;vec4 r=vec4(0);for(int i=80;i>0;i--)r+=n(f,1.-float(i)/80.)*(.008-float(i)*5e-5);vec4 i=n(f,1.);gl_FragColor=(i.w==0.?n(f,-.2)*.02:i)+sqrt(r);}` diff --git a/tests/real/heart.expected b/tests/real/heart.expected new file mode 100644 index 00000000..4246b3c8 --- /dev/null +++ b/tests/real/heart.expected @@ -0,0 +1,18 @@ +// Generated with (https://github.com/laurentlb/Shader_Minifier/) +pub const VAR_MOUSE: &'static [u8] = b"f\0"; +pub const VAR_RESOLUTION: &'static [u8] = b"y\0"; +pub const VAR_TIME: &'static [u8] = b"v\0"; + +pub const HEART_FRAG: &'static [u8] = b"\ + uniform float v;\ + uniform vec2 y;\ + uniform vec4 f;\ + void main()\ + {\ + vec2 f=(2.*gl_FragCoord.xy-y)/y.y;\ + float m=mod(v,2.)/2.,a=pow(m,.2)*.5+.5;\ + a-=a*.2*sin(m*6.2831*5.)*exp(-m*6.);\ + f*=vec2(.5,1.5)+a*vec2(.5,-.5);\ + float r=atan(f.x,f.y)/3.141593,x=length(f),e=abs(r),C=(13.*e-22.*e*e+10.*e*e*e)/(6.-5.*e),F=step(x,C)*pow(1.-x/C,.25);\ + gl_FragColor=vec4(F,0,0,1);\ + }\0"; diff --git a/tests/real/kinder_painter.expected b/tests/real/kinder_painter.expected index 9e8eef55..f7c08017 100644 --- a/tests/real/kinder_painter.expected +++ b/tests/real/kinder_painter.expected @@ -1,187 +1,194 @@ // Generated with (https://github.com/laurentlb/Shader_Minifier/) +# define VAR_mouse "s" +# define VAR_resolution "v" +# define VAR_tex0 "w" +# define VAR_tex1 "f" +# define VAR_tex2 "o" +# define VAR_tex3 "b" +# define VAR_time "z" // tests/real/kinder_painter.frag -"uniform vec2 resolution;" - "uniform float time;" - "uniform vec4 mouse;" - "uniform sampler2D tex0,tex1,tex2,tex3;" - "vec4 fpar00[6],fpar01[6];" - "float cylinder(vec4 sph,vec3 ro,vec3 rd)" +"uniform vec2 v;" + "uniform float z;" + "uniform vec4 s;" + "uniform sampler2D w,f,o,b;" + "vec4 r[6],i[6];" + "float t(vec4 z,vec3 m,vec3 v)" "{" - "vec3 d=ro-sph.xyz;" - "float a=dot(rd.xz,rd.xz),b=dot(rd.xz,d.xz),c=dot(d.xz,d.xz)-sph.w*sph.w,t;" - "t=b*b-a*c;" - "if(t>0.)" - "t=-(b+sqrt(t))/a;" - "return t-.001;" + "vec3 r=m-z.xyz;" + "float w=dot(v.xz,v.xz),d=dot(v.xz,r.xz),s=dot(r.xz,r.xz)-z.w*z.w,i;" + "i=d*d-w*s;" + "if(i>0.)" + "i=-(d+sqrt(i))/w;" + "return i-.001;" "}" - "float esfera(vec4 sph,vec3 ro,vec3 rd)" + "float d(vec4 z,vec3 m,vec3 v)" "{" - "vec3 d=ro-sph.xyz;" - "float b=dot(rd,d),c=dot(d,d)-sph.w*sph.w,t=b*b-c;" - "if(t>0.)" - "t=-b-sqrt(t);" - "return t-.001;" + "vec3 r=m-z.xyz;" + "float d=dot(v,r),i=dot(r,r)-z.w*z.w,w=d*d-i;" + "if(w>0.)" + "w=-d-sqrt(w);" + "return w-.001;" "}" - "bool esfera2(vec4 sph,vec3 ro,vec3 rd,float tmin)" + "bool d(vec4 z,vec3 m,vec3 v,float w)" "{" - "vec3 d=ro-sph.xyz;" - "float b=dot(rd,d),c=dot(d,d)-sph.w*sph.w,t=b*b-c;" - "bool r=false;" - "if(t>0.)" - "t=-b-sqrt(t),r=t>0.&&t0.)" + "f=-d-sqrt(f),s=f>0.&&f0.)" - "t=-(b+sqrt(t)),r=t>0.&&t0.)" + "f=-(d+sqrt(f)),b=f>0.&&f2.5?" - "(nor.xz=inter.xz-obj.xz,nor.y=0.,nor/=obj.w,vec2(nor.x,inter.y)):" - "col.w>1.5?" - "(nor=obj.xyz,inter.xz*.2):" - "(nor=inter-obj.xyz,nor/=obj.w,nor.xy);" - "return nor;" + "vec3 w;" + "r=z.w>2.5?" + "(w.xz=m.xz-v.xz,w.y=0.,w/=v.w,vec2(w.x,m.y)):" + "z.w>1.5?" + "(w=v.xyz,m.xz*.2):" + "(w=m-v.xyz,w/=v.w,w.xy);" + "return w;" "}" - "vec4 cmov(vec4 a,vec4 b,bool cond)" + "vec4 m(vec4 z,vec4 v,bool w)" "{" - "return cond?" - "b:" - "a;" + "return w?" + "v:" + "z;" "}" - "float cmov(float a,float b,bool cond)" + "float m(float z,float v,bool w)" "{" - "return cond?" - "b:" - "a;" + "return w?" + "v:" + "z;" "}" - "int cmov(int a,int b,bool cond)" + "int m(int z,int v,bool w)" "{" - "return cond?" - "b:" - "a;" + "return w?" + "v:" + "z;" "}" - "float intersect(vec3 ro,vec3 rd,out vec4 obj,out vec4 col)" + "float m(vec3 v,vec3 z,out vec4 w,out vec4 f)" "{" - "float tmin=1e4,t;" - "col.w=-1.;" - "bool isok;" - "t=esfera(fpar00[0],ro,rd);" - "isok=t>0.&&t0.&&t0.&&t0.&&t0.&&t0.&&t0.&&b0.&&b0.&&b0.&&b0.&&b0.&&b Date: Sun, 22 Jan 2023 13:41:35 +0100 Subject: [PATCH 29/32] Rename and use enum instead of string for the export prefix (#229) This also fixes formatting of hlsl function externals in rust. Tests are lacking --- src/ast.fs | 7 +++++-- src/formatter.fs | 24 ++++++++---------------- src/renamer.fs | 8 ++++---- 3 files changed, 17 insertions(+), 22 deletions(-) diff --git a/src/ast.fs b/src/ast.fs index cff81310..845626ae 100644 --- a/src/ast.fs +++ b/src/ast.fs @@ -110,12 +110,15 @@ let makeFunctionType ty name args sem = // An ExportedName is a name that is used outside of the shader code (e.g. uniform and attribute // values). We need to provide accessors for the developer (e.g. create macros for C/C++). +type ExportPrefix = + | Variable + | HlslFunction type ExportedName = { - ty: string // "F" for hlsl functions, empty for vars + prefix: ExportPrefix name: string newName: string } - + type Shader = { filename: string mutable code: TopLevel list diff --git a/src/formatter.fs b/src/formatter.fs index 80a97b21..969d52d9 100644 --- a/src/formatter.fs +++ b/src/formatter.fs @@ -4,6 +4,10 @@ open System open System.IO open Options.Globals +let private formatPrefix = function + | Ast.ExportPrefix.Variable -> "var" + | Ast.ExportPrefix.HlslFunction -> "F" + let private printHeader out (shaders: Ast.Shader[]) asAList exportedNames = let fileName = if options.outputName = "" || options.outputName = "-" then "shader_code.h" @@ -18,10 +22,7 @@ let private printHeader out (shaders: Ast.Shader[]) asAList exportedNames = for value: Ast.ExportedName in List.sort exportedNames do // let newName = Printer.identTable.[int newName] - if value.ty = "" then - fprintfn out "# define VAR_%s \"%s\"" value.name value.newName - else - fprintfn out "# define %s_%s \"%s\"" value.ty value.name value.newName + fprintfn out "# define %s_%s \"%s\"" ((formatPrefix value.prefix).ToUpper()) value.name value.newName fprintfn out "" for shader in shaders do @@ -51,10 +52,7 @@ let private 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 - if value.ty = "" then - fprintfn out "var var_%s = \"%s\"" (value.name.ToUpper()) value.newName - else - fprintfn out "var %s_%s = \"%s\"" value.ty (value.name.ToUpper()) value.newName + fprintfn out "var %s_%s = \"%s\"" (formatPrefix value.prefix) (value.name.ToUpper()) value.newName fprintfn out "" for shader in shaders do @@ -66,10 +64,7 @@ let private printNasmHeader 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 - if value.ty = "" then - fprintfn out "_var_%s: db '%s', 0" (value.name.ToUpper()) value.newName - else - fprintfn out "_%s_%s: db '%s', 0" value.ty (value.name.ToUpper()) value.newName + fprintfn out "_%s_%s: db '%s', 0" (formatPrefix value.prefix) (value.name.ToUpper()) value.newName fprintfn out "" for shader in shaders do @@ -81,10 +76,7 @@ let private 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 - if value.ty = "" then - fprintfn out "pub const VAR_%s: &'static [u8] = b\"%s\\0\";" (value.name.ToUpper()) value.newName - else - fprintfn out "pub const %s_%s: &'static [u8] = b\"%s\\0\":" value.ty (value.name.ToUpper()) value.newName + 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 fprintfn out "" diff --git a/src/renamer.fs b/src/renamer.fs index f1ca3cca..d8c43b2d 100644 --- a/src/renamer.fs +++ b/src/renamer.fs @@ -181,9 +181,9 @@ module private RenamerImpl = for name in names do env <- dontRename env (Ident name) env - let export env ty (id: Ident) = + let export env prefix (id: Ident) = if not id.IsUniqueId then - env.exportedNames.Value <- {ty = ty; name = id.OldName; newName = id.Name} :: env.exportedNames.Value + env.exportedNames.Value <- {prefix = prefix; name = id.OldName; newName = id.Name} :: env.exportedNames.Value let renFunction env nbArgs (id: Ident) = // we're looking for a function name, already used before, @@ -220,7 +220,7 @@ module private RenamerImpl = env | None -> let newEnv = renFunction env (List.length f.args) f.fName - if isExternal then export env "F" f.fName + if isExternal then export env ExportPrefix.HlslFunction f.fName newEnv let renList env fct li = @@ -261,7 +261,7 @@ module private RenamerImpl = env | None -> let env = env.newName env decl.name - export env "" decl.name + export env ExportPrefix.Variable decl.name env renList env aux vars From 7c27b3e5fb580f5eaccb282d412c020a4c5e80cd Mon Sep 17 00:00:00 2001 From: Eldritch Conundrum Date: Sun, 22 Jan 2023 19:59:45 +0100 Subject: [PATCH 30/32] Remove global mutable state in parser and printer (#230) --- src/parse.fs | 26 ++++++++++++-------------- src/printer.fs | 27 ++++++++------------------- 2 files changed, 20 insertions(+), 33 deletions(-) diff --git a/src/parse.fs b/src/parse.fs index ee5ba617..608de84d 100644 --- a/src/parse.fs +++ b/src/parse.fs @@ -2,22 +2,21 @@ open Options.Globals -module private ParseImpl = +open FParsec.Primitives +open FParsec.CharParsers +open FParsec - open FParsec.Primitives - open FParsec.CharParsers - open FParsec +type ParseImpl() = - // TODO: Get rid of this global state. Not threadsafe. - let mutable private forbiddenNames = [] + let mutable forbiddenNames = [] let mutable reorderFunctions = false - let private commentLine = parse { + let commentLine = parse { do! skipString "//" // .>> noneOf "[")) // (pchar '[')) // "comment, not verbatim code" do! notFollowedBy (anyOf "[]") "not a verbatim code" do! skipManyTill anyChar (followedBy newline) } |> attempt - let private commentBlock = parse { + let commentBlock = parse { do! skipString "/*" do! skipManyTill anyChar (skipString "*/") } @@ -105,7 +104,7 @@ module private ParseImpl = let simpleExpr = pipe2 prim (many post) (fun prim posts -> List.fold (fun acc elt -> elt acc) prim posts) - opp.TermParser <- simpleExpr + do opp.TermParser <- simpleExpr // Operators @@ -235,7 +234,7 @@ module private ParseImpl = many (ch ':' >>. simpleExpr) // eg. "int foo[] = exp, bar = 3" - declRef.Value <- ( + do declRef.Value <- ( let bracket = between (ch '[') (ch ']') (opt expr) |>> (fun size -> defaultArg size (Ast.Int (0, ""))) let init = ch '=' >>. exprNoComma let var = pipe4 ident (opt bracket) semantics (opt init) Ast.makeDecl @@ -323,7 +322,7 @@ module private ParseImpl = (key <|> ret) .>> ch ';' // A statement - stmtRef.Value <- choice [ + do stmtRef.Value <- choice [ block jump forLoop @@ -367,7 +366,7 @@ module private ParseImpl = let parse = ws >>. toplevel .>> eof - let runParser streamName content : Ast.Shader = + member _.runParser streamName content : Ast.Shader = forbiddenNames <- [ "if"; "in"; "do" ] reorderFunctions <- false let res = runParserOnString parse () streamName content @@ -380,5 +379,4 @@ module private ParseImpl = } | Failure(str, _, _) -> failwithf "Parse error: %s" str - -let runParser = ParseImpl.runParser +let runParser = (new ParseImpl()).runParser diff --git a/src/printer.fs b/src/printer.fs index 97b6d3a1..2b3a5fe4 100644 --- a/src/printer.fs +++ b/src/printer.fs @@ -5,9 +5,7 @@ open Ast open Options.Globals open System.Text.RegularExpressions -module private PrinterImpl = - - let mutable outputFormat = Options.Text +type PrinterImpl(outputFormat) = let out a = sprintf a @@ -266,7 +264,7 @@ module private PrinterImpl = | TLDecl decl -> out "%s%s;" (nl 0) (declToS 0 decl) | TypeDecl t -> out "%s;" (typeSpecToS t) - let print tl = + member _.Print tl = let mutable wasMacro = true // handle the required \n before a macro ignoreFirstNewLine <- true @@ -278,19 +276,10 @@ module private PrinterImpl = else topLevelToS x tl |> List.map f |> String.concat "" + member _.ExprToS = exprToS + member _.TypeToS = typeToS -let print tl = - PrinterImpl.outputFormat <- options.outputFormat - PrinterImpl.print tl - -let printText tl = - PrinterImpl.outputFormat <- Options.Text - PrinterImpl.print tl - -let exprToS x = - PrinterImpl.outputFormat <- Options.Text - PrinterImpl.exprToS 0 x - -let typeToS ty = - PrinterImpl.outputFormat <- Options.Text - PrinterImpl.typeToS ty +let print tl = (new PrinterImpl(options.outputFormat)).Print(tl) +let printText tl = (new PrinterImpl(Options.Text)).Print(tl) +let exprToS x = (new PrinterImpl(Options.Text)).ExprToS 0 x +let typeToS ty = (new PrinterImpl(Options.Text)).TypeToS ty From 6d073f00ad673cd670f4b29091e4076efcdf9334 Mon Sep 17 00:00:00 2001 From: Laurent Le Brun Date: Sat, 28 Jan 2023 22:39:04 +0100 Subject: [PATCH 31/32] Disable the x-=x optimization for setting a vector to 0s (#231) The optimization can break code when the vector contains NaN or Inf values --- src/rewriter.fs | 7 ++++--- tests/compression_results.log | 12 ++++++------ tests/real/controllable-machinery.frag.expected | 2 +- tests/real/from-the-seas-to-the-stars.frag.expected | 10 +++++----- tests/real/slisesix.frag.expected | 2 +- tests/unit/float.frag.expected | 2 +- 6 files changed, 18 insertions(+), 17 deletions(-) diff --git a/src/rewriter.fs b/src/rewriter.fs index ee41927d..988e1758 100644 --- a/src/rewriter.fs +++ b/src/rewriter.fs @@ -181,9 +181,10 @@ let private simplifyOperator env = function | FunCall(Op "=", [Var x; FunCall(Op op, [Var y; e])]) when x.Name = y.Name && augmentableOperators.Contains op -> FunCall(Op (op + "="), [Var x; e]) - | FunCall(Op "=", [Var x; FunCall(Var fctName, [Int (0, _)])]) - when List.contains fctName.Name ["vec2"; "vec3"; "vec4"; "ivec2"; "ivec3"; "ivec4"] -> - FunCall(Op "-=", [Var x; Var x]) // x=vec3(0); -> x-=x; + // Unsafe when x contains NaN or Inf values. + //| FunCall(Op "=", [Var x; FunCall(Var fctName, [Int (0, _)])]) + // when List.contains fctName.Name ["vec2"; "vec3"; "vec4"; "ivec2"; "ivec3"; "ivec4"] -> + // FunCall(Op "-=", [Var x; Var x]) // x=vec3(0); -> x-=x; | e -> e diff --git a/tests/compression_results.log b/tests/compression_results.log index f2d3be4d..5c1d6164 100644 --- a/tests/compression_results.log +++ b/tests/compression_results.log @@ -1,11 +1,11 @@ -clod.frag... 8955 => 1544.138 +clod.frag... 8960 => 1545.563 audio-flight-v2.frag 4650 => 902.661 buoy.frag 4239 => 632.427 -controllable-machinery.frag 7768 => 1227.323 +controllable-machinery.frag 7773 => 1227.926 ed-209.frag 7926 => 1363.748 elevated.hlsl 3416 => 603.918 endeavour.frag 2661 => 541.942 -from-the-seas-to-the-stars.frag 14345 => 2344.104 +from-the-seas-to-the-stars.frag 14370 => 2345.702 frozen-wasteland.frag 4609 => 812.410 kinder_painter.frag 2905 => 450.888 leizex.frag 2327 => 515.566 @@ -14,10 +14,10 @@ mandelbulb.frag 2419 => 546.857 ohanami.frag 3292 => 736.461 orchard.frag 5643 => 1034.091 oscars_chair.frag 4653 => 984.586 -robin.frag 6338 => 1058.995 -slisesix.frag 4582 => 934.241 +robin.frag 6343 => 1057.981 +slisesix.frag 4587 => 937.138 terrarium.frag 3634 => 747.342 the_real_party_is_in_your_pocket.frag 12248 => 1815.043 valley_ball.glsl 4386 => 888.496 yx_long_way_from_home.frag 3030 => 615.535 -Total: 119257 => 21356.587 +Total: 119302 => 21362.097 diff --git a/tests/real/controllable-machinery.frag.expected b/tests/real/controllable-machinery.frag.expected index 70b5d885..54d36f5b 100644 --- a/tests/real/controllable-machinery.frag.expected +++ b/tests/real/controllable-machinery.frag.expected @@ -494,7 +494,7 @@ void mainImage(out vec4 fragColor,vec2 fragCoord) #endif - col-=col; + col=vec3(0); sr=2.*mod(dot(mod(floor(.5*(uv+1.)*canvas),2.),vec2(1)),2.)-1.; for(float a=float(VAR_ZERO);a<3.;a++) rd=vuMat*normalize(vec3(uv+step(1.5,3.)*Rot2D(vec2(.5/canvas.y,0),sr*(.667*a+.5)*3.1415927),zmFac)),col+=1./3.*ShowScene(ro,rd); diff --git a/tests/real/from-the-seas-to-the-stars.frag.expected b/tests/real/from-the-seas-to-the-stars.frag.expected index dd39ec7d..ded8fa7a 100644 --- a/tests/real/from-the-seas-to-the-stars.frag.expected +++ b/tests/real/from-the-seas-to-the-stars.frag.expected @@ -107,7 +107,7 @@ void ammonite() { float t=pow(w.z,.3)*2.,c=.5+.5*cos(t*300); col=mix(vec3(1,.5,.4),vec3(.3),c)/8.; - p-=p; + p=vec3(0); p.xy=(disc(w.xy)*mix(.8,1.,c)+vec2(0,1+t))*t*.05; p.yz*=rotmat(t*10.+2); w.w=R(); @@ -214,7 +214,7 @@ void main() w.w=R(); if(w.w<.25) { - of-=of; + of=vec3(0); w.x=R(); w.y=R(); w.z=R(); @@ -312,14 +312,14 @@ void main() if(ww<.3) { if(R()<.1) - w.x=R(),w.y=R(),w.z=R(),w.w=R(),of-=of,jellyfish(),p.yz*=rotmat(.5),p*=.6,p.y+=.11,col=vec3(1); + w.x=R(),w.y=R(),w.z=R(),w.w=R(),of=vec3(0),jellyfish(),p.yz*=rotmat(.5),p*=.6,p.y+=.11,col=vec3(1); p+=vec3(-.8,.3,0); } else if(ww<.6) { if(R()<.2) - w.x=R(),w.y=R(),w.z=R(),w.w=R(),of-=of,ammonite(),p.yz*=rotmat(-.5),p*=.6,p=p.zyx,col=vec3(1); + w.x=R(),w.y=R(),w.z=R(),w.w=R(),of=vec3(0),ammonite(),p.yz*=rotmat(-.5),p*=.6,p=p.zyx,col=vec3(1); p+=vec3(.6,-.6,0); } else @@ -379,7 +379,7 @@ void main() w.w=R(); if(w.w<.25) { - of-=of; + of=vec3(0); w.x=R(); w.y=R(); w.z=R(); diff --git a/tests/real/slisesix.frag.expected b/tests/real/slisesix.frag.expected index f78c7e02..b717cf0f 100644 --- a/tests/real/slisesix.frag.expected +++ b/tests/real/slisesix.frag.expected @@ -195,7 +195,7 @@ void main() } else if(matID==2) - rgb-=rgb; + rgb=vec3(0); else if(matID==1) { diff --git a/tests/unit/float.frag.expected b/tests/unit/float.frag.expected index 7ec1aa55..61af4b05 100644 --- a/tests/unit/float.frag.expected +++ b/tests/unit/float.frag.expected @@ -20,5 +20,5 @@ "void main()" "{" "float f1=1.5,f2=3e-7,f3=.42,f6=-.002,f7=2e-9,f8=2e6,f9=2e10;" - "gl_FragColor-=gl_FragColor;" + "gl_FragColor=vec4(0);" "}", From 27ab58de6a983bfc2a1d0da831eaf53fdd1c6645 Mon Sep 17 00:00:00 2001 From: Laurent Le Brun Date: Sat, 28 Jan 2023 23:01:06 +0100 Subject: [PATCH 32/32] Update version to 1.3.3 (#232) --- README.md | 11 +++++------ src/options.fs | 2 +- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 269003e9..7a8e1fc4 100644 --- a/README.md +++ b/README.md @@ -95,7 +95,7 @@ $ mono shader_minifier.exe # Linux, Mac... ``` USAGE: Shader Minifier [--help] [-o ] [-v] [--hlsl] - [--format ] + [--format ] [--field-names ] [--preserve-externals] [--preserve-all-globals] [--no-inlining] [--aggressive-inlining] [--no-renaming] @@ -112,7 +112,7 @@ OPTIONS: -o Set the output filename (default is shader_code.h) -v Verbose, display additional information --hlsl Use HLSL (default is GLSL) - --format + --format Choose to format the output (use 'text' if you want just the shader) --field-names @@ -135,8 +135,7 @@ OPTIONS: --no-sequence Do not use the comma operator trick --smoothstep Use IQ's smoothstep trick --no-remove-unused Do not remove unused code - --move-declarations - Move declarations to group them + --move-declarations Move declarations to group them --help display this list of options. ``` @@ -148,8 +147,8 @@ In short: If you pass `-` for the output, it will be printed on stdout. * Use `--format` to control the output format. By default, it will create a C - header. There are other options to get only the shader, or have it in a .js or - nasm file. + header. There are other options to get only the shader, or have it in a + Javascript, Rust, or nasm file. ## Tips diff --git a/src/options.fs b/src/options.fs index 6b1ade3c..3529117a 100644 --- a/src/options.fs +++ b/src/options.fs @@ -3,7 +3,7 @@ open System.IO open Argu -let version = "1.3.2" // Shader Minifier version +let version = "1.3.3" // Shader Minifier version let debugMode = false type OutputFormat =

$O?SA;4> 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≦kYg;{8gbI$OpoSf!v9tr;CxGk9~9> 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%0A?6rXF>trZCB?)PN0e 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