From e17feea9feaaec5ba1a41e6c3f298c4b5ef1ec6e Mon Sep 17 00:00:00 2001 From: AEspinosaDev Date: Mon, 18 Nov 2024 18:40:35 +0100 Subject: [PATCH] Load 3D texture function added --- include/engine/core/materials/hair_strand.h | 31 +++++--- include/engine/core/textures/texture.h | 3 + .../engine/graphics/utilities/initializers.h | 1 + include/engine/tools/loaders.h | 9 ++- resources/shaders/forward/hair_strand2.glsl | 11 +-- .../scripts/BRDFs/marschner_LUT_BSDF.glsl | 18 ++++- resources/textures/GI.png | Bin 0 -> 26072 bytes resources/textures/M_GI.png | Bin 0 -> 2161 bytes src/graphics/device.cpp | 17 +++-- src/graphics/utilities/initializers.cpp | 3 +- src/tools/loaders.cpp | 71 ++++++++++++++---- 11 files changed, 122 insertions(+), 42 deletions(-) create mode 100644 resources/textures/GI.png create mode 100644 resources/textures/M_GI.png diff --git a/include/engine/core/materials/hair_strand.h b/include/engine/core/materials/hair_strand.h index fc7456e..334464f 100644 --- a/include/engine/core/materials/hair_strand.h +++ b/include/engine/core/materials/hair_strand.h @@ -215,12 +215,14 @@ class HairStrandMaterial2 : public HairStrandMaterial enum Textures { - M = 0, - N1 = 1, - N2 = 2, + + N1 = 0, + N2 = 1, + GI = 2, + MGI = 3, }; - std::unordered_map m_textures{{M, nullptr}, {N1, nullptr}, {N2, nullptr}}; + std::unordered_map m_textures{{N1, nullptr}, {N2, nullptr}, {GI, nullptr}, {MGI, nullptr}}; virtual Graphics::MaterialUniforms get_uniforms() const; virtual inline std::unordered_map get_textures() const { @@ -240,22 +242,27 @@ class HairStrandMaterial2 : public HairStrandMaterial TextureSettings settings{}; settings.useMipmaps = false; settings.adressMode = TextureAdressModeType::EDGE_CLAMP; - m_textures[M] = new Texture(settings); m_textures[N1] = new Texture(settings); m_textures[N2] = new Texture(settings); - Tools::Loaders::load_texture( - m_textures[M], ENGINE_RESOURCES_PATH "textures/m.png", TextureFormatType::COLOR_FORMAT, false); + m_textures[GI] = new Texture(settings); + m_textures[MGI] = new Texture(settings); Tools::Loaders::load_texture( m_textures[N1], ENGINE_RESOURCES_PATH "textures/N_TT_R.png", TextureFormatType::COLOR_FORMAT, false); Tools::Loaders::load_texture( m_textures[N2], ENGINE_RESOURCES_PATH "textures/N_TRT.png", TextureFormatType::COLOR_FORMAT, false); - m_textures[M]->set_format(RGBA_8U); + Tools::Loaders::load_3D_texture( + m_textures[GI], ENGINE_RESOURCES_PATH "textures/GI.png"); + Tools::Loaders::load_texture( + m_textures[MGI], ENGINE_RESOURCES_PATH "textures/M_GI.png", TextureFormatType::COLOR_FORMAT, false); m_textures[N1]->set_format(RGBA_8U); m_textures[N2]->set_format(RGBA_8U); - m_textureBindingState[M] = false; - m_textureBindingState[N1] = false; - m_textureBindingState[N2] = false; - m_isDirty = true; + m_textures[GI]->set_format(RGBA_8U); + m_textures[MGI]->set_format(RGBA_8U); + m_textureBindingState[N1] = false; + m_textureBindingState[N2] = false; + m_textureBindingState[GI] = false; + m_textureBindingState[MGI] = false; + m_isDirty = true; } }; } // namespace Core diff --git a/include/engine/core/textures/texture.h b/include/engine/core/textures/texture.h index a8ce805..c0c42aa 100644 --- a/include/engine/core/textures/texture.h +++ b/include/engine/core/textures/texture.h @@ -93,6 +93,9 @@ class ITexture inline Extent3D get_size() const { return m_image.extent; } + inline void set_size(Extent3D s) { + m_image.extent = s; + } inline void set_use_mipmaps(bool op) { m_settings.useMipmaps = op; diff --git a/include/engine/graphics/utilities/initializers.h b/include/engine/graphics/utilities/initializers.h index e88166b..cc40adc 100644 --- a/include/engine/graphics/utilities/initializers.h +++ b/include/engine/graphics/utilities/initializers.h @@ -57,6 +57,7 @@ VkImageCreateInfo image_create_info(VkFormat format, uint32_t mipLevels = 1, VkSampleCountFlagBits samples = VK_SAMPLE_COUNT_1_BIT, uint32_t layers = 1, + VkImageType type = VK_IMAGE_TYPE_2D, VkImageCreateFlags flags = {}); VkImageViewCreateInfo imageview_create_info(VkFormat format, VkImage image, diff --git a/include/engine/tools/loaders.h b/include/engine/tools/loaders.h index c39ed79..00b6461 100644 --- a/include/engine/tools/loaders.h +++ b/include/engine/tools/loaders.h @@ -61,11 +61,18 @@ Load .png file. void load_PNG(Core::Texture* const texture, const std::string fileName, TextureFormatType textureFormat = TextureFormatType::COLOR_FORMAT); - /* Load .hrd */ void load_HDRi(Core::TextureHDR* const texture, const std::string fileName); +/* +Load texture as 3D image. It will require and image with all the layers defined. The larger of their extent properties +will be used for computing the depth if no depthy input is given. PNG or JPEG available. +*/ +void load_3D_texture(Core::ITexture* const texture, + const std::string fileName, + uint16_t depth = 0, + TextureFormatType textureFormat = TextureFormatType::COLOR_FORMAT); void compute_tangents_gram_smidt(std::vector& vertices, const std::vector& indices); diff --git a/resources/shaders/forward/hair_strand2.glsl b/resources/shaders/forward/hair_strand2.glsl index 6661973..d4697ed 100644 --- a/resources/shaders/forward/hair_strand2.glsl +++ b/resources/shaders/forward/hair_strand2.glsl @@ -153,9 +153,10 @@ layout(set = 1, binding = 1) uniform MaterialUniforms { bool occlusion; } material; -layout(set = 2, binding = 0) uniform sampler2D mTex; -layout(set = 2, binding = 1) uniform sampler2D nTex1; -layout(set = 2, binding = 2) uniform sampler2D nTex2; +layout(set = 2, binding = 0) uniform sampler2D nTex1; +layout(set = 2, binding = 1) uniform sampler2D nTex2; +layout(set = 2, binding = 2) uniform sampler3D GITex; +// layout(set = 2, binding = 3) uniform sampler2D mGITex; MarschnerLookupBSDF bsdf; @@ -198,9 +199,9 @@ vec3 computeAmbient(vec3 n) { normalize(-g_pos), texture(irradianceMap, rotatedNormal).rgb*scene.ambientIntensity, bsdf, - mTex, nTex1, nTex2, + GITex, material.r, false, //Take oput transmitance material.trt); @@ -233,9 +234,9 @@ void main() { normalize(-g_pos), scene.lights[i].color * scene.lights[i].intensity, bsdf, - mTex, nTex1, nTex2, + GITex, material.r, material.tt, material.trt); diff --git a/resources/shaders/scripts/BRDFs/marschner_LUT_BSDF.glsl b/resources/shaders/scripts/BRDFs/marschner_LUT_BSDF.glsl index 9ae46e5..42b6adb 100644 --- a/resources/shaders/scripts/BRDFs/marschner_LUT_BSDF.glsl +++ b/resources/shaders/scripts/BRDFs/marschner_LUT_BSDF.glsl @@ -21,6 +21,7 @@ #define SCALE_N_TRT 0.25 #define GLOBAL_SCALE 5.0 +#define DENSITY 0.7 struct MarschnerLookupBSDF{ @@ -49,9 +50,9 @@ vec3 evalMarschnerLookupBSDF( vec3 v, //View vector vec3 irradiance, MarschnerLookupBSDF bsdf, - sampler2D texM, sampler2D texN, sampler2D texNTRT, + sampler3D texGI, bool r, bool tt, bool trt) @@ -86,8 +87,8 @@ vec3 evalMarschnerLookupBSDF( ////////////////////////////////////////////////////////////////////////// // N - vec2 index1 = vec2( phiH * ONE_OVER_PI, 1.0-ix_th ); - vec2 index2 = vec2( phiTRT * ONE_OVER_PI, 1.0-ix_th ); + vec2 index1 = vec2( phiH * ONE_OVER_PI, 1-ix_th ); + vec2 index2 = vec2( phiH * ONE_OVER_PI, 1-ix_th ); vec4 N = texture(texN, index1); float NR = SCALE_N_R * N.a; @@ -109,6 +110,17 @@ vec3 evalMarschnerLookupBSDF( ////////////////////////////////////////////////////////////////////////// // Local Scattering ////////////////////////////////////////////////////////////////////////// + float ix_thH = thH * ONE_OVER_PI * 0.5 + 0.5; + vec3 ix_spread = sqrt(vec3(0.5)) * ONE_OVER_PI*0.5; + + vec3 gi; + gi.r = DENSITY * texture( texGI, vec3( ix_spread.r, ix_thH, 1-ix_th ) ).r; + gi.g = DENSITY * texture( texGI, vec3( ix_spread.g, ix_thH, 1-ix_th ) ).g; + gi.b = DENSITY * texture( texGI, vec3( ix_spread.b, ix_thH, 1-ix_th ) ).b; + + //specular += gi; + + // specular *= directFraction; return (specular) * irradiance * GLOBAL_SCALE; diff --git a/resources/textures/GI.png b/resources/textures/GI.png new file mode 100644 index 0000000000000000000000000000000000000000..500c044db885a521d31498c92e0229838cdd6433 GIT binary patch literal 26072 zcmXuKLwIBj+qPS=*Zkv2ELSI<}LY=l%XYsv6Z~9cNv-SD2iP zC<5$HSO5TkATB1P@cl^$0DuFaLBGEty-frI0LD4uLIO%|Acc+YDF;JQwD_7fiy2#L zw35j@86O|rGk4shKJQlIj#DQs6%|woMndm&zG}!M_3an>_39+dcc3kR%SI8rC5@{{ z*C{R>?#rtBrCmNRp`3~Rxyv^g+CNHTkK~Yn*@zAbpz_DR~H4T7P+fLM$hEEN= zj+M+iNgB!5)HG_x;Z+GLw-r#9TS(JtFE!5I+Ck_>{LC8u9-Tva^V<&U3N$O8x5xy? z!Y1%ubT@c=fu8bF0-z_q*NbP*1T4~BX-?8tl&{+<$0`B?W`jd31RFab;+OnJ!3VK; zg;-8Lhwfvcvoi5+5e@1Vl>d+rfSJNa`t-am0h3>tV`t?G?{$4|=1qTe$YH@1fJ9LT zd-b$~o?oGFHBFGXWJ^+r&cr}logCk zwA0e01owGxOP$4rvn?01*XRkQ=iMSU$kebeN}nu9=T79Ph-c>5yP-IY6h=Cvsa^-D zDPG6;IYHChVvM)ToSXRy37^3@88za8r4 z6xv4MNHUV?Zj#Q$d$z;qDnM50dc0E#AzjkAtygL{~I!syOyu_P$L2 zuA0K%DvOopv@e`t*q15+5BzHxY9w^ZA!3iaS+0NO)c#JXmMhyM-7^_ERS_$}mrAGT z)Sz6D`l`g4<~bn+F8Z4UbXXlM3pGZ#I%BlqJ)OO|?yz7+cWJcZ@EOBLsS92vabrb$1?xI8o?Vz_j>(zEgmL})~>t0&K@ztvL?uLByqjl|T%uThP92f1C~ac+Hx6|@cEzEcZG z!;iko%R>HJTZ=&a0G@Vi3s({GcjS#;t`%|v3R4@68CHrXY&|p>=)(QWxXMbE#)4W8`?I0WO5AXB5AC=i@^Eu=j4Ql*bd5!oP%}ptQr{zu_^m)j8mjo$YV~Ya)6q4OV(1u1q zL=xn~4mQ+}O!3v(&yf+AX`%tsoJPncE7N!jKljwC4MlzOMP=skTqmR(`5WJ?Rrwx6r6(qOaz(_ zg5}*kY_yL7B+_=adNvxEP5S3=pM|9XJEW=fbN}1&4&DUekDV#W^yHDPWFb#n+Y*|9 zq=9EYTajiB(&?a}|CqwxkFR$0Y^9~2@56(T#4y%-QIEh{!$3zU+xPI|-9Jyb_S1Ls@@*%Vq@1#e zf(s&1q{e4?5bCB1J@1wvVZEPaW>=3phhxo?+NY91Y6~Sr*lYr?pb&jN&$hGr5!L^X zDq1**(juo98ltK-$ebe z0ktu?-vA}yL@5Y0t}=VjmrCQWY43_t~ZDORMTO@!viEujO=F)I#IC^ZC*7Om`k+jLYWI{si| zCTjT3c00T&H`XKYp|00Z8N4tCj9V5gv-8x$wlu@)l(kUGY{MHlJ>s`aD|m5&&jmID z&|9}c1uMeL?-cu;9AFjumo?C ztCJ}=MgPO9;i&~EOC-s*TqRvoeWCvkE_!fW>0`~sG;si_7mxeAo}=^vVV2mS0dEx4 zCS-EK;sk&(^V?1o(JmKO;x;}YeeglB(x4JZ5J)wC0Khy66+lb6w|)_z%%p?Jt(!TS za+dii?|f2)@c+xz-M)mari%pUf}!Tan{cAJz|wI6_;u9B;|0}nF}Cv>bfUTKka0si zQ!arF2;+>A!M0Q9j|#n0`~{D0Xi@_OA;3N3bBJS0CWn_y*CAXhSu=Q7=&xgPkJPuF zrB?cPqzarZUR*y(kZ8h?_-O-EtDHkIrkiuoIk*0l;Nf5Q$j zC{cvz@`^|PDQ)J#rP>@6`#wZmzt!mS@XBtbyN4~qP(!xmQxpAiH*H;G9SC&}sknYb zHHch+oFzC8XU0Tm+>Btmzf9=oy-45Z^Y!}fq?ujKoIc@a z*80yO*|z}GLbe5I1N8lRemljeT2V0d42`is&3|MOt;{^R6)KTW(HG|H>FaH$vtNjo zavpWUT!#XXGDl*{a-3y#_uABTt;-V_vwR2?<==K2HY=?}r+zFIPx&QYiU%q|qV_8@{E{ zR9UKEcAxLIN`oF%8#U%4&Sqlf(Jv=BxtUcC;CD1F9s@^yPP3-}CsIP;Ed0_MzxDQZ zkm%oHS(v?CV8((~-K(mjMAD~8LmT;{|njEPreh-73WdM+HEV|r3mU~MCEN7 zSG2zz3|1MRx4G;dtea5Sc)7h?yw*Da87ZHJhK(QiuYVOqt3j?qZk->Icd|%D1g`3n znu$qVE3jVwf&-Eb?}?#&`4nFVU!yQWD*HwRQ(Y7_SkX|%^fbU^eBqo1u60(fKFq^3 zu|Wn|{sL~T!+Le)ykdtyKisa51NiVuL3LMc;VTmhU=lUhJ8?ThnP^8|JqrOP0k-GM z=-L(L0?TbIkn@EQKe4U=UYx<>vjqs*W%S~Ie;|`AXO10+Yg(BbRI@~TkWoVBlRl4g za%bx0BzDb+&zzeTu0>y3E3b7SyFAZx<>~}BBSFpF+VK*4B@(rwu*i&0`4Wq-8K;n_ zRuolW`3GbD$H{Q^K;|1gFTa_pjiq+5>B=?J| zVRlWKa3he<`{|O6oO)f(w9oVFZvP#4@Db-0 znZhq!<0*7Xsyo9cw-q=xwwFoL0W3a91$G_1!wD0mS)YG)&5ZFmkJCvwOhZM@OcORfj9VqxM_?U$SvE^r6acL{?UA@`- zsd_z$;~I-QXeq~~>qWxk?QjSh$t{XmRK2wePY#9-RUa#&x=M0f2NtPAHEy_F44BK~qZ1pw4;Z~R z9su!tT=@(|aF+qw%4{{ePPH9Xxz2spwG!AG=+9ehZG3o@JP_KxScQ%a+W|F{ccW2~ zw}V<6IU9)v33rR^7e2@MxwTTf)}D~LmqyGSG%Pn;A2Q*S8-RUAq@ zWHR+mM40d?ZM(^wOuscMfb02ax+z+TAg>%vLVdk0@d{ozkSTSE@FrmR6ge2Q(xi;i z|6D)$Kmt#wYhl1KKSe-{P$T-=-f?K51k9H_RRmFmFI>T0T+FK&Q|C*;rE(JY%;q5C zpEAD~w*qaHOY$#F7%nbsQUE1jQ3x~iCBA^r1L_;?()rw#MQ#!`T0vJqY1MC80&MbS z`WNatOf#_VL09YH!nhJG8ArM~NTucVg}zHgC3HaB5+L??aS+6Q`X!{`?ppfB$j`VF zNw1RHBdn8_J~Vn3#$11H9y;Bp5IczKhHZ~@+4@o8^;1W19%Z&(QOTnhjlbIwd_H6> z*R?(GqTY23n46fH4DL2Ih8?Sw*RyUy>Sy>=8b#^;hY5yH?5(qgj?GOFv$1BAZ;2({ zpSe!4t1X+g^!#rRcwrqKGd&+-`l>Af)0<4;(E~g3)&rzt(rnd1Y4FhV@%eh7&Mk-= zkGE0mP>!Pj_EtW@8eOnAHTqo~1~sQ38y;BaM*V0md)=^X$`RTK!A#1SRf$FImDcsS zF!>rMet)W&mTf*f1#TZf(CEJ_t}gc4WRUytn&I2@Bk_5uDRfPpp8l+H%tRr^uojcB zAQ8Ou>1GK07Nr`WCkAoL6f>I>W`h|tV|}Ulo zhm1-0XY#psZRi&^rWf3wlEr81TNu`)D5?5C_IID;7I zuUIp&E>}*%qd)vTL)j_aAazg~Aatp?dC=7uLYNBL0kv7#3AaZKPF4mB9wsBw;1ZP7 z^<427KbdlbXx!IuSokg7Xd?Zx-lnWRjTj4Xg?_|(?@i!)OaHVuA9Gj?bjGWg!W8}C zz|VpT#gZk3a#!G9_JQGYD*Y>a$gk$!Xc=~dL@odDKSk<)=y`7ulvb&mEvn^VdzkVN zmeaycHMILqE`MNqY(<3sr2{F>R5)*Iy%P6N0fM->^dr!zTUjSU^6e) zj7A9s`oHbaU`kKQmHV3wEizO>Y`3&!CV2n#cwnu@qgHMYp;aizQD`d7)YV1z>og}@ zY6!!By-r$IqW9b+krtcF-1%Sqaz2l-UnT1`=FELbgoe<pg9BD_;+9cXmqO?2q3+m5egHl^TY1n1wl*Tx(U9 z#?7_VdYD&)T)%C1eCMT($vadON;DK>)fs$KxW%TA)Uxp>M|$**&S$g_;_(32;ADR8 zl9$rtjcLU?-VN?yh(eNNUyChw#6(g`BTAqfAgtynq*YPe8Ykc*boc*xBkBkx5$R5aCXi_D*} zcUHy~?~S$rM)BIEiy^=MT4ky<>cq5>LW7el7KL!Hu)ffE{W1%OUemb30|k%XU0Fx- zTvXDuw5qCO9UA(yc!mE1eYvB3T`Q|#zucjC>R%bU3SW)yC!&PF-_Y{Ac6i6qH~w?w zqN5$zqIxNd-Vlst2OlXK6g<(tf5{KegfE6&gjQR7IxmzkigXTa<`i5qvnyNdH3g`s z0x5lAeNncSbL$5WZ#VrdTYWy<&w2N7w0*xZyBeKhKo_}`#Nm9we(`r_f>y`#_PXZL zJrvJ1Foik)^B7W55l!-42Yt1J<&cG{nH}`u7a?(}>nHZ2pq3+kKyE@QR)@94{}!d7 z`xvDtqquTQg)MQDNizQfaohQA)1Js(qs5bq-3-^1AN4VmebhtJcAgOphi@GfPPi9>y|t- z(Ox#ia*>_mRVP+XFtP@t538KZ3{uEf5Wk+?h$d<+lI7ITvXAQhUDB<>P2r0ZJhz?=%&176)Pfm(^rgHmBZCJ+XM1@OcXB;06rV z*UwOfVm{uXl{}o{gCv|*$v*pE8>#RMBUI1V2=WAAyViH_r{<-2nlS`s;MNycNQ!Q; zh}lEUKdr&>^n$}nGuHhz-wt*aok`ydMp!e+j$vxj(t9o=m4$`nuFchQuHxu$C9*ri zHE8ji_4~wi=hur?aAYe|;C?gCvapl|pVL^z{bAA7zri_^iZS%eNwVe+$L_0IpjT@H ztOiKaV*cX@6|Ym_#>^dT%ho+$Q7(|A!fWir8}R_?B!hIkbCfo8&y>6V-*9+>H3K^R z3Fv^gK8GDXC!S_39yO6HUFIlH^?M4f&shnrdmq9SM9lmiiLA@Hxr-Yex@4_NOI<&H zVhs~m59rD1PIM_DM_}3cS!6kPVg|6_tP#u25G|L>gPRa=-b?Jee1f1C4L6gn%Y_I8ygI;!+C!r$P*~^gP44|@kAqD6 z8G$VK^vz8Su9OC;1A^StJef^NK?cw>2wc2)tX7@iKLuI<`*64?6kQ6OU@9766Y7o& zv|gds$uW|{BFO5vDH>VsTVPcY?3a>DUPVHgn0jDNY$FDVmA!KFJ5) z=o6^x?d6@lH}5P$-s26U)L_EmOSj6!|D*uR_j#``e$-Z2vhI+z*Fh)}T{k4XyHwrr z`1oco{d~90i~O`?U~9`#X-_s(JBnHWJ*$x%5`Rm+a)0$LIol@w*~x*9>ShU;3UG8m zEK`LRQMVagb&jroPl)uh`(1@m6$bjk*zB-{2(ySSy2h%LS{o^{M<=uvpK~$>` z6J-ibnAF{G%WGWKZl7gy51*1r)B6`7LlH=<_0e0E6sX1xQCNMk6jd%MUQquyr+Qa$ zyLR!e`qH4E)ZDZwN>V?NX0x@dStohphe)W$AnFZDBzjTPTs&7nM`_GYuj50T{dF(m z2a0%|Pi@^Xyq%6`5gbUdR11$~EmnFjaeFz}g#V;A`(;IGMANrWX8YC{#sZxr!FL7# z)%~qbJ2Cg7zo%)>)o~Ix2O>c}w(XZG^OR2KNUpY}26KEt!^X99e_&~3EkjY^b;|FK zY5yhyQCo;pJF&y*+q~uAyY^l^)fxJ}ij`M_#9_%(Kpb4CdoylZxn#=dDaqhzd9j72 zp2TaliXXriC>Zy{CAcG9>pn=1eq82+$cPD{7VrnyVo3Nj+}YwI=?zz9t5U%Lo=f9* z8Qac<_W^_MOE9DR1`Hi2Ez^i_NeNi_Q600D6@yRSC-;i0+?8Jb18sV@`LzpX-UbDu zLC+!ft$#EJ$qev!d+0B;^G%~bXNW~`^}T&QB@mC|EJU#-voCD^SYAI*X7v`G*59A} z=g)!=i=xcB553MR#_tLt1+0XiXWDOeuzQ4l^*nN4H9r6?&a@sf!L{Sbg?P~^@JTmI zJ}~z8$@#OSl$c>2lN{V{CaPD1B4^>;lRAhcAjaqQ=YwAf{sM@r&Rhe@5}QN@7E~#C zEY{p-aQu^;Glb9kWtINP8JceK;UR{xm|Vd4Qc)y2%43z_-+lwz`4rk?GU6U<4Se0B z@4aYiK&%%dU3(wZbdt(|)cr`;u`XJFnKkIj=kEHM+wapjthu!u`3$vQzrrD972DFx zB)i!bPS|#em+lh(bzG)EtvElB%Nc8ziHz(Wn<~#fp zkNDM{`>ie6fVlQOWZoY2U-!$#06OWuiv&io?|$24DcB;R^*4)iyXI2y#PxBvSMEn6 zqP~q}pSWToiAYtx=&N8`Tkfl?Y0QSLW5-SSZl=2eimVJODW__3T?Kr`iX6}*V_qni z2-RH#;%{C>GK;iLQ`wtC2}M4X`VTEO(lZC*H?0}TSJZ;KBxO}69$@nD7b&``xD|aO z(-UExg(JkfIb$QLzUB2MloH7_q=IFY5W6ADw2q zdY|^}RfVzVeHmfPehzM)4{q)y0K5&Ctjprx4tExd(*xNp6iW2mzlNHbpJ43qXu~v>s;OSdVv(cA&QM zR6TdSVZG~yI=pXveAnq3>DZ1J`7IeL;Cv$9GI=8F?@qS7wXv7wt8?awY(~*{cYqDj z!y63MO>CCRy93L;%Q2Q&TlFj-z?5Euw?2&dpVT07KZ|*WnQP2-sMQPQhj^TEm}2m! z-3>L%_@5V~+}iur;vDYdsNu2V!jU742UgBXt<#37om}53 z)gx%t9ZW`u0yiBz z3Fj?BpOZri!p7wWcgd5Nw1kiRRfqn}qnANH8l2>0hlr@U+~}>U^Q&EAnUZuu3H2G1hoxMS61Q`=I3`PZSxv z(FPk=ZqTi=T&mZV`}t=JUir%;jfk|q=~n5>iOtoUFCVEVycj>Xj#$td$G%U&WU<=l zcvFw+hMPs5K;=V~MqH9gyRFEhm!;DscSQY)CX?Ll_$524o~1}bb_w@D7Q-kQu*A>? z*9Aqf#i^n$PF>~=6gfFf&_ykU0vaUVLp>u>vcN*P31mwXXn2=QayF0)h`vGz4(pGS z{Rw-2Q()O<#_wfvRoA~GN*ZQj%unE-ERwM9cwYC$B{20GrC2MHmm5E79X`A-mPOEea z(GMhBdMLRsJ6JISVxz%@k=YR%;;zJSS+y1`u+$auqEUgA>y^Yc_ z^kGi0n12f8Cq|TJ)cRlOzX=9zcl(fb?7N4Ve@jnj)Lh0n&E{W?onaL-1?K6x)Qlse zDB6toVcTs`sF`I-9ow5hI;+^7VX_qMp~yp{2Wb)v|i@5ipTHves_eB83n z+ER$U7}-iG&=OWt)nXLu9x<=pf&ZsK#FOq}&7<00n6qTtO?uIWbs|^OuL;+$xXIr; zm~r>d2HL6l)K79Gc3C*kfe|>R=&Y+lA2$By!{y^+bN9BXlYu&tpI<+V(^c^=9(5`| zo_2?G_y&xsCI55{p5ZbUGaf0Y;>BuBPY1z%Jv58Pvz;YJ@|Kv(I3561iVmXH;l^?f z5eZ(KO~0HXnz6}MB4>`pEPJV~4d~(&lqWVO97vA}E*kp@Iyl_9U zGn%vT@$2&d;&D_*%DBNVr!kZI< z8TkAM3E{{u%~>E>^7u!?RwL>~eBczqXi4}GZE(5?q23A2C*@dti1rskK_MR)$=4!5 zt4vD)(by|~M4~Q`$1qzjdwj+1>%qHh#p;-a20H<{l&Boj`Wn9I-dU&kAl23=hE7uM zKa1xaF2ApS)=Qp@a%3I~qNSvpXhX2c#v;!ll6c84dy$A3g_|Ag_{aN={cU0 zCTu4U?ZEhCJD|c+ieXD8HwBTyKP3R##XwRCph=4MT+r;_Z@RNIRqbTTKaQM$r`-d2 zp`8N=U@;oPx<7NIbj}Qt<8Up6v)nu+9sBM_J2R*+u3XF&`OQb7mD9OxV6^+7*<5wv zs#3!G0jceKYCs^L=Z8cfNCz$BH`6LDzPV@vlcZ$)cz;>F*>nhe=zHTqajO5{zm;SpzF_ib`2BElCiOv_#~F~i^rY) zmxj?bn=JHqxQvNqR#vN9^w6>02hRUPhw^*;*)dg*4^ONRv+~aFWzlj{5p;A;B|Zoe{bGlCLi3$DtpsY^RyEZg znv)X-Z$XpihNk6N9#B`Xbeg|vNmUuQg|z=Uyx~(x7Z3z7Zqz&30~vE~+hETzCo2f~ z)eI;KBjp*_!pZB3tfc&0yx}TbrE*d6;pG2{wvO5KQ-&08PnGcLM*nV{d#gUH3w1FK zwojxr6Ne^R7`^$GsTRC-=4)bbpuWXv>eJr0xSb@~lU4u@EU7u}{pbqpEhFeD;NTJZ zfaxs9_(3ws!$a#!Pf}ZLY#q>eBsu`oRz=r!c=j%&k z3NIM`N6vJcaTX*ThNaoiu`2&`4?V}BMa<>p6&K{6GFfAa&JAIl8_&I>h6Gr6i*Lc#YQo3w-qFNlF4A#B^s;B5g(t zBjO4JOq$f|%mQbnp{9m~s>{&ycOS6pWQP>byR%C>EgNlyYc?^Xm)$U zjKtR02cdt`S)%pL(McvWKtv5*rJtv5w;7x|q;HJFm*_SmQWT_4M5kIv{K=ihQGQBt zWi)b9^f-qT=oTYQGuMGpJ@<-7B)iF1MB4sndSi_Q@qVI5ikbd_mHyo+Y@kyOl&g07 z4Hs`UPFxAtZig(JcGFy*;Qg6^(;^Y$Zx?uXgmTC#HWq<0qjKb2YdZG%*@C|k@Lwq) zf>eEH9jzBOoHHaEql>~}9Qh>p{R0F(pU4TVw5RS8Jdki;6@tvY9Um_#N?4y~wlVog zsh&Fifmmvx1DT|Q8km_`6IVmGwo{)k7&VUNC+@vu^-5xt@=9%Gn))=`{aT&Df@-Og8iEdZn=#+D^uGkTi2Ubi zE@qP#uAC5*j5YR=(f@cK=W&gA8$w-lWmNqK(Yo{=`Y_qe(&18g0g!BT1-SPG(79>8 zxBgWNDWDucHe^<%&0tFH5nLMPCpUQB`vkkv_PhlSH5D)63xKpi+@J2)qkFUbu{m+a zD~MCfGSE&)GKzb6Ihlqkyb2?TZj)(kadMpLm@E1lItN2d3HDu=mG1PMr)(t2#e`Q8 zof1(!ssBZr0w7%OqS1-^a5HeSx;{r9RCdcae0vMfUU{DQOvHB{Oe8hyb)Wq8^exf|-$8l3me)?lZ6RL_uHAj|g3LG^fDf zGiwx#mI{nT!Y89Nf)6f)4o%?~vX4AK^ZzTFV}BbtB-fd7I0)=Vyqic)kw;&*`?PZN z%8uY1XqAZlTwYpv^lW8VU#snZ&Jqb!CGVanM3w^{i^&DWI=I-rh1_0-WE30g5RsAJ zU^quCueJVu#8kW=uaTu!6hyMQtD`v)h+&~9#m?X4TiS-^`+Uc$PfLF17KWeeAX%*= zLsGA*5E}au6W;y$xQG4%{piUu?4mV465a5KE)>IL(^6!PR+mkMEH$RtQG{!V_GzrU*=z6ZhUQ`}Jy zC;{aE>BL?Xty2KjizdSE-iX!~rr-t?qW>vx+dy9&MZRrZ&il-2O~fBNr(yTck;$zPTUrgtOnXN9d-N1O zfSfd|$XwU3j39uLvW-{IeXwO-_qVITIJ5oNv2ty7I2Hc7ZV9x^Q58bA)TBoUZ3z6@ zT4vTSt4{6NBG3xJQmrl!9GbsGFQ{QD9bxY%syOs3FuRMC8q#KG-kvql1I!lYaLqZt z2i9^>ezc?hQLSR0&&?GYQ57i}dD__~7{A>4jL0p7;*zX|?BD3?=m*c=gMUJ-O&%4K zgjoIgQ8CX7d03$%--$)EtjBt$5xfzL^&fdS;hZ1j{atTPw3YyN7L#==mF1nkKqr@c zReIh_GUs1@K7#%iu~WDQTHPDSs@+XzUU?zB5`bBu59iA`V337jU z@w$D|+R93j@zU}25o$ElmtDRX7QUvlu2w=xjBWqm^rTpZdf0^3QGU-)zk^? zRL_ZjyO78QLVxOC8DyKZOCItj&10nRd*`HcS~alChC=sWPJdrXGA3fhwx}@A^fC_T z*mwE5yaHrXNVSi@E3zteX!g|unm;=f!Esm}7cHl56@jj|C4m2&*53D+xtkUqI!en( zPsi0;B>d~KYU^Vr0r~iKvk~a5WuZ#@I94=OuUl-$U zoa$P8$x8J8d`J9fu5o*ZX6rZ*N!J1EmeybwEpGeqvW4RPd|F_76S+Fk0i^}Sm@G-T z*Dt%9_E#0mZ&l30~oSNxTr{2Wl-;h1sCKCNxhi z1$`xz?>VRG-)$$LJ8_XU;(I#fq=Bo)(zId0PyXC32wN}%H*ltNd#?!Yks1>SKZza zYk9EGkjN#ZoH(SCJ&J~YQ*uh8CcSNa#iG@A4i>5nT@GHy5nVHm+|_3S20RwEb(FK7)?b80 zpI?@bzc+oIqjlWlRHfW%LBm4X!8LD;&)Yl036t;_U=b>@!T2B6fUp|;Ni#Z+zx`it zFT|rU^|1k*Cg&h0f`Clni1Y=oM=YWgzR$(cZmFB5|Na(~d>P;{1^j!%h0aXcw3gfH z4MqtvA(%;!!eqPRV6n2I7cy#|nyDTyVVBtPzv7q(XTp@~O`PUP|0w3&iT%dMv7-lv z2;~ud1)hQbE}>c*b9@b~x^b#`E79S?ZIT?wnXFLE5xEzMkXmIJu4qXEi^a7q|Is&Z zHYlD^dN~B!n%1R62-G{{Bw2}cWpOQ#YPk~Cxl^RDATw?QU1bZ6O6Xm3CRX8Ms?NG1 zKm$?U{r6}xcmR}6VgCDTEsd7}XUTfl0DXvrgzut=!fJh9Y zGF-mCo_unpmc?rq0Dc`k>CXNHq;lsQ3a40~cYWO1{6*;dBRnwE@5p}BDbm9@X%*z> zHxZz?p1Y#g)Jo#zq_hG{+yrR1Nme{k>?2k!FWFs2I-aRQm zkSCN)+K3R+*L07#gc|^akOwRCy;(6Jstvv0+fJ+Yu@6vp#<1A%i_{zhK^ z(IEF)eK3{%TQ$LIFUS#_U5SN0XE9(7QrGT`0N9rSH~785yzCe|Flmy_5DzjA#a+!v ztkL}8#ge4W->4)~`?1vx#*WX(j|LLINnYpOcVr8KXBb?HD|mgLjnv$s3_|Alm7&_9 zGB8wkz&T`&5-jG=uV$h|$zK`sH3ELb%9%m@KHO}3UF9zR-Eoy18XHiH;H6e)rs4OJ z_c!$kXkHc@yX+6K8a+R4cR}6{AD{N$MT$v+^BKFml%B?5Z;iXYMO|O0rijXTXzV!` z$5qWtZZ;5kW4L`JUE4X`P2B2PClFLv-}$(5T=P!aho$0aEcF6i$PNj3`@Y{8&@Q>Z zXVN`3j;0g|R|wRP_=*XE^LcqOoPbokXDV68MFI1QMlBSVPI;Mz(n$0EewjdYP476C zY33LrKq!M|JTtr{jV!CRz23i#V5S?`dJHq3M3y_Bb}ZB{QPCqbs!m!jRyLux>1|U=?pIaA-)@>ta`m64&ikVP971u9jOv zb6)!W8lIysP0F7FvA+M5W?sOQUMsgRf7uvwobJ$hRdn(&-RW=P z-2_f4SdOaNy&BQLoTsi>h>gmLw|%&1dnZ%7nA^m74Hi%7(5djq%~F15t%8R&a%#z- z!r-L2HzT(SnZoYepx`nSa*8G;+O*#pl`;e^0-$cgU9zpVGp_tsjd-GF;2?;({`jzbo%`WN>pFS@OkJ^u3c-T9XGW;N zUHpLWVRHv6M1I4lQBj>bq_sYv3OXaeQ`uCtVn$n!@KirPFf(TEtBhJv-* z0U+qylRL}FuU;-{6iDD3qNpf9-XCJgKwX15P`M?YT{Kc#ZqesMKnso^3W3=DE>QOt z;q_zdTZ88UZ!Y{ca$ZWbi<+di|33)6c!W+aj7&0cW@<&G6l784A*LZZ4dM-66mZoS zx2Rj)Tm%84@W{ex@mJ(6-K^#)-qyYK7RYZBDJ>5s=pZ0nUz61E6v0f)_YEW#y@F|q zws_7f_E>4`nlB&Vw6Ds~F}B-cOUvf&Y59#PfajQ>xRtspQSr4K6-B6@FQOU%cYTY%0e>ij9}U zQIo{-_sl5Zr>cCRf{<&9#5AJHlD-GTv+N7genSta^r<5btbDPgQ;PX!gtGca9Oyv$ zuWW2318C09^~FIY2=|2RU^?*Hw)abe7CV%&g>tX*`y|tfUvdJT(*+~y^qC(On@DV{ zbJKX!=gGf8$~R`ViD)iTfWfzemGBNyK3)&NH3|QpHaM}p4%ENgT`lUXbA7|_QyBie zHO*@OnfZ<3|GJ;b`&kZK&V+>W?`q*76`j!wmP=*t&HS@Xt%r;!g79oCnUxG7Z|y-zTMc+!Aj^0UfBRy)x@S_=5Ia(9mY{ zxyxUd!y}EJ;{O99L~jZqAY*Z3!Cjl@NV(Z@KV|O!Nd;U`4zL}zGzi zWP^BvpahDq=jyI-sGCIn-AU`puT(?m^wDh6g|+) zZ1BEQfN4k@Q4ab9Ts&h3am

=4)qH$L5ZO9`1F#AWgN&V8QUy6f`jB>-YsY9J37Z zP9rIZyH=y6s@!@D$yXzINrwDwpNNyqqF;c9u|z{K(nE-aL;~6paDoY!^p!gyy1aFt z9E6~M@@e;hu!idHJtzI`=Eo13Uv@$`L>H<9X~%U#l^87!feXS_aZO>d%IZ`|Sbh*d zWC*kqCv+#|#ny7hwqJJA9+R`!Zts{Jp0X@5{D!TgjmKkn>@6?e6_kK^ZEv!dF`VAT z<&O0It%QzwSMU2O52|(>dhyx0o(!Bbf^tassB5AogwCE{lu}Gy^u`9yC_7 zih*AhW8teRPT#hPF`*fZ1swT;s6ti!bbC34I%4_Uv~km28DxJg-^nGm*+gq|Qd8Pp zD`FC#XhTh)^-+)wK?$bXpYmhI<5E=F1haP2%7e_=ip7vhXP#PH1m9!EAD&n4U7u$! zJ+gyYwu)6HpnoFwyW#i6QNwA?z>8q|BUu0MVr!gx1>F~G69RFELnMt_^TIB*w8MY> zB4P0qj9mNx=zE{V^BuaOcM3td6biI{U0n*r|9$K^IR;ZE zv@NU>=4jMv#!?^s_d)bucMEJ8XWWtaoESZh!fwDSgPPJ{b`qfFN7kS#vE!YKI^K9m z!DuqXUM9(qN(vh-T;S?C_&PfWQx=@3^(!&>Xoud7C zm+O|Uy!`%ZIo6Bb^vytvyT@POd*JE5GYB76-Uv>Q zq^7W`;RG0^$JM=DQ1|LM9?-qy^*0}}vfDdcrM z<_0lVT}AyJi^;C2gz7zh@P%opqa9kXT{`utoArLr^$O9hk?&Bm?Im+jp9l^!L=t=cJr7a?6HQ5ByG+0?fpe%bI zvXEDZ8?tcHtYbqJBwGKQ{V}||6<5I-R<1=AQ&&=Chz_=#JMYRsICNNHc$L_yt)4ys zz@}md9Nk+~p$FG&lOYKE9tD+s1146JtIfO}T_G9`o`3{@UI{}$<=}OnXSx2`d&*#? zQdzd6!0jf_`gy=#B4>iz0bjcMgRCw}tdCtID9rP}t0g>ch|&vIVx-oU;Bw^d23eaAeRQY0R=uNs!k6~1>?RpbEN9F|Rm!roOJ*e=588o>r z_NlAURc=@cXQt(H3g@FoFqum>0BhNK0GTjirj%mUl=3>VRFx@}x`$SW*AItN@Rt*% z?|G@RxG`K452<)WViZgbOH*zXmOkmHag@UQx98)*pFq8*!~ngdWMTbe1YET!2VHa7 zriL(LwRzRA!}njmVq%EgWl7T#?Lrv?jd*v}CT$zK{VnTy!jw{;s<5yHQH^ZI349-k-oG^LbcbW6<6Wwg~MCfydl~*@xL7pIC{FCNs6{P>g-E5FKh2AJMCxW*AP)s}bxIMb>b<0%6+Hu3-ihQ5 zGXqs9Cxb@T=TzR;j@JRxJmrzAZDpSHI8|9^)ufaY;j*_>11O`KhfZ|de2*$$jiTv! zalsNP@0sPmRb^}Br}5}}tfKL@manizo9sN~VW6^(qbo4QhFEi0*4ebOj$xF`kN119 zc@sd=@91Nty5!M*$2n?ltloH~SykuEV2DkJ^aiv#c7o+SigXahx9ZDwJMlf)jgsWC zAAW^z8@ka3pw=kEefz4Ln@#Ew(N%Hmmz7) z?Eha{*EKnEB*|4)W&zzZJu{poXUV-Kcc?Sd+sW)?ru+XtK=&f)RVG_V{EW=$ov*fBupA$SM$aj+a9wKtZx9ee%i;nIRFzF;CMf2@94t@SoSI^5S^ zJP%z(;`8FCWu1YD2*_M`XJ`{D=t7i&wrQ?OLr?;|{qhB%r+K|h%XwVFtWt(u+ru-F@00ES9a4>90U59sds;{lj^>j5B%*e!T2bF%xCyPf&9Ga6kU- zeq89`vRtN>8z4)dj-)MlUAMm8J@(Z7`KOOyVWDoC{WyC}>au#7BFZY3U8Ok56ZMpj z-FH7fKq|0i81z+EVOe?Id=jGUy;=OI0#Tv&qS~9GKZBfwn4g7!9s=YTsV`j-{jSnl z{fIV9vHVPnP%og1TqAlWijuu3@6rbP2w}Dhdz%CqA{4|9BC6kp7y+0HBwg!pmTQX_ zA03L%aG%KOwq}siulXqrXj)+vm2tzu+k~#nGMlhsNAp8_qiU;n+9}hIwXN$gYP$4- z)TW;UP_QU1KM6gD*}8o9RQh;gb?(9IMfUUhrmhyM_wBbyKS!|IEku%2gnAfg)6T}+ zoAmP&yKR7pTopg0M(t?B_4Y~1!PfY(6Q(h)4Y`%<(H=Re(7tMEniJkHb*AU))ZgEd zNtHL1J6NTSCtF*OlU>McEl15!hNFs~^iTybU4VAB1dzU$EU0c^TI~H8;X|X-cQ`Eq zK)nr2RII=9RASV;T;bSD+` zDSf?PRBot>m&YjSxhjHD@CV)pXODvf=y9aZR{0iaee+lm2oRD5?#;m-1{?WNxhLaH zf~xhd2w#z@X2#4xI05?2!G-%iF|V9Jya9JzF^2sjHsj;~4RUT%0BNiMd6o!Vk%Y%W zB8Gugl)2`+*hBe&yp30NxEHsF<6v)&_85}~QnwPV#xrmMF)b z)Eh9)V-~*8KQ)?|c*#f0ver~%2BQW-mR zxo_UwoyYmZX~K8b)z53c^j@~i^c`vm6__GGg$qViIsZ^>6pn z;!opxnbw(OgfRKoKo+05GDlS1y6=Aa2m)5>5N4eHyl?<4nv#S{M>Ph0LNV_9pYP!T z&a(R>42oD5j1zgEWv4i;PFwFWU0(`&a0ZD_!1aV3#)%4W53V3YN$IGB*`c9kuKpZb z3~~U+y0*rXS@PiwI;stal$mwc7dkx`W)hHR^To}1v_st3KX@$7MhEsGJEhNeVICELx)YIwzvqJr8d z)QF$a={rH^0Bp{1ed)QWH6V);?Z%*H(p=6TXv_=;;G2|wS4u4eNGA;U3eQa?bH(_> zU7SgvA@PIj2WKUKk)xiIq)VOFjC6mk2uTy@y#e%bumigrSEJFhFcjTZCYq_=?L=%Q zaBl{CKmh4*z^9zG{6M+1`bZU2ipb-H002e$HwSxjaN%BB8zG`)`rry0T8ZmU5rrkk zi6i}^Lky&kYGUo)0MWn_WMh2TbB4*yqapzO6L}IJmrvcxX9pyHdtiQg;hoKy@x?;% zT^|H6j82*B!~#B~jA=He;J$cudl)c3jE*nD@t4(`mDWIykwFXrcqkJbX`yNlU8DQ@ z%^iyJZ(aB8vQosD*g1vz5VhfvL2`9JmTbs-usnAh|mTT zst3RH~@Ge@hYmS1%}0^t+Jw8YMc}K(?K(=Bc^ebl--jd1k}|B4{>% z96nZ3zD$od05>*%H7!uKS(Ui9%r@ujHoFao6~qT7sYCu!PB!~+S9w_ry5WaP06vn@ zSE;FfCS%kNypw*tlU6H?lwfiotrVo^zeeAtUyW%cVkQc6SJjg2t1MayR-yS zvLvqqzycIeD$fSJnxtI0?m;Rd*MZNC8W}YJ&EV%w)amn!(*ZyQm8(n^+i~!*RuwWG z*^;U4v8e(CcZ8jlGr8NoYjI>wI|B1NzRh1VYQ5r++MZ8m`*70>eB)q`_crsC$ImtC z2WX2JfbL7%3&U|GIS5|)8jFefQeCgn=?}IaTpucs^kuTz9AhlC+odQ{&7mA1i}Y^~?&iSh2Y3eZJk{RwJ6{On z!71yY_q^L#7kt~je0JpYB~0H(PS}=>@7Auv6OZpvlqkw8nuat%#!K9~a_8QBb{l$& z+>!XQ`gQe7hs=BC!(+hIn1|JErL9ER9`5TmF9I#=x=zbF&1N#eGChX`Vvs+boYI3w z!6m@kFJA%rGA*ZZ?k~Vwy!R^$QP=xU*pK`)SlgQ&y^;#1B2PP0(4cfB5&0^GfG=y^PDe@Qfmc%x6@Ht|&pb7wM@A zzWeC|Mg~8eJx#OcI&g|6L{+Grmejj^K2n#xyRoNn8D~FXgjP(EmtCV(xXLGG7i)kj z``S6|&>NsH9y?3{mv2NZq#r>%5>JvaHEF9zI{`2xoU#v~9bbvVtUiiTk?X`*X-h?2 zRa$1!;(sl_XZcLIQ)LEJ(l6}Ol}ePI*!;buhnPG7UN7s2K`BRgBz#AjwBz zu(obWjb8!D_Ix_qTb$yZy&BzSck6D`_Moo>wD*V4j_?YBTP+4-UQl-q1qci zN)&Oj##+SS6BYEe@vC;4fW{w^k-uX9TcYA{0^K=#aQ)z{v&KsHCfk43iIR1En=7Ji z5wSOtDQGz$z+eYZ#2q%dPp#6a2-Faz*vl+2*MI~1@!*bw4GoC7C%I;a?usiYm5s2p z*NGS)fZiM&&cguoUZV%Y@dEENdZ}i=2pu5c+S?=2cY}@S$t-b)KX6D%&#AIrQx=SB zP2(xxwI%oR`4L6j92p(iOTOaC#v3nR=Lq2AH91YJ&i(%Nb2Jtweu1Rd z)i0|zYXIaqq@W!P$>R{1FqOZD@+d{Dmfn5+`2nwNE&`3wzUijq_WiK38iw#+bP^VXA7VK|jJPaerK_E~Ldhn;AHTReU8Z**jrV?D{M4_u@A|$o zt0EjRbXFkG_UA$|l?#zY%al(XSs) z=gWc~pvf2^A2+Hi>!}@tesfUwZ$E!PS1+?akIS^In9;Q?Z4vq>QR&Lp+;=~|hd5)( zG5XWuLmdbiL?S5~+)JXMT+ezfOlnPwiLSt?j~lW`E2f;g-kxkq#b@M;`nZ-Bmd z>@aVDpa-?!7~$|qBa5~LQPc5~*tG#Lc=O7-1{AOqWlktc*G~7GHl3zNS+c@Fra7_^ za6_wAGrH^pH8Iq5Sj)AIjuF+24@Qr;U6%gxHo9ZthZH}%6-a;xZBiCHmeSlLXwv=N zBg+=x;Lt`*bTQ$WV?fVt8Q;_*p!rDwb`H~M2dN<~VX7&js}#i=qQ(WSD+dT9-ON&u zeoH!!+!Jalh+#}&jdWM4TzAlGkE<(4kQrP>+11ySpjN9gQ2Eog2O)@9n0lv2tX+V* ztQH-IYkJEBndHUs3_nP%Q3#Y~POSldUoD8rE5O>mw`^@aG%A=|akLt#nIuy4s*}(G zfNLOr&N8}9@J%yFQS(#`Dii^x$0@jS;y?wR9$AHt59H@2r~oCe77wp)_Uj3z6+6Z&}Wl%GmA{5l0dU54Im%3?S(%bOoB_s8c4FW2g;@&pAy{0qPHfJq`|G z*n>=%)D3P?z38Hk7l9{{@nNtx2ZtDgq#t>dZ~AP@a^q9ljZ<%_i_?8PaMrkn0AYB- zuYzUz1WICXm6AVM1a08sKTPLd-Q64p zP9N{a5v{{1Wb9(2#kGEM6^$C>wJaGEe@2{V9HP3G`s&dy%e*eDOn4mZD<1ZD9`2WS_vdjvkJCJZ zB(xx`6K!o>`IWNwz4)ZA?k_*R$HY&Izf9}I#qb8m_QtKPA!rM^S6+GMzW?bR^bPa_ zab9q8j8sMzq96u)SWmHMZ-$<8U;MoK87t;JI$wN}-iZwrI2;!D8$dX>AftB;JKX6rf^6)0kZFV2X)0uG`I+EwmsOix>~sO zHP@scj1&58RSi4iC(e&#gGn1@*3quTT1_ro((kS92gg@bU~6Ie}Eq-n*GKXPAw{*ouB=TFzw&&#?j0S9Rt>dCAO zA7BD6CT(%Hzyq+%eG%tvDGi)*iuJ}?6ATbuCu*<6Y*ul;S^i>jG)d}d8pCuvfvXDj-*z&Xq#ox8K z26X%gocNHnJkk9QnAd@+r6yN^f1f{1lbLZ~l4bdWUlomP#yfadvb1u25b#<-hVd8^QOzmgVH1xV;IO#O>?o2ad+1x|;n zWhBf#+(Q670mC1?O%U9sgX5Hs+kXcxWJu*o&nWL;NS-Fscs9qc3pq z1?PHkhvfa~3#4|T7;5Z4HN&clh`;B=tsNYnPT>2z)@tMOUyjjkbWzo!Zk#?ahru2O zH-!9+QjMZ_NrLtSgRT@|0y)41dJGV_7b*)hRWY*K-|(kpmJOYQOCj)wsOgddZa zB8fI_jDeaW>c3Kh8zk%7}g{esx&kJXY$eOf6Tq6n%K&H&S@)iVm4(!3* z-W+hv=wg`yj~6Vnk1j!RNH->|;dy4uNAC5jyCc{?U_N_J*ZXz#%j)I#oH{BnVa81| zJU!$(ZL?#Z?hkKX3-4_A%d*bPGMhDZ62Lg*lJ+R@l39xX-7Y*oaew-U&(XnYp2umv zj1wb+pB~H@?@h7?ic%|UYid!;tJ_A9_wJjoJ_qi{httRVj>%cp#hQLKVbQ|4#w)4Z zyN&u?IoubopMSjX*JT;U$pKmf&SViXRS!SysJ`6~);QKUS-F^WtXpMin%7T1+{44^ zd>Q9?UO^C!dQFRgeF`0WUvhu_`ImX|r^`Gd3dYl~J}+>vdwHQIQuydoD)|0~zkzjZ z)wK9&UJy(wDVmVoCCbj$7q`LHVef8-Gt!^eiI)J)UQtGfvC2vZ!STxIsiy8KeG-_} zf1CgdYIuPIx-eDh2$e*Q)PDF0hsFQ03hzFitDNy|=!cTg-FC*PbS1zVF*?sDFEao6 ztkUrs($8^XF;t;e?w~m0&~x%!9Uvu9n2;9f0rH-dH|*J`5XNncq$MnWknbbZt)e7(jhGte9u7j7@iu zACrkYgLj5wsApY%S8`)e+dFHWiv{!=J_{(R$!X@5ntA0Hm$L^NaG~BfCH;tBt22f9 zk{3x^TYPΠ(>?JrX|*Zg6-F1eyGcMvEi#fZQ4Va2STch5}3yzT}qK z5VBvBT4~zdJ1#Jgfy9r;;fMgv33^)Nq}x@DRDr5wQ$!jkG!(9Bfqrv593}sN&Oc2? z0Y~=rh#E@l85yIko25q%S%aM0o8u98pkL6%LD_7)V0)v5$wVa#6BZISx&2kEIlznO z&wzY`{0Al{qRzdu4Pph-ZUmlfxN zDMA!V#pLX>sA^z(+_*b?dmPT3`y%K#B!E!m!!_!sR>@CEK7Ik>(@hM^Spzqt2daFf zp=Abw?UVB1hQA!&;(JS=odu2rJwp53^5Ouomege0bcC8JEM5{y7#HRws;Q(cpN63- z_DMC`BSUVJMRh?5N}frMipfw_L5xVdt5bSq)zfV8We;+5)7y}InOV{{v=fbN)p8M_ z_@(59jq#>QstkEMwYfi5sbLbeu9^GN&HSf~c$+@yFt%YR2wgQ6RAxmNki*io^yO0b zKq?5v81$3Wkd%>8S*uDn=~G>SN&k_n(stU8H&w~E=%nJ?dc1-YM61bFZFNR3*$%qO z$2PW?xe8Itbt%(NTXYq~=;UE&P*!K-(eojtm zXF2VZu9l@!*LqWgB2M4*Ky@4-<}cZs1TD3Ki##_{T6muLDOBr;aDr~o+2Jr8@sBF3 zP3THTlfC42rYVl>OPJV$colhepc;G}hT-OTI3ABE0FBN~_37XH)Y?W23VIy$P@XiI zKLjgG%kAy$v)h}4q#r&Hu=t^eA$gPuW5RD*Q#PfDmYhh@vuC%*=6HK^i#iyP?S5VG->s3RzU$$kUNl5X z5S%vM^j?*5!;D>^$cs{N>amZefJ8P@!&_>~P9wm7{>N`G(%~-CV&0Muin4^fX}CCx?IM%!+n7d%?ujeu+kO%xf;mbJ-Y=t2bPCE!J1k< zwd7vS^xDy%&ZlV{(OL|q41ZEEb?mzCCm!yHAO3p2jQ95sm&=4On0|~7k53W^C0*3m z<~HWeqW$mx^Jk1LrU(rf#|dMK9gr!aQcfwUa`o;LDno$pSs|PQ2<8V>;D{k|kRs1j z`bqw-!n5fQg9Sy?v;cV)bl~$JYXzF3ODS@{!x!z_HN>X_FRO5mD+BZ4Qw=`oUL9eF z6siq7KefzEU__9j%*i#R?@JZQECX5jrfqu_lmmpBiNEGB;V+I-Kra!x<}5?K+X~xC zZlWUMR`lfbsZL)l4wVK_4v-GLz!}XeVsxA){bc$DIfl2j9*FXo_{(}g<3dpNTBm=F zq6%LXl4r6EPnp!T-lWnm*F2`ADv;!32$Sn93)R&*mr#4SWzj0pG)b3DrJ;=iD!yX{ zwJw#$@E&xVF2@j6%iH-*)aV%`-QrwL6(E3zzwknv)vu+ftEWgsOM!MO=#+;kzoESt z)$%^-87SCP$CzCIoDFFhyq%Rdn`UO3L2N~&#Vw%*9Iz)JYiwo$$3g}1qM;U-Oy~&IQ zwZoycl2(am-FRvKAp_@ z%!tAF`xSllea6p0@|aK@c+-#+OL715FaHhD4-XITiihN{MSBqA0 z-sz`Y!GHbdfByB|yB~l25s#*6x{R06jk3jk!H&EXMGvQ>-|3;LyUows+qZ8I$0L|| z|L#3x!dc!76V_NI9Y#MFu$%1e(OVH6MiieZa$S_xJo5X!qx!!4>kmKt?U!F3?(fHO z#B5?lWqCb-=kw`uxnLD^j1(pp)7mKQx^_D3tIu9yI!~w5nUBk594DL-M5Yy-`EXGA zqsqXth0;!KY%-^Z(}dlXW0vaz{CSam-~b`W2EO&+0#4=M;)0yP2}>I*P|zVseu?OD zu}klZ4d)llj(!XFNf`G5#77mCcye0^((t(ukmR>oD(z3xHm!V~yps}+onS3Dp^qU`#~{9}yj+`;ea09o#{*Vojy zM~zMDKg5tJ(&=YulOS9phW>OkqH%b(>Iv^^*c#S0bDDKk@m@|9EtD*c9{rij*LBL)@yX~XPY_bSLQ+Ocx( gO~?$jgU;Xj|0TRaItRG5a{vGU07*qoM6N<$g748%R{#J2 literal 0 HcmV?d00001 diff --git a/resources/textures/M_GI.png b/resources/textures/M_GI.png new file mode 100644 index 0000000000000000000000000000000000000000..c87a2f130f4d9cef3f4a32985ff3b509575d7f57 GIT binary patch literal 2161 zcmV-%2#)uOP)000O$Nkl8C2qDBHVgo!Ou>mC3#twL34?M8}1PcH)w4kSFl8Iy2 zq3(6+YNwMKr{Z?oj{V)vIg~UvYCcrnM$Kjp^eO+L_~z)>=?3;2{-js4`^vYvE3ibs zA~pxia>&pl=nD@-prC~9SPsA!46uki4Ffi^#yPMSy0=Slpb0kW;i@a)Dy?v!t+zUO za$`6}=GglXc$S`4lN4QrMw}LX;L9~&RYB-2bZQ~fmi&>V@*5*E_5v+(Xer;Qv$TAT z{J{r@9?QQJA!w*t_hFR@bpjTwgU;lC%$z|Ed`M^WJr8w524 z+9uGJ{A%lH;83nzC`8>ujX0E$!@3|r`L3LRX*JBFXB~46xaL!?S`2ADhto})ZtM_ph$wX6Mj$SKYR7gCQW3-VMCp z$j@-m^#jrA*OC&U^;Sy=bAq^<&^^qPFx*UnOiimDemxFQGdm5?=_PK4@6h#^!^OqL zB_A#*??Iub!o~!I5Q>N#2>0G&k0)d*i4dckt6}r}>h|j9 zw%c5aj?X|RA?8`al}gW`U=!DKwlmot zW-%TF8KwA)feI2ZJ<1FR2b*}v6!oJ9#E9^T8-5D^_VZ8oFE0NWhPzSB+wrh_bAUJ0 z#77o@TxuE!9U3J(wLDy;3htj%;Kc{>@4o)xr-|(U-oLzm^?k*$k!q-E_7`Smwn_P@PkzueK?9g!L0Bk4vBoms>NeF62^m43>`fB5K= z`@7#?ZVr3?YNmsr97ty(uOU*0n8pRV)H=>4@e+aWf4%`PJLlJl-N)1RFLHPwhsSw* zJ&(J2QUt_&5c33zgF&yBhAWIEW(Yeb9{#x)tbI;L4!1D=17b_W7N#8_^x6Tb{_N4K z1LA^Z^^c%CU*280bVM+iw*Y$rBN1xBJUZWP$w^iw`oSFGcD1} zu{Beeh)^q_R}R?xfOEjaM}HM?D7+7U@!9h?0z+U@(#qaW1tl|)dMorkJTr+nfKR;z zV@a^{*Qqn2c1qObQJJop;+970u;-w(|*73>Q{AP@*A^zfB4 z)?^)_Hw9q#Haa>zkjU?i@nr$$o@9_Y5H>0qsF`axSY2KD8sSC2ZLUW0=lMY)fwwX( zy5xVVH^srtEFT-EMSgQvv{6L8=y0aXuSW?34I^FpwKGdCk?g?_X4{y;VD>H4P7Ul2B;S0 znLqAiJ|p?tZ{luj^+ueZVjOS6tO%f?6B z!*Co3f(~ht(2572FZ3ebMtJJ?H5{-M5ISK2IS$SNQgNU(iBLsks46g<+%fVttaZY+`gd0I$M!zOJ=6|-t5SidwrSC!{ nt_m~+imL=YEt1$DST^KelQw$~{8fIP00000NkvXXu0mjfii8t& literal 0 HcmV?d00001 diff --git a/src/graphics/device.cpp b/src/graphics/device.cpp index e224447..cd37d03 100644 --- a/src/graphics/device.cpp +++ b/src/graphics/device.cpp @@ -159,6 +159,12 @@ Image Device::create_image(Extent3D extent, ImageConfig config, bool useMipmaps, useMipmaps ? static_cast(std::floor(std::log2(std::max(extent.width, extent.height)))) + 1 : 1; img.layers = config.viewType == TextureType::TEXTURE_CUBE ? CUBEMAP_FACES : config.layers; + VkImageType imageType = VK_IMAGE_TYPE_2D; + if (config.viewType == TextureType::TEXTURE_3D) + imageType = VK_IMAGE_TYPE_3D; + if (config.viewType == TextureType::TEXTURE_1D || config.viewType == TextureType::TEXTURE_1D_ARRAY) + imageType = VK_IMAGE_TYPE_1D; + VkImageCreateInfo img_info = Init::image_create_info(Translator::get(config.format), config.usageFlags, @@ -166,6 +172,7 @@ Image Device::create_image(Extent3D extent, ImageConfig config, bool useMipmaps, img.mipLevels, static_cast(config.samples), img.layers, + imageType, config.viewType == TextureType::TEXTURE_CUBE ? VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT : 0); VK_CHECK(vmaCreateImage(m_allocator, &img_info, &img_allocinfo, &img.handle, &img.allocation, nullptr)); @@ -501,7 +508,7 @@ void Device::upload_texture_image(Image& img, config.usageFlags = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT; config.samples = 1; config.aspectFlags = VK_IMAGE_ASPECT_COLOR_BIT; - img = create_image(img.extent, config, mipmapping); + img = create_image(img.extent, config, mipmapping); img.create_view(config); VkDeviceSize imageSize = img.extent.width * img.extent.height * img.extent.depth * bytesPerPixel; @@ -759,10 +766,10 @@ void Device::wait() { VK_CHECK(vkDeviceWaitIdle(m_handle)); } -void Device::init_imgui(void* windowHandle, - WindowingSystem windowingSystem, - VulkanRenderPass renderPass, - uint16_t samples) { +void Device::init_imgui(void* windowHandle, + WindowingSystem windowingSystem, + VulkanRenderPass renderPass, + uint16_t samples) { m_guiPool = create_descriptor_pool(1000, 1000, diff --git a/src/graphics/utilities/initializers.cpp b/src/graphics/utilities/initializers.cpp index 034727a..7a3b0d1 100644 --- a/src/graphics/utilities/initializers.cpp +++ b/src/graphics/utilities/initializers.cpp @@ -280,6 +280,7 @@ VkImageCreateInfo Init::image_create_info(VkFormat format, uint32_t mipLevels, VkSampleCountFlagBits samples, uint32_t layers, + VkImageType type, VkImageCreateFlags flags) { VkImageCreateInfo info = {}; @@ -287,7 +288,7 @@ VkImageCreateInfo Init::image_create_info(VkFormat format, info.pNext = nullptr; info.flags = flags; - info.imageType = VK_IMAGE_TYPE_2D; + info.imageType = type; info.format = format; info.extent = extent; diff --git a/src/tools/loaders.cpp b/src/tools/loaders.cpp index 1c73028..d7c7d5d 100644 --- a/src/tools/loaders.cpp +++ b/src/tools/loaders.cpp @@ -732,7 +732,7 @@ void VKFW::Tools::Loaders::load_PNG(Core::Texture* const texture, if (imgCache) { texture->set_image_cache(imgCache, {static_cast(w), static_cast(h), 1}, 4); - // Set automatically teh best format for each type. + // Set automatically teh optimal format for each type. // User can override it after, I he need some other more specific format ... switch (textureFormat) { @@ -777,9 +777,50 @@ void VKFW::Tools::Loaders::load_HDRi(Core::TextureHDR* const texture, const std: DEBUG_LOG("HDRi Texture loaded successfully"); #endif // DEBUG } - +void VKFW::Tools::Loaders::load_3D_texture(Core::ITexture* const texture, + const std::string fileName, + uint16_t depth, + TextureFormatType textureFormat) { + int w, h, ch; + unsigned char* imgCache = nullptr; + imgCache = stbi_load(fileName.c_str(), &w, &h, &ch, STBI_rgb_alpha); + if (imgCache) + { + texture->set_type(TextureType::TEXTURE_3D); + int largerSide = w > h ? w : h; + int shorterSide = w > h ? h : w; + uint16_t finalDepth = depth == 0 ? largerSide / shorterSide : depth; + texture->set_image_cache( + imgCache, + {static_cast(shorterSide), static_cast(largerSide / finalDepth), finalDepth}, + 4); + // Set automatically the optimal format for each type. + // User can override it after, I he need some other more specific format ... + switch (textureFormat) + { + case TextureFormatType::COLOR_FORMAT: + texture->set_format(SRGBA_8); + break; + case TextureFormatType::NORMAL_FORMAT: + texture->set_format(RGBA_8U); + break; + case TextureFormatType::HDR_FORMAT: + texture->set_format(SRGBA_16F); + break; + } + } else + { +#ifndef NDEBUG + DEBUG_LOG("Failed to load texture PNG file" + fileName); +#endif + return; + }; +#ifndef NDEBUG + DEBUG_LOG("PNG Texture loaded successfully"); +#endif // DEBUG +} void VKFW::Tools::Loaders::compute_tangents_gram_smidt(std::vector& vertices, - const std::vector& indices) { + const std::vector& indices) { if (!indices.empty()) for (size_t i = 0; i < indices.size(); i += 3) { @@ -788,12 +829,12 @@ void VKFW::Tools::Loaders::compute_tangents_gram_smidt(std::vector