From 92d3c5732f95ad6117a1e518b70fb35ebf5ac785 Mon Sep 17 00:00:00 2001 From: Nils Hasenbanck Date: Tue, 17 Dec 2024 14:30:23 +0100 Subject: [PATCH] Implement SDF rendering for rectangles Also updates the interface images for new SDF based icons created by eleriaqueen. --- korangar/archive/data/texture/checked_box.png | Bin 267547 -> 0 bytes .../archive/data/texture/collapsed_arrow.png | Bin 270048 -> 915 bytes .../archive/data/texture/expanded_arrow.png | Bin 270030 -> 942 bytes korangar/archive/data/texture/filled_box.png | Bin 0 -> 797 bytes .../archive/data/texture/unchecked_box.png | Bin 267547 -> 0 bytes .../archive/data/texture/unfilled_box.png | Bin 0 -> 652 bytes korangar/src/graphics/instruction.rs | 16 ++++ .../graphics/passes/interface/rectangle.rs | 75 +++++++++++++++-- .../passes/interface/shader/rectangle.wgsl | 13 ++- .../interface/shader/rectangle_bindless.wgsl | 9 +- .../passes/postprocessing/rectangle.rs | 77 +++++++++++++++--- .../postprocessing/shader/rectangle.wgsl | 28 +++++-- .../shader/rectangle_bindless.wgsl | 28 +++++-- korangar/src/renderer/game_interface.rs | 31 +++++++ korangar/src/renderer/interface.rs | 42 +++++++--- korangar/src/renderer/mod.rs | 2 + 16 files changed, 267 insertions(+), 54 deletions(-) delete mode 100755 korangar/archive/data/texture/checked_box.png create mode 100644 korangar/archive/data/texture/filled_box.png delete mode 100755 korangar/archive/data/texture/unchecked_box.png create mode 100644 korangar/archive/data/texture/unfilled_box.png diff --git a/korangar/archive/data/texture/checked_box.png b/korangar/archive/data/texture/checked_box.png deleted file mode 100755 index 0b8b03e2d13421522c4e535d33386fb78021cac3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 267547 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 OzDuvpYwmw?(*FYh^1o#O diff --git a/korangar/archive/data/texture/collapsed_arrow.png b/korangar/archive/data/texture/collapsed_arrow.png index bceca4523f4f6b1241e445159f53287e80cb08c5..363d37408bf081c66bf3f30ee06035bc1cb9ac1b 100755 GIT binary patch literal 915 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 ai*KD69^GK0=L_mUn|{Aq{M~2#?Ee9Z@tIrz diff --git a/korangar/archive/data/texture/expanded_arrow.png b/korangar/archive/data/texture/expanded_arrow.png index ea6b5f01a94896145ca5d53980fd20ce03b60cbe..ac5eef0ea9590b30640d6f31580214962ea3d105 100755 GIT binary patch literal 942 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE3?yBabRA=0V4M`-6XN>+|Nnpg{sBoi1H#2c zLX-hzAqv3yMhWVK03=lJi=T)AMp9czkY6wZgNcQem5q&^or8mulZ%U+n}>7%&fR70SEqj3N?OsQ_Zt+J#*p10!E{SOOh^LPg9;WQ#1I`nP`#bPyggLvlc)4 z+_Ej@^2-WN)v0T&Lyz3c6Knlqur-;j^yxISWhWx8{_c@hpT5s8?AS*EiH>j1?%SW0 zl|Nsx{B~BxJUvB62Cd*!V0v-&ba4!+m{WT>G@8kgq4gnix5s7$g+&VMlDfIHwn-!` zN+<_{Kl$u}H|)-zJGYglhqd-?{o3oZVWt4*hOKkI&5bo=cdFLBZ*L*O-`5v>@Z`!J%<0cP_kW1> zVhz7;uF`SG%d(*Sya9iI;7f&nU(W0axWpH*KL33YUrkNjN%s5ppZwx%-aiv>)rn|* TD=fbU7{v^pu6{1-oD!M<2xNib literal 270030 zcmeI52V7H06Tl-_QL&5Nh$uFMgpQ!1SWr<8v0)7m6p8?GyRMe}Z$Kh})I(Kz) z<8VsAX$el*(hv<2ZS>)A$|pv;_YZXwgmZ&Lfj+*Ygxt_EK|-!D!WSM!q`z1)VB1Zb zs-3>=nK49XlDFBZ2SFtx%N+XBcD1`tT5Idq&o{3u{j^D}+sIWLYrSkg^mDs!ZLb~v z*!}9$g;z%Ut}ppjlwuMVHZmf6_UC~ek`8B#fAj13@Gn`DBqn%2%$%6mq z{srrfgm*jNYQeXen|7Og2tT;r)$Ku-gu`AV!|&*B^42>O?@;OK-D+n7z25p?9hdcC z;Wa(``=btjToyOBpYhO*%NnLUT(HMuMYSiN2C=ThO!abL;8%zjpnj$>2H9quL1h$Lob#?B$(nx#9D$Ce9}3?jN6*-PqV;r0*}) zd1n)+h-R!ja4P$HSi6936`$#K-*2He>GWXl!=DZ$Mc%c&-Q95YIM3q;*MuAIF54k% z>|a7}r*qZZ59xmS`sL%JF)rS&ugv-l*)cWv(3Dy&##ir`P;L2s*R-UBA)_30D;qZ0 z+M{#T+GRV%bQ5&0xpsQxQ{5)o^`6`Oq+@9(%hpY6hjjbx{)PJX%c6R`?7sHIHG!+; zgO<&+{qApA-*cC!@6(f_^-~g>p55$`8b9*#5Vy>8EsxLmD`cN{TI!4?S5lV#yL99> zkM4Us{I(oA{zr76|2y9;Tld@^Gh+DtbGMe4k8BvcZvNCc{86bFw_P-TVE#6Bz=pGS zH=eiL7C+*3pFg%Hq(2>KwLbps)xmpTB;0s8)ve8w`)mKKm)O(c#k*ctSHypP^0xed z1;&1v=YAhLVr5)#>T`$5HnAHY&6;(*mC?;pb!xBO;V^u4w{sWGAK6Zt`&e&w4>t$f z?)F~ZW`WZq?=MI+4l(%U%fL5b0}j2d`EBIG*1c{Sn16V5FuRps$^g&XwWIc|E@Nqw zF!ycZ`~HcS{pNZtj2G5(^%E`|IdJTZYvo?tKU8*n{gA5DF8Dn=(yP3e_mZgQ?Mff4 zQ$Nh>I(Or9QKVsoL)FUlKCNr7b9>Ef%g80WYMs=roqWo6_KxR+j0a542peLh!`sul zRjb)InhKWKj$RQ_V`136rG9Y@dexo3Ir_*wiw#!2jk|YAx3A;Y#@=+@5|8tJul#lJ z)KdLTQG@6Ao*neweqHr@ZQRzlK0STOGb}pYvT~`iRR+CE<~-DO?mN&^*suM;?&-tA z25)-jexqKaZDF0y3Pr0I1$U{JHq7q#9xdGB4Ez^t791|MzUl_cH6`w+Zs7-=G3nE! z@@3pptgm%Dw=WM0hq$|f#VZ;Yw5W`Vc=!t!HB$9y;*5tGo& zIA-Y|##c_An(!&q?4z%q?*$v%GfslnaWU4_?M%u-5XbI&G~L!r?wlyIFFfzTuLS0{-svF$+hQo71kperSsG+d7?GNl}+-f ze|o0}H+_{>%_`K>Zb{|-vAgyrJeuQH(|@lpf$tD}E~#S1rA^E9+Eu8oBodBBbw}WtQ|I-bEjparV$ZCvr4r-Fm85elEsCMPuzD^xwmP@q*ZIP zYW=2nyZ7ZG+<|qvwsE<)$!3?RansA6tC~)<(se)i{8p6hYJPe^3b(JH$fIM&O-J;a z|51OZ>vf%zW5X`IN_6b-V0_j4f&SlWKVCWEYwgG1BDe-~%Kl?8@6NVi2_q`ab8>G` z;ge3)l3cx`6V|<)&@9|2@y@e3XCqg|3D2CZ`**#`3Fb38*6w`dQu)72_ta|^!s}Q6 z^vg|y#+Nzs^=SJGCkAwBn7;VS^#g|n{A0BLb)8S0>Rzuo;->Fk2_5Q|6d0#@WgL4j zbBx~P#QKqo%b$Ca*zQc97ac+~QWtiZeS$Y3;pV_&(=9}6XL>bx-9LD8x6Vhp9Cd5C zyTfnRLvJ7LUnOPB%t|*5HdjpZMOojz6z08d^aB&OjDEiUDNT(pJ2V}qpLKF>=HAy{eN2+R zUUxtH>4MRUi7k?wG(32#KBsvDPH96Olgy(thpj1H$%I$OjyGeZewX>3y7r7K&!52= zHo?Pq+UYtmK?CeJRPej@rv6ObM$?-cZ7n-~bYR_F)3M=`7i;umYEEb} zW})ka(KqLZdb=O$!_>I#>{B{ zAZydp$v*KX6Ia^yS;Qrp)?NIvg~0;ObjPc6wmuko zf9u%_pW8&OZnUs-rNrJhy9Ul$e6w5ahGjlhXp%AUNy&QKKJ0QlX>C2~$?j2=^|FIs z3U$L%-gsCwtG>{*uGxvrH?0re3Jd(L<}b5Ku5VEOww}w49bs+W%t~99IMpKPi_6wk zS30&Ru`grN;f%rUvsyK8G}d%z@6Gr8x-Fh|E4KX(or4vc8AMjxKk;r#oup=+2KO*t zlf3R%=hNk$4Y|bgGjR7gzf^y!{ieHnHcVP%D%$?UEb7y#JBLrjC#?%@m$4|mD>o^1 zMU$-w!{%4p{@UY`-VU#XMe#c8zYKBH)A4(Qlla)La{Ozu;EpV7TJSuQ@7?UN_` z{rj?sLwt|lUDPA$MVl=7+d2zzS(Bz4k(k|jRR z9zP)PW^mbK8y4Q$aoehPK=Q^ae-3%FJh_2MOhEN_ajtXq$2m>A`O2o}(b78OhBf|8 z-{)!H57%Pe@{^a}yA~p_;CedFyQ=dbUB}??omb0#U9P*mM3rx)LL$P4mbT~Y0Bv4S zpc?NR6zYX)yhArf{Uc^&6F$#ya6BIOzRl&7fHu#+EwOsStz7m(_Cd#!6PqWy_KSO^z+H$@Jm*IHBV=7DcC?v_U+iw)wyFw@ty&y zh#foMq3d7m>m483dyip_Qf;Q$l#J_H(`miU$QmQ-PwOc$WtCUNfnCb>ylK0%X zbJFul^6>%v%Jg%r{Dl)7Dsl^*U-jFf>K?};gKo|Z|Ii@(6=!u{&!ty*B}OFpH~ojl zTRxzM?)JwMqsPtSwlGgwykK3)^f}w3K7NcexI5s*`E1+BD{;p;E4$jKRJh#qHg`@y zdg(`F?^SMjszs)4=6+`bqjC2W?q$|}bTCEde1#>O?%M}X>wjk7j!Q@5hK)RS`Iw;3 z<>o`XM#YJ4--}z=A}+Ys*Q3Mw4ju5&?yTV0&S_1$R$jeoqG7ikRaW;gKHeeby_f%& zj@yPBF6yw&u$FC2*D0mb{+;wK`BlKyo2ly-Ri9O2x#^s@JiU@(6C$q!C(W(@=Qy2@ zD<`x(^u+X9^pakewz!!5TJoL0uE8}Imo(kh;nB&)9j%1@-dwIOvb~c%E2+6|g_}AK zenSFhkBx21Y5ufDux`D2I$mS`9uoNW<;$zLzdBrg{Ho0KdZHbpr)_x!d%J93*u(XA z>0##;=-*o49q1`+9pN7Yqk_Y+Zx<0H@bVLeay^B^eFGc}UnL$k?v( zC>-J2HBuz(9of^}E7H%)*4waMTRr;-J1D?k7%JdK_>T$*v5Rmp%qiCn&hfUXAvY&U zsGoyje-~G7$3T&gYth=GwV6q$2;VTiVOu?}y~x|g&dsTFZV_G(0@K zb+~!!K+$kho~^B|sTtpt&o_Y-CLv=2LIn{f0U?dCi0@@M2}8U@FqC}*1GreGz%y`k zsDq&)Jm-q#^AB=y$tyk}B$op4FpUrdnetkjnfm*iO6CX&?Gy%uM(6VqtD>W8&#)X=dVOYaKg(n#^8w09rL|~!QZdGPk~XsIghy9oMCGx@cLd!h#*Yp zol_Cy`~JvlgdkwJ5axI8fD+&LEugb(g;snapYH?xWNU3=!4p7#3oWfotSrs=o;+J` zb4zbw{?bDNeL}+pBBA4OXeqP?22f6GxXp4XnZZAIo~0e%){bw{ z(u{9sW@c!rgeH3VSXuD-0uvi+z8ADp-~(sYo+g&w78X|47B-${!tZ^X2asVC`6gyo zCT4ulbnVRHpIQDU+MD9SCGJ#v)Bkk)_XH9v9iaJs4^~iEkWKSeNkSQ^ZF1g{-`~RL!7yyc1IPBQ&R(snNc6;T5x(*28 za9TIUqeR5|c3~V2m*ec@=pIpm!;Q`upR*^V|A+t)AOb{y2oM1xKm>>Y5g-CYfCvx) zB0vO)01+SpM1Tko0U|&IhyW2F0z`la5CQchkaEpCQv5D}dbWV1CIUo&2oM1xKm>>Y z5g-CYfCvx)B0vO)01+SpM1Tko0U|&IhyW2F0z`la5CI}U1SAPKRNB{z-UW~(Lgz$) z2oM1xKm>>Y5g-CYfCvx)B0vO)01+SpM1Tko0U|&IhyW2F0z`la5CI}U1k{@Vy$hh; z{YTOh0U|&IhyW2F0z`la5CO#zD51EbsbnI+ZUW!FeZ%oz@+XHb+%NT$XFtoMPWO+L zC{dydEdbEN+8kgK=s^25d7u|IDRGi(;~e-3?dHP*a1r5XbtvLfps>NCDbH{LprBm@ z*5l;ICg-ev^eLc~p90!7#3 zP+J1i3!D7dssgnEd;l6j1&FT0Q5UZ%5CI~fRs?YW-wGChPlZWcpay^$AmclTA`8n* z&ximKU@d{jq9#8|{!201;3N0;fSrTUY?T6(#LYH2}<*TRVtI2vir$7XV0P6|F!JIuIt(1js0mOyC zR=@zx@e9Gq;(HVm0V2RU0{Dx+maqV1NGn;98UPjq1wMgjnzV&dIwC*>lt*C6s>N*! zco!f>mW2SNl}a1HgrE_Wf#?z(P4Sun5g-DrBJdofX$%X%8(E~1N*llepSP83mcQ09Xrb1IVlxBixjU z2*{NHzO0wy3502>GHU=>5v(|5R*Wfe%0~p`M~A>ucuj!_ z5CNqU__xuK(dH8G0_1rGVJZb9Z2&6+jUXE${Bn>25g-D}Cy?J02*dgrYXjo?Kr6s6 zBYKFhDJB9$K;Z=b;{=3hjf^z_i3?@!U(j758Y&Wm0oNO00jYo z(5zULyo921hyW2NkN`RXk=x|Q8swq@U_qb-U|EOZXouGnhyW3gD*=2J|EEqsnARj0 z4FD^Ll?hE0;hzP`tQZ2JKm_DVAkPU%c2ciDB;Ey(UoG6|jPY_)3B+Q7YOn^*2aB&M zCIUpD*aV971j4iixv2ya0))c(Yl&+*B?3gCcm#^{1j4j%&{#}$#LSdSH=0f;36O@M5RiD6Jo1Y{$Ce`d3X57QH}Ws@znLNovg z5zze**%p%kLZ?JPN&+%@0+F)J|0GlB0syPmRj83{i~R>X-5>&m5wg_LP284(}?9FEMMK$t>Ps5XE?fkr@f#+ddF<L?9ml#-2d( zl_JB1vNQnP3LFEu;$@JHk`e)JBf!`b2vbl>(*RIF&;lAlgnuQ_!)ppefC%IfKu;i@ z@~)J0qBIQv+XD@}3(-s^wT-GF0_s8le_xM3s8f1Sss@0q11+E&MCovlZ7~Ewfe3Io zYvIFjNC6;j9ef2-l*@5;a&#}?v3zeSRU1Ijq0#vA1KAmqZ$DCL>Pz5X5Isy);wyat z$ZhCah?7;-XsVY8u!w+MJb^H6kJ7gTVnJbBU<&8>o`9+rA+abF69H8bkeeqErVUWp z|AdM%GF=x-i_v1=>7eL%zm2L;bLcq$n7tRlguPG)18cZP1D+n9f z$O>%$L4Zck0-_6Wl)`HYL_h-xD9i~6Q&z0d08n_)0`SK}WMYhIPf|X0AfPZOAWR$2 z8Vvv&09t@PM7Q9mj@J~3fCdpjCm^lhgYFZX+Qb?S0HFY!HxNx`6Cjd>2*`;*B-%55l{jFS)71;`ZTzQ(%%KhW5A8h7|*&rfmk}& z8<3qbF${{;l>i#XXbGQi8EkC;D^&u71<>w7M0Up5I&w%ZX$UCI6Nogz6qJUw8UP9l zT0mKdZooly#t;Yvbs~VCKpMjb8UCq@wSl!701^XuA0Z;!VyqoLBv>H?l9?z4>mdIH(aHlcndk6LU2P=I4r9Eg zKm=Gs06l>i!201ruPMClIFXRcj4E zqS2vn{$ApmPKkgb39!x+2-C)D!~y_YfqMXe%!)A`1(Z(~0=Va&Crbu4r`3op00M?> z0Gbs`hoe4TQy>BgBG4B;aJDF@Y^4{g5gGtegHA!SV!tY#AXTVM1ke+RM%lI37!5!? z3PBS{f^$dlHN`|gP6W^sh&_DJoG4y-7b*tv*!3=exIG%94Tu{AF_{>XfI+8nBOr@c z5V=*V=z=tE0f5yS?Fg(_G&m|>s|cVIkZ?_GvBoU`xt$aOG5+0_0uhi00oFSKVcJNI zTmV1|cm_botQgZ#LHQ&Jpc9ZOk~cKzTq75N+zy%xahfJ|7PUns1k}O_2vaf|_ZI<4 z5b)OlXSm)gd5_MCfD8oG#tDcFZOWHalQjT*PhcOkHa=gA>4FGIPe5&)fJon@{3$hB z1Hh(&7SI@?D{z#-YYId_N&*Mq1Ei~zX{AW!W7M)aJKqJ!6P_ELFMe-y z3jzv6Kw1L$8+82jnZ^f=R|&8OK`p2N5&npP?2I803PllE3m+Uqib|vj&oy2Hz)phB zdL$KMG!zwAYnzM(U`|tu>j=u7MgfPQ?C?=Kw$*b(i2Ew4Jz!JR%`*p0AMT7 z2G0M2L#x^?Za>9E5>Q)DAVs$9CkeDk1Hi4oap0g)zxDh{ztU}H1k~0O2(#vD;U^(z z0Sy4wH8}K`LZf^dNdUKpR`4N#e*w^%pj8?G_9}GnJ&4G*nAQw&sT&$1_sL&ldJ}jr zmCJEd$3!#{Wmd0pN z#uz>f(71$F2CW|W(D7tjOe=?dUZXX}6G&c*WIWMo4FFkz7El8sv?@{suPJB^0rUjY z3O)orX-$g@XsA|e0LUX({hLq#8@i?01R}M4@?-aEy#{~~Kno}d(PcQA;WY(~CxD(n zY+(UFrvUN~LY-@E)#zOSF#xUC1`q@ciZ2j}#84>KXacwZh!nOEs2Mt10CGDF1_ap| zQ?tR#P+X1l1j3L7Z3iU5!M4BUl$iGqZcF0wH(g1$I znL9wDf4EJT>Q6wUJ%KRo9?}2`AO~6iE{ynRBZ~qa(=GKQpz)qSn05(i00oc(EdY&0 z1j3=1zZn-$C*4vg0p)lCS@gLLylSX6b^(4QPK&{hL~^fTK{x@YWMb?meAMXnLFmif zY9y~xMWyXPA-G{%&;TA^g`<2S$>pkl1#UxDvMt7tpB%H{o`0Sk%hRf& zXbVt`?uKnZMaYhpDC!iW7|L2a0)1gI-cr0GWY7KO^D7pLypm`@U=uixvqzx1U9%coN02fiRGgeHF46>tHCwo|g(W(mth6G3hULaJ(sF=bDkSCDB`AGegGythl6`3#u zQlNzj3W_H{o_Kz;zC z=u6T76ixVt@?k4*5^k;g;Wk}lspnh15h$>tPZq*S`eW@k@9#=A%_6+Xax)8 zCpPg|5&i}~B)J@CCr5WS$)ylkxX~HoNhMGS+QJKkQU4fHke#vom?GJ>8sryGGp|S` zP*J~vT2Kb6PKCorMIx}NT6Dl*3kv``1)!ir0;B;b5w>Jixu15ClJ~Uq94EbqCckQW zpB4bsaL=g~20hvqJETGp*ibcj0#RWv&=x?2@Ud#x3bcagJRI6+TZ}w`;2=<8APqo; z@Ud#p0`Pl)6)F}(Rn?Ox5LJ=St(P1ajv<>@BT%7eI0#k~SboLxty{5$HnoXm+@{3dK-X)o4%61Qx+B z%Bqm+DVP9h0|j$Y`dyd|*-)vr{6vmCfhc{16HQVF73aHC=(DoN{VZYAtB{ix1k)MWxnCmHm_eZ2^9YMl}y$a%4cw zF{-Iu;kB-($**w6GF3ntfK0fQlNhuBO|&hBo%vs{Kng@081k!Ekw5eM8E`WG!kv1SE!Lk@M z0{rz{ARL$!5T<0xbRf0eoCG|Slm6d0I;}oP&8No z)ZNZld(dW*S&mt2#iK0%%ey}J8}wN$7xQQ0p(hZU{6C|^g8QTau%Hu)5&^UTbu=r6 zo0!vMAfY&S917ZxhCh)h8Z2#^M#2Aw1+B1|qen;64an&TwprE_)@ zAPs=s{ZpWHpaq~=u`_U(6_`LZH}Umldsv`OsHS?Vl?egT0GLoyaUPgtXjTk=Gr*=m zPC(ey8&b+b8i16b*q9770k)VGBPSqi93WE2L>hn;kXW1~0A$0-r|LjXKvdlWRKIo- z04-n|9I6b@pmKdRr0-FE?o)afK(gbw(HY|$m@23lR4fr70!#?Nq%?rzoe~y-HB98AJVby9D3}0D z{%8d+0Jy-Q5km?@fC#XS08Gv@aHK165r}46o28fM;pCR-^e%w(yeOsG6M%)FkAfBh zeD^>TJ)Nq3pHl;fKt2L6Q49fygf55x5nv|)nEWl_$dcnCa0bevAC|DQyGbe{ z@LvKjVdu+n0ciK%8t4uYAOfr<0F%Em953Xs2;gs$DG&i7pl$?U@&^`k0l;m9k-D{; zhy*tD(kC&lSDHhb(#*K>fRsS|A?+ zFsXMlSP;VHQ#+MH1c-o23Bcs%!tq{)Mc@XcMNg&_hyW4L1OhOjWwA5XM-$piZ6E?f zAeR6v02Sbn#;n*WNJplnY2*+AO(OskyC}0_Xl%qz)7nk#Ap%4I2;e6>9EF(`+f1N{ z01?n&0(T; zrK5p7zi4U4W3$0G`6pNeMBh(Ke9>YQ)N~?11c(3;AOb{y2oM1xKm>>Y5g-CYKrIRQ pI&|Ct-*K4Jy8yCuAN&yH+qd9Mn>UBe+xcQf=T1GHwsjab@qd2CQse*t diff --git a/korangar/archive/data/texture/filled_box.png b/korangar/archive/data/texture/filled_box.png new file mode 100644 index 0000000000000000000000000000000000000000..50a7cf392f8e55a4d3075d9be253d7c1b49fc621 GIT binary patch literal 797 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE3?yBabRA=0U}OsL332^T2>ko^52yq}5>ks( zo*3;wHOR`4*${IvMUd^oFN;TIdwbbKV4#GR1o;IsNQX2p-Ff!^nI%oZQVforCw~7r z-r?Z;`O{+W=O_2SuwR*PXXjI}>Z9c3smFrktQ}VWY-9?Xw(DRhW8upk+fHwvB5Q3a zb82g_A7jz0MQeV1JsS9-UBXMfcH((QXl&+3LFwO9Y>${h56HcMsc- zKQik-F;-vjFm7qtP;~EHU7S*&tdgOa=%Xq3ou4~*rdX(EP4G(JByzs6(x9?azaxP` zf8wGDCgZEq6KZw_Jzc*d?37QS^BVI5PCq9ztUnvJyVyDU)i;J;%&VBzbO>r~v%FGn zU=&zw^hhGZ?xM()=!I;D_f6 z>Lj=N#!f5I*ElmZTm00n%M5oX&a01SS~I0|a%!?t{GW5r z3{P<7ebUGGsm*o!sbUW9oxkNm=WL75+GY{HM*8L7hdPJ0uB%z8*psTeTOwcjICu5G Z`=8>yQa%Q>R{~?0!PC{xWt~$(69BVL^m70J literal 0 HcmV?d00001 diff --git a/korangar/archive/data/texture/unchecked_box.png b/korangar/archive/data/texture/unchecked_box.png deleted file mode 100755 index ad6b9c4cbbaa3eed285be7247684735c7c9328a0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 267547 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 diff --git a/korangar/archive/data/texture/unfilled_box.png b/korangar/archive/data/texture/unfilled_box.png new file mode 100644 index 0000000000000000000000000000000000000000..508a0c9bdcbda5a9f3b701776117348ad4fa0d8d GIT binary patch literal 652 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE3?yBabR7dy=L38~T>ldS|Ni|0DuIxM)Z&yU zPdhQX(A0eT#dsd*HP@0LzhDOGkmjX3&;CENq$ya6!Ljqi?_b9|9DF~2TI~J&ESkUU9jfF2yZ+AF&%CG3vqBTFJeLWiZpI zo_=C|DjBSym9;WP@s;a`sIA|+B(F&CDtzv{b>>o5oiz3Dp@kL2ci1g-15WHWf4JDpTd*j4$qd~yCp;8y<$OOfUq77d@DcII zPgj|L_=P-9VK9?Ewf~;wzPopC{Ysg)l>d15f8jh6-iQ;I-&plDUk+XJmuV@lcC=tj SS2r*Y7(8A5T-G@yGywo4FqY&1 literal 0 HcmV?d00001 diff --git a/korangar/src/graphics/instruction.rs b/korangar/src/graphics/instruction.rs index f35fd6e0..d2a0132d 100644 --- a/korangar/src/graphics/instruction.rs +++ b/korangar/src/graphics/instruction.rs @@ -121,6 +121,14 @@ pub enum RectangleInstruction { screen_size: ScreenSize, color: Color, }, + Sdf { + screen_position: ScreenPosition, + screen_size: ScreenSize, + color: Color, + texture_position: Vector2, + texture_size: Vector2, + texture: Arc, + }, Sprite { screen_position: ScreenPosition, screen_size: ScreenSize, @@ -141,6 +149,14 @@ pub enum InterfaceRectangleInstruction { color: Color, corner_radius: CornerRadius, }, + Sdf { + screen_position: ScreenPosition, + screen_size: ScreenSize, + screen_clip: ScreenClip, + color: Color, + corner_radius: CornerRadius, + texture: Arc, + }, Sprite { screen_position: ScreenPosition, screen_size: ScreenSize, diff --git a/korangar/src/graphics/passes/interface/rectangle.rs b/korangar/src/graphics/passes/interface/rectangle.rs index e42fefa3..2368dee0 100644 --- a/korangar/src/graphics/passes/interface/rectangle.rs +++ b/korangar/src/graphics/passes/interface/rectangle.rs @@ -224,12 +224,16 @@ impl Drawer<{ BindGroupCount::One }, { ColorAttachmentCount::One }, { DepthAttac pass.set_bind_group(2, self.solid_pixel_texture.get_bind_group(), &[]); for (index, instruction) in draw_data.iter().enumerate() { - if let InterfaceRectangleInstruction::Sprite { texture, .. } = instruction - && texture.get_id() != current_texture_id - { - current_texture_id = texture.get_id(); - pass.set_bind_group(2, texture.get_bind_group(), &[]); + match instruction { + InterfaceRectangleInstruction::Sdf { texture, .. } | InterfaceRectangleInstruction::Sprite { texture, .. } + if texture.get_id() != current_texture_id => + { + current_texture_id = texture.get_id(); + pass.set_bind_group(2, texture.get_bind_group(), &[]); + } + _ => {} } + let index = index as u32; pass.draw(0..6, index..index + 1); @@ -276,6 +280,38 @@ impl Prepare for InterfaceRectangleDrawer { padding: Default::default(), }); } + InterfaceRectangleInstruction::Sdf { + screen_position, + screen_size, + screen_clip, + color, + corner_radius, + texture, + } => { + let mut texture_index = texture_views.len() as i32; + let id = texture.get_id(); + let potential_index = self.lookup.get(&id); + + if let Some(potential_index) = potential_index { + texture_index = *potential_index; + } else { + self.lookup.insert(id, texture_index); + texture_views.push(texture.get_texture_view()); + } + + self.instance_data.push(InstanceData { + color: color.components_linear(), + corner_radius: (*corner_radius).into(), + screen_clip: (*screen_clip).into(), + screen_position: (*screen_position).into(), + screen_size: (*screen_size).into(), + texture_position: [0.0, 0.0], + texture_size: [1.0, 1.0], + rectangle_type: 1, + texture_index, + padding: Default::default(), + }); + } InterfaceRectangleInstruction::Sprite { screen_position, screen_size, @@ -285,7 +321,7 @@ impl Prepare for InterfaceRectangleDrawer { texture, smooth, } => { - let rectangle_type = if *smooth { 1 } else { 2 }; + let rectangle_type = if *smooth { 2 } else { 3 }; let mut texture_index = texture_views.len() as i32; let id = texture.get_id(); @@ -327,7 +363,7 @@ impl Prepare for InterfaceRectangleDrawer { screen_size: (*screen_size).into(), texture_position: (*texture_position).into(), texture_size: (*texture_size).into(), - rectangle_type: 3, + rectangle_type: 4, texture_index: 0, padding: Default::default(), }); @@ -370,6 +406,27 @@ impl Prepare for InterfaceRectangleDrawer { padding: Default::default(), }); } + InterfaceRectangleInstruction::Sdf { + screen_position, + screen_size, + screen_clip, + color, + corner_radius, + texture: _, + } => { + self.instance_data.push(InstanceData { + color: color.components_linear(), + corner_radius: (*corner_radius).into(), + screen_clip: (*screen_clip).into(), + screen_position: (*screen_position).into(), + screen_size: (*screen_size).into(), + texture_position: [0.0, 0.0], + texture_size: [1.0, 1.0], + rectangle_type: 1, + texture_index: 0, + padding: Default::default(), + }); + } InterfaceRectangleInstruction::Sprite { screen_position, screen_size, @@ -379,7 +436,7 @@ impl Prepare for InterfaceRectangleDrawer { texture: _, smooth, } => { - let rectangle_type = if *smooth { 1 } else { 2 }; + let rectangle_type = if *smooth { 2 } else { 3 }; self.instance_data.push(InstanceData { color: color.components_linear(), @@ -410,7 +467,7 @@ impl Prepare for InterfaceRectangleDrawer { screen_size: (*screen_size).into(), texture_position: (*texture_position).into(), texture_size: (*texture_size).into(), - rectangle_type: 3, + rectangle_type: 4, texture_index: 0, padding: Default::default(), }); diff --git a/korangar/src/graphics/passes/interface/shader/rectangle.wgsl b/korangar/src/graphics/passes/interface/shader/rectangle.wgsl index 4bf7b16b..fa918a7d 100644 --- a/korangar/src/graphics/passes/interface/shader/rectangle.wgsl +++ b/korangar/src/graphics/passes/interface/shader/rectangle.wgsl @@ -88,14 +88,19 @@ fn fs_main(input: VertexOutput) -> @location(0) vec4 { switch (instance.rectangle_type) { case 1u: { + // SDF + let pixel = textureSample(texture, linear_sampler, input.texture_coordinates); + color *= vec4(pixel.rgb, saturate((pixel.a - 0.5) * 2.0 / fwidth(pixel.a))); + } + case 2u: { // Sprite (linear filtering) color *= textureSample(texture, linear_sampler, input.texture_coordinates); } - case 2u: { + case 3u: { // Sprite (nearest filtering) color *= textureSample(texture, nearest_sampler, input.texture_coordinates); } - case 3u: { + case 4u: { // Text (coverage) color *= textureSample(font_atlas, nearest_sampler, input.texture_coordinates).r; } @@ -155,13 +160,13 @@ fn rectangle_with_rounded_edges( let sample_distance = rectangle_sdf(relative_position + offset, half_size, corner_radius); total += step(0.0, -sample_distance); } - alpha = total * (1.0/9.0); + alpha = total * (1.0 / 9.0); } return color * alpha; } -// 8-point Poisson Disk pattern +// 8-point Poisson Disk pattern that showed the best performance / quality characteristic. const SAMPLE_OFFSETS: array, 8> = array, 8>( vec2( 0.924, 0.382) * 0.5, vec2( 0.382, 0.924) * 0.5, diff --git a/korangar/src/graphics/passes/interface/shader/rectangle_bindless.wgsl b/korangar/src/graphics/passes/interface/shader/rectangle_bindless.wgsl index 1e61f4d2..ee0b3afe 100644 --- a/korangar/src/graphics/passes/interface/shader/rectangle_bindless.wgsl +++ b/korangar/src/graphics/passes/interface/shader/rectangle_bindless.wgsl @@ -88,14 +88,19 @@ fn fs_main(input: VertexOutput) -> @location(0) vec4 { switch (instance.rectangle_type) { case 1u: { + // SDF + let pixel = textureSample(textures[instance.texture_index], linear_sampler, input.texture_coordinates); + color *= vec4(pixel.rgb, saturate((pixel.a - 0.5) * 2.0 / fwidth(pixel.a))); + } + case 2u: { // Sprite (linear filtering) color *= textureSample(textures[instance.texture_index], linear_sampler, input.texture_coordinates); } - case 2u: { + case 3u: { // Sprite (nearest filtering) color *= textureSample(textures[instance.texture_index], nearest_sampler, input.texture_coordinates); } - case 3u: { + case 4u: { // Text (coverage) color *= textureSample(font_atlas, nearest_sampler, input.texture_coordinates).r; } diff --git a/korangar/src/graphics/passes/postprocessing/rectangle.rs b/korangar/src/graphics/passes/postprocessing/rectangle.rs index 6757aed8..737524d4 100644 --- a/korangar/src/graphics/passes/postprocessing/rectangle.rs +++ b/korangar/src/graphics/passes/postprocessing/rectangle.rs @@ -43,8 +43,8 @@ pub(crate) struct InstanceData { screen_size: [f32; 2], texture_position: [f32; 2], texture_size: [f32; 2], + rectangle_type: u32, texture_index: i32, - linear_filtering: u32, padding: [u32; 2], } @@ -215,12 +215,16 @@ impl Drawer<{ BindGroupCount::One }, { ColorAttachmentCount::One }, { DepthAttac pass.set_bind_group(2, self.solid_pixel_texture.get_bind_group(), &[]); for (index, instruction) in draw_data.instructions.iter().enumerate() { - if let RectangleInstruction::Sprite { texture, .. } = instruction - && texture.get_id() != current_texture_id - { - current_texture_id = texture.get_id(); - pass.set_bind_group(2, texture.get_bind_group(), &[]); + match instruction { + RectangleInstruction::Sdf { texture, .. } | RectangleInstruction::Sprite { texture, .. } + if texture.get_id() != current_texture_id => + { + current_texture_id = texture.get_id(); + pass.set_bind_group(2, texture.get_bind_group(), &[]); + } + _ => {} } + let index = offset + index as u32; pass.draw(0..6, index..index + 1); @@ -274,8 +278,38 @@ impl Prepare for PostProcessingRectangleDrawer { screen_size: (*screen_size).into(), texture_position: [0.0; 2], texture_size: [0.0; 2], + rectangle_type: 0, texture_index: -1, - linear_filtering: 0, + padding: Default::default(), + }); + } + RectangleInstruction::Sdf { + screen_position, + screen_size, + color, + texture_position, + texture_size, + texture, + } => { + let mut texture_index = texture_views.len() as i32; + let id = texture.get_id(); + let potential_index = self.lookup.get(&id); + + if let Some(potential_index) = potential_index { + texture_index = *potential_index; + } else { + self.lookup.insert(id, texture_index); + texture_views.push(texture.get_texture_view()); + } + + self.instance_data.push(InstanceData { + color: color.components_linear(), + screen_position: (*screen_position).into(), + screen_size: (*screen_size).into(), + texture_position: (*texture_position).into(), + texture_size: (*texture_size).into(), + rectangle_type: 1, + texture_index, padding: Default::default(), }); } @@ -288,6 +322,8 @@ impl Prepare for PostProcessingRectangleDrawer { linear_filtering, texture, } => { + let rectangle_type = if *linear_filtering { 2 } else { 3 }; + let mut texture_index = texture_views.len() as i32; let id = texture.get_id(); let potential_index = self.lookup.get(&id); @@ -305,8 +341,8 @@ impl Prepare for PostProcessingRectangleDrawer { screen_size: (*screen_size).into(), texture_position: (*texture_position).into(), texture_size: (*texture_size).into(), + rectangle_type, texture_index, - linear_filtering: *linear_filtering as u32, padding: Default::default(), }); } @@ -348,8 +384,27 @@ impl Prepare for PostProcessingRectangleDrawer { screen_size: (*screen_size).into(), texture_position: [0.0; 2], texture_size: [0.0; 2], + rectangle_type: 0, texture_index: -1, - linear_filtering: 0, + padding: Default::default(), + }); + } + RectangleInstruction::Sdf { + screen_position, + screen_size, + color, + texture_position, + texture_size, + texture: _, + } => { + self.instance_data.push(InstanceData { + color: color.components_linear(), + screen_position: (*screen_position).into(), + screen_size: (*screen_size).into(), + texture_position: (*texture_position).into(), + texture_size: (*texture_size).into(), + rectangle_type: 1, + texture_index: 0, padding: Default::default(), }); } @@ -362,14 +417,16 @@ impl Prepare for PostProcessingRectangleDrawer { linear_filtering, texture: _, } => { + let rectangle_type = if *linear_filtering { 2 } else { 3 }; + self.instance_data.push(InstanceData { color: color.components_linear(), screen_position: (*screen_position).into(), screen_size: (*screen_size).into(), texture_position: (*texture_position).into(), texture_size: (*texture_size).into(), + rectangle_type, texture_index: 0, - linear_filtering: *linear_filtering as u32, padding: Default::default(), }); } diff --git a/korangar/src/graphics/passes/postprocessing/shader/rectangle.wgsl b/korangar/src/graphics/passes/postprocessing/shader/rectangle.wgsl index 96f333c2..9f27b5fe 100644 --- a/korangar/src/graphics/passes/postprocessing/shader/rectangle.wgsl +++ b/korangar/src/graphics/passes/postprocessing/shader/rectangle.wgsl @@ -4,8 +4,8 @@ struct InstanceData { screen_size: vec2, texture_position: vec2, texture_size: vec2, + rectangle_type: u32, texture_index: i32, - linear_filtering: u32, } struct VertexOutput { @@ -42,14 +42,24 @@ fn vs_main( fn fs_main(input: VertexOutput) -> @location(0) vec4 { let instance = instance_data[input.instance_index]; - if instance.texture_index == -1 { - return instance.color; - } - - if instance.linear_filtering == 0 { - return textureSample(texture, nearest_sampler, input.texture_coordinates) * instance.color; - } else { - return textureSample(texture, linear_sampler, input.texture_coordinates) * instance.color; + switch (instance.rectangle_type) { + case 1u: { + // SDF + let pixel = textureSample(texture, linear_sampler, input.texture_coordinates); + return vec4(pixel.rgb, saturate((pixel.a - 0.5) * 2.0 / fwidth(pixel.a))) * instance.color; + } + case 2u: { + // Sprite (linear filtering) + return textureSample(texture, linear_sampler, input.texture_coordinates) * instance.color; + } + case 3u: { + // Sprite (nearest filtering) + return textureSample(texture, nearest_sampler, input.texture_coordinates) * instance.color; + } + default: { + // Solid + return instance.color; + } } } diff --git a/korangar/src/graphics/passes/postprocessing/shader/rectangle_bindless.wgsl b/korangar/src/graphics/passes/postprocessing/shader/rectangle_bindless.wgsl index d61ab5c6..2d105eb4 100644 --- a/korangar/src/graphics/passes/postprocessing/shader/rectangle_bindless.wgsl +++ b/korangar/src/graphics/passes/postprocessing/shader/rectangle_bindless.wgsl @@ -4,8 +4,8 @@ struct InstanceData { screen_size: vec2, texture_position: vec2, texture_size: vec2, + rectangle_type: u32, texture_index: i32, - linear_filtering: u32, } struct VertexOutput { @@ -42,14 +42,24 @@ fn vs_main( fn fs_main(input: VertexOutput) -> @location(0) vec4 { let instance = instance_data[input.instance_index]; - if instance.texture_index == -1 { - return instance.color; - } - - if instance.linear_filtering == 0 { - return textureSample(textures[instance.texture_index], nearest_sampler, input.texture_coordinates) * instance.color; - } else { - return textureSample(textures[instance.texture_index], linear_sampler, input.texture_coordinates) * instance.color; + switch (instance.rectangle_type) { + case 1u: { + // SDF + let pixel = textureSample(textures[instance.texture_index], linear_sampler, input.texture_coordinates); + return vec4(pixel.rgb, saturate((pixel.a - 0.5) * 2.0 / fwidth(pixel.a))) * instance.color; + } + case 2u: { + // Sprite (linear filtering) + return textureSample(textures[instance.texture_index], linear_sampler, input.texture_coordinates) * instance.color; + } + case 3u: { + // Sprite (nearest filtering) + return textureSample(textures[instance.texture_index], nearest_sampler, input.texture_coordinates) * instance.color; + } + default: { + // Solid + return instance.color; + } } } diff --git a/korangar/src/renderer/game_interface.rs b/korangar/src/renderer/game_interface.rs index e5047dca..3dffa6af 100644 --- a/korangar/src/renderer/game_interface.rs +++ b/korangar/src/renderer/game_interface.rs @@ -49,6 +49,37 @@ impl SpriteRenderer for GameInterfaceRenderer { ) { self.render_indexed(texture, position, size, color, 1, 0, smooth); } + + fn render_sdf( + &self, + texture: Arc, + screen_position: ScreenPosition, + screen_size: ScreenSize, + _screen_clip: ScreenClip, + color: Color, + ) { + let screen_position = ScreenPosition { + left: screen_position.left / self.window_size.width, + top: screen_position.top / self.window_size.height, + }; + + let screen_size = ScreenSize { + width: screen_size.width / self.window_size.width, + height: screen_size.height / self.window_size.height, + }; + + let texture_position = Vector2::new(0.0, 0.0); + let texture_size = Vector2::new(1.0, 1.0); + + self.instructions.borrow_mut().push(RectangleInstruction::Sdf { + screen_position, + screen_size, + color, + texture_position, + texture_size, + texture, + }); + } } impl GameInterfaceRenderer { diff --git a/korangar/src/renderer/interface.rs b/korangar/src/renderer/interface.rs index 9ae8ac35..ddf910e7 100644 --- a/korangar/src/renderer/interface.rs +++ b/korangar/src/renderer/interface.rs @@ -15,8 +15,8 @@ use crate::renderer::SpriteRenderer; pub struct InterfaceRenderer { instructions: RefCell>, font_loader: Rc>, - checked_box_texture: Arc, - unchecked_box_texture: Arc, + filled_box_texture: Arc, + unfilled_box_texture: Arc, expanded_arrow_texture: Arc, collapsed_arrow_texture: Arc, window_size: ScreenSize, @@ -33,8 +33,8 @@ impl InterfaceRenderer { ) -> Self { let instructions = RefCell::new(Vec::default()); - let checked_box_texture = texture_loader.get("checked_box.png").unwrap(); - let unchecked_box_texture = texture_loader.get("unchecked_box.png").unwrap(); + let filled_box_texture = texture_loader.get("filled_box.png").unwrap(); + let unfilled_box_texture = texture_loader.get("unfilled_box.png").unwrap(); let expanded_arrow_texture = texture_loader.get("expanded_arrow.png").unwrap(); let collapsed_arrow_texture = texture_loader.get("collapsed_arrow.png").unwrap(); @@ -43,8 +43,8 @@ impl InterfaceRenderer { Self { instructions, font_loader, - checked_box_texture, - unchecked_box_texture, + filled_box_texture, + unfilled_box_texture, expanded_arrow_texture, collapsed_arrow_texture, window_size, @@ -182,7 +182,7 @@ impl korangar_interface::application::InterfaceRenderer for I ); if self.high_quality_interface { - size.y = size.y / 2; + size.y /= 2; } size.y as f32 @@ -197,11 +197,11 @@ impl korangar_interface::application::InterfaceRenderer for I checked: bool, ) { let texture = match checked { - true => self.checked_box_texture.clone(), - false => self.unchecked_box_texture.clone(), + true => self.filled_box_texture.clone(), + false => self.unfilled_box_texture.clone(), }; - self.render_sprite(texture, position, size, clip, color, true); + self.render_sdf(texture, position, size, clip, color); } fn render_expand_arrow( @@ -217,7 +217,7 @@ impl korangar_interface::application::InterfaceRenderer for I false => self.collapsed_arrow_texture.clone(), }; - self.render_sprite(texture, position, size, clip, color, true); + self.render_sdf(texture, position, size, clip, color); } } @@ -250,4 +250,24 @@ impl SpriteRenderer for InterfaceRenderer { smooth, }); } + + fn render_sdf(&self, texture: Arc, position: ScreenPosition, size: ScreenSize, mut screen_clip: ScreenClip, color: Color) { + if self.high_quality_interface { + screen_clip = screen_clip * 2.0; + } + + // Normalize screen_position and screen_size in range 0.0 and 1.0. + let screen_position = position / self.window_size; + let screen_size = size / self.window_size; + let corner_radius = CornerRadius::default(); + + self.instructions.borrow_mut().push(InterfaceRectangleInstruction::Sdf { + screen_position, + screen_size, + screen_clip, + color, + corner_radius, + texture, + }); + } } diff --git a/korangar/src/renderer/mod.rs b/korangar/src/renderer/mod.rs index d17a3dc9..dc0d4e6c 100644 --- a/korangar/src/renderer/mod.rs +++ b/korangar/src/renderer/mod.rs @@ -34,6 +34,8 @@ pub trait SpriteRenderer { color: Color, smooth: bool, ); + + fn render_sdf(&self, texture: Arc, position: ScreenPosition, size: ScreenSize, screen_clip: ScreenClip, color: Color); } /// Trait to render markers.