From 0a1e240831aacb2027edcdcc39cd857ce3ecce4c Mon Sep 17 00:00:00 2001 From: Kelsi Date: Mon, 23 Feb 2026 08:40:16 -0800 Subject: [PATCH] Fix WMO shadow receiving and enable shadows by default Remove isInterior restriction from WMO shadow sampling so city buildings (flagged as interior groups) correctly receive shadows. Apply shadow to interior-lit surfaces. Enable shadows by default and persist the setting across sessions. --- assets/shaders/wmo.frag.glsl | 38 ++++++++++++++++++----------------- assets/shaders/wmo.frag.spv | Bin 18492 -> 20156 bytes include/ui/game_screen.hpp | 2 +- src/rendering/renderer.cpp | 3 ++- src/ui/game_screen.cpp | 6 ++++-- 5 files changed, 27 insertions(+), 22 deletions(-) diff --git a/assets/shaders/wmo.frag.glsl b/assets/shaders/wmo.frag.glsl index 705ecd47..dbd55436 100644 --- a/assets/shaders/wmo.frag.glsl +++ b/assets/shaders/wmo.frag.glsl @@ -152,11 +152,29 @@ void main() { vec3 result; + // Sample shadow map for all non-window WMO surfaces + float shadow = 1.0; + if (shadowParams.x > 0.5) { + vec3 ldir = normalize(-lightDir.xyz); + float normalOffset = SHADOW_TEXEL * 2.0 * (1.0 - abs(dot(norm, ldir))); + vec3 biasedPos = FragPos + norm * normalOffset; + vec4 lsPos = lightSpaceMatrix * vec4(biasedPos, 1.0); + vec3 proj = lsPos.xyz / lsPos.w; + proj.xy = proj.xy * 0.5 + 0.5; + if (proj.x >= 0.0 && proj.x <= 1.0 && + proj.y >= 0.0 && proj.y <= 1.0 && + proj.z >= 0.0 && proj.z <= 1.0) { + float bias = max(0.0005 * (1.0 - dot(norm, ldir)), 0.00005); + shadow = sampleShadowPCF(uShadowMap, vec3(proj.xy, proj.z - bias)); + } + shadow = mix(1.0, shadow, shadowParams.y); + } + if (unlit != 0) { - result = texColor.rgb; + result = texColor.rgb * shadow; } else if (isInterior != 0) { vec3 mocv = max(VertColor.rgb, vec3(0.5)); - result = texColor.rgb * mocv; + result = texColor.rgb * mocv * shadow; } else { vec3 ldir = normalize(-lightDir.xyz); float diff = max(dot(norm, ldir), 0.0); @@ -165,22 +183,6 @@ void main() { vec3 halfDir = normalize(ldir + viewDir); float spec = pow(max(dot(norm, halfDir), 0.0), 32.0) * specularIntensity; - float shadow = 1.0; - if (shadowParams.x > 0.5) { - float normalOffset = SHADOW_TEXEL * 2.0 * (1.0 - abs(dot(norm, ldir))); - vec3 biasedPos = FragPos + norm * normalOffset; - vec4 lsPos = lightSpaceMatrix * vec4(biasedPos, 1.0); - vec3 proj = lsPos.xyz / lsPos.w; - proj.xy = proj.xy * 0.5 + 0.5; - if (proj.x >= 0.0 && proj.x <= 1.0 && - proj.y >= 0.0 && proj.y <= 1.0 && - proj.z >= 0.0 && proj.z <= 1.0) { - float bias = max(0.0005 * (1.0 - dot(norm, ldir)), 0.00005); - shadow = sampleShadowPCF(uShadowMap, vec3(proj.xy, proj.z - bias)); - } - shadow = mix(1.0, shadow, shadowParams.y); - } - result = ambientColor.rgb * texColor.rgb + shadow * (diff * lightColor.rgb * texColor.rgb + spec * lightColor.rgb); diff --git a/assets/shaders/wmo.frag.spv b/assets/shaders/wmo.frag.spv index f1241ab896f55b43eeff964f992468880552a011..a7b9ef940c38550f2f1e033f8f4ee5c56700db4e 100644 GIT binary patch literal 20156 zcmZ{r378#K(S{plCSjMIgmnVQE(&pB5fTCtkdOoub|KzO?j(bE7H0`TK?8`mf*UG` zBB+R>qM(9+$N+*1AS#NxhzlyK3JNOvzi;3ECha`_{oH!aS6|hsQ>V`9)7@d{SbL|b zMX^?~ez9S(dq+`Tn-puq6mV0@cJ91I^Y$JYUAFg&U-BXyHY(bV`aF+*owQ1Sqi=ww zI2PFg<8)*vWLM-=h^;L6^a2V%3&hWhk3hGQjqNOTB++Y_vIVaM|IF zp3%YK-Ado}i*0C!8pDlNtFdZ94;hX04GtXL7}{-R@4n?2z56%}aXN}=v|}s9UBz_p z%D(35hxH9FUR2t~Z z0K#+>CuqmHi?ux&Jlb5=|n{hP7rA8KbN0cYNOf>kXve)Uw|caC4xs zwAGwHINaZ8u}l+rxhLDUg$s@@`?Pad2Rt;`zo@6tVis#+t=s00rWEDwVyjH#w;p&! zvv2u|QARkfL0txV?41192M;8JMWe&bf#sts;9RFS(0aKZt7-fD1}18K9{Rvo|HOdS z|01|nlqs+?&!Rlsf>RKwuOj&ucT!y7xeayG_AX1UQ4^I*&1ye zdtB*r19}w;MxS+x8`p5-1TT2cf9vm3uR_Gg8-uCNuoW6lZtE^Q=u_OB8 zDu(CZVs0MRfS4V{F6eVgTUU85&gmPitj6jn_Q2l0?>dUT?K@|FnaeS4yrgenCHjbq za2)qqisqb-$7jtPI*U`#m-Y4bCXc1))moKf_Mxw6w0hls_8&m^IS~Jg%KqhJr5y88 zboNd4^lImQ4P5#BDf8+qu1BwraSQr-?c*zWo~ z16QB-bLea4-BoPBjj29oc(CDtU>x7K2FE7KUCbqp?*-c~&jGp3Yn=DL+_W0!{V%s|jdMJ??i%NPFSm1z^O-BR zTaEKME9ZOCT+UeM>pZN5&)FRj=Nf%RP4^jAx2tPUf8TShW%~P!aJ)?r<9YsTw;t-g z3#(g;BhWo>z1sSkv)X*UtZ{s-OS_)!es-<*Q@7u2B>m(j_cQl;KXv=9M$%7iO}};y z9dP>Hio`GLd|!<-wtf%RxUBP&HO~0@S-ix{I&WO#vd-Obu3w%}*3&b7M`LhBpV3xJ z-E-f1dujK4)}LlVulsw()#IsakH6nA#1R_uHbF(w+8xk6W_Ue$!&%1{1RCcd*Y`(^WFk|2lQ@at+M6WL2F!j{cU$d{=*f0cXa(XC!0NJ z6ZhrdqFBAZac6*%aP;!wRji)1Jzu__9nPgL*5ZHZ@``!Ap4Oc0Z(i!2J(-97&qQ1| z{m-gw^5$WC4&wb5{c^DTLjNmhjpcaB`_tf}m_6HlcN0k4T2i$uy8G^Cc>Rp`waQ1% zeAREMIQP*w*m%ij7Wj6=eVP330((Wj7d*St?K_phXU@FtV8`1W%&*+Xj;HR~DyMx~ zh21CG)jezZmAd|(wRPRIR(%@&djY&ha^JiF-Tf(_{AN{L^jB1U)Xnz@^ubNfJs|o# z^iK?(HOu(Ng2(Z(9@}#ldPd1bwEchL{Eo-h^|PPzQ}=9>OFk!}n}_}aP7&ZN0RsUyUx6 z{`aC}Z#ah^w*AXm?tuOqbmwaBzpb#f%Xl*|4sO~pQTtudx4QnA{hYh^jOVnM{a*>D z>%`pEJ-6ldqJr*&`RL9ul5s}hx#lGARp>s?V!s2Ov*MuW-$38tyw{d>a$eso`>&oI z`!CTix%lFVv*cIky}i8?{(oxQC-g^4efos{7&>>&tmOSTx<2x*TgG_`{hqt$P4rva zVi&6qjeV0+pM6O5Y3LW;_VmO&wnM+??z<=Q+#Y@A%#m5va|W2-L_O7g?#aEB>M%53 z?Mv<%7;EO*Y)R`kw|i0DJ>>Uxbe}8THC?;k&#|lTGD-IvId<=3zmw~_-^$VLzj%`F zw_ogz-&@o5_q#84^Y^qR%d-+6W2Z@lRCzo(|_ ze}7Ha?zdh1&Cl<;=-MBv>Gtnt!RmIu;p)2IaCQC2NxI)_u^Z3twdjuL_gY==tLggt zy%xK=-)nW<@3p$_w_0@L`>ht;{(h^~b-&f3>+iQ(UH4lpy8Zo5tLuKFMYq4-W_8_f zv%2ngS#;z1T~^oqE>qv1{qGsEDeJK*?ZMnZ-W%!%Ve?$t61)YnL3K`T1?E@0qO#e? z`$yhBJ`cAB`z*Yw(zgN2{T<)!XubY{O@3QM&U;jxakmE>_f1tEJAmafp8B)&Nncz0 z`rbGL>^qje-plHVyEAwvB=dPbm|r;`ZT9hgmrtMFz&^XvXLm5avX3_VcqYiF&z@lO z*XH@49@`7SjuHJuVEaek2W+2XIJI1#eZlte3OBRjq{F?q;#lqp?j>->_ln<3D^5Dx z%POwkcRx6D@rvL66(=3;fQqy4!fKx!2xs2rX95dxF_d;Ccykzlza5cg!_*gnmj=J>A!JC6HQf5%9?qrl#GH&pSC2Fv+A z_o<4T4>pE2^Iu5oW&YY0Aadp}Hn#P96=J;>SNfugvyR7r)t&1}v?n9J6Q^0bHmyPSLzxE{%ry}PPQ~fny`^e}1X@L2a_m6gS@tG)}ynDdrm$=Ko z`n;!#+XU+)Z~vvVa{7A)EC=Td=mo1MRv%b@`}u5D*XG*37VKJRJB?O-f7Z~LE$}w9 z#MFjAz`~UO&mEk7JD!>kVN0>pMWJo;jYWj*s8a znd4b-@|ois!E%}7YOt4c)b=Js&YZ-?_W5--*zs-$8{2g{2VFk*%$vb-=OWH6acpxB zo(Fau=cK=5crTq#>t!DLyakan5AnZ>wMs1K`0nesgEvF0#oK7rQ;T%=sLq0qLFjWClIO|g;Fb79avog)ufKNJ?h;zL)am2k$#wb! zoP5^)lVJNTsLq8e!E%b1jk!6$PoZcxM)vck!S=rj$usmbV12#JOCP!P`7GEzS0m~3 zIk0{Bm3{P)OP-$x+b8GlHDG?_xvMSnm$%Pev|mK_u5|bLwP0i9+`SI0k9^{O3CypI ztKGO?pp`f79@xGNo{r?5@GD?B_s$KpUhWk&EkjyUuAD%iMrC%h3Xm+{oS_tV$b zzTR6mgEv94&R+vhUgulj*Qh{heTbW$pDf7tbSkYms}Epo`~fWI74DA}Cmrrj73VrE zWbcpDJ_2Wd{k2;Y&xLW?N6{TyA9H<(R?a-eu|E!$%bGs{mQ%cJ9Lu?FN&6&({`F`6 zpV8%W&-?`}7kO({x4*&}U%R}9d!@^{ zR&vjP_0^U+JPURl@2k}HA7FjG%uOG;^!X>)K35~@^DnS{_?3P1kxQTFz!}Fmy1)Jn zCw~k1dH((fEa!hC@%~-QVsm-_YP0xq-oO45du{OK*d4kcH&?Mc!E){g&z!`u&3i)^ z*l|1?^mh#Nm@4Kn4}GQ}a^@jU9_xTpm&|cpIQh(RJ+Pc}G>^owO&;rm9mm}CcMS8` zkk-pQ^w|KBGY@g{*a$p1kLSV3ryd)FsE5zIt}`cLC2pwB?z<8<b6(qI~y+R z_X0Ti=zD`5Bl*4%tdD%oh8KYy$1B`E73X+4EBA%dSDSIne*{tz{zJWhlAxZmm|Pl z&PCf?=|p_$VZEIT|ddcx5i`bMKi2@N&B$`p!q3!;!Sw5_ciEUZZ2sv$}>e)6fKoON{m&eb_v$CDWF1hD%qbsQ(=iE>Eh ze-cCRk4KGOjTB^`e{#=^0|}m!sQ9KJ#1wwx9FVZZ1n{ zKwyojx8$qn+73gDN@3nIf$9LbYgp<$te>&J0^5#20E0;An1MHftqBX`iF`@wSd$=GuBbMA;rKZw?I&o;ID0C@5l@j*EGvqcx@TulVJPG`<>{$eyh- zc{pSF??R4Y9DTEgw43La*uMbwo~?gNe-Tbz|7&Q~_4obiTCnG2&N$ymu7i`$JIR;8 za(O5D3fRkc5^Y~bv^nPOv~sEIJz(ovfB(4`PCj-0E?7?Sa(rRl zf9^xkCpG*YSRZSs&2jIhl}`y!OPmqH);?6m~vTWYi!SS~f%96Y&3TfoVu zMq7gA6tBrO+6rDDW2Z*b!SensV&=RxxL%`e(BRl4`z&gk~ZzX3fTT_3M-yHuQGhTFB` z=*oTC{&)V};Owuzc4M29e`BfbIkMgl@oz01+kZ3i@^AfLhM#}`>i@ee_V3j;Ld@U) zS0sOfxgB_FrFYZLn56sv#%On3ecd-={dPpG%TBb$wf!6S%JXS=LA$bAo5-}B`By9M7})OSXVWnZ!5noq`kL1nXb+!xZm2=Q{>?^kKI#NNe@jV=@ZEfU4MsSR|h&7Yfp0SSryO+#azatSj{j<;HTtnB>b+ApX zUJ15VtLg7vItr0<4YNn&?4Ld2daCb2YdqV;n+JAn67OiRT;geyvw!xw`!e&H4|YEJ zo>>T%TY&tVKI--R)W7lc^8ddvm(6IsAGe@ggiNjJC)9M;^5jZ)Y}flZmwhZC1B%3e@&&QPXk>a`8=1F zg56)<`^MDAe4M8?W4T9~h+NL>Ua;K3k{fSBXvo+oR7QSAODV3h{<}_Ta>1-tH_gb)gzTaA4*RK=N z=9*h)`Sj@r%jNH|2ElRzi2qIMb+leSFSHFIa;~2^`*0ZSdb>Bo+V#sgV_?V0-Z~v@ zZhIoy9B(CJj;_6S=Xw_H8<964XClV)JbDu%ufKakJ+`yKa_3iP*STQ1a}e(d`@b1+ z{5=ru+KjcDR$F4d1uU0m#`$2m*xw3vtk~ZMmeW3k_U(xC$-LhIcHF%YW9hHYKsB#- zg7q;M_q2M(dKY*#lCdrT%f)^n*gmnp8!VSx-UIgD%eVS_!PZ(PD~aewEze`&?ZdzoYA^$~D; zZ?*q!>7$k1^G=(4E6@1Lz}gk_+MM=di1D?#=dPgrIO3kW9LYGJsQA1ad=mX*h`e*~ zOp!~BPk|@LxC%}_-;SRF%Y7O##+9^kj%jXJBgRb*p9SmVzd^XaK8MItjzpjFp)Gws)rTPoe$Z$fb_) zWnXdn-UqgC^zVVK?=@Ad?}PP`*Jldt4-oI6==X!2PyRmQhhTl=udL$y2y85Ep7lSb z^)f$g4^o9hrk!r^xuH3+1cc24S$Qs>1Tg!a?acJwhp$&bB%w8 zxK4Se{e8vlPMbX>SKmX{FLn9@*m*|(BiK5ck9GSKqK~}s98@hh-@%cO0 z^+^4n0qZAkzE9A~#s42*=Mep$lk|U~+b8pX4y=!S#`rf_z6Z&3=|5m&YjfOZY2_Tp zby$movA#}gqg$us(SdHCoOhk*a!StEE-=6HxoCD4N`4?j!>@GsBdSph!YjkX{5- zkdE}CAR9a2VM$jrt>YZI0 zHbq`T-ay_&evj;c^L5B8jIkd5^=Dwva7L@u9>+GKwq|YmjCs>%&6+;rpm_^>dgk@@ zFK;&HH9NZ+^V&Om8w>k8mp1epRq^ZWTG$+DuR65hQO&1~kw!7b!tNzK1O1H|-R%e0 z7xs7e?g-b$EH|X>srS~K&HA!g3yId(+1)j>-m~M*xp-vl z?cn~#vPN@SqpPp8A69-uZ715J+q?S@FZ8zBezf(jMa@QQDuvG^xFz*vrh?v9n@oGm z%vm$*{f*wvdXwlQ3r_pudLL=@5A;&c@UCaQ*|WGlx6#)R9$Ch4eFnOkoh_~v!yVAs zcW9TPyLD`)=VN}v=#l1>FjFnJ_$&_)r)>3!Hur^f@b6J?%pN! zCgmT@%YD+a&7L*0=+nx25UV7y=!2};DFZuIJjng zd82n)qsJib!})Lv2YQLyKciwQ;xE898?mo95^FiDqoc23-5v8}+V)1Xzkbxwh0hA~ zG8T+JqiUzE;)+p=SvCiX`Z)es*auoAJ|ty;qVMq9`Lvw{9#OlSwx_qT)WGI*KYG1` z)gGKnTkS!(1&xmG-bRZw$H(DLDgw81ej2^E(Kpa!62^HBy`$cqZCh~PgZuA$W@POL za7!D#+zPE^QSlv7oGW3xU*3RU)SP#4Z+BNew?b#vqL$w;;X69J>dm57!)w1rpIgT8 zOq$Eh!x|8Cc@Tgx8eaPow$^<&y!Kc7PC2~DWeaW?@Vw5hrRdzd z=;e8EOm}ayyuaIO+rZCm^d8(>UsCSV7DuSU-`4v>KYplt_wk-}-E0E)rTj4XrrUN- zPkmv7Te`QC6J=FD@5jQjZ_ARb+mk*kXT8?poT&|_h1d6iAaoig_q5t=J zI->S2IM3!KWuM)L=;QxOZ>#Nt&ZZg6)3_7i1_n>N*4RhFd7rm(X{#+nUsCVM)++K@ z4tJ6ZS+d4D1CB$gt9*pOjHq1>w`z}%s9kHU?u9%h9ILH(?j6luPEz){9iJx8w3g3^ z+P&!QogE#~A3!f_QH=2j`r>-C!{xRA6X>3^@qbpmsCR3AFQGU4tZYkv72SOm|Ml2V z3p(qXiyXH?ADB}F@aQeZI1H}6vv?E~K1ZOl*5wnY<Pxz#$K zM%0!WgJN|xn#C9^(O1=>t#&qgZ=<8h{x5d2^*ax)Z=h>B?*Sf#Fe7Uh!!4-yHKz1> zQ*<@@n2B|{0)A1mu8Q7PyLwf;xpvp*4!CM9??qo#%eLBMr9P#%yY5YF9N$~I2L_jr z^M6F~p0hP}OtnMsnM~_7uGI{3l)m7+7vpCi{k(s|c@N92UE%B_=X*!|ym#d`s&L-3 za+_5+?^(I6DxBlVjjnLst8&{`IG>YpJ61TKjdD99(>WI>(>f1pF@<(4;#{MTspvj; zs&;kl>F@iZwM_pvz>eoTmhn8ZwObGM-Sxz# zKXv;}M$%7iXg_nW_EWdt3MBpHR`qM;FdR<5N0Intou998#@6rk3YT?u{^@Ic{VZO% ztn+#mF6%rR&h^W4#d>-!k2MBY^f4{9&^@cIzn6B;RQ+iN^{T(``uaOp{XJi*@zwQD zfA6ov-;iB_irue+)*jgeymMCHl-TZ7v3*9PyKl71YxjQAZY=HV&}x@ge_N^R zGX~FfY3*wqeYNYi3GHf#wh5)~`@Gyv==R?Z+4O-I_Km(h`kJp?KVf6+-Z!HWFYW5P zAm$zaJ-}C8x%tG6V8>VZ;sd0%Vv=zVfFF%Gu6a$Qbw2W2lkMaZt4GW&*fzSYVw?kM z&1Ev;{M4r)a^`2hsfhbX|7o<^|V}%>R_+fJHhTv`yWqhf5(siiC{9Ayg8$s z4$`)oROO1kB`bOcyne!WvXaQgnyH%7mq=afmt-x_RBOyO zO%Rv5Ij;-XmM!qo47&r1g@s=IWls zUYX}E=xwEL?B(d3VFx6ilhL<1^MsoN!IDxVAnS5sqQmMZf~js#H)45{SC&NSyP`Ee$%>l)qRHeJsaIU z_{)l}{ntZuze(e-{ZAF$``+)+*wy_Ojjq4nqE+2*tLTpJcU5%#{jQ2`{(e_Q_dfKy zs;W<@==S$}Dt2|hr>eT&Qqhg?cT{x!{f4UQ*ACJBUW(oRelJD0zu!w${gH~Uzu!x- ztNXna-TC>w6y11!FGbhi@1?5lw^3F1+o-DhT@>ATeiubIp5H}P-S494`mY?K`&|^f z{rx7Y>V6MJxBnGGbiaeDcE5q58_#c`s{UB1@5lc29{)b#b9*9pfO}j00Bk;weu(&- zTf02xUI$aY+Chjm`?&vKN9^PC@5jg+$StM*lal)@zCQzd{R5l)PZ2rqF>%KIIoPU=g(mC*XI4L9^2o*juHLuVEae^2iQJGaO#Yt{U5|WUg7=;mNSoV|0+3_ zcaZxx*!W)Y`wv*I+E+!c+IKZLbMZ>wVI^1XJG|uVJGkCRqM9eB6_3f#rM$bRVt* z_HrL;TN{ycABv5AJoa_L#`ayy*sh1)UGfi=u{QwA`TpgeOdQ*{xbqx;L$KqxPxW_< z#M=n$efMA)ZxeJm-`{R7xlO^w&}ROd(|Vb|w#^VZ^A{W2`fUleUUN%*D|9*Q=yOHg zxsIdV78!$#MeOhMal4YA#R=hgusyn*;$`Ey>#u!B2;cKgC#L#4!1j^P{qs&RKgAiM z-CTU8$tUlf!RD8^yMXn%sEoTSSRZ-&`wW!R-!ou0aLxdqhw6#72Uvgm`D|3z=GyKF zb}h8|oK)YBH8kd4;0 zm+PzT-N+Qg^%WcE4D6G@zBj9z<7BY;97CO4zXQ?rkvCVL?Q-Vo7{)VhY*UBW^f9)v zrh)CRukQ@%nd3oV=XfWQIUWorpE*tk%Vmy-g1wxhwnGp(a}pcd=htCi$2%8nY}e^M z=<>N|W`gBrAkHmuY;zAD4t5;pq`zZ$FU_X)G7o)bA#&y+{wKRtEa&*{>p9?@??-~w zQ;WG^YcZBKwKxhapIRIZmdl=SPRF2E&w=-%%WaJ095@ziUv1|8ep)Yc*Y-X{&V0q@ z^MusIz^n;L!)ET4019#}5tSmM~GhV#LWV=eS|4D(n(>t!DL)Db!J5Id&(wHYoMMM?N)@ zvqsL%c{m?yG>-NTWDJrTxdwNZeCBo+x}4%=V-C5G?uO7Od+HvrK7QkAGmqP8<&*b) zVE0+{`@#BLN?zV4p9AY7pL^%?V19}kYOjNheJ@yB=JX)gIgLe9*DrwOGpC2Za*CHt zwXR=;*a6A8|1j7-@|owC!2A^R)NU>h(8_0CUj{p`=#PT+Sy`^vV_<#c6Zdg2KSf;a z#(jiVK5@PRuGa6X==!97PlEN4PyN0I=BKEi_BuGWr%T%waQZ!kSWln*Uk6X2Jrr?# z*XJ8>^6oqJXTZjgH{T~{<;2g@dJZ0lr}4gt?)ppxpGcdS&w;h&ed2kr+ziBX{zY0Z z?@etlAad?$vH8AC`z^%y7b3>qn)cg>eCqcK*!9h`@H=2RuW;WjIq7iUD>?VdZ0>FE zm+!;bUw`e+)#shIAD}z7KGxzTS~>I3{u)>=`|^iiImOGyv7DRlvadtvUwxPT5xRVy z1#f`mBInT8v*E{Z#@B8xuhPn;CO-ko<-O#mU^&IhChsLbL(%Tq%qG6?DnBoEIrq2R zFTnb0%N%|Qb{y9}b^R4sUoUghM=pJS4Yp4|l0I*O?ZZ#eM<2QL`3*SZI7j#CZ{g%0 zAwSw~%<&&!xjOO8BXMk#$Nz{CbJM>Vk39Yb z_A(EB{)xz$hd6os8$2|R|G>$o9(1Y6r5=f6n><#-$8n1JgB`&HN8;EfkJZ7BV{ZC8hIy<(>t#Lk8HLE1hd6nx2_Blq zT5$5I$J$`I)FW|hlgBz>$1ykk9m71y!`5JHlXGSp zbUDS#n5pCF(zm*vW8mbC=RG|Z?3l@a99SRuoE6)G9mgx&b|vR{IXkz9(^s2u;=2P_ z8$Y#U8P#!jL~(BN+MT=4I(he1*26Zrz5}dJo`vs3_gUq$(6cRmJHc!7J>Ic)24gPX z<6Rr$=#w$EJ7%7Tw$^YQ?XK7yV;5TE``mdKSU%64-N15+mtzUzzdOo4kn!IGT~6_e zf8ImK!y8k-%xO=sbC13k`n~AMb8mF>Jd}7DcON+UjJq#bPVvgP`Ig@gULRv8#{S@H z?i0}ElxmFR{%&~V=$Bj%06$U5bt3xETqnWFC)defIi)&Iay<}UA7ig%t$apL0Xx37 z_)P`NTfg{C16yNl?t#n6O)hgj2z(t}ayb}XPO0YNz3jNt;jN|LC;HxqVk~Wkpc_B+ zITT&aJ{eoi{dWz1o9d8*INRh<0;5j8;DP-;rQ*>BOgc|ILBdmi3?{-iqIejGZx#h1Zrb-Uqg?yzg+%>HT2G)|Rv3II#2FskGN=JtLg&5!ke+_8$P7 zxa$*1=7z;cS0v4zZO%AkFQ(O=96zCsb7EbI zu1}slSAq4BxBnHia#_Pqf?dO1XpP|-ehMs~HT*PKPVq7~VaB)?MW1VsoFO-WKU0yM zAveNhZuYw#(bwFrrq!Og-2^t@=r@D)$y{#%yC<`UKMR(-6-geqf#oB~<94{@;W)v# zqp*O?#a-wg*d_`%S+G5XZfjR$J=!1+ZN9z(Zj7z@hZh$35^xIQi^>hrx1+ zmpKTt2fl=&kFmo&0+x3@GUqRYUDMR=QLvo8sl8nM9|u=!^aOgfMqfeKM?Q7F8(io_1ETEpq_cW4EDK@v*lZ0^YUzY5&ROOkA2%|wfo+80`+Zxm_4P~`jp$=O z&QqJQtl18TT=s(g_S+rV4%r^j=ik&*Tk36%{C5vt>mvIQ+d8jT;&o`(FR|}_8z8QU z|A!?t_uaO-2K!a?iQq{?^yx$N85P|zjvJ!SujuBsprY&FRnfJdJVakn(e*#AqMP6O z72W=KS9JaFAEG}vM1Q=Z+yCi`ZvW>>-Sb9$SHzlDe{b@xlFxhLZs@L`?}gf2^POnr zv*xa?T>hQJo?touFM_{^+MCwPcW7;UA#$#tIQwuPujaiUHmOGpN`W}YJ`TX*pkb4i}`0qrt zYcrPnN?T&h1j}`o_sHR3x!7lc9V_tFTbHUYIjzX7<{b;a#lFKn*x#aR*@CHb}0geS*bNS@=K5+6gzA^Mme(wkCll;^( z{s+L-@jr+zmv7s7V8@fUzxSw|cs^|%G1l6&3z7Aa{0_0bPe9yrok+%Mmb}kq`z=B2EAJc@lw4wTqYsVI z11Fz%(q6FKiHI?}XyqK!G5QeWCWn5oK7QM{zXlMw%x`JQ$*0drVEe>p8CXtn-5qB+ zVoj~1V;V=l%u9Q6`Vcrdc`tn!sjmAeC71C&f-a||=BI*H7(=eWPCqw!U|j zv91E^Bd?G9;A&)kMgJt&`Q&dRp91S6e^VLf(_mw1^Q^y?*30~~U4vYUn4j3WCSQ5S zw*J>4u3z-)!7C8!to;T=PCskAf>uudGiYx_s_S_Z`U)iLc{5la`K;$HVEO8L-iq#e zYRh`crAD6xd*(#H4Ll!NNuJj5c0^7;`_HG9bKb7Eb+EO+YkUXdI<26;`duY=CvEnS zTy+mwKl@vkdyo|s{a&zjG#~BvA^ON0@9vUI{+~m4jiY}aJRiyaegLeGy#4Q|mDAt4 ze*vl1{ULP6NZr3!`pBp54};~ab^j8&b=Q_$9s$oslFOID`pL)VQLyWg`acHN?@`2j zAEcFw{}W*65dAAd^sl1ZCu2Sd)<-^Ld<`tW9g^qLQ($9jbKJ*i5!c)g1LGT8Wu{VlM4lIyp@a!PW21)N-sXAJ#(x6|f(|NjDaltmo? diff --git a/include/ui/game_screen.hpp b/include/ui/game_screen.hpp index bdf159b7..cd0cf212 100644 --- a/include/ui/game_screen.hpp +++ b/include/ui/game_screen.hpp @@ -80,7 +80,7 @@ private: bool pendingFullscreen = false; bool pendingVsync = false; int pendingResIndex = 0; - bool pendingShadows = false; + bool pendingShadows = true; int pendingMasterVolume = 100; int pendingMusicVolume = 30; int pendingAmbientVolume = 100; diff --git a/src/rendering/renderer.cpp b/src/rendering/renderer.cpp index bd66a99a..7115d935 100644 --- a/src/rendering/renderer.cpp +++ b/src/rendering/renderer.cpp @@ -603,7 +603,8 @@ void Renderer::updatePerFrameUBO() { } } - currentFrameData.shadowParams = glm::vec4(shadowsEnabled ? 1.0f : 0.0f, 0.5f, 0.0f, 0.0f); + currentFrameData.lightSpaceMatrix = lightSpaceMatrix; + currentFrameData.shadowParams = glm::vec4(shadowsEnabled ? 1.0f : 0.0f, 0.8f, 0.0f, 0.0f); // Player water ripple data: pack player XY into shadowParams.zw, ripple strength into fogParams.w if (cameraController) { diff --git a/src/ui/game_screen.cpp b/src/ui/game_screen.cpp index bc0489d3..8c0ae570 100644 --- a/src/ui/game_screen.cpp +++ b/src/ui/game_screen.cpp @@ -5893,7 +5893,7 @@ void GameScreen::renderSettingsWindow() { constexpr int kDefaultResH = 1080; constexpr bool kDefaultFullscreen = false; constexpr bool kDefaultVsync = true; - constexpr bool kDefaultShadows = false; + constexpr bool kDefaultShadows = true; constexpr int kDefaultMusicVolume = 30; constexpr float kDefaultMouseSensitivity = 0.2f; constexpr bool kDefaultInvertMouse = false; @@ -5910,8 +5910,8 @@ void GameScreen::renderSettingsWindow() { if (!settingsInit) { pendingFullscreen = window->isFullscreen(); pendingVsync = window->isVsyncEnabled(); - pendingShadows = renderer ? renderer->areShadowsEnabled() : true; if (renderer) { + renderer->setShadowsEnabled(pendingShadows); // Read non-volume settings from actual state (volumes come from saved settings) if (auto* cameraController = renderer->getCameraController()) { pendingMouseSensitivity = cameraController->getMouseSensitivity(); @@ -7089,6 +7089,7 @@ void GameScreen::saveSettings() { // Gameplay out << "auto_loot=" << (pendingAutoLoot ? 1 : 0) << "\n"; out << "ground_clutter_density=" << pendingGroundClutterDensity << "\n"; + out << "shadows=" << (pendingShadows ? 1 : 0) << "\n"; out << "antialiasing=" << pendingAntiAliasing << "\n"; out << "normal_mapping=" << (pendingNormalMapping ? 1 : 0) << "\n"; out << "normal_map_strength=" << pendingNormalMapStrength << "\n"; @@ -7172,6 +7173,7 @@ void GameScreen::loadSettings() { // Gameplay else if (key == "auto_loot") pendingAutoLoot = (std::stoi(val) != 0); else if (key == "ground_clutter_density") pendingGroundClutterDensity = std::clamp(std::stoi(val), 0, 150); + else if (key == "shadows") pendingShadows = (std::stoi(val) != 0); else if (key == "antialiasing") pendingAntiAliasing = std::clamp(std::stoi(val), 0, 3); else if (key == "normal_mapping") pendingNormalMapping = (std::stoi(val) != 0); else if (key == "normal_map_strength") pendingNormalMapStrength = std::clamp(std::stof(val), 0.0f, 2.0f);