From f2169d333c9fa423e4776b4c0f4f84feef711d9c Mon Sep 17 00:00:00 2001 From: PeaAshMeter Date: Sat, 6 Dec 2025 21:41:43 +0300 Subject: [PATCH] Add alpha mask shader and stencil-based skill icon masking --- assets/masks/rrect32.png | Bin 0 -> 1586 bytes assets/masks/squircle.png | Bin 0 -> 2802 bytes assets/shaders/alpha_mask.glsl | 8 ++++++++ assets/shaders/soft_uniform_noise.glsl | 4 ++-- lib/simple_ui/level/skill_row.lua | 26 +++++++++++++++++++++---- 5 files changed, 32 insertions(+), 6 deletions(-) create mode 100644 assets/masks/rrect32.png create mode 100644 assets/masks/squircle.png create mode 100644 assets/shaders/alpha_mask.glsl diff --git a/assets/masks/rrect32.png b/assets/masks/rrect32.png new file mode 100644 index 0000000000000000000000000000000000000000..dff51021fcd016765cdeb73ff3d9c07e55611006 GIT binary patch literal 1586 zcmeAS@N?(olHy`uVBq!ia0y~yU<5K5893O0R7}x|G$6%U;1OBOz`!j8!i<;h*8O2% zV1450;uumf=k49Mfzj>~Z4brG8}2a5I%sjMJFtXlH_P+~LUZ^6SPzP_XmPwcAS!yqA<#ejIZZA78&i?u5p0YPv_WP}RwPICY`Csuvau1gWTW^kX^#rSUwZ`S#+~6^M!BUpNE!aJa~BZ z?zgw!j~3rQv77f^>%px}^51T) ziErC~DOtOrc(VMrdmoe2+2x`b=X|})b-?1!##dI2p^P)W?4J1MccM+0oJh=8)*oq~ z4!@B3wzKy9C$0st4j;B}Y`^$xLk082Ph1aH7q$oPHa{*N&hR$mp#3p9xA)s0Rx)*K zH|QUeRr+IoySn-J(fXkPpE*z*2(36*%%eh2U>HyU{Gke^AdDPFwa~AZe*lwwXsPiUhP+i-S#J~%Z8`t5 zI-F^qbalsv+#l|GYzyY{?J@dikQLs2{h!W#?hjXQ9A0sE_T$rxJ4$pI+_HDoJiK2Z zmT+;&effeH#SDuJqeI;fAKZU%)$PXH@;`F!B!<}O`~RzYQpq5`jmbdja=YHQ=&h^~ zSNg={e#;!Vmv#QPMdgdL_Fr8V1oQJW?lpZ~{KL_IEyF2C#~a?-{J(UgpU-SC|H~f9 zd7y5_TH~LuCHYzRZj^1y9tmFaBWBd&4zs4@!N1$J}|b&`$s7QH8^z&GL6#IriTPonNiJ z{zLTjWzh|xx9&am4z2wZ*)VtJx8Favf3o*N?Z=Td@4PH~ojW{?Bdk zsp5dO& literal 0 HcmV?d00001 diff --git a/assets/masks/squircle.png b/assets/masks/squircle.png new file mode 100644 index 0000000000000000000000000000000000000000..8bd5a6dd7ee91001e1b45152877b8a3d7d35a057 GIT binary patch literal 2802 zcmb_edpy)x8-IQ?!wfNIHxpZFMp_}4QHvV4k?baF70NYJT5`8BmXIF`CB;r^Hi=R~ zndH81jig%Bx=rgc)5WH;H7+r3tzq8L?jP^x{rmmne4gh#=lP!V+|F~(X_r0UsVc8l z1^`vZojdjcAaWJ~f}))G94iTs6Q#(Vo>2fRzFZzi?~4;s0OcEwJM7$IuZ+FOau*$4 zrO3=tWE${X?V8AE>r$?zW)puVZr0jB-XK6qnL8C$kX5+MVdVjxcPlrYHR4w;O-Qb^ zX=`s|`oB0Zw~&)CJ3r4c&B!$5U%W|aTAX{nK5_JC*(*s-Q*@poe|%Odvj1C;FPrE( zb6>C$>E<45<@SzD^-pzOa!vYK%li_hXzjW>%a%u{al9YTR7LN7#_#Qabj2E z#&@+A=50-ZfpWc%?(e(qXH6zo_MhLU_x!`!n3W*2Wt+IRTIO{f=rMa<-1SqBz4l>H zKXp*O(KIepEZ5ra9MHM%B9={;*`zLgkVwF;ADW12UyjXMnR-jlN_o~>+nG*~?H?PYQapx6UZc*!h z5k?%|g+%5k%h*-cIyHM9kNoatuCrSkrXI+$ZJrKoQTVj$!N|1f2dZWi=p__~PutP@ zpuX?J7M=F)A<@9q-T@3Vx3^bl9Ti%)i^jWLnIYTu_!Rrg1le8jCB&iiUl+tsmVQ~|p?Ys0Z3n)> z*?S||RyrJ3c6uy+dkl91o;d%fKQ1{S2!uC$ieJ1mj^^O!T0VXK?lv^x zqAb7di{OQ-^WlZ(iHym%$(J+tqAJATBJK7W(eC~M5?rK_l|T7*Dn*;&Bf}o3dCjzB zh8JdnNAX*gLSI?%!oibac%Fl>o0(4$);Z3#hK4<6ilU(I422%`a<<(*Op&)y6n`x$ zLezwolxy=0d_`kv0*r#!(~pSqseq&zV7qyFRLB(Ck(wz?7q)8Ps7}b0k0&@ zK1cgxSL{&dLyF3Wr3(v$E1Plk`=zw{x?4VG1J&4yKk<)>CQmX2L|)?zFV@GrnOWk9 z9~xB~797osWD|LVlt&{?jvA4npM|XGWiImO{GsYj*Q~ynQ2a+`Kjo~D&O&O|3J@Rt z6PnF@{|3|_Q`m1|2&-@V-e#pkoYQ1oKUR0R|C=Ls-RiKBv*|&l?o}*HU?#+z{8hC~=0P(@BO%u)glvBTdB?-9|;K#aHXKcfU~1KWJnpM* z2L`E4;$Zg{D)8_+R=C1N1#yP$hTof+0JT^H0h}8S<)hjcZ(Z(37|eG-)n%h3jw2&u z4<1ad|46vEvfG%EG4gcTm|+73LHs&v0T>=m_CRok&j8~nAaS-q#_|-itVIVxh&E8U zr?dg53sf2c$x8odf6_{B(${-f{Tr4y#-r-}yN4XKQoaSCJly{R{;x}hYG@V~whP}N zks~$f+2bn6f7>QMijN&?ML^q{02$&|xx@cj6{?U{f3+4Piw4F{Th)I+`PMcz2akBp z`r(n25~p?WiG5;PXumZu4M-keK!{vAmm@WT?n!L42OLO}+er+1O+@O9qmOFC{>bH>o$#P^MHRI1;`&dBg>Ll`Z z!Lk$suj9BgQ=1FDQ|(mlt4rW5JQ-C$Nu6gl{@P5QPw%G$j5%aQ;L$kX)M=O*1NCAD zM0(PmiZWNr(`{%HoDff@I`Oe1L}gC?Zm;pAT5%e+7T0FgTsG#5FxSCy@rr?Z&Pxjg zG_H&cYA-jD0s@;uawA^(CbJNliDk%fKj08f#tnK3F!JK_6v*qF97;%ui>*OQTxL2M z4ZulnuJIv*#lZy5spgtHSoBlKGvrN3+8mL{sa`0%ouJliSz!#t<&|k_3OoxF8)vT{ zR1X+oS53|S*=q`Hc7)8=&H68UEk=MD=!%(ReM-;<@{3*L9Z1OjN|EYqs_aog^GDjQg7f-IckJ-l?=j2^ z=WG@NRq3d+1{6h4588$dAV*49)K{&CqUEcaD(GCw`eqE2DNW7B!rE%x*oEr>KR7d**mc>Xuy`{iR$v0Jl2aI`TZS6)V^ zq{-!Lq5HIZUV8zH1fHuEnlrap*A1OX{hHWGf*@Z%AHu9alyTt-pxExO6>kiRq8A##b06?eklZ zCeutO782CXwP2}EjhyhXRVfc5cgFew=f(xrQbiN#15G+wd3{Z6f!793DvMtH-H&}HYrN&SoZhL_ukCe%*>vHz z6GB0{DV||RqL~%RA?ldIY<#QxaSioNif4Q1S_KyVa_I$3;i!SpHL1vUK;~R)e!G=Lkqe*e@x}+@;WZl8Bx^7$JB( z+BxOEUXfSppq%o9zIwEhq*|XGzw{}5JaFC~#|zKw?Y=fIiSSP-9G%f2&)Jves`-vK z63}6v8^l9!N6Emb=54X(r|&&Qhv^3&i0U&{1Xd~4tsWR Iw=+}z1Ah44+yDRo literal 0 HcmV?d00001 diff --git a/assets/shaders/alpha_mask.glsl b/assets/shaders/alpha_mask.glsl new file mode 100644 index 0000000..5339bf7 --- /dev/null +++ b/assets/shaders/alpha_mask.glsl @@ -0,0 +1,8 @@ +vec4 effect(vec4 color, Image tex, vec2 texCoord, vec2 screenCoord) +{ + vec4 px = Texel(tex, texCoord); + if (px.a == 0.0) { + discard; + } + return vec4(1.0); +} diff --git a/assets/shaders/soft_uniform_noise.glsl b/assets/shaders/soft_uniform_noise.glsl index 6cdba61..e843952 100644 --- a/assets/shaders/soft_uniform_noise.glsl +++ b/assets/shaders/soft_uniform_noise.glsl @@ -8,10 +8,10 @@ vec2 hash(vec2 p) { vec4 effect(vec4 color, Image tex, vec2 uv, vec2 px) { - vec2 cell = floor(px / 2.0); + vec2 cell = floor(px / 2.0); // тут можно размер зерна менять float n = hash(cell).x; // 0..1 - float v = 0.9 + n * 0.2; // 0.9..1.0 + float v = 0.9 + n * 0.1; // 0.9..1.0 return vec4(v, v, v, 1.0); } diff --git a/lib/simple_ui/level/skill_row.lua b/lib/simple_ui/level/skill_row.lua index aa0e92a..049e1a5 100644 --- a/lib/simple_ui/level/skill_row.lua +++ b/lib/simple_ui/level/skill_row.lua @@ -160,8 +160,29 @@ end local c = love.graphics.newCanvas(1280, 720) --- @TODO: выставлять канвасу правильный размер в зависимости от окна function skillRow:draw() - love.graphics.setCanvas(c) + love.graphics.setCanvas({ c, stencil = true }) love.graphics.clear() + love.graphics.setColor(1, 1, 1) + + -- сначала иконки скиллов + for _, skb in ipairs(self.children) do + skb:draw() + end + + -- маска для вырезов под иконки + love.graphics.setShader(Tree.assets.files.shaders.alpha_mask) + love.graphics.stencil(function() + local mask = Tree.assets.files.masks.rrect32 + local maskSize = mask:getWidth() + for _, skb in ipairs(self.children) do + love.graphics.draw(mask, skb.bounds.x, skb.bounds.y, 0, + skb.bounds.width / maskSize, skb.bounds.height / maskSize) + end + end, "replace", 1) + love.graphics.setShader() + + -- дальше рисуем панель, перекрывая иконки + love.graphics.setStencilTest("less", 1) -- шум love.graphics.setShader(Tree.assets.files.shaders.soft_uniform_noise) love.graphics.rectangle("fill", self.bounds.x, self.bounds.y, self.bounds.width, self.bounds.height) @@ -177,9 +198,6 @@ function skillRow:draw() self:drawBorder("outer") love.graphics.setColor(1, 1, 1) - for _, skb in ipairs(self.children) do - skb:draw() - end love.graphics.setCanvas()