From 7034d883f182b182bfe3228e6390ffb1be91bbc4 Mon Sep 17 00:00:00 2001 From: "Steinar H. Gunderson" Date: Sat, 22 Apr 2017 10:40:39 +0200 Subject: [PATCH] Add the Nageru theme. --- nageru/tfk_pause.png | Bin 0 -> 54652 bytes nageru/ultimate.lua | 736 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 736 insertions(+) create mode 100644 nageru/tfk_pause.png create mode 100644 nageru/ultimate.lua diff --git a/nageru/tfk_pause.png b/nageru/tfk_pause.png new file mode 100644 index 0000000000000000000000000000000000000000..d74a9775e43c1eb0ce18099ac2a3b589faad69f3 GIT binary patch literal 54652 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%0DdJkPJ;m^tGVdukxt(brup+K_ zU2eYAj|cW+CC}5VN%+fsKKkEg#2)3u9l2tp7K=`=E_G;-ExnO-S;C%qeACq2?0Hhz z7t%sq5!(-%E-ZM0hiyIz%Mv)?CZ%f`UTZ;CH*UTQeLYg^c}f>*%2|0c<4e>`Z+&)f zNVI~e?McP2D+vou;GOv9I$}vbFFLf(8GUgiN~4mpY9@^N6?DvFbId>IPP#ewQ$8=N z*7w1PF;3KN&ER90t)!M6xL-(*jHCW$dPdK{L$=bccKtVlKArdQmY8KDyP<7mQJc$g zG{l}Azn)Z|C4*PGtw_u7DxrpWw{cl#;PB?7^u1-Ge)Bh6@()61X29xjI>V5utY|Dg zzHHJWdqU{yvHunTG8HaUFjbwX5KrXf9udm$N48}vk{Lq$)~d1_1yb({NZ54=uf&Z- zXPY?9_!qC@WVr#3o@iC=BO35yUs=m~TpA|TlkGmmH;Y?>#7Va>yPidNC5etUetv;U zlc|?fRIn9AW9WP>9M(flDdEf*ySMkFkW(^U9}N@A6Wp@Gje%CqS9x{%0Q+{P(4+rd z&r-B*OZEH5gx#$wFZshiTTC7qhO?F&Z$UnqT%kU znBY=mfH{_OU$P1Nr#Q3 zX&ayX-Z0sT|HWz;W;P$KX$nrFRe`BY8zc@o*}wXqDylg!nW7(Z%&`{t$9amU2jr6x z+kN&>;s7)?WqYRMzGqZr=FaAxQ;#%&BDXXIn^`+9prB=SY9Ue{67C7JJEvPK%EgMG zEfxOu0}RXXteg70p{9ojg^P$U_Nh*-M|9Ou_MZE2z6Gp?_pi*vzpmylI8cx79~|tN zET=kJ7{2EI#bk)|>Xc(I!xwc}9^~X|AdU9!%y$6$FMUA>sAxBkNNSZ-kjOBcG~-ll zoX^9!uk`si#ErV?=>^Jx6#n&+pM)geOKb?Oo_VxFYzY~q3#te22-?i3T!zp0BZTfG zHUNcb7a#Wz2N&cBPaQY1pX%L+h1Zzo8>s+?n8|{7Glg6QII!BAR6jfpO77E^VX)9s z$m9F4nSQqArTN3mte5BUdf4+w$)?!&pI!D6h7I@1YO?V!T(FAi7z8MOAH?H~{v_(X zv`Dr<_o6A9Ly4aNCoLnA4%3eKv!{3VdJMQK8kTHSkLX$7!tuso>w0!Qrle7>_+9J! z)!A%9&(2o{Yn^(c(u+r}?O|UT!0ejmy6?hbml7diiesf z+sCq=wQS}WzATI@tfYuMH()uI_#z_=n^g658m8H!rurpJwCmEeV)}>xvw}VRi>oV* z^J)NA5aeAaPPp;bsbIFh2u|0t*)y|L&?7g|apot2l%URzkRUK(Rye9~Tl47Rm;86d zrvi_-2gfN@E#I^9g>?Ggj2PDOEPKH0d82~t7hGK39o1)w_VD;DPBAAVcmifq-hrbU z=OeT&g(B$f^SQUDH)u+}&tT1(oit{h<%V0c{BAwoeGdElk<9w_v%iUktiOy4K}=(| zfKWm3Cv^Gat-80^S&7mQVif!8Qk?n;>1O@1-fWAPDfz!)h1_NXGtL!BT^H?gALO+} z6sK)}?lHL!z7|~;?7z1dCG=wUI0wHrFk(-K?u| zIt%mH-4a*l`>kn`=6Ec05OJOTZ-V*U$F`?;v~8JNt*D7}y#S64vvIheCmF*H<(> zf2P8Sfyd52Zv>HT6Kl=wwH}*F>f>yiw=>OfTRCCNL%4Mpf@ICAA=WIP;QuouBt&lB zC|L!%i*Db`%1BwM_?2sA$gAhcjPdW{T{7RXK9MIrI8g5BBBxbdQS5x^XMZ-tR)KU# zS%4e{V#usTgtIRr-=1#Z>nS6u1fvU9{rT*4#8y?>L38e0e1i7-M#r&-8AJ6Mj}5r; z%8F<*ntFC|{Y5x^c1==oYg2Ii4xe0A9Sr1vCb0yUaETSqg5q?#6FDobj~7pD>)2lu zXBFU|v|N$8ix=JMA#=?|1OOa-`WHEdIbmsWa{6?nS+Xp zsoPFf@n@hGPeTGNbX*zd+OKR(sS2*=qVI4K>hYZhVz$dVS+nM1P{@jg&k+D>d(0}? z+`cR2eeIWW1^ig!+BH#a@%TKYSSvx6ce}-B1EZ&>z2*mM7*(!Txd07D)sri762lui z!7MT&X+|?i=Q_g93fzJCkE(1mo(W6EPH(&maLpiR+ZyGp)#*+TFxOCANr7RdHz$@( zDw2#-oyOD4%`l-SW*UjXN9QNV`j|_YQZV4e=;=ZUBgruCeB%3FTodi&90545h=3Y~ zo9M9uF_Ma!&~#gDymfH@B|+4NMn|VWZ6Dk;2H7T zBwhBpTFUnQ_NmY@UrjK4#HqDU|E%GXPQ{%2Vl?f5UyCn)j>`JW_dQKQsbJir3rqlQ zIcElz8^Hkl)_crO!&sY9S7@ZXc7`6WW7xvI)-5TEl)BPaL99g**c>@Mw?*HE6<&?3 zYboqJTh?sgJZL@Jy71iD37I<^Ivw^Lgx~z3-Wox|M=*hReQ48y{3J^=O@dl8TT^%V z9jPLw%}r=c>)o(S8V$vIl#sr~?#6<3&2Ntx+ zS{kKJx6p|{`CMyHFm6_ES8X4_qoGwSnVPT1K`il6AITiJM6rag6uxDpKd&@km1>vE zLgt14$4i6g|FEP3tc!w0;RP*O|ougctDUYIr$;8`kBo_-+eCp7{&q-_5hDi|pVXK%Ke zRScS5u46H92%3r8tc0-9L6-9;eT{P-3*S(X!#mU-INTL0y%D0hql79?RH-x+jhP%Z zho$G+D8pU}7R^kfwIjo!pI<`1^fj#Fu$rFiHy=L32jugCHg7m_j!SPkBL%MzU2D2C zvwD!=ZU~}4t5L)0z?jnzQ3su<7lmJwf#G?-E#=8m(bHhNtZ_^`HsHZ0`0l@Cl~L!1 z;^|*3#njXYC9M(Cvm9}J&Z~EU1h~yvvxtg{-GIh&vOUoWWvV;t{jbLD$}f|gp_zW& z5$`*^7Xz%66Qe+n;>gJ(Ke@J}i|XTEUzS&Qa+fO2Ol;bcuG}WYsQVW^=+K z;|Wu&tD_Mh{hghGUXH+k<@7N3j55y?AxlDPhk=}3 z_z-3>zZ;5l2E~F#h{n7rq!$qCia;n z=t0W227~Pts~^5Wv?KOx?N4(unbK3WIqnZ*aB}i=_~j4W1MM~s6ST)#&ae;IGG)g6?LBm zii8sML8_G7Z_;AYO4Fj;in-5s`~cl1%6Xr*O-9VKKIKLfsF-=0>LB96;> zlLf&M_%_hzyq^VQIdngdLD|gY51y7r)?j0+3z@llZiG?}#B)@RoK zR|`<_n^aP#TBuObWpq0%kLG30{;cIK-(=j(c6-`l2sy%ZpQ&q}3`NDr7feurRy%F= z>C*EQPq;0uCU3Z2a@?YarqVp}R{Yiy= ze%OZIiOEln&Ztac6{Qt)FYPa>1I=h;-F54fjXkmP;(NpUHeB3X2@#2RfW^B{>t%gP zhwZWLmd4tk+lL%{uMG6176Qxl&67tEk9w3}`wE_pE{lAlXFMN#VO6)7RfaO+m4*M} z51IFX4krw1y#j77f32*LRS+#w6KI*QoliR7m8lqLH*X+Ofn@5^G9Fv}2{`n!qeLe=C7apJql;MEvZHAU$UQzKWa3 zp_NjvKtQZ1r+})l<88noqB*tG7R6e*2FT7~n`m_cXzEl1Wn!G5aeZOD*XMpz@Td9& z&+C)@$FjZmGpq+v5GvIA?f56RXz%(0hLvO0&P&=H^O&nHi0w5A}-T0-I+! ztd~U7c~plir|+U^Sz6>QO)!y3-X!1^o!)VC1z2k)lR~2NNKiDmXQoKlYUb*ebaojv zdfKJz60xELDn+z`{NUp9S~oOj+&nhaH$`VHtJ?cb`(0TZIehWubqbxI#_37*%>ug) zHcrM@qz6wFezRjHA+JVUCkvZ#uZ&g$Nq&UTw$>Z+2x{}oOeZhMFw11hp+-rtwQGeP zsUnqQeoVnf?wkR;`ZE_VQH;coysc|;Z%);)){IuZy0o8uyZ5ky8Gp$@w3pE}_MmhG z|Md==zwl(B^ydU=#ti}U6ZFSxPt`oG4x(ZS%@X>mqAl@;wkD*wEzlX>B_A+wCmWjc z@J*@9cGM|GX$oUj^72XW@7U+^D3Qarzc|Xcr4K97PTcfi&t;_}S8r?QZ%thp()=3Z zq3HVuw4FDgLX%9@A=B)vehRT2yKoG*(DL-vs?}r8>w_Ze87t|GUcPx=LgkiX3BiH9-@8sN_p8Ad9swPs+xE!QN8BlJIR zZdL4$?pnLefi;c0Hlc}zAK7*Dgg5ayaWah0MlXm~ZsL0mW^lH;f@HG*dmzCvGd1rOC>^Zg(dzw#~A#n*>S^+4}Z2rEkzQ1x4C< zn;&jg4o!NT$yv~2#QGMob7g6n6}9C3Qa*%g&-_6+=q~$lgzzs_0cTpI=p!Y~@G4Mx z_`hs!$U2T4unBNwNjnD7NwxmwXA!@V^z`snV8(3+GTp7!Vy~sImoLbM9fx@AApS~>1Y$HMrry#W#g0O-`L!3RpkMe8h@f*U z=AQ#HJ0xRle~5?Ps`wo_qE{{ycZ zLRoMsu9daW!o~U3L+wv3i3#j6P%^xZNO$f0Q>>G*k7wd+GcWzT%L^sQD~#={U$Lsz zmt{#7`NMi&$V2+7rgR8 znDd}s_gFp{yrPO_OHD@CVb}5AI1185aov;0>3x_l$QQ?dy>AM zEYd2s_j<+B@-ZjX&M2qoTUzbea43s@?2MSC(;Hp)7J{p~$LgO6HP<(_lOi@HQPfmDtd7ja}mK9u+lIFPRE8 z>46K@FK%oetaK6**2&%LMBcx;*Hz;HY5UefR3-8)2$x+e&6hSo)ApeB;TjZcuJ0~u zw7XhOStt^2mn{W2@_i1=GE6P;qg}kZS{}hT>GkQ^Kc3ikS_mOGP@UUtD1t0`4(5W+ zRGf8sML{Rpg0a0e4!6Mz#rP*<1#>PvYYE703k+^5BC)~zTGQ^4&8C=$)YY(+-K$g< zYfi~QS(dqjAc*8)7df!l+5s%GR_#?ygt!oOupj<{uk6|>K$|{cT}~Nlx}5oO?;u1M zX}0D8tFt1$s z#wXn7Ex4al(zCwEhHzqWf8|_Q6-|~b3&+DHx-SRCVETv4o1Vl|>#@+#=#9a$^VQa@ z%X{dq3J5NHs&0|jy^;{a8f>AdX6&b;3u>>tnaJZ0CGwxeQfU!(Y}&4>vdmlAr>Kj2 z1-pQ|4W~X*Qei`&B=Lvu5L{Kb-2JulO6)!*{ULiK> zuuzG=A*3+G5LycA%e@137(Lo*EAg<*p6hjemhpbbPyMT#(eT3PbhcISQ*^S0rNqTW4a)kxOU zZ74o)`f`1QHoOB1I1-tWx_g$WZ<_+q^G=+q&P-f+@7X!xPYCgqLwTg3s&GH!y5@7L z!4+Dh&lr32x>xb}U=V%4*`}~#peSTJwx-k)vKj>G#HKJ71d>g zX+H1>Y<7J9ip6v}-nY%}%F9-862O=o7#lSSKj$r<&cs9tip>XbL6oak95}a;KTTXs zaW4x4(&nSW?63`amC6fODElzK@ex_up7w{0=cCqgzJ1ss*zMUS)=ksKGAi@^y}4EH#lC%}qO@lH z3{BpG8J6f$%-a-zh2`RkkOWlzUH_jwm@9LUV1q-pD8vsm>dGO~cwg>|_P0QsN6Js| zT{a+VdX8FsVIaooHP$rG*?SC)ci7dKF9+A?g~TK%eWNh?3~cza$&Q+PpB-Tx4m<~) z%L<-i!tX3tbla7>c@pPq$Y026&{?km-9_VMt0P%{ZmF=WZqbXD?0I}!7{}n^EhKp~ zBu@st@#Y4+WU(;U-O{V#aBR)s!kb=5j9r=u8Q#BBuJRV8)=enP^&FiOEaXqSgCtn{ z=dSgW+l}ull|RH@o%d!hYo5Wpx)keC6p}n4s8%Um8}73kr@TIxIV7~`B>F_(vA>Z% zaHH!NGtw^C%k;Oqhx=b9FYayPMUx0Le&LYUr~n@uAe~+N{K-K=Cp%iO^{oBIkfaQ--w^EUH7WkCzQ@zhwv$t zf_`hemG{yfrdt44;EhwZkb4qZskQZ=jqB6Poy&ipYz>534BkN^9-?fQb=pO z4B@3|dN|}gy>_M9gVwPq1$d2l>OvVhY62+F{v)(%yThcSo48-7Ge7 zgGGnh`qtJB=ZCx@8wHpT1@cG|%-agMqC4kM$E7CO9F=hAeK69{HCYKq!SP)J7q?C^ z`nj5#t7T1YKt0grbd;~chcxZNK9#9>b!gCjUQ{V@&C;;8Ul_C%FUU5XbjZ%8TMw$x zdPaI8KiBfcNvWYODy3jAIOkuMT1u$%LUh1dSm*i(<_GNWr zvIEhf=*)oG^pb-O-zre;-)0vKCc|9ZdxuU$W5#zq@Z8>WaG}*M;m=!zF<+OTwnLX| zb;c5x0!pe4zxfm2dMx-Hf3&_vc&2P4cHZkh`wBF+!N~B87#xH+&l>YC*hyU%;p^MH z=^F1%SEvFa=V#-8ylhe)YDUz$MGxze;Uy7u__{v+?<|J&t9(EWY?6hBQKdR=k_{(l zyS#pj%5>-MNX~CCzoj@dP0z0IT5@@XDwx*^RkT>}92uva^$gic1`4NLGPze5!I%Yu zMruN|FcDs@-CUfm@|Ja_QmYLgKm%h`ET&`Q0(FeAl9M)o^&yqM3oQ~q=JMz(DwDQf zP;CB}3!wO;`d^pqCyxRCqZiRNmz5$>o{#0jj-(IQYgB_cR z-3xEa=0&7#ViV8DeHD@d{p;~(DUA<>586|$!z!m%NM3mS#>OeFHZ+KPB|N(XhO+jy z`_+;D0vr@R`%#*s`uV<|d@MTi;%|pWN3AENk2w~)zm9H0*_1nAw3(F%XQSI|(N8dH z`s5B@-z}-hwLs*M7h~&gYVBZyUzBOPbe6j`n;j2wo!m_i*?U5i+{>$*8-byz|D82F z1ya6Gqg&-`iQ#V=R;Kz`KXf|AtqUtrx-P%yUJbG3{xx4*Q~Fe*D~apbuh|TyTIdM7 zpuT36-YQSWSw=KEtAXPm)s4a`yUKRH$I-=WZ7AJ>LBqq`mg$~uK?qG%vHJ6V85g|>W+Q|JaciPK>M^~g$_iX_`L;ex8 zpIp;70G~-7tZq)16h#P6imxYbYYQIY-E|J5U6_y_Y|*VH-H_FEN(36L+nd9IHwC0pZ}6zxk8mFSc! zpqTkU({O#=t~1&B3kgcR{nMhynB;@=Zq1Eh;}h0NqS9yE`}$?AL*`}zx^{Ppgp+EW z9GXq7d&ZpBvw1E;R0Ew=iy5|h&(wL&Hb3_#4UYiM%S-qFWebkBtNubqki~q8I_kYN zRkfEzCXuMtXd!$`{YDe5=q0Du-}&ZJbmvp?u3M`GhRJ51n#zz4H7#w{73;}OJyrGV zi5bJ4VEnxTaTY!vO!05s#7bc^LD4Xwzr4(^H24p-s{igjng<^qT{se^xuy+{ zaJu!|p-D@XK6}J1Kw!Ca^j=6#!QGI@XWQ^e8#rN50X2=gaL!#0M(Tl~jVZ$D6i)5~k{v z(Vmj+y+CyrEc(gxq!f*(SV9 zbxYvAja~U5$}+j+lK3h=ySGd-$Y13H_uBgOW@153lXFCOdQpT9WvZ)pF84(hX*>Pn zdp~w(woQ*FWP0ZEoy^?{KoEHf{4F<%j*9ulaI0&`3dnQUI21+Jet5SB|DvQ~Y2;J7 z6^i=w@EPh;qhTo2T(otgqpi8Cd!|_}fn3;+@R(hq#%!bj^d%TdPVYN)9PYJ$ZJ6+z zO26^RuLSw~(~Clg|Fzpve4lnu-F8&Gs0tiZP39g0odS&Bn0&g)wi8KZ1YD1$NZ?DB z2^>_$ZcV{x^A%@Zqy-6InA^aYP}MrXV;A8~tH`5-j?7v34uM*H>cONCz5DeaOM$i3 zdp1&94bLupLD;V_l*I0XSO6ZC&9{*o*OU0dc?BZY3ba za+5#RTgJ7|z5>+_?jA=(p(8%;a$}u`zd$pmvs6#2!}SbWX4dNHo8$T@rmZi^?t5s0 zQK6Ff++j7(aG*LYTfxKDh!tnS`IoRXjgS_IHdvuUc_N)%j{&3@-(TdgOT)kthuSor z*-YraZn*0?j=Ff(q|TZ25=XrJuW*zc)!D&1C>*p`s1M2JPuK21~k)}}Y@u*5P` z2B!OirUOx;8uw04KK}N$A@d^)q8St|Z&urn9`^}YnKwrDO8P#Q9DFDWKa@*6Q{h(K z-{{ZoCs1TGRwG=5GbFM&xcy*1hI#TT$H>}VvhMQ4z0rC9Zeo%rdq;G`h72Q^4^G0F zEk%Rs@ZR_>^WT2T|F1ia(l6m4pU_+OoLp<8){7E_L7U&1#51bH2G&x}$Jiw9Q0I5tthF7rPmPi03)WYc57@9bJ@Fn$`BCs)iU zl9K{R#DQ;4C&R;LfbWH)ZrDYLgs}nx(WueU&a_kbHNd@z{BP*J+~@yoHXWTbc!OGvD+6#nSHSy1XL?kS60k7% z$Yl|Zs^=zY0A+=n<=f2~c6Uv|D!Q*dXQ@AgzPHS3dcp}@*!)win7F(MFj6gk9*e5D zhr(Yk3}ABvE;~NcQRq;yTd2__KRNLg2t6(sn>WMQ!UjxOpLtTL=i*{lp>@3PfPbOW zsyp}=qW{+X9kp3?DL+s7=?BZ4{8iC}fkzcXXygM=Xg;)I=VcY&XuVczsxj+ z&OEG)&*^t4fWJm5j`;O|dsq0kuhl3xgt5v82mNJd9$gl!c@@jHCVL6muK_4jXv9k(&ea2h|y6m;yP0SiJ$bU8@>g0;P zZ#??k`L|8y1G@f~1CnK}9}Mh-d5m+#m14prm>gFZV zrbY9_&8kg1Z4t|NB=T5cB5$~#Z8QU8WNCg#e?U z_@f@tZ*7t90OPSu47YN}3%z9a!B3^0QhbcF_`mN3c=J@)Q{2(UWTizi@yz{lKTwh> zY8vq*dZZItN9#fuZ~ZC*-NEs>W~xD2Y^D7)?tv30x-=WYNN+MpIGj3l3ZvsQ8$%9| z$;lbN(jfYN$f$oKgO7i^)x&G@KT8^RMD-;;y4-Zj&oaifXW|@akSHI?GX;5CP34F; zDhsucYM5WBb&Gvqs~U*i)Hyp6q4vH#K>bYlsT?{t(;9-*kM;50L~)ko!YlUs#r+%N zSCUw|(Ws)EjrSy?_sA7s##G-&lUr#i0hnX8KSTILP5Mc3|A@v@DViX392X&Jls%h; z8jb^XvT(g#xe_Hz2v#@`_l~GIVrJDkqC^()y{s^4;K$vB?q}~11(#0LRd#fbeT&E+ zKlYS?OWRuEAD@#i!j@8B{`n9`>Fv7Wf)=IrW(5w+^iQWQ9og-Y42W91_8-nR=Yd5} zBf>5NHdB7Ej0QKC5A9wTenAyE9L-bk<%4YESCVTgaF94y0+mp=*}yS|~a`t9#5J2OvQ$Q0?#I6P0&9>gr0FbF4t8Ym8WRp@NbAFpH*_TSYn5`0FCH zA3C=mv z*I$$^$#W!KF+}PTbpIhfYEI$eM3!G;IHmlOwV90X-POg}f;%N_8)9eKT3HVz~R~-iqe-qRxi+ApdOziRqWSXXG0losYL4lFAPs#)j$9nWX-OCZ*-SAG^w857M;d7d4J<;eNKE6f`;oFWj=JEbg?FFzp z(xv6&1n>Dw?p}2z)0{GR_?$Mh^f!U-4?)b|Loj z{KFHR1296k|Fm0c2u)6pvO0q=X>W&xf`0<2Lo!w`j(h?b{$i&u{P^+LH;TAY_m2|O zq9z+BH`=kf6QW3!j8jc*56LZx2{x-D1!c}3+ip3C*7t#`WX#cA8E5VWo9Cq%*IQ3d zC-&LbCh(E*bqLaw1FR!>x+WzBhYx#ntylkU|5cgx@DUrdEZys2gn`zN=f^Jr65V-C z9`|cb`nzT=+m+vB2H|tj0s}AGhYR@-17O?FuDyoHU%wMCCx80cY0LzA`Q6J@&mffZ z9NmNfFZO(sl0}?coQrN=eHxpvGh3 z*~mxkjBP|jR3`b(ZuFvAc`5?yKY#u;A@g_PLmfk_TAXBH|G1xs&xrhG8$bz}<0R&@ zjs_OOa)|SVMon1P*r^AFg<_yRL2=K>CzfPf zM;jUB`CdnU+e>{Jl+;DCFtbowL6ao8D#=xfRn7Wn4A_bXQtCfVGOfALe8R7oUFwP- z3AEZ6-GrE!Jy#`%^H3-M`h9RXBkZ%`m_w$T^iaBcAiYe<$N8vzY_?S+_|;Zt_;VIM@lO^O28mh1q0SGRSHG8N;pnWiCVbcX0FGjLQg3z2adFo1Of z#wKLbOu78C8;nd}NT+^)$y^yrH+E zPs=PCQUJ3=zp$d$i!zo`xwK$*4?#%K@I6xzV$jWCvG=O_`-;ijcCq+(!f{jmuTBC|k$Sx4+!I zp@KKaB{x0q1SB8AU9FreUtm)BqB-UgE`01{^+RNAH}qluX!M z?BLESyPNym_WkHR&!B2W0)&!gD0pWe}JdI~(om4a{+l>-B= z8*pF#DG#ZG4Np$$%4)pB89d|qu!2w=l39DTcENJe9oe4!{20&nT@>ojotq>D8z-G$ z*)8tQH>?u3M27*53i8b#qJ;W3jNYVs{J39nugm6i7wZ(jSsrw3gFp>ojN-mZI3(~; zH%T2F_Q@s_CMm97ES%!lJ-!?KQwHGPl1~@-g7PN+gIM65y;kxUvmVh0adj_RnfFjP zfp(A6zZfowP6pT=6a{ow>@>*f+D$)*Uo|gLTkVxvEQF2xQm~y4H^%PvpP$}t zm}$n&TxnY+ZU&nVr4N5;x~fR>6+Td&j-z1#w#swGyilHQmr!SNN7M)Eau^(_Vnys( zvPxF*Z{PlgX*sG-&Uh%>4F2{up9pX2xZlK^6$hmNl=3YmpXBqd$uo~hzOykg)N(cQ z@6EU1P;cT&46ond$8gkcu>6FxPiZi&HOG9s4Chy zP>p@y;z=vqSG`M7l!bx|0a;4zj~+gI6p`!x{nLLwz4dKMZs_~9b;AbDkRBi@DG=}@PI!C63~O^xjYEMGb^gWJ~8b{si;(>u9}rX2zRwDs$;rbTQfywK_BvScP) zPe#TpiuE4s@b;mk711;&;l)Nq&5w;V8{v+lBH%}T zALlV|A|d_G7fqCm;fg~kN%qs&t)Caax|DLrZmj^77X z&zJ+XhWzZDIK!&rhGOWLvuIWt!fd`{_|z5|3apb#V{A zBAqL@>VKXqbjGn@MmvYR_TE5Fu&AL7WM5XcDSj$jn>nhe)yH*{p5bNnYDz(A7I{<~-+-p-{X*AFlu zO&`LJ(kKqEXW^)r4*PFthrQITfQACy_eN$Yoo;$%+ECv0l(p)cn0!U#>Ysd>h{yaT zHH0Nu{M*cI_#+aJaXVm29v_oWzK;u5Jn?sVBXqNSg)+3g#`LIzi;59atNX5S)3DkGL%;dv~4jj=U94aR9(8Ry?r^hKhy zE9*qUgB)Ww^a^6ES9mNIJV75j{^Q1L-d+RBuIG6pxd&Z9HCSH(TA<=rFzN)l6# z?=Bmhs#KY|6#G_rTdnRR6O6wB3P$~ibU7GTq|lzd-!7|dW3B?>q(a3|M)2_oHtRqO z6a^eU^fk_2A6^())=$$&Z?N#P>>!A6@XM7b>^m|Nyj`rG?u5(NcE+U8JG|CGJ_X*VMaL5vmk zGn7dSw2#1Cn4NquW@risG49<|!n@-XW2vH~fm%L)#|z;ZRLRs!_bytK8cOPlXa-!v z1w&Yz8E*0Ody`HWdG>}!6;x$pe)GIXe}DgIoNS2J6oLaw44g%uqdfrSuW=X{Ad!{% z*D^zxPo-wwQ{L<M5sc z?QMc_zM*qwqd*;QTiN|RCYFF%`L12{PnHg?h2-fdwKp}HCi#p~8am<(5;z(gGjW{R zO2iI5xM1y}7EfwW+@@Z%$Z+IzI>3yj-c;~Lpz>M1HiCsWvAnWiRUxQf#d`QROhaGy z0I$c>T8VMC4~3CF5MPL}axl*J;$oJl_G_SSaP?$Ia?Jc42HOIKF|f0qU)f9|Zlf%j zVP|DOY5GLIDy_VIW&w^N#UdA|e9pTa#_Nc3ofP1LVK0Q$rdsf79b(`|u+mHX5sXnD zwd}AtlzWN(`WNbd(1*DZbjzT82`WI%X-6F>)IzMI{GJ>RCv8mD9Rae6uKA~5Y@k*t zimjXIi`7xPwN%-zl?2aTrz58}{6ZC*I*r$HBUWy$bFX3ye^sn{IJ-ZrW297^qPE@F zNCeQV;YS0GK#VbY{GayT`XS0b`W78jL<9+uE?-gv=}v{_s40ahkFNF6FlBa%RJz zA$-Ej3%w>4a9AsnQE7wSNmSTIyvE#t_zg3uV40U`-W3%#)q6_iWz(Z9IJ|2&w;&4vt$VCHypOp)d-0lZ zFK$yh4F&w%+qGa1^Ld3iCG8ceh7&%z4!7E{$f+qs6yIxVY zWi|eytzKLN=T*EH`>Jl>O^ac~3^9pN%mb!9*GB{Ggvyy0mQ;xa0AHcxxJi(L3~$FY zYoC=YoPw|_agf!rtC?3zwf_b5LL;X=nJ&4Mdge0){Ta~Va4MKCf0Zl|Mq83v9tICj z-6i$9r$v#;+$lWVAn|FnZ6n!vEFjRyi=HrwT=rlscb?#)+0-e8O$&4xhATqzE|Tx}}?*Npp=O;YjeaWQ%&cb=Km`7`iPfDNWn zf<1v6w${xuZ`>hp+m4&y@%?j1JqIE$Cpu=YhP?KK!w@0`X(5$b!bO0rp&*GNw z6je7^Nh(}U7o`7PwfeuS7CI`yH5&Vc;w6n(Z})ZNfu!^U04+;iN^h^u`eK|7$g)`B zqf{Nz(@}LY^n;P+DC3T>GY`{V-9hPaes*m(LwoQ4UVQ9~O2~rzoU4CB#tDeR$iIxU z6oI>w2r5q_=ge3<c0U`44`nOGrXUfSjaO=JJ2=-E|vPez>huIGFrz32zH-Xnq2FxjH;e;i*IQYPGbt7E_TlG)~R=x7^amR|>o zjM_C_DUxStwPkfcSEx6}3>SXrO3r%I{YuUze=jBEX*E=j<=jZe8Dq zMvX#S1cd-M&o)D&bt$mvC{gm|BrVn(Qd>4-4Cgq_Y}z0basFle`*jBHuFZPW+LMAe zF8tXtRyu|DaGb{=)2buPoPO_cLhhLf#wN^_^^?aWtKU5X?%K_cMtJ!MO>^589wgO! za*=qJ>5Ox)?6VakGf748ZMra!?≶iSwS9*A+AD4@q1Bkn0N46j+H!d$JN92|802 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 literal 0 HcmV?d00001 diff --git a/nageru/ultimate.lua b/nageru/ultimate.lua new file mode 100644 index 0000000..ceaef45 --- /dev/null +++ b/nageru/ultimate.lua @@ -0,0 +1,736 @@ +-- Nageru theme for TFK mini-tournament 2017, based on the default theme. + +local transition_start = -2.0 +local transition_end = -1.0 +local transition_type = 0 +local transition_src_signal = 0 +local transition_dst_signal = 0 + +local neutral_colors = { + {0.5, 0.5, 0.5}, -- Input 0. + {0.5, 0.5, 0.5}, -- Input 1. + {0.5, 0.5, 0.5} -- Input 2. +} + +local overlay_transition_start = -2.0 +local overlay_transition_end = -1.0 +local overlay_alpha_src = 0.0 +local overlay_alpha_dst = 1.0 +local overlay_enabled = false + +local live_signal_num = 0 +local preview_signal_num = 1 + +-- Valid values for live_signal_num and preview_signal_num. +local INPUT0_SIGNAL_NUM = 0 +local INPUT1_SIGNAL_NUM = 1 +local INPUT2_SIGNAL_NUM = 2 +local STATIC_SIGNAL_NUM = 3 + +-- Preview-only signal showing the current signal with the overlay. +-- Not valid for live_signal_num! +local OVERLAY_SIGNAL_NUM = 4 + +-- Valid values for transition_type. (Cuts are done directly, so they need no entry.) +local NO_TRANSITION = 0 +local FADE_TRANSITION = 2 + +-- Last width/height/frame rate for each channel, if we have it. +-- Note that unlike the values we get from Nageru, the resolution is per +-- frame and not per field, since we deinterlace. +local last_resolution = {} + +local caspar_input = VideoInput.new("unix:///tmp/caspar.sock") +caspar_input:change_rate(2.0) + +-- Utility function to help creating many similar chains that can differ +-- in a free set of chosen parameters. +function make_cartesian_product(parms, callback) + return make_cartesian_product_internal(parms, callback, 1, {}) +end + +function make_cartesian_product_internal(parms, callback, index, args) + if index > #parms then + return callback(unpack(args)) + end + local ret = {} + for _, value in ipairs(parms[index]) do + args[index] = value + ret[value] = make_cartesian_product_internal(parms, callback, index + 1, args) + end + return ret +end + +-- An overlay with variable alpha. +function make_overlay(chain, base) + local image = chain:add_video_input(caspar_input, false) + local multiply_effect = chain:add_effect(MultiplyEffect.new()) + local overlay_effect = chain:add_effect(OverlayEffect.new(), base, multiply_effect) + return { + image = image, + multiply_effect = multiply_effect, + overlay_effect = overlay_effect + } +end + +function possibly_make_overlay(has_overlay, chain, base) + if has_overlay == true then + return make_overlay(chain, base) + else + return nil + end +end + +function make_fade_input(chain, signal, live, deint, scale) + local input, wb_effect, resample_effect, last + if live then + input = chain:add_live_input(false, deint) + input:connect_signal(signal) + last = input + else + input = chain:add_effect(ImageInput.new("tfk_pause.png")) + last = input + end + + -- If we cared about this for the non-main inputs, we would have + -- checked hq here and invoked ResizeEffect instead. + if scale then + resample_effect = chain:add_effect(ResampleEffect.new()) + last = resample_effect + end + + -- Make sure to put the white balance after the scaling (usually more efficient). + if live then + wb_effect = chain:add_effect(WhiteBalanceEffect.new()) + last = wb_effect + end + + return { + input = input, + wb_effect = wb_effect, + resample_effect = resample_effect, + last = last + } +end + +-- A chain to fade between two inputs, of which either can be a picture +-- or a live input. In practice only used live, but we still support the +-- hq parameter. +function make_fade_chain(input0_live, input0_deint, input0_scale, input1_live, input1_deint, input1_scale, has_overlay, hq) + local chain = EffectChain.new(16, 9) + + local input0 = make_fade_input(chain, INPUT0_SIGNAL_NUM, input0_live, input0_deint, input0_scale) + local input1 = make_fade_input(chain, INPUT1_SIGNAL_NUM, input1_live, input1_deint, input1_scale) + + local mix_effect = chain:add_effect(MixEffect.new(), input0.last, input1.last) + local overlay = possibly_make_overlay(has_overlay, chain, mix_effect) + + chain:finalize(hq) + + return { + chain = chain, + input0 = input0, + input1 = input1, + mix_effect = mix_effect, + overlay = overlay + } +end + +-- Chains to fade between two inputs, in various configurations. +local fade_chains = make_cartesian_product({ + {"static", "live", "livedeint"}, -- input0_type + {true, false}, -- input0_scale + {"static", "live", "livedeint"}, -- input1_type + {true, false}, -- input1_scale + {true, false}, -- has_overlay + {true} -- hq +}, function(input0_type, input0_scale, input1_type, input1_scale, has_overlay, hq) + local input0_live = (input0_type ~= "static") + local input1_live = (input1_type ~= "static") + local input0_deint = (input0_type == "livedeint") + local input1_deint = (input1_type == "livedeint") + return make_fade_chain(input0_live, input0_deint, input0_scale, input1_live, input1_deint, input1_scale, has_overlay, hq) +end) + +-- A chain to show a single input on screen. +function make_simple_chain(input_deint, input_scale, has_overlay, hq) + local chain = EffectChain.new(16, 9) + + local input = chain:add_live_input(false, input_deint) + input:connect_signal(0) -- First input card. Can be changed whenever you want. + + local resample_effect, resize_effect + if scale then + if hq then + resample_effect = chain:add_effect(ResampleEffect.new()) + else + resize_effect = chain:add_effect(ResizeEffect.new()) + end + end + + local wb_effect = chain:add_effect(WhiteBalanceEffect.new()) + local overlay = possibly_make_overlay(has_overlay, chain, wb_effect) + + chain:finalize(hq) + + return { + chain = chain, + input = input, + wb_effect = wb_effect, + resample_effect = resample_effect, + resize_effect = resize_effect, + overlay = overlay + } +end + +-- Make all possible combinations of single-input chains. +local simple_chains = make_cartesian_product({ + {"live", "livedeint"}, -- input_type + {true, false}, -- input_scale + {true, false}, -- has_overlay + {true, false} -- hq +}, function(input_type, input_scale, has_overlay, hq) + local input_deint = (input_type == "livedeint") + return make_simple_chain(input_deint, input_scale, has_overlay, hq) +end) + +-- A chain to show a single static picture on screen. +local static_chains = make_cartesian_product({ + {true, false}, -- has_overlay + {true, false} -- hq +}, function(has_overlay, hq) + local chain = EffectChain.new(16, 9) + local chain_input = chain:add_effect(ImageInput.new("tfk_pause.png")) + local overlay = possibly_make_overlay(has_overlay, chain, chain_input) + + chain:finalize(hq) + return { + chain = chain, + overlay = overlay + } +end) + +-- A chain to show the overlay and nothing more. LQ only, +-- since it is not a valid live signal. +local overlay_chain_lq = EffectChain.new(16, 9) +local overlay_chain_lq_input = overlay_chain_lq:add_video_input(caspar_input, false) +overlay_chain_lq:finalize(false) + +-- Used for indexing into the tables of chains. +function get_input_type(signals, signal_num) + if signal_num == STATIC_SIGNAL_NUM then + return "static" + elseif signals:get_interlaced(signal_num) then + return "livedeint" + else + return "live" + end +end + +function needs_scale(signals, signal_num, width, height) + if signal_num == STATIC_SIGNAL_NUM then + -- We assume this is already correctly scaled at load time. + return false + end + assert(is_plain_signal(signal_num)) + return (signals:get_width(signal_num) ~= width or signals:get_height(signal_num) ~= height) +end + +function set_scale_parameters_if_needed(chain_or_input, width, height) + if chain_or_input.resample_effect then + chain_or_input.resample_effect:set_int("width", width) + chain_or_input.resample_effect:set_int("height", height) + elseif chain_or_input.resize_effect then + chain_or_input.resize_effect:set_int("width", width) + chain_or_input.resize_effect:set_int("height", height) + end +end + +-- API ENTRY POINT +-- Returns the number of outputs in addition to the live (0) and preview (1). +-- Called only once, at the start of the program. +function num_channels() + return 5 +end + +function is_plain_signal(num) + return num >= INPUT0_SIGNAL_NUM and num <= INPUT2_SIGNAL_NUM +end + +-- Helper function to write e.g. “720p60”. The difference between this +-- and get_channel_resolution_raw() is that this one also can say that +-- there's no signal. +function get_channel_resolution(signal_num) + res = last_resolution[signal_num] + if (not res) or not res.is_connected then + return "disconnected" + end + if res.height <= 0 then + return "no signal" + end + if not res.has_signal then + if res.height == 525 then + -- Special mode for the USB3 cards. + return "no signal" + end + return get_channel_resolution_raw(res) .. ", no signal" + else + return get_channel_resolution_raw(res) + end +end + +-- Helper function to write e.g. “60” or “59.94”. +function get_frame_rate(res) + local nom = res.frame_rate_nom + local den = res.frame_rate_den + if nom % den == 0 then + return nom / den + else + return string.format("%.2f", nom / den) + end +end + +-- Helper function to write e.g. “720p60”. +function get_channel_resolution_raw(res) + if res.interlaced then + return res.height .. "i" .. get_frame_rate(res) + else + return res.height .. "p" .. get_frame_rate(res) + end +end + +-- API ENTRY POINT +-- Returns the name for each additional channel (starting from 2). +-- Called at the start of the program, and then each frame for live +-- channels in case they change resolution. +function channel_name(channel) + local signal_num = channel - 2 + if is_plain_signal(signal_num) then + return "Input " .. (signal_num + 1) .. " (" .. get_channel_resolution(signal_num) .. ")" + elseif signal_num == STATIC_SIGNAL_NUM then + return "Static picture" + elseif signal_num == OVERLAY_SIGNAL_NUM then + return "Overlay" + end +end + +-- API ENTRY POINT +-- Returns, given a channel number, which signal it corresponds to (starting from 0). +-- Should return -1 if the channel does not correspond to a simple signal. +-- (The information is used for whether right-click on the channel should bring up +-- an input selector or not.) +-- Called once for each channel, at the start of the program. +-- Will never be called for live (0) or preview (1). +function channel_signal(channel) + if channel == 2 then + return 0 + elseif channel == 3 then + return 1 + else + return -1 + end +end + +-- API ENTRY POINT +-- Called every frame. Returns the color (if any) to paint around the given +-- channel. Returns a CSS color (typically to mark live and preview signals); +-- "transparent" is allowed. +-- Will never be called for live (0) or preview (1). +function channel_color(channel) + if transition_type ~= NO_TRANSITION then + if channel_involved_in(channel, transition_src_signal) or + channel_involved_in(channel, transition_dst_signal) then + return "#f00" + end + else + if channel_involved_in(channel, live_signal_num) then + return "#f00" + end + end + if channel_involved_in(channel, preview_signal_num) then + return "#0f0" + end + return "transparent" +end + +function channel_involved_in(channel, signal_num) + if is_plain_signal(signal_num) then + return channel == (signal_num + 2) + end + if signal_num == STATIC_SIGNAL_NUM then + return (channel == 5) + end + return false +end + +-- API ENTRY POINT +-- Returns if a given channel supports setting white balance (starting from 2). +-- Called only once for each channel, at the start of the program. +function supports_set_wb(channel) + return is_plain_signal(channel - 2) +end + +-- API ENTRY POINT +-- Gets called with a new gray point when the white balance is changing. +-- The color is in linear light (not sRGB gamma). +function set_wb(channel, red, green, blue) + if is_plain_signal(channel - 2) then + neutral_colors[channel - 2 + 1] = { red, green, blue } + end +end + +function finish_transitions(t) + if transition_type ~= NO_TRANSITION and t >= transition_end then + live_signal_num = transition_dst_signal + transition_type = NO_TRANSITION + end + + -- Disable the overlay if it is no longer visible. + if overlay_enabled and t > overlay_transition_end and overlay_alpha_dst == 0.0 then + overlay_enabled = false + print("Turning off overlay") + end +end + +function in_transition(t) + return t >= transition_start and t <= transition_end +end + +-- API ENTRY POINT +-- Called every frame. +function get_transitions(t) + if preview_signal_num == OVERLAY_SIGNAL_NUM then + if t < overlay_transition_end then + -- Fade in progress. + return {} + end + if overlay_enabled then + return {"Overlay off", "", "Fade ovl out"} + else + return {"Overlay on", "", "Fade ovl in"} + end + end + + if in_transition(t) then + -- Transition already in progress, the only thing we can do is really + -- cut to the preview. (TODO: Make an “abort” and/or “finish”, too?) + return {"Cut"} + end + + if live_signal_num == preview_signal_num then + -- No transitions possible. + return {} + end + + if (is_plain_signal(live_signal_num) or live_signal_num == STATIC_SIGNAL_NUM) and + (is_plain_signal(preview_signal_num) or preview_signal_num == STATIC_SIGNAL_NUM) then + return {"Cut", "", "Fade"} + end + + return {"Cut"} +end + +function swap_preview_live() + local temp = live_signal_num + live_signal_num = preview_signal_num + preview_signal_num = temp +end + +function start_transition(type_, t, duration) + transition_start = t + transition_end = t + duration + transition_type = type_ + transition_src_signal = live_signal_num + transition_dst_signal = preview_signal_num + swap_preview_live() +end + +-- API ENTRY POINT +-- Called when the user clicks a transition button. +function transition_clicked(num, t) + if preview_signal_num == OVERLAY_SIGNAL_NUM then + if num == 0 then + -- Cut. + overlay_transition_start = -2.0 + overlay_transition_end = -1.0 + if overlay_enabled then + overlay_enabled = false + overlay_alpha_src = 0.0 + overlay_alpha_dst = 0.0 + else + overlay_enabled = true + overlay_alpha_src = 1.0 + overlay_alpha_dst = 1.0 + end + elseif num == 2 then + -- Fade. + overlay_transition_start = t + overlay_transition_end = t + 1.0 + if overlay_enabled then + overlay_alpha_src = 1.0 + overlay_alpha_dst = 0.0 + else + overlay_alpha_src = 0.0 + overlay_alpha_dst = 1.0 + end + overlay_enabled = true + end + return + end + + if num == 0 then + -- Cut. + if in_transition(t) then + -- Ongoing transition; finish it immediately before the cut. + finish_transitions(transition_end) + end + + swap_preview_live() + elseif num == 1 then + -- Zoom. + finish_transitions(t) + + if live_signal_num == preview_signal_num then + -- Nothing to do. + return + end + + if is_plain_signal(live_signal_num) and is_plain_signal(preview_signal_num) then + -- We can't zoom between these. Just make a cut. + io.write("Cutting from " .. live_signal_num .. " to " .. live_signal_num .. "\n") + swap_preview_live() + return + end + elseif num == 2 then + finish_transitions(t) + + -- Fade. + if (live_signal_num ~= preview_signal_num) and + (is_plain_signal(live_signal_num) or + live_signal_num == STATIC_SIGNAL_NUM) and + (is_plain_signal(preview_signal_num) or + preview_signal_num == STATIC_SIGNAL_NUM) then + start_transition(FADE_TRANSITION, t, 1.0) + else + -- Fades involving SBS are ignored (we have no chain for it). + end + end +end + +-- API ENTRY POINT +function channel_clicked(num) + preview_signal_num = num +end + +function get_fade_chain(signals, t, width, height, input_resolution) + local input0_type = get_input_type(signals, transition_src_signal) + local input0_scale = needs_scale(signals, transition_src_signal, width, height) + local input1_type = get_input_type(signals, transition_dst_signal) + local input1_scale = needs_scale(signals, transition_dst_signal, width, height) + local chain = fade_chains[input0_type][input0_scale][input1_type][input1_scale][overlay_enabled][true] + prepare = function() + if input0_type == "live" or input0_type == "livedeint" then + chain.input0.input:connect_signal(transition_src_signal) + set_neutral_color_from_signal(chain.input0.wb_effect, transition_src_signal) + end + set_scale_parameters_if_needed(chain.input0, width, height) + if input1_type == "live" or input1_type == "livedeint" then + chain.input1.input:connect_signal(transition_dst_signal) + set_neutral_color_from_signal(chain.input1.wb_effect, transition_dst_signal) + end + set_scale_parameters_if_needed(chain.input1, width, height) + local tt = calc_fade_progress(t, transition_start, transition_end) + + chain.mix_effect:set_float("strength_first", 1.0 - tt) + chain.mix_effect:set_float("strength_second", tt) + prepare_overlay_live(chain, t) + end + return chain.chain, prepare +end + +-- API ENTRY POINT +-- Called every frame. Get the chain for displaying at input , +-- where 0 is live, 1 is preview, 2 is the first channel to display +-- in the bottom bar, and so on up to num_channels()+1. t is the +-- current time in seconds. width and height are the dimensions of +-- the output, although you can ignore them if you don't need them +-- (they're useful if you want to e.g. know what to resample by). +-- +-- is basically an exposed InputState, which you can use to +-- query for information about the signals at the point of the current +-- frame. In particular, you can call get_width() and get_height() +-- for any signal number, and use that to e.g. assist in chain selection. +-- +-- You should return two objects; the chain itself, and then a +-- function (taking no parameters) that is run just before rendering. +-- The function needs to call connect_signal on any inputs, so that +-- it gets updated video data for the given frame. (You are allowed +-- to switch which input your input is getting from between frames, +-- but not calling connect_signal results in undefined behavior.) +-- If you want to change any parameters in the chain, this is also +-- the right place. +-- +-- NOTE: The chain returned must be finalized with the Y'CbCr flag +-- if and only if num==0. +function get_chain(num, t, width, height, signals) + local input_resolution = {} + for signal_num=0,2 do + local res = { + width = signals:get_width(signal_num), + height = signals:get_height(signal_num), + interlaced = signals:get_interlaced(signal_num), + has_signal = signals:get_has_signal(signal_num), + is_connected = signals:get_is_connected(signal_num), + frame_rate_nom = signals:get_frame_rate_nom(signal_num), + frame_rate_den = signals:get_frame_rate_den(signal_num) + } + + if res.interlaced then + -- Convert height from frame height to field height. + -- (Needed for e.g. place_rectangle.) + res.height = res.height * 2 + + -- Show field rate instead of frame rate; really for cosmetics only + -- (and actually contrary to EBU recommendations, although in line + -- with typical user expectations). + res.frame_rate_nom = res.frame_rate_nom * 2 + end + + input_resolution[signal_num] = res + end + last_resolution = input_resolution + + if num == 0 then -- Live. + -- See if we're in a transition. + finish_transitions(t) + if transition_type == FADE_TRANSITION then + return get_fade_chain(signals, t, width, height, input_resolution) + elseif is_plain_signal(live_signal_num) then + local input_type = get_input_type(signals, live_signal_num) + local input_scale = needs_scale(signals, live_signal_num, width, height) + local chain = simple_chains[input_type][input_scale][overlay_enabled][true] + prepare = function() + chain.input:connect_signal(live_signal_num) + set_scale_parameters_if_needed(chain, width, height) + set_neutral_color_from_signal(chain.wb_effect, live_signal_num) + prepare_overlay_live(chain, t) + end + return chain.chain, prepare + elseif live_signal_num == STATIC_SIGNAL_NUM then -- Static picture. + local chain = static_chains[overlay_enabled][true] + prepare = function() + prepare_overlay_live(chain, t) + end + return chain.chain, prepare + else + assert(false) + end + end + + -- We do not show overlays on the individual preview inputs. + -- The M/E preview matches what we'd put live by doing a transition, as always. + local show_overlay = false + if num == 1 then -- Preview. + if preview_signal_num == OVERLAY_SIGNAL_NUM then + num = live_signal_num + 2 + show_overlay = not overlay_enabled + + if transition_type ~= NO_TRANSITION then + num = transition_dst_signal + 2 + end + else + num = preview_signal_num + 2 + show_overlay = overlay_enabled + end + end + + -- Individual preview inputs (usually without overlay). + if is_plain_signal(num - 2) then + local signal_num = num - 2 + local input_type = get_input_type(signals, signal_num) + local input_scale = needs_scale(signals, signal_num, width, height) + local chain = simple_chains[input_type][input_scale][show_overlay][false] + prepare = function() + chain.input:connect_signal(signal_num) + set_scale_parameters_if_needed(chain, width, height) + set_neutral_color(chain.wb_effect, neutral_colors[signal_num + 1]) + prepare_overlay_static(chain, t) + end + return chain.chain, prepare + end + if num == STATIC_SIGNAL_NUM + 2 then + local chain = static_chains[show_overlay][false] + prepare = function() + prepare_overlay_static(chain, t) + end + return chain.chain, prepare + end + if num == OVERLAY_SIGNAL_NUM + 2 then + prepare = function() +-- prepare_overlay(overlay_chain_lq, t) + end + return overlay_chain_lq, prepare + end +end + +-- This is broken, of course (even for positive numbers), but Lua doesn't give us access to real rounding. +function round(x) + return math.floor(x + 0.5) +end + +function prepare_overlay_live(chain, t) + if chain.overlay then + local tt = calc_fade_progress(t, overlay_transition_start, overlay_transition_end) + overlay_alpha = overlay_alpha_src + tt * (overlay_alpha_dst - overlay_alpha_src) + --print("overlay_alpha=" .. overlay_alpha .. " [" .. overlay_alpha_src .. "," .. overlay_alpha_dst .. "]@" .. tt) + if t > overlay_transition_end and overlay_alpha_dst == 0.0 then + overlay_enabled = false -- Takes effect next frame. + -- print("Turning off overlay") + end + chain.overlay.multiply_effect:set_vec4("factor", overlay_alpha, overlay_alpha, overlay_alpha, overlay_alpha) + end +end + +function prepare_overlay_static(chain) + if chain.overlay then + chain.overlay.multiply_effect:set_vec4("factor", 1.0, 1.0, 1.0, 1.0) + end +end + +function set_neutral_color(effect, color) + effect:set_vec3("neutral_color", color[1], color[2], color[3]) +end + +function set_neutral_color_from_signal(effect, signal) + if is_plain_signal(signal) then + set_neutral_color(effect, neutral_colors[signal - INPUT0_SIGNAL_NUM + 1]) + end +end + +function calc_zoom_progress(t) + if t < transition_start then + return 0.0 + elseif t > transition_end then + return 1.0 + else + local tt = (t - transition_start) / (transition_end - transition_start) + -- Smooth it a bit. + return math.sin(tt * 3.14159265358 * 0.5) + end +end + +function calc_fade_progress(t, transition_start, transition_end) + local tt = (t - transition_start) / (transition_end - transition_start) + if tt < 0.0 then + return 0.0 + elseif tt > 1.0 then + return 1.0 + end + + -- Make the fade look maybe a tad more natural, by pumping it + -- through a sigmoid function. + tt = 10.0 * tt - 5.0 + tt = 1.0 / (1.0 + math.exp(-tt)) + + return tt +end -- 2.39.2