From 8cc844e9ea2c587e5cf88cfe30865da23b6b379d Mon Sep 17 00:00:00 2001 From: Timur Gagiev Date: Sun, 1 Nov 2020 10:56:17 +0300 Subject: [PATCH] Xbox One port (UWP) --- src/cache.h | 8 +- src/core.h | 18 +- src/gapi/d3d11.h | 17 +- src/inventory.h | 76 +-- src/level.h | 28 +- src/libs/tinf/tinflate.c | 2 +- .../xb1/Assets/LargeTile.scale-200.png | Bin 0 -> 11210 bytes .../xb1/Assets/SmallTile.scale-200.png | Bin 0 -> 2296 bytes .../xb1/Assets/SplashScreen.scale-200.png | Bin 0 -> 11991 bytes .../Assets/Square150x150Logo.scale-200.png | Bin 0 -> 5198 bytes ...x44Logo.altform-unplated_targetsize-48.png | Bin 0 -> 706 bytes .../xb1/Assets/Square44x44Logo.scale-200.png | Bin 0 -> 1519 bytes .../Assets/Square44x44Logo.targetsize-48.png | Bin 0 -> 706 bytes .../xb1/Assets/StoreLogo.scale-200.png | Bin 0 -> 1589 bytes .../xb1/Assets/Wide310x150Logo.scale-200.png | Bin 0 -> 5645 bytes src/platform/xb1/OpenLara.sln | 51 ++ src/platform/xb1/OpenLara.vcxproj | 332 ++++++++++++ src/platform/xb1/OpenLara.vcxproj.filters | 103 ++++ src/platform/xb1/OpenLara.vcxproj.user | 23 + src/platform/xb1/OpenLara_TemporaryKey.pfx | Bin 0 -> 2512 bytes src/platform/xb1/Package.StoreAssociation.xml | 371 +++++++++++++ src/platform/xb1/Package.appxmanifest | 33 ++ src/platform/xb1/main.cpp | 503 ++++++++++++++++++ src/shader.h | 2 +- src/shaders/common.hlsl | 13 +- src/shaders/compile_d3d11.bat | 4 + src/shaders/sky.hlsl | 116 ++++ src/shaders/water_compose.hlsl | 4 +- src/shaders/water_rays.hlsl | 6 +- src/sound.h | 2 +- src/utils.h | 239 ++++++++- 31 files changed, 1868 insertions(+), 83 deletions(-) create mode 100644 src/platform/xb1/Assets/LargeTile.scale-200.png create mode 100644 src/platform/xb1/Assets/SmallTile.scale-200.png create mode 100644 src/platform/xb1/Assets/SplashScreen.scale-200.png create mode 100644 src/platform/xb1/Assets/Square150x150Logo.scale-200.png create mode 100644 src/platform/xb1/Assets/Square44x44Logo.altform-unplated_targetsize-48.png create mode 100644 src/platform/xb1/Assets/Square44x44Logo.scale-200.png create mode 100644 src/platform/xb1/Assets/Square44x44Logo.targetsize-48.png create mode 100644 src/platform/xb1/Assets/StoreLogo.scale-200.png create mode 100644 src/platform/xb1/Assets/Wide310x150Logo.scale-200.png create mode 100644 src/platform/xb1/OpenLara.sln create mode 100644 src/platform/xb1/OpenLara.vcxproj create mode 100644 src/platform/xb1/OpenLara.vcxproj.filters create mode 100644 src/platform/xb1/OpenLara.vcxproj.user create mode 100644 src/platform/xb1/OpenLara_TemporaryKey.pfx create mode 100644 src/platform/xb1/Package.StoreAssociation.xml create mode 100644 src/platform/xb1/Package.appxmanifest create mode 100644 src/platform/xb1/main.cpp create mode 100644 src/shaders/sky.hlsl diff --git a/src/cache.h b/src/cache.h index 6605252..5a6721f 100644 --- a/src/cache.h +++ b/src/cache.h @@ -12,6 +12,10 @@ #define USE_SCREEN_TEX #endif +#if defined(_GAPI_D3D8) || defined(_GAPI_D3D9) || defined(_GAPI_D3D11) + #define EARLY_CLEAR +#endif + struct ShaderCache { enum Effect { FX_NONE = 0, FX_UNDERWATER = 1, FX_ALPHA_TEST = 2 }; @@ -86,8 +90,8 @@ struct ShaderCache { void prepareSky(int fx) { compile(Core::passSky, Shader::DEFAULT, fx, rsBase); if (Core::support.tex3D) { - compile(Core::passSky, Shader::SKY_CLOUDS, fx, rsBase); - compile(Core::passSky, Shader::SKY_CLOUDS_AZURE, fx, rsBase); + compile(Core::passSky, Shader::SKY_CLOUDS, fx, rsBase); + compile(Core::passSky, Shader::SKY_AZURE, fx, rsBase); } } diff --git a/src/core.h b/src/core.h index 621e639..adba0a4 100644 --- a/src/core.h +++ b/src/core.h @@ -13,7 +13,16 @@ #define USE_CUBEMAP_MIPS -#ifdef WIN32 +#ifdef __UWP__ + #define _OS_UWP 1 + #define _GAPI_D3D11 1 + + #ifdef __XB1__ + #define _OS_XB1 + #endif + + #undef OS_PTHREAD_MT +#elif WIN32 #define _OS_WIN 1 #define _GAPI_GL 1 //#define _GAPI_D3D9 1 @@ -137,6 +146,12 @@ #define NOMINMAX #include #include +#elif _X360 + #define _OS_X360 1 + // TODO +#elif _XB1 + #define _OS_XB1 1 + #define _GAPI_D3D11 1 #endif #ifndef _OS_PSP @@ -1014,6 +1029,7 @@ namespace Core { GAPI::deinit(); NAPI::deinit(); Sound::deinit(); + Stream::deinit(); } void setVSync(bool enable) { diff --git a/src/gapi/d3d11.h b/src/gapi/d3d11.h index 801a7e1..bb2426e 100644 --- a/src/gapi/d3d11.h +++ b/src/gapi/d3d11.h @@ -37,7 +37,11 @@ extern ID3D11Device *device; extern ID3D11DeviceContext *deviceContext; +#ifdef _OS_XB1 +extern IDXGISwapChain1 *swapChain; +#else extern IDXGISwapChain *swapChain; +#endif namespace GAPI { using namespace Core; @@ -134,7 +138,7 @@ namespace GAPI { #define SHADER_U(S,P) (underwater ? SHADER(S##_u,P) : SHADER(S,P)) #define SHADER_AU(S,P) ((underwater && alphatest) ? SHADER(S##_au,P) : (alphatest ? SHADER(S##_a,P) : SHADER_U(S,P))) - const uint8 *vSrc, *fSrc; + const uint8 *vSrc = NULL, *fSrc = NULL; switch (pass) { case passCompose : switch (type) { @@ -161,7 +165,14 @@ namespace GAPI { default : ASSERT(false); } break; - case passSky : SHADER ( gui, v ); SHADER ( gui, f ); break; // TODO + case passSky : + switch (type) { + case 0 : SHADER ( sky, v ); SHADER ( sky, f ); break; + case 1 : SHADER ( sky_clouds, v ); SHADER ( sky_clouds, f ); break; + case 2 : SHADER ( sky_azure, v ); SHADER ( sky_azure, f ); break; + default : ASSERT(false); + } + break; case passWater : switch (type) { case 0 : SHADER ( water_drop, v ); SHADER ( water_drop, f ); break; @@ -179,7 +190,7 @@ namespace GAPI { case 1 : SHADER ( filter_downsample, v ); SHADER ( filter_downsample, f ); break; case 3 : SHADER ( filter_grayscale, v ); SHADER ( filter_grayscale, f ); break; case 4 : SHADER ( filter_blur, v ); SHADER ( filter_blur, f ); break; - case 5 : SHADER ( filter_anaglyph, v ); SHADER ( filter_anaglyph, f ); break; // TODO anaglyph + case 5 : SHADER ( filter_anaglyph, v ); SHADER ( filter_anaglyph, f ); break; default : ASSERT(false); } break; diff --git a/src/inventory.h b/src/inventory.h index 7debb50..c9a12f9 100644 --- a/src/inventory.h +++ b/src/inventory.h @@ -82,8 +82,10 @@ struct OptionItem { int maxWidth = UI::getTextSize(STR[color + value]).x; maxWidth = maxWidth / 2 + 8; x += w * 0.5f; - if (checkValue(value - 1)) UI::specOut(vec2(x - maxWidth - 16.0f, y), 108); - if (checkValue(value + 1)) UI::specOut(vec2(x + maxWidth, y), 109); + if (maxValue != 0xFF) { + if (checkValue(value - 1)) UI::specOut(vec2(x - maxWidth - 16.0f, y), 108); + if (checkValue(value + 1)) UI::specOut(vec2(x + maxWidth, y), 109); + } } return y + LINE_HEIGHT; } @@ -123,23 +125,51 @@ struct OptionItem { } }; -#define SETTINGS(x) OFFSETOF(Core::Settings, x) +#define SETTINGS(x) int32(OFFSETOF(Core::Settings, x)) + +#if defined(_OS_PSP) || defined(_OS_PSV) || defined(_OS_3DS) || defined(_OS_GCW0) || defined(_OS_CLOVER) || defined(_OS_PSC) || defined(_OS_XBOX) || defined(_OS_XB1) + #define INV_GAMEPAD_ONLY +#else + #define INV_QUALITY +#endif + +#if !(defined(_OS_PSP) || defined(_OS_PSV) || defined(_OS_3DS) || defined(_OS_GCW0) || defined(_OS_XBOX) || defined(_OS_XB1)) + #define INV_STEREO +#endif + +#if defined(_OS_PSP) || defined(_OS_PSV) || defined(_OS_3DS) || defined(_OS_GCW0) + #define INV_SINGLE_PLAYER +#endif + +#if defined(_OS_PSP) || defined(_OS_PSV) || defined(_OS_3DS) || defined(_OS_CLOVER) || defined(_OS_XBOX) + #define INV_GAMEPAD_NO_TRIGGER +#endif + +#ifdef INV_SINGLE_PLAYER + #define INV_CTRL_START_OPTION 1 +#else + #define INV_CTRL_START_OPTION 2 +#endif + +#if defined(_OS_WIN) || defined(_OS_LINUX) || defined(_OS_RPI) || defined(_OS_GCW0) || defined(_OS_XBOX) || defined(_OS_XB1) + #define INV_VIBRATION +#endif static const OptionItem optDetail[] = { OptionItem( OptionItem::TYPE_TITLE, STR_SELECT_DETAIL ), OptionItem( ), +#ifdef INV_QUALITY OptionItem( OptionItem::TYPE_PARAM, STR_OPT_DETAIL_FILTER, SETTINGS( detail.filter ), STR_QUALITY_LOW, 0, 2 ), OptionItem( OptionItem::TYPE_PARAM, STR_OPT_DETAIL_LIGHTING, SETTINGS( detail.lighting ), STR_QUALITY_LOW, 0, 2 ), OptionItem( OptionItem::TYPE_PARAM, STR_OPT_DETAIL_SHADOWS, SETTINGS( detail.shadows ), STR_QUALITY_LOW, 0, 2 ), OptionItem( OptionItem::TYPE_PARAM, STR_OPT_DETAIL_WATER, SETTINGS( detail.water ), STR_QUALITY_LOW, 0, 2 ), - OptionItem( OptionItem::TYPE_PARAM, STR_OPT_SIMPLE_ITEMS, SETTINGS( detail.simple ), STR_OFF, 0, 1 ), -#if !defined(_OS_3DS) && !defined(_OS_GCW0) - OptionItem( OptionItem::TYPE_PARAM, STR_OPT_RESOLUTION, SETTINGS( detail.scale ), STR_SCALE_100, 0, 3 ), #endif -#if defined(_OS_WIN) || defined(_OS_LINUX) || defined(_OS_PSP) || defined(_OS_RPI) || defined(_OS_PSV) + OptionItem( OptionItem::TYPE_PARAM, STR_OPT_SIMPLE_ITEMS, SETTINGS( detail.simple ), STR_OFF, 0, 1 ), +#ifdef INV_QUALITY + OptionItem( OptionItem::TYPE_PARAM, STR_OPT_RESOLUTION, SETTINGS( detail.scale ), STR_SCALE_100, 0, 3 ), OptionItem( OptionItem::TYPE_PARAM, STR_OPT_DETAIL_VSYNC, SETTINGS( detail.vsync ), STR_OFF, 0, 1 ), #endif -#if !defined(_OS_PSP) && !defined(_OS_PSV) && !defined(_OS_3DS) && !defined(_OS_GCW0) +#ifdef INV_STEREO OptionItem( OptionItem::TYPE_PARAM, STR_OPT_DETAIL_STEREO, SETTINGS( detail.stereo ), STR_NO_STEREO, 0, #if defined(_OS_WIN) || defined(_OS_ANDROID) 4 /* with VR option */ @@ -164,28 +194,6 @@ static const OptionItem optSound[] = { #endif }; -#if defined(_OS_PSP) || defined(_OS_PSV) || defined(_OS_3DS) || defined(_OS_GCW0) || defined(_OS_CLOVER) || defined(_OS_PSC) || defined(_OS_XBOX) - #define INV_GAMEPAD_ONLY -#endif - -#if defined(_OS_PSP) || defined(_OS_PSV) || defined(_OS_3DS) || defined(_OS_GCW0) - #define INV_SINGLE_PLAYER -#endif - -#if defined(_OS_PSP) || defined(_OS_PSV) || defined(_OS_3DS) || defined(_OS_CLOVER) - #define INV_GAMEPAD_NO_TRIGGER -#endif - -#ifdef INV_SINGLE_PLAYER - #define INV_CTRL_START_OPTION 1 -#else - #define INV_CTRL_START_OPTION 2 -#endif - -#if defined(_OS_WIN) || defined(_OS_LINUX) || defined(_OS_RPI) || defined(_OS_GCW0) || defined(_OS_XBOX) - #define INV_VIBRATION -#endif - static const OptionItem optControls[] = { OptionItem( OptionItem::TYPE_TITLE, STR_SET_CONTROLS ), OptionItem( ), @@ -199,7 +207,7 @@ static const OptionItem optControls[] = { OptionItem( OptionItem::TYPE_PARAM, STR_OPT_CONTROLS_RETARGET , SETTINGS( controls[0].retarget ), STR_OFF, 0, 1 ), OptionItem( OptionItem::TYPE_PARAM, STR_OPT_CONTROLS_MULTIAIM , SETTINGS( controls[0].multiaim ), STR_OFF, 0, 1 ), #ifdef INV_GAMEPAD_ONLY - OptionItem( OptionItem::TYPE_PARAM, STR_EMPTY , SETTINGS( playerIndex ), STR_OPT_CONTROLS_GAMEPAD, 0, 0 ), + OptionItem( OptionItem::TYPE_PARAM, STR_EMPTY , SETTINGS( ctrlIndex ), STR_OPT_CONTROLS_KEYBOARD, 0, 0xFF ), #else OptionItem( OptionItem::TYPE_PARAM, STR_EMPTY , SETTINGS( ctrlIndex ), STR_OPT_CONTROLS_KEYBOARD, 0, 1 ), #endif @@ -499,14 +507,14 @@ struct Inventory { case cUp : nextSlot(slot, -1); break; case cDown : nextSlot(slot, +1); break; case cLeft : - if (opt->type == OptionItem::TYPE_PARAM && opt->checkValue(value - 1)) { + if (opt->type == OptionItem::TYPE_PARAM && (opt->maxValue != 0xFF) && opt->checkValue(value - 1)) { value--; timer = 0.2f; return opt; } break; case cRight : - if (opt->type == OptionItem::TYPE_PARAM && opt->checkValue(value + 1)) { + if (opt->type == OptionItem::TYPE_PARAM && (opt->maxValue != 0xFF) && opt->checkValue(value + 1)) { value++; timer = 0.2f; return opt; @@ -2090,7 +2098,7 @@ struct Inventory { const char *bSelect = STR[STR_KEY_FIRST + ikEnter]; const char *bBack = STR[STR_KEY_FIRST + Core::settings.controls[playerIndex].keys[cInventory].key]; - #if defined(_OS_SWITCH) || defined(_OS_3DS) || defined(_OS_GCW0) || defined(_OS_XBOX) + #if defined(_OS_SWITCH) || defined(_OS_3DS) || defined(_OS_GCW0) || defined(_OS_XBOX) || defined(_OS_XB1) bSelect = "A"; bBack = "B"; #endif diff --git a/src/level.h b/src/level.h index 64c5ba4..a7c02b4 100644 --- a/src/level.h +++ b/src/level.h @@ -1808,7 +1808,7 @@ struct Level : IGame { } void renderSky() { - #ifndef _GAPI_GL + #if !defined(_GAPI_GL) && !defined(_GAPI_D3D11) return; #endif ASSERT(mesh->transparent == 0); @@ -1819,7 +1819,7 @@ struct Level : IGame { if (level.version & TR::VER_TR1) { if (Core::settings.detail.lighting < Core::Settings::HIGH || !Core::support.tex3D || !TR::getSkyParams(level.id, skyParams)) return; - type = Shader::SKY_CLOUDS_AZURE; + type = Shader::SKY_AZURE; } else { // TR2, TR3 if (level.extra.sky == -1) return; @@ -1857,7 +1857,7 @@ struct Level : IGame { time = (time - int(time)) * SKY_TIME_PERIOD; } - Core::active.shader->setParam(uParam, vec4(skyParams.wind * time, 1.0)); + Core::active.shader->setParam(uParam, vec4(skyParams.wind * time * 2.0f, 1.0)); Core::active.shader->setParam(uLightProj, *(mat4*)&skyParams); Core::active.shader->setParam(uPosScale, skyParams.cloudDownColor, 2); @@ -2608,7 +2608,18 @@ struct Level : IGame { Texture *screen = NULL; if (water) { screen = (waterCache && waterCache->visible) ? waterCache->getScreenTex() : NULL; - Core::setTarget(screen, NULL, RT_CLEAR_COLOR | RT_CLEAR_DEPTH | RT_STORE_COLOR | (screen ? RT_STORE_DEPTH : 0)); // render to screen texture (FUCK YOU iOS!) or back buffer + + int clearFlags = RT_STORE_COLOR; + + if (screen) { + clearFlags |= RT_CLEAR_COLOR | RT_CLEAR_DEPTH | RT_STORE_DEPTH; + } + + #ifndef EARLY_CLEAR + clearFlags |= RT_CLEAR_COLOR | RT_CLEAR_DEPTH; + #endif + + Core::setTarget(screen, NULL, clearFlags); // render to screen texture or back buffer Core::validateRenderState(); setupBinding(); } @@ -2649,7 +2660,7 @@ struct Level : IGame { Core::Pass pass = Core::pass; if (water && waterCache && waterCache->visible && screen) { - Core::setTarget(NULL, NULL, RT_STORE_COLOR); + Core::setTarget(NULL, NULL, RT_CLEAR_DEPTH | RT_STORE_COLOR); Core::validateRenderState(); waterCache->blitTexture(screen); } @@ -3201,6 +3212,13 @@ struct Level : IGame { #endif } } + + #ifdef EARLY_CLEAR + if (view == 0 && eye <= 0) { + Core::setTarget(NULL, NULL, RT_CLEAR_COLOR | RT_CLEAR_DEPTH | RT_STORE_COLOR | RT_STORE_DEPTH); + Core::validateRenderState(); + } + #endif } void renderEye(int eye, bool showUI, bool invBG) { diff --git a/src/libs/tinf/tinflate.c b/src/libs/tinf/tinflate.c index b2bec56..8de5f73 100644 --- a/src/libs/tinf/tinflate.c +++ b/src/libs/tinf/tinflate.c @@ -303,7 +303,7 @@ static int tinf_inflate_block_data(TINF_DATA *d, TINF_TREE *lt, TINF_TREE *dt) /* check for end of block */ if (sym == 256) { - *d->destLen += d->dest - start; + *d->destLen += (unsigned int)(d->dest - start); return TINF_OK; } diff --git a/src/platform/xb1/Assets/LargeTile.scale-200.png b/src/platform/xb1/Assets/LargeTile.scale-200.png new file mode 100644 index 0000000000000000000000000000000000000000..6b8e2cb58d81da4ec9fffa88541443765dd3d7f8 GIT binary patch literal 11210 zcma)iWl$VW?=W&`aXlz{xVt;tA;pWk929qo75Q;E96g|g;uMDh=acH?xkRPb@BaZylE@YPhoZ&6UtT>rPR(O)S3>V%Xppi4(X zAMyfGQBl#+(E$Je4h{|;9v%S!0WmQ#85tQ62&AE*VPIfj0)bdqSlHOuI5|0acz6T_ z1;xa~WMpI%6cm(|mDSbNwY9bN^z@94jm^!?ZEbCxot-^BJ$-$BKYaKAgTdnB;t&W# zT3T9OUS45gVQFb;MMVV?iL9@$Z*6Vu?(XjE>-+WV*XZczyyC14T{z5C8vLUuitAjw>q?X%l~*JTa3p#PDO1L<5Ax@uK;othx6WpP#MX z=lRvN*kbQb^LjPpwQ_sket+96+-~ARfe-pawX=f0$1X-(XC0v1wX}a@R}nK$?*XD< zC8x3^s`2epT)8qrjkHcrWUv3xc$y!>@s4q0Q|8mI;>U6S-OGUc&RCP|NTJTt?X4M= zB_;W+ZoJlv3}$t|yT{4s{nIPLxIPq=tI&$DP%Blz^Cy|gM>(X3`9U3-R=`+M*z+AC zlqWVF)hqCR&s+ExJGsM#04&P!nZj21kcIxs#zS=qu7u?L-|iDRVu7~B*XC@JCU5<; z$lMt<6eAgF0>>=HSsWxi2%li<<6yjYAqqjUd=cF04_+b9-{d+Qo6onGK26_dm%a_g z?xBxM@6#*M&(_QCaY+gMU4L!H;zf!I3bUrrO1~lT4;qTP$QHCp4#bTZJQ#89>ix1k zC47xF)!3b9taK{MkC0W3-46|#I{W>ppv$(9pS_{ zfhZ=gw+_KO9T>4~+}3$QjWd~?+lW9Q*wXf9=rB9((^%Yy3^=x}3pucno%qj6`j272 zRgG?d4N>6ttZKRpCA{=SmlSYrtKE8K zc41U8aXZI9yl4(kG$B;dA+32i2z=K<1r8;z86KIpr<>oPRX;~~@W(!IT2H9CM$O6` z3drGqoAxmTMK?=P_}SvO?_7>&q>WCnk|4DlCwCB&{j4(8;rFM+eA7qYV#;u%OzGNP7MrR51#G&EgN zc|bNKDr|y$#5Lo+oo@9|(r`xeI^^rIQ!L@Uh3wZeA2oZCDf@@2JG{u{-YepxIWU@^ zOdVGSy6{12@LwQi^29>=(&!h_O4&!j218d+^zDnjEMD}+K}B+AlP~HXMdffT33ESW z_g{FGo7)w+x z7%!Uj3B5z$Q(SATV=R!Ol?IYAr{cQP`SycRn`#$giI}4M<^`lvJ8T?@#m)=eT4?ve84+ zbI>VU>!rcXW4-Nd+_+dLPzf&YrjxXFd$PVdDTf4~mAxJ`#rb$&)_QN^x$ z*;zor=>|0u(`wgL+xu9bceQbvy+qX}#yu?|P;c*LG%!lfoBTQ-EvudyHd=0`ORM>G zBhNuKSIp$hYS&Gci;QghKX{-^%lYg=h}6ke@WU%iVxS>O&a#gz_r`y}0-p&mi2;X# zb#Gn$2K56-ZHSy$mAU$&pL_jqfZ)HHa7mTd?cuv4K0vUwFv!y2njY3`<^A7WmyK21osq0E>k=yEmEeV0D%C(B~6PKZh+Tj^b)CFQdw>WkJMA&1sQ zC9~zSi=u*LXW>WG!%=Zqu`ee_nKc$RIk`Vv;x&nChI`)#c0v=1B@C6x7A;5Tc->}6 zr%CV%=1z*8UFWU^{_WVjh*XO}UoS8Yv_)bQ)mVv$;)(Bw0b;=y?Y6GF;@1NA6pSQZ zIzo*?=3XNf;8*|+e@#j+>5_m?4;mPaz@=Xln{aEB1P_F&A_Bda%o}W_d%*{CO=8Zy zaE1qH6pN1iDBtBWY;<8^6FIquRu+1`k_q1IfW$JaMK&*FBCvaKnur--|4p0L*oQ(; zDAINr&=}S#-@1O6F*q|U9kQciLg5#RMd3H+uY>J#MS}6Zytn0Q`){ziqYeqHOvF0l zim)(<8x8D4iBNsK7bQUuF-(1|GTJUW5o@h_<11;lLxh=3(X(WcGv`OlFlC$mtjj36 zizr|I0E&+KAlaH07>klzJ{LMQFW_Jrp-?o6G+rl(9MJ=UbC-YUZvMKOL<28a-y9@A ziLT0kYZCVl4c8q2u@6JYxA_gj*b#$uY>Tl^6!g9jG(Y1O*@oLb&0nBsSyHKs)_Xe0 zNagfs@K`Gb(2~J6;JUqMLGYSq4FW&YQ>BRW(W& zs({f3{`GdK9sHLbVr4Rv zx@Wp4Z%374dTOq=*T+DB`PQ8~M8j&7W3cOJLhOZ*;aK^a)s(Rs^^o;puKD|xCbrgt zI+PbSRst#7yTM&sepy;xg)N8AsELT-Z=fI6s+qEKh$sjuikDVWyF5hh_rpoytvXkER%2KdkHsr~^`yp4g9xyeIcz(o1{EQRW07USO@_P%v_4C14O zLT;xQ94qL#F=BSVcDRp7N%AlgB2o~|A#26sR^m^YR5^GR-XBv45x1LGMLvL`93xnp z9^Bx~P1C2h>2C_e9jv3km9Eauc6JlFQ&`cnk9+{MA4{%O-b+VvNADT?&BB`bj$ zEv8}m=>X;LXG~_&KKJ@T=LBgh<&TYb0}J68(7wK|eL?;`W+5#jQ(DeOu`M#|%SR{)o-~$J~9`>3*`|yT3!#3dx#}MFqf{ z8!$8@sKFeRhyS6S0@UdisGP=e_T8`AEkj&*bb}w!K(G1P3TSH{Q=lcNTMuN?!`R$M zOKTBME0a?u7x`2@%RNVgXt)xkA=opi9W)F7s&#g`;B;s39b>a8P&_!m+V0j6qQi6> zbd(aBj+o#hIuaZHGIEYWFt2Y}4cR=U$=3K9E)mk&^p*ET5E@j8AsZac&X6RfoHhnD zVl0c$h@l411vH_sp#Xf`sE2pwVM_RR1dH7uQiv>f&*kE_Oyc&dHrUrY!9Hb#Qm?6l zf%$XilARp}@R1F>_M0Ae6OUkWO)CeljrXEmlw>gC9c+H_BDQAGP5gmv{f$2?Q^ziq z6|}pL3Jq`Fm?#x5e}kmz5e1l}a(o;id~eDTN@6aEq%MfU$FBYBJy+_$InGq}ReOyN z$R(Vt05Gwa2(}SsJ$t}RUcKt@b*#jO`s2VV3&<*H`!9@JZ`xILYx;|C4~|LFgc>!hk12P8V3jHAFc4|RZIwd}Ym!+)Ws=UXl8zCZx`7Ljr|7z+ zs&B)nF=PM0U$^vevb<>HM4BIj*Hf||RiUW>cco+lp8L=NevOLk4XVBpDz3gdoS4ct z;3cAY|8Zz++s%vvBbJ$H`i5h=v6N5J#rV8n;PIAqh2@nDp01Y+dZ2`zHqaYs&otbD zwKA%7Leg!233HReGD~Hjk<>sm#IUeif*gY#?1};Iai9v^ZrdPY)2(UFi$B6oq*dPC zm=MF9!+Q}W@5=XL`2iW$B79Usn8evrLYnXh%WyI)pfOK!R>9ymg%c5p8ML0SW?V7t zxR{HWWF{=)!Hr2YE^?ylC!8@#L56SEn&p!W!dot|vUZmRX)M{qn{*o98x9lMku%^n zO_vlObLK`6z(tyEw!+{BM1i|W228(^fl5%^SJK`EK>3M)uLx$IASg>OXE6L-0W8%= z5J(EBlPR-i=pHKWBSQP7GR}!D9S-7>`AzXL2p-OXCS~R{e4Hugc(@$8>`*zVzSxFc zOHyuKa`~Cs`6AdjO8ssnDQfdm4oeJ0i2V!~SM5}+yg!}eO8QS}zTNedRdiHw8nZH0 zq=jNq>aB&R=BxhS#!~L`$*TG}?7To@4CUdT_v(+l;!H{!<2nrtFdOV8aKCt|5z>K0 z^@(@y)uDS2PBbX}zI(_#G&nEZdPmpQ<-j6}>QRcshWJD;Rwnv)jOlO<@Yr4k_ZfD9YO1V+%bg09z2xuR z{FCO;J;e>H%%PH`=$^{868h}yzg0oT1o z%bc~Rq$7lvUVE$3F^2qNHRHNahofry?&Kx{nClY2y-ciZa8c}w+TPa8N6cIsi3#x} zFD0@+DNToyd$akf`cG_%YXsCy@UXnpa$wzv%@>=&5bgLTlFFckNJ-QGpyxD$b9DE= zPc-h)cS$iUr3M{&&3@Y9#-_+NGKu8_OEpeTlaqhJmqqp*-%^m?D&KfiPL*~(DPkOV z+rR}CHZyGorO;w@bq?Xob15HHnuqz^>^a(MWlj_^3K_*6(lrKJpB{^O&P*AArRG21 z+5C{I&<0u{t1cWrIr6JEI|;~+##zI?(}oK0XJvU!f2MT)gd^&bdPS5Ebl}>#=d(gw z9#W;&JGsf5WC3`Z2YQ!FQ9S`K>6f;D{d=XXBEMvOl^@MD2QJ1}@ppsdpNn<5SGQZbSrEVm1B&1@g{xDDazlzs&ys^2pRgMbm(DGHu2LbQr*j&HSCcWB<5`2k=l+bjOBToFz= z>C9V$tNeHssA^A-@xdDGxTCo6_X4a5;gqjDVZPfAs`p|J`@aOB#^DUFPqU+}`|ZL{ zQFP!jwprm(#b3&Bw5V7YWilmP@q9cpb~jn|`vb6qNdFMkMS|o1a7cZIo$KGsg|miH6fCZF)GSfTNy0MJgIME}OY5Kr5%x?9aqnELf}7Nh z{}}U??at0BLF31~U^aoOgXDf8!}k&ide`}C_lvs^X_GIo!hRD-j+{MD)s{{J<^G?2|FI=!j*J0 zVuRJ=MP5l8vXkilAY?SZ+H1z)A)D_nZAu*bCFG+A5`3C$gM#i@DMfy1_Kjyk1m z+*bnf^e9t8V3-jL#<(e~zljcwuJ9Za4G}JRIKZ!t?Y|OtVL#{g9KWKbd6O?**F}6P z9d66eJ+-#27XBqFUe4QJeX8Gd{C>M>z_dBbeOjsrz=juguSBNwi%cEiRO2VZ7Y|7F z2*6p=#BPjwWvYkcfsMQ4?mdryxmgYUG1hcIyV9kGP>ZnTxBb6 zFDTMv(4-8kN)p3*jn0>iO=1r^UP`e&A_B1|$h%WXfWkjaeCB-+J*sXuA=vl!e-$!h z;9e0~u@vdi1A=RFObguOOfAibO{Nt)=HsxjCw$v@wW)gD41f2@XA5d8r&yxaY6faG zv+vE^lgswO72eSTD$6|b+4x@&nhqseq|GVX;{0(r@GPb|ebz<>hOTZ8f>$^JIAme? zUeFH|Fa<$kd1UIu^2Y6>9!E`d|H`j@n~LUnT;T=d50C`Hk7FKgYWX|-UpzAo0_$|f zd^ELyYE!@v;g9h(b=ZN^`adqdEo+bo&i>cK8=`1%%v}#Rp7ywq4fqE|PWm?&QQk&f z*udt63XH`=TRNpzo)6mm&mRnjtctsGrVw6z%G7(=q52hT?&FN5^K-6weytqd0M$h&hwCV&Bwf3nLKhWz- zoNb-vICE}O!o*u!H$Qld@;LerTPEyjEDw9o90E^cBT&M~u+kz?US-w2TXOD{tqV*3x5Uqu|S%}zSgQ37{35v^TV*(v`t$q0a)O>{@Z~}g zv4V9%2|3PqiU=>`cf~x|e#UM>o`P_{#XIc4`$C>ss<;iVkZ|L3Xa-bSl9c+MHs^e@AnR* zQ&2IVrMQ=3Db4J;BZcO35qhyy&K^t|*AB)ICT$=Z{iUL&)_r1XRQ+$fscIUR8V9E! zp;WhpJSX~g3(zC=YWYekzMXuQ!?Jd$_3czA?KHhx|1pW((6DzQgkaS8=Y8f^FST)8 zem@EZ48N?H$k(YHECj7lR!wF^-OM;!uVuIxJt^bYV_(|*6&DHxvU|LKMNsFcJikJ` zTacmB8cWe2etuY~2|$;|n4bcgEA}a5KqouhK?K-?Yjp21aC#=dTcby zbzA#5PSy#+4+9OwH!lMXyde;`QVI9W&Z;b-?^IPm zCKA+E&s*UO`$Olp26u!!7LNtlDil5 zAT)VTr|>_vu6&9*%ue?ERc4plNP&RQc3Xi$6GI4*ZoZ;PW3?YQWdjyjwqF?S6Ez-( zy<6eIIj8puP1H4w4YQKs(vnYpeqMn-{?8{7f1npGL}c2gn&)h=p2ns@g_d2~e%$Q* zIfg_7!v}ozn$dL6Fr#Ojl4NvXn6G0!aOg>Ng6rx*?q}zQ9DG~-IY48)Ej16q?gcBS z;z^ktf{W1VBzlf++HzNHr3Zmybx5|3OV^SdAYPptOKv@}T-0f}ncZu0NqL zCsPx5JC9eji-iJn=i_|D8DLFbbeHZq%m3iQPUL}d=n5fmYo1*`JivQUYu>uPVF#^+ z5atI_Nq>@>tBhn3;sAEZg(8D3%1NgjYv&l^7t;4S&Y&OQ5RjA>AYQ3hNZAe*=2X)ehTE%afmdiYA>ckMn zla2WnZ{7D}I4JMqadd)h>|hI)Va&``XifQL^f6J3vrwKBCzpGy4>JD}pDH3q+rVJf zD_}>p8Ip>A7owa|kK6X&Z-E(E0`}p{U~`N#UMIUBrV+SrN^YFPMK610Q_w>5#tV@0~1zw}dcbl|JjIEh*p?)Yl*U$$kFKHjeI!KQG=sEmdB z$J(%!)9cTqqbpVc(;x9;8|tXopNhX}>Bx2;5>mUco>AbCq!@~P|LQvz+|E6VhRDWV z;l|3+&I?RQug7(bFVG@0lj)y@9?3&=cwo(JFCrmgZq8GjzuoX6dd3dyn*|o=^mPPa zw_3D_$pRmCGAz8{en&3P%LSqf{TbmlS!GhpL)JFYHbFWhj&AuM(QhYr z2FI*4-&Bxug__gX3W`%huk!?Qd6epv7t1!jR+z`&k_1;;A)~}bz+}ST_n7kH4(Wuy zzWw5+Z?k5=`%M+OTjsEA-F7mpXFzsYf{8g;|UYo0Jqg>#e)2RME_xm|&G8Yw2SUgE3 zFtLFokm;q-?ZH5|A_4uAQ_}xCcjX?A1%iDesZ25Kdeiu>d^2;z zqyD3x7zOPUi=^G4#NqV00pr=R5SVNJitecI;A74!S+_1!1H#6ZeL5@IQ>*3Hx`?CH z`8-02R9(DGMxLZndPb3XBC>!^z`SXMQZdJjQzhg1qZ9c|hvdqlxo_cp`Tc4!8ZoiK zHDOh6G{ZTc+$_a9fJi^fHln`;r~8I4p&N@S@o*(CY}q7-$|7a#d`02plOtqtMaE+X zg8Dx@q+YGOR_p&w!O?xl#Do>!=KfWn30Yh7XGu=loKp2y)nI9`#LRcDEJ4*g76U$t zh=2G3tw(9e5mfZ<9ZmOj4Lxq8Z~sPrJvXvF@}_{9>I63qauBEZ|KS{?ipGZiEA)De zuOPA2fUl5CDWn5e&9(Z>%lhwV`U$cqFQ6>+gxE!}I67Vao~`a(2tf}81YaYxSt^iRSLM#PTJ>(SldsiYF;Y8)^B5?!iyvn0`o;!p7=!rcT3zeDc2Ur< zYS#q!5IH6@MWuhlu8PQ&L0eJ(X{ox&(GW_yXe?Ku(zUG(>b7z&vKz6Q77HewQUhx89hTNab7pEQspj+JuiuZ{VP57Pyrl7nR}dVcW6SAJE; z)QTWiJ@aiOn>q5$rF{NCr)!`T^<{YGdD|a$ncNoL30JNo%cl zVt2?=3$7h)udU{awo0>j?M9B)jiYoIm{S~*_owrxDue3R$D2S%wabilM0}5=mADG+ zlzrT)!zJIHDiGbeTa}t`+=&^w=lf(-3kYAEQj}Fu`LR>1R1t>Ei7olw7v>ahfM`7r z7q}Zd_BZX+)UO#$LJkJTZ@(Yneo8JAFA#gR0=L`hnGyLw5fJ4QlybE4{)^oj9StB+ zu89>uw{6Y!rp85&$d%{EMY(S{GZbOB#pFk|as7#}cJz33eK+Ia-psU9UaMw2>47JO zWyxpCnch`uBZaMDscuo$qv}v7Dg3}^x2gdXP$xBv784To2D){P34ldi)h!~%b=u5s zX%dy%RB;SvzsSiWC-Mm&tJMv#8OGM3(oWNNGQZ-Lq9dJ4m@^8T!W-UgeZ!7s99xgf zU0$>((?ez8L;)Dhs^C4&(~a|inCNBYlgJs3Zxkx-@d|B3DP!YN;u8lx?WhDkwGOn? z748R^^=8VVp@E4qxkn3p3GcXPS-nU{QzJ1P6xz&C`%J z10}NINm|Gt-^I`$(o5M<^2pz}=U1Bv?6rzy0~eLmT_xi1BoxU-6cn$&G*8BQJGc1p z{v6e-*h?g|k3dQRDZ)X`~&U*+i z{Un=FF&nEtdVf`;7~l1|z^5VDcahojMN>|j%eam(v;NT1ci*Ih}EtMOf5VtnHywWH&_c8xV#F0^M_n6z^8uN0pP zT6g2qZdXk3M+z3tCU|9HTq!5U7m70pNov#5$#s^IRUOw|AK%Zr?1>_FTex;0qh!YS zIqqrvZ(6^f*D?Ub`sjN0-e{f;PU~z2nve$6)B25s%BVn+$U(-Z!f8bW2}U%2+)sD% zkJt)^6XZ~tYs0wD6I5g`FR}&PHV|9{~wd z;#K2&Cn;yj@zC>^00`T1DnGA%vyUfuC981azLi{>?2p!MhyAWYsFsiHnP|*BL^(Ij zH|;UI#^u)XIuUTLEj%M{lBgArubd!zk>^^#u0j`R`W$Fdo}(ZTO%xQ!ZQXJ~9;YYE z$CYE7x4gKSlWL~C*;9*+JG|@It{n44rx3tMAN~-9-iM^;Yp=N+sUP$l8s(#pAYImivgBO{HbSy zdI^SkQLjakRC1L&e!}{U8vro&+8`3)4xzJVU@&vDMOA|MIJ#F^b@0c`T@UU%Yv%dp zdl+prN8XoI&3a__oWt{nuak7+gtB~!$P;kI?>26BXFdeMv&oz3W(nu-V;3Id<3MAo z{`b0e?~BEY{>e>j^aLK9!{Sjk^owkx82i(?>Pl^W19tDqnisk{f5$yk!oN?9y;ROu zsg!}fH$5gUK9-ZKl!kxkDhFe-<;z667s3dIb=hEfoHvdMZN%8ML8PT;cj?hx&VxK` zmu#HqyA_}71f~kEWg{KaUL08=!4r~_^)l}v6!-{TS5Esf^x7=%x`QsyBFw{ode`3m zeW^X(2hs0Js4s=YP1w=$!CPttqUiNw3u%P{`QPkdW=DP9moGE+es@p*I8#*(3LFcf z_vue$XD9wx;a}EREV?&Jsw`WEIVLvKiwWwALI2Bs{F%)-<0= zRH2R$lFwMZo4etTMW=4osS2tRZAxLj@wT>+Y9pk`dNaCv<6VC$DKO+*x2AW?F5p_( z_!E>$I5N2$S<~?O8nwre&)n8`dOHNg(5zn9ME~SJZMtIpxhUKo%+zThcU287E(fR1 zyhg`@qHk*(7Qyf=1Y^){*!J(xKztcW!Bj)ikF$Kvt}Rx)RKg!R5($j^?-uRn_}`1B z3}H=Gi@wSxi+Xle_u3X9U85wI(H3)qE`Blp4=dxaA7lY{ubDr=YDdC`u%wx#^9+r( z|6A2R%O%&BU29mtRcG|%qMEMY(M(e2q)&gUI=TwtZ+Rt@*MOQzD4p7b&>jz(eOzA_ z9}|R(r;BKW{dTOryj)vUyWaSFb-&k<{^$Oy(4{O&ZKC#K>!@L?Pr#B)XIq9HXDVS) z5?^&l*-VpP=7;;7h{6mz=XxX~=QPUb7sKJ#m!so}eD_CGcFs0p`m!g2qv~ASh=vy) zBp00hPM+MmKf<{zZYj6oa=R?fFWFh4QII;Jcn;r zaP0p6mikk3hPqOIz3!1pINFCAP^w%}G2|MqaU}Ptd=j&w;4BX%WIc!4f{UI(kJM0B zzGNo%>B=k}!$p;su1o5@`DL7LQn`^u=@8Z)JMFQ=DD~iP%-v7RN#*Jr=sH)_|Ig>t Z2NZA_YlCIEF6@6~HHa4YyP`Gh{{YN1Hyr=~ literal 0 HcmV?d00001 diff --git a/src/platform/xb1/Assets/SmallTile.scale-200.png b/src/platform/xb1/Assets/SmallTile.scale-200.png new file mode 100644 index 0000000000000000000000000000000000000000..d5e72e284f9b058543bd0c82dc903b18a5dafa84 GIT binary patch literal 2296 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 literal 0 HcmV?d00001 diff --git a/src/platform/xb1/Assets/Square150x150Logo.scale-200.png b/src/platform/xb1/Assets/Square150x150Logo.scale-200.png new file mode 100644 index 0000000000000000000000000000000000000000..78f8b2354c252e7b1929ca1d9353c4bc132adefd GIT binary patch literal 5198 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 IM6N<$g3+iZ9{>OV literal 0 HcmV?d00001 diff --git a/src/platform/xb1/Assets/Square44x44Logo.altform-unplated_targetsize-48.png b/src/platform/xb1/Assets/Square44x44Logo.altform-unplated_targetsize-48.png new file mode 100644 index 0000000000000000000000000000000000000000..42fb2bdbac909e43fa7484cb12614fc21e31dbe6 GIT binary patch literal 706 zcmV;z0zLhSP)c~w|hT3K6LUX{VXU>Ypjj0U?+ElaN%mPA-s7z_pq z zwHJk(xq_t3IkjPT=Q(_tp`8BOB~Fd+uA4;pPRlb`0wj~C*g663!sHtZ677X%N$f|1filVKA#RddFkcsJ z_NJ!_qMoIpe2_9ttH9nwH!z>$ceCJ@HQLzyVDkP=oi0&ASIcAYUwu!(>!B2nc`(pQ zae|)9Kq*zv*iZXAy=o2PauKzqeEyR9D50g)Feiu$-INHBk?zXrW1L2`#GM)-*ZM1U z09s2#pcir=XqMK2wpO>Dyhbm6{5ZKo?$JiP^|#7~hv7!RQz>i$4Pd1C<7;pI2Cc!y z5bPcGzoR|N?oSsi~*kS8vLumEf3d1?jlfqmGi+XE&P`lEu5}k3jt)gd3itg o>J|XOiWBsQBhS@ zRbO9UW@ct-X=!Y1Y;tjObaZrnetv<0frp2Oj*gC!l9HE~mz+bIE@$vEU^78fd_4fAm_xJbs z`1twx`TP6({QUg={r&#_{{R2~L`HN0000E`Nkl+a3fcwCK+IOO@Ak?Y2`@e>lB$}V!hiZt|DO^8#2QJDg|YENYVLl` zV(+?XAt|}24yLYs^GrU~5|RanPgEu8XY9Zrl?=L^E1e7U{aH0x$%4J-STE_>9-qP{ zE4abHsK8$DJQ>)^EghpgyZ0BVz=G0vS+R1Gu403_DwmoLTapNDaY45R4_fK0=&9#Y z?~lhY$(oHBD|$zeMBvIt2K?5qqyzgESowNWmQ>(_umXENh)uWI0+$MG!Xz8$D#MC9 zvZ)*vSadj#T%GYOS+AM0pgjDnIdGEbmoqr%y>^aJ>%3EyFM|^#;?`fNoR6oMBL>HN zSZgH-_k&Jd(B&_;2Z2a}bvdGoNR1XN$5)-(!{6>8BeqLVuUtu$%J(|V?|j(n(=#w| zt>B#Fa})9#Ze`(vXYVnGCIe>&KPQ_-l5ljqD!)*fljFJApYPyt4oIHlVLU;PMdfJ=IHd??2U>1-SPqcCJ}Jfc_6o6jMu zyS&MP{zt*k;*#oB!x^k(<5hM@rWMG}+!K2L*;4YEVBd2Uzl~JA?wp1UYHw6J_Qc4) z|GB2m_%JwO@O*&Tb>5yB==ic4EY-!LbIMlq8QJ&CXD24*ERSL3?6mP+wZRnV{y0OKG(!% zxUwF;xI2tNi(bE-FT@D0=^V!uvH7)pxC)zL;Xn+D{+o-)7>kp^OdW@Nxk@Y!#+kS> zE$Pw)7h{4D}pQ+-?yCTGLJgg&f$4K~g^gJ<_^FDzQUKE3n2Hj=gX-*vxKTpw6y zxM=mSyby~sl3tb9VzOM=*22xTyk5kTclsts| zZ|)VHl2q5ox@Jn~avqqIvW~d&n)LB=G1n{xHn`v%KN^tS9brmkPO*_K070K~w#5{3 z1#QlQet2@4EkMw^?oL6PFrHg+)5xM6~-{#Fmr(cK7ruYvkx8?Z|VFn$Yv1luc z*ayyd*@!P#lG_g*{`K6J@~r|Bzj+pTCnb>ruIITJ5tF|n35ML{E)(bSt1rp%q9WPi zqTJIkYDzBhehofr9@w~IpBS`Vg2)zksJs&xY)kOSzyc|cVB&YX!12=+Wb^gy)wQLl zV@5?_b)GedpfO>f*X@UiV80>-@m$cSXQ8SPgDze0fph-Z>XQS@>)fxXDLUwrm^@_X*9GeA6N{xLqyJzGsMU zBCzKWvUE~vm3tlRQZXvi0xwoENQ^)X>guXHksk_5jvFq!9`ASbqE!gK6q~>HJ?@mY z_Fw6ol3&DbLAl*2@8E@%E*)Li;?6d+itHL_PbPP*#@5T2##OPAN_IpGENbcB zzdd7#Sc`*qYHsTGQe7JB002ovPDHLkV1jV20UrPW literal 0 HcmV?d00001 diff --git a/src/platform/xb1/Assets/Square44x44Logo.targetsize-48.png b/src/platform/xb1/Assets/Square44x44Logo.targetsize-48.png new file mode 100644 index 0000000000000000000000000000000000000000..42fb2bdbac909e43fa7484cb12614fc21e31dbe6 GIT binary patch literal 706 zcmV;z0zLhSP)c~w|hT3K6LUX{VXU>Ypjj0U?+ElaN%mPA-s7z_pq z zwHJk(xq_t3IkjPT=Q(_tp`8BOB~Fd+uA4;pPRlb`0wj~C*g663!sHtZ677X%N$f|1filVKA#RddFkcsJ z_NJ!_qMoIpe2_9ttH9nwH!z>$ceCJ@HQLzyVDkP=oi0&ASIcAYUwu!(>!B2nc`(pQ zae|)9Kq*zv*iZXAy=o2PauKzqeEyR9D50g)Feiu$-INHBk?zXrW1L2`#GM)-*ZM1U z09s2#pcir=XqMK2wpO>Dyhbm6{5ZKo?$JiP^|#7~hv7!RQz>i$4Pd1C<7;pI2Cc!y z5bPcGzoR|N?oSsi~*kS8vLumEf3d1?jlfqmGi+XE&P`lEu5}k3jt)gd3itg o>J|X@$&cC;5ENvSeT-qRzyz zlqYv5h{!;v|F`Iv@UIa3+GnfX;~? zFEfAyR9!g{pRSHK4~b|nO+orsn=g5RbZ8TV^YLOY14ypt(~zgjUC72E-yZ1GPMSY6 zfP8Pn#HFErUuFL{zA+l*HbTO&gJb zZ{HD6;{Rp&JU<`K5ioh*)XHQWS*R~0ZC^+ zFS6MwGUABINm9+p5v5xy?iDsji6~Ch$1BBN60H$MHpSR|q|uerGILWlARA)r58Pqt77t^oQnrDPlcJ94D+N?jugX&6#*9TNNr34-nU598*ajvL3?J zDNT=EOg!3AdSYGTnsshYHO}<%AkC?wAH}InRkk7PF!qu=6Z^A?6HuO+?Jj|;>v~BX zvHMJ8;#C1rW-lWi=u^>x>(VRyJpPR3?uBc}Gg(!0l3#H4cCB7{J1T?A6=K|!zE+W3wJ8sHU zMO^p_4`+`32yxtNjENuK9Yq9%TdFDh4kdYO0mL&X@QF)<_!!VewUx^`h zJaJym`_U3KDaa81+7QjmUo2VTMQ#=%*mdWkl!u7p#k)ggKM(oa(5}gJU^KQOWM<)Q zoL_Sp#Mm7-#()Frs#2MJS5*goP`>CkXMF_JnHCX~g)WTEUNP}zb+bC*&{D0w2Z2Cj z_NGoX8JEi0d$Y1nr4|w1XPk1tK?MQ{0U`_A58sjT77_)3phaaFAp}_p!6{$(R6>ja z^I8o_Y$CjkHeLGgY#So7j8SK@T0X@0kBjff`Os}Q$`Bynf@d+Wuk@qRt(Vp+&7Yiq=7k7kxMehwkBWNjas3qn!g#j zK^BVRQ?U^!v4MzFYe1{+- ni3AY=VjkH_B!vH^f57<<2E05hM_=vT00000NkvXXu0mjfObPnH literal 0 HcmV?d00001 diff --git a/src/platform/xb1/Assets/Wide310x150Logo.scale-200.png b/src/platform/xb1/Assets/Wide310x150Logo.scale-200.png new file mode 100644 index 0000000000000000000000000000000000000000..12e41d09e6961eb138cb6c9419c416222133f547 GIT binary patch literal 5645 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 literal 0 HcmV?d00001 diff --git a/src/platform/xb1/OpenLara.sln b/src/platform/xb1/OpenLara.sln new file mode 100644 index 0000000..86965dc --- /dev/null +++ b/src/platform/xb1/OpenLara.sln @@ -0,0 +1,51 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 15 +VisualStudioVersion = 15.0.28307.1022 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "OpenLara", "OpenLara.vcxproj", "{0DF8D188-E91B-49C5-A2C5-75C430648B5E}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|ARM = Debug|ARM + Debug|ARM64 = Debug|ARM64 + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|ARM = Release|ARM + Release|ARM64 = Release|ARM64 + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {0DF8D188-E91B-49C5-A2C5-75C430648B5E}.Debug|ARM.ActiveCfg = Debug|ARM + {0DF8D188-E91B-49C5-A2C5-75C430648B5E}.Debug|ARM.Build.0 = Debug|ARM + {0DF8D188-E91B-49C5-A2C5-75C430648B5E}.Debug|ARM.Deploy.0 = Debug|ARM + {0DF8D188-E91B-49C5-A2C5-75C430648B5E}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {0DF8D188-E91B-49C5-A2C5-75C430648B5E}.Debug|ARM64.Build.0 = Debug|ARM64 + {0DF8D188-E91B-49C5-A2C5-75C430648B5E}.Debug|ARM64.Deploy.0 = Debug|ARM64 + {0DF8D188-E91B-49C5-A2C5-75C430648B5E}.Debug|x64.ActiveCfg = Debug|x64 + {0DF8D188-E91B-49C5-A2C5-75C430648B5E}.Debug|x64.Build.0 = Debug|x64 + {0DF8D188-E91B-49C5-A2C5-75C430648B5E}.Debug|x64.Deploy.0 = Debug|x64 + {0DF8D188-E91B-49C5-A2C5-75C430648B5E}.Debug|x86.ActiveCfg = Debug|Win32 + {0DF8D188-E91B-49C5-A2C5-75C430648B5E}.Debug|x86.Build.0 = Debug|Win32 + {0DF8D188-E91B-49C5-A2C5-75C430648B5E}.Debug|x86.Deploy.0 = Debug|Win32 + {0DF8D188-E91B-49C5-A2C5-75C430648B5E}.Release|ARM.ActiveCfg = Release|ARM + {0DF8D188-E91B-49C5-A2C5-75C430648B5E}.Release|ARM.Build.0 = Release|ARM + {0DF8D188-E91B-49C5-A2C5-75C430648B5E}.Release|ARM.Deploy.0 = Release|ARM + {0DF8D188-E91B-49C5-A2C5-75C430648B5E}.Release|ARM64.ActiveCfg = Release|ARM64 + {0DF8D188-E91B-49C5-A2C5-75C430648B5E}.Release|ARM64.Build.0 = Release|ARM64 + {0DF8D188-E91B-49C5-A2C5-75C430648B5E}.Release|ARM64.Deploy.0 = Release|ARM64 + {0DF8D188-E91B-49C5-A2C5-75C430648B5E}.Release|x64.ActiveCfg = Release|x64 + {0DF8D188-E91B-49C5-A2C5-75C430648B5E}.Release|x64.Build.0 = Release|x64 + {0DF8D188-E91B-49C5-A2C5-75C430648B5E}.Release|x64.Deploy.0 = Release|x64 + {0DF8D188-E91B-49C5-A2C5-75C430648B5E}.Release|x86.ActiveCfg = Release|Win32 + {0DF8D188-E91B-49C5-A2C5-75C430648B5E}.Release|x86.Build.0 = Release|Win32 + {0DF8D188-E91B-49C5-A2C5-75C430648B5E}.Release|x86.Deploy.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {037CFBE7-50F7-492C-B712-18C42FD39BE3} + EndGlobalSection +EndGlobal diff --git a/src/platform/xb1/OpenLara.vcxproj b/src/platform/xb1/OpenLara.vcxproj new file mode 100644 index 0000000..f12b042 --- /dev/null +++ b/src/platform/xb1/OpenLara.vcxproj @@ -0,0 +1,332 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + Debug + ARM + + + Release + ARM + + + Debug + ARM64 + + + Release + ARM64 + + + + {0df8d188-e91b-49c5-a2c5-75c430648b5e} + DirectXApp + OpenLara + en-US + 14.0 + true + Windows Store + 10.0.17763.0 + 10.0.16299.0 + 10.0 + + + + Application + true + v141 + + + Application + true + v141 + + + Application + true + v141 + true + + + Application + true + v141 + + + Application + false + true + v141 + true + + + Application + false + true + v141 + true + + + Application + false + true + v141 + true + + + Application + false + true + v141 + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + OpenLara_TemporaryKey.pfx + False + False + Always + x64 + 0F7D3218F53B8902E26C7E787E16EB3520A9898C + 1 + OnApplicationRun + False + + + ..\..\libs\;..\..\;$(VC_IncludePath);$(WindowsSDK_IncludePath); + + + ..\..\libs\;..\..\;$(VC_IncludePath);$(WindowsSDK_IncludePath); + + + + d2d1.lib; d3d11.lib; dxgi.lib; windowscodecs.lib; dwrite.lib; %(AdditionalDependencies) + %(AdditionalLibraryDirectories); $(VCInstallDir)\lib\store\arm; $(VCInstallDir)\lib\arm + + + pch.h + $(IntDir)pch.pch + $(ProjectDir);$(IntermediateOutputPath);%(AdditionalIncludeDirectories) + /bigobj %(AdditionalOptions) + 4453;28204 + _DEBUG;%(PreprocessorDefinitions) + + + + + d2d1.lib; d3d11.lib; dxgi.lib; windowscodecs.lib; dwrite.lib; %(AdditionalDependencies) + %(AdditionalLibraryDirectories); $(VCInstallDir)\lib\store\arm; $(VCInstallDir)\lib\arm + + + pch.h + $(IntDir)pch.pch + $(ProjectDir);$(IntermediateOutputPath);%(AdditionalIncludeDirectories) + /bigobj %(AdditionalOptions) + 4453;28204 + NDEBUG;%(PreprocessorDefinitions) + + + + + d2d1.lib; d3d11.lib; dxgi.lib; windowscodecs.lib; dwrite.lib; %(AdditionalDependencies) + %(AdditionalLibraryDirectories); $(VCInstallDir)\lib\store\arm64; $(VCInstallDir)\lib\arm64 + + + pch.h + $(IntDir)pch.pch + $(ProjectDir);$(IntermediateOutputPath);%(AdditionalIncludeDirectories) + /bigobj %(AdditionalOptions) + 4453;28204 + _DEBUG;%(PreprocessorDefinitions) + + + + + d2d1.lib; d3d11.lib; dxgi.lib; windowscodecs.lib; dwrite.lib; %(AdditionalDependencies) + %(AdditionalLibraryDirectories); $(VCInstallDir)\lib\store\arm64; $(VCInstallDir)\lib\arm64 + + + pch.h + $(IntDir)pch.pch + $(ProjectDir);$(IntermediateOutputPath);%(AdditionalIncludeDirectories) + /bigobj %(AdditionalOptions) + 4453;28204 + NDEBUG;%(PreprocessorDefinitions) + + + + + d2d1.lib; d3d11.lib; dxgi.lib; windowscodecs.lib; dwrite.lib; %(AdditionalDependencies) + %(AdditionalLibraryDirectories); $(VCInstallDir)\lib\store; $(VCInstallDir)\lib + + + pch.h + $(IntDir)pch.pch + $(ProjectDir);$(IntermediateOutputPath);%(AdditionalIncludeDirectories) + /bigobj %(AdditionalOptions) + 4453;28204 + _DEBUG;%(PreprocessorDefinitions) + + + + + d2d1.lib; d3d11.lib; dxgi.lib; windowscodecs.lib; dwrite.lib; %(AdditionalDependencies) + %(AdditionalLibraryDirectories); $(VCInstallDir)\lib\store; $(VCInstallDir)\lib + + + pch.h + $(IntDir)pch.pch + $(ProjectDir);$(IntermediateOutputPath);%(AdditionalIncludeDirectories) + /bigobj %(AdditionalOptions) + 4453;28204 + NDEBUG;%(PreprocessorDefinitions) + + + + + d2d1.lib; d3d11.lib; dxgi.lib; windowscodecs.lib; dwrite.lib; %(AdditionalDependencies) + %(AdditionalLibraryDirectories); $(VCInstallDir)\lib\store\amd64; $(VCInstallDir)\lib\amd64 + + + pch.h + $(IntDir)pch.pch + $(ProjectDir);$(IntermediateOutputPath);%(AdditionalIncludeDirectories) + /bigobj %(AdditionalOptions) + 4453;28204 + _DEBUG;%(PreprocessorDefinitions) + + + + + vccorlib.lib; msvcrt.lib; d2d1.lib; d3d11.lib; dxgi.lib; windowscodecs.lib; dwrite.lib; %(AdditionalDependencies) + %(AdditionalLibraryDirectories); $(VCInstallDir)\lib\store\amd64; $(VCInstallDir)\lib\amd64 + vccorlib;msvcrt + + + $(ProjectDir);$(IntermediateOutputPath);%(AdditionalIncludeDirectories) + /bigobj %(AdditionalOptions) + 4453;28204 + __XB1__;__UWP__;NOMINMAX;_CRT_SECURE_NO_WARNINGS;NDEBUG;%(PreprocessorDefinitions) + NotUsing + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + false + + + false + + + + + + Designer + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/platform/xb1/OpenLara.vcxproj.filters b/src/platform/xb1/OpenLara.vcxproj.filters new file mode 100644 index 0000000..619c14b --- /dev/null +++ b/src/platform/xb1/OpenLara.vcxproj.filters @@ -0,0 +1,103 @@ + + + + + db6ab835-f1cb-4efb-94eb-2bdfd0c3a3d2 + bmp;fbx;gif;jpg;jpeg;tga;tiff;tif;png + + + {ba6867bc-3dac-49f7-b628-c02d534f8825} + + + {d606bd3a-145c-432f-ae5a-66dcb178b466} + + + {d5e2e716-2bc5-43a1-bebc-4c5631d0b1bc} + + + + + + libs\tinf + + + libs\stb_vorbis + + + + + libs\tinf + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Assets + + + Assets + + + Assets + + + Assets + + + Assets + + + Assets + + + Assets + + + Assets + + + Assets + + + \ No newline at end of file diff --git a/src/platform/xb1/OpenLara.vcxproj.user b/src/platform/xb1/OpenLara.vcxproj.user new file mode 100644 index 0000000..8551252 --- /dev/null +++ b/src/platform/xb1/OpenLara.vcxproj.user @@ -0,0 +1,23 @@ + + + + UWPRemoteDebugger + 192.168.1.49 + + + AppHostLocalDebugger + 192.168.1.49 + + + UWPRemoteDebugger + 192.168.1.49 + + + True + False + x64 + False + 192.168.1.49 + True + + \ No newline at end of file diff --git a/src/platform/xb1/OpenLara_TemporaryKey.pfx b/src/platform/xb1/OpenLara_TemporaryKey.pfx new file mode 100644 index 0000000000000000000000000000000000000000..fc69764f43cbcc350600d74caed1b4780f7521c5 GIT binary patch literal 2512 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 + + CN=EAAE5CD2-DCE4-4EC0-B98D-40B753FDC939 + XProger + MSA + http://www.w3.org/2001/04/xmlenc#sha256 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 39822XProger.OpenLara + + OpenLara + + + + + \ No newline at end of file diff --git a/src/platform/xb1/Package.appxmanifest b/src/platform/xb1/Package.appxmanifest new file mode 100644 index 0000000..312c87c --- /dev/null +++ b/src/platform/xb1/Package.appxmanifest @@ -0,0 +1,33 @@ + + + + + + OpenLara + XProger + Assets\StoreLogo.png + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/platform/xb1/main.cpp b/src/platform/xb1/main.cpp new file mode 100644 index 0000000..1207fb1 --- /dev/null +++ b/src/platform/xb1/main.cpp @@ -0,0 +1,503 @@ +#include +#include +#include +#include + +#include "game.h" + +using namespace Concurrency; +using namespace Windows; +using namespace Windows::ApplicationModel::Activation; +using namespace Windows::UI::Core; +using namespace Windows::Foundation; +using namespace Windows::Graphics; +using namespace Windows::Gaming::Input; +using namespace Windows::Storage; +using namespace Windows::Globalization; +using namespace Windows::System::UserProfile; +using namespace Microsoft::WRL; + + +ID3D11Device *device; +ID3D11DeviceContext *deviceContext; +IDXGISwapChain1 *swapChain; + + +// multi-threading +void* osMutexInit() +{ + CRITICAL_SECTION *CS = new CRITICAL_SECTION(); + InitializeCriticalSection(CS); + return CS; +} + +void osMutexFree(void *obj) +{ + DeleteCriticalSection((CRITICAL_SECTION*)obj); + delete (CRITICAL_SECTION*)obj; +} + +void osMutexLock(void *obj) +{ + EnterCriticalSection((CRITICAL_SECTION*)obj); +} + +void osMutexUnlock(void *obj) +{ + LeaveCriticalSection((CRITICAL_SECTION*)obj); +} + + +// timing +LARGE_INTEGER timerFreq; +LARGE_INTEGER timerStart; + +int osGetTimeMS() +{ + LARGE_INTEGER time; + QueryPerformanceCounter(&time); + return int32((time.QuadPart - timerStart.QuadPart) * 1000L / timerFreq.QuadPart); +} + + +// input +struct JoyDevice { + Gamepad^ gamepad; + int time; + float vL, vR; + float oL, oR; +} joyDevice[INPUT_JOY_COUNT]; + +Core::Mutex joyLock; + +#define JOY_MIN_UPDATE_FX_TIME 50 +#define JOY_TRIGGER_THRESHOLD 0.1f + +void osJoyVibrate(int index, float L, float R) +{ + joyDevice[index].vL = L; + joyDevice[index].vR = R; +} + +float joyTrigger(double value) +{ + return clamp(((float)value - JOY_TRIGGER_THRESHOLD) / (1.0f - JOY_TRIGGER_THRESHOLD), 0.0f, 1.0f); +} + +void joyUpdate() +{ + OS_LOCK(joyLock); + + #define JOY_BUTTON(index, btn, mask) Input::setJoyDown(index, btn, (state.Buttons & mask) == mask); + + for (int i = 0; i < INPUT_JOY_COUNT; i++) + { + JoyDevice &joy = joyDevice[i]; + + if (!joy.gamepad) continue; + + GamepadReading& state = joy.gamepad->GetCurrentReading(); + + JOY_BUTTON(i, jkA, GamepadButtons::A); + JOY_BUTTON(i, jkB, GamepadButtons::B); + JOY_BUTTON(i, jkX, GamepadButtons::X); + JOY_BUTTON(i, jkY, GamepadButtons::Y); + JOY_BUTTON(i, jkLeft, GamepadButtons::DPadLeft); + JOY_BUTTON(i, jkRight, GamepadButtons::DPadRight); + JOY_BUTTON(i, jkUp, GamepadButtons::DPadUp); + JOY_BUTTON(i, jkDown, GamepadButtons::DPadDown); + JOY_BUTTON(i, jkSelect, GamepadButtons::View); + JOY_BUTTON(i, jkStart, GamepadButtons::Menu); + JOY_BUTTON(i, jkL, GamepadButtons::LeftThumbstick); + JOY_BUTTON(i, jkR, GamepadButtons::RightThumbstick); + JOY_BUTTON(i, jkLB, GamepadButtons::LeftShoulder); + JOY_BUTTON(i, jkRB, GamepadButtons::RightShoulder); + + Input::setJoyPos(i, jkL, vec2(float(state.LeftThumbstickX), -float(state.LeftThumbstickY))); + Input::setJoyPos(i, jkR, vec2(float(state.RightThumbstickX), -float(state.RightThumbstickY))); + Input::setJoyPos(i, jkLT, vec2(joyTrigger(state.LeftTrigger), 0.0f)); + Input::setJoyPos(i, jkRT, vec2(joyTrigger(state.RightTrigger), 0.0f)); + + if ((joy.vL != joy.oL || joy.vR != joy.oR) && osGetTimeMS() >= joy.time) { + GamepadVibration vibration; + vibration.LeftMotor = joy.vL; + vibration.RightMotor = joy.vR; + joy.gamepad->Vibration = vibration; + joy.oL = joy.vL; + joy.oR = joy.vR; + joy.time = osGetTimeMS() + JOY_MIN_UPDATE_FX_TIME; + } + } + + #undef JOY_BUTTON +} + +void joyAdd(Platform::Object^, Gamepad^ args) +{ + OS_LOCK(joyLock); + for (int i = 0; i < INPUT_JOY_COUNT; i++) + { + JoyDevice &joy = joyDevice[i]; + if (joy.gamepad) continue; + joy.gamepad = args; + return; + } +} + +void joyRemove(Platform::Object^, Gamepad^ args) +{ + OS_LOCK(joyLock); + for (int i = 0; i < INPUT_JOY_COUNT; i++) + { + JoyDevice &joy = joyDevice[i]; + if (!joy.gamepad) continue; + if (joy.gamepad == args) { + joy = {}; + return; + } + } +} + +void joyInit() +{ + Gamepad::GamepadAdded += ref new EventHandler(&joyAdd); + Gamepad::GamepadRemoved += ref new EventHandler(&joyRemove); +} + + +// sound +#define SND_SIZE 4704*sizeof(int16) +#define SND_MAX_BUFFERS 2 + +struct AudioContext : public IXAudio2VoiceCallback +{ + Microsoft::WRL::ComPtr pXAudio2; + HANDLE event; + + virtual void STDMETHODCALLTYPE OnVoiceProcessingPassStart(UINT32) override {} + virtual void STDMETHODCALLTYPE OnVoiceProcessingPassEnd() override {} + virtual void STDMETHODCALLTYPE OnStreamEnd() override {} + virtual void STDMETHODCALLTYPE OnLoopEnd(void*) override {} + virtual void STDMETHODCALLTYPE OnVoiceError(void*, HRESULT) override {} + virtual void STDMETHODCALLTYPE OnBufferStart(void*) override {} + + virtual void STDMETHODCALLTYPE OnBufferEnd(void* pBufferContext) + { + SetEvent(event); + } + + AudioContext() + { + event = CreateEventEx(NULL, NULL, 0, EVENT_ALL_ACCESS); + } + + virtual ~AudioContext() + { + CloseHandle(event); + } + + void start() + { + CreateThread(NULL, 0, fill, this, 0, NULL); + } + + void stop() { + SetEvent(event); + } + + void suspend() { + pXAudio2->StopEngine(); + } + + void resume() { + pXAudio2->StartEngine(); + } + + static DWORD WINAPI fill(LPVOID lpParam) + { + AudioContext* context = (AudioContext*)lpParam; + + IXAudio2MasteringVoice* masteringVoice; + IXAudio2SourceVoice* sourceVoice; + uint32 bufferIndex = 0; + + if (FAILED(XAudio2Create(context->pXAudio2.GetAddressOf(), 0))) { + return 0; + } + + if (FAILED(context->pXAudio2->CreateMasteringVoice(&masteringVoice))) { + return 0; + } + + uint8* data = new uint8[SND_SIZE * SND_MAX_BUFFERS]; + + WAVEFORMATEX waveFmt = { WAVE_FORMAT_PCM, 2, 44100, 44100 * 4, 4, 16, sizeof(waveFmt) }; + + if (FAILED(context->pXAudio2->CreateSourceVoice(&sourceVoice, &waveFmt, 0, XAUDIO2_DEFAULT_FREQ_RATIO, context))) { + return 0; + } + + if (FAILED(sourceVoice->Start(0))) { + return 0; + } + + while (!Core::isQuit) + { + XAUDIO2_VOICE_STATE state; + sourceVoice->GetState(&state, XAUDIO2_VOICE_NOSAMPLESPLAYED); + + if (state.BuffersQueued < SND_MAX_BUFFERS) { + XAUDIO2_BUFFER buffer = {}; + buffer.AudioBytes = SND_SIZE; + buffer.pAudioData = data + SND_SIZE * bufferIndex; + + Sound::fill((Sound::Frame*)buffer.pAudioData, buffer.AudioBytes / 4); + + bufferIndex = (bufferIndex + 1) % SND_MAX_BUFFERS; + + sourceVoice->SubmitSourceBuffer(&buffer); + } else { + WaitForSingleObject(context->event, INFINITE); + } + } + + delete[] data; + + return 0; + } +}; + + +struct RenderContext +{ + void init(CoreWindow^ window) + { + D3D_FEATURE_LEVEL featureLevels[] = { + D3D_FEATURE_LEVEL_10_0, + D3D_FEATURE_LEVEL_9_3, + D3D_FEATURE_LEVEL_9_2, + D3D_FEATURE_LEVEL_9_1 + }; + + HRESULT ret; + ret = D3D11CreateDevice(NULL, D3D_DRIVER_TYPE_HARDWARE, NULL, 0, featureLevels, ARRAYSIZE(featureLevels), D3D11_SDK_VERSION, &device, NULL, &deviceContext); + ASSERT(ret == S_OK); + + ComPtr dxgiDevice; + ComPtr(device).As(&dxgiDevice); + + ComPtr dxgiAdapter; + dxgiDevice->GetAdapter(&dxgiAdapter); + + ComPtr dxgiFactory; + dxgiAdapter->GetParent(IID_PPV_ARGS(&dxgiFactory)); + + DXGI_SWAP_CHAIN_DESC1 desc = {}; + desc.Width = Core::width; + desc.Height = Core::height; + desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; + desc.BufferCount = 2; + desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; + desc.SampleDesc.Count = 1; + desc.SampleDesc.Quality = 0; + desc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL; + desc.Scaling = DXGI_SCALING_NONE; + desc.AlphaMode = DXGI_ALPHA_MODE_IGNORE; + + ret = dxgiFactory->CreateSwapChainForCoreWindow(device, reinterpret_cast(window), &desc, NULL, &swapChain); + ASSERT(ret == S_OK); + + dxgiDevice->SetMaximumFrameLatency(1); + } + + void present() + { + swapChain->Present(Core::settings.detail.vsync ? 1 : 0, 0); + } +}; + + +ref class View sealed : public ApplicationModel::Core::IFrameworkView +{ +private: + AudioContext audioContext; + RenderContext renderContext; + + bool m_windowVisible; + +public: + View() : m_windowVisible(true) {}; + + virtual void Initialize(ApplicationModel::Core::CoreApplicationView^ applicationView) + { + applicationView->Activated += ref new TypedEventHandler(this, &View::OnActivated); + ApplicationModel::Core::CoreApplication::Suspending += ref new EventHandler(this, &View::OnSuspending); + ApplicationModel::Core::CoreApplication::Resuming += ref new EventHandler(this, &View::OnResuming); + } + + virtual void SetWindow(CoreWindow^ window) + { + window->VisibilityChanged += ref new TypedEventHandler(this, &View::OnVisibilityChanged); + window->Closed += ref new TypedEventHandler(this, &View::OnWindowClosed); + SystemNavigationManager::GetForCurrentView()->BackRequested += ref new EventHandler(this, &View::OnBackRequested); + + Core::width = 1920; + Core::height = 1080; + + renderContext.init(window); + } + + int checkLanguage() + { + Platform::String^ language = GlobalizationPreferences::Languages->GetAt(0); + const wchar_t* id = language->Begin(); + + #define CHECK(str) (wcsstr(id, L##str"-") != 0) + + int str = STR_LANG_EN; + + if (CHECK("fr")) { + str = STR_LANG_FR; + } else if (CHECK("de")) { + str = STR_LANG_DE; + } else if (CHECK("es")) { + str = STR_LANG_ES; + } else if (CHECK("it")) { + str = STR_LANG_IT; + } else if (CHECK("pl")) { + str = STR_LANG_PL; + } else if (CHECK("pt")) { + str = STR_LANG_PT; + } else if (CHECK("ru") || CHECK("be") || CHECK("uk")) { + str = STR_LANG_RU; + } else if (CHECK("ja")) { + str = STR_LANG_JA; + } else if (CHECK("gr")) { + str = STR_LANG_GR; + } else if (CHECK("fi")) { + str = STR_LANG_FI; + } else if (CHECK("cs")) { + str = STR_LANG_CZ; + } else if (CHECK("zh")) { + str = STR_LANG_CN; + } + + return str - STR_LANG_EN; + } + + virtual void Load(Platform::String^ entryPoint) + { + // + } + + virtual void Run() + { + contentDir[0] = saveDir[0] = cacheDir[0] = 0; + + StorageFolder^ localFolder = ApplicationData::Current->LocalFolder; + wcstombs(contentDir, localFolder->Path->Data(), sizeof(contentDir)); + strcat(contentDir, "\\"); + strcpy(saveDir, contentDir); + strcpy(cacheDir, contentDir); + + Stream::addPack("content.zip"); + + GAPI::defRTV = NULL; + GAPI::defDSV = NULL; + + QueryPerformanceFrequency(&timerFreq); + QueryPerformanceCounter(&timerStart); + + Sound::channelsCount = 0; + + joyInit(); + audioContext.start(); + + Core::defLang = checkLanguage(); + + Game::init((const char*)NULL); + + while (!Core::isQuit) + { + if (m_windowVisible) + { + CoreWindow::GetForCurrentThread()->Dispatcher->ProcessEvents(CoreProcessEventsOption::ProcessAllIfPresent); + + joyUpdate(); + + if (Game::update()) { + Game::render(); + renderContext.present(); + } + } else { + CoreWindow::GetForCurrentThread()->Dispatcher->ProcessEvents(CoreProcessEventsOption::ProcessOneAndAllPending); + } + } + + audioContext.stop(); + Game::deinit(); + } + + virtual void Uninitialize() + { + // TODO save state? + } + +protected: + void OnActivated(ApplicationModel::Core::CoreApplicationView^ applicationView, ApplicationModel::Activation::IActivatedEventArgs^ args) + { + CoreWindow::GetForCurrentThread()->Activate(); + } + + void OnSuspending(Platform::Object^ sender, ApplicationModel::SuspendingEventArgs^ args) + { + audioContext.suspend(); + + ApplicationModel::SuspendingDeferral^ deferral = args->SuspendingOperation->GetDeferral(); + + create_task([this, deferral]() + { + // TODO save state? + deferral->Complete(); + }); + } + + void OnResuming(Platform::Object^ sender, Platform::Object^ args) + { + audioContext.resume(); + // TODO load state? + } + + void OnVisibilityChanged(CoreWindow^ sender, VisibilityChangedEventArgs^ args) + { + m_windowVisible = args->Visible; + } + + void OnWindowClosed(CoreWindow^ sender, CoreWindowEventArgs^ args) + { + ::Core::quit(); + } + + void OnBackRequested(Platform::Object^, BackRequestedEventArgs^ args) + { + args->Handled = true; + } +}; + + +ref class ViewSource sealed : ApplicationModel::Core::IFrameworkViewSource +{ +public: + virtual ApplicationModel::Core::IFrameworkView^ CreateView() + { + return ref new View(); + } +}; + + +[Platform::MTAThread] +int main(Platform::Array^) { + auto viewSource = ref new ViewSource(); + ApplicationModel::Core::CoreApplication::Run(viewSource); + return 0; +} \ No newline at end of file diff --git a/src/shader.h b/src/shader.h index 25306a6..754e516 100644 --- a/src/shader.h +++ b/src/shader.h @@ -10,7 +10,7 @@ struct Shader : GAPI::Shader { SPRITE = 0, FLASH, ROOM, ENTITY, MIRROR, FILTER_UPSCALE = 0, FILTER_DOWNSAMPLE, FILTER_DOWNSAMPLE_DEPTH, FILTER_GRAYSCALE, FILTER_BLUR, FILTER_ANAGLYPH, FILTER_EQUIRECTANGULAR, WATER_DROP = 0, WATER_SIMULATE, WATER_CAUSTICS, WATER_RAYS, WATER_MASK, WATER_COMPOSE, - SKY_TEXTURE = 0, SKY_CLOUDS, SKY_CLOUDS_AZURE, + SKY_TEXTURE = 0, SKY_CLOUDS, SKY_AZURE, MAX = 6 }; diff --git a/src/shaders/common.hlsl b/src/shaders/common.hlsl index c5ed1c7..9c5edd9 100644 --- a/src/shaders/common.hlsl +++ b/src/shaders/common.hlsl @@ -62,8 +62,8 @@ struct VS_INPUT { #define SAMPLE_2D_LINEAR_WRAP(T,uv) T.Sample(smpLinearWrap, uv) #define SAMPLE_2D_CMP(T,uv) T.SampleCmp(smpCmp, uv.xy, uv.z) #define SAMPLE_2D_LOD0(T,uv) T.SampleLevel(smpLinear, uv, 0) - #define SAMPLE_3D(T,uv) T.Sample(smpLinear, uv) - #define SAMPLE_CUBE(T,uv) T.Sample(smpLinear, uv) + #define SAMPLE_3D(T,uv) T.SampleLevel(smpLinearWrap, uv, 0) + #define SAMPLE_CUBE(T,uv) T.Sample(smpLinear, uv) #else sampler2D sDiffuse : register(s0); sampler2D sNormal : register(s1); @@ -81,6 +81,8 @@ struct VS_INPUT { #define SAMPLE_2D_CMP(T,uv) ((tex2D(T, uv.xy) => uv.z) ? 1 : 0) #define SAMPLE_3D(T,uv) tex3D(T, uv) #define SAMPLE_CUBE(T,uv) texCUBE(T, uv) + + #define SV_POSITION POSITION #endif float4 uParam : register( c0 ); @@ -147,15 +149,16 @@ float calcCausticsV(float3 coord) { return 0.5 + abs(sin(dot(coord.xyz, 1.0 / 1024.0) + uParam.x)) * 0.75; } +#ifndef NORMAL_AS_3D float3 calcHeightMapNormal(float2 tcR, float2 tcB, float base) { float dx = SAMPLE_2D_LOD0(sNormal, tcR).x - base; float dz = SAMPLE_2D_LOD0(sNormal, tcB).x - base; return normalize( float3(dx, 64.0 / (1024.0 * 8.0), dz) ); } +#endif -half calcFresnel(half VoH, half f0) { - half f = (half)pow(1.0 - VoH, 5.0); - return f + f0 * (1.0h - f); +float calcFresnel(float NdotV, float f0) { + return f0 + (1.0 - f0) * pow(1.0 - NdotV, 5.0); } void applyFogUW(inout float3 color, float3 coord, float waterFogDist, float waterColorDist) { diff --git a/src/shaders/compile_d3d11.bat b/src/shaders/compile_d3d11.bat index 2382817..6e38efd 100644 --- a/src/shaders/compile_d3d11.bat +++ b/src/shaders/compile_d3d11.bat @@ -25,6 +25,10 @@ call :compile filter _grayscale "/DGRAYSCALE" call :compile filter _blur "/DBLUR" call :compile filter _anaglyph "/DANAGLYPH" +call :compile sky +call :compile sky _clouds "/DSKY_CLOUDS" +call :compile sky _azure "/DSKY_AZURE" + call :compile gui diff --git a/src/shaders/sky.hlsl b/src/shaders/sky.hlsl new file mode 100644 index 0000000..2b05139 --- /dev/null +++ b/src/shaders/sky.hlsl @@ -0,0 +1,116 @@ +#define NORMAL_AS_3D + +#include "common.hlsl" + +struct VS_OUTPUT { + float4 pos : SV_POSITION; + half4 color : TEXCOORD0; + half2 texCoord : TEXCOORD1; + float3 coord : TEXCOORD2; +}; + +#ifdef VERTEX + VS_OUTPUT main(VS_INPUT In) { + VS_OUTPUT Out; + + Out.color = (half4)In.aColor; + Out.texCoord = (half2)In.aTexCoord.xy; + Out.coord = float3(In.aCoord.x, -In.aCoord.y, In.aCoord.z); + + Out.pos = mul(uViewProj, float4(In.aCoord.xyz * 5.0, 1.0)); + Out.pos.z = Out.pos.w; + + return Out; + } + +#else // PIXEL + + #ifdef SKY_AZURE + #define SKY_CLOUDS + #endif + + #ifdef SKY_CLOUDS + #define STEPS 8.0 + #define MIN_HEIGHT 2.0 + #define MAX_HEIGHT 4.0 + #define skyWind uParam.xyz + #define skyDown float3(uLightProj[0].x, uLightProj[1].x, uLightProj[2].x) + #define skyUp float3(uLightProj[0].y, uLightProj[1].y, uLightProj[2].y) + #define sunDir float3(uLightProj[0].z, uLightProj[1].z, uLightProj[2].z) + #define sunSize uLightProj[3].z + #define sunColor float3(uLightProj[0].w, uLightProj[1].w, uLightProj[2].w) + #define sunGlare uLightProj[3].w + #define cloudsDown uPosScale[0].xyz + #define cloudsUp uPosScale[1].xyz + + // based on https://www.shadertoy.com/view/XsVGz3 / https://www.shadertoy.com/view/XslGRr + float noise3D(float3 p) { + p = p * 0.15 + skyWind; + return SAMPLE_3D(sNormal, p).x; + } + + float density(float3 pos) { + float den = noise3D(pos) * 3.0 - 2.0 + (pos.y - MIN_HEIGHT); + float edge = 1.0 - smoothstep(MIN_HEIGHT, MAX_HEIGHT, pos.y); + den = clamp(den * edge * edge, 0.0, 1.0); + return den; + } + + float3 raymarching(float2 screenPos, float3 dir, float t0, float t1, float3 backCol) { + float dither = SAMPLE_2D_POINT_WRAP(sMask, screenPos * (1.0 / 8.0)).x; + + float3 step = dir * ((t1 - t0) / STEPS); + float3 pos = dir * t0 + step * dither; + float4 sum = 0.0; + + for (float i = 0.0; i < STEPS; i++) { + float den = density(pos); + + if (den > 0.01) { + float dif = max(0.0, den - density(pos + 0.3 * sunDir)) * 4.0; + + float4 col = float4(lerp(cloudsUp, cloudsDown, den), den); + float3 lin = sunColor * dif + 1.0; + + col.rgb *= lin; + + col.a *= 0.5; + col.rgb *= col.a; + sum = sum + col * (1.0 - sum.a); + } + + pos += step; + } + + sum = clamp(sum, 0.0, 1.0); + + float h = dir.y; + sum.rgb = lerp(sum.rgb, backCol, exp(-20.0 * h * h) ); + + return lerp(backCol, sum.xyz, sum.a); + } + #endif + + half4 main(VS_OUTPUT In) : COLOR0 { + float3 dir = normalize(In.coord); + + #ifdef SKY_AZURE + float3 col = lerp(skyDown, skyUp, dir.y); + #else + float3 col = SAMPLE_2D_LINEAR(sDiffuse, In.texCoord).xyz * In.color.xyz; + #endif + + #ifdef SKY_CLOUDS + float sun = clamp(sunSize + dot(sunDir, dir), 0.0, 1.0); + col += sunColor * pow(sun, sunGlare); + + float2 dist = float2(MIN_HEIGHT, MAX_HEIGHT) / dir.y; + + if (dist.x > 0.0) { + col = raymarching(In.pos.xy, dir, dist.x, dist.y, col); + } + #endif + + return half4(col, 1.0h); + } +#endif diff --git a/src/shaders/water_compose.hlsl b/src/shaders/water_compose.hlsl index fc588c4..5f3abe8 100644 --- a/src/shaders/water_compose.hlsl +++ b/src/shaders/water_compose.hlsl @@ -30,9 +30,9 @@ VS_OUTPUT main(VS_INPUT In) { Out.pos = mul(uViewProj, float4(coord, 1.0)); Out.hpos = Out.pos.xyw; Out.viewVec.xyz = uViewPos.xyz - coord; + Out.lightVec = uLightPos[0].xyz - coord; Out.viewVec.y = abs(Out.viewVec.y); Out.lightVec.y = abs(Out.lightVec.y); - Out.lightVec = uLightPos[0].xyz - coord; Out.viewVec.w = step(uPosScale[0].y, uViewPos.y); @@ -63,7 +63,7 @@ half4 main(VS_OUTPUT In) : COLOR0 { half3 refr = lerp(refrA.xyz, refrB.xyz, refrA.w); half3 refl = SAMPLE_2D_LINEAR(sReflect, float2(tc.x, tc.y) + dudv * uParam.w).xyz; - half fresnel = calcFresnel(max(0.0, dot(normal, viewVec)), 0.12); + half fresnel = calcFresnel(abs(dot(normal, viewVec)), 0.12); half mask = SAMPLE_2D_POINT(sMask, In.maskCoord).r; half4 color = half4(lerp(refr, refl, fresnel), mask); diff --git a/src/shaders/water_rays.hlsl b/src/shaders/water_rays.hlsl index da95581..ff776b5 100644 --- a/src/shaders/water_rays.hlsl +++ b/src/shaders/water_rays.hlsl @@ -33,9 +33,9 @@ float boxIntersect(float3 rayPos, float3 rayDir, float3 center, float3 hsize) { #ifdef _GAPI_GXM float4 main(VS_OUTPUT In) : COLOR0 { float2 pixelCoord = float2(__pixel_x(), __pixel_y()); -#else -float4 main(VS_OUTPUT In/*, float2 pixelCoord: VPOS*/) : COLOR0 { - float2 pixelCoord = 0.0; +#else defined(_GAPI_D3D11 +float4 main(VS_OUTPUT In) : COLOR0 { + float2 pixelCoord = In.pos.xy; #endif float3 viewVec = normalize(In.viewVec); diff --git a/src/sound.h b/src/sound.h index f8691c8..29e9c7e 100644 --- a/src/sound.h +++ b/src/sound.h @@ -8,7 +8,7 @@ #define DECODE_OGG -#if !defined(_OS_PSP) && !defined(_OS_WEB) && !defined(_OS_PSV) && !defined(_OS_3DS) && !defined(_OS_XBOX) +#if !defined(_OS_PSP) && !defined(_OS_WEB) && !defined(_OS_PSV) && !defined(_OS_3DS) && !defined(_OS_XBOX) && !defined(_OS_XB1) #define DECODE_MP3 #endif diff --git a/src/utils.h b/src/utils.h index 1a9e48e..2ec5854 100644 --- a/src/utils.h +++ b/src/utils.h @@ -23,6 +23,20 @@ #define LOG printf #endif + #if defined(_OS_XBOX) || defined(_OS_XB1) + #define MAX_LOG_LENGTH 1024 + + #undef LOG + void LOG(const char *format, ...) { + char str[MAX_LOG_LENGTH]; + va_list arglist; + va_start(arglist, format); + _vsnprintf(str, MAX_LOG_LENGTH, format, arglist); + va_end(arglist); + OutputDebugStringA(str); + } + #endif + #else #define ASSERT(expr) @@ -50,20 +64,6 @@ #define LOG(...) __android_log_print(ANDROID_LOG_INFO,"OpenLara",__VA_ARGS__) #endif -#ifdef _OS_XBOX - #define MAX_LOG_LENGTH 1024 - - #undef LOG - void LOG(const char *format, ...) { - char str[MAX_LOG_LENGTH]; - va_list arglist; - va_start(arglist, format); - _vsnprintf(str, MAX_LOG_LENGTH, format, arglist); - va_end(arglist); - OutputDebugStringA(str); - } -#endif - #ifdef _OS_PSP extern "C" { @@ -1572,6 +1572,8 @@ char contentDir[255]; #define STREAM_BUFFER_SIZE (16 * 1024) +#define MAX_PACKS 32 + struct Stream { typedef void (Callback)(Stream *stream, void *userData); Callback *callback; @@ -1584,12 +1586,144 @@ struct Stream { char *buffer; int bufferIndex; + bool buffering; + uint32 baseOffset; + + struct Pack + { + Stream* stream; + uint8* table; + uint32 count; + + struct FileInfo + { + uint32 size; + uint32 offset; + }; + + bool findFile(const char* name, FileInfo &info) + { + if (!table || !name || !name[0]) { + return false; + } + + uint16 len = (uint16)strlen(name); + uint8* ptr = table; + + for (uint32 i = 0; i < count; i++) + { + uint32 magic; + memcpy(&magic, ptr, sizeof(magic)); + if (magic != 0x02014B50) { + ASSERT(false); + return false; + } + + uint16 nameLen, extraLen, infoLen; + memcpy(&nameLen, ptr + 28, sizeof(nameLen)); + memcpy(&extraLen, ptr + 30, sizeof(extraLen)); + + if ((nameLen == len) && (memcmp(ptr + 46, name, len) == 0)) + { + uint16 compression; + memcpy(&compression, ptr + 10, sizeof(compression)); + + if (compression != 0) + { + ASSERT(false); + return false; + } + + memcpy(&info.size, ptr + 24, sizeof(info.size)); + memcpy(&info.offset, ptr + 42, sizeof(info.offset)); + + stream->setPos(info.offset); + magic = stream->readLE32(); + + if (magic != 0x04034B50) { + ASSERT(false); + return false; + } + stream->seek(22); + nameLen = stream->readLE16(); + extraLen = stream->readLE16(); + + info.offset += 4 + 22 + 2 + 2 + nameLen + extraLen; + + return true; + } + + memcpy(&infoLen, ptr + 32, sizeof(infoLen)); + + ptr += 46 + nameLen + extraLen + infoLen; + } + + return false; + } + + Pack(const char *name) : stream(NULL), table(NULL), count(0) + { + stream = new Stream(name); + stream->buffering = false; + stream->setPos(stream->size - 22); + uint32 magic = stream->readLE32(); + + if (magic != 0x06054B50) + { + ASSERT(false); + return; + } + + stream->seek(6); + count = stream->readLE16(); + uint32 tableSize = stream->readLE32(); + uint32 tableOffset = stream->readLE32(); + + stream->setPos(tableOffset); + + table = new uint8[tableSize]; + stream->raw(table, tableSize); + } + + ~Pack() { + delete stream; + delete[] table; + } + }; + + static Pack* packs[MAX_PACKS]; + + static bool addPack(const char *name) + { + if (!existsContent(name)) { + return false; + } + + for (int i = 0; i < MAX_PACKS; i++) + { + if (!packs[i]) + { + packs[i] = new Pack(name); + return true; + } + } + return false; + } + + static void deinit() + { + for (int i = 0; i < MAX_PACKS; i++) + { + if (!packs[i]) break; + delete packs[i]; + } + } Stream(const char *name, const void *data, int size, Callback *callback = NULL, void *userData = NULL) : callback(callback), userData(userData), f(NULL), data((char*)data), name(NULL), size(size), pos(0), buffer(NULL) { this->name = String::copy(name); } - Stream(const char *name, Callback *callback = NULL, void *userData = NULL) : callback(callback), userData(userData), f(NULL), data(NULL), name(NULL), size(-1), pos(0), buffer(NULL) { + Stream(const char *name, Callback *callback = NULL, void *userData = NULL) : callback(callback), userData(userData), f(NULL), data(NULL), name(NULL), size(-1), pos(0), buffer(NULL), buffering(true), baseOffset(0) { if (!name && callback) { callback(NULL, userData); delete this; @@ -1600,10 +1734,45 @@ struct Stream { ASSERT(false); } + Stream::Pack::FileInfo info; + char path[256]; + + for (int i = 0; i < MAX_PACKS; i++) + { + if (!packs[i]) break; + + if (packs[i]->findFile(name, info)) + { + path[0] = 0; + if (contentDir[0] && (!cacheDir[0] || !strstr(name, cacheDir))) { + strcpy(path, contentDir); + } + strcat(path, packs[i]->stream->name); + fixBackslash(path); + + f = fopen(path, "rb"); + if (!f) { + LOG("error loading file from pack \"%s -> %s\"\n", packs[i]->stream->name, name); + ASSERT(false); + return; + } + baseOffset = info.offset; + fseek(f, info.offset, SEEK_SET); + size = info.size; + + fpos = 0; + bufferIndex = -1; + + this->name = String::copy(name); + if (callback) callback(this, userData); + return; + } + } + path[0] = 0; if (contentDir[0] && (!cacheDir[0] || !strstr(name, cacheDir))) { - strcat(path, contentDir); + strcpy(path, contentDir); } strcat(path, name); fixBackslash(path); @@ -1627,14 +1796,12 @@ struct Stream { fseek(f, 0, SEEK_END); size = (int32)ftell(f); fseek(f, 0, SEEK_SET); - fpos = 0; + fpos = 0; bufferIndex = -1; this->name = String::copy(name); - - if (callback) - callback(this, userData); + if (callback) callback(this, userData); } } @@ -1685,6 +1852,15 @@ struct Stream { } static bool existsContent(const char *name) { + for (uint32 i = 0; i < MAX_PACKS; i++) + { + if (!packs[i]) break; + + Pack::FileInfo info; + if (packs[i]->findFile(name, info)) + return true; + } + char fileName[1024]; strcpy(fileName, contentDir); strcat(fileName, name); @@ -1704,6 +1880,18 @@ struct Stream { if (!count) return; if (f) { + + if (!buffering) { + if (fpos != pos) { + fseek(f, baseOffset + pos, SEEK_SET); + fpos = pos; + } + fread(data, 1, count, f); + pos += count; + fpos += count; + return; + } + uint8 *ptr = (uint8*)data; while (count > 0) { @@ -1712,16 +1900,16 @@ struct Stream { if (bufferIndex != bIndex) { bufferIndex = bIndex; - size_t readed; + int readed; int part; if (fpos == pos) { part = min(count / STREAM_BUFFER_SIZE * STREAM_BUFFER_SIZE, size - fpos); if (part > STREAM_BUFFER_SIZE) { - readed = fread(ptr, 1, part, f); + readed = (int)fread(ptr, 1, part, f); #ifdef TEST_SLOW_FIO - LOG("%s read %d + %d\n", name, fpos, (int)readed); + LOG("%s read %d + %d\n", name, fpos, readed); Sleep(5); #endif @@ -1742,7 +1930,7 @@ struct Stream { if (fpos != bufferIndex * STREAM_BUFFER_SIZE) { fpos = bufferIndex * STREAM_BUFFER_SIZE; - fseek(f, fpos, SEEK_SET); + fseek(f, baseOffset + fpos, SEEK_SET); #ifdef TEST_SLOW_FIO LOG("%s seek %d\n", name, fpos); @@ -1755,7 +1943,7 @@ struct Stream { } part = min(STREAM_BUFFER_SIZE, size - fpos); - readed = fread(buffer, 1, part, f); + readed = (int)fread(buffer, 1, part, f); #ifdef TEST_SLOW_FIO LOG("%s read %d + %d\n", name, fpos, readed); @@ -1829,6 +2017,7 @@ struct Stream { } }; +Stream::Pack* Stream::packs[MAX_PACKS]; #ifdef OS_FILEIO_CACHE void osDataWrite(Stream *stream, const char *dir) {