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 0000000..6b8e2cb Binary files /dev/null and b/src/platform/xb1/Assets/LargeTile.scale-200.png differ 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 0000000..d5e72e2 Binary files /dev/null and b/src/platform/xb1/Assets/SmallTile.scale-200.png differ diff --git a/src/platform/xb1/Assets/SplashScreen.scale-200.png b/src/platform/xb1/Assets/SplashScreen.scale-200.png new file mode 100644 index 0000000..3ef8086 Binary files /dev/null and b/src/platform/xb1/Assets/SplashScreen.scale-200.png differ 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 0000000..78f8b23 Binary files /dev/null and b/src/platform/xb1/Assets/Square150x150Logo.scale-200.png differ 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 0000000..42fb2bd Binary files /dev/null and b/src/platform/xb1/Assets/Square44x44Logo.altform-unplated_targetsize-48.png differ diff --git a/src/platform/xb1/Assets/Square44x44Logo.scale-200.png b/src/platform/xb1/Assets/Square44x44Logo.scale-200.png new file mode 100644 index 0000000..8893058 Binary files /dev/null and b/src/platform/xb1/Assets/Square44x44Logo.scale-200.png differ 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 0000000..42fb2bd Binary files /dev/null and b/src/platform/xb1/Assets/Square44x44Logo.targetsize-48.png differ diff --git a/src/platform/xb1/Assets/StoreLogo.scale-200.png b/src/platform/xb1/Assets/StoreLogo.scale-200.png new file mode 100644 index 0000000..98ba5a8 Binary files /dev/null and b/src/platform/xb1/Assets/StoreLogo.scale-200.png differ 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 0000000..12e41d0 Binary files /dev/null and b/src/platform/xb1/Assets/Wide310x150Logo.scale-200.png differ 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 0000000..fc69764 Binary files /dev/null and b/src/platform/xb1/OpenLara_TemporaryKey.pfx differ diff --git a/src/platform/xb1/Package.StoreAssociation.xml b/src/platform/xb1/Package.StoreAssociation.xml new file mode 100644 index 0000000..b6f680e --- /dev/null +++ b/src/platform/xb1/Package.StoreAssociation.xml @@ -0,0 +1,371 @@ + + + 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) {