summaryrefslogtreecommitdiff
path: root/out/html/index.mem
diff options
context:
space:
mode:
Diffstat (limited to 'out/html/index.mem')
-rw-r--r--out/html/index.mem8435
1 files changed, 8435 insertions, 0 deletions
diff --git a/out/html/index.mem b/out/html/index.mem
new file mode 100644
index 0000000..e5c223f
--- /dev/null
+++ b/out/html/index.mem
@@ -0,0 +1,8435 @@
+"(ט/Be#D7q/;Mۉ۵8H[V9YO?m^BؾopE[N1$} Uo{t]r;ހ5%ܛ&itJi%O8GՌƝew̡ $u+Yo,-ntJAܩ\SڈvfRQ>2-m1?!'Y= %
+GoQcpn
+g))/F
+'&&\8!.*Zm,M߳ 8ScTs
+ew<
+jvG.;5,rdL迢0BKfpK0TQlReU$* qW5ѻ2pjҸSAQl7LwH'Hᵼ4cZų 9ˊAJNscwOʜ[o.h]t`/CocxrxȄ9dnj(c#齂lPyƲ+SrxqƜa&>'!Ǹ}xnO}orgȢ}c
+ ?G5 q}#w($@{2
+<L gCB>˾L*~e)Y:o_XGJDl`x0`x00`xx0`x0`x0``x0`x0###F&&###FF&###F&###F&####F&###F&####F&#?~?~?~?~~?~??~?~oooooo臇oo臇&Lˇ&Lˇ&Lˇ&LLˇ&Lˇ&&Lˇ&Lˇڸbmڸbmmڸbbmڸbmڸbmڸbmڸbm       OO!OBn OO!OBn OO!OBnn OO!OBBn OO!OOBn OO!!OBn OOO!OBn O666l666ll666l666l6666l666l6666l6YQYQQYQYYQYQYQYQo޽ o޽ o޽ o޽ o޽ oo޽ o޽ yyyyyyyyyyyyyyyyyyyyyyyyooo_00ooo_0ooo_0ooo__0oooo_0ooo_0oooo_0o~?mm~??m~?m~?m~?m~~?m~?mRRURRRURRRURRRURRRURRRRUURRRRURR```'GG```'G```'G```''G````'G```'G````'G`ʼve55ʼvee5ʼvve5ʼve5ʼve5ʼve5ʼve5V+77V++7V+7V+7V+7VV+7V+7q[ңq[[ңq[ңqq[ңq[ңq[ңq[ң 0 `<ll 0 `<l 0 `<<l 0 ``<l 0 `<l 00 `<l 0 `<l {{{{{{{{{{{{{{{{{{{{{{{{555j555jj555j555j5555j555j5555j5ti:ti::tii:ti:ti:tti:ti:SGݳSGݳSGGݳSSGݳSGݳ১SGݳSGݳ{!!{!{!{!{!{{!{!/^활/^홙/^활/^^활/^활//^활/^활...m\CC...m\\C...m\C...mm\C....m\C...m\C....m\C.KK1Kbz))KK1Kbz)KK1Kbzz)KK1Kbbz)KK1KKbz)KK11Kbz)KKK1Kbz)K!]]!]!!]!]!]!]!]WWAWWWAWWWAWWWAWWWAWWWWAAWWWWAWWTA*TA**TAA*TA*TA*TTA*TA*wwwwwwwwwwwwwwwwwwwwwwww777n777nn777n777n7777n777n7777n7{Vמ{Vמ{VVמ{{Vמ{Vמ峳{Vמ{Vמ域F#F##F#F#F#FF#F#########JJ5Jj JJ5Jj JJ5Jj JJ5Jjj JJ5JJj JJ55Jj JJJ5Jj JOڞDDOڞDOڞDOڞDOڞDOOڞDOڞDXX}X%XX}X%XX}X%%XX}X%XX}XX%XX}}X%XXX}X%Xʏʏʏʏʏʏʏ)))UR||)))URR|)))UR|)))UUR|))))UR|)))UR|))))UR|)
+
+(
+P"ZZ
+
+(
+P"Z
+
+(
+P""Z
+
+(
+PP"Z
+
+(
+
+P"Z
+
+((
+P"Z
+
+
+(
+P"Z
+OPPOPOOPOPOPOPOPi]ɠi]]ɠi]ɠii]ɠi]ɠi]ɠi]ɠkkkkkkkkkkkkkkkkkkkkkkkk.\م.\م.\م.\\م.\م..\م.\مνsg<<νsgg<νssg<νsg<νsg<νsg<νsg<]]i]4]]i]4]]i]44]]i]4]]i]]4]]ii]4]]]i]4]@P @P @PP @P @P @@P @P        >>>|>>>||>>>|>>>|>>>>|>>>|>>>>|>(
+--(
+
+-(
+-((
+-(
+-(
+-(
+-gggxxgggxgggxgggxggggxgggxggggxgsS՗sS՗sSS՗ssS՗sS՗䷷sS՗sS՗'''%N'''%NN'''%N'''%%N''''%N'''%N''''%N'AAA2XssAAA2XsAAA2XXsAAA22XsAAAA2XsAAA2XsAAAA2XsA, , , ,, , , , QSQSSQSQQSQSQSQS}}}ϔ}}}ϔ}}}ϔ}}}ϔ}}}}ϔ}}}ϔ}}}}ϔ}n7IIn77In7In7In7Inn7In7IG؎VVG؎VG؎VG؎VG؎VGG؎VG؎V0pp0p00p0p0p0p0p#q#q#qq##q#q#q#q|||Ǒ|||Ǒ|||Ǒ|||Ǒ||||Ǒ|||Ǒ||||Ǒ|fffqqfffqfffqfffqffffqfffqffffqfSݦ{{Sݦ{Sݦ{Sݦ{Sݦ{SSݦ{Sݦ{\K.\K..\KK.\K.\K.\\K.\K.GGGFEEGGGFEGGGFFEGGGFEGGGGFEGGGFEGGGGFEGB!B!!B!B!B!BB!B!ʼnʼnʼnʼnʼnʼnʼn---uZXX---uZZX---uZX---uuZX----uZX---uZX----uZX-ƿyc..ƿycc.ƿyyc.ƿyc.ƿyc.ƿyc.ƿyc.8??8?8?88?8?8?8?#G#GG##G#G#G#G#GZZuZ/ZZuZ/ZZuZ//ZZuZ/ZZuZZ/ZZuuZ/ZZZuZ/Z6l6l6l6ll6l66l6l333f333ff333f333f3333f333f3333f3ccc?\\ccc?\ccc?\ccc??\cccc?\ccc?\cccc?\c
+
+
+
+
+
+
+
+98I98II988I998I98I98I98Iqqqqqqqqqqqqqqqqqqqqqqqqύύύύύύύd}2d}22d}}2d}2d}2dd}2d}2II9Irp;;II9Irp;II9Irpp;II9Irrp;II9IIrp;II99Irp;III9Irp;ICن__Cن_Cن_Cن_Cن_CCن_Cن_11111111KHۨKHۨKHHۨKKHۨKHۨ㫫KHۨKHۨ[[q[*[[q[*[[q[**[[q[*[[q[[*[[qq[*[[[q[*[4 4 4 44 4 4 4 R)>>R))>R)>R)>R)>RR)>R)>&&&-L &&&-LL &&&-L &&&--L &&&&-L &&&-L &&&&-L &222d222dd222d222d2222d222d2222d2J}YYJ}}YJJ}YJ}YJ}YJ}YJ}Yjjjjjj郃jj<x3ww<x3w<x33w<xx3w<x3w<<x3w<x3ws榷33s榷3s榦3s榷3s榷3ss榷3s榷3Հ:t:t:t:tt:t::t􀀀:t􀾾¾|a''¾|aa'¾||a'¾|a'¾|a'¾|a'¾|a'&އ&އ&އ&&އ&އ&އ&އ444h444hh444h444h4444h444h4444h4HH=Hzu22HH=Hzu2HH=Hzuu2HH=Hzzu2HH=HHzu2HH==Hzu2HHH=Hzu2H$TT$T$$T$T$T$T$Tzzzzzzzzzzzzzzzzzzzzzzzzz=ddz==dz=dz=dz=dzz=dz=d__a_>__a_>__a_>>__a_>__a__>__aa_>___a_>_ @== @@= @= @= @= @= @= hhhghhhghhhghhhgghhhhghhhghhhhghhr4hr44hrr4hr4hr4hhr4hr4,A,AA,,A,A,A,A,A^u}}^uu}^^u}^u}괴^u}^u}^u}TTMTTTMTTTMTTTMTTTMTTTTMMTTTTMTTv;v;;v;v;v;vv;v;""" D//""" DD/""" D/""" D/"""" D/""" D/"""" D/"dddccdddcdddcdddcddddcdddcddddcd********ssssssssssssssssssssssssHZ$HZ$$HZZ$HZ$HZ$HHZ$HZ$@@@:]zz@@@:]z@@@:]]z@@@::]z@@@@:]z@@@:]z@@@@:]z@ @(HH @(H @((H @@(H @(H @(H @(H+V蛕+V蛛+V蛕+VV蛕+V蛕++V蛕+V蛕3{3{3{{33{3{엗3{3{KۖMMKۖMKۖMKۖMKۖMKKۖMKۖMۡa_a__a_aa_a_a_a_===z===zz===z===z====z===z====z=f3[[f33[f3[f3[f3[ff3[f3[
+
+
+
+
+
+
+
+cƲcƲcƲcƲcƲccƲcƲѥA W䥥A WW䥥A W䥥AA W䥥A W䥥A W䥥A WCM١CM١CMM١CCM١CM١⯯CM١CM١aaa/NNaaa/Naaa/Naaa//Naaaa/Naaa/Naaaa/NaE{BBE{{BEE{BE{BE{BE{BE{B!!!B44!!!BB4!!!B4!!!B4!!!!B4!!!B4!!!!B4!J%J%%J%J%J%JJ%J%xf<xf<<xff<xf<xf<xxf<xf<CCC"RaaCCC"RaCCC"RRaCCC""RaCCCC"RaCCC"RaCCCC"RaC;v;v;v;vv;v;;v;v+OO+O++O+O+O+O+O $$ $ $ $ $ $ $QQYQQQYQQQYQQQYQQQYQQQQYYQQQQYQQ^/%%^//%^/%^/%^/%^^/%^/%mmmO""mmmO"mmmO"mmmOO"mmmmO"mmmO"mmmmO"m 4 h9ee 4 h9e 4 h99e 4 hh9e 4 h9e 44 h9e 4 h9e 5yy5y55y5y5y5y5y[߶ii[߶i[߶i[߶i[߶i[[߶i[߶i~~~כ~~~כ~~~כ~~~כ~~~~כ~~~כ~~~~כ~$$$=H$$$=HH$$$=H$$$==H$$$$=H$$$=H$$$$=H$;;;v;;;vv;;;v;;;v;;;;v;;;v;;;;v;1=K1=KK1==K11=K1=K1=K1=K>с>с>с>>с>с>с>сDU"DU""DUU"DU"DU"DDU"DU"       NN%NJkNN%NJkNN%NJkkNN%NJJkNN%NNJkNN%%NJkNNN%NJkNQsffQssfQQsfQsf混QsfQsfQsf ` ` `` ` `닋 ` `<<<x<<<xx<<<x<<<x<<<<x<<<x<<<<x<>|>|>|>||>|>>|>|j5@@j55@j5@j5@j5@jj5@j5@       ޹go޹goo޹ggo޹go޹go޹go޹goL_&L_&&L__&L_&L_&LL_&L_&,,,}XQQ,,,}XXQ,,,}XQ,,,}}XQ,,,,}XQ,,,}XQ,,,,}XQ,kָkָkָkָkָkkָkָk\ӌk\ӌk\\ӌkk\ӌk\ӌ绻k\ӌk\ӌnnnW99nnnW9nnnW9nnnWW9nnnnW9nnnW9nnnnW9n7n󕪪7n󕕪7n7nn7n77n7n       VVEVVVEVVVEVVVEVVVEVVVVEEVVVVEVVDD DI^^DD DI^DD DII^DD DI^DD DDI^DD DI^DDD DI^Dߞߞߞߞߞߞߞ!7O!7OO!77O!!7O!7O!7O!7O***MTgg***MTTg***MTg***MMTg****MTg***MTg****MTg*ֻmk
+
+ֻmkk
+ֻmmk
+ֻmk
+ֻmk
+ֻmk
+ֻmk
+#F⟇#F⟟#F⟇#FF⟇#F⟇##F⟇#F⟇SSQSSSQSSSQSSSQSSSQSSSSQQSSSSQSSWܮrrWܮrWܮrWܮrWܮrWWܮrWܮr , X'SS , X'S , X''S , XX'S , X'S ,, X'S , X'S N'N''N'N'N'NN'N'lllG++lllG+lllG+lllGG+llllG+lllG+llllG+l111b111bb111b111b1111b111b1111b1tttttttttttttttttttttttt       FFF
+CLLFFF
+CLFFF
+CCLFFF
+
+CLFFFF
+CLFFF
+CLFFFF
+CLF &E &EE &&E &E &E &E &E<<<<<<<<PD(PD((PDD(PD(PD(PPD(PD([Bߺ[Bߺ[BBߺ[[Bߺ[Bߺᣣ[Bߺ[BߺXN,XN,,XNN,XN,XN,XXN,XN,:::t:::tt:::t:::t::::t:::t::::t:iiioiiioiiioiiiooiiiioiiioiiiioi $ H-AA $ H-A $ H--A $ HH-A $ H-A $$ H-A $ H-A ppppppppppppppppppppppppTqooTqqoTTqoTqoⶶTqoTqoTqogηgηgηgηgηggηgη;~;~;~~;;~;~퓓;~;~.ۅ.ۅ.ۅ..ۅ.ۅ.ۅ.ۅBBB*WhhBBB*WhBBB*WWhBBB**WhBBBB*WhBBB*WhBBBB*WhBZ-,,Z--,Z-,Z-,Z-,ZZ-,Z-,IUIUUIUIIUIUIUIU(((]Puu(((]PPu(((]Pu(((]]Pu((((]Pu(((]Pu((((]Pu(\\m\1\\m\1\\m\11\\m\1\\m\\1\\mm\1\\\m\1\?kk?k??k?k?k?k?k"D†"D†"D†"DD†"D†""D†"D†#臸O6yoR` {5.KWw7JX)
+k]>g'A}|fG-Z3
+
+
+
+
+
+
+
+
+
+
+I
+I
+
+
+
+
+
+
+
+j
+
+
+
+
+
+R
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+|
+|
+V
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+\
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+b
+
+g
+
+
+
+
+
+
+
+
+\,Q]tL K
+蒴dВCF.7Gnn6
+ظY| K
+ A2VPD׿غ' 9C#U k2JV"42\!7c#L"CuZGdDՁ
+6J&,o])(|1
+`~zC|_cM7-X Hzj)s
++xck$swyH6kɱ(1
+<ܨl3d+XW=?';<}
+]n@TS FTh"k9{^]qR& 
+vuӿ
+k)ʑ:XiCwVgVxzxvT
+`SQ/xtJ2b~hԙF74>6
+a~Δ3V)'"Ll
+Lna&S}UZg'͛VV
+ȸYm0?ʗvE0HZ&>1;y9%ݐOp.%U~;͆ SghT$Բ Qo5ݰgyE9`[*|ﭳ
+ҕ_
+{*9Pғ[g`9JP'v-{sBcm=i׌l'
+MĆ&qۛlhMf%8#џM۷
+
+dގ3(
+
+&
+62ײ67J v[43^3)2E$@
+[pnVk~|RaPw?k&itNqdǩac
+
+CyڦxyNqf@9`Us@
+&
+Q*j
+E,v
+X0<4E87N I-dDGj
+ A2VPD׿غ' 9C#U k2JV"42\!7c#L"CuZGdDՁ
+/\HS7_j[_H(I
+rn;#& ( HnSw}Z u,0Wu0AzU&\lJKD0&\lJKD0ٻ|)\kҮ~W,KH/'#:DS2bT~5FawE-T\T/iWۡ>f
+q9zaHV
+rn;#& ( HnSwWۡ>f
+rn;#& ( HnStf,a0Nfs= vį/I%j+<s":eaIBz+yV.-l49m{"FDA~i9'
+q9zaHV
+~* 9UEȫ@$w'^CqxwjREi.^G 6O<x^eϥ-H.X醑U[Dœ
+¾O'eﺑJP:"(&"(&9TD|/}Ҧ.>b|9ɔ:PLdhE:?kG~O &46FGԯu ¤\뎕Rb )XdO)(FF!wBA&<S8m(]o~PA/q TVnl%:k;2ee
+.ɋȵ+ǹMw=4Ac-]Z%:
+.ɋȵ+ǹMw>g@P^( c#.dZ!2.Ljp;b ;xԍPh{}_|mPG@j^h5" "}8]Vc2꿩x"
+
+
+хRЀ;U.?gdqvZ/o4Byd8ւvÊb*}wKcWz1e
+
+!
+V(W&`Pqy?ʳ%dDg%gMRw4:Qm<H5gRR-:v?pO\09NA_[l{uB"XG[rgk0ZzQd |m);o 40aEW
+([ ow0%0nV4ERј4|qP`tT "GRb4Z''Jivj֨^R
+b|}R
+qN8qc~uks)
+K=c #.r!Ź(ɜ`幡̀AƘu]12D:mH
+ܚ}ts1s'0]Aۅ0a(6p1Ĺ
+Kџ;hd Y`Щ#~3
+S zLv
+c" .I'T^jUi~wKVA\o&1m&l@PXMBeg4ѤqCJ.Mme\67E _Q[O8GdNrs!HpĐ}ˬ<\$#R.8=us`a;RʝjƣRT]^ޒ k
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+/ 6$=&i''NͲuu t,,X.4-6nnZZ[RRM;;vaַγ}{))R>q//^SShѹ
+
+II
+ l$$H\\]ŸnӽשּׁCbbĨ917Ӌyy2CȋY77nmmڌdձNN੩IllVV%ϯeeʎzz鮮Gպoxxo%%Jr..\$8WǴsQƗ#|ݡtt!>KKܽa ppB>>|ĵqffHHaa_55jWWйiX':'8볘+3"iip٩3-"< I·UUx((PzߥY  ڿe1BBhhAA)w--Z˰{TTֻm:,ccƥ||ww{{ kkֽooޱőT00`PggΩ++V}׵bMvvʏEɉ@}}YYGG AԳg_Eꜜ#Srr[u=&&Lj66lZ??~ÃO44h\Q4qqثs11bS*? ǕR##FeÝ^0(7
+/ $6=&''Niuu ,,Xt4.6-nnܲZZ[RR;;vMַa}))R{>//^qSSѹh
+
+II
+$$Hl\\Ÿ]ӽnCbbĦ917yy2ȋC77nYmmڷձdNNҩIllشVV%eeʯzz􎮮Goxx%%Jo..\r8$WsƗQ#ݡ|tt>!KKݽa܋ pp>>|Bqff̪HHaa£55j_WWiІX:''8+"3iiһ٩p3-<" ·IUU((PxߥzY e1BBhhиAAÙ)--Zw{TTm,:cƥc||ww{{ kֽkoޱoőT0`P0gΩg+V}+׵b׫MvvʏEʂɉ@}}YYGG AԳgԢ_Eꯜ#Srr[u·=&Lj&6lZ6?~A?̃O4h\4Q4qqثs1bS1*? ǕR#Fe#Ý^0(7
+/ $6=&'Ni'Ͳuu  ,Xt,4.6-nܲnZZ[RR;vM;ַaֳ}γ)R{)>/^q/SSѹh
+
+II
+$Hl$\\Ÿ]ӽnӬCbĦb917yy2ȋC7nY7mڷmձdNNIlشlVV%eʯezzGoպxx%Jo%.\r.8$WsǴƗQ#ݡ|tt>!KKaܽ pp>|B>qĵf̪fHHa£a5j_5WWiйX:''8+"3iһi٩pَ3-<" ·IUU(Px(ߥzߌY  eڿ1BBhиhAA)-Zw-{˰TTmֻ,:ƥcc||ww{{ ֽkkޱooT`P00ΩggV}++bM櫫vvE@}}YYGG A쭭g_E꯯#Srr[u·=Lj&&lZ66~A??Oh\44Q4qqsbS11*? RFe##^0(7
+/ $6=&Ni''Ͳuu Xt,,4.6-ܲnnZZ[RRvM;;a}γR{))>^q//SSh
+
+II
+Hl$$\\]½nCשּׁĦbb917yy2CnY77ڷmmd՜NNI੩شllVV%ʯeezzG鮮oպxxJo%%\r..8$WsǴQ#|tt>!KKaܽ pp|B>>qĵ̪ffHH£aaj_55WWiйX:''8+"3һiip3-<" IΪUUPx((zY  eڿ1BBиhhAA)Zw--{˰TTmֻ,:
+|B|
+!\hT[:.6$g
+ WҖO aiKwZ
+*C"< Nj򹨶-ȩWLuݙ`&r\;fD4~[v)C#hc1cB@" Ƅ}$J=2m)K/0R wl+pH"dGČ?,}V3"NI8ʌ6 Ԙρ(z&ڤ?:, xP_jbF~Tؐ^9.Â]|i-o%;ȧ}nc{; x&Yn쨚Oen~ϼ!ٛ6oJ |)11#?*0f57NtʂАا3JAP/MvMCTMўjL,QeF^]5st.A ZgRے3VGmaךz 7Y<'5a<GzYҜ?sUy7sS[_o=߆Dx>h,4$8_@r %⼋I<(A q9޳ ؐVda{p2t\lHBWЧQPeA~S^':k;EXK0 Umvv̈L%O*D5&bZI%gE]u/LFk_眒zmYRڃ-!tXiI)ɎDujyx>Xkq'Oᾶ f:}Jc13Q`SbEwdk+hHpXElޔ{Rs#KrWUf*(µ/{ņ7ӥ(0#j\ϊ+yiNe;b4ĊS.4U2u 9`@q^nQ!>ݖ=>ݮMFT]qoP`$֗C@̞gwB谽[8y
+|GB|
+d\h!T[.6$:g
+ WґO aKwZi
+*"<C  Nj򭨶-WuLݙ`&r\;fD~[4)Cv#hc1ʅcB"@Ƅ $J}=2)m/K0R w+lpHdG"?,}Vؐ3"NI8ʌ Ԙ6z(&?:,xP _jF~Tb¸ؐ9.^Â]i|-o%ϳ;}cn;{x& YnOne~ϼ!6oJ |)ֲ1#?*10f5Nt7ʂАا3JAP/MvCMMTߵўjL,QeF^5]tsA .gZےRV3Gmaך 7zY<'a5Gz<ҜYsU?y7sS_[o=Dxʁh>4$8,@_r% I<( A9q ؜Vd{a2p\lHtWBQPA~Seä':^;kEXK0 Uvm̈v%LO*5&DbIZ%gE]/uLFk_mzRY-tX!I)iɎDujxyXk>'qᾶO f}:cJ1Q`3SbEdwk+HpXhEޔl{Rs#KrWUf*(/ņ{7ӥ(0#j\ϊ+yiNeվ4bĊ.4SU2u 9`@q^nQ!>ݖ=>ݮMFTq]oP`$֗@Cgw谽B8[y|G
+B|
+d\h![T6$:.
+ gWҖOa wZiK
+*"<C  Ƕ-ȩWuL`&r\fD;[4~Cv)#hc1cB@"Ƅ J}$=2)mK/0 Rw+lpHG"dČ?}V,3"IN8ʌԘ6 ρz(޷&?:,xP _j~TbFؐ9.^Â]i|o-%ϳ;}nc;{& xYnOen~!ٛoJ6 )|1?*1#05fNt7ʐЧ3JAP/MvCMTMўjL,eFQ^]5st .AgZےR3VmGךa7z Y<'a5Gz<ҜYU?sys7S_[=oDxۯʁh>$8,4_@r %<(I A9q ޳؜Vd{a2plHt\BWQP~SeAä:^';kEXK U0mvv%LO*&D5bIZ%gE]u/LFk_zmYR-X!tI)iDujxyk>X'qOf }:cJ1`3QbESwdk+pXhHElR{#srKWf*U(/µ{ӥ70(#j\+ϧyNieվb4Ċ4S.U2ኤu 9@`^qQn>!=ݮ>MF摵Tq]o`P$֗齉C@gwٰB8[yȡG
+||B
+dh!\T[$:.6 g
+WҖOa ZiKw
+*<C" Nj-ȩWLuݙ`&\rD;f[4~v)C#hc1Bc@" ƅ}$J=2m)K/0 Rw+lpHG"dČ?V,}"3NI8ʘ6 Ԧρ(z&?,:P xj_TbF~.^9ß]i|o-ϳ%;}nc{; x&nYOen~!ϼٛJ6o )|1*1#?05ft7NʂА3اJAP/vMCMTMLj,FQe^]5st.A ZgR3VmG֚a7z Y<'5az<GYU?sys7S_[o=xDʁ>h8,4$_@r %(I<A 9q޳ ؜dV{ap2Ht\lBW
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+  
+
+`m~8lkxpj 9cd6G(ZGuQ5Ojϋ
+Jſ
+
+W9/D?Sa.z9y'WA뜍֬|*u e[@ywDGt2$ݽT~D$uU7'|M_QuVX,7۪J>5&5 M{n0f&%HVV^c ϲc|E pPr(pH# yM;-AB G&LjMG\^ |Y#јr8S#/nqFnEV 9q +A|iCHy}B{BIZ
+(Υ'R¦սTUdpfM w&ۄgC!`X0TroSUGڿ]bVhkʃ;n-Ӧ\= wL3{9+^S_aodC x^c"&gI{ڷ"%-U^7rRyL H[k0 cq/޹ S E!5(T<)c)A|-nRPf4,0P1`sY&D\dwR3A+ٺ|o!PaH?ek«dv&4{^% ;MM1$~I,;jx`]sVz\/1Co0TyXR^/2zj0>՚1B°I #ڸ(0q_`ɣaM/Ǚ."płNؼ40y;'ƸaiH
+ `s5GƱVL>#8d^BFzk
+Od^AE#\;]>rC|m~ll9`qpsv#E@]%=`GK6DήPQH<p}}d^(O= &g.yr?U+HԼ?^!@WNFRWs3NɷdŸW1O g_?@k{C=K۵cUȗn-J(JqoCCl< _P/~׿PZG.Q>pX.0_|r
+*,]I鎸P'WIoyR}}Yr@EEt]>uOiVA#. '`vteyvvwHNma}/ 4H<0(Ow Vܒ M"7)}V'|@|硴f^aÝ <є`AFv\;
+@sg4|~q6UO/Т`?mPьGn
+=Dmn`I:T`H'W+8$ ږ%Eh;}E `P/(b4 ٠m+1+d
+- y#;(8itb߷@!{7
+Tɪס2Zb,gTzuw11&o6F HjyZVLj~CRv/ t,t* M|k .TA5B=!&|,aRe1i%
+^Iy p1 d>>̶Ոî 0rlqn/kءDVÈ9/ű1(x⤣2}o~X
+_w:^VxV޾\!uQųåҶw#)Ei/z毲p[v F98/gs
+ ~tn,fy3jXDD1
+H_%A@N$A
+UeQr%
+9jyMc@hV 틕Z Vqק)N-fc
+ QV$AV ʔUWnྵa$
+XK'aU{whkldMDfd~i/IO70j5,s@IvM;B(HDLns) _ɋ}oaOw.+rץ<}+FYYEEهTNoHm| ǥcs_DVj͈prͳ]ny` E`1©\1BN"r\,rN@%/N2g@#x\n܃"ukMxnXO DH?{vw#Vu*F_( +8=6 JRft;QZylu eX&hJpFS(l\v0k)h76*g$ k%ֿh,DUueI40" WIbuU~bڨv^FESGml,gHL|3ەCh\SU2` ߝWc9^28aI37~^b<#NygCHKJf-ۄoH Ja
+"nҕ[N$]B 'n{ܨEs/##5&攰33~t+7s%iHةb:8⇧vSH6tc ivEP*Y#56nLΤ}-l] ū/! ߉x_3ODFu+չHAܛ Ȇ}s3
+"rJ<f1Ɉb`zGRȶ<vi?RNM1dp8YTf !0Qh[l/>0qt&@3/C~A^ l( ؒ0~of˜os*`ژ46K-%#= %IH
+ngtr9ѱE7XXVþ0n$!)E1^ŎF8JXFNPF_C)x;$mN,dJTO
+aϩI=߹_d: }+p?PO+Zbbyj.H@,Z@"ғ-ES4n)olIIBr~V>olbfLTq*+9)XLVRf.S9v.i硦>iFt+LVvuOx39]O#2]2=&K/~~<O^?vf)o=E4ӷ+4grN=U"g`k8=ü0}8QcÐӝXyTGָaYwSW-XVcNx.F~eyUڑ0@5㶼P?!@=LXI6QpӱڍyKoqK 0ݻ맕d5w
+tцB*v:-7ޚ,
+)p@ :$7ѴyN] h1 HZ޻Bf1畏?r 3uQB}\cmd!@
+WS1zݨ]3CoFq"8ԚέiGb[UgfN G[oLĎnrWxzdD]Ջ` l_9
+L=mPO%os#(ĴyI%4aĘnzn|l6AT޾'VAJ<mgB`u{ $;g9?T0q;Bd2̤E}JpB
+}z[WZ?ՌM (ԤΤ0y43S;w7x泀hN~Ţ |9O*C}/6"+7$Wx4oagH^RA^e$.@{脠X[ݔVH۲8rWs1d[O~/<PodJ#uwz!![zM:&) Q|ceY{nr
+0NndQ& #Phꃢd
+
+
+
+
+
+3֍
+5vM#IB$猞G^Z.)/J&|JsBl}C.weķ$=/'49n+>SK?NvہTG= `yȱ4g|"UCР;X)z`KQ'nU_O_MKaLۻ{*z'9<sJreuT_Rm#5zȵ5qШV*{̜)SsNz'`ax/,u'z^}հ$#ETHw2[FdlCz v#:;wkD(>AYst
+t ^yU /)f:`ϰgi9PکH 1K#=gwu홠)sP`=1er/X^fJ2Ak
+Xd߫!U3zP 3-ĪZr&j|I9X+RLo]ŵ좃',w;6.F^2|!ltJN5 gmp)՞R Vb#]e_$?iU6Hژc|
++0C:ͳ4yJQ"; tgN)܀b4h!145Mܷݏ괓Z'Hp!vp)a[Q;#ÐO]kNGY|(ʾ.»L*% 4h<j'Ù&[q懧<r! тK[C1tOFٺ wl]azW {+Rdj>svd/k&Νa%J3 یᦅ} ]Wq
+Xd߫!U3zP 3-ĪZr&j|I9X+RLo]ŵ좃',w;6.F^2|!ltJN5 gmp)՞R Vb#]e_$?iU6Hژc|
++0C:ͳ4yJQ"; tgN)܀b4h!$@mtt [-`H?f>h<n82.V\=Pvŷա(7^H~m̪TA+KZXE6~z#ǾY 1@ F/p^tnׂr2KʃYҌ7oB+QQ 3K%GκlD>Z'1'Sj0A/8S7=vuF&`&p|Ҵ645Mܷݏ괓Z'Hp!vp)a[Q;#ÐO]kNGY|(ʾ.»L*% 4h<j'Ù&[q懧<r! тK[C1tOFٺ wl]azW {+Rdj>svd/k&Νa%J3 یᦅ} ]Wq
+Xd߫!U3zP 3-ĪZr&j|I9X+RLo]ŵ좃',w;6.F^2|!ltJN5 gmp)՞R Vb#]e_$?iU6Hژc|
++0C:ͳ4yJQ"; tgN)܀b4h!
+Xd߫!U3zP 3-ĪZr&j|I9X+RLo]ŵ좃',w;6.F^2|!ltJN5 gmp)՞R Vb#]e_$?iU6Hژc|
++0C:ͳ4yJQ"; tgN)܀b4h!
+
+
+
+
+
+
+
+
+
+
+
+4#4`4&4K14P;=4pI4#V4d4Ums44 44i424?44i446q4I45 55v{5&57{15=5^LI5;aV5Od5%s5y55|ْ5d5R53a5%5.5A5A.5W5f6O 66M6u&62G16t<6^I6e"V6 d6r6S66r666]65-6ǰ666`66@7 777E&7=17<7oH7U7c7r7-77t77,7G7yy77G77s78~ 8m88b&8V08]<8H8U83c8nPr88kj8X8*ۛ8 8hŰ8;B8)~88e8,8
+&H:'U:c:xq:;::::˚:]:ӻ:::::\
+
+
+
+
+
+
+z@
+(@ՙ@t@?@Lj@
+(@
+(@@
+(@^@@@
+@>@s@ @@A@A@t@j@@m @>@p@Y@@?@d6@Tg@@@@)@Y@Lj@V@@@E@t@N@@
+(@
+(xA=6A
+7B,BAl@B=6UBijB
+7BwBB\1BAlBa
+7pC&"wCw~ChC
+CvCCC 6C6ʗCaCCC<CCC4C2CCHC
+DO" DDDDe D
+D DhDD
+DB Dv"D$D&D(D%*Di-,D 6.D?0D6J2DU4Da6Dn8D|:D<D>D@DļBDDDFDKHD KDMD4ODKQD2cSDy{UDWDFYD[D]D
+D)DIDhDhDqDȳD?D
+D+DBLDmDvDjDӼDDD;D^DDDdDiDD 6DZDDݤD6DDD;DaD6DۮDDD $DKD9sDD9DD D<DeDώD!DD_ DK5Dh_DD;DD D4D4`DDXD2D>Dy;DgDDLDFDpDHDQvDDD
+
+"gVsoDBM&(sP
+j : h;5+kwQ;x
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+I
+
+
+
+
+
+,,
+
+
+ۛIrS{y%P;LylO`@ž\^c$johSl>9oR;Qm,0DE ^J3(fK.WtE9_ ӹyU
+2`
+,y|$ryVw.?rU$qk.P̈́GXzt}K:zfC cdG27;C$CMQe*
+^*>Zw=Ne)։>%fRxL.jxS<-
+N=+6&9`y#RnfE{7(2åZl!Xeh;/ۭ}*/n[(!pa)uGa0a4c\s9pL ު˼,b`\ndi#PZe2Zh@*<1! T_~}=b7w-_h)5ǡޖXxWcr"ÃF
+T0.SHُ(1mX4a(s<|J]d]B> EꫪOlOBBǵj;Oe!AyMjGKPb=bF&[$ti GV
+ʫ%xP()Sچ,
+mbh
+جV@E'H::SU kKмgUXc)3VJ*%1?~^|1)p/'\,(H"m?H܆AyG@n]Q_2Տd5A4x{%`*`lc´2Of#k>3b $;" r(-Exb}doITH}'>AcG
+t.no:7`L knU{7,gm;e' )
+n *Ngd_ڈ鿾dW{x`M``FѰ8Ew63kBqA_^
+r9$||_rㆹMr[xUT|=M^Pa<QloNVο*6742cg
+sMLۻ9)PF&^Q-jc"‰.$CaMjP[d&(::KbU/Rio?Y
+w >;Z4ٷ,Q+:Ֆ}}>(-}|%rZLZq)GW;()f(.y_xU`uD^mm%adâW<'*:m?!cf&(3uU4V<wQ(
+gQ̫_QM08bX7 z{>d!Q2Ow~㶨F=)iSHd$m-if!
+FEdlX [@X̻k~jEY:D
+5>ʹrdfGo<cҞ]/Tw®pcN tW[qr]}S@@NjF4(:Hn΂;?o 5K'r'`a?+y:%E49KyQ2/ɺ~ǼǪIO8
+*9g6|1O+Y:CE',"*q%a뜶YdѨ^ jePBn;ۘLdx22ߒ+4qAt
+4K q2vÍ5./Go TLybo~>f,ҏ"W##v215VbuZ6ns҈bIPLVq
+z2E{S
+`cC#( (D@D
+
+?/3>d`D$,".HCK 
+ !!hcK+dbF&
+
+TRFtsG7 -DBF5(# +daE%:#91\RN9&2011*laM-\SO$0 82
+:XPH`bB"(! )033( xqI9hbJ*("
+*088(! -,&ܳ38/`@ `QET@DDcO/lcK+hSKXbB"`3305! )( "ࣇ'Б <264CK H/쀈`L,l(4AED!3?<1 =< ((BNL62><%9 # +(bF&drJ:x#'$#/,1rB2pBB@AA@
+ ,,*044 .)QM\8SGT.
+bJ*h1
+#,쁍 ?sK;xPL\"!cC#`## AM LȒ2
+:8
+*(RN\)RFTCC@ 0%@HHqI9x<!!  SO\sG7tPDT2 !%$COL
+
+@L L3 ;8BJ
+H7)DTP ,%$!M\QC@CAPQ<
+C#`c(( DD@
+
+?/3>D$d`.,"K HC
+! !K+hcF&db
+
+HBFTRG7ts -FDB5 +(#E%da:#91N\R9&2101*M-laO\S$0 
+:82HXPB"`b )(!303( I9xqJ*hb
+*("880(-,! &38/ ``@TQED@D/lcO+hcKXSK"`bB3035)(! "' <642 HCK/,l`L(4DAE!?<3=<1 (( LBN6><2%9  +(# &dbF:xrJ'$#/,#12prB@BB@AA
+,, *440  .)\QM8TSG.
+*hbJ1
+#, ?;xsK\PL"!#`cC# # LAM:82
+
+\RN)TRF@CC 0%H@H9xqI<! !  \SO7tsGTPD2 %$!LCO
+
+ L@L;83
+HBJ7
+
+
+
+
+
+
+
+(
+
+
+
+
+6
+
+
+
+.
+K
+b
+
+
+
+.
+.<
+.]
+.
+.
+.k
+.
+.
+.
+."
+.F
+.g
+.
+.
+."
+.
+
+
+
+
+&v
+&
+&
+
+
+
+
+"
+"
+"
+"
+
+"
+"
+
+
+
+
+
+
+
+
+
+
+
+
+
+N
+g
+
+
+
+9
+`
+-
+
+
+
+7
+F
+
+
+=
+X
+%
+ 1
+ {4
+ 4
+ 4
+ 4
+ 4
+ 4
+ 4
+ 4
+ 5
+ f5
+ t5
+ 5
+ 5
+ 5
+ 5
+>
+H<
+T<
+a<
+q<
+<
+<
+<
+<
+<
+<
+<
+
+ =
+=
+-=
+<=
+K=
+T=
+c=
+o=
+}=
+=
+=
+=
+=
+=
+;
+M
+
+N
+P
+N
+;
+ <
+E
+S
+<
+4<
+dN
+N
+T
+>
+]H
+H
+H
+H
+H
+WI
+I
+J
+L
+L
+M
+M
+6M
+FM
+WM
+M
+N
+X
+Y
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+5lBɻ@l2u\E Y=ѫ0&:
+| <qPA' %hWo fa^)"а=Y .;\l ұt9Gwҝ&s c;d>jm Zjz  '
+}Dңhi]Wbgeq6lknv+ӉZzJgo߹ホCՎ`~ѡ8ROggW?K6H+ L
+J6`zA`Ugn1yiFafo%6hRw G "/&U;( Z+j\1е,[d&c윣ju
+m ?6grW
+ TN³9a&g`MGiIwn>JjѮZf @;7SŞϲG0򽽊º0S$6к)WTg#.zfJah]+o*7 Z-
+Ζ
+" ˮO]_lF?mtCZ#AplAwG6-ŵ
+-
+=G\ p&Gw)` /a߫i5&LsZ<#0zMzFM8,9; :<D? >R:<eP=X^6o}7654W1Օ0k23k$%1'[-&LMb#{'"" $!(x*޺+F`)q
+>(q-v,.7/pXqYs3r%w+OQvrtEux܉~OK }!b|tyBxʠz{.lD~m8onlk[wjR1h58ib?mcf+aQ`צedd"fig HINSKyuJcO NZLݘMFGN@E$DD2AsX@*IBCPhTg3U>uW ַVS:R|P~Q9ZS [fYX4])\ZEo^m/_5qϱ٥s\<k2g z8J& Va`/ӈ6\ilU,zBĞu\H
+
+yKiw\¹9~$ 66nQfq>,o,IӔ 渱{I .H>C-Yn馑gQz taf
+k5Blۻ֬@2lE\u ϫ=Y&0Q
+L_ |Pq<'A  Wh% of a^)ɘИ"רY=. \;l  tҚG9w&sc d; mj>zjZ
+
+L6JAz``ègU1nFiyaf%oҠRh6 w G"U&/ź; (+Z\j1,ٞ[ޮd°c&ujm
+ 6?rg
+x NT9§g&a`IiGM>nwۮjJZ@ f7;𩼮S޻G0齽ʺŠS0$6TW)#gfz.aJ]h*o+ 7 Z-
+\
+ ˈ_]OFlm?tZCA#lpwA6G-
+-
+ \G=&pGw`)/ ai5&sL<Z0#zzM8MF9,;ɒ: ?D<> <:R=Pe6^X7}o5641W0ճ2k3$k%'1&-[#bML"'{ "!$*x(+)`F(>
+q-q,v.Ț/7pqXsYr3w%vQO+tru՛E~xKO} |b!ytxBz{l.m~Do8nkljw[h1Ri85bcm?a+f`Qeddf"giH IKSNJuyOcN LZMݥFĚGE@ND$A2D@XsBI*CThPU3gWu>V SR:P|Q~Z9[ SYfX]4\)^oEZ_/m5qs<\kg2z &J8 좞V`a/6i\lU,zB\u
+;g
+Kyi׫w¡\~9$66 Qnf>q,o,ӹI 散 I{.C>HnY-Qg̰t zfa
+
+
+
+r;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+I
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+='=/=/;K`;
+#<N<
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+I
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+'
+(
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+'8!.m,M 8STs
+e
+jv.,r迢KfpK£Ql$օ5pjl7LwH'4 9JNOʜ[o.htocxxȄnjlPxq
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+I
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+!
+
+
+
+
+
+
+
+
+9|
+
+
+
+
+
+
+
+
+
+
+!
+1
+9
+=
+I
+W
+a
+c
+g
+o
+u
+{
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+    # ) - ? G Q W ] e o {   % / 1 A [ _ a m s w      ! + - = ? O U i y !'/5;KWY]kqu}  %)1CGMOSY[gk!%+9=?Qisy{ '-9EGY_cio #)+17AGS_qsy} '-7CEIOW]gim{!/3;EMYkoqu %)+7=ACI_egk} %39=EOUimou #'3A]cw{57;CIMUgqw}13EIQ[y!#-/5?MQik{}#%/17;AGOUYeks '+-3=EKOUs !#59?AKS]ciqu{} %+/=IMOmq 9IKQgu{   ' ) - 3 G M Q _ c e i w } !!5!A!I!O!Y![!_!s!}!!!!!!!!!!!!!!!!!" """!"%"+"1"9"K"O"c"g"s"u"""""""""""""""# # #'#)#/#3#5#E#Q#S#Y#c#k################$ $$$)$=$A$C$M$_$g$k$y$}$$$$$$$$$$$$$$$$$$%%%%'%1%=%C%K%O%s%%%%%%%%%%%%%%%%& &&&'&)&5&;&?&K&S&Y&e&i&o&{&&&&&&&&&&&&&&&''5'7'M'S'U'_'k'm's'w''''''''''''''(( ((((!(1(=(?(I(Q([(](a(g(u((((((((((((()))!)#)?)G)])e)i)o)u))))))))))))))))***%*/*O*U*_*e*k*m*s***************+'+1+3+=+?+K+O+U+i+m+o+{++++++++++++++ ,,,#,/,5,9,A,W,Y,i,w,,,,,,,,,,,,,,,,---;-C-I-M-a-e-q-----------... ...%.-.3.7.9.?.W.[.o.y................/ / //'/)/A/E/K/M/Q/W/o/u/}///////////////0 0#0)070;0U0Y0[0g0q0y0}000000000000000001 11!1'1-191C1E1K1]1a1g1m1s11111111111111 2222)252Y2]2c2k2o2u2w2{22222222222222223%3+3/353A3G3[3_3g3k3s3y33333333333334444474E4U4W4c4i4m44444444444444 555-535;5A5Q5e5o5q5w5{5}555555555555555666#6165676;6M6O6S6Y6a6k6m6666666666667777?7E7I7O7]7a7u7777777777778 8!83858A8G8K8S8W8_8e8o8q8}8888888888888899#9%9)9/9=9A9M9[9k9y9}999999999999999999::::':+:1:K:Q:[:c:g:m:y::::::::::::;;;!;#;-;9;E;S;Y;_;q;{;;;;;;;;;;;;;;;;;;< <<<<)<5<C<O<S<[<e<k<q<<<<<<<<<<<<<= ====!=-=3=7=?=C=o=s=u=y={=============> >>>>#>)>/>3>A>W>c>e>w>>>>>>>>>>>>>>>> ? ?7?;?=?A?Y?_?e?g?y?}????????????@!@%@+@1@?@C@E@]@a@g@m@@@@@@@@@@@@@ A AAA!A3A5A;A?AYAeAkAwA{AAAAAAAAAAABBBB#B)B/BCBSBUB[BaBsB}BBBBBBBBBBBBBBCCC%C'C3C7C9COCWCiCCCCCCCCCCCCCCCCC D DD#D)D;D?DEDKDQDSDYDeDoDDDDDDDDDDDDDDEEE+E1EAEIESEUEaEwE}EEEEEEEE
+
+
+
+
+
+
+"
+;
+A
+J
+P
+[
+a
+j
+p
+
+
+
+
+
+
+
+
+ 
+
+
+
+!
+5
+;
+D
+J
+U
+[
+d
+j
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+   ' - 8 > G M a g p v    ' -     # < B K Q \ b k q
+$*39RXagrx 06?EPV_e~tz  +1:@TZcitz 7=FLW]fl17@FQW`f#)4:CI]clr} #)
+8>GMX^gm%+6<EKdjsy "+1EKTZektz (.7=HNW]qw(.7= $-3LR[alr{*09?JPY_x~)/8>IOX^rx )/8>U[dju{ !5;DJU[dj+1:@KQZ`y#.4=CW]flw}# 
+$*39RXagrx 06?EPV_e~tz  +1:@TZcitz 7=FLW]fl17@FQW`f#)4:CI]clr} #)
+8>GMX^gm%+6<EKdjsy "+1EKTZektz (.7=HNW]qw(.7= $-3LR[alr{*09?JPY_x~)/8>IOX^rx )/8>U[dju{ !5;DJU[dj+1:@KQZ`y#.4=CW]flw}#
+-3<BMS\b{%06?EY_hny% 4:CITZci}!'28AG`fou '-AGPVagpv $*39DJSYms|
+$*39
+~"Qg ) 
+1=Bwzi
+f1mT ((
+^JnI$lnT5vz ~+@JB/@BCgkh(nda V688n87+(<?316 ggAVJ&gz v9=
+I=SUWS]I^ !
+Y1 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ LLT!%(,[1K6;ADH~OqW/`ibt
+
+ LLT!%(,[1K6;ADH~OqW/`ibt
+
+
+m
+m
+m
+
+
+m
+ (2?KV`bdfhjlnprtvxz|~+:=@GNXgqx*17>AMT[^knw~
+!'+4BLS_ipv}
+
+
+
+"
+)
+7
+A
+H
+S
+c
+p
+|
+
+
+
+
+
+
+
+
+
+
+  " , 9 E R [ e r     ( 6 C P _ n |
+  % 1 B Q Z f r ~  $,4<BGLRYag
+ (2?K`bdfhjlnprtvxz|~_p}C`JVmgt}GqgB
+4
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ pass # replace with function body
+
+
+
+
+
+
+
+
+
+
+
+
+U U*H *H *H *H *H *H *H *H *H ++ +++<*H ++*H +*H  *H  *H  *H  *H  *H  *H  *H  *H  *H  `HB`HB`HB+*H + + *H  *H  +`HB`HB`HB`HB`HB`HB`HB `HB `HBUUUUUUUUU U#+UUeUdU*UU+U+UU U *H}B
+*H}B *H8+*H8+$+$*H )*H  U%++++++++7+7+7
++7
++7
+`HBUUU+e*H  *H  *H  *H  *H  *H  *H 
+*H 
+*H 
+*H 
+*H 
+*H 
+*H  *H  *H  *H  *H  *H  *H *H ++*H  *H *H *H 
++7*H  U)U.++0++0+0+ **H*H8*H8*H *H *H  *H  
+*H   *H   *H   *H  *H  *H  *H  *H  *H  *H  *H  *H  *H  *H  *H  *H  *H  *H  *H  *H  *H  *H  *H  *H  *H  *H  *H  *H  *H  *H  *H  *H  *H  *H  *H  *H +
++ + +
++
++++++++++ +
++ + + +++++++++++++++++++++++++ +
++ +++++++++++ + + + + +
++
++
++
++
++ + + + +0+0+0+0+0+0+0+0+0+0+0 +0
++0 ++ U++++++++++++:X &,d &,d UU7*H +
++ +
+UHU$U7U8*H=*H=*H=*H=*H=*H=*H=*H=*H=*H=*H=*H=+7`He`He`He`He`He`He`He`He`He)`He*`He+`He,U*H8*H8*H8 & &, &,d &,d &,d &,d &,d
+ &,d &,d &,d &,d &,d &,d &,d &,d &,d &,d &,d &,d &,d &,d &,d &,d &,d &,d &,d &,d &,d &,d &,d &,d &,d &,d
+ &,d &,d &,d &,d &,d &,d &,d &,d &,d &,d &,d &,d &,d &,d &,d &,d &,d% &,d& &,d' &,d( &,d) &,d* &,d+ &,d- &,d. &,d/ &,d0 &,d1 &,d2 &,d3 &,d4 &,d5 &,d6 &,d7 &,d8U-+++++U,UAg*g*
+g*
+g* g*
+*H g+7+7U U+++
+*H=
++
+g+ g+ U
+*H  `He`He(
+******b*c**
+*H *H>+$+$+$+$+$+$+$+$+$ +$
++$ +$ +$ +$*H  +H?
+
+
+
+
+ IPSec/IKE/Oakley curve #3 over a 155 bit binary field.
+ Not suitable for ECDSA.
+ Questionable extension field!
+ IPSec/IKE/Oakley curve #4 over a 185 bit binary field.
+ Not suitable for ECDSA.
+ Questionable extension field!
+
+
+
+
+
+
+
+
+%*sVersion :
+%*sLog ID :
+%*sTimestamp :
+%*sExtensions:
+%*sSignature :
+%*s
+%*s
+
+%*s
+
+%*s
+
+
+
+
+
+
+
+
+%*s
+
+%*sZone: %s, User:
+
+
+
+
+
+
+
+
+  !"#$%&'()*+,-./0123X509_EXTENSIONS
+
+
+
+thirdparty/openssl/ssl/d1_lib.c
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~
+ 
+  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~
+ 
+  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+                                                                                
+ 
+ 
+ 
+ 
+  !"#$%&'()*+,-./0123456789:;<=>?
+  !"#$%&'()*+,-./0123456789:;<=>?
+  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~
+  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ıwebp
+ڽ r,
+yP>,@UG
+&Ր".7!G?rr Q( `T$YbejHdo KPBfcJ>()5 kJ+I1A&i34shO WWDG,r3/)nB-fŽXX*.-+auU&#='5W+8"3hrf]M'U:Zb@"t"+Ik6 3Q+Dj@$r"fL|>N_U9203e#oY.o<opqMU&xr(*
+mX+%+=?C-DdP+3GNN"ū)(fӷ32R$&,CW:Rs;?;Z;]I((t"'/"1-.!b 9.6%A Is( s3W% s;M@/h7, 65@ZF()969p)&"t
+ '5r I AvIK 3+3X#CfU7U8o;-%7&F|If"b}b*XhUuR_T5Ydqe-KO{/3Q9Gf95)1&! y9IU)
+CMnZ/rs
+fe
+Ue9
+ff"+u$Df=G%"5E<G&Iw%D-"/ >FU7>F%+%dU? \@ UK @wV@87t:R9y(2#3g,{V(@--[@8'<fS 6D/UUU  ?#
+ P#cP~6-U~/W3) eKvtU8)U% >Gwve&<7F+$a-=>Q@ )up =À0
+ 
+ 
+   `I7' eN:*
+ !/?WiZF4% &5G[ncRB0#$1CSdsl^L@2,(")-3AM_mvqg\PD<869=EQ]hrwtojaXTJHKUYbkpu
+  !"#$%&'()*+,-./0123456789:;<=>?
+
+  !"#$%%&'()*+,-../0123456789:;<=>?@ABCDEFGHIJKLLMNOPQRSTUVWXY[]_`bdefhjlnprtvz|~`n`lns
+ operators/expression
+ haccept error
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 
+
+ need dictionary
+
+
+
+
+
+
+
+
+
+
+
+
+/*
+from VisualServer:
+
+ARRAY_VERTEX=0,
+ARRAY_NORMAL=1,
+ARRAY_TANGENT=2,
+ARRAY_COLOR=3,
+ARRAY_TEX_UV=4,
+ARRAY_TEX_UV2=5,
+ARRAY_BONES=6,
+ARRAY_WEIGHTS=7,
+ARRAY_INDEX=8,
+*/
+
+//hack to use uv if no uv present so it works with lightmap
+
+
+/* INPUT ATTRIBS */
+
+layout(location=0) in highp vec4 vertex_attrib;
+layout(location=1) in vec3 normal_attrib;
+#if defined(ENABLE_TANGENT_INTERP) || defined(ENABLE_NORMALMAP) || defined(LIGHT_USE_ANISOTROPY)
+layout(location=2) in vec4 tangent_attrib;
+#endif
+
+#if defined(ENABLE_COLOR_INTERP)
+layout(location=3) in vec4 color_attrib;
+#endif
+
+#if defined(ENABLE_UV_INTERP)
+layout(location=4) in vec2 uv_attrib;
+#endif
+
+#if defined(ENABLE_UV2_INTERP)
+layout(location=5) in vec2 uv2_attrib;
+#endif
+
+uniform float normal_mult;
+
+#ifdef USE_SKELETON
+layout(location=6) in ivec4 bone_indices; // attrib:6
+layout(location=7) in vec4 bone_weights; // attrib:7
+#endif
+
+#ifdef USE_INSTANCING
+
+layout(location=8) in highp vec4 instance_xform0;
+layout(location=9) in highp vec4 instance_xform1;
+layout(location=10) in highp vec4 instance_xform2;
+layout(location=11) in lowp vec4 instance_color;
+
+#if defined(ENABLE_INSTANCE_CUSTOM)
+layout(location=12) in highp vec4 instance_custom_data;
+#endif
+
+#endif
+
+layout(std140) uniform SceneData { //ubo:0
+
+ highp mat4 projection_matrix;
+ highp mat4 camera_inverse_matrix;
+ highp mat4 camera_matrix;
+ highp vec4 time;
+
+ highp vec4 ambient_light_color;
+ highp vec4 bg_color;
+ float ambient_energy;
+ float bg_energy;
+
+ float shadow_z_offset;
+ float shadow_z_slope_scale;
+ float shadow_dual_paraboloid_render_zfar;
+ float shadow_dual_paraboloid_render_side;
+
+ highp vec2 screen_pixel_size;
+ vec2 shadow_atlas_pixel_size;
+ vec2 directional_shadow_pixel_size;
+
+ float reflection_multiplier;
+ float subsurface_scatter_width;
+ float ambient_occlusion_affect_light;
+
+};
+
+uniform highp mat4 world_transform;
+
+#ifdef USE_LIGHT_DIRECTIONAL
+
+layout(std140) uniform DirectionalLightData { //ubo:3
+
+ highp vec4 light_pos_inv_radius;
+ mediump vec4 light_direction_attenuation;
+ mediump vec4 light_color_energy;
+ mediump vec4 light_params; //cone attenuation, angle, specular, shadow enabled,
+ mediump vec4 light_clamp;
+ mediump vec4 shadow_color_contact;
+ highp mat4 shadow_matrix1;
+ highp mat4 shadow_matrix2;
+ highp mat4 shadow_matrix3;
+ highp mat4 shadow_matrix4;
+ mediump vec4 shadow_split_offsets;
+};
+
+#endif
+
+
+/* Varyings */
+
+out highp vec3 vertex_interp;
+out vec3 normal_interp;
+
+#if defined(ENABLE_COLOR_INTERP)
+out vec4 color_interp;
+#endif
+
+#if defined(ENABLE_UV_INTERP)
+out vec2 uv_interp;
+#endif
+
+#if defined(ENABLE_UV2_INTERP)
+out vec2 uv2_interp;
+#endif
+
+
+#if defined(ENABLE_TANGENT_INTERP) || defined(ENABLE_NORMALMAP) || defined(LIGHT_USE_ANISOTROPY)
+out vec3 tangent_interp;
+out vec3 binormal_interp;
+#endif
+
+
+VERTEX_SHADER_GLOBALS
+
+
+#if defined(USE_MATERIAL)
+
+layout(std140) uniform UniformData { //ubo:1
+
+MATERIAL_UNIFORMS
+
+};
+
+#endif
+
+#ifdef RENDER_DEPTH_DUAL_PARABOLOID
+
+out highp float dp_clip;
+
+#endif
+
+#define SKELETON_TEXTURE_WIDTH 256
+
+#ifdef USE_SKELETON
+uniform highp sampler2D skeleton_texture; //texunit:-6
+#endif
+
+out highp vec4 position_interp;
+
+void main() {
+
+ highp vec4 vertex = vertex_attrib; // vec4(vertex_attrib.xyz * data_attrib.x,1.0);
+
+ mat4 world_matrix = world_transform;
+
+
+#ifdef USE_INSTANCING
+
+ {
+ highp mat4 m=mat4(instance_xform0,instance_xform1,instance_xform2,vec4(0.0,0.0,0.0,1.0));
+ world_matrix = world_matrix * transpose(m);
+ }
+#endif
+
+ vec3 normal = normal_attrib * normal_mult;
+
+
+#if defined(ENABLE_TANGENT_INTERP) || defined(ENABLE_NORMALMAP) || defined(LIGHT_USE_ANISOTROPY)
+ vec3 tangent = tangent_attrib.xyz;
+ tangent*=normal_mult;
+ float binormalf = tangent_attrib.a;
+#endif
+
+#if defined(ENABLE_COLOR_INTERP)
+ color_interp = color_attrib;
+#if defined(USE_INSTANCING)
+ color_interp *= instance_color;
+#endif
+
+#endif
+
+#ifdef USE_SKELETON
+ {
+ //skeleton transform
+ ivec2 tex_ofs = ivec2( bone_indices.x%256, (bone_indices.x/256)*3 );
+ highp mat3x4 m = mat3x4(
+ texelFetch(skeleton_texture,tex_ofs,0),
+ texelFetch(skeleton_texture,tex_ofs+ivec2(0,1),0),
+ texelFetch(skeleton_texture,tex_ofs+ivec2(0,2),0)
+ ) * bone_weights.x;
+
+ tex_ofs = ivec2( bone_indices.y%256, (bone_indices.y/256)*3 );
+
+ m+= mat3x4(
+ texelFetch(skeleton_texture,tex_ofs,0),
+ texelFetch(skeleton_texture,tex_ofs+ivec2(0,1),0),
+ texelFetch(skeleton_texture,tex_ofs+ivec2(0,2),0)
+ ) * bone_weights.y;
+
+ tex_ofs = ivec2( bone_indices.z%256, (bone_indices.z/256)*3 );
+
+ m+= mat3x4(
+ texelFetch(skeleton_texture,tex_ofs,0),
+ texelFetch(skeleton_texture,tex_ofs+ivec2(0,1),0),
+ texelFetch(skeleton_texture,tex_ofs+ivec2(0,2),0)
+ ) * bone_weights.z;
+
+
+ tex_ofs = ivec2( bone_indices.w%256, (bone_indices.w/256)*3 );
+
+ m+= mat3x4(
+ texelFetch(skeleton_texture,tex_ofs,0),
+ texelFetch(skeleton_texture,tex_ofs+ivec2(0,1),0),
+ texelFetch(skeleton_texture,tex_ofs+ivec2(0,2),0)
+ ) * bone_weights.w;
+
+
+ vertex.xyz = vertex * m;
+
+ normal = vec4(normal,0.0) * m;
+#if defined(ENABLE_TANGENT_INTERP) || defined(ENABLE_NORMALMAP) || defined(LIGHT_USE_ANISOTROPY)
+ tangent.xyz = vec4(tangent.xyz,0.0) * mn;
+#endif
+ }
+#endif
+
+
+#if defined(ENABLE_TANGENT_INTERP) || defined(ENABLE_NORMALMAP) || defined(LIGHT_USE_ANISOTROPY)
+
+ vec3 binormal = normalize( cross(normal,tangent) * binormalf );
+#endif
+
+#if defined(ENABLE_UV_INTERP)
+ uv_interp = uv_attrib;
+#endif
+
+#if defined(ENABLE_UV2_INTERP)
+ uv2_interp = uv2_attrib;
+#endif
+
+#if defined(USE_INSTANCING) && defined(ENABLE_INSTANCE_CUSTOM)
+ vec4 instance_custom = instance_custom_data;
+#else
+ vec4 instance_custom = vec4(0.0);
+#endif
+
+ highp mat4 modelview = camera_inverse_matrix * world_matrix;
+ highp mat4 local_projection = projection_matrix;
+
+//defines that make writing custom shaders easier
+#define projection_matrix local_projection
+#define world_transform world_matrix
+{
+
+VERTEX_SHADER_CODE
+
+}
+
+
+
+
+#if !defined(SKIP_TRANSFORM_USED)
+
+ vertex = modelview * vertex;
+ normal = normalize((modelview * vec4(normal,0.0)).xyz);
+#endif
+
+
+ vertex_interp = vertex.xyz;
+ normal_interp = normal;
+
+#if defined(ENABLE_TANGENT_INTERP) || defined(ENABLE_NORMALMAP) || defined(LIGHT_USE_ANISOTROPY)
+
+#if !defined(SKIP_TRANSFORM_USED)
+
+ tangent = normalize((modelview * vec4(tangent,0.0)).xyz);
+ binormal = normalize((modelview * vec4(binormal,0.0)).xyz);
+
+#endif
+ tangent_interp = tangent;
+ binormal_interp = binormal;
+#endif
+
+#ifdef RENDER_DEPTH
+
+
+#ifdef RENDER_DEPTH_DUAL_PARABOLOID
+
+ vertex_interp.z*= shadow_dual_paraboloid_render_side;
+ normal_interp.z*= shadow_dual_paraboloid_render_side;
+
+ dp_clip=vertex_interp.z; //this attempts to avoid noise caused by objects sent to the other parabolloid side due to bias
+
+ //for dual paraboloid shadow mapping, this is the fastest but least correct way, as it curves straight edges
+
+ highp vec3 vtx = vertex_interp+normalize(vertex_interp)*shadow_z_offset;
+ highp float distance = length(vtx);
+ vtx = normalize(vtx);
+ vtx.xy/=1.0-vtx.z;
+ vtx.z=(distance/shadow_dual_paraboloid_render_zfar);
+ vtx.z=vtx.z * 2.0 - 1.0;
+
+ vertex.xyz=vtx;
+ vertex.w=1.0;
+
+
+#else
+
+ float z_ofs = shadow_z_offset;
+ z_ofs += (1.0-abs(normal_interp.z))*shadow_z_slope_scale;
+ vertex_interp.z-=z_ofs;
+
+#endif //RENDER_DEPTH_DUAL_PARABOLOID
+
+#endif //RENDER_DEPTH
+
+
+#if !defined(SKIP_TRANSFORM_USED) && !defined(RENDER_DEPTH_DUAL_PARABOLOID)
+ gl_Position = projection_matrix * vec4(vertex_interp,1.0);
+#else
+ gl_Position = vertex;
+#endif
+
+ position_interp=gl_Position;
+}
+
+
+
+
+
+#define M_PI 3.14159265359
+
+/* Varyings */
+
+#if defined(ENABLE_COLOR_INTERP)
+in vec4 color_interp;
+#endif
+
+#if defined(ENABLE_UV_INTERP)
+in vec2 uv_interp;
+#endif
+
+#if defined(ENABLE_UV2_INTERP)
+in vec2 uv2_interp;
+#endif
+
+#if defined(ENABLE_TANGENT_INTERP) || defined(ENABLE_NORMALMAP) || defined(LIGHT_USE_ANISOTROPY)
+in vec3 tangent_interp;
+in vec3 binormal_interp;
+#endif
+
+in highp vec3 vertex_interp;
+in vec3 normal_interp;
+
+
+/* PBR CHANNELS */
+
+//used on forward mainly
+uniform bool no_ambient_light;
+
+uniform sampler2D brdf_texture; //texunit:-1
+
+#ifdef USE_RADIANCE_MAP
+
+uniform sampler2D radiance_map; //texunit:-2
+
+
+layout(std140) uniform Radiance { //ubo:2
+
+ mat4 radiance_inverse_xform;
+ vec3 radiance_box_min;
+ vec3 radiance_box_max;
+ float radiance_ambient_contribution;
+
+};
+
+#endif
+
+/* Material Uniforms */
+
+
+FRAGMENT_SHADER_GLOBALS
+
+
+#if defined(USE_MATERIAL)
+
+layout(std140) uniform UniformData {
+
+MATERIAL_UNIFORMS
+
+};
+
+#endif
+
+
+layout(std140) uniform SceneData {
+
+ highp mat4 projection_matrix;
+ highp mat4 camera_inverse_matrix;
+ highp mat4 camera_matrix;
+ highp vec4 time;
+
+ highp vec4 ambient_light_color;
+ highp vec4 bg_color;
+
+
+ float ambient_energy;
+ float bg_energy;
+
+ float shadow_z_offset;
+ float shadow_z_slope_scale;
+ float shadow_dual_paraboloid_render_zfar;
+ float shadow_dual_paraboloid_render_side;
+
+ highp vec2 screen_pixel_size;
+ vec2 shadow_atlas_pixel_size;
+ vec2 directional_shadow_pixel_size;
+
+ float reflection_multiplier;
+ float subsurface_scatter_width;
+ float ambient_occlusion_affect_light;
+
+};
+
+//directional light data
+
+#ifdef USE_LIGHT_DIRECTIONAL
+
+layout(std140) uniform DirectionalLightData {
+
+ highp vec4 light_pos_inv_radius;
+ mediump vec4 light_direction_attenuation;
+ mediump vec4 light_color_energy;
+ mediump vec4 light_params; //cone attenuation, angle, specular, shadow enabled,
+ mediump vec4 light_clamp;
+ mediump vec4 shadow_color_contact;
+ highp mat4 shadow_matrix1;
+ highp mat4 shadow_matrix2;
+ highp mat4 shadow_matrix3;
+ highp mat4 shadow_matrix4;
+ mediump vec4 shadow_split_offsets;
+};
+
+
+uniform highp sampler2DShadow directional_shadow; //texunit:-4
+
+#endif
+
+//omni and spot
+
+struct LightData {
+
+ highp vec4 light_pos_inv_radius;
+ mediump vec4 light_direction_attenuation;
+ mediump vec4 light_color_energy;
+ mediump vec4 light_params; //cone attenuation, angle, specular, shadow enabled,
+ mediump vec4 light_clamp;
+ mediump vec4 shadow_color_contact;
+ highp mat4 shadow_matrix;
+
+};
+
+
+layout(std140) uniform OmniLightData { //ubo:4
+
+ LightData omni_lights[MAX_LIGHT_DATA_STRUCTS];
+};
+
+layout(std140) uniform SpotLightData { //ubo:5
+
+ LightData spot_lights[MAX_LIGHT_DATA_STRUCTS];
+};
+
+
+uniform highp sampler2DShadow shadow_atlas; //texunit:-3
+
+
+struct ReflectionData {
+
+ mediump vec4 box_extents;
+ mediump vec4 box_offset;
+ mediump vec4 params; // intensity, 0, interior , boxproject
+ mediump vec4 ambient; //ambient color, energy
+ mediump vec4 atlas_clamp;
+ highp mat4 local_matrix; //up to here for spot and omni, rest is for directional
+ //notes: for ambientblend, use distance to edge to blend between already existing global environment
+};
+
+layout(std140) uniform ReflectionProbeData { //ubo:6
+
+ ReflectionData reflections[MAX_REFLECTION_DATA_STRUCTS];
+};
+uniform mediump sampler2D reflection_atlas; //texunit:-5
+
+
+#ifdef USE_FORWARD_LIGHTING
+
+uniform int omni_light_indices[MAX_FORWARD_LIGHTS];
+uniform int omni_light_count;
+
+uniform int spot_light_indices[MAX_FORWARD_LIGHTS];
+uniform int spot_light_count;
+
+uniform int reflection_indices[MAX_FORWARD_LIGHTS];
+uniform int reflection_count;
+
+#endif
+
+
+
+#ifdef USE_MULTIPLE_RENDER_TARGETS
+
+layout(location=0) out vec4 diffuse_buffer;
+layout(location=1) out vec4 specular_buffer;
+layout(location=2) out vec4 normal_mr_buffer;
+#if defined (ENABLE_SSS_MOTION)
+layout(location=3) out vec4 motion_ssr_buffer;
+#endif
+
+#else
+
+layout(location=0) out vec4 frag_color;
+
+#endif
+
+in highp vec4 position_interp;
+uniform highp sampler2D depth_buffer; //texunit:-9
+
+float contact_shadow_compute(vec3 pos, vec3 dir, float max_distance) {
+
+ if (abs(dir.z)>0.99)
+ return 1.0;
+
+ vec3 endpoint = pos+dir*max_distance;
+ vec4 source = position_interp;
+ vec4 dest = projection_matrix * vec4(endpoint, 1.0);
+
+ vec2 from_screen = (source.xy / source.w) * 0.5 + 0.5;
+ vec2 to_screen = (dest.xy / dest.w) * 0.5 + 0.5;
+
+ vec2 screen_rel = to_screen - from_screen;
+
+ /*float pixel_size; //approximate pixel size
+
+ if (screen_rel.x > screen_rel.y) {
+
+ pixel_size = abs((pos.x-endpoint.x)/(screen_rel.x/screen_pixel_size.x));
+ } else {
+ pixel_size = abs((pos.y-endpoint.y)/(screen_rel.y/screen_pixel_size.y));
+
+ }*/
+ vec4 bias = projection_matrix * vec4(pos+vec3(0.0,0.0,0.04), 1.0); //todo un-harcode the 0.04
+
+
+
+ vec2 pixel_incr = normalize(screen_rel)*screen_pixel_size;
+
+ float steps = length(screen_rel) / length(pixel_incr);
+
+ //steps=10.0;
+
+ vec4 incr = (dest - source)/steps;
+ float ratio=0.0;
+ float ratio_incr = 1.0/steps;
+
+ do {
+ source += incr*2.0;
+ bias+=incr*2.0;
+
+ vec3 uv_depth = (source.xyz / source.w) * 0.5 + 0.5;
+ float depth = texture(depth_buffer,uv_depth.xy).r;
+
+ if (depth < uv_depth.z) {
+ if (depth > (bias.z/bias.w) * 0.5 + 0.5) {
+ return min(pow(ratio,4.0),1.0);
+ } else {
+ return 1.0;
+ }
+ }
+
+
+ ratio+=ratio_incr;
+ steps-=1.0;
+ } while (steps>0.0);
+
+ return 1.0;
+}
+
+
+// GGX Specular
+// Source: http://www.filmicworlds.com/images/ggx-opt/optimized-ggx.hlsl
+float G1V(float dotNV, float k)
+{
+ return 1.0 / (dotNV * (1.0 - k) + k);
+}
+
+
+float SchlickFresnel(float u)
+{
+ float m = 1.0-u;
+ float m2 = m*m;
+ return m2*m2*m; // pow(m,5)
+}
+
+float GTR1(float NdotH, float a)
+{
+ if (a >= 1.0) return 1.0/M_PI;
+ float a2 = a*a;
+ float t = 1.0 + (a2-1.0)*NdotH*NdotH;
+ return (a2-1.0) / (M_PI*log(a2)*t);
+}
+
+
+
+void light_compute(vec3 N, vec3 L,vec3 V,vec3 B, vec3 T,vec3 light_color,vec3 diffuse_color, vec3 specular_color, float specular_blob_intensity, float roughness, float rim,float rim_tint, float clearcoat, float clearcoat_gloss,float anisotropy,inout vec3 diffuse, inout vec3 specular) {
+
+ float dotNL = max(dot(N,L), 0.0 );
+ float dotNV = max(dot(N,V), 0.0 );
+
+#if defined(LIGHT_USE_RIM)
+ float rim_light = pow(1.0-dotNV,(1.0-roughness)*16.0);
+ diffuse += rim_light * rim * mix(vec3(1.0),diffuse_color,rim_tint) * light_color;
+#endif
+
+ diffuse += dotNL * light_color * diffuse_color;
+
+ if (roughness > 0.0) {
+
+ float alpha = roughness * roughness;
+
+ vec3 H = normalize(V + L);
+
+ float dotNH = max(dot(N,H), 0.0 );
+ float dotLH = max(dot(L,H), 0.0 );
+
+ // D
+#if defined(LIGHT_USE_ANISOTROPY)
+
+ float aspect = sqrt(1.0-anisotropy*0.9);
+ float rx = roughness/aspect;
+ float ry = roughness*aspect;
+ float ax = rx*rx;
+ float ay = ry*ry;
+ float dotXH = dot( T, H );
+ float dotYH = dot( B, H );
+ float pi = M_PI;
+ float denom = dotXH*dotXH / (ax*ax) + dotYH*dotYH / (ay*ay) + dotNH*dotNH;
+ float D = 1.0 / ( pi * ax*ay * denom*denom );
+
+#else
+ float alphaSqr = alpha * alpha;
+ float pi = M_PI;
+ float denom = dotNH * dotNH * (alphaSqr - 1.0) + 1.0;
+ float D = alphaSqr / (pi * denom * denom);
+#endif
+ // F
+ float F0 = 1.0;
+ float dotLH5 = SchlickFresnel( dotLH );
+ float F = F0 + (1.0 - F0) * (dotLH5);
+
+ // V
+ float k = alpha / 2.0f;
+ float vis = G1V(dotNL, k) * G1V(dotNV, k);
+
+ float speci = dotNL * D * F * vis;
+
+ specular += speci * light_color /* specular_color*/ * specular_blob_intensity;
+
+#if defined(LIGHT_USE_CLEARCOAT)
+ float Dr = GTR1(dotNH, mix(.1,.001,clearcoat_gloss));
+ float Fr = mix(.04, 1.0, dotLH5);
+ float Gr = G1V(dotNL, .25) * G1V(dotNV, .25);
+
+ specular += .25*clearcoat*Gr*Fr*Dr;
+#endif
+ }
+
+
+}
+
+
+float sample_shadow(highp sampler2DShadow shadow, vec2 shadow_pixel_size, vec2 pos, float depth, vec4 clamp_rect) {
+
+#ifdef SHADOW_MODE_PCF_13
+
+ float avg=textureProj(shadow,vec4(pos,depth,1.0));
+ avg+=textureProj(shadow,vec4(pos+vec2(shadow_pixel_size.x,0.0),depth,1.0));
+ avg+=textureProj(shadow,vec4(pos+vec2(-shadow_pixel_size.x,0.0),depth,1.0));
+ avg+=textureProj(shadow,vec4(pos+vec2(0.0,shadow_pixel_size.y),depth,1.0));
+ avg+=textureProj(shadow,vec4(pos+vec2(0.0,-shadow_pixel_size.y),depth,1.0));
+ avg+=textureProj(shadow,vec4(pos+vec2(shadow_pixel_size.x,shadow_pixel_size.y),depth,1.0));
+ avg+=textureProj(shadow,vec4(pos+vec2(-shadow_pixel_size.x,shadow_pixel_size.y),depth,1.0));
+ avg+=textureProj(shadow,vec4(pos+vec2(shadow_pixel_size.x,-shadow_pixel_size.y),depth,1.0));
+ avg+=textureProj(shadow,vec4(pos+vec2(-shadow_pixel_size.x,-shadow_pixel_size.y),depth,1.0));
+ avg+=textureProj(shadow,vec4(pos+vec2(shadow_pixel_size.x*2.0,0.0),depth,1.0));
+ avg+=textureProj(shadow,vec4(pos+vec2(-shadow_pixel_size.x*2.0,0.0),depth,1.0));
+ avg+=textureProj(shadow,vec4(pos+vec2(0.0,shadow_pixel_size.y*2.0),depth,1.0));
+ avg+=textureProj(shadow,vec4(pos+vec2(0.0,-shadow_pixel_size.y*2.0),depth,1.0));
+ return avg*(1.0/13.0);
+
+#endif
+
+#ifdef SHADOW_MODE_PCF_5
+
+ float avg=textureProj(shadow,vec4(pos,depth,1.0));
+ avg+=textureProj(shadow,vec4(pos+vec2(shadow_pixel_size.x,0.0),depth,1.0));
+ avg+=textureProj(shadow,vec4(pos+vec2(-shadow_pixel_size.x,0.0),depth,1.0));
+ avg+=textureProj(shadow,vec4(pos+vec2(0.0,shadow_pixel_size.y),depth,1.0));
+ avg+=textureProj(shadow,vec4(pos+vec2(0.0,-shadow_pixel_size.y),depth,1.0));
+ return avg*(1.0/5.0);
+#endif
+
+#if !defined(SHADOW_MODE_PCF_5) && !defined(SHADOW_MODE_PCF_13)
+
+ return textureProj(shadow,vec4(pos,depth,1.0));
+#endif
+
+}
+
+#ifdef RENDER_DEPTH_DUAL_PARABOLOID
+
+in highp float dp_clip;
+
+#endif
+
+#if 0
+//need to save texture depth for this
+
+vec3 light_transmittance(float translucency,vec3 light_vec, vec3 normal, vec3 pos, float distance) {
+
+ float scale = 8.25 * (1.0 - translucency) / subsurface_scatter_width;
+ float d = scale * distance;
+
+ /**
+ * Armed with the thickness, we can now calculate the color by means of the
+ * precalculated transmittance profile.
+ * (It can be precomputed into a texture, for maximum performance):
+ */
+ float dd = -d * d;
+ vec3 profile = vec3(0.233, 0.455, 0.649) * exp(dd / 0.0064) +
+ vec3(0.1, 0.336, 0.344) * exp(dd / 0.0484) +
+ vec3(0.118, 0.198, 0.0) * exp(dd / 0.187) +
+ vec3(0.113, 0.007, 0.007) * exp(dd / 0.567) +
+ vec3(0.358, 0.004, 0.0) * exp(dd / 1.99) +
+ vec3(0.078, 0.0, 0.0) * exp(dd / 7.41);
+
+ /**
+ * Using the profile, we finally approximate the transmitted lighting from
+ * the back of the object:
+ */
+ return profile * clamp(0.3 + dot(light_vec, normal),0.0,1.0);
+}
+#endif
+
+void light_process_omni(int idx, vec3 vertex, vec3 eye_vec,vec3 normal,vec3 binormal, vec3 tangent, vec3 albedo, vec3 specular, float roughness, float rim, float rim_tint, float clearcoat, float clearcoat_gloss,float anisotropy,inout vec3 diffuse_light, inout vec3 specular_light) {
+
+ vec3 light_rel_vec = omni_lights[idx].light_pos_inv_radius.xyz-vertex;
+ float light_length = length( light_rel_vec );
+ float normalized_distance = light_length*omni_lights[idx].light_pos_inv_radius.w;
+ vec3 light_attenuation = vec3(pow( max(1.0 - normalized_distance, 0.0), omni_lights[idx].light_direction_attenuation.w ));
+
+ if (omni_lights[idx].light_params.w>0.5) {
+ //there is a shadowmap
+
+ highp vec3 splane=(omni_lights[idx].shadow_matrix * vec4(vertex,1.0)).xyz;
+ float shadow_len=length(splane);
+ splane=normalize(splane);
+ vec4 clamp_rect=omni_lights[idx].light_clamp;
+
+ if (splane.z>=0.0) {
+
+ splane.z+=1.0;
+
+ clamp_rect.y+=clamp_rect.w;
+
+ } else {
+
+ splane.z=1.0 - splane.z;
+
+ /*
+ if (clamp_rect.z<clamp_rect.w) {
+ clamp_rect.x+=clamp_rect.z;
+ } else {
+ clamp_rect.y+=clamp_rect.w;
+ }
+ */
+
+ }
+
+ splane.xy/=splane.z;
+ splane.xy=splane.xy * 0.5 + 0.5;
+ splane.z = shadow_len * omni_lights[idx].light_pos_inv_radius.w;
+
+ splane.xy = clamp_rect.xy+splane.xy*clamp_rect.zw;
+ float shadow = sample_shadow(shadow_atlas,shadow_atlas_pixel_size,splane.xy,splane.z,clamp_rect);
+ if (shadow>0.01 && omni_lights[idx].shadow_color_contact.a>0.0) {
+
+ float contact_shadow = contact_shadow_compute(vertex,normalize(light_rel_vec),min(light_length,omni_lights[idx].shadow_color_contact.a));
+ shadow=min(shadow,contact_shadow);
+
+
+ }
+ light_attenuation*=mix(omni_lights[idx].shadow_color_contact.rgb,vec3(1.0),shadow);
+ }
+
+ light_compute(normal,normalize(light_rel_vec),eye_vec,binormal,tangent,omni_lights[idx].light_color_energy.rgb*light_attenuation,albedo,specular,omni_lights[idx].light_params.z,roughness,rim,rim_tint,clearcoat,clearcoat_gloss,anisotropy,diffuse_light,specular_light);
+
+}
+
+void light_process_spot(int idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 binormal, vec3 tangent,vec3 albedo, vec3 specular, float roughness, float rim,float rim_tint, float clearcoat, float clearcoat_gloss,float anisotropy, inout vec3 diffuse_light, inout vec3 specular_light) {
+
+ vec3 light_rel_vec = spot_lights[idx].light_pos_inv_radius.xyz-vertex;
+ float light_length = length( light_rel_vec );
+ float normalized_distance = light_length*spot_lights[idx].light_pos_inv_radius.w;
+ vec3 light_attenuation = vec3(pow( max(1.0 - normalized_distance, 0.0), spot_lights[idx].light_direction_attenuation.w ));
+ vec3 spot_dir = spot_lights[idx].light_direction_attenuation.xyz;
+ float spot_cutoff=spot_lights[idx].light_params.y;
+ float scos = max(dot(-normalize(light_rel_vec), spot_dir),spot_cutoff);
+ float spot_rim = (1.0 - scos) / (1.0 - spot_cutoff);
+ light_attenuation *= 1.0 - pow( spot_rim, spot_lights[idx].light_params.x);
+
+ if (spot_lights[idx].light_params.w>0.5) {
+ //there is a shadowmap
+ highp vec4 splane=(spot_lights[idx].shadow_matrix * vec4(vertex,1.0));
+ splane.xyz/=splane.w;
+
+ float shadow = sample_shadow(shadow_atlas,shadow_atlas_pixel_size,splane.xy,splane.z,spot_lights[idx].light_clamp);
+
+ if (shadow>0.01 && spot_lights[idx].shadow_color_contact.a>0.0) {
+
+ float contact_shadow = contact_shadow_compute(vertex,normalize(light_rel_vec),min(light_length,spot_lights[idx].shadow_color_contact.a));
+ shadow=min(shadow,contact_shadow);
+
+ }
+
+ light_attenuation*=mix(spot_lights[idx].shadow_color_contact.rgb,vec3(1.0),shadow);
+ }
+
+ light_compute(normal,normalize(light_rel_vec),eye_vec,binormal,tangent,spot_lights[idx].light_color_energy.rgb*light_attenuation,albedo,specular,spot_lights[idx].light_params.z,roughness,rim,rim_tint,clearcoat,clearcoat_gloss,anisotropy,diffuse_light,specular_light);
+
+}
+
+void reflection_process(int idx, vec3 vertex, vec3 normal,vec3 binormal, vec3 tangent,float roughness,float anisotropy,vec3 ambient,vec3 skybox,vec2 brdf, inout highp vec4 reflection_accum,inout highp vec4 ambient_accum) {
+
+ vec3 ref_vec = normalize(reflect(vertex,normal));
+ vec3 local_pos = (reflections[idx].local_matrix * vec4(vertex,1.0)).xyz;
+ vec3 box_extents = reflections[idx].box_extents.xyz;
+
+ if (any(greaterThan(abs(local_pos),box_extents))) { //out of the reflection box
+ return;
+ }
+
+ vec3 inner_pos = abs(local_pos / box_extents);
+ float blend = max(inner_pos.x,max(inner_pos.y,inner_pos.z));
+ //make blend more rounded
+ blend=mix(length(inner_pos),blend,blend);
+ blend*=blend;
+ blend=1.001-blend;
+
+ if (reflections[idx].params.x>0.0){// compute reflection
+
+ vec3 local_ref_vec = (reflections[idx].local_matrix * vec4(ref_vec,0.0)).xyz;
+
+ if (reflections[idx].params.w > 0.5) { //box project
+
+ vec3 nrdir = normalize(local_ref_vec);
+ vec3 rbmax = (box_extents - local_pos)/nrdir;
+ vec3 rbmin = (-box_extents - local_pos)/nrdir;
+
+
+ vec3 rbminmax = mix(rbmin,rbmax,greaterThan(nrdir,vec3(0.0,0.0,0.0)));
+
+ float fa = min(min(rbminmax.x, rbminmax.y), rbminmax.z);
+ vec3 posonbox = local_pos + nrdir * fa;
+ local_ref_vec = posonbox - reflections[idx].box_offset.xyz;
+ }
+
+
+
+ vec3 splane=normalize(local_ref_vec);
+ vec4 clamp_rect=reflections[idx].atlas_clamp;
+
+ splane.z*=-1.0;
+ if (splane.z>=0.0) {
+ splane.z+=1.0;
+ clamp_rect.y+=clamp_rect.w;
+ } else {
+ splane.z=1.0 - splane.z;
+ splane.y=-splane.y;
+ }
+
+ splane.xy/=splane.z;
+ splane.xy=splane.xy * 0.5 + 0.5;
+
+ splane.xy = splane.xy * clamp_rect.zw + clamp_rect.xy;
+ splane.xy = clamp(splane.xy,clamp_rect.xy,clamp_rect.xy+clamp_rect.zw);
+
+ highp vec4 reflection;
+ reflection.rgb = textureLod(reflection_atlas,splane.xy,roughness*5.0).rgb * brdf.x + brdf.y;
+
+ if (reflections[idx].params.z < 0.5) {
+ reflection.rgb = mix(skybox,reflection.rgb,blend);
+ }
+ reflection.rgb*=reflections[idx].params.x;
+ reflection.a = blend;
+ reflection.rgb*=reflection.a;
+
+ reflection_accum+=reflection;
+ }
+
+ if (reflections[idx].ambient.a>0.0) { //compute ambient using skybox
+
+
+ vec3 local_amb_vec = (reflections[idx].local_matrix * vec4(normal,0.0)).xyz;
+
+ vec3 splane=normalize(local_amb_vec);
+ vec4 clamp_rect=reflections[idx].atlas_clamp;
+
+ splane.z*=-1.0;
+ if (splane.z>=0.0) {
+ splane.z+=1.0;
+ clamp_rect.y+=clamp_rect.w;
+ } else {
+ splane.z=1.0 - splane.z;
+ splane.y=-splane.y;
+ }
+
+ splane.xy/=splane.z;
+ splane.xy=splane.xy * 0.5 + 0.5;
+
+ splane.xy = splane.xy * clamp_rect.zw + clamp_rect.xy;
+ splane.xy = clamp(splane.xy,clamp_rect.xy,clamp_rect.xy+clamp_rect.zw);
+
+ highp vec4 ambient_out;
+ ambient_out.a=blend;
+ ambient_out.rgb = textureLod(reflection_atlas,splane.xy,5.0).rgb;
+ ambient_out.rgb=mix(reflections[idx].ambient.rgb,ambient_out.rgb,reflections[idx].ambient.a);
+ if (reflections[idx].params.z < 0.5) {
+ ambient_out.rgb = mix(ambient,ambient_out.rgb,blend);
+ }
+
+ ambient_out.rgb *= ambient_out.a;
+ ambient_accum+=ambient_out;
+ } else {
+
+ highp vec4 ambient_out;
+ ambient_out.a=blend;
+ ambient_out.rgb=reflections[idx].ambient.rgb;
+ if (reflections[idx].params.z < 0.5) {
+ ambient_out.rgb = mix(ambient,ambient_out.rgb,blend);
+ }
+ ambient_out.rgb *= ambient_out.a;
+ ambient_accum+=ambient_out;
+
+ }
+}
+
+#ifdef USE_GI_PROBES
+
+uniform mediump sampler3D gi_probe1; //texunit:-11
+uniform highp mat4 gi_probe_xform1;
+uniform highp vec3 gi_probe_bounds1;
+uniform highp vec3 gi_probe_cell_size1;
+uniform highp float gi_probe_multiplier1;
+uniform highp float gi_probe_bias1;
+uniform bool gi_probe_blend_ambient1;
+
+uniform mediump sampler3D gi_probe2; //texunit:-10
+uniform highp mat4 gi_probe_xform2;
+uniform highp vec3 gi_probe_bounds2;
+uniform highp vec3 gi_probe_cell_size2;
+uniform highp float gi_probe_multiplier2;
+uniform highp float gi_probe_bias2;
+uniform bool gi_probe2_enabled;
+uniform bool gi_probe_blend_ambient2;
+
+vec3 voxel_cone_trace(sampler3D probe, vec3 cell_size, vec3 pos, vec3 ambient, bool blend_ambient, vec3 direction, float tan_half_angle, float max_distance, float p_bias) {
+
+
+ float dist = p_bias;//1.0; //dot(direction,mix(vec3(-1.0),vec3(1.0),greaterThan(direction,vec3(0.0))))*2.0;
+ float alpha=0.0;
+ vec3 color = vec3(0.0);
+
+ while(dist < max_distance && alpha < 0.95) {
+ float diameter = max(1.0, 2.0 * tan_half_angle * dist);
+ vec4 scolor = textureLod(probe, (pos + dist * direction) * cell_size, log2(diameter) );
+ float a = (1.0 - alpha);
+ color += scolor.rgb * a;
+ alpha += a * scolor.a;
+ dist += diameter * 0.5;
+ }
+
+ if (blend_ambient) {
+ color.rgb = mix(ambient,color.rgb,min(1.0,alpha/0.95));
+ }
+
+ return color;
+}
+
+void gi_probe_compute(sampler3D probe, mat4 probe_xform, vec3 bounds,vec3 cell_size,vec3 pos, vec3 ambient, vec3 environment, bool blend_ambient,float multiplier, mat3 normal_mtx,vec3 ref_vec, float roughness,float p_bias, out vec4 out_spec, out vec4 out_diff) {
+
+
+
+ vec3 probe_pos = (probe_xform * vec4(pos,1.0)).xyz;
+ vec3 ref_pos = (probe_xform * vec4(pos+ref_vec,1.0)).xyz;
+
+ ref_vec = normalize(ref_pos - probe_pos);
+
+/* out_diff.rgb = voxel_cone_trace(probe,cell_size,probe_pos,normalize((probe_xform * vec4(ref_vec,0.0)).xyz),0.0 ,100.0);
+ out_diff.a = 1.0;
+ return;*/
+ //out_diff = vec4(textureLod(probe,probe_pos*cell_size,3.0).rgb,1.0);
+ //return;
+
+ if (any(bvec2(any(lessThan(probe_pos,vec3(0.0))),any(greaterThan(probe_pos,bounds)))))
+ return;
+
+ vec3 blendv = probe_pos/bounds * 2.0 - 1.0;
+ float blend = 1.001-max(blendv.x,max(blendv.y,blendv.z));
+ blend=1.0;
+
+ float max_distance = length(bounds);
+
+ //radiance
+#ifdef VCT_QUALITY_HIGH
+
+#define MAX_CONE_DIRS 6
+ vec3 cone_dirs[MAX_CONE_DIRS] = vec3[] (
+ vec3(0, 0, 1),
+ vec3(0.866025, 0, 0.5),
+ vec3(0.267617, 0.823639, 0.5),
+ vec3(-0.700629, 0.509037, 0.5),
+ vec3(-0.700629, -0.509037, 0.5),
+ vec3(0.267617, -0.823639, 0.5)
+ );
+
+ float cone_weights[MAX_CONE_DIRS] = float[](0.25, 0.15, 0.15, 0.15, 0.15, 0.15);
+ float cone_angle_tan = 0.577;
+ float min_ref_tan = 0.0;
+#else
+
+#define MAX_CONE_DIRS 4
+
+ vec3 cone_dirs[MAX_CONE_DIRS] = vec3[] (
+ vec3(0.707107, 0, 0.707107),
+ vec3(0, 0.707107, 0.707107),
+ vec3(-0.707107, 0, 0.707107),
+ vec3(0, -0.707107, 0.707107)
+ );
+
+ float cone_weights[MAX_CONE_DIRS] = float[](0.25, 0.25, 0.25, 0.25);
+ float cone_angle_tan = 0.98269;
+ max_distance*=0.5;
+ float min_ref_tan = 0.2;
+
+#endif
+ vec3 light=vec3(0.0);
+ for(int i=0;i<MAX_CONE_DIRS;i++) {
+
+ vec3 dir = normalize( (probe_xform * vec4(pos + normal_mtx * cone_dirs[i],1.0)).xyz - probe_pos);
+ light+=cone_weights[i] * voxel_cone_trace(probe,cell_size,probe_pos,ambient,blend_ambient,dir,cone_angle_tan,max_distance,p_bias);
+
+ }
+
+ light*=multiplier;
+
+ out_diff = vec4(light*blend,blend);
+
+ //irradiance
+
+ vec3 irr_light = voxel_cone_trace(probe,cell_size,probe_pos,environment,blend_ambient,ref_vec,max(min_ref_tan,tan(roughness * 0.5 * M_PI)) ,max_distance,p_bias);
+
+ irr_light *= multiplier;
+ //irr_light=vec3(0.0);
+
+ out_spec = vec4(irr_light*blend,blend);
+}
+
+
+void gi_probes_compute(vec3 pos, vec3 normal, float roughness, vec3 specular, inout vec3 out_specular, inout vec3 out_ambient) {
+
+ roughness = roughness * roughness;
+
+ vec3 ref_vec = normalize(reflect(normalize(pos),normal));
+
+ //find arbitrary tangent and bitangent, then build a matrix
+ vec3 v0 = abs(normal.z) < 0.999 ? vec3(0, 0, 1) : vec3(0, 1, 0);
+ vec3 tangent = normalize(cross(v0, normal));
+ vec3 bitangent = normalize(cross(tangent, normal));
+ mat3 normal_mat = mat3(tangent,bitangent,normal);
+
+ vec4 diff_accum = vec4(0.0);
+ vec4 spec_accum = vec4(0.0);
+
+ vec3 ambient = out_ambient;
+ out_ambient = vec3(0.0);
+
+ vec3 environment = out_specular;
+
+ out_specular = vec3(0.0);
+
+ gi_probe_compute(gi_probe1,gi_probe_xform1,gi_probe_bounds1,gi_probe_cell_size1,pos,ambient,environment,gi_probe_blend_ambient1,gi_probe_multiplier1,normal_mat,ref_vec,roughness,gi_probe_bias1,spec_accum,diff_accum);
+
+ if (gi_probe2_enabled) {
+
+ gi_probe_compute(gi_probe2,gi_probe_xform2,gi_probe_bounds2,gi_probe_cell_size2,pos,ambient,environment,gi_probe_blend_ambient2,gi_probe_multiplier2,normal_mat,ref_vec,roughness,gi_probe_bias2,spec_accum,diff_accum);
+ }
+
+ if (diff_accum.a>0.0) {
+ diff_accum.rgb/=diff_accum.a;
+ }
+
+ if (spec_accum.a>0.0) {
+ spec_accum.rgb/=spec_accum.a;
+ }
+
+ out_specular+=spec_accum.rgb;
+ out_ambient+=diff_accum.rgb;
+
+}
+
+#endif
+
+
+void main() {
+
+#ifdef RENDER_DEPTH_DUAL_PARABOLOID
+
+ if (dp_clip>0.0)
+ discard;
+#endif
+
+ //lay out everything, whathever is unused is optimized away anyway
+ highp vec3 vertex = vertex_interp;
+ vec3 albedo = vec3(0.8,0.8,0.8);
+ vec3 specular = vec3(0.2,0.2,0.2);
+ vec3 emission = vec3(0.0,0.0,0.0);
+ float roughness = 1.0;
+ float rim = 0.0;
+ float rim_tint = 0.0;
+ float clearcoat=0.0;
+ float clearcoat_gloss=0.0;
+ float anisotropy = 1.0;
+ vec2 anisotropy_flow = vec2(1.0,0.0);
+
+#if defined(ENABLE_AO)
+ float ao=1.0;
+#endif
+
+ float alpha = 1.0;
+
+#ifdef METERIAL_DOUBLESIDED
+ float side=float(gl_FrontFacing)*2.0-1.0;
+#else
+ float side=1.0;
+#endif
+
+
+#if defined(ENABLE_TANGENT_INTERP) || defined(ENABLE_NORMALMAP) || defined(LIGHT_USE_ANISOTROPY)
+ vec3 binormal = normalize(binormal_interp)*side;
+ vec3 tangent = normalize(tangent_interp)*side;
+#else
+ vec3 binormal = vec3(0.0);
+ vec3 tangent = vec3(0.0);
+#endif
+ vec3 normal = normalize(normal_interp)*side;
+
+#if defined(ENABLE_UV_INTERP)
+ vec2 uv = uv_interp;
+#endif
+
+#if defined(ENABLE_UV2_INTERP)
+ vec2 uv2 = uv2_interp;
+#endif
+
+#if defined(ENABLE_COLOR_INTERP)
+ vec4 color = color_interp;
+#endif
+
+#if defined(ENABLE_NORMALMAP)
+
+ vec3 normalmap = vec3(0.0);
+#endif
+
+ float normaldepth=1.0;
+
+
+
+#if defined(ENABLE_DISCARD)
+ bool discard_=false;
+#endif
+
+#if defined (ENABLE_SSS_MOTION)
+ float sss_strength=0.0;
+#endif
+
+{
+
+
+FRAGMENT_SHADER_CODE
+
+}
+
+
+
+#if defined(ENABLE_NORMALMAP)
+
+ normalmap.xy=normalmap.xy*2.0-1.0;
+ normalmap.z=sqrt(1.0-dot(normalmap.xy,normalmap.xy)); //always ignore Z, as it can be RG packed, Z may be pos/neg, etc.
+
+ normal = normalize( mix(normal_interp,tangent * normalmap.x + binormal * normalmap.y + normal * normalmap.z,normaldepth) ) * side;
+
+#endif
+
+#if defined(LIGHT_USE_ANISOTROPY)
+
+ if (anisotropy>0.01) {
+ //rotation matrix
+ mat3 rot = mat3( tangent, binormal, normal );
+ //make local to space
+ tangent = normalize(rot * vec3(anisotropy_flow.x,anisotropy_flow.y,0.0));
+ binormal = normalize(rot * vec3(-anisotropy_flow.y,anisotropy_flow.x,0.0));
+ }
+
+#endif
+
+#if defined(ENABLE_DISCARD)
+ if (discard_) {
+ //easy to eliminate dead code
+ discard;
+ }
+#endif
+
+#ifdef ENABLE_CLIP_ALPHA
+ if (albedo.a<0.99) {
+ //used for doublepass and shadowmapping
+ discard;
+ }
+#endif
+
+/////////////////////// LIGHTING //////////////////////////////
+
+ //apply energy conservation
+
+ vec3 specular_light = vec3(0.0,0.0,0.0);
+ vec3 ambient_light;
+ vec3 diffuse_light = vec3(0.0,0.0,0.0);
+
+ vec3 eye_vec = -normalize( vertex_interp );
+
+#ifndef RENDER_DEPTH
+ float ndotv = clamp(dot(normal,eye_vec),0.0,1.0);
+
+ vec2 brdf = texture(brdf_texture, vec2(roughness, ndotv)).xy;
+#endif
+
+#ifdef USE_RADIANCE_MAP
+
+ if (no_ambient_light) {
+ ambient_light=vec3(0.0,0.0,0.0);
+ } else {
+ {
+
+
+
+ float lod = roughness * 5.0;
+
+ { //read radiance from dual paraboloid
+
+ vec3 ref_vec = reflect(-eye_vec,normal); //2.0 * ndotv * normal - view; // reflect(v, n);
+ ref_vec=normalize((radiance_inverse_xform * vec4(ref_vec,0.0)).xyz);
+
+ vec3 norm = normalize(ref_vec);
+ float y_ofs=0.0;
+ if (norm.z>=0.0) {
+
+ norm.z+=1.0;
+ y_ofs+=0.5;
+ } else {
+ norm.z=1.0 - norm.z;
+ norm.y=-norm.y;
+ }
+
+ norm.xy/=norm.z;
+ norm.xy=norm.xy * vec2(0.5,0.25) + vec2(0.5,0.25+y_ofs);
+ specular_light = textureLod(radiance_map, norm.xy, lod).xyz * brdf.x + brdf.y;
+
+ }
+ //no longer a cubemap
+ //vec3 radiance = textureLod(radiance_cube, r, lod).xyz * ( brdf.x + brdf.y);
+
+ }
+
+ {
+
+ /*vec3 ambient_dir=normalize((radiance_inverse_xform * vec4(normal,0.0)).xyz);
+ vec3 env_ambient=textureLod(radiance_cube, ambient_dir, 5.0).xyz;
+
+ ambient_light=mix(ambient_light_color.rgb,env_ambient,radiance_ambient_contribution);*/
+ ambient_light=vec3(0.0,0.0,0.0);
+ }
+ }
+
+#else
+
+ if (no_ambient_light){
+ ambient_light=vec3(0.0,0.0,0.0);
+ } else {
+ ambient_light=ambient_light_color.rgb;
+ }
+#endif
+
+
+#ifdef USE_LIGHT_DIRECTIONAL
+
+ vec3 light_attenuation=vec3(1.0);
+
+#ifdef LIGHT_DIRECTIONAL_SHADOW
+
+ if (gl_FragCoord.w > shadow_split_offsets.w) {
+
+ vec3 pssm_coord;
+
+#ifdef LIGHT_USE_PSSM_BLEND
+ float pssm_blend;
+ vec3 pssm_coord2;
+ bool use_blend=true;
+ vec3 light_pssm_split_inv = 1.0/shadow_split_offsets.xyz;
+ float w_inv = 1.0/gl_FragCoord.w;
+#endif
+
+
+#ifdef LIGHT_USE_PSSM4
+
+
+ if (gl_FragCoord.w > shadow_split_offsets.y) {
+
+ if (gl_FragCoord.w > shadow_split_offsets.x) {
+
+ highp vec4 splane=(shadow_matrix1 * vec4(vertex,1.0));
+ pssm_coord=splane.xyz/splane.w;
+
+
+#if defined(LIGHT_USE_PSSM_BLEND)
+
+ splane=(shadow_matrix2 * vec4(vertex,1.0));
+ pssm_coord2=splane.xyz/splane.w;
+ pssm_blend=smoothstep(0.0,light_pssm_split_inv.x,w_inv);
+#endif
+
+ } else {
+
+ highp vec4 splane=(shadow_matrix2 * vec4(vertex,1.0));
+ pssm_coord=splane.xyz/splane.w;
+
+#if defined(LIGHT_USE_PSSM_BLEND)
+ splane=(shadow_matrix3 * vec4(vertex,1.0));
+ pssm_coord2=splane.xyz/splane.w;
+ pssm_blend=smoothstep(light_pssm_split_inv.x,light_pssm_split_inv.y,w_inv);
+#endif
+
+ }
+ } else {
+
+
+ if (gl_FragCoord.w > shadow_split_offsets.z) {
+
+ highp vec4 splane=(shadow_matrix3 * vec4(vertex,1.0));
+ pssm_coord=splane.xyz/splane.w;
+
+#if defined(LIGHT_USE_PSSM_BLEND)
+ splane=(shadow_matrix4 * vec4(vertex,1.0));
+ pssm_coord2=splane.xyz/splane.w;
+ pssm_blend=smoothstep(light_pssm_split_inv.y,light_pssm_split_inv.z,w_inv);
+#endif
+
+ } else {
+ highp vec4 splane=(shadow_matrix4 * vec4(vertex,1.0));
+ pssm_coord=splane.xyz/splane.w;
+
+#if defined(LIGHT_USE_PSSM_BLEND)
+ use_blend=false;
+
+#endif
+
+ }
+ }
+
+
+
+#endif //LIGHT_USE_PSSM4
+
+#ifdef LIGHT_USE_PSSM2
+
+ if (gl_FragCoord.w > shadow_split_offsets.x) {
+
+ highp vec4 splane=(shadow_matrix1 * vec4(vertex,1.0));
+ pssm_coord=splane.xyz/splane.w;
+
+
+#if defined(LIGHT_USE_PSSM_BLEND)
+
+ splane=(shadow_matrix2 * vec4(vertex,1.0));
+ pssm_coord2=splane.xyz/splane.w;
+ pssm_blend=smoothstep(0.0,light_pssm_split_inv.x,w_inv);
+#endif
+
+ } else {
+ highp vec4 splane=(shadow_matrix2 * vec4(vertex,1.0));
+ pssm_coord=splane.xyz/splane.w;
+#if defined(LIGHT_USE_PSSM_BLEND)
+ use_blend=false;
+
+#endif
+
+ }
+
+#endif //LIGHT_USE_PSSM2
+
+#if !defined(LIGHT_USE_PSSM4) && !defined(LIGHT_USE_PSSM2)
+ { //regular orthogonal
+ highp vec4 splane=(shadow_matrix1 * vec4(vertex,1.0));
+ pssm_coord=splane.xyz/splane.w;
+ }
+#endif
+
+
+ //one one sample
+
+ float shadow = sample_shadow(directional_shadow,directional_shadow_pixel_size,pssm_coord.xy,pssm_coord.z,light_clamp);
+
+#if defined(LIGHT_USE_PSSM_BLEND)
+
+ if (use_blend) {
+ shadow=mix(shadow, sample_shadow(directional_shadow,directional_shadow_pixel_size,pssm_coord2.xy,pssm_coord2.z,light_clamp));
+ }
+#endif
+
+ if (shadow>0.01 && shadow_color_contact.a>0.0) {
+
+ float contact_shadow = contact_shadow_compute(vertex,-light_direction_attenuation.xyz,shadow_color_contact.a);
+ shadow=min(shadow,contact_shadow);
+
+ }
+
+ light_attenuation=mix(shadow_color_contact.rgb,vec3(1.0),shadow);
+
+
+ }
+
+#endif //LIGHT_DIRECTIONAL_SHADOW
+
+ light_compute(normal,-light_direction_attenuation.xyz,eye_vec,binormal,tangent,light_color_energy.rgb*light_attenuation,albedo,specular,light_params.z,roughness,rim,rim_tint,clearcoat,clearcoat_gloss,anisotropy,diffuse_light,specular_light);
+
+
+#endif //#USE_LIGHT_DIRECTIONAL
+
+#ifdef USE_GI_PROBES
+ gi_probes_compute(vertex,normal,roughness,specular,specular_light,ambient_light);
+#endif
+
+
+#ifdef USE_FORWARD_LIGHTING
+
+ highp vec4 reflection_accum = vec4(0.0,0.0,0.0,0.0);
+ highp vec4 ambient_accum = vec4(0.0,0.0,0.0,0.0);
+
+
+
+ for(int i=0;i<reflection_count;i++) {
+ reflection_process(reflection_indices[i],vertex,normal,binormal,tangent,roughness,anisotropy,ambient_light,specular_light,brdf,reflection_accum,ambient_accum);
+ }
+
+ if (reflection_accum.a>0.0) {
+ specular_light+=reflection_accum.rgb/reflection_accum.a;
+ }
+ if (ambient_accum.a>0.0) {
+ ambient_light+=ambient_accum.rgb/ambient_accum.a;
+ }
+
+ for(int i=0;i<omni_light_count;i++) {
+ light_process_omni(omni_light_indices[i],vertex,eye_vec,normal,binormal,tangent,albedo,specular,roughness,rim,rim_tint,clearcoat,clearcoat_gloss,anisotropy,diffuse_light,specular_light);
+ }
+
+ for(int i=0;i<spot_light_count;i++) {
+ light_process_spot(spot_light_indices[i],vertex,eye_vec,normal,binormal,tangent,albedo,specular,roughness,rim,rim_tint,clearcoat,clearcoat_gloss,anisotropy,diffuse_light,specular_light);
+ }
+
+
+
+#endif
+
+
+
+
+#if defined(USE_LIGHT_SHADER_CODE)
+//light is written by the light shader
+{
+
+LIGHT_SHADER_CODE
+
+}
+#endif
+
+#ifdef RENDER_DEPTH
+//nothing happens, so a tree-ssa optimizer will result in no fragment shader :)
+#else
+
+ specular_light*=reflection_multiplier;
+ ambient_light*=albedo; //ambient must be multiplied by albedo at the end
+
+#if defined(ENABLE_AO)
+ ambient_light*=ao;
+#endif
+
+ //energy conservation
+ diffuse_light=mix(diffuse_light,vec3(0.0),specular);
+ ambient_light=mix(ambient_light,vec3(0.0),specular);
+ specular_light *= max(vec3(0.04),specular);
+
+#ifdef USE_MULTIPLE_RENDER_TARGETS
+
+#if defined(ENABLE_AO)
+
+ float ambient_scale=0.0; // AO is supplied by material
+#else
+ //approximate ambient scale for SSAO, since we will lack full ambient
+ float max_emission=max(emission.r,max(emission.g,emission.b));
+ float max_ambient=max(ambient_light.r,max(ambient_light.g,ambient_light.b));
+ float max_diffuse=max(diffuse_light.r,max(diffuse_light.g,diffuse_light.b));
+ float total_ambient = max_ambient+max_diffuse+max_emission;
+ float ambient_scale = (total_ambient>0.0) ? (max_ambient+ambient_occlusion_affect_light*max_diffuse)/total_ambient : 0.0;
+#endif //ENABLE_AO
+
+ diffuse_buffer=vec4(emission+diffuse_light+ambient_light,ambient_scale);
+ specular_buffer=vec4(specular_light,max(specular.r,max(specular.g,specular.b)));
+
+
+ normal_mr_buffer=vec4(normalize(normal)*0.5+0.5,roughness);
+
+#if defined (ENABLE_SSS_MOTION)
+ motion_ssr_buffer = vec4(vec3(0.0),sss_strength);
+#endif
+
+#else
+
+
+#ifdef SHADELESS
+ frag_color=vec4(albedo,alpha);
+#else
+ frag_color=vec4(emission+ambient_light+diffuse_light+specular_light,alpha);
+#endif //SHADELESS
+
+
+#endif //USE_MULTIPLE_RENDER_TARGETS
+
+
+
+#endif //RENDER_DEPTH
+
+
+}
+
+
+
+
+
+
+layout(location=0) in highp vec4 vertex_attrib;
+layout(location=4) in vec2 uv_in;
+
+out vec2 uv_interp;
+
+void main() {
+
+ uv_interp = uv_in;
+ gl_Position = vertex_attrib;
+}
+
+
+
+uniform highp samplerCube source_cube; //texunit:0
+in vec2 uv_interp;
+
+uniform bool z_flip;
+uniform highp float z_far;
+uniform highp float z_near;
+uniform highp float bias;
+
+void main() {
+
+ highp vec3 normal = vec3( uv_interp * 2.0 - 1.0, 0.0 );
+/*
+ if(z_flip) {
+ normal.z = 0.5 - 0.5*((normal.x * normal.x) + (normal.y * normal.y));
+ } else {
+ normal.z = -0.5 + 0.5*((normal.x * normal.x) + (normal.y * normal.y));
+ }
+*/
+
+ //normal.z = sqrt(1.0-dot(normal.xy,normal.xy));
+ //normal.xy*=1.0+normal.z;
+
+ normal.z = 0.5 - 0.5*((normal.x * normal.x) + (normal.y * normal.y));
+ normal = normalize(normal);
+
+/*
+ normal.z=0.5;
+ normal=normalize(normal);
+*/
+ if (!z_flip) {
+ normal.z=-normal.z;
+ }
+
+ //normal = normalize(vec3( uv_interp * 2.0 - 1.0, 1.0 ));
+ float depth = texture(source_cube,normal).r;
+
+ // absolute values for direction cosines, bigger value equals closer to basis axis
+ vec3 unorm = abs(normal);
+
+ if ( (unorm.x >= unorm.y) && (unorm.x >= unorm.z) ) {
+ // x code
+ unorm = normal.x > 0.0 ? vec3( 1.0, 0.0, 0.0 ) : vec3( -1.0, 0.0, 0.0 ) ;
+ } else if ( (unorm.y > unorm.x) && (unorm.y >= unorm.z) ) {
+ // y code
+ unorm = normal.y > 0.0 ? vec3( 0.0, 1.0, 0.0 ) : vec3( 0.0, -1.0, 0.0 ) ;
+ } else if ( (unorm.z > unorm.x) && (unorm.z > unorm.y) ) {
+ // z code
+ unorm = normal.z > 0.0 ? vec3( 0.0, 0.0, 1.0 ) : vec3( 0.0, 0.0, -1.0 ) ;
+ } else {
+ // oh-no we messed up code
+ // has to be
+ unorm = vec3( 1.0, 0.0, 0.0 );
+ }
+
+ float depth_fix = 1.0 / dot(normal,unorm);
+
+
+ depth = 2.0 * depth - 1.0;
+ float linear_depth = 2.0 * z_near * z_far / (z_far + z_near - depth * (z_far - z_near));
+ gl_FragDepth = (linear_depth*depth_fix+bias) / z_far;
+}
+
+
+
+layout(location=0) in highp vec4 vertex_attrib;
+layout(location=4) in vec2 uv_in;
+
+out vec2 uv_interp;
+
+
+void main() {
+
+ uv_interp = uv_in;
+ gl_Position = vertex_attrib;
+}
+
+
+
+in vec2 uv_interp;
+uniform sampler2D source_specular; //texunit:0
+uniform sampler2D source_ssr; //texunit:1
+
+uniform float stuff;
+
+in vec2 uv2_interp;
+
+layout(location = 0) out vec4 frag_color;
+
+void main() {
+
+ vec4 specular = texture( source_specular, uv_interp );
+
+#ifdef USE_SSR
+
+ vec4 ssr = textureLod(source_ssr,uv_interp,0.0);
+ specular.rgb = mix(specular.rgb,ssr.rgb*specular.a,ssr.a);
+#endif
+
+ frag_color = vec4(specular.rgb,1.0);
+}
+
+
+
+layout(location=0) in highp vec4 vertex_attrib;
+layout(location=4) in vec2 uv_in;
+
+out vec2 uv_interp;
+out vec2 pos_interp;
+
+void main() {
+
+ uv_interp = uv_in;
+ gl_Position = vertex_attrib;
+ pos_interp.xy=gl_Position.xy;
+}
+
+
+
+in vec2 uv_interp;
+in vec2 pos_interp;
+
+uniform sampler2D source_diffuse; //texunit:0
+uniform sampler2D source_normal_roughness; //texunit:1
+uniform sampler2D source_depth; //texunit:2
+
+uniform float camera_z_near;
+uniform float camera_z_far;
+
+uniform vec2 viewport_size;
+uniform vec2 pixel_size;
+
+uniform float filter_mipmap_levels;
+
+uniform mat4 inverse_projection;
+uniform mat4 projection;
+
+uniform int num_steps;
+uniform float depth_tolerance;
+uniform float distance_fade;
+uniform float acceleration;
+
+layout(location = 0) out vec4 frag_color;
+
+
+vec2 view_to_screen(vec3 view_pos,out float w) {
+ vec4 projected = projection * vec4(view_pos, 1.0);
+ projected.xyz /= projected.w;
+ projected.xy = projected.xy * 0.5 + 0.5;
+ w=projected.w;
+ return projected.xy;
+}
+
+
+
+#define M_PI 3.14159265359
+
+
+void main() {
+
+
+ ////
+
+ vec4 diffuse = texture( source_diffuse, uv_interp );
+ vec4 normal_roughness = texture( source_normal_roughness, uv_interp);
+
+ vec3 normal;
+
+ normal = normal_roughness.xyz*2.0-1.0;
+
+ float roughness = normal_roughness.w;
+
+ float depth_tex = texture(source_depth,uv_interp).r;
+
+ vec4 world_pos = inverse_projection * vec4( uv_interp*2.0-1.0, depth_tex*2.0-1.0, 1.0 );
+ vec3 vertex = world_pos.xyz/world_pos.w;
+
+ vec3 view_dir = normalize(vertex);
+ vec3 ray_dir = normalize(reflect(view_dir, normal));
+
+ if (dot(ray_dir,normal)<0.001) {
+ frag_color=vec4(0.0);
+ return;
+ }
+ //ray_dir = normalize(view_dir - normal * dot(normal,view_dir) * 2.0);
+
+ //ray_dir = normalize(vec3(1,1,-1));
+
+
+ ////////////////
+
+
+ //make ray length and clip it against the near plane (don't want to trace beyond visible)
+ float ray_len = (vertex.z + ray_dir.z * camera_z_far) > -camera_z_near ? (-camera_z_near - vertex.z) / ray_dir.z : camera_z_far;
+ vec3 ray_end = vertex + ray_dir*ray_len;
+
+ float w_begin;
+ vec2 vp_line_begin = view_to_screen(vertex,w_begin);
+ float w_end;
+ vec2 vp_line_end = view_to_screen( ray_end, w_end);
+ vec2 vp_line_dir = vp_line_end-vp_line_begin;
+
+ //we need to interpolate w along the ray, to generate perspective correct reflections
+
+ w_begin = 1.0/w_begin;
+ w_end = 1.0/w_end;
+
+
+ float z_begin = vertex.z*w_begin;
+ float z_end = ray_end.z*w_end;
+
+ vec2 line_begin = vp_line_begin/pixel_size;
+ vec2 line_dir = vp_line_dir/pixel_size;
+ float z_dir = z_end - z_begin;
+ float w_dir = w_end - w_begin;
+
+
+ // clip the line to the viewport edges
+
+ float scale_max_x = min(1.0, 0.99 * (1.0 - vp_line_begin.x) / max(1e-5, vp_line_dir.x));
+ float scale_max_y = min(1.0, 0.99 * (1.0 - vp_line_begin.y) / max(1e-5, vp_line_dir.y));
+ float scale_min_x = min(1.0, 0.99 * vp_line_begin.x / max(1e-5, -vp_line_dir.x));
+ float scale_min_y = min(1.0, 0.99 * vp_line_begin.y / max(1e-5, -vp_line_dir.y));
+ float line_clip = min(scale_max_x, scale_max_y) * min(scale_min_x, scale_min_y);
+ line_dir *= line_clip;
+ z_dir *= line_clip;
+ w_dir *=line_clip;
+
+ //clip z and w advance to line advance
+ vec2 line_advance = normalize(line_dir); //down to pixel
+ float step_size = length(line_advance)/length(line_dir);
+ float z_advance = z_dir*step_size; // adapt z advance to line advance
+ float w_advance = w_dir*step_size; // adapt w advance to line advance
+
+ //make line advance faster if direction is closer to pixel edges (this avoids sampling the same pixel twice)
+ float advance_angle_adj = 1.0/max(abs(line_advance.x),abs(line_advance.y));
+ line_advance*=advance_angle_adj; // adapt z advance to line advance
+ z_advance*=advance_angle_adj;
+ w_advance*=advance_angle_adj;
+
+ vec2 pos = line_begin;
+ float z = z_begin;
+ float w = w_begin;
+ float z_from=z/w;
+ float z_to=z_from;
+ float depth;
+ vec2 prev_pos=pos;
+
+ bool found=false;
+
+ //if acceleration > 0, distance between pixels gets larger each step. This allows covering a larger area
+ float accel=1.0+acceleration;
+ float steps_taken=0.0;
+
+ for(int i=0;i<num_steps;i++) {
+
+ pos+=line_advance;
+ z+=z_advance;
+ w+=w_advance;
+
+ //convert to linear depth
+ depth = texture(source_depth, pos*pixel_size).r * 2.0 - 1.0;
+ depth = 2.0 * camera_z_near * camera_z_far / (camera_z_far + camera_z_near - depth * (camera_z_far - camera_z_near));
+ depth=-depth;
+
+ z_from = z_to;
+ z_to = z/w;
+
+ if (depth>z_to) {
+ //if depth was surpassed
+ if (depth<=max(z_to,z_from)+depth_tolerance) {
+ //check the depth tolerance
+ found=true;
+ }
+ break;
+ }
+
+ steps_taken+=1.0;
+ prev_pos=pos;
+ z_advance*=accel;
+ w_advance*=accel;
+ line_advance*=accel;
+ }
+
+
+
+
+ if (found) {
+
+ float margin_blend=1.0;
+
+
+ vec2 margin = vec2((viewport_size.x+viewport_size.y)*0.5*0.05); //make a uniform margin
+ if (any(bvec4(lessThan(pos,-margin),greaterThan(pos,viewport_size+margin)))) {
+ //clip outside screen + margin
+ frag_color=vec4(0.0);
+ return;
+ }
+
+ {
+ //blend fading out towards external margin
+ vec2 margin_grad = mix(pos-viewport_size,-pos,lessThan(pos,vec2(0.0)));
+ margin_blend = 1.0-smoothstep(0.0,margin.x,max(margin_grad.x,margin_grad.y));
+ //margin_blend=1.0;
+
+ }
+
+ vec2 final_pos;
+ float grad;
+
+#ifdef SMOOTH_ACCEL
+ //if the distance between point and prev point is >1, then take some samples in the middle for smoothing out the image
+ vec2 blend_dir = pos - prev_pos;
+ float steps = min(8.0,length(blend_dir));
+ if (steps>2.0) {
+ vec2 blend_step = blend_dir/steps;
+ float blend_z = (z_to-z_from)/steps;
+ vec2 new_pos;
+ float subgrad=0.0;
+ for(float i=0.0;i<steps;i++) {
+
+ new_pos = (prev_pos+blend_step*i);
+ float z = z_from+blend_z*i;
+
+ depth = texture(source_depth, new_pos*pixel_size).r * 2.0 - 1.0;
+ depth = 2.0 * camera_z_near * camera_z_far / (camera_z_far + camera_z_near - depth * (camera_z_far - camera_z_near));
+ depth=-depth;
+
+ subgrad=i/steps;
+ if (depth>z)
+ break;
+ }
+
+ final_pos = new_pos;
+ grad=(steps_taken+subgrad)/float(num_steps);
+
+ } else {
+#endif
+ grad=steps_taken/float(num_steps);
+ final_pos=pos;
+#ifdef SMOOTH_ACCEL
+ }
+
+#endif
+
+
+
+#ifdef REFLECT_ROUGHNESS
+
+
+ vec4 final_color;
+ //if roughness is enabled, do screen space cone tracing
+ if (roughness > 0.001) {
+ ///////////////////////////////////////////////////////////////////////////////////////
+ //use a blurred version (in consecutive mipmaps) of the screen to simulate roughness
+
+ float gloss = 1.0-roughness;
+ float cone_angle = roughness * M_PI * 0.5;
+ vec2 cone_dir = final_pos - line_begin;
+ float cone_len = length(cone_dir);
+ cone_dir = normalize(cone_dir); //will be used normalized from now on
+ float max_mipmap = filter_mipmap_levels - 1.0;
+ float gloss_mult=gloss;
+
+ float rem_alpha=1.0;
+ final_color = vec4(0.0);
+
+ for(int i=0;i<7;i++) {
+
+ float op_len = 2.0 * tan(cone_angle) * cone_len; //opposite side of iso triangle
+ float radius;
+ {
+ //fit to sphere inside cone (sphere ends at end of cone), something like this:
+ // ___
+ // \O/
+ // V
+ //
+ // as it avoids bleeding from beyond the reflection as much as possible. As a plus
+ // it also makes the rough reflection more elongated.
+ float a = op_len;
+ float h = cone_len;
+ float a2 = a * a;
+ float fh2 = 4.0f * h * h;
+ radius = (a * (sqrt(a2 + fh2) - a)) / (4.0f * h);
+ }
+
+ //find the place where screen must be sampled
+ vec2 sample_pos = ( line_begin + cone_dir * (cone_len - radius) ) * pixel_size;
+ //radius is in pixels, so it's natural that log2(radius) maps to the right mipmap for the amount of pixels
+ float mipmap = clamp( log2( radius ), 0.0, max_mipmap );
+
+ //mipmap = max(mipmap-1.0,0.0);
+ //do sampling
+
+ vec4 sample_color;
+ {
+ sample_color = textureLod(source_diffuse,sample_pos,mipmap);
+ }
+
+ //multiply by gloss
+ sample_color.rgb*=gloss_mult;
+ sample_color.a=gloss_mult;
+
+ rem_alpha -= sample_color.a;
+ if(rem_alpha < 0.0) {
+ sample_color.rgb *= (1.0 - abs(rem_alpha));
+ }
+
+ final_color+=sample_color;
+
+ if (final_color.a>=0.95) {
+ // This code of accumulating gloss and aborting on near one
+ // makes sense when you think of cone tracing.
+ // Think of it as if roughness was 0, then we could abort on the first
+ // iteration. For lesser roughness values, we need more iterations, but
+ // each needs to have less influence given the sphere is smaller
+ break;
+ }
+
+ cone_len-=radius*2.0; //go to next (smaller) circle.
+
+ gloss_mult*=gloss;
+
+
+ }
+ } else {
+ final_color = textureLod(source_diffuse,final_pos*pixel_size,0.0);
+ }
+
+ frag_color = vec4(final_color.rgb,pow(clamp(1.0-grad,0.0,1.0),distance_fade)*margin_blend);
+
+#else
+ frag_color = vec4(textureLod(source_diffuse,final_pos*pixel_size,0.0).rgb,pow(clamp(1.0-grad,0.0,1.0),distance_fade)*margin_blend);
+#endif
+
+
+
+ } else {
+ frag_color = vec4(0.0,0.0,0.0,0.0);
+ }
+
+
+
+}
+
+
+
+layout(location=0) in highp vec4 vertex_attrib;
+layout(location=4) in vec2 uv_in;
+
+out vec2 uv_interp;
+
+
+void main() {
+
+ uv_interp = uv_in;
+ gl_Position = vertex_attrib;
+}
+
+
+
+in vec2 uv_interp;
+uniform sampler2D source_color; //texunit:0
+
+#ifdef SSAO_MERGE
+uniform sampler2D source_ssao; //texunit:1
+#endif
+
+uniform float lod;
+uniform vec2 pixel_size;
+
+
+layout(location = 0) out vec4 frag_color;
+
+#ifdef SSAO_MERGE
+
+uniform vec4 ssao_color;
+
+#endif
+
+#if defined (GLOW_GAUSSIAN_HORIZONTAL) || defined(GLOW_GAUSSIAN_VERTICAL)
+
+uniform float glow_strength;
+
+#endif
+
+#if defined(DOF_FAR_BLUR) || defined (DOF_NEAR_BLUR)
+
+#ifdef DOF_QUALITY_LOW
+const int dof_kernel_size=5;
+const int dof_kernel_from=2;
+const float dof_kernel[5] = float[] (0.153388,0.221461,0.250301,0.221461,0.153388);
+#endif
+
+#ifdef DOF_QUALITY_MEDIUM
+const int dof_kernel_size=11;
+const int dof_kernel_from=5;
+const float dof_kernel[11] = float[] (0.055037,0.072806,0.090506,0.105726,0.116061,0.119726,0.116061,0.105726,0.090506,0.072806,0.055037);
+
+#endif
+
+#ifdef DOF_QUALITY_HIGH
+const int dof_kernel_size=21;
+const int dof_kernel_from=10;
+const float dof_kernel[21] = float[] (0.028174,0.032676,0.037311,0.041944,0.046421,0.050582,0.054261,0.057307,0.059587,0.060998,0.061476,0.060998,0.059587,0.057307,0.054261,0.050582,0.046421,0.041944,0.037311,0.032676,0.028174);
+#endif
+
+uniform sampler2D dof_source_depth; //texunit:1
+uniform float dof_begin;
+uniform float dof_end;
+uniform vec2 dof_dir;
+uniform float dof_radius;
+
+#ifdef DOF_NEAR_BLUR_MERGE
+
+uniform sampler2D source_dof_original; //texunit:2
+#endif
+
+#endif
+
+
+#ifdef GLOW_FIRST_PASS
+
+uniform float exposure;
+uniform float white;
+
+#ifdef GLOW_USE_AUTO_EXPOSURE
+
+uniform highp sampler2D source_auto_exposure; //texunit:1
+uniform highp float auto_exposure_grey;
+
+#endif
+
+uniform float glow_bloom;
+uniform float glow_hdr_treshold;
+uniform float glow_hdr_scale;
+
+#endif
+
+uniform float camera_z_far;
+uniform float camera_z_near;
+
+void main() {
+
+
+
+#ifdef GAUSSIAN_HORIZONTAL
+ vec2 pix_size = pixel_size;
+ pix_size*=0.5; //reading from larger buffer, so use more samples
+ vec4 color =textureLod( source_color, uv_interp+vec2( 0.0, 0.0)*pix_size,lod )*0.214607;
+ color+=textureLod( source_color, uv_interp+vec2( 1.0, 0.0)*pix_size,lod )*0.189879;
+ color+=textureLod( source_color, uv_interp+vec2( 2.0, 0.0)*pix_size,lod )*0.157305;
+ color+=textureLod( source_color, uv_interp+vec2( 3.0, 0.0)*pix_size,lod )*0.071303;
+ color+=textureLod( source_color, uv_interp+vec2(-1.0, 0.0)*pix_size,lod )*0.189879;
+ color+=textureLod( source_color, uv_interp+vec2(-2.0, 0.0)*pix_size,lod )*0.157305;
+ color+=textureLod( source_color, uv_interp+vec2(-3.0, 0.0)*pix_size,lod )*0.071303;
+ frag_color = color;
+#endif
+
+#ifdef GAUSSIAN_VERTICAL
+ vec4 color =textureLod( source_color, uv_interp+vec2( 0.0, 0.0)*pixel_size,lod )*0.38774;
+ color+=textureLod( source_color, uv_interp+vec2( 0.0, 1.0)*pixel_size,lod )*0.24477;
+ color+=textureLod( source_color, uv_interp+vec2( 0.0, 2.0)*pixel_size,lod )*0.06136;
+ color+=textureLod( source_color, uv_interp+vec2( 0.0,-1.0)*pixel_size,lod )*0.24477;
+ color+=textureLod( source_color, uv_interp+vec2( 0.0,-2.0)*pixel_size,lod )*0.06136;
+ frag_color = color;
+#endif
+
+//glow uses larger sigma for a more rounded blur effect
+
+#ifdef GLOW_GAUSSIAN_HORIZONTAL
+ vec2 pix_size = pixel_size;
+ pix_size*=0.5; //reading from larger buffer, so use more samples
+ vec4 color =textureLod( source_color, uv_interp+vec2( 0.0, 0.0)*pix_size,lod )*0.174938;
+ color+=textureLod( source_color, uv_interp+vec2( 1.0, 0.0)*pix_size,lod )*0.165569;
+ color+=textureLod( source_color, uv_interp+vec2( 2.0, 0.0)*pix_size,lod )*0.140367;
+ color+=textureLod( source_color, uv_interp+vec2( 3.0, 0.0)*pix_size,lod )*0.106595;
+ color+=textureLod( source_color, uv_interp+vec2(-1.0, 0.0)*pix_size,lod )*0.165569;
+ color+=textureLod( source_color, uv_interp+vec2(-2.0, 0.0)*pix_size,lod )*0.140367;
+ color+=textureLod( source_color, uv_interp+vec2(-3.0, 0.0)*pix_size,lod )*0.106595;
+ color*=glow_strength;
+ frag_color = color;
+#endif
+
+#ifdef GLOW_GAUSSIAN_VERTICAL
+ vec4 color =textureLod( source_color, uv_interp+vec2(0.0, 0.0)*pixel_size,lod )*0.288713;
+ color+=textureLod( source_color, uv_interp+vec2(0.0, 1.0)*pixel_size,lod )*0.233062;
+ color+=textureLod( source_color, uv_interp+vec2(0.0, 2.0)*pixel_size,lod )*0.122581;
+ color+=textureLod( source_color, uv_interp+vec2(0.0,-1.0)*pixel_size,lod )*0.233062;
+ color+=textureLod( source_color, uv_interp+vec2(0.0,-2.0)*pixel_size,lod )*0.122581;
+ color*=glow_strength;
+ frag_color = color;
+#endif
+
+#ifdef DOF_FAR_BLUR
+
+ vec4 color_accum = vec4(0.0);
+
+ float depth = textureLod( dof_source_depth, uv_interp, 0.0).r;
+ depth = depth * 2.0 - 1.0;
+ depth = 2.0 * camera_z_near * camera_z_far / (camera_z_far + camera_z_near - depth * (camera_z_far - camera_z_near));
+
+ float amount = smoothstep(dof_begin,dof_end,depth);
+ float k_accum=0.0;
+
+ for(int i=0;i<dof_kernel_size;i++) {
+
+ int int_ofs = i-dof_kernel_from;
+ vec2 tap_uv = uv_interp + dof_dir * float(int_ofs) * amount * dof_radius;
+
+ float tap_k = dof_kernel[i];
+
+ float tap_depth = texture( dof_source_depth, tap_uv, 0.0).r;
+ tap_depth = tap_depth * 2.0 - 1.0;
+ tap_depth = 2.0 * camera_z_near * camera_z_far / (camera_z_far + camera_z_near - tap_depth * (camera_z_far - camera_z_near));
+
+ float tap_amount = mix(smoothstep(dof_begin,dof_end,tap_depth),1.0,int_ofs==0);
+ tap_amount*=tap_amount*tap_amount; //prevent undesired glow effect
+
+ vec4 tap_color = textureLod( source_color, tap_uv, 0.0) * tap_k;
+
+ k_accum+=tap_k*tap_amount;
+ color_accum+=tap_color*tap_amount;
+
+
+ }
+
+ if (k_accum>0.0) {
+ color_accum/=k_accum;
+ }
+
+ frag_color = color_accum;///k_accum;
+
+#endif
+
+#ifdef DOF_NEAR_BLUR
+
+ vec4 color_accum = vec4(0.0);
+
+ float max_accum=0;
+
+ for(int i=0;i<dof_kernel_size;i++) {
+
+ int int_ofs = i-dof_kernel_from;
+ vec2 tap_uv = uv_interp + dof_dir * float(int_ofs) * dof_radius;
+ float ofs_influence = max(0.0,1.0-float(abs(int_ofs))/float(dof_kernel_from));
+
+ float tap_k = dof_kernel[i];
+
+ vec4 tap_color = textureLod( source_color, tap_uv, 0.0);
+
+ float tap_depth = texture( dof_source_depth, tap_uv, 0.0).r;
+ tap_depth = tap_depth * 2.0 - 1.0;
+ tap_depth = 2.0 * camera_z_near * camera_z_far / (camera_z_far + camera_z_near - tap_depth * (camera_z_far - camera_z_near));
+ float tap_amount = 1.0-smoothstep(dof_end,dof_begin,tap_depth);
+ tap_amount*=tap_amount*tap_amount; //prevent undesired glow effect
+
+#ifdef DOF_NEAR_FIRST_TAP
+
+ tap_color.a= 1.0-smoothstep(dof_end,dof_begin,tap_depth);
+
+#endif
+
+ max_accum=max(max_accum,tap_amount*ofs_influence);
+
+ color_accum+=tap_color*tap_k;
+
+ }
+
+ color_accum.a=max(color_accum.a,sqrt(max_accum));
+
+
+#ifdef DOF_NEAR_BLUR_MERGE
+
+ vec4 original = textureLod( source_dof_original, uv_interp, 0.0);
+ color_accum = mix(original,color_accum,color_accum.a);
+
+#endif
+
+#ifndef DOF_NEAR_FIRST_TAP
+ //color_accum=vec4(vec3(color_accum.a),1.0);
+#endif
+ frag_color = color_accum;
+
+#endif
+
+
+
+#ifdef GLOW_FIRST_PASS
+
+#ifdef GLOW_USE_AUTO_EXPOSURE
+
+ frag_color/=texelFetch(source_auto_exposure,ivec2(0,0),0).r/auto_exposure_grey;
+#endif
+ frag_color*=exposure;
+
+ float luminance = max(frag_color.r,max(frag_color.g,frag_color.b));
+ float feedback = max( smoothstep(glow_hdr_treshold,glow_hdr_treshold+glow_hdr_scale,luminance), glow_bloom );
+
+ frag_color *= feedback;
+
+#endif
+
+
+#ifdef SIMPLE_COPY
+ vec4 color =textureLod( source_color, uv_interp,0.0);
+ frag_color = color;
+#endif
+
+#ifdef SSAO_MERGE
+
+ vec4 color =textureLod( source_color, uv_interp,0.0);
+ float ssao =textureLod( source_ssao, uv_interp,0.0).r;
+
+ frag_color = vec4( mix(color.rgb,color.rgb*mix(ssao_color.rgb,vec3(1.0),ssao),color.a), 1.0 );
+
+#endif
+
+
+}
+
+
+
+layout(location=0) in highp vec4 vertex_attrib;
+layout(location=4) in vec2 uv_in;
+
+out vec2 uv_interp;
+
+
+void main() {
+
+ uv_interp = uv_in;
+ gl_Position = vertex_attrib;
+}
+
+
+//#define QUALIFIER uniform // some guy on the interweb says it may be faster with this
+#define QUALIFIER const
+
+#ifdef USE_25_SAMPLES
+
+const int kernel_size=25;
+QUALIFIER vec4 kernel[25] = vec4[] (
+ vec4(0.530605, 0.613514, 0.739601, 0.0),
+ vec4(0.000973794, 1.11862e-005, 9.43437e-007, -3.0),
+ vec4(0.00333804, 7.85443e-005, 1.2945e-005, -2.52083),
+ vec4(0.00500364, 0.00020094, 5.28848e-005, -2.08333),
+ vec4(0.00700976, 0.00049366, 0.000151938, -1.6875),
+ vec4(0.0094389, 0.00139119, 0.000416598, -1.33333),
+ vec4(0.0128496, 0.00356329, 0.00132016, -1.02083),
+ vec4(0.017924, 0.00711691, 0.00347194, -0.75),
+ vec4(0.0263642, 0.0119715, 0.00684598, -0.520833),
+ vec4(0.0410172, 0.0199899, 0.0118481, -0.333333),
+ vec4(0.0493588, 0.0367726, 0.0219485, -0.1875),
+ vec4(0.0402784, 0.0657244, 0.04631, -0.0833333),
+ vec4(0.0211412, 0.0459286, 0.0378196, -0.0208333),
+ vec4(0.0211412, 0.0459286, 0.0378196, 0.0208333),
+ vec4(0.0402784, 0.0657244, 0.04631, 0.0833333),
+ vec4(0.0493588, 0.0367726, 0.0219485, 0.1875),
+ vec4(0.0410172, 0.0199899, 0.0118481, 0.333333),
+ vec4(0.0263642, 0.0119715, 0.00684598, 0.520833),
+ vec4(0.017924, 0.00711691, 0.00347194, 0.75),
+ vec4(0.0128496, 0.00356329, 0.00132016, 1.02083),
+ vec4(0.0094389, 0.00139119, 0.000416598, 1.33333),
+ vec4(0.00700976, 0.00049366, 0.000151938, 1.6875),
+ vec4(0.00500364, 0.00020094, 5.28848e-005, 2.08333),
+ vec4(0.00333804, 7.85443e-005, 1.2945e-005, 2.52083),
+ vec4(0.000973794, 1.11862e-005, 9.43437e-007, 3.0)
+);
+
+#endif //USE_25_SAMPLES
+
+#ifdef USE_17_SAMPLES
+
+const int kernel_size=17;
+
+QUALIFIER vec4 kernel[17] = vec4[](
+ vec4(0.536343, 0.624624, 0.748867, 0.0),
+ vec4(0.00317394, 0.000134823, 3.77269e-005, -2.0),
+ vec4(0.0100386, 0.000914679, 0.000275702, -1.53125),
+ vec4(0.0144609, 0.00317269, 0.00106399, -1.125),
+ vec4(0.0216301, 0.00794618, 0.00376991, -0.78125),
+ vec4(0.0347317, 0.0151085, 0.00871983, -0.5),
+ vec4(0.0571056, 0.0287432, 0.0172844, -0.28125),
+ vec4(0.0582416, 0.0659959, 0.0411329, -0.125),
+ vec4(0.0324462, 0.0656718, 0.0532821, -0.03125),
+ vec4(0.0324462, 0.0656718, 0.0532821, 0.03125),
+ vec4(0.0582416, 0.0659959, 0.0411329, 0.125),
+ vec4(0.0571056, 0.0287432, 0.0172844, 0.28125),
+ vec4(0.0347317, 0.0151085, 0.00871983, 0.5),
+ vec4(0.0216301, 0.00794618, 0.00376991, 0.78125),
+ vec4(0.0144609, 0.00317269, 0.00106399, 1.125),
+ vec4(0.0100386, 0.000914679, 0.000275702, 1.53125),
+ vec4(0.00317394, 0.000134823, 3.77269e-005, 2.0)
+);
+
+#endif //USE_17_SAMPLES
+
+
+#ifdef USE_11_SAMPLES
+
+const int kernel_size=11;
+
+QUALIFIER vec4 kernel[11] = vec4[](
+ vec4(0.560479, 0.669086, 0.784728, 0.0),
+ vec4(0.00471691, 0.000184771, 5.07566e-005, -2.0),
+ vec4(0.0192831, 0.00282018, 0.00084214, -1.28),
+ vec4(0.03639, 0.0130999, 0.00643685, -0.72),
+ vec4(0.0821904, 0.0358608, 0.0209261, -0.32),
+ vec4(0.0771802, 0.113491, 0.0793803, -0.08),
+ vec4(0.0771802, 0.113491, 0.0793803, 0.08),
+ vec4(0.0821904, 0.0358608, 0.0209261, 0.32),
+ vec4(0.03639, 0.0130999, 0.00643685, 0.72),
+ vec4(0.0192831, 0.00282018, 0.00084214, 1.28),
+ vec4(0.00471691, 0.000184771, 5.07565e-005, 2.0)
+);
+
+#endif //USE_11_SAMPLES
+
+
+uniform float max_radius;
+uniform float fovy;
+uniform float camera_z_far;
+uniform float camera_z_near;
+uniform vec2 dir;
+in vec2 uv_interp;
+
+uniform sampler2D source_diffuse; //texunit:0
+uniform sampler2D source_motion_ss; //texunit:1
+uniform sampler2D source_depth; //texunit:2
+
+layout(location = 0) out vec4 frag_color;
+
+void main() {
+
+ float strength = texture(source_motion_ss,uv_interp).a;
+ strength*=strength; //stored as sqrt
+
+ // Fetch color of current pixel:
+ vec4 base_color = texture(source_diffuse, uv_interp);
+
+ if (strength>0.0) {
+
+
+ // Fetch linear depth of current pixel:
+ float depth = texture(source_depth, uv_interp).r * 2.0 - 1.0;
+ depth = 2.0 * camera_z_near * camera_z_far / (camera_z_far + camera_z_near - depth * (camera_z_far - camera_z_near));
+ depth=-depth;
+
+
+ // Calculate the radius scale (1.0 for a unit plane sitting on the
+ // projection window):
+ float distance = 1.0 / tan(0.5 * fovy);
+ float scale = distance / -depth; //remember depth is negative by default in OpenGL
+
+ // Calculate the final step to fetch the surrounding pixels:
+ vec2 step = max_radius * scale * dir;
+ step *= strength; // Modulate it using the alpha channel.
+ step *= 1.0 / 3.0; // Divide by 3 as the kernels range from -3 to 3.
+
+ // Accumulate the center sample:
+ vec3 color_accum = base_color.rgb;
+ color_accum *= kernel[0].rgb;
+
+ // Accumulate the other samples:
+ for (int i = 1; i < kernel_size; i++) {
+ // Fetch color and depth for current sample:
+ vec2 offset = uv_interp + kernel[i].a * step;
+ vec3 color = texture(source_diffuse, offset).rgb;
+
+#ifdef ENABLE_FOLLOW_SURFACE
+ // If the difference in depth is huge, we lerp color back to "colorM":
+ float depth_cmp = texture(source_depth, offset).r *2.0 - 1.0;
+ depth_cmp = 2.0 * camera_z_near * camera_z_far / (camera_z_far + camera_z_near - depth_cmp * (camera_z_far - camera_z_near));
+ depth_cmp=-depth_cmp;
+
+ float s = clamp(300.0f * distance *
+ max_radius * abs(depth - depth_cmp),0.0,1.0);
+ color = mix(color, base_color.rgb, s);
+#endif
+
+ // Accumulate:
+ color_accum += kernel[i].rgb * color;
+ }
+
+ frag_color = vec4(color_accum,base_color.a); //keep alpha (used for SSAO)
+ } else {
+ frag_color = base_color;
+ }
+}
+
+
+
+layout(location=0) in highp vec4 vertex_attrib;
+
+void main() {
+
+ gl_Position = vertex_attrib;
+}
+
+
+
+#ifdef MINIFY_START
+
+#define SDEPTH_TYPE highp sampler2D
+uniform float camera_z_far;
+uniform float camera_z_near;
+
+#else
+
+#define SDEPTH_TYPE mediump usampler2D
+
+#endif
+
+uniform SDEPTH_TYPE source_depth; //texunit:0
+
+uniform ivec2 from_size;
+uniform int source_mipmap;
+
+layout(location = 0) out mediump uint depth;
+
+void main() {
+
+
+ ivec2 ssP = ivec2(gl_FragCoord.xy);
+
+ // Rotated grid subsampling to avoid XY directional bias or Z precision bias while downsampling.
+ // On DX9, the bit-and can be implemented with floating-point modulo
+
+#ifdef MINIFY_START
+ float fdepth = texelFetch(source_depth, clamp(ssP * 2 + ivec2(ssP.y & 1, ssP.x & 1), ivec2(0), from_size - ivec2(1)), source_mipmap).r;
+ fdepth = fdepth * 2.0 - 1.0;
+ fdepth = 2.0 * camera_z_near * camera_z_far / (camera_z_far + camera_z_near - fdepth * (camera_z_far - camera_z_near));
+ fdepth /= camera_z_far;
+ depth = uint(clamp(fdepth*65535.0,0.0,65535.0));
+
+#else
+ depth = texelFetch(source_depth, clamp(ssP * 2 + ivec2(ssP.y & 1, ssP.x & 1), ivec2(0), from_size - ivec2(1)), source_mipmap).r;
+#endif
+
+
+}
+
+
+
+
+layout(location=0) in highp vec4 vertex_attrib;
+
+void main() {
+
+ gl_Position = vertex_attrib;
+ gl_Position.z=1.0;
+}
+
+
+
+#define NUM_SAMPLES (11)
+
+// If using depth mip levels, the log of the maximum pixel offset before we need to switch to a lower
+// miplevel to maintain reasonable spatial locality in the cache
+// If this number is too small (< 3), too many taps will land in the same pixel, and we'll get bad variance that manifests as flashing.
+// If it is too high (> 5), we'll get bad performance because we're not using the MIP levels effectively
+#define LOG_MAX_OFFSET (3)
+
+// This must be less than or equal to the MAX_MIP_LEVEL defined in SSAO.cpp
+#define MAX_MIP_LEVEL (4)
+
+// This is the number of turns around the circle that the spiral pattern makes. This should be prime to prevent
+// taps from lining up. This particular choice was tuned for NUM_SAMPLES == 9
+#define NUM_SPIRAL_TURNS (7)
+
+
+uniform sampler2D source_depth; //texunit:0
+uniform highp usampler2D source_depth_mipmaps; //texunit:1
+uniform sampler2D source_normal; //texunit:2
+
+uniform ivec2 screen_size;
+uniform float camera_z_far;
+uniform float camera_z_near;
+
+uniform float intensity_div_r6;
+uniform float radius;
+
+#ifdef ENABLE_RADIUS2
+uniform float intensity_div_r62;
+uniform float radius2;
+#endif
+
+uniform float bias;
+uniform float proj_scale;
+
+layout(location = 0) out float visibility;
+
+uniform vec4 proj_info;
+
+vec3 reconstructCSPosition(vec2 S, float z) {
+ return vec3((S.xy * proj_info.xy + proj_info.zw) * z, z);
+}
+
+vec3 getPosition(ivec2 ssP) {
+ vec3 P;
+ P.z = texelFetch(source_depth, ssP, 0).r;
+
+ P.z = P.z * 2.0 - 1.0;
+ P.z = 2.0 * camera_z_near * camera_z_far / (camera_z_far + camera_z_near - P.z * (camera_z_far - camera_z_near));
+ P.z = -P.z;
+
+ // Offset to pixel center
+ P = reconstructCSPosition(vec2(ssP) + vec2(0.5), P.z);
+ return P;
+}
+
+/** Reconstructs screen-space unit normal from screen-space position */
+vec3 reconstructCSFaceNormal(vec3 C) {
+ return normalize(cross(dFdy(C), dFdx(C)));
+}
+
+
+
+/** Returns a unit vector and a screen-space radius for the tap on a unit disk (the caller should scale by the actual disk radius) */
+vec2 tapLocation(int sampleNumber, float spinAngle, out float ssR){
+ // Radius relative to ssR
+ float alpha = (float(sampleNumber) + 0.5) * (1.0 / float(NUM_SAMPLES));
+ float angle = alpha * (float(NUM_SPIRAL_TURNS) * 6.28) + spinAngle;
+
+ ssR = alpha;
+ return vec2(cos(angle), sin(angle));
+}
+
+
+/** Read the camera-space position of the point at screen-space pixel ssP + unitOffset * ssR. Assumes length(unitOffset) == 1 */
+vec3 getOffsetPosition(ivec2 ssC, vec2 unitOffset, float ssR) {
+ // Derivation:
+ // mipLevel = floor(log(ssR / MAX_OFFSET));
+ int mipLevel = clamp(int(floor(log2(ssR))) - LOG_MAX_OFFSET, 0, MAX_MIP_LEVEL);
+
+ ivec2 ssP = ivec2(ssR * unitOffset) + ssC;
+
+ vec3 P;
+
+ // We need to divide by 2^mipLevel to read the appropriately scaled coordinate from a MIP-map.
+ // Manually clamp to the texture size because texelFetch bypasses the texture unit
+ ivec2 mipP = clamp(ssP >> mipLevel, ivec2(0), (screen_size >> mipLevel) - ivec2(1));
+
+
+ if (mipLevel < 1) {
+ //read from depth buffer
+ P.z = texelFetch(source_depth, mipP, 0).r;
+ P.z = P.z * 2.0 - 1.0;
+ P.z = 2.0 * camera_z_near * camera_z_far / (camera_z_far + camera_z_near - P.z * (camera_z_far - camera_z_near));
+ P.z = -P.z;
+
+ } else {
+ //read from mipmaps
+ uint d = texelFetch(source_depth_mipmaps, mipP, mipLevel-1).r;
+ P.z = -(float(d)/65535.0)*camera_z_far;
+ }
+
+
+ // Offset to pixel center
+ P = reconstructCSPosition(vec2(ssP) + vec2(0.5), P.z);
+
+ return P;
+}
+
+
+
+/** Compute the occlusion due to sample with index \a i about the pixel at \a ssC that corresponds
+ to camera-space point \a C with unit normal \a n_C, using maximum screen-space sampling radius \a ssDiskRadius
+
+ Note that units of H() in the HPG12 paper are meters, not
+ unitless. The whole falloff/sampling function is therefore
+ unitless. In this implementation, we factor out (9 / radius).
+
+ Four versions of the falloff function are implemented below
+*/
+float sampleAO(in ivec2 ssC, in vec3 C, in vec3 n_C, in float ssDiskRadius,in float p_radius, in int tapIndex, in float randomPatternRotationAngle) {
+ // Offset on the unit disk, spun for this pixel
+ float ssR;
+ vec2 unitOffset = tapLocation(tapIndex, randomPatternRotationAngle, ssR);
+ ssR *= ssDiskRadius;
+
+ // The occluding point in camera space
+ vec3 Q = getOffsetPosition(ssC, unitOffset, ssR);
+
+ vec3 v = Q - C;
+
+ float vv = dot(v, v);
+ float vn = dot(v, n_C);
+
+ const float epsilon = 0.01;
+ float radius2 = p_radius*p_radius;
+
+ // A: From the HPG12 paper
+ // Note large epsilon to avoid overdarkening within cracks
+ //return float(vv < radius2) * max((vn - bias) / (epsilon + vv), 0.0) * radius2 * 0.6;
+
+ // B: Smoother transition to zero (lowers contrast, smoothing out corners). [Recommended]
+ float f=max(radius2 - vv, 0.0);
+ return f * f * f * max((vn - bias) / (epsilon + vv), 0.0);
+
+ // C: Medium contrast (which looks better at high radii), no division. Note that the
+ // contribution still falls off with radius^2, but we've adjusted the rate in a way that is
+ // more computationally efficient and happens to be aesthetically pleasing.
+ // return 4.0 * max(1.0 - vv * invRadius2, 0.0) * max(vn - bias, 0.0);
+
+ // D: Low contrast, no division operation
+ // return 2.0 * float(vv < radius * radius) * max(vn - bias, 0.0);
+}
+
+
+
+void main() {
+
+
+ // Pixel being shaded
+ ivec2 ssC = ivec2(gl_FragCoord.xy);
+
+ // World space point being shaded
+ vec3 C = getPosition(ssC);
+
+/* if (C.z <= -camera_z_far*0.999) {
+ // We're on the skybox
+ visibility=1.0;
+ return;
+ }*/
+
+ //visibility=-C.z/camera_z_far;
+ //return;
+
+ //vec3 n_C = texelFetch(source_normal,ssC,0).rgb * 2.0 - 1.0;
+
+ vec3 n_C = reconstructCSFaceNormal(C);
+ n_C = -n_C;
+
+
+ // Hash function used in the HPG12 AlchemyAO paper
+ float randomPatternRotationAngle = float((3 * ssC.x ^ ssC.y + ssC.x * ssC.y) * 10);
+
+ // Reconstruct normals from positions. These will lead to 1-pixel black lines
+ // at depth discontinuities, however the blur will wipe those out so they are not visible
+ // in the final image.
+
+ // Choose the screen-space sample radius
+ // proportional to the projected area of the sphere
+ float ssDiskRadius = -proj_scale * radius / C.z;
+
+ float sum = 0.0;
+ for (int i = 0; i < NUM_SAMPLES; ++i) {
+ sum += sampleAO(ssC, C, n_C, ssDiskRadius, radius,i, randomPatternRotationAngle);
+ }
+
+ float A = max(0.0, 1.0 - sum * intensity_div_r6 * (5.0 / float(NUM_SAMPLES)));
+
+#ifdef ENABLE_RADIUS2
+
+ //go again for radius2
+ randomPatternRotationAngle = float((5 * ssC.x ^ ssC.y + ssC.x * ssC.y) * 11);
+
+ // Reconstruct normals from positions. These will lead to 1-pixel black lines
+ // at depth discontinuities, however the blur will wipe those out so they are not visible
+ // in the final image.
+
+ // Choose the screen-space sample radius
+ // proportional to the projected area of the sphere
+ ssDiskRadius = -proj_scale * radius2 / C.z;
+
+ sum = 0.0;
+ for (int i = 0; i < NUM_SAMPLES; ++i) {
+ sum += sampleAO(ssC, C, n_C, ssDiskRadius,radius2, i, randomPatternRotationAngle);
+ }
+
+ A= min(A,max(0.0, 1.0 - sum * intensity_div_r62 * (5.0 / float(NUM_SAMPLES))));
+#endif
+ // Bilateral box-filter over a quad for free, respecting depth edges
+ // (the difference that this makes is subtle)
+ if (abs(dFdx(C.z)) < 0.02) {
+ A -= dFdx(A) * (float(ssC.x & 1) - 0.5);
+ }
+ if (abs(dFdy(C.z)) < 0.02) {
+ A -= dFdy(A) * (float(ssC.y & 1) - 0.5);
+ }
+
+ visibility = A;
+
+}
+
+
+
+
+
+layout(location=0) in highp vec4 vertex_attrib;
+
+
+void main() {
+
+ gl_Position = vertex_attrib;
+ gl_Position.z=1.0;
+}
+
+
+
+uniform sampler2D source_ssao; //texunit:0
+uniform sampler2D source_depth; //texunit:1
+
+
+layout(location = 0) out float visibility;
+
+
+//////////////////////////////////////////////////////////////////////////////////////////////
+// Tunable Parameters:
+
+/** Increase to make depth edges crisper. Decrease to reduce flicker. */
+#define EDGE_SHARPNESS (1.0)
+
+/** Step in 2-pixel intervals since we already blurred against neighbors in the
+ first AO pass. This constant can be increased while R decreases to improve
+ performance at the expense of some dithering artifacts.
+
+ Morgan found that a scale of 3 left a 1-pixel checkerboard grid that was
+ unobjectionable after shading was applied but eliminated most temporal incoherence
+ from using small numbers of sample taps.
+ */
+#define SCALE (3)
+
+/** Filter radius in pixels. This will be multiplied by SCALE. */
+#define R (4)
+
+
+//////////////////////////////////////////////////////////////////////////////////////////////
+
+
+// Gaussian coefficients
+const float gaussian[R + 1] =
+// float[](0.356642, 0.239400, 0.072410, 0.009869);
+// float[](0.398943, 0.241971, 0.053991, 0.004432, 0.000134); // stddev = 1.0
+ float[](0.153170, 0.144893, 0.122649, 0.092902, 0.062970); // stddev = 2.0
+// float[](0.111220, 0.107798, 0.098151, 0.083953, 0.067458, 0.050920, 0.036108); // stddev = 3.0
+
+/** (1, 0) or (0, 1)*/
+uniform ivec2 axis;
+
+uniform float camera_z_far;
+uniform float camera_z_near;
+
+void main() {
+
+ ivec2 ssC = ivec2(gl_FragCoord.xy);
+
+ float depth = texelFetch(source_depth, ssC, 0).r;
+
+ depth = depth * 2.0 - 1.0;
+ depth = 2.0 * camera_z_near * camera_z_far / (camera_z_far + camera_z_near - depth * (camera_z_far - camera_z_near));
+
+ float depth_divide = 1.0 / camera_z_far;
+
+ depth*=depth_divide;
+
+ /*
+ if (depth > camera_z_far*0.999) {
+ discard;//skybox
+ }
+ */
+
+ float sum = texelFetch(source_ssao, ssC, 0).r;
+
+ // Base weight for depth falloff. Increase this for more blurriness,
+ // decrease it for better edge discrimination
+ float BASE = gaussian[0];
+ float totalWeight = BASE;
+ sum *= totalWeight;
+
+
+ for (int r = -R; r <= R; ++r) {
+ // We already handled the zero case above. This loop should be unrolled and the static branch optimized out,
+ // so the IF statement has no runtime cost
+ if (r != 0) {
+
+ ivec2 ppos = ssC + axis * (r * SCALE);
+ float value = texelFetch(source_ssao, ppos, 0).r;
+ float temp_depth = texelFetch(source_depth, ssC, 0).r;
+
+ temp_depth = temp_depth * 2.0 - 1.0;
+ temp_depth = 2.0 * camera_z_near * camera_z_far / (camera_z_far + camera_z_near - temp_depth * (camera_z_far - camera_z_near));
+ temp_depth *= depth_divide;
+
+ // spatial domain: offset gaussian tap
+ float weight = 0.3 + gaussian[abs(r)];
+
+ // range domain (the "bilateral" weight). As depth difference increases, decrease weight.
+ weight *= max(0.0, 1.0
+ - (EDGE_SHARPNESS * 2000.0) * abs(temp_depth - depth)
+ );
+
+ sum += value * weight;
+ totalWeight += weight;
+ }
+ }
+
+ const float epsilon = 0.0001;
+ visibility = sum / (totalWeight + epsilon);
+}
+
+
+layout(location=0) in highp vec4 vertex_attrib;
+
+
+void main() {
+
+ gl_Position = vertex_attrib;
+
+}
+
+
+
+uniform highp sampler2D source_exposure; //texunit:0
+
+#ifdef EXPOSURE_BEGIN
+
+uniform highp ivec2 source_render_size;
+uniform highp ivec2 target_size;
+
+#endif
+
+#ifdef EXPOSURE_END
+
+uniform highp sampler2D prev_exposure; //texunit:1
+uniform highp float exposure_adjust;
+uniform highp float min_luminance;
+uniform highp float max_luminance;
+
+#endif
+
+layout(location = 0) out highp float exposure;
+
+
+
+void main() {
+
+
+
+#ifdef EXPOSURE_BEGIN
+
+
+ ivec2 src_pos = ivec2(gl_FragCoord.xy)*source_render_size/target_size;
+
+#if 1
+ //more precise and expensive, but less jittery
+ ivec2 next_pos = ivec2(gl_FragCoord.xy+ivec2(1))*source_render_size/target_size;
+ next_pos = max(next_pos,src_pos+ivec2(1)); //so it at least reads one pixel
+ highp vec3 source_color=vec3(0.0);
+ for(int i=src_pos.x;i<next_pos.x;i++) {
+ for(int j=src_pos.y;j<next_pos.y;j++) {
+ source_color += texelFetch(source_exposure,ivec2(i,j),0).rgb;
+ }
+ }
+
+ source_color/=float( (next_pos.x-src_pos.x)*(next_pos.y-src_pos.y) );
+#else
+ highp vec3 source_color = texelFetch(source_exposure,src_pos,0).rgb;
+
+#endif
+
+ exposure = max(source_color.r,max(source_color.g,source_color.b));
+
+#else
+
+ ivec2 coord = ivec2(gl_FragCoord.xy);
+ exposure = texelFetch(source_exposure,coord*3+ivec2(0,0),0).r;
+ exposure += texelFetch(source_exposure,coord*3+ivec2(1,0),0).r;
+ exposure += texelFetch(source_exposure,coord*3+ivec2(2,0),0).r;
+ exposure += texelFetch(source_exposure,coord*3+ivec2(0,1),0).r;
+ exposure += texelFetch(source_exposure,coord*3+ivec2(1,1),0).r;
+ exposure += texelFetch(source_exposure,coord*3+ivec2(2,1),0).r;
+ exposure += texelFetch(source_exposure,coord*3+ivec2(0,2),0).r;
+ exposure += texelFetch(source_exposure,coord*3+ivec2(1,2),0).r;
+ exposure += texelFetch(source_exposure,coord*3+ivec2(2,2),0).r;
+ exposure *= (1.0/9.0);
+
+#ifdef EXPOSURE_END
+
+#ifdef EXPOSURE_FORCE_SET
+ //will stay as is
+#else
+ highp float prev_lum = texelFetch(prev_exposure,ivec2(0,0),0).r; //1 pixel previous exposure
+ exposure = clamp( prev_lum + (exposure-prev_lum)*exposure_adjust,min_luminance,max_luminance);
+
+#endif //EXPOSURE_FORCE_SET
+
+
+#endif //EXPOSURE_END
+
+#endif //EXPOSURE_BEGIN
+
+
+}
+
+
+
+
+layout(location=0) in highp vec4 vertex_attrib;
+layout(location=4) in vec2 uv_in;
+
+out vec2 uv_interp;
+
+
+
+void main() {
+
+ gl_Position = vertex_attrib;
+ uv_interp = uv_in;
+
+}
+
+
+
+in vec2 uv_interp;
+
+uniform highp sampler2D source; //texunit:0
+
+uniform float exposure;
+uniform float white;
+
+#ifdef USE_AUTO_EXPOSURE
+
+uniform highp sampler2D source_auto_exposure; //texunit:1
+uniform highp float auto_exposure_grey;
+
+#endif
+
+#if defined(USE_GLOW_LEVEL1) || defined(USE_GLOW_LEVEL2) || defined(USE_GLOW_LEVEL3) || defined(USE_GLOW_LEVEL4) || defined(USE_GLOW_LEVEL5) || defined(USE_GLOW_LEVEL6) || defined(USE_GLOW_LEVEL7)
+
+uniform highp sampler2D source_glow; //texunit:2
+uniform highp float glow_intensity;
+
+#endif
+
+layout(location = 0) out vec4 frag_color;
+
+#ifdef USE_GLOW_FILTER_BICUBIC
+
+// w0, w1, w2, and w3 are the four cubic B-spline basis functions
+float w0(float a)
+{
+ return (1.0/6.0)*(a*(a*(-a + 3.0) - 3.0) + 1.0);
+}
+
+float w1(float a)
+{
+ return (1.0/6.0)*(a*a*(3.0*a - 6.0) + 4.0);
+}
+
+float w2(float a)
+{
+ return (1.0/6.0)*(a*(a*(-3.0*a + 3.0) + 3.0) + 1.0);
+}
+
+float w3(float a)
+{
+ return (1.0/6.0)*(a*a*a);
+}
+
+// g0 and g1 are the two amplitude functions
+float g0(float a)
+{
+ return w0(a) + w1(a);
+}
+
+float g1(float a)
+{
+ return w2(a) + w3(a);
+}
+
+// h0 and h1 are the two offset functions
+float h0(float a)
+{
+ return -1.0 + w1(a) / (w0(a) + w1(a));
+}
+
+float h1(float a)
+{
+ return 1.0 + w3(a) / (w2(a) + w3(a));
+}
+
+uniform ivec2 glow_texture_size;
+
+vec4 texture2D_bicubic(sampler2D tex, vec2 uv,int p_lod)
+{
+ float lod=float(p_lod);
+ vec2 tex_size = vec2(glow_texture_size >> p_lod);
+ vec2 pixel_size =1.0/tex_size;
+ uv = uv*tex_size + 0.5;
+ vec2 iuv = floor( uv );
+ vec2 fuv = fract( uv );
+
+ float g0x = g0(fuv.x);
+ float g1x = g1(fuv.x);
+ float h0x = h0(fuv.x);
+ float h1x = h1(fuv.x);
+ float h0y = h0(fuv.y);
+ float h1y = h1(fuv.y);
+
+ vec2 p0 = (vec2(iuv.x + h0x, iuv.y + h0y) - 0.5) * pixel_size;
+ vec2 p1 = (vec2(iuv.x + h1x, iuv.y + h0y) - 0.5) * pixel_size;
+ vec2 p2 = (vec2(iuv.x + h0x, iuv.y + h1y) - 0.5) * pixel_size;
+ vec2 p3 = (vec2(iuv.x + h1x, iuv.y + h1y) - 0.5) * pixel_size;
+
+ return g0(fuv.y) * (g0x * textureLod(tex, p0,lod) +
+ g1x * textureLod(tex, p1,lod)) +
+ g1(fuv.y) * (g0x * textureLod(tex, p2,lod) +
+ g1x * textureLod(tex, p3,lod));
+}
+
+
+
+#define GLOW_TEXTURE_SAMPLE(m_tex,m_uv,m_lod) texture2D_bicubic(m_tex,m_uv,m_lod)
+
+#else
+
+#define GLOW_TEXTURE_SAMPLE(m_tex,m_uv,m_lod) textureLod(m_tex,m_uv,float(m_lod))
+
+#endif
+
+
+void main() {
+
+ ivec2 coord = ivec2(gl_FragCoord.xy);
+ vec3 color = texelFetch(source,coord,0).rgb;
+
+
+#ifdef USE_AUTO_EXPOSURE
+
+ color/=texelFetch(source_auto_exposure,ivec2(0,0),0).r/auto_exposure_grey;
+#endif
+
+ color*=exposure;
+
+
+#if defined(USE_GLOW_LEVEL1) || defined(USE_GLOW_LEVEL2) || defined(USE_GLOW_LEVEL3) || defined(USE_GLOW_LEVEL4) || defined(USE_GLOW_LEVEL5) || defined(USE_GLOW_LEVEL6) || defined(USE_GLOW_LEVEL7)
+ vec3 glow = vec3(0.0);
+
+#ifdef USE_GLOW_LEVEL1
+
+ glow+=GLOW_TEXTURE_SAMPLE(source_glow,uv_interp,1).rgb;
+#endif
+
+#ifdef USE_GLOW_LEVEL2
+ glow+=GLOW_TEXTURE_SAMPLE(source_glow,uv_interp,2).rgb;
+#endif
+
+#ifdef USE_GLOW_LEVEL3
+ glow+=GLOW_TEXTURE_SAMPLE(source_glow,uv_interp,3).rgb;
+#endif
+
+#ifdef USE_GLOW_LEVEL4
+ glow+=GLOW_TEXTURE_SAMPLE(source_glow,uv_interp,4).rgb;
+#endif
+
+#ifdef USE_GLOW_LEVEL5
+ glow+=GLOW_TEXTURE_SAMPLE(source_glow,uv_interp,5).rgb;
+#endif
+
+#ifdef USE_GLOW_LEVEL6
+ glow+=GLOW_TEXTURE_SAMPLE(source_glow,uv_interp,6).rgb;
+#endif
+
+#ifdef USE_GLOW_LEVEL7
+ glow+=GLOW_TEXTURE_SAMPLE(source_glow,uv_interp,7).rgb;
+#endif
+
+
+ glow *= glow_intensity;
+
+
+
+#ifdef USE_GLOW_REPLACE
+
+ color.rgb = glow;
+
+#endif
+
+#ifdef USE_GLOW_SCREEN
+
+ color.rgb = clamp((color.rgb + glow) - (color.rgb * glow), 0.0, 1.0);
+
+#endif
+
+#ifdef USE_GLOW_SOFTLIGHT
+
+ {
+
+ glow = (glow * 0.5) + 0.5;
+ color.r = (glow.r <= 0.5) ? (color.r - (1.0 - 2.0 * glow.r) * color.r * (1.0 - color.r)) : (((glow.r > 0.5) && (color.r <= 0.25)) ? (color.r + (2.0 * glow.r - 1.0) * (4.0 * color.r * (4.0 * color.r + 1.0) * (color.r - 1.0) + 7.0 * color.r)) : (color.r + (2.0 * glow.r - 1.0) * (sqrt(color.r) - color.r)));
+ color.g = (glow.g <= 0.5) ? (color.g - (1.0 - 2.0 * glow.g) * color.g * (1.0 - color.g)) : (((glow.g > 0.5) && (color.g <= 0.25)) ? (color.g + (2.0 * glow.g - 1.0) * (4.0 * color.g * (4.0 * color.g + 1.0) * (color.g - 1.0) + 7.0 * color.g)) : (color.g + (2.0 * glow.g - 1.0) * (sqrt(color.g) - color.g)));
+ color.b = (glow.b <= 0.5) ? (color.b - (1.0 - 2.0 * glow.b) * color.b * (1.0 - color.b)) : (((glow.b > 0.5) && (color.b <= 0.25)) ? (color.b + (2.0 * glow.b - 1.0) * (4.0 * color.b * (4.0 * color.b + 1.0) * (color.b - 1.0) + 7.0 * color.b)) : (color.b + (2.0 * glow.b - 1.0) * (sqrt(color.b) - color.b)));
+ }
+
+#endif
+
+#if !defined(USE_GLOW_SCREEN) && !defined(USE_GLOW_SOFTLIGHT) && !defined(USE_GLOW_REPLACE)
+ color.rgb+=glow;
+#endif
+
+
+#endif
+
+
+#ifdef USE_REINDHART_TONEMAPPER
+
+ {
+ color.rgb = ( color.rgb * ( 1.0 + ( color.rgb / ( white) ) ) ) / ( 1.0 + color.rgb );
+
+ }
+#endif
+
+#ifdef USE_FILMIC_TONEMAPPER
+
+ {
+
+ float A = 0.15;
+ float B = 0.50;
+ float C = 0.10;
+ float D = 0.20;
+ float E = 0.02;
+ float F = 0.30;
+ float W = 11.2;
+
+ vec3 coltn = ((color.rgb*(A*color.rgb+C*B)+D*E)/(color.rgb*(A*color.rgb+B)+D*F))-E/F;
+ float whitetn = ((white*(A*white+C*B)+D*E)/(white*(A*white+B)+D*F))-E/F;
+
+ color.rgb=coltn/whitetn;
+
+ }
+#endif
+
+#ifdef USE_ACES_TONEMAPPER
+
+ {
+ float a = 2.51f;
+ float b = 0.03f;
+ float c = 2.43f;
+ float d = 0.59f;
+ float e = 0.14f;
+ color.rgb = clamp((color.rgb*(a*color.rgb+b))/(color.rgb*(c*color.rgb+d)+e),vec3(0.0),vec3(1.0));
+ }
+
+#endif
+
+ //regular Linear -> SRGB conversion
+ vec3 a = vec3(0.055);
+ color.rgb = mix( (vec3(1.0)+a)*pow(color.rgb,vec3(1.0/2.4))-a , 12.92*color.rgb , lessThan(color.rgb,vec3(0.0031308)));
+
+
+
+
+ frag_color=vec4(color.rgb,1.0);
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+VERTEX_SHADER_GLOBALS
+MATERIAL_UNIFORMS
+VERTEX_SHADER_CODE
+FRAGMENT_SHADER_GLOBALS
+FRAGMENT_SHADER_CODE
+LIGHT_SHADER_CODE
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+layout(location=0) in highp vec2 vertex;
+layout(location=3) in vec4 color_attrib;
+
+#ifdef USE_TEXTURE_RECT
+
+layout(location=1) in highp vec4 dst_rect;
+layout(location=2) in highp vec4 src_rect;
+
+#else
+
+layout(location=4) in highp vec2 uv_attrib;
+
+//skeletn
+#endif
+
+
+layout(std140) uniform CanvasItemData { //ubo:0
+
+ highp mat4 projection_matrix;
+ highp vec4 time;
+};
+
+uniform highp mat4 modelview_matrix;
+uniform highp mat4 extra_matrix;
+
+
+out mediump vec2 uv_interp;
+out mediump vec4 color_interp;
+
+#ifdef USE_LIGHTING
+
+layout(std140) uniform LightData { //ubo:1
+
+ //light matrices
+ highp mat4 light_matrix;
+ highp mat4 light_local_matrix;
+ highp mat4 shadow_matrix;
+ highp vec4 light_color;
+ highp vec4 light_shadow_color;
+ highp vec2 light_pos;
+ highp float shadowpixel_size;
+ highp float shadow_gradient;
+ highp float light_height;
+ highp float light_outside_alpha;
+ highp float shadow_distance_mult;
+};
+
+
+out vec4 light_uv_interp;
+
+#if defined(NORMAL_USED)
+out vec4 local_rot;
+#endif
+
+#ifdef USE_SHADOWS
+out highp vec2 pos;
+#endif
+
+#endif
+
+
+VERTEX_SHADER_GLOBALS
+
+#if defined(USE_MATERIAL)
+
+layout(std140) uniform UniformData { //ubo:2
+
+MATERIAL_UNIFORMS
+
+};
+
+#endif
+
+void main() {
+
+ vec4 vertex_color = color_attrib;
+
+
+#ifdef USE_TEXTURE_RECT
+
+
+ uv_interp = src_rect.xy + abs(src_rect.zw) * vertex;
+ highp vec4 outvec = vec4(dst_rect.xy + dst_rect.zw * mix(vertex,vec2(1.0,1.0)-vertex,lessThan(src_rect.zw,vec2(0.0,0.0))),0.0,1.0);
+
+#else
+ uv_interp = uv_attrib;
+ highp vec4 outvec = vec4(vertex,0.0,1.0);
+#endif
+
+
+{
+ vec2 src_vtx=outvec.xy;
+
+VERTEX_SHADER_CODE
+
+}
+
+#if !defined(SKIP_TRANSFORM_USED)
+ outvec = extra_matrix * outvec;
+ outvec = modelview_matrix * outvec;
+#endif
+
+ color_interp = vertex_color;
+
+#ifdef USE_PIXEL_SNAP
+
+ outvec.xy=floor(outvec+0.5);
+#endif
+
+
+ gl_Position = projection_matrix * outvec;
+
+#ifdef USE_LIGHTING
+
+ light_uv_interp.xy = (light_matrix * outvec).xy;
+ light_uv_interp.zw =(light_local_matrix * outvec).xy;
+#ifdef USE_SHADOWS
+ pos=outvec.xy;
+#endif
+
+#if defined(NORMAL_USED)
+ local_rot.xy=normalize( (modelview_matrix * ( extra_matrix * vec4(1.0,0.0,0.0,0.0) )).xy );
+ local_rot.zw=normalize( (modelview_matrix * ( extra_matrix * vec4(0.0,1.0,0.0,0.0) )).xy );
+#ifdef USE_TEXTURE_RECT
+ local_rot.xy*=sign(src_rect.z);
+ local_rot.zw*=sign(src_rect.w);
+#endif
+
+#endif
+
+#endif
+
+}
+
+
+
+
+uniform mediump sampler2D color_texture; // texunit:0
+uniform highp vec2 color_texpixel_size;
+
+in mediump vec2 uv_interp;
+in mediump vec4 color_interp;
+
+
+#if defined(SCREEN_TEXTURE_USED)
+
+uniform sampler2D screen_texture; // texunit:-3
+
+#endif
+
+layout(std140) uniform CanvasItemData {
+
+ highp mat4 projection_matrix;
+ highp vec4 time;
+};
+
+
+#ifdef USE_LIGHTING
+
+layout(std140) uniform LightData {
+
+ highp mat4 light_matrix;
+ highp mat4 light_local_matrix;
+ highp mat4 shadow_matrix;
+ highp vec4 light_color;
+ highp vec4 light_shadow_color;
+ highp vec2 light_pos;
+ highp float shadowpixel_size;
+ highp float shadow_gradient;
+ highp float light_height;
+ highp float light_outside_alpha;
+ highp float shadow_distance_mult;
+};
+
+uniform lowp sampler2D light_texture; // texunit:-1
+in vec4 light_uv_interp;
+
+
+#if defined(NORMAL_USED)
+in vec4 local_rot;
+#endif
+
+#ifdef USE_SHADOWS
+
+uniform highp sampler2D shadow_texture; // texunit:-2
+in highp vec2 pos;
+
+#endif
+
+#endif
+
+uniform mediump vec4 final_modulate;
+
+FRAGMENT_SHADER_GLOBALS
+
+
+layout(location=0) out mediump vec4 frag_color;
+
+
+#if defined(USE_MATERIAL)
+
+layout(std140) uniform UniformData {
+
+MATERIAL_UNIFORMS
+
+};
+
+#endif
+
+void main() {
+
+ vec4 color = color_interp;
+#if defined(NORMAL_USED)
+ vec3 normal = vec3(0.0,0.0,1.0);
+#endif
+
+#if !defined(COLOR_USED)
+//default behavior, texture by color
+
+#ifdef USE_DISTANCE_FIELD
+ const float smoothing = 1.0/32.0;
+ float distance = texture(color_texture, uv_interp).a;
+ color.a = smoothstep(0.5 - smoothing, 0.5 + smoothing, distance) * color.a;
+#else
+ color *= texture( color_texture, uv_interp );
+
+#endif
+
+#endif
+
+#if defined(ENABLE_SCREEN_UV)
+ vec2 screen_uv = gl_FragCoord.xy*screen_uv_mult;
+#endif
+
+
+{
+ float normal_depth=1.0;
+
+#if defined(NORMALMAP_USED)
+ vec3 normal_map=vec3(0.0,0.0,1.0);
+#endif
+
+FRAGMENT_SHADER_CODE
+
+#if defined(NORMALMAP_USED)
+ normal = mix(vec3(0.0,0.0,1.0), normal_map * vec3(2.0,-2.0,1.0) - vec3( 1.0, -1.0, 0.0 ), normal_depth );
+#endif
+
+}
+#ifdef DEBUG_ENCODED_32
+ highp float enc32 = dot( color,highp vec4(1.0 / (256.0 * 256.0 * 256.0),1.0 / (256.0 * 256.0),1.0 / 256.0,1) );
+ color = vec4(vec3(enc32),1.0);
+#endif
+
+
+ color*=final_modulate;
+
+
+
+
+#ifdef USE_LIGHTING
+
+ vec2 light_vec = light_uv_interp.zw;; //for shadow and normal mapping
+
+#if defined(NORMAL_USED)
+ normal.xy = mat2(local_rot.xy,local_rot.zw) * normal.xy;
+#endif
+
+ float att=1.0;
+
+ vec2 light_uv = light_uv_interp.xy;
+ vec4 light = texture(light_texture,light_uv) * light_color;
+#if defined(SHADOW_COLOR_USED)
+ vec4 shadow_color=vec4(0.0,0.0,0.0,0.0);
+#endif
+
+ if (any(lessThan(light_uv_interp.xy,vec2(0.0,0.0))) || any(greaterThanEqual(light_uv_interp.xy,vec2(1.0,1.0)))) {
+ color.a*=light_outside_alpha; //invisible
+
+ } else {
+
+#if defined(USE_LIGHT_SHADER_CODE)
+//light is written by the light shader
+ {
+ vec4 light_out=light*color;
+LIGHT_SHADER_CODE
+ color=light_out;
+ }
+
+#else
+
+#if defined(NORMAL_USED)
+ vec3 light_normal = normalize(vec3(light_vec,-light_height));
+ light*=max(dot(-light_normal,normal),0.0);
+#endif
+
+ color*=light;
+/*
+#ifdef USE_NORMAL
+ color.xy=local_rot.xy;//normal.xy;
+ color.zw=vec2(0.0,1.0);
+#endif
+*/
+
+//light shader code
+#endif
+
+
+#ifdef USE_SHADOWS
+
+ float angle_to_light = -atan(light_vec.x,light_vec.y);
+ float PI = 3.14159265358979323846264;
+ /*int i = int(mod(floor((angle_to_light+7.0*PI/6.0)/(4.0*PI/6.0))+1.0, 3.0)); // +1 pq os indices estao em ordem 2,0,1 nos arrays
+ float ang*/
+
+ float su,sz;
+
+ float abs_angle = abs(angle_to_light);
+ vec2 point;
+ float sh;
+ if (abs_angle<45.0*PI/180.0) {
+ point = light_vec;
+ sh=0.0+(1.0/8.0);
+ } else if (abs_angle>135.0*PI/180.0) {
+ point = -light_vec;
+ sh = 0.5+(1.0/8.0);
+ } else if (angle_to_light>0.0) {
+
+ point = vec2(light_vec.y,-light_vec.x);
+ sh = 0.25+(1.0/8.0);
+ } else {
+
+ point = vec2(-light_vec.y,light_vec.x);
+ sh = 0.75+(1.0/8.0);
+
+ }
+
+
+ highp vec4 s = shadow_matrix * vec4(point,0.0,1.0);
+ s.xyz/=s.w;
+ su=s.x*0.5+0.5;
+ sz=s.z*0.5+0.5;
+ //sz=lightlength(light_vec);
+
+ highp float shadow_attenuation=0.0;
+
+#ifdef USE_RGBA_SHADOWS
+
+#define SHADOW_DEPTH(m_tex,m_uv) dot(texture2D((m_tex),(m_uv)),vec4(1.0 / (256.0 * 256.0 * 256.0),1.0 / (256.0 * 256.0),1.0 / 256.0,1) )
+
+#else
+
+#define SHADOW_DEPTH(m_tex,m_uv) (texture2D((m_tex),(m_uv)).r)
+
+#endif
+
+
+
+#ifdef SHADOW_USE_GRADIENT
+
+#define SHADOW_TEST(m_ofs) { highp float sd = SHADOW_DEPTH(shadow_texture,vec2(m_ofs,sh)); shadow_attenuation+=1.0-smoothstep(sd,sd+shadow_gradient,sz); }
+
+#else
+
+#define SHADOW_TEST(m_ofs) { highp float sd = SHADOW_DEPTH(shadow_texture,vec2(m_ofs,sh)); shadow_attenuation+=step(sz,sd); }
+
+#endif
+
+
+#ifdef SHADOW_FILTER_NEAREST
+
+ SHADOW_TEST(su+shadowpixel_size);
+
+#endif
+
+
+#ifdef SHADOW_FILTER_PCF3
+
+ SHADOW_TEST(su+shadowpixel_size);
+ SHADOW_TEST(su);
+ SHADOW_TEST(su-shadowpixel_size);
+ shadow_attenuation/=3.0;
+
+#endif
+
+
+#ifdef SHADOW_FILTER_PCF5
+
+ SHADOW_TEST(su+shadowpixel_size*3.0);
+ SHADOW_TEST(su+shadowpixel_size*2.0);
+ SHADOW_TEST(su+shadowpixel_size);
+ SHADOW_TEST(su);
+ SHADOW_TEST(su-shadowpixel_size);
+ SHADOW_TEST(su-shadowpixel_size*2.0);
+ SHADOW_TEST(su-shadowpixel_size*3.0);
+ shadow_attenuation/=5.0;
+
+#endif
+
+
+#ifdef SHADOW_FILTER_PCF9
+
+ SHADOW_TEST(su+shadowpixel_size*4.0);
+ SHADOW_TEST(su+shadowpixel_size*3.0);
+ SHADOW_TEST(su+shadowpixel_size*2.0);
+ SHADOW_TEST(su+shadowpixel_size);
+ SHADOW_TEST(su);
+ SHADOW_TEST(su-shadowpixel_size);
+ SHADOW_TEST(su-shadowpixel_size*2.0);
+ SHADOW_TEST(su-shadowpixel_size*3.0);
+ SHADOW_TEST(su-shadowpixel_size*4.0);
+ shadow_attenuation/=9.0;
+
+#endif
+
+#ifdef SHADOW_FILTER_PCF13
+
+ SHADOW_TEST(su+shadowpixel_size*6.0);
+ SHADOW_TEST(su+shadowpixel_size*5.0);
+ SHADOW_TEST(su+shadowpixel_size*4.0);
+ SHADOW_TEST(su+shadowpixel_size*3.0);
+ SHADOW_TEST(su+shadowpixel_size*2.0);
+ SHADOW_TEST(su+shadowpixel_size);
+ SHADOW_TEST(su);
+ SHADOW_TEST(su-shadowpixel_size);
+ SHADOW_TEST(su-shadowpixel_size*2.0);
+ SHADOW_TEST(su-shadowpixel_size*3.0);
+ SHADOW_TEST(su-shadowpixel_size*4.0);
+ SHADOW_TEST(su-shadowpixel_size*5.0);
+ SHADOW_TEST(su-shadowpixel_size*6.0);
+ shadow_attenuation/=13.0;
+
+#endif
+
+
+#if defined(SHADOW_COLOR_USED)
+ color=mix(shadow_color,color,shadow_attenuation);
+#else
+ //color*=shadow_attenuation;
+ color=mix(light_shadow_color,color,shadow_attenuation);
+#endif
+//use shadows
+#endif
+ }
+
+//use lighting
+#endif
+ //color.rgb*=color.a;
+ frag_color = color;
+
+}
+
+
+
+
+uniform highp mat4 projection_matrix;
+uniform highp mat4 light_matrix;
+uniform highp mat4 world_matrix;
+uniform highp float distance_norm;
+
+layout(location=0) in highp vec3 vertex;
+
+out highp vec4 position_interp;
+
+void main() {
+
+ gl_Position = projection_matrix * (light_matrix * (world_matrix * vec4(vertex,1.0)));
+ position_interp=gl_Position;
+}
+
+
+in highp vec4 position_interp;
+
+#ifdef USE_RGBA_SHADOWS
+
+layout(location=0) out lowp vec4 distance_buf;
+
+#else
+
+layout(location=0) out highp float distance_buf;
+
+#endif
+
+void main() {
+
+ highp float depth = ((position_interp.z / position_interp.w) + 1.0) * 0.5 + 0.0;//bias;
+
+#ifdef USE_RGBA_SHADOWS
+
+ highp vec4 comp = fract(depth * vec4(256.0 * 256.0 * 256.0, 256.0 * 256.0, 256.0, 1.0));
+ comp -= comp.xxyz * vec4(0, 1.0 / 256.0, 1.0 / 256.0, 1.0 / 256.0);
+ distance_buf=comp;
+#else
+
+ distance_buf=depth;
+
+#endif
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+layout(location=0) in highp vec4 vertex_attrib;
+#ifdef USE_CUBEMAP
+layout(location=4) in vec3 cube_in;
+#else
+layout(location=4) in vec2 uv_in;
+#endif
+layout(location=5) in vec2 uv2_in;
+
+#ifdef USE_CUBEMAP
+out vec3 cube_interp;
+#else
+out vec2 uv_interp;
+#endif
+
+out vec2 uv2_interp;
+
+void main() {
+
+#ifdef USE_CUBEMAP
+ cube_interp = cube_in;
+#else
+ uv_interp = uv_in;
+#endif
+ uv2_interp = uv2_in;
+ gl_Position = vertex_attrib;
+}
+
+
+
+#ifdef USE_CUBEMAP
+in vec3 cube_interp;
+uniform samplerCube source_cube; //texunit:0
+#else
+in vec2 uv_interp;
+uniform sampler2D source; //texunit:0
+#endif
+
+
+float sRGB_gamma_correct(float c){
+ float a = 0.055;
+ if(c < 0.0031308)
+ return 12.92*c;
+ else
+ return (1.0+a)*pow(c, 1.0/2.4) - a;
+}
+
+
+uniform float stuff;
+uniform vec2 pixel_size;
+
+in vec2 uv2_interp;
+
+layout(location = 0) out vec4 frag_color;
+
+void main() {
+
+ //vec4 color = color_interp;
+
+#ifdef USE_CUBEMAP
+ vec4 color = texture( source_cube, normalize(cube_interp) );
+
+#else
+ vec4 color = texture( source, uv_interp );
+#endif
+
+#ifdef LINEAR_TO_SRGB
+ //regular Linear -> SRGB conversion
+ vec3 a = vec3(0.055);
+ color.rgb = mix( (vec3(1.0)+a)*pow(color.rgb,vec3(1.0/2.4))-a , 12.92*color.rgb , lessThan(color.rgb,vec3(0.0031308)));
+#endif
+
+#ifdef DEBUG_GRADIENT
+ color.rg=uv_interp;
+ color.b=0.0;
+#endif
+
+#ifdef DISABLE_ALPHA
+ color.a=1.0;
+#endif
+
+
+#ifdef GAUSSIAN_HORIZONTAL
+ color*=0.38774;
+ color+=texture( source, uv_interp+vec2( 1.0, 0.0)*pixel_size )*0.24477;
+ color+=texture( source, uv_interp+vec2( 2.0, 0.0)*pixel_size )*0.06136;
+ color+=texture( source, uv_interp+vec2(-1.0, 0.0)*pixel_size )*0.24477;
+ color+=texture( source, uv_interp+vec2(-2.0, 0.0)*pixel_size )*0.06136;
+#endif
+
+#ifdef GAUSSIAN_VERTICAL
+ color*=0.38774;
+ color+=texture( source, uv_interp+vec2( 0.0, 1.0)*pixel_size )*0.24477;
+ color+=texture( source, uv_interp+vec2( 0.0, 2.0)*pixel_size )*0.06136;
+ color+=texture( source, uv_interp+vec2( 0.0,-1.0)*pixel_size )*0.24477;
+ color+=texture( source, uv_interp+vec2( 0.0,-2.0)*pixel_size )*0.06136;
+#endif
+
+
+ frag_color = color;
+}
+
+
+
+/*
+from VisualServer:
+
+ARRAY_VERTEX=0,
+ARRAY_NORMAL=1,
+ARRAY_TANGENT=2,
+ARRAY_COLOR=3,
+ARRAY_TEX_UV=4,
+ARRAY_TEX_UV2=5,
+ARRAY_BONES=6,
+ARRAY_WEIGHTS=7,
+ARRAY_INDEX=8,
+*/
+
+#ifdef USE_2D_VERTEX
+#define VFORMAT vec2
+#else
+#define VFORMAT vec3
+#endif
+
+/* INPUT ATTRIBS */
+
+layout(location=0) in highp VFORMAT vertex_attrib;
+layout(location=1) in vec3 normal_attrib;
+
+#ifdef ENABLE_TANGENT
+layout(location=2) in vec4 tangent_attrib;
+#endif
+
+#ifdef ENABLE_COLOR
+layout(location=3) in vec4 color_attrib;
+#endif
+
+#ifdef ENABLE_UV
+layout(location=4) in vec2 uv_attrib;
+#endif
+
+#ifdef ENABLE_UV2
+layout(location=5) in vec2 uv2_attrib;
+#endif
+
+#ifdef ENABLE_SKELETON
+layout(location=6) in ivec4 bone_attrib;
+layout(location=7) in vec4 weight_attrib;
+#endif
+
+/* BLEND ATTRIBS */
+
+#ifdef ENABLE_BLEND
+
+layout(location=8) in highp VFORMAT vertex_attrib_blend;
+layout(location=9) in vec3 normal_attrib_blend;
+
+#ifdef ENABLE_TANGENT
+layout(location=10) in vec4 tangent_attrib_blend;
+#endif
+
+#ifdef ENABLE_COLOR
+layout(location=11) in vec4 color_attrib_blend;
+#endif
+
+#ifdef ENABLE_UV
+layout(location=12) in vec2 uv_attrib_blend;
+#endif
+
+#ifdef ENABLE_UV2
+layout(location=13) in vec2 uv2_attrib_blend;
+#endif
+
+#ifdef ENABLE_SKELETON
+layout(location=14) in ivec4 bone_attrib_blend;
+layout(location=15) in vec4 weight_attrib_blend;
+#endif
+
+#endif
+
+/* OUTPUTS */
+
+out VFORMAT vertex_out; //tfb:
+
+#ifdef ENABLE_NORMAL
+out vec3 normal_out; //tfb:ENABLE_NORMAL
+#endif
+
+#ifdef ENABLE_TANGENT
+out vec4 tangent_out; //tfb:ENABLE_TANGENT
+#endif
+
+#ifdef ENABLE_COLOR
+out vec4 color_out; //tfb:ENABLE_COLOR
+#endif
+
+#ifdef ENABLE_UV
+out vec2 uv_out; //tfb:ENABLE_UV
+#endif
+
+#ifdef ENABLE_UV2
+out vec2 uv2_out; //tfb:ENABLE_UV2
+#endif
+
+#ifdef ENABLE_SKELETON
+out ivec4 bone_out; //tfb:ENABLE_SKELETON
+out vec4 weight_out; //tfb:ENABLE_SKELETON
+#endif
+
+uniform float blend_amount;
+
+void main() {
+
+
+#ifdef ENABLE_BLEND
+
+ vertex_out = vertex_attrib_blend + vertex_attrib * blend_amount;
+
+#ifdef ENABLE_NORMAL
+ normal_out = normal_attrib_blend + normal_attrib * blend_amount;
+#endif
+
+#ifdef ENABLE_TANGENT
+
+ tangent_out.xyz = tangent_attrib_blend.xyz + tangent_attrib.xyz * blend_amount;
+ tangent_out.w = tangent_attrib_blend.w; //just copy, no point in blending his
+#endif
+
+#ifdef ENABLE_COLOR
+
+ color_out = color_attrib_blend + color_attrib * blend_amount;
+#endif
+
+#ifdef ENABLE_UV
+
+ uv_out = uv_attrib_blend + uv_attrib * blend_amount;
+#endif
+
+#ifdef ENABLE_UV2
+
+ uv2_out = uv2_attrib_blend + uv2_attrib * blend_amount;
+#endif
+
+
+#ifdef ENABLE_SKELETON
+
+ bone_out = bone_attrib_blend;
+ weight_out = weight_attrib_blend + weight_attrib * blend_amount;
+#endif
+
+#else //ENABLE_BLEND
+
+
+ vertex_out = vertex_attrib * blend_amount;
+
+#ifdef ENABLE_NORMAL
+ normal_out = normal_attrib * blend_amount;
+#endif
+
+#ifdef ENABLE_TANGENT
+
+ tangent_out.xyz = tangent_attrib.xyz * blend_amount;
+ tangent_out.w = tangent_attrib.w; //just copy, no point in blending his
+#endif
+
+#ifdef ENABLE_COLOR
+
+ color_out = color_attrib * blend_amount;
+#endif
+
+#ifdef ENABLE_UV
+
+ uv_out = uv_attrib * blend_amount;
+#endif
+
+#ifdef ENABLE_UV2
+
+ uv2_out = uv2_attrib * blend_amount;
+#endif
+
+
+#ifdef ENABLE_SKELETON
+
+ bone_out = bone_attrib;
+ weight_out = weight_attrib * blend_amount;
+#endif
+
+#endif
+ gl_Position = vec4(0.0);
+}
+
+
+
+void main() {
+
+}
+
+
+
+layout(location=0) in highp vec2 vertex;
+
+layout(location=4) in highp vec2 uv;
+
+out highp vec2 uv_interp;
+
+void main() {
+
+ uv_interp=uv;
+ gl_Position=vec4(vertex,0,1);
+}
+
+
+
+precision highp float;
+precision highp int;
+
+
+uniform samplerCube source_cube; //texunit:0
+uniform int face_id;
+uniform float roughness;
+in highp vec2 uv_interp;
+
+
+layout(location = 0) out vec4 frag_color;
+
+
+#define M_PI 3.14159265359
+
+
+vec3 texelCoordToVec(vec2 uv, int faceID)
+{
+ mat3 faceUvVectors[6];
+/*
+ // -x
+ faceUvVectors[1][0] = vec3(0.0, 0.0, 1.0); // u -> +z
+ faceUvVectors[1][1] = vec3(0.0, -1.0, 0.0); // v -> -y
+ faceUvVectors[1][2] = vec3(-1.0, 0.0, 0.0); // -x face
+
+ // +x
+ faceUvVectors[0][0] = vec3(0.0, 0.0, -1.0); // u -> -z
+ faceUvVectors[0][1] = vec3(0.0, -1.0, 0.0); // v -> -y
+ faceUvVectors[0][2] = vec3(1.0, 0.0, 0.0); // +x face
+
+ // -y
+ faceUvVectors[3][0] = vec3(1.0, 0.0, 0.0); // u -> +x
+ faceUvVectors[3][1] = vec3(0.0, 0.0, -1.0); // v -> -z
+ faceUvVectors[3][2] = vec3(0.0, -1.0, 0.0); // -y face
+
+ // +y
+ faceUvVectors[2][0] = vec3(1.0, 0.0, 0.0); // u -> +x
+ faceUvVectors[2][1] = vec3(0.0, 0.0, 1.0); // v -> +z
+ faceUvVectors[2][2] = vec3(0.0, 1.0, 0.0); // +y face
+
+ // -z
+ faceUvVectors[5][0] = vec3(-1.0, 0.0, 0.0); // u -> -x
+ faceUvVectors[5][1] = vec3(0.0, -1.0, 0.0); // v -> -y
+ faceUvVectors[5][2] = vec3(0.0, 0.0, -1.0); // -z face
+
+ // +z
+ faceUvVectors[4][0] = vec3(1.0, 0.0, 0.0); // u -> +x
+ faceUvVectors[4][1] = vec3(0.0, -1.0, 0.0); // v -> -y
+ faceUvVectors[4][2] = vec3(0.0, 0.0, 1.0); // +z face
+*/
+
+ // -x
+ faceUvVectors[0][0] = vec3(0.0, 0.0, 1.0); // u -> +z
+ faceUvVectors[0][1] = vec3(0.0, -1.0, 0.0); // v -> -y
+ faceUvVectors[0][2] = vec3(-1.0, 0.0, 0.0); // -x face
+
+ // +x
+ faceUvVectors[1][0] = vec3(0.0, 0.0, -1.0); // u -> -z
+ faceUvVectors[1][1] = vec3(0.0, -1.0, 0.0); // v -> -y
+ faceUvVectors[1][2] = vec3(1.0, 0.0, 0.0); // +x face
+
+ // -y
+ faceUvVectors[2][0] = vec3(1.0, 0.0, 0.0); // u -> +x
+ faceUvVectors[2][1] = vec3(0.0, 0.0, -1.0); // v -> -z
+ faceUvVectors[2][2] = vec3(0.0, -1.0, 0.0); // -y face
+
+ // +y
+ faceUvVectors[3][0] = vec3(1.0, 0.0, 0.0); // u -> +x
+ faceUvVectors[3][1] = vec3(0.0, 0.0, 1.0); // v -> +z
+ faceUvVectors[3][2] = vec3(0.0, 1.0, 0.0); // +y face
+
+ // -z
+ faceUvVectors[4][0] = vec3(-1.0, 0.0, 0.0); // u -> -x
+ faceUvVectors[4][1] = vec3(0.0, -1.0, 0.0); // v -> -y
+ faceUvVectors[4][2] = vec3(0.0, 0.0, -1.0); // -z face
+
+ // +z
+ faceUvVectors[5][0] = vec3(1.0, 0.0, 0.0); // u -> +x
+ faceUvVectors[5][1] = vec3(0.0, -1.0, 0.0); // v -> -y
+ faceUvVectors[5][2] = vec3(0.0, 0.0, 1.0); // +z face
+
+ // out = u * s_faceUv[0] + v * s_faceUv[1] + s_faceUv[2].
+ vec3 result = (faceUvVectors[faceID][0] * uv.x) + (faceUvVectors[faceID][1] * uv.y) + faceUvVectors[faceID][2];
+ return normalize(result);
+}
+
+vec3 ImportanceSampleGGX(vec2 Xi, float Roughness, vec3 N)
+{
+ float a = Roughness * Roughness; // DISNEY'S ROUGHNESS [see Burley'12 siggraph]
+
+ // Compute distribution direction
+ float Phi = 2.0 * M_PI * Xi.x;
+ float CosTheta = sqrt((1.0 - Xi.y) / (1.0 + (a*a - 1.0) * Xi.y));
+ float SinTheta = sqrt(1.0 - CosTheta * CosTheta);
+
+ // Convert to spherical direction
+ vec3 H;
+ H.x = SinTheta * cos(Phi);
+ H.y = SinTheta * sin(Phi);
+ H.z = CosTheta;
+
+ vec3 UpVector = abs(N.z) < 0.999 ? vec3(0.0, 0.0, 1.0) : vec3(1.0, 0.0, 0.0);
+ vec3 TangentX = normalize(cross(UpVector, N));
+ vec3 TangentY = cross(N, TangentX);
+
+ // Tangent to world space
+ return TangentX * H.x + TangentY * H.y + N * H.z;
+}
+
+// http://graphicrants.blogspot.com.au/2013/08/specular-brdf-reference.html
+float GGX(float NdotV, float a)
+{
+ float k = a / 2.0;
+ return NdotV / (NdotV * (1.0 - k) + k);
+}
+
+// http://graphicrants.blogspot.com.au/2013/08/specular-brdf-reference.html
+float G_Smith(float a, float nDotV, float nDotL)
+{
+ return GGX(nDotL, a * a) * GGX(nDotV, a * a);
+}
+
+float radicalInverse_VdC(uint bits) {
+ bits = (bits << 16u) | (bits >> 16u);
+ bits = ((bits & 0x55555555u) << 1u) | ((bits & 0xAAAAAAAAu) >> 1u);
+ bits = ((bits & 0x33333333u) << 2u) | ((bits & 0xCCCCCCCCu) >> 2u);
+ bits = ((bits & 0x0F0F0F0Fu) << 4u) | ((bits & 0xF0F0F0F0u) >> 4u);
+ bits = ((bits & 0x00FF00FFu) << 8u) | ((bits & 0xFF00FF00u) >> 8u);
+ return float(bits) * 2.3283064365386963e-10; // / 0x100000000
+}
+
+vec2 Hammersley(uint i, uint N) {
+ return vec2(float(i)/float(N), radicalInverse_VdC(i));
+}
+
+
+
+#ifdef LOW_QUALITY
+
+#define SAMPLE_COUNT 64u
+
+#else
+
+#define SAMPLE_COUNT 512u
+
+#endif
+
+uniform bool z_flip;
+
+void main() {
+
+#ifdef USE_DUAL_PARABOLOID
+
+ vec3 N = vec3( uv_interp * 2.0 - 1.0, 0.0 );
+ N.z = 0.5 - 0.5*((N.x * N.x) + (N.y * N.y));
+ N = normalize(N);
+
+ if (!z_flip) {
+ N.y=-N.y; //y is flipped to improve blending between both sides
+ } else {
+ N.z=-N.z;
+ }
+
+
+#else
+ vec2 uv = (uv_interp * 2.0) - 1.0;
+ vec3 N = texelCoordToVec(uv, face_id);
+#endif
+ //vec4 color = color_interp;
+
+#ifdef USE_DIRECT_WRITE
+
+ frag_color=vec4(texture(N,source_cube).rgb,1.0);
+
+#else
+
+ vec4 sum = vec4(0.0, 0.0, 0.0, 0.0);
+
+ for(uint sampleNum = 0u; sampleNum < SAMPLE_COUNT; sampleNum++) {
+ vec2 xi = Hammersley(sampleNum, SAMPLE_COUNT);
+
+ vec3 H = ImportanceSampleGGX( xi, roughness, N );
+ vec3 V = N;
+ vec3 L = normalize(2.0 * dot( V, H ) * H - V);
+
+ float ndotl = clamp(dot(N, L),0.0,1.0);
+
+ if (ndotl>0.0) {
+ sum.rgb += textureLod(source_cube, H, 0.0).rgb *ndotl;
+ sum.a += ndotl;
+ }
+ }
+ sum /= sum.a;
+
+ frag_color = vec4(sum.rgb, 1.0);
+
+#endif
+
+}
+
+
+
+
+layout(location=0) in highp vec4 color;
+layout(location=1) in highp vec4 velocity_active;
+layout(location=2) in highp vec4 custom;
+layout(location=3) in highp vec4 xform_1;
+layout(location=4) in highp vec4 xform_2;
+layout(location=5) in highp vec4 xform_3;
+
+
+struct Attractor {
+
+ vec3 pos;
+ vec3 dir;
+ float radius;
+ float eat_radius;
+ float strength;
+ float attenuation;
+};
+
+#define MAX_ATTRACTORS 64
+
+uniform bool emitting;
+uniform float system_phase;
+uniform float prev_system_phase;
+uniform int total_particles;
+uniform float explosiveness;
+uniform float randomness;
+uniform vec4 time;
+uniform float delta;
+
+uniform int attractor_count;
+uniform Attractor attractors[MAX_ATTRACTORS];
+uniform bool clear;
+uniform uint cycle;
+uniform float lifetime;
+uniform mat4 emission_transform;
+
+
+out highp vec4 out_color; //tfb:
+out highp vec4 out_velocity_active; //tfb:
+out highp vec4 out_custom; //tfb:
+out highp vec4 out_xform_1; //tfb:
+out highp vec4 out_xform_2; //tfb:
+out highp vec4 out_xform_3; //tfb:
+
+VERTEX_SHADER_GLOBALS
+
+#if defined(USE_MATERIAL)
+
+layout(std140) uniform UniformData { //ubo:0
+
+MATERIAL_UNIFORMS
+
+};
+
+#endif
+
+uint hash(uint x) {
+
+ x = ((x >> uint(16)) ^ x) * uint(0x45d9f3b);
+ x = ((x >> uint(16)) ^ x) * uint(0x45d9f3b);
+ x = (x >> uint(16)) ^ x;
+ return x;
+}
+
+
+void main() {
+
+#ifdef PARTICLES_COPY
+
+ out_color=color;
+ out_velocity_active=velocity_active;
+ out_custom = custom;
+ out_xform_1 = xform_1;
+ out_xform_2 = xform_2;
+ out_xform_3 = xform_3;
+
+#else
+
+ bool apply_forces=true;
+ bool apply_velocity=true;
+ float local_delta=delta;
+
+ float mass = 1.0;
+
+ float restart_phase = float(gl_VertexID)/float(total_particles);
+
+ if (randomness>0.0) {
+ uint seed = cycle;
+ if (restart_phase >= system_phase) {
+ seed-=uint(1);
+ }
+ seed*=uint(total_particles);
+ seed+=uint(gl_VertexID);
+ float random = float(hash(seed) % uint(65536)) / 65536.0;
+ restart_phase+=randomness * random * 1.0 / float(total_particles);
+ }
+
+ restart_phase*= (1.0-explosiveness);
+ bool restart=false;
+ bool shader_active = velocity_active.a > 0.5;
+
+ if (system_phase > prev_system_phase) {
+ if (prev_system_phase < restart_phase && system_phase >= restart_phase) {
+ restart=true;
+#ifdef USE_FRACTIONAL_DELTA
+ local_delta = (system_phase - restart_phase) * lifetime;
+#endif
+ }
+
+ } else {
+ if (prev_system_phase < restart_phase) {
+ restart=true;
+#ifdef USE_FRACTIONAL_DELTA
+ local_delta = (1.0 - restart_phase + system_phase) * lifetime;
+#endif
+ } else if (system_phase >= restart_phase) {
+ restart=true;
+#ifdef USE_FRACTIONAL_DELTA
+ local_delta = (system_phase - restart_phase) * lifetime;
+#endif
+ }
+ }
+
+ uint current_cycle = cycle;
+
+ if (system_phase < restart_phase) {
+ current_cycle-=uint(1);
+ }
+
+ uint particle_number = current_cycle * uint(total_particles) + uint(gl_VertexID);
+
+ if (restart) {
+ shader_active=emitting;
+ }
+
+ mat4 xform;
+
+#if defined(ENABLE_KEEP_DATA)
+ if (clear) {
+#else
+ if (clear || restart) {
+#endif
+ out_color=vec4(1.0);
+ out_velocity_active=vec4(0.0);
+ out_custom=vec4(0.0);
+ if (!restart)
+ shader_active=false;
+
+ xform = mat4(
+ vec4(1.0,0.0,0.0,0.0),
+ vec4(0.0,1.0,0.0,0.0),
+ vec4(0.0,0.0,1.0,0.0),
+ vec4(0.0,0.0,0.0,1.0)
+ );
+ } else {
+ out_color=color;
+ out_velocity_active=velocity_active;
+ out_custom=custom;
+ xform = transpose(mat4(xform_1,xform_2,xform_3,vec4(vec3(0.0),1.0)));
+ }
+
+ if (shader_active) {
+ //execute shader
+
+ {
+VERTEX_SHADER_CODE
+ }
+
+#if !defined(DISABLE_FORCE)
+
+ if (true) {
+
+ vec3 force = vec3(0.0);
+ for(int i=0;i<attractor_count;i++) {
+
+ vec3 rel_vec = xform[3].xyz - attractors[i].pos;
+ float dist = length(rel_vec);
+ if (attractors[i].radius < dist)
+ continue;
+ if (attractors[i].eat_radius>0 && attractors[i].eat_radius > dist) {
+ out_velocity_active.a=0.0;
+ }
+
+ rel_vec = normalize(rel_vec);
+
+ float attenuation = pow(dist / attractors[i].radius,attractors[i].attenuation);
+
+ if (attractors[i].dir==vec3(0.0)) {
+ //towards center
+ force+=attractors[i].strength * rel_vec * attenuation * mass;
+ } else {
+ force+=attractors[i].strength * attractors[i].dir * attenuation *mass;
+
+ }
+ }
+
+ out_velocity_active.xyz += force * local_delta;
+ }
+#endif
+
+#if !defined(DISABLE_VELOCITY)
+
+ if (true) {
+
+ xform[3].xyz += out_velocity_active.xyz * local_delta;
+ }
+#endif
+ } else {
+ xform=mat4(0.0);
+ }
+
+ xform = transpose(xform);
+
+ out_velocity_active.a = mix(0.0,1.0,shader_active);
+
+ out_xform_1 = xform[0];
+ out_xform_2 = xform[1];
+ out_xform_3 = xform[2];
+
+#endif //PARTICLES_COPY
+
+}
+
+
+//any code here is never executed, stuff is filled just so it works
+
+FRAGMENT_SHADER_GLOBALS
+
+#if defined(USE_MATERIAL)
+
+layout(std140) uniform UniformData {
+
+MATERIAL_UNIFORMS
+
+};
+
+#endif
+
+void main() {
+
+ {
+FRAGMENT_SHADER_CODE
+ }
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+   in use by IDAT
+JZ*j:zN^.n>~CS#c3sGW'g7w K[+k;{O_/o?
+*:JZjz +;K[k{ ,<L\l| -=M]m}.>N^n~/?O_o
+J*jZ:zF&fV6vN.n^>~A!aQ1q I)iY9yE%eU5u M-m]=}C#cS3s K+k[;{G'gW7wO/o_?Valid palette required for paletted images
+
+Can't set both read_data_fn and write_data_fn in the same structure
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+render_mode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+LMB: Set color
+RMB: Remove preset
+
+
+"(V "(  ""җ9ardf2woϳ799I$'0K-JhмU:gy__Xz7N
+^~<^|w+vp#p2k?e}b STOw#_ U}~ߋ=׿FW\c'Qd ]P!؃
+d:mw F*(^
+<(QR DbusT nЧs܇xs k@ɡ ,0
+y^sh>ev*K"_GRK |70jZxxUpʬ0> X)?Y_] <;-*O{wБ!Q=P9ZR|] uv>;O"
+e%]);¾^_|.D-=>2
+GZnc
+`8d۷@^/w' 99p"b[*HW? `}LH
+#DaQ%0F]є0c}J)B@OA϶۬žNks3|.[Ơh oJCOmЗ:<]+_Ne#jHK<{ %"&9l!S@AɝH^m{9񊻨O :CNC{[l+U9
+|$WdO_8Xp2?Y1-6#FyK"N
+<x44rb-X\*xHt
+~_wrJKK7^`BgnA#Y^ئC@Ȱ
+|@bD8?
+y
+- ownNpeJ~ر}UK
+[ډiiH
+nA#
+1u]x_$m
+BiS
+A DRZ͵}pE DD#EL~]+
+2!\D.,@@P *AA<aG,+_rlQ(é;P*
+~S94x{m\cum 
+tR'U<+,QgG1`x
+*K^6ȣcv u Vmi\Ar4VH<'3̾w[k1`DWCb$b3@(2` x{oeQ4A- f{F2d*͞zEkobhm婳ƛ5:0r"_FY,xln
+5eZaEWwjG9K]`+|CĚq&òΤcȄ"ȿgxNѺo)
+p|M`_?;ͽs R<{_8 !g]ntWz|*؀^ZOvpSfz6Kh/&:=*-óS}RJ [R[6Rڭ;~NMqvU[ޢJ
+ִDֆz۷S?O]AmeIIn6<\4ZڣBg_p &QW!ꋎXɣz!ަ(MP(Z/%W\>;z)@k'(wM:*xU,}&iqq
+a-k4݊@pfev
+4i(b6rr&q#!{NP#A
+3Le1մ}1毞zQ(3KSɵ1 Kc1Kc˲JN=ֿYd@QrȲYoe:Y-eJY=˲;#
+;;/2_6XKwkr 9FD^ɲc{1Ocv1LI{ddɹ1Ac̎Y}e.i}_ǘb
+w[6M.8\r)!ف'd:(uo}48q%;2
+Řbt,C*6S,͒N΢䘋ǹ:e}'cS'0}NJ"owME7[&Vp:y#&L~{N6-7Kxm+xDr1@!\7@ʡS(q7vhZ^@.| lS_ T0.Dp "Q+0Qg8lŠ]pXW_ ɅE(Dr<Z_ہc[w7!Wz1aZ~E Jc-%B~::G=/"
+9FiGї%Ss+f" GO1Agk]m0Ld0XP!6܂VAF-?! E\By.g/^AUuyr=uoֺa6%9Ů"+(1mA"AJeK2eեWm.bo}#b9'
+>ED4, 1[T$ [k=fʹnmvD>  mmC@iQp
+-l'K_Ene9 u~ *ҸGtv߹
+["!= |YbnD>-]&`=QH)1h2N
+'e\
+1J4{}.@7#(\I8Zۋ_%
+{aqUm.zE5@Y*pV*c{2«,yA҉+h(j57(u-<֊;> kk
+q¤  =+'Yp/] 9fx1ƹBZsMs\#s~}^JVDh%j gv_uٟL3𒐽BS[LVDRjK >` 
+5Sf5c._%`<RL J NciVA(Ug"fߣ\
+ŨtNȿAYJZ7@
+Dlr:5J+d_
+
+S) 8<UO2A#ލ8@ mC<]Sg'd
+D<ݠ8+ t,Կ1gZ!򕾵x?`YHy Y7)9
+Y){)r4&A±;bWί(%|?nȣJjgi%T3kx+κ%}׎70V" 
+uc4cjƘ*C[|cE{{[wm4Oa؀tpY8ncF!=Q@׫Բ'蘯+tLIǸvt_AtT54x"
+`VXظrW: R-܎^9 W +6=Afvt_At;Hk~Mu
+Au
+X
+~ iY(59kT+/*7s]S>?`SUz"إQ,oOݘ!<ChiE!׍}}f4kC5Uߟ|Y* k1
+'c-[dY61Gh909}UWk9(HcFl4akZXY|3P
+gYv[Ƙoc7ƬnNLcY=ܮ@ڥJwOݘ+ )N>@SނQ"[/9p
+:ޔGZ)n*A# Kvo OY
+)^ 8
+oeZXs`\k5Ȯ9e㘓"'+a? )tfGנ
+`_Y
+>OXiwl[/, E?B
+>0-r:Բ}Sߩ[
+ 2K2Iݸ#_YR2@OaÝg*"P@ٿH'$$QA9"QG433kʍN
+
+D|}&,q+_Jr,9 Y
+
+ݥN8pꂿ҆b,k9'`ϟQRoZ%\@&ʷR
+!UUi7~,%W]CnxC|_5}$O8ϲxm
+ÒH>mENM2%=YlQ(_؛{䇜΀(1,Lrӧơb$K,6
+8ƛs1f1f,˂Rhks,0+
+6cє׶W»C
+
+QvҝZ ~ru!b|cP+n!`0 ٷ
+t$` -y} ơ8C6`P6,ڸEiא/;T?V!nT̀o,g zюgkXr˭
+v2Aɽ@722]k"ME%`A}.rjvl|LnI21:f̎
+M#g67mK^4mҲ߫)EEA (X><
+$VBw&-Cd"rk[i_`+v(kɅË<u6 Z_*<69JTc2Dy.Vb _{/E
+2l[G=Q
+%yЀ(*q꟡Ymv3CiKc2|*1U-6~@#%,8;]:7;eېvgSpRȿXua댨5e rO"Զz +Kq̀[`N8?դݗmծŻSc~݀<E,Q4tQ:`I[+W-o|ڠfhky7->>/U=5@t^l >Z_+|:cK,{$6Zҵid]yJwWj팡o9\ :g}P?ď
+RݔiK` - T(yt`}Oۥ=.Fu^Da?&9
+ tS_l܈R
+qB,luQ6 ! ұ^ψ}^bc!Pe?˩["p`]D׹G)k!{x7XDȡk,
+-S+98B]\C.zأ8^{K;~ӮN{5 ~"6Vk/{-Sz$': R`9sm\1Dp'>|~{hq͏(
+v8vt&y-
+
+ 2~c =TODWeq-Z
+ˑ6V
+Pcsxd&Sg@6v]VKYwqdմ&ǎ}1g*
+
+R!@Eؾ̩.
+WE
+ddU$;hT"$xɗɓ(|DgT8!'ʜ:~-$D!0`sv
+eZ[ >bw@-]/j4YUxVy
+hHZT*<\gBp <b:=cøj;dI=`PѮ</-:Q
+e Ҷ1rj i|K
+74R蓋%2+c+17@nwۍwJQ
+gfĄxT|ћ%]>;8=@*J־Ws([ _lz2mX}rQ J;?Lb1fOcS5;1n"1gY)_e Ə)dYG/>)ɲl1{Ƙ9j,8$!Je[մ]Ap~rcLƌFS
+5hҬoEXG- 
+l<6A4!
+$JP$I-Wb0 = >iJ}Nݓm7XքӦ1] W<ŞvQe硳P^ӟ38@9+JN 
+::85lÚB`AO> @ ƆkW
+P2YLRy"  A&
+pe10cdc 5]Y=1pY X)fYt<e
+]4quL c6q~?.6eײ,1fa0dY'\¨
+P/Z1ߛ7wPswQT94K'J
+mjѰ;k+2D#"
+gᶭ" ^_XBD)ѿF Uػdx 0fYֈR#RFEbt#)I 1myG9:*ߠ-ofJ
+GS3_7\`dCkkoM04^
+ɮ҆T<Wb/@@_ z
+
+
+PA)*tjP. !>?zs3gys{s3e2{ն4Qb
+zOdGھ]E;"
+y'a
+'7
+|ypW
+)6T1|~,k}%}p٠L- 25WH,w~q2űi?pv
+꺐-!wo3 g{4OV^\ID6((7ȔZCqn*R.8cp=@ 㬀=1)u8?^ SOņ0rCAHɝ|]L;e2ˁShK|]eryL*
+lʸڏK/M),bY<-+__Ɩ cstC a]M:ǡ 4lg>bEuV3se1L#V4TGW쓨57™ӘT> x
+!Bx>pl7$}\'* $Mz”o%m%i)IG5
+YyξIl4pc|uڟ쯔.\/Vɜ/Rթ ;)C8:Z91Hi lυshn!˫`κC
+`>̂:3
+cϷ!_ށ)woCm$Xcۘouҙ|X@WfNKهe
+T='Ot
+"[`Zg+yEm
+n +K4'0߁BpE#$sS*00BJ[#
+U+.]
+3,_6
+hs 0-˭Ҙ߰5"زHy3a (MA7tf
+cBS$Vg9DW1Wz,2w I?mXzDՊ-Bo1LYL%9
+5 Le{^
+qKIBR۩Rn)Ba*ck {K_wdK !x vVRB)G=Dk
+oGȒ0uV$|%gۇe2N6zLstgt)B)g`
+<~WuY. 7u~8R{CX.J5,sתR{kaxW?4L'Kb.0u{3;
+Izޘq?*i3S[Wb;량Х
+Y³ņ
+pWṀ+@kU ;f:88'iO Ė_̜LD^u_~ YB3
+6*0UmW
+`mך=EO<^
+ܥm,;1T f}ۦ>7/K5jMŖ
+s yx$)01\`PNm#
+|| S ItY\?̹eJ:b䓋bf0:6j0$2[Q
+˚y?{ɽ`6a>/c:kq>U^+gWW ]laCHuCC"$YɃ\XI7vQ &1p#-[*Ow~XYJ=Q~G4.˻sdkIt;z-+_Hedw`բ"ohpZ{h .hTa*51%2@J:$;VZ0%>.wWVBy7_Ґ;ئGgΣ:XpKFP $=RLS@q?-}.'S
+ }A<%8ؓH:H>CD7j0ɛK%
+m
+
+T:ҁ%e# ӐܢFv-2p<&n*HiKh)]bj >OV9˹dy E~lQǐٵ -9M0Ǔ$JXuKSԳ/)c|WTrdYVWM:"ln
+!,ic$mGKZ/E={c0fk6{[@!iqnSY3{<^zve,%LP,U#@J"4WZ`1 'Нa B: зwhоtiOke̔;J P)$Tì,c%-!+O!VR${RÆB`aV
+M={E 9DwiJ*
+OŊo`.(N/,BLlNBs,BW'iIOKB=6ܺ{/;n9P,JHُ<S^!7pLx~dzޥM IW -)
+Edxch~LH o/r}D o0 / PsxFf䩃7$ŶdkExsAapb32+t­k+ʖu
+o%
+
+
+
+
+
+
+"$%4?FGHwwv
+
+
+޸0X(X\EdḁNA@S R,@'#(y4PKLf xy<czͨ~:/r4؀VϓAg^Տ`to/U&&f_kWVf<$6gm/|"mt%
+
+
+"$%4?FGHwwk(Rz
+
+
+
+BAbJFՄђim?t؆åG=H<}>1l20p^
+|aPDE
+
+
+
+
+"$ %4?FGHC:-wIwJ
+!Jz~ExBɩWLϬo6)i lK ݌+=9 4Ʋ}p'ZL BP
+y@IW B!W~J62^ VN`
+![\tk:5dksq
+
+
+"$ %4?FGHC:-wIwJ
+Xҩ k`aYrFUhmms;YĐi sy.EI t (rE {o#jb+u:  ʇ\9SQfD혫a|r
+3c6d_NgMb^l[ph Һ0ء]/Wj>N=;B`[x~?wY^ݿC
+
+
+"$ %4?FGHC:-wIwJ
+!6c]vC3-ubܻG-?>=^:2
+յO94׺"X|h
+
+
+"$ %4?FGHC:-wIwJ
+ +TH $'\9*X O9㌩`:@_p Рq5MujO;\F!\&kzMѢk>=s^{ ˫Iycw 3A3MO~
+
+
+
+
+
+
+_Ͻ:V
+
+
+
+ ''''''''''''''''''GGHӢyyysss
+i
+Litv*~eI
+
+
+
+ ''''''''''''''''''GGH}f
+
+
+
+ !
+&6DMRTU'C5s: (vwE7LNOPx;<tS7!Zl
+
+
+&6DMRTU'C5: (E7LNOP;<S|f
+xZwU7unkb*lXU
+TSm{(`k7z5[Nn @(p
+jSoKN)yZ˖f/+f&^Gf-,y-8j[f?~zn2 ـXxOK2[|4"JLј *ta},
+
+
+
+
+
+
+
+
+ -v8vlS''C& p4g؜a.h鑯KZ}*,kOf+%7@
+
+
+&)*HemnfJ3
+j)3
+
+
+ 7D TT+^ ןL
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ed 1(, OUs}(
+V[CSRe=Xx<jpgR2{{3f۳"'G,n*b!2u
+
+
+
+
+
+
+
+_
+k`
+
+
+
+
+Cs\??
+
+
+
+
+
+
+
+
+
+
+
+
+$I84~TJ-H)w2ЛL&]IJLUHxpΝdY5>S:
+
+
+ "#'5?EF@qڬ
+=SbPp
+
+
+s
+
+
+
+
+
+
+3L
+
+
+Ru
+*Ya0lI
+""*7魟kUUD2l$qj*KE+-$0EhRN`B\fl
+": &ABm[#H237*J*BZ*Q7@H#ۈh\<o|0yIxѭyvi) 4,=z'NK޴K3Xv
+_x=`h^cB
+
+
+
+
+ dAܬTܲ/O"d&ts!N.b|ӡw5H=pyw98+C0g0wt0 La Ï
+
+
+%R:45K.%c]
+@:dʒ1$Қ@/t'^INnIB}}GL
+j
+lrXA2w"Iϊ
+L\8_ʜc|q|ًϟ{vD٥eX.,-
+<~ykS0LS0
+!`۶.׵jyVڗ)ݽoo?(nV*fs%N0sz[_L;;;hjxmmۺ
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+&)*Hemnf % tt
+
+
+
+
+
+
+
+
+
+
+H| _ȘW,s} UPaj````xϟ?0000HHH`u0
+
+
+
+
+"$%4?FGHwwv
+
+
+"$%4?FGHw1k
+(Z)lUVA47ۻQº-)^S=aPèAa>˂~]k
+
+
+ "$%4?FGwQ^
+
+
+0 .Wuw<Gimkך@&
+ۘ"O
+0W,TZo'Ū5Xk{۬DR#Ώۀ1٘5U#-ʵ?N5XcއϏow s Xۅs
+kpՐ;Q
+
+
+
+
+
+
+
+
+z
+
+
+;;{6W 
+
+
+;;{6W 
+
+
+
+
+
+
+
+
+E3;_,ň
+
+
+
+
+
+
+1Cч0iv!eqQD!*F+C d*N:i;m0 ^'7u{吚
+
+
+
+
+
+
+
+&)*HemnfJ
+
+
+
+
+
+
+
+
+
+
+yō`k}̀ћ1g<u`% $jWBvi8izyI/e-E ^;
+
+
+
+
+
+
+X> "I:bS\"i.8r
+;A
+
+
+
+
+0[\#lGGpHCWӈ\ơ J 1c /L!Ro| +d[)P
+p Zuw`z[D)%(
+
+
+[ fœM| iXw@THJґu8M{,P7 e3͗X=
+i=Q;& X(m%৕'>&=mmܖWs(/Hmf-O{\{nz
+ :Tÿo҅UC˺Ƅ{ɺ
+<h%]?%4NE: ׭+{8XŐNΘ'&Od~_\]{հ^o+GwޝqiOUZL`mZYiƛ]/sE7s*F*P> I~+_0^L*fw ;f[͛Sv{)4Cs%74msݷ3/ t
+ԧ>
+֊f-4?$MM0fH; #ZeFfZ
+3@A
+;z5t4~_:H  }o@#C,è*,b)x|0Njq:;'3
+-
+0&HMZ`wfv>&Ʉߑ2|$ߢIlgSڼH0`ҼC!)~RL-kާ8u ̣2|W6#N@NQaKI`I7~{‹nlB
+l@AkwmCo#dk)WB>>4tiRMSv`J1^zr]u &44I,-&c1YKy~+1 .4QQGl O~‡J>5{,S Qd
+)QP&+
+yI1,Խ:%iŀ| Ė
+}r8҃*
+M h4Ί&\@WҼvv \gs>U`mgg }&4UFN
+ g,7;&nKu3@Q?8A?];6 1=uc`A#4?&|t׆|&lv$"]ʃrKwNGW ( ^
+)ô8MՔ'zzcU=ta,usehQMmI -S<V)D2
+'ji/7F ȩzh
+~ c/
+65Q?2uo\u\0m 0 o4+>Dc\}Y%js)]pk}e4fY rlf*D8 V2$Ҭ'<W#f^wIb}fl& 4BǘV<6rx=V=c+}t^ Uh -y%Id,cjLgmv?Uab о"/3a.0tunæ?24H/Eh74eޱDzكwq:4
+.ua]_Axqĩ @ 
+TXܷa-wјWW,鱢qV97.WRR>.EHvKiEIG{ &O"Ra w @.p\kW=}1΋ K v_&0>vC.}hlG,iWIU eV3cY$b1N
+?ް񂅖S50I`,Vx}DC@fN6æ=r4dїǰz);aV>HKe^&ͺRe_Du3ܳ`Ƌz+ɞ6ŋ;`شGYם+ّcq
+d.>pxN"{pTykbaW<\'
+Rzpq.@]
+SCb' luhg1T
+o9?F .
+&?.}|\uI5cRMM&c :tg8_qDre/'G{گJ;VҕU-[bȹp+hKwgHFfʺ#Dqx蒫@s>~q[l{NH]5GTD`2g@<x ȷfׯL Y \H"G,+&z%UFV]>%ɺTTa;Ir㉵J-p̸#,8IJ@.OVlEïx|H:?b {'S.Q8*.ėM54}nNJȘU GTYa,]pdx N{t)
+mhmI?%a_.> Dpp(hWK ?
+
+D*JO͍=s3N\Ω` +@OicI;i;h: %? '}H͐
+,v竜@~ECJ
+J*WH$N@_@}JK&pyn(YFe/o\$Cr _+gZ֠S-T܅YWVO;)ή۲1D}?3Xr[N~&
+a!;I.nHxleS*2Ry+"͡w
+%|_oQ#g)(wD
+;VCw
+z%F\^9oŬn:KO5BiAxsfXAQx )E"8Nq()&`x|4?X1&~#YJe$<#؇$\C\X$
+eߕ/LFzKh>cϯDj]cSO%SJ|Wΐ1aMT260\~qqn;䷒Ag
+p[h#=rlG\d$;#B_yNJ'h
+<hF
+o5p}1'G[ ׻<,p2QbِPEnEMf m0F^PI
+F \>ח0>X¯"Fwg_YCҘBx;}KoaݡnwUK0
+02|ea+-0
+JCЕouG?ehw%
+.+
+v+hy=$Lb3[Y&/ljK>
+
+
+
+kk[<o)x*17P#!{=PF\嶺
+
+
+
+}
+
+
+
+
+
+---------
+%ls
+[%ls]:
+
+--------
+%ls
+
+
+
+
+
+I$\Ӭby7mNlVezx%.tKp>fHa5WiَU(ߌ BhA-T'{'
+
+
+XE,?k:AOgst"57unGq)ʼnobV>Ky xZݨ31Y'_`QJ -zɜ;M*<Sa+~w&icU! }_File
+
+
+
+[output overflow, print less text!]
+
+ 
+ 
+  !"#
+  !"#StartFontMetrics
+ WhXn GMI k !7"#:
+@zHPmXh]=bj[rosz՞lșQA
+".6e$ttwecn2akwe"llbrC
+t
+lhnIe#gscc'd)Ur6JcccnCccikle#nQlcD
+$`y
+w ecca"kkiseelkcwe$ls")hldrzCKpneQecccE
+
+e$te nVcki crn!de&n!clfG
+3
+=
+k
+s
+
+
+ ' 4 A Z ke3a
+E
+L
+^ea
+Tncec
+}
+
+
+na"c
+
+e$xt"t
+t ch
+
+ !nBe
+
+ ccckn3cm G On e'e cl`s q lg zkeH
+cm6Kn*@ce)n;okv~ck.ansssliee(w,actcvJ
+le>e$t)2t@wBnDe-lmduN
+wHe.nFlne
+հ0%i0%f0%`0%P0%l0%g0%h0%d0%e0%Y5 0%X0%R0%S0%k0%ja,eZ tdkcCbkn`NZtfla^auccce$x\ttt`wbthenMn!fh"0;Ha nGc(c)ccciZ`an!ee3c,lskT
+njcsze5krn15Zy1a;QknsgklsgnsclutccehexwtV
+%%%0'v1'w2'x3'y4'z5'{6'|7'}8'~9'4' %2%6%:%>%B%F%J%N%R%V0'1'2'3'4'5'6'7'8'9'5'%r%v%z%~%%%%%%0'1'2'3'4'5'6'7'8'9'6'%%%%%%%%%%0'1!2'3!4!5'6'7'8'9'7'%%%%&&&
+&&&0'1'2'3'4'5'6'7'8'9'8'&2&6&:&>&B&F&J&N&R&V0'1'2'3'4'5'6'7'8'9'9'&r&v&z&~&&&&&&0'1'2'3'4'5'6'7'8'9'2'&&&&&&&&&'
+i
+i
+>e3n)*)4);i a >i
+b)P)y))n)_)nn_a pi o1e))))))ecweeec))*9*nc))e$x
+***%*1eweeee
+qa s
++|+++++++++01234567893
+++++++++++01234 5!6"7#8$9%4
+++,
+,6,:,>,B,F,J,N,R,V,Z012345678 9
+6
+,t,x,|,,,,,,,0 1 23450617283947
+,,,,,,,,,,051Q263748596:7;8<9=8
+,,,,-
+-.-2-6-:->-B-F-J-N-R0H1I2J3K4L5M6N7O89R1-`---0
+-v-z-~-------0S1T2U3V4W5X6Y7Z8[9\0^4----56b7r8t9-----23_4c5s6u8--3--12ȴ6ٲ9 0..0 1 7..b//01"1i3.".08.(.,1j8 9.B.F.J.N.R.V.Z.^2`3a4b5c6d7e8f9g4.r..//./f/0.~....0h1i379!1
+..........0"1#2$3%4&5'6(7)8*9+2
+.......///
+0,1-2.3/4051627384953///"/&/*061728394:4 /B/F/J/N/R/V/Z/^/b0@1A2B3C4D5E6F8H9I5 /z/~///////0J1K2L3M4N5O6P7Q8R0G5///0/////56~7891/////1y2349ҳ460
+0050s06 58600!0%0)0-014567897
+0K0O0S0W0[0_0c0g0k0o01234567898
+00000000000123456789900004*5+700000000K5100067835911
+11111345678981*1V1[01:1>1B1F1J1N1R0123467941a1e12961w11111112118!9!2!71113 ,4 -5 .4 7m7g11e
+i
+h11a0Bei22)202<2U2e2b22i o1a cu2C2Li
+i
+i
+Hn2q2z222c9cccen222i a Hi
+k22a02hqn1Ol34G4Pe34Bf3)323A3O334%43c'w0ch3U3a3^3e3h3qc#cw33c%cwwOa33e33c"ca3344cIcccw.w/h!5l"La4Xsm4j4r4}4neAd
+kp555a55e3
+lam Brl"Ct
+i
+i i
+Ln999i a Li
+a =y99nan9:w wb
+i
+,h::a0pi?a0r
+i
+-kSi<U<`<k<y<a0sa0ki
+e31l<>7>Ba<>2k<<<=r==e%d<<d%e%l<=Je<= g<=r%e%t=!=5t0=*l;t0=?l<r=S=be%e%r=x=e%g==r%e%s===m==e%e&;e%r&p=> r==e%e%g>>'e%e%k$#wk%eBo>\>i>tia0|a0n$e3r>??@c>?8e>>>xt
+? ?(?-tm??de]l\pl8t?@?jt
+i
+e3uAAAAi ba i
+k!rA;AAA[f!nAJAUb,b n!o1cA~AAAn a
+i
+o1eBBBCCC%ccBBk'cGdBBrBBcccnscciCDhCQCtCCaCWCfn2wn2n2in1Jn2 oCChCCCnCCi
+ii i kiCDCcCDDD&D4aCD
+K
+i
+&a0`a0lIIIc/tIIh3Iw3wcaIJJcOcOaJJ)cLcLa daJ?JHwwbbJvKsK}l JJKK KK&K8KFKQeaJJtJJt0
+Jl=t0 Jl>rJJb+wJJt!t!a eeKbl",e K2b3b?dlK^Kdr bo1 e3cKKKKnacKKe$wtdKLL'LZaKKKL
+i
+!lLLcca \aL0L:LAi a "uLHLQi
+i
+"tLaLjt w eLLLLLLMM?cLLrLLcknkc4e
+i
+'kWiMMMNNNaMMsMbDd&fMe&bs
+NNNNNOOO'OOiia0ia0r
+nQQa Ei
+nehQ=QHnencQ_Qde$x
+i
+GcDgR+R2e
+hRFRQR\Rfngo1a0HeiR{RSSo1t
+i
+nhS%S?aS+S6chu0(d&kiSRSdn2'r ee8pSSn${rSSd$nn!wr xiXecekSSa0ShtoTTi
+tn1TlT#T.Tkc;eT4T;t"nTETNTce$jpTTT[n$~d$n!zs &Tvl"mTTTTTnTTeec<h Tl1eEpTTn[t"nUUUUEUeUto1#c=dUU2h U'l2cgKUMUXo1%cce oUUUkn1Sn[UUdd\UUd^k]pUUn$nUsuUVl
+xWX,m
+^t! aXXXcNcNcKo1e$teXYLYVhYYY-Y=rYYcAncccce&@f
+i
+kaZZceu0%i[[n2$r ee5p[@[Gn$xr[N[Td$nn!tr uiUl[{nm[[eFe3o[[[[a[[iiiOl"
+i
+ja\H\Scdu0$i\b\tn2#r ei e4p\\n$wr\\d$nn!sr tt\]n\\e$mp\]
+i
+a0La0a^^lcrcb^1^;o1 ec^L^S^\^rna#c^d^ie$xt#t!^t!e^^^^^_8c3a0Ra0l"Qr^_ _h^^^wwws
+i
+n____c:ccce__`
+Zk`e3i`B`M`Xa0Na0m`^`incl`r`h2`}w2wcSl``ep````ddd``dreadmaan!eGoa-a8a0Ta0aaJaPn$e3ra_aaaeamt"e
+i
+9hcZcccqcc-cicwcca0oce3*a0chi
+Maccc!c!r1drddcJndd(p!p!e3fdIde
+w4hf!f=fEfwffaf'f5ccGwafPfotfWfcccceffcciffaffcca0xaffcce3{kgg&a0ghe36kge39tgQwkfgcrigxggghggggaggn2{n2n2mn1Nn2 a0ra0ghqhhhhh.h>42hh1dwwwwweHo hwhhhi iiniinpihhi+a0{a0hhmhhhhhhh962wwwwi.oiidki(i4i:iPb b b!b"e3Britiiizicr bs&he#n$rdeuiiiia0ue33a0ihtj b vn
+i
+hoo(a0DeioEoOoZoaozoooi c8a uohoqi
+i
+i
+@e c9noooi a @i
+j3kooa0ohrn1clpp
+ewmpp^ap#p7pPn+p,cl"Si
+?eInpuppppt"y"nktppeppl"+pppbppm#!t#!xtppp# p# n")e3vppqt%e%e&;oqq!q)cQk/aq4qIqQsqAsnisn$i
+rsqxqqqlqqa0Ca0qhhi ehrtqqnqqa0a0e)qw-urro1)cNnr*r4r;i a ?i
+arQr\cucwj
+i
+o1crrrncrre$x5le_ess&sgcXms1s:sHsXc,ccchsmsvcchssasssi a ussi
+i
+n{s0eJn$rk
+i
+huua0Kca0u9hvpuKu`auRknuluzun1qpuun1n1xn1ye3 suuvv v(ouuc@c@a0e3avvcPcMchpco1cvvvvavve3na7e$t7w3evvw
+i
+hwwwwc.ccccawwa Yi
+Yhwxxx&awx
+ox>xoxyx~hxIxRx[xeiiiii[kie3ixxxxa0Ma0xhwoxxxe3e3e3kyy'y6y?yMay
+yn2nn2n2`n11n2
+zhyya0Se3ayyia0yhze3crzz2l2bCazCzIn$e3cotzezne3duz|za0Oa0zhxe3e3l
+i
+2iEm
+{C|||=|K|^|n|||a{I{f{U{c{{ca{m{e{w{ccw{{ccce{{cccDa|ed| |4h<|+w<wcccccce||cm||cce%b|}}
+rtlo1 c}}%}.}In>a<c}6};e$w=t<t@}`}it@w7}sn9e}}~t}}bbs
+w;a 4c~~~i a an~~i a cm~~~ekeLe3o:EKui,l"5d"'t
+i
+.hhwwa0~i(g'awiiiKik1PWw9DiiiHits~ii1tuiiGoсwiiiIiiwiiiJiiFa0ނ@he&Be3Gws&Bsvwe3bo1e3ce$e3t̂tAwCelwăe_m$cEcce+8ci@OccHe3Ma0e3~a0დhmރh>w>wntaۃwawwwhkqe3i6[Ad=Vhet
+i
+(a0ja0ʈ9heIe3b`jo1 e
+i
+ihZda0klstrxsi2=wnމ#an2on2iʼnn15n2an16n14a
+n1hn2n1gn1fa0kkC[a0ˊOhtepiiMe
+i
+oaciu0)in2(r ee9pAHn$|rOUd$nn!xr ytun}e$rpn$d$iYj̋cZa0hlҋgwImeNe3n =a$i a #u+4i
+i
+#a )oT_xq(a0na0Όlhne
+i
+<mˎn
+i
+o
+nKRa Ii
+nckpe$x
+n1Zg*1kۑ$b(e
+hEPZna0Jo`jenyeweeetQiekёa0hun1Wwm
+&-nMeSeQa Paɒ=ALZj1cadwc{tpc}si
+nseOe
+i
+gaS^ccaf
+i
+KnTpPWbn$t%n#%rodue
+p
+i
+*a0qi/a0lbcn1rah
+c~nzwcWi/>cXa0zcYa0cr1>wNt
+i
++iƚ1h֚an2zn2n2ln1Mn2 nxi:ko%*Dkh1:iii i`4?JXppϛݜavn2sn2in1vn2ekn1rn1Bn2skn1tn1Dn1ut&n1wn1sa0ta0kns
+3٦#ŧЧWa ơ͢7B[rn|i eUdסݡa 0l"xe3e3e3ewu%.i
+i
+0a0a0Ohi mxi ndo"6o1c¢nYaWe$tWdݢettYw[n]eEhf+k ;u5<t"t"rPUd
+fHvtU`knYbdtb9dee3Qlw_g|dzeRoa0a0hi#n$r+Oma3=Di a 1i
+\hV_ccc}i a `i
+ni a Di
+rt֧k%dyru!Pa0a0hp'Je.<i i hi$cgqxi a i
+ni a Ci
+s
+i
+8a0Ua0h{ch᩼hAwAwa08jra!)i2iAm iDiCi3i0i@i@XciFQii5ii4iBuzeeii7ii6i8i9o1cҪ!7natga_aYcckZc).e$x]ttLUtawc_tie Zu߬b<cd 3en
+i
+ma~cgu0'in2&r ee7pѭn$zr߭d$nn!vr wt+n e$pp#n$d$iWn
+i
+6wo1cIeUn`iwc4ccccl w a¯ѯ߯1ȯͱ552ׯ2ewwwwci'2cn<dBhINWwIs]qt,hw,t-{w-wwst*w*t+w+kiݱ -KS` að1lka0Wa0!h|q5>wwr"<wsoαܱaun2tn2in1~n2fkn1zn1En1{pn2n1}n1|x
+i
+lacfu0&in2%r ee6pԲn$yrd$nn!ur vtOn:ce$oi p@Gn$d$iVl[oh
+g
+&4CQ_ln1In1n1n12n1en1Cn1Fn18rtg
+ͷ׷ Zki k޷n"t"a $ui
+i
+$h-Kc7ci3Bca0_ce3}a0xhc@uv긞sJhJwJwbƸrgo1
+c<Wnelach-cc{c|c}cDIe$wqtcdjtst{tkwme ɺ"ejcBchϹع,Uc*cicc i#ca0fi6Ecc m[}afoc)cecicccsa0ƺhle!!k&awwn,5H]e$in2)pNUn$}d$n!yhtػth8w8wcrwwhʼbܽ`<aֻ
+i
+%lc0ct,KRw4?iiiLiejht}c+ccces"e"4aʼ1ki8h!*an2yn2n2kn1Ln2 nBKe$lpQXn$d$onikin
+i
+iaccu0#in2"r ei e3pn$vrd$ns
+pbnwoeTo`lnia0ha0hnRWe?FLr#-6adddddexose3'itt0l]l9t0l^l:iakn$r
+k!"ssfkg%*/4n%f%t%p%sEliOchFZwFwer}cFeŽœ¡ª¹1”˜2ebwwwwc[rt)jÝa i a u i
+i
+h4=K[cycgchcias}Äi a uËÔi
+i
+ duíøa0da0hla0ca0howne ;e3e$kp$+n$d$n!{yENYe$suSDp_fn$d$o
+i
+hacbu0"i-?n2!r ei e2pyŀn$urŇōd$nn!qsŢŪer
+[d_{e
+i
+ hfa0Fo(en7?JR^eweeetqvcekǙDZǼa0ǥhscyn1\mankcs{i
+AeUnGe
+sgos
+7c^la0Ea0+hitCNcceikseywuuɇɑɘɱi a
+uɟɨi
+i
+
+i
+Bni a Bi
+ni a Ai
+v
+i
+5a0vtʏʯʻh5ʁʆ55w5hʕʝwmKʦwKwwe$we4?Eˈc2h%cckclcma0s&@lPVr
+ai a i
+eVobnxd%In3>a0a0a0Vha0n$t{̂e}dư̐a0a0w
+i
+/a0ka0hn1QiNl%a0a02hlcccSXe$xwdgqs
+P[bitnfeza [i
+[h~ׇו׳c8ciכתca0Vcnc2ca0fwwwn%9h60w6wo1cU\rn~cdie$xlt|؂؋t|weءجٱc7dزcca0\a0o
+$=JUalvفوc`i a fu+4i
+i
+fc`r ee0nr piPhٔٝ٩rr e ahټo1enjcc6dcci*5@a0Xa0wweZojua0^a0n$keuڧڲa0Za0raster1
+%#}&*+<=>?CGJMXYZ[\]^_`acdefgijklrstyz{|
+ꖪ^
+
+
+
+
+
+
+
+
+  !"#
+  !"#