diff --git a/sdk/include/jpeg/libjpeg.vcxproj b/sdk/include/jpeg/libjpeg.vcxproj index 95cdbd8cee..87d1504053 100644 --- a/sdk/include/jpeg/libjpeg.vcxproj +++ b/sdk/include/jpeg/libjpeg.vcxproj @@ -13,6 +13,10 @@ Release x64 + + VerifiedDX11ASAN + x64 + VerifiedDX11 x64 @@ -56,6 +60,15 @@ MultiByte x64 + + StaticLibrary + false + v143 + false + MultiByte + x64 + true + StaticLibrary v143 @@ -81,6 +94,10 @@ + + + + @@ -110,6 +127,12 @@ $(xrGameDir)bin_dbg\$(Platform)\$(Configuration)\ $(xrIntDir)$(ProjectName)\ + + E:\STALKER\X-Ray Source\x_ray_1602_VS13\xray-16\src\3rd party;$(IncludePath);$(xrSdkDir)include; + C:\Program Files (x86)\Windows Kits\8.1\Lib\winv6.3\um\x86;$(LibraryPath) + $(xrGameDir)bin_dbg\$(Platform)\$(Configuration)\ + $(xrIntDir)$(ProjectName)\ + E:\STALKER\X-Ray Source\x_ray_1602_VS13\xray-16\src\3rd party;$(IncludePath);$(xrSdkDir)include; C:\Program Files (x86)\Windows Kits\8.1\Lib\winv6.3\um\x86;$(LibraryPath) @@ -215,6 +238,32 @@ false + + + Disabled + false + ..\;%(AdditionalIncludeDirectories) + NotSet + ProgramDatabase + false + _DISABLE_VECTOR_ANNOTATION;_DISABLE_STRING_ANNOTATION;USE_VERIFY_IN_RELEASE;_VC80_UPGRADE=0x0710;_SILENCE_STDEXT_HASH_DEPRECATION_WARNINGS;%(PreprocessorDefinitions) + Neither + Level3 + false + Disabled + false + stdcpp17 + true + + + true + true + true + + + false + + ..\;%(AdditionalIncludeDirectories) diff --git a/sdk/include/ogg/libogg_static.vcxproj b/sdk/include/ogg/libogg_static.vcxproj index cacca512c1..bfd98b427f 100644 --- a/sdk/include/ogg/libogg_static.vcxproj +++ b/sdk/include/ogg/libogg_static.vcxproj @@ -13,6 +13,10 @@ Release x64 + + VerifiedDX11ASAN + x64 + VerifiedDX11 x64 @@ -49,6 +53,12 @@ Unicode false + + StaticLibrary + v120 + Unicode + false + StaticLibrary v143 @@ -77,6 +87,13 @@ Unicode x64 + + v143 + StaticLibrary + Unicode + x64 + true + StaticLibrary true @@ -101,6 +118,10 @@ + + + + @@ -125,6 +146,10 @@ $(SolutionDir)..\$(Platform)\$(Configuration)\ $(xrIntDir)$(ProjectName)\ + + $(SolutionDir)..\$(Platform)\$(Configuration)\ + $(xrIntDir)$(ProjectName)\ + $(SolutionDir)..\$(Platform)\$(Configuration)\ $(xrIntDir)$(ProjectName)\ @@ -149,6 +174,11 @@ .lib libogg_static + + $(xrGameDir)bin_dbg\$(Platform)\$(Configuration)\ + .lib + libogg_static + $(xrGameDir)bin_dbg\$(Platform)\$(Configuration)\ .lib @@ -259,6 +289,34 @@ false + + + X64 + + + Disabled + false + Neither + ..\include;%(AdditionalIncludeDirectories) + _DISABLE_VECTOR_ANNOTATION;_DISABLE_STRING_ANNOTATION;USE_VERIFY_IN_RELEASE;WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) + NotSet + + + ProgramDatabase + 4244;%(DisableSpecificWarnings) + false + false + Disabled + false + Level4 + CompileAsC + stdcpp17 + true + + + false + + X64 diff --git a/sdk/include/theora/libtheora_static.vcxproj b/sdk/include/theora/libtheora_static.vcxproj index ebd210f0d4..94b823e1a9 100644 --- a/sdk/include/theora/libtheora_static.vcxproj +++ b/sdk/include/theora/libtheora_static.vcxproj @@ -13,6 +13,10 @@ Release x64 + + VerifiedDX11ASAN + x64 + VerifiedDX11 x64 @@ -55,6 +59,14 @@ false x64 + + StaticLibrary + v143 + Unicode + false + x64 + true + StaticLibrary v143 @@ -84,6 +96,11 @@ + + + + + @@ -113,6 +130,11 @@ $(xrIntDir)$(ProjectName)\ libtheora_static + + $(xrGameDir)bin_dbg\$(Platform)\$(Configuration)\ + $(xrIntDir)$(ProjectName)\ + libtheora_static + $(xrGameDir)bin_dbg\$(Platform)\$(Configuration)\ $(xrIntDir)$(ProjectName)\ @@ -223,6 +245,34 @@ false + + + X64 + + + Disabled + false + Neither + ..\..\include;..\..\lib;%(AdditionalIncludeDirectories) + _DISABLE_VECTOR_ANNOTATION;_DISABLE_STRING_ANNOTATION;USE_VERIFY_IN_RELEASE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;_BIND_TO_CURRENT_CRT_VERSION;WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) + + + ProgramDatabase + 4244;4267;4057;4100;4245;%(DisableSpecificWarnings) + NotSet + false + Level4 + false + Disabled + false + CompileAsC + stdcpp17 + true + + + false + + X64 @@ -283,11 +333,13 @@ $(IntDir)%(Filename)1.obj $(IntDir)%(Filename)1.obj $(IntDir)%(Filename)1.obj + $(IntDir)%(Filename)1.obj $(IntDir)%(Filename)1.obj $(IntDir)%(Filename)1.xdc $(IntDir)%(Filename)1.xdc $(IntDir)%(Filename)1.xdc $(IntDir)%(Filename)1.xdc + $(IntDir)%(Filename)1.xdc $(IntDir)%(Filename)1.xdc @@ -300,6 +352,7 @@ true true true + true true @@ -312,11 +365,13 @@ $(IntDir)%(Filename)1.obj $(IntDir)%(Filename)1.obj $(IntDir)%(Filename)1.obj + $(IntDir)%(Filename)1.obj $(IntDir)%(Filename)1.obj $(IntDir)%(Filename)1.xdc $(IntDir)%(Filename)1.xdc $(IntDir)%(Filename)1.xdc $(IntDir)%(Filename)1.xdc + $(IntDir)%(Filename)1.xdc $(IntDir)%(Filename)1.xdc @@ -328,11 +383,13 @@ $(IntDir)%(Filename)1.obj $(IntDir)%(Filename)1.obj $(IntDir)%(Filename)1.obj + $(IntDir)%(Filename)1.obj $(IntDir)%(Filename)1.obj $(IntDir)%(Filename)1.xdc $(IntDir)%(Filename)1.xdc $(IntDir)%(Filename)1.xdc $(IntDir)%(Filename)1.xdc + $(IntDir)%(Filename)1.xdc $(IntDir)%(Filename)1.xdc diff --git a/sdk/include/vorbis/libvorbis_static.vcxproj b/sdk/include/vorbis/libvorbis_static.vcxproj index f38cb0e1e0..6fe78e18da 100644 --- a/sdk/include/vorbis/libvorbis_static.vcxproj +++ b/sdk/include/vorbis/libvorbis_static.vcxproj @@ -13,6 +13,10 @@ Release x64 + + VerifiedDX11ASAN + x64 + VerifiedDX11 x64 @@ -55,6 +59,14 @@ false x64 + + StaticLibrary + v143 + Unicode + false + x64 + true + StaticLibrary v143 @@ -84,6 +96,11 @@ + + + + + @@ -109,6 +126,10 @@ $(xrGameDir)bin_dbg\$(Platform)\$(Configuration)\ $(xrIntDir)$(ProjectName)\ + + $(xrGameDir)bin_dbg\$(Platform)\$(Configuration)\ + $(xrIntDir)$(ProjectName)\ + $(xrGameDir)bin_dbg\$(Platform)\$(Configuration)\ $(xrIntDir)$(ProjectName)\ @@ -218,6 +239,34 @@ false + + + X64 + + + Disabled + false + Neither + ..\..\include;%(AdditionalIncludeDirectories) + _DISABLE_VECTOR_ANNOTATION;_DISABLE_STRING_ANNOTATION;USE_VERIFY_IN_RELEASE;WIN32;ANALYSIS;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) + NotSet + + + ProgramDatabase + 4244;4100;4267;4189;4305;4127;4706;%(DisableSpecificWarnings) + false + Level4 + false + Disabled + false + CompileAsC + stdcpp17 + true + + + false + + X64 diff --git a/sdk/include/vorbis/libvorbisfile_static.vcxproj b/sdk/include/vorbis/libvorbisfile_static.vcxproj index 48d879f505..2defbfa054 100644 --- a/sdk/include/vorbis/libvorbisfile_static.vcxproj +++ b/sdk/include/vorbis/libvorbisfile_static.vcxproj @@ -13,6 +13,10 @@ Release x64 + + VerifiedDX11ASAN + x64 + VerifiedDX11 x64 @@ -53,6 +57,13 @@ Unicode x64 + + StaticLibrary + v143 + Unicode + x64 + true + StaticLibrary v143 @@ -82,6 +93,11 @@ + + + + + @@ -107,6 +123,10 @@ $(xrGameDir)bin_dbg\$(Platform)\$(Configuration)\ $(xrIntDir)$(ProjectName)\ + + $(xrGameDir)bin_dbg\$(Platform)\$(Configuration)\ + $(xrIntDir)$(ProjectName)\ + $(xrGameDir)bin_dbg\$(Platform)\$(Configuration)\ $(xrIntDir)$(ProjectName)\ @@ -212,6 +232,31 @@ false + + + X64 + + + ..\;%(AdditionalIncludeDirectories) + _DISABLE_VECTOR_ANNOTATION;_DISABLE_STRING_ANNOTATION;USE_VERIFY_IN_RELEASE;WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) + NotSet + + + ProgramDatabase + Disabled + Neither + Level3 + false + Disabled + false + stdcpp17 + true + + + $(OutDir)$(TargetName)$(TargetExt) + false + + X64 diff --git a/src/3rd party/DXERR/DXERR.vcxproj b/src/3rd party/DXERR/DXERR.vcxproj index 63237008b0..a32ea3ea61 100644 --- a/src/3rd party/DXERR/DXERR.vcxproj +++ b/src/3rd party/DXERR/DXERR.vcxproj @@ -13,6 +13,10 @@ Release x64 + + VerifiedDX11ASAN + x64 + VerifiedDX11 x64 @@ -56,6 +60,15 @@ Unicode x64 + + StaticLibrary + false + v143 + false + Unicode + x64 + true + StaticLibrary v143 @@ -81,6 +94,10 @@ + + + + @@ -106,6 +123,11 @@ $(xrGameDir)bin_dbg\$(Platform)\$(Configuration)\ $(xrIntDir)$(ProjectName)\ + + DxErr + $(xrGameDir)bin_dbg\$(Platform)\$(Configuration)\ + $(xrIntDir)$(ProjectName)\ + DxErr $(xrGameDir)bin_dbg\$(Platform)\$(Configuration)\ @@ -208,6 +230,32 @@ false + + + Disabled + false + NotSet + ProgramDatabase + false + _DISABLE_VECTOR_ANNOTATION;_DISABLE_STRING_ANNOTATION;USE_VERIFY_IN_RELEASE;_VC80_UPGRADE=0x0710;_SILENCE_STDEXT_HASH_DEPRECATION_WARNINGS;%(PreprocessorDefinitions) + Neither + Level3 + false + true + Disabled + false + stdcpp17 + true + + + true + true + true + + + false + + AdvancedVectorExtensions diff --git a/src/3rd party/NVTT/NVTT.vcxproj b/src/3rd party/NVTT/NVTT.vcxproj index 9c68b2c5e5..183d0bdac9 100644 --- a/src/3rd party/NVTT/NVTT.vcxproj +++ b/src/3rd party/NVTT/NVTT.vcxproj @@ -13,6 +13,10 @@ Release x64 + + VerifiedDX11ASAN + x64 + VerifiedDX11 x64 @@ -128,6 +132,8 @@ + + @@ -209,6 +215,15 @@ v143 x64 + + StaticLibrary + false + true + MultiByte + v143 + x64 + true + StaticLibrary v143 @@ -234,6 +249,10 @@ + + + + @@ -255,6 +274,10 @@ $(xrGameDir)bin_dbg\$(Platform)\$(Configuration)\ $(xrIntDir)$(ProjectName)\ + + $(xrGameDir)bin_dbg\$(Platform)\$(Configuration)\ + $(xrIntDir)$(ProjectName)\ + $(xrGameDir)bin_dbg\$(Platform)\$(Configuration)\ $(xrIntDir)$(ProjectName)\ @@ -364,6 +387,34 @@ false + + + Disabled + false + include;src;src\nvcore;src\nvtt\squish;%(AdditionalIncludeDirectories) + _DISABLE_VECTOR_ANNOTATION;_DISABLE_STRING_ANNOTATION;USE_VERIFY_IN_RELEASE;WIN32;NDEBUG;_MBCS;%(PreprocessorDefinitions) + NotSet + Neither + false + false + 4005 + ProgramDatabase + Level3 + false + Disabled + false + stdcpp17 + true + + + true + true + true + + + false + + include;src;src\nvcore;src\nvtt\squish;%(AdditionalIncludeDirectories) diff --git a/src/3rd party/OpenAL-new/OpenAL-new.vcxproj b/src/3rd party/OpenAL-new/OpenAL-new.vcxproj index e43d573dc7..ca3507fb4f 100644 --- a/src/3rd party/OpenAL-new/OpenAL-new.vcxproj +++ b/src/3rd party/OpenAL-new/OpenAL-new.vcxproj @@ -13,6 +13,10 @@ Release x64 + + VerifiedDX11ASAN + x64 + VerifiedDX11 x64 @@ -59,6 +63,15 @@ false x64 + + StaticLibrary + v143 + false + MultiByte + false + x64 + true + StaticLibrary v143 @@ -81,6 +94,10 @@ + + + + @@ -101,9 +118,13 @@ $(ProjectName) .lib $(xrGameDir)bin_dbg\$(Platform)\$(Configuration)\ + $(xrGameDir)bin_dbg\$(Platform)\$(Configuration)\ $(xrIntDir)$(ProjectName)\ + $(xrIntDir)$(ProjectName)\ $(ProjectName) + $(ProjectName) .lib + .lib $(xrGameDir)bin_dbg\$(Platform)\$(Configuration)\ $(xrIntDir)$(ProjectName)\ $(ProjectName) @@ -247,6 +268,51 @@ %(AdditionalOptions) /machine:x64 + + + $(SolutionDir)3rd party\OpenAL-new\include;$(SolutionDir)3rd party\OpenAL-new;$(SolutionDir)3rd party\OpenAL-new\common;%(AdditionalIncludeDirectories) + %(AdditionalOptions) /w14640 + $(IntDir) + Default + true + 4065;4127;4268;4324;5030;5051 + false + Disabled + stdcpp17 + false + Disabled + NotUsing + MultiThreadedDLL + false + false + Level4 + _DISABLE_VECTOR_ANNOTATION;_DISABLE_STRING_ANNOTATION;%(PreprocessorDefinitions);USE_VERIFY_IN_RELEASE;WIN32;_WINDOWS;NDEBUG;AL_LIBTYPE_STATIC;AL_BUILD_LIBRARY;AL_ALEXT_PROTOTYPES;ALC_API=;AL_API=;_WIN32;NOMINMAX;RESTRICT=__restrict;_CRT_SECURE_NO_WARNINGS;_DISABLE_CONSTEXPR_MUTEX_CONSTRUCTOR;_DISABLE_VECTOR_ANNOTATION;_DISABLE_STRING_ANNOTATION + $(IntDir) + ProgramDatabase + false + false + false + false + false + true + Neither + + + %(PreprocessorDefinitions);WIN32;_WINDOWS;NDEBUG;AL_LIBTYPE_STATIC;AL_BUILD_LIBRARY;AL_ALEXT_PROTOTYPES;ALC_API=;AL_API=;_WIN32;NOMINMAX;RESTRICT=__restrict;_CRT_SECURE_NO_WARNINGS + $(SolutionDir)3rd party\OpenAL-new\include;$(SolutionDir)3rd party\OpenAL-new;$(SolutionDir)3rd party\OpenAL-new\common;%(AdditionalIncludeDirectories) + + + $(SolutionDir)3rd party\OpenAL-new\include;$(SolutionDir)3rd party\OpenAL-new;$(SolutionDir)3rd party\OpenAL-new\common;%(AdditionalIncludeDirectories) + $(ProjectDir)/$(IntDir) + %(Filename).h + %(Filename).tlb + %(Filename)_i.c + %(Filename)_p.c + + + %(AdditionalOptions) /machine:x64 + + $(SolutionDir)3rd party\OpenAL-new\include;$(SolutionDir)3rd party\OpenAL-new;$(SolutionDir)3rd party\OpenAL-new\common;%(AdditionalIncludeDirectories) diff --git a/src/3rd party/crypto/crypto.vcxproj b/src/3rd party/crypto/crypto.vcxproj index 5bbe3e0e99..b49af64d69 100644 --- a/src/3rd party/crypto/crypto.vcxproj +++ b/src/3rd party/crypto/crypto.vcxproj @@ -13,6 +13,10 @@ Release x64 + + VerifiedDX11ASAN + x64 + VerifiedDX11 x64 @@ -54,6 +58,14 @@ false x64 + + StaticLibrary + v143 + MultiByte + false + x64 + true + StaticLibrary v143 @@ -79,6 +91,10 @@ + + + + @@ -111,6 +127,12 @@ $(xrGameDir)bin_dbg\$(Platform)\$(Configuration)\ $(xrIntDir)$(ProjectName)\ + + $(ProjectName) + .lib + $(xrGameDir)bin_dbg\$(Platform)\$(Configuration)\ + $(xrIntDir)$(ProjectName)\ + $(ProjectName) .lib @@ -215,6 +237,31 @@ Default + + + openssl;$(xrSdkDir)include;$(SolutionDir)include;%(AdditionalIncludeDirectories) + _DISABLE_VECTOR_ANNOTATION;_DISABLE_STRING_ANNOTATION;USE_VERIFY_IN_RELEASE;CRYPTO_BUILD;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + ProgramDatabase + NotSet + false + Neither + false + 4005;4996 + Disabled + false + Level4 + false + Disabled + false + stdcpp17 + true + + + $(xrLibDir)$(TargetName).lib + true + Default + + openssl;$(xrSdkDir)include;$(SolutionDir)include;%(AdditionalIncludeDirectories) diff --git a/src/3rd party/crypto/xr_dsa.cpp b/src/3rd party/crypto/xr_dsa.cpp index c38ad66006..48b4316f4e 100644 --- a/src/3rd party/crypto/xr_dsa.cpp +++ b/src/3rd party/crypto/xr_dsa.cpp @@ -1,6 +1,7 @@ #include "xr_dsa.h" #include "crypto.h" #include +#include "../xrCore/profiler.h" namespace crypto { @@ -30,6 +31,7 @@ shared_str const xr_dsa::sign (private_key_t const & priv_key, u8 const* data, u32 const data_size) { + PROF_EVENT("crypto::xr_dsa::sign"); BN_bin2bn(priv_key.m_value, sizeof(priv_key.m_value), m_dsa->priv_key); unsigned int sign_size = DSA_size(m_dsa); @@ -185,4 +187,4 @@ void xr_dsa::generate_params() #endif //#ifdef DEBUG -} //namespace crypto \ No newline at end of file +} //namespace crypto diff --git a/src/3rd party/cximage/cximage.vcxproj b/src/3rd party/cximage/cximage.vcxproj index 592b7ebebb..634986ce98 100644 --- a/src/3rd party/cximage/cximage.vcxproj +++ b/src/3rd party/cximage/cximage.vcxproj @@ -13,6 +13,10 @@ Release x64 + + VerifiedDX11ASAN + x64 + VerifiedDX11 x64 @@ -59,6 +63,16 @@ false x64 + + StaticLibrary + v143 + false + MultiByte + false + false + x64 + true + StaticLibrary v143 @@ -88,6 +102,11 @@ + + + + + @@ -125,6 +144,13 @@ $(xrGameDir)bin_dbg\$(Platform)\$(Configuration)\ $(xrIntDir)$(ProjectName)\ + + $(ProjectName) + .lib + $(VC_LibraryPath_x86);$(WindowsSDK_LibraryPath_x86) + $(xrGameDir)bin_dbg\$(Platform)\$(Configuration)\ + $(xrIntDir)$(ProjectName)\ + $(ProjectName) .lib @@ -286,6 +312,47 @@ $(xrLibDir)$(TargetName).lib + + + Disabled + false + Neither + false + $(XRAY_16X_LIBS);$(SolutionDir);%(AdditionalIncludeDirectories) + _DISABLE_VECTOR_ANNOTATION;_DISABLE_STRING_ANNOTATION;USE_VERIFY_IN_RELEASE;WIN32;NDEBUG;_LIB;JAS_WIN_MSVC_BUILD;CXIMAGE_BUILD;%(PreprocessorDefinitions) + NotSet + 4995;4100;4702;%(DisableSpecificWarnings) + ProgramDatabase + false + Level4 + false + Disabled + false + stdcpp17 + true + + + NDEBUG;%(PreprocessorDefinitions) + 0x0809 + + + /ignore:4075 %(AdditionalOptions) + $(OutDir)$(ProjectName).lib + $(XRAY_16X_LIBS)\jpeg\libraries\Release;$(xrLibDir);%(AdditionalLibraryDirectories) + true + true + false + + + true + .\Release/cximage.bsc + + + + $(XRAY_16X_LIBS)\jpeg-8c\Release\;$(xrLibDir);%(AdditionalLibraryDirectories) + $(xrLibDir)$(TargetName).lib + + $(XRAY_16X_LIBS);$(SolutionDir);%(AdditionalIncludeDirectories) diff --git a/src/3rd party/fastdelegate/fastdelegate.h b/src/3rd party/fastdelegate/fastdelegate.h index aa722586c7..fdb443d436 100644 --- a/src/3rd party/fastdelegate/fastdelegate.h +++ b/src/3rd party/fastdelegate/fastdelegate.h @@ -1,71 +1,78 @@ -// FastDelegate.h -// Efficient delegates in C++ that generate only two lines of asm code! +// FastDelegate.hpp +// Efficient delegates in C++ that generate only two lines of asm code! // Documentation is found at http://www.codeproject.com/cpp/FastDelegate.asp // -// - Don Clugston, Mar 2004. -// Major contributions were made by Jody Hagins. +// - Don Clugston, Mar 2004. +// Major contributions were made by Jody Hagins. +// Version 2.0 by Pa�l Jim�nez. +// Version 2.0.1 by Benjamin YanXiang Huang +// // History: -// 24-Apr-04 1.0 * Submitted to CodeProject. +// 24-Apr-04 1.0 * Submitted to CodeProject. // 28-Apr-04 1.1 * Prevent most unsafe uses of evil static function hack. -// * Improved syntax for horrible_cast (thanks Paul Bludov). -// * Tested on Metrowerks MWCC and Intel ICL (IA32) -// * Compiled, but not run, on Comeau C++ and Intel Itanium ICL. -// 27-Jun-04 1.2 * Now works on Borland C++ Builder 5.5 -// * Now works on /clr "managed C++" code on VC7, VC7.1 -// * Comeau C++ now compiles without warnings. -// * Prevent the virtual inheritance case from being used on -// VC6 and earlier, which generate incorrect code. -// * Improved warning and error messages. Non-standard hacks -// now have compile-time checks to make them safer. -// * implicit_cast used instead of static_cast in many cases. -// * If calling a const member function, a const class pointer can be used. -// * MakeDelegate() global helper function added to simplify pass-by-value. -// * Added fastdelegate.clear() +// * Improved syntax for horrible_cast (thanks Paul Bludov). +// * Tested on Metrowerks MWCC and Intel ICL (IA32) +// * Compiled, but not run, on Comeau C++ and Intel Itanium ICL. +// 27-Jun-04 1.2 * Now works on Borland C++ Builder 5.5 +// * Now works on /clr "managed C++" code on VC7, VC7.1 +// * Comeau C++ now compiles without warnings. +// * Prevent the virtual inheritance case from being used on +// VC6 and earlier, which generate incorrect code. +// * Improved warning and error messages. Non-standard hacks +// now have compile-time checks to make them safer. +// * implicit_cast used instead of static_cast in many cases. +// * If calling a const member function, a const class pointer can be used. +// * MakeDelegate() global helper function added to simplify pass-by-value. +// * Added fastdelegate.clear() // 16-Jul-04 1.2.1* Workaround for gcc bug (const member function pointers in templates) // 30-Oct-04 1.3 * Support for (non-void) return values. -// * No more workarounds in client code! -// MSVC and Intel now use a clever hack invented by John Dlugosz: -// - The FASTDELEGATEDECLARE workaround is no longer necessary. -// - No more warning messages for VC6 -// * Less use of macros. Error messages should be more comprehensible. -// * Added include guards -// * Added FastDelegate::empty() to test if invocation is safe (Thanks Neville Franks). -// * Now tested on VS 2005 Express Beta, PGI C++ +// * No more workarounds in client code! +// MSVC and Intel now use a clever hack invented by John Dlugosz: +// - The FASTDELEGATEDECLARE workaround is no longer necessary. +// - No more warning messages for VC6 +// * Less use of macros. Error messages should be more comprehensible. +// * Added include guards +// * Added FastDelegate::empty() to test if invocation is safe (Thanks Neville Franks). +// * Now tested on VS 2005 Express Beta, PGI C++ // 24-Dec-04 1.4 * Added DelegateMemento, to allow collections of disparate delegates. // * <,>,<=,>= comparison operators to allow storage in ordered containers. -// * Substantial reduction of code size, especially the 'Closure' class. -// * Standardised all the compiler-specific workarounds. +// * Substantial reduction of code size, especially the 'Closure' class. +// * Standardised all the compiler-specific workarounds. // * MFP conversion now works for CodePlay (but not yet supported in the full code). // * Now compiles without warnings on _any_ supported compiler, including BCC 5.5.1 -// * New syntax: FastDelegate< int (char *, double) >. +// * New syntax: FastDelegate< int (char *, double) >. // 14-Feb-05 1.4.1* Now treats =0 as equivalent to .clear(), ==0 as equivalent to .empty(). (Thanks elfric). -// * Now tested on Intel ICL for AMD64, VS2005 Beta for AMD64 and Itanium. +// * Now tested on Intel ICL for AMD64, VS2005 Beta for AMD64 and Itanium. // 30-Mar-05 1.5 * Safebool idiom: "if (dg)" is now equivalent to "if (!dg.empty())" -// * Fully supported by CodePlay VectorC +// * Fully supported by CodePlay VectorC // * Bugfix for Metrowerks: empty() was buggy because a valid MFP can be 0 on MWCC! // * More optimal assignment,== and != operators for static function pointers. - -#ifndef FASTDELEGATE_H -#define FASTDELEGATE_H +// 06-Feb-13 2.0 * GetMemento is now const +// * Added hash method that makes use of new unchecked function unsafe_horrible_cast +// * Removed VC6 code +// * Use variadic templates (C++11) +// * Added MakeDelegate for plain function pointers +// * Use static_assert for compile-time checks (C++11) +// 21-Jan-14 2.0.1* Fixed 2 typos (line 393 & 429) where a static_cast should have been a static_assert. +// 21-Jun-14 2.0.2* Fixed incorrect union member name in the SimplifyMemFunc struct. + +#ifndef FASTDELEGATE_HPP +#define FASTDELEGATE_HPP #if _MSC_VER > 1000 #pragma once #endif // _MSC_VER > 1000 -#include // to allow <,> comparisons - -////////////////////////////////////////////////// -#define xr_stdcall __stdcall -/////////////////////////////////////////////////// +#include // to allow <,> comparisons //////////////////////////////////////////////////////////////////////////////// -// Configuration options +// Configuration options // //////////////////////////////////////////////////////////////////////////////// // Uncomment the following #define for optimally-sized delegates. // In this case, the generated asm code is almost identical to the code you'd get // if the compiler had native support for delegates. -// It will not work on systems where sizeof(dataptr) < sizeof(codeptr). +// It will not work on systems where sizeof(dataptr) < sizeof(codeptr). // Thus, it will not work for DOS compilers using the medium model. // It will also probably fail on some DSP systems. #define FASTDELEGATE_USESTATICFUNCTIONHACK @@ -75,7 +82,7 @@ //#define FASTDELEGATE_ALLOW_FUNCTION_TYPE_SYNTAX //////////////////////////////////////////////////////////////////////////////// -// Compiler identification for workarounds +// Compiler identification for workarounds // //////////////////////////////////////////////////////////////////////////////// @@ -83,17 +90,11 @@ // many vendors fraudulently define Microsoft's identifiers. #if defined(_MSC_VER) && !defined(__MWERKS__) && !defined(__VECTOR_C) && !defined(__ICL) && !defined(__BORLANDC__) #define FASTDLGT_ISMSVC - -#if (_MSC_VER <1300) // Many workarounds are required for VC6. -#define FASTDLGT_VC6 -#pragma warning(disable:4786) // disable this ridiculous warning -#endif - #endif // Does the compiler uses Microsoft's member function pointer structure? // If so, it needs special treatment. -// Metrowerks CodeWarrior, Intel, and CodePlay fraudulently define Microsoft's +// Metrowerks CodeWarrior, Intel, and CodePlay fraudulently define Microsoft's // identifier, _MSC_VER. We need to filter Metrowerks out. #if defined(_MSC_VER) && !defined(__MWERKS__) #define FASTDLGT_MICROSOFT_MFP @@ -119,2859 +120,858 @@ #define FASTDELEGATE_ALLOW_FUNCTION_TYPE_SYNTAX #endif -#ifdef __GNUC__ // Workaround GCC bug #8271 - // At present, GCC doesn't recognize constness of MFPs in templates +#ifdef __GNUC__ // Workaround GCC bug #8271 + // At present, GCC doesn't recognize constness of MFPs in templates #define FASTDELEGATE_GCC_BUG_8271 #endif + //////////////////////////////////////////////////////////////////////////////// -// General tricks used in this code +// General tricks used in this code // // (a) Error messages are generated by typdefing an array of negative size to // generate compile-time errors. // (b) Warning messages on MSVC are generated by declaring unused variables, and -// enabling the "variable XXX is never used" warning. +// enabling the "variable XXX is never used" warning. // (c) Unions are used in a few compiler-specific cases to perform illegal casts. // (d) For Microsoft and Intel, when adjusting the 'this' pointer, it's cast to // (char *) first to ensure that the correct number of *bytes* are added. // //////////////////////////////////////////////////////////////////////////////// -// Helper templates +// Helper templates // //////////////////////////////////////////////////////////////////////////////// -namespace fastdelegate -{ - namespace detail - { - // we'll hide the implementation details in a nested namespace. - - // implicit_cast< > - // I believe this was originally going to be in the C++ standard but - // was left out by accident. It's even milder than static_cast. - // I use it instead of static_cast<> to emphasize that I'm not doing - // anything nasty. - // Usage is identical to static_cast<> - template - inline OutputClass implicit_cast(InputClass input) - { - return input; - } - - // horrible_cast< > - // This is truly evil. It completely subverts C++'s type system, allowing you - // to cast from any class to any other class. Technically, using a union - // to perform the cast is undefined behaviour (even in C). But we can see if - // it is OK by checking that the union is the same size as each of its members. - // horrible_cast<> should only be used for compiler-specific workarounds. - // Usage is identical to reinterpret_cast<>. - - // This union is declared outside the horrible_cast because BCC 5.5.1 - // can't inline a function with a nested class, and gives a warning. - template - union horrible_union - { - OutputClass out; - InputClass in; - }; - - template - inline OutputClass horrible_cast(const InputClass input) - { - horrible_union u; - // Cause a compile-time error if in, out and u are not the same size. - // If the compile fails here, it means the compiler has peculiar - // unions which would prevent the cast from working. - typedef int ERROR_CantUseHorrible_cast[sizeof(InputClass) == sizeof(u) - && sizeof(InputClass) == sizeof(OutputClass) - ? 1 - : -1]; - u.in = input; - return u.out; - } - - //////////////////////////////////////////////////////////////////////////////// - // Workarounds - // - //////////////////////////////////////////////////////////////////////////////// - - // Backwards compatibility: This macro used to be necessary in the virtual inheritance - // case for Intel and Microsoft. Now it just forward-declares the class. -#define FASTDELEGATEDECLARE(CLASSNAME) class CLASSNAME; - - // Prevent use of the static function hack with the DOS medium model. +namespace fastdelegate { +namespace detail { // we'll hide the implementation details in a nested namespace. + +// implicit_cast< > +// I believe this was originally going to be in the C++ standard but +// was left out by accident. It's even milder than static_cast. +// I use it instead of static_cast<> to emphasize that I'm not doing +// anything nasty. +// Usage is identical to static_cast<> +template +inline OutputClass implicit_cast(InputClass input){ + return input; +} + +// horrible_cast< > +// This is truly evil. It completely subverts C++'s type system, allowing you +// to cast from any class to any other class. Technically, using a union +// to perform the cast is undefined behaviour (even in C). But we can see if +// it is OK by checking that the union is the same size as each of its members. +// horrible_cast<> should only be used for compiler-specific workarounds. +// Usage is identical to reinterpret_cast<>. + +// This union is declared outside the horrible_cast because BCC 5.5.1 +// can't inline a function with a nested class, and gives a warning. +template +union horrible_union{ + OutputClass out; + InputClass in; +}; + +template +inline OutputClass horrible_cast(const InputClass input){ + horrible_union u; + // Cause a compile-time error if in, out and u are not the same size. + // If the compile fails here, it means the compiler has peculiar + // unions which would prevent the cast from working. + static_assert(sizeof(InputClass)==sizeof(u) && sizeof(InputClass)==sizeof(OutputClass), "Cannot use horrible_cast<>"); + u.in = input; + return u.out; +} + +template +inline OutputClass unsafe_horrible_cast(const InputClass input){ + horrible_union u; + u.in = input; + return u.out; +} + +//////////////////////////////////////////////////////////////////////////////// +// Workarounds +// +//////////////////////////////////////////////////////////////////////////////// + +// Backwards compatibility: This macro used to be necessary in the virtual inheritance +// case for Intel and Microsoft. Now it just forward-declares the class. +#define FASTDELEGATEDECLARE(CLASSNAME) class CLASSNAME; + +// Prevent use of the static function hack with the DOS medium model. #ifdef __MEDIUM__ #undef FASTDELEGATE_USESTATICFUNCTIONHACK #endif - // DefaultVoid - a workaround for 'void' templates in VC6. - // - // (1) VC6 and earlier do not allow 'void' as a default template argument. - // (2) They also doesn't allow you to return 'void' from a function. - // - // Workaround for (1): Declare a dummy type 'DefaultVoid' which we use - // when we'd like to use 'void'. We convert it into 'void' and back - // using the templates DefaultVoidToVoid<> and VoidToDefaultVoid<>. - // Workaround for (2): On VC6, the code for calling a void function is - // identical to the code for calling a non-void function in which the - // return value is never used, provided the return value is returned - // in the EAX register, rather than on the stack. - // This is true for most fundamental types such as int, enum, void *. - // Const void * is the safest option since it doesn't participate - // in any automatic conversions. But on a 16-bit compiler it might - // cause extra code to be generated, so we disable it for all compilers - // except for VC6 (and VC5). -#ifdef FASTDLGT_VC6 -// VC6 workaround -typedef const void * DefaultVoid; -#else - // On any other compiler, just use a normal void. - typedef void DefaultVoid; -#endif +typedef void DefaultVoid; + +// Translate from 'DefaultVoid' to 'void'. +// Everything else is unchanged +template +struct DefaultVoidToVoid { typedef T type; }; + +template <> +struct DefaultVoidToVoid { typedef void type; }; + +// Translate from 'void' into 'DefaultVoid' +// Everything else is unchanged +template +struct VoidToDefaultVoid { typedef T type; }; + +template <> +struct VoidToDefaultVoid { typedef DefaultVoid type; }; + + + +//////////////////////////////////////////////////////////////////////////////// +// Fast Delegates, part 1: +// +// Conversion of member function pointer to a standard form +// +//////////////////////////////////////////////////////////////////////////////// - // Translate from 'DefaultVoid' to 'void'. - // Everything else is unchanged - template - struct DefaultVoidToVoid - { - typedef T type; - }; - - template <> - struct DefaultVoidToVoid - { - typedef void type; - }; - - // Translate from 'void' into 'DefaultVoid' - // Everything else is unchanged - template - struct VoidToDefaultVoid - { - typedef T type; - }; - - template <> - struct VoidToDefaultVoid - { - typedef DefaultVoid type; - }; - - - //////////////////////////////////////////////////////////////////////////////// - // Fast Delegates, part 1: - // - // Conversion of member function pointer to a standard form - // - //////////////////////////////////////////////////////////////////////////////// - - // GenericClass is a fake class, ONLY used to provide a type. - // It is vitally important that it is never defined, so that the compiler doesn't - // think it can optimize the invocation. For example, Borland generates simpler - // code if it knows the class only uses single inheritance. - - // Compilers using Microsoft's structure need to be treated as a special case. +// GenericClass is a fake class, ONLY used to provide a type. +// It is vitally important that it is never defined, so that the compiler doesn't +// think it can optimize the invocation. For example, Borland generates simpler +// code if it knows the class only uses single inheritance. + +// Compilers using Microsoft's structure need to be treated as a special case. #ifdef FASTDLGT_MICROSOFT_MFP #ifdef FASTDLGT_HASINHERITANCE_KEYWORDS - // For Microsoft and Intel, we want to ensure that it's the most efficient type of MFP - // (4 bytes), even when the /vmg option is used. Declaring an empty class - // would give 16 byte pointers in this case.... - class __single_inheritance GenericClass; + // For Microsoft and Intel, we want to ensure that it's the most efficient type of MFP + // (4 bytes), even when the /vmg option is used. Declaring an empty class + // would give 16 byte pointers in this case.... + class __single_inheritance GenericClass; #endif - // ...but for Codeplay, an empty class *always* gives 4 byte pointers. - // If compiled with the /clr option ("managed C++"), the JIT compiler thinks - // it needs to load GenericClass before it can call any of its functions, - // (compiles OK but crashes at runtime!), so we need to declare an - // empty class to make it happy. - // Codeplay and VC4 can't cope with the unknown_inheritance case either. - class GenericClass - { - }; + // ...but for Codeplay, an empty class *always* gives 4 byte pointers. + // If compiled with the /clr option ("managed C++"), the JIT compiler thinks + // it needs to load GenericClass before it can call any of its functions, + // (compiles OK but crashes at runtime!), so we need to declare an + // empty class to make it happy. + // Codeplay and VC4 can't cope with the unknown_inheritance case either. + class GenericClass {}; #else - class GenericClass; + class GenericClass; #endif - // The size of a single inheritance member function pointer. - const int SINGLE_MEMFUNCPTR_SIZE = sizeof(void (xr_stdcall GenericClass::*)()); - - // SimplifyMemFunc< >::Convert() - // - // A template function that converts an arbitrary member function pointer into the - // simplest possible form of member function pointer, using a supplied 'this' pointer. - // According to the standard, this can be done legally with reinterpret_cast<>. - // For (non-standard) compilers which use member function pointers which vary in size - // depending on the class, we need to use knowledge of the internal structure of a - // member function pointer, as used by the compiler. Template specialization is used - // to distinguish between the sizes. Because some compilers don't support partial - // template specialisation, I use full specialisation of a wrapper struct. - - // general case -- don't know how to convert it. Force a compile failure - template - struct SimplifyMemFunc - { - template - inline static GenericClass* xr_stdcall Convert(X* pthis, XFuncType function_to_bind, - GenericMemFuncType& bound_func) - { - // Unsupported member function type -- force a compile failure. - // (it's illegal to have a array with negative size). - typedef char ERROR_Unsupported_member_function_pointer_on_this_compiler[N - 100]; - return 0; - } - }; - - // For compilers where all member func ptrs are the same size, everything goes here. - // For non-standard compilers, only single_inheritance classes go here. - template <> - struct SimplifyMemFunc - { - template - inline static GenericClass* xr_stdcall Convert(X* pthis, XFuncType function_to_bind, - GenericMemFuncType& bound_func) - { +// The size of a single inheritance member function pointer. +const int SINGLE_MEMFUNCPTR_SIZE = sizeof(void (GenericClass::*)()); + +// SimplifyMemFunc< >::Convert() +// +// A template function that converts an arbitrary member function pointer into the +// simplest possible form of member function pointer, using a supplied 'this' pointer. +// According to the standard, this can be done legally with reinterpret_cast<>. +// For (non-standard) compilers which use member function pointers which vary in size +// depending on the class, we need to use knowledge of the internal structure of a +// member function pointer, as used by the compiler. Template specialization is used +// to distinguish between the sizes. Because some compilers don't support partial +// template specialisation, I use full specialisation of a wrapper struct. + +// general case -- don't know how to convert it. Force a compile failure +template +struct SimplifyMemFunc { + template + inline static GenericClass *Convert(X *pthis, XFuncType function_to_bind, + GenericMemFuncType &bound_func) { + // Unsupported member function type -- force a compile failure. + // (it's illegal to have a array with negative size). + static_assert(N - 100, "Unsupported member function pointer on this compiler"); + return 0; + } +}; + +// For compilers where all member func ptrs are the same size, everything goes here. +// For non-standard compilers, only single_inheritance classes go here. +template <> +struct SimplifyMemFunc { + template + inline static GenericClass *Convert(X *pthis, XFuncType function_to_bind, + GenericMemFuncType &bound_func) { #if defined __DMC__ - // Digital Mars doesn't allow you to cast between abitrary PMF's, - // even though the standard says you can. The 32-bit compiler lets you - // static_cast through an int, but the DOS compiler doesn't. - bound_func = horrible_cast(function_to_bind); + // Digital Mars doesn't allow you to cast between abitrary PMF's, + // even though the standard says you can. The 32-bit compiler lets you + // static_cast through an int, but the DOS compiler doesn't. + bound_func = horrible_cast(function_to_bind); #else - bound_func = reinterpret_cast(function_to_bind); + bound_func = reinterpret_cast(function_to_bind); #endif - return reinterpret_cast(pthis); - } - }; + return reinterpret_cast(pthis); + } +}; - //////////////////////////////////////////////////////////////////////////////// - // Fast Delegates, part 1b: - // - // Workarounds for Microsoft and Intel - // - //////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +// Fast Delegates, part 1b: +// +// Workarounds for Microsoft and Intel +// +//////////////////////////////////////////////////////////////////////////////// - // Compilers with member function pointers which violate the standard (MSVC, Intel, Codeplay), - // need to be treated as a special case. +// Compilers with member function pointers which violate the standard (MSVC, Intel, Codeplay), +// need to be treated as a special case. #ifdef FASTDLGT_MICROSOFT_MFP - // We use unions to perform horrible_casts. I would like to use #pragma pack(push, 1) - // at the start of each function for extra safety, but VC6 seems to ICE - // intermittently if you do this inside a template. - - // __multiple_inheritance classes go here - // Nasty hack for Microsoft and Intel (IA32 and Itanium) - template <> - struct SimplifyMemFunc - { - template - inline static GenericClass* xr_stdcall Convert(X* pthis, XFuncType function_to_bind, - GenericMemFuncType& bound_func) - { - // We need to use a horrible_cast to do this conversion. - // In MSVC, a multiple inheritance member pointer is internally defined as: - union - { - XFuncType func; - - struct - { - GenericMemFuncType funcaddress; // points to the actual member function - int delta; // #BYTES to be added to the 'this' pointer - } s; - } u; - // Check that the horrible_cast will work - typedef int ERROR_CantUsehorrible_cast[sizeof(function_to_bind) == sizeof(u.s) ? 1 : -1]; - u.func = function_to_bind; - bound_func = u.s.funcaddress; - return reinterpret_cast(reinterpret_cast(pthis) + u.s.delta); - } - }; - - // virtual inheritance is a real nuisance. It's inefficient and complicated. - // On MSVC and Intel, there isn't enough information in the pointer itself to - // enable conversion to a closure pointer. Earlier versions of this code didn't - // work for all cases, and generated a compile-time error instead. - // But a very clever hack invented by John M. Dlugosz solves this problem. - // My code is somewhat different to his: I have no asm code, and I make no - // assumptions about the calling convention that is used. - - // In VC++ and ICL, a virtual_inheritance member pointer - // is internally defined as: - struct MicrosoftVirtualMFP - { - void (GenericClass::*codeptr)(); // points to the actual member function - int delta; // #bytes to be added to the 'this' pointer - int vtable_index; // or 0 if no virtual inheritance - }; - - // The CRUCIAL feature of Microsoft/Intel MFPs which we exploit is that the - // m_codeptr member is *always* called, regardless of the values of the other - // members. (This is *not* true for other compilers, eg GCC, which obtain the - // function address from the vtable if a virtual function is being called). - // Dlugosz's trick is to make the codeptr point to a probe function which - // returns the 'this' pointer that was used. - - // Define a generic class that uses virtual inheritance. - // It has a trival member function that returns the value of the 'this' pointer. - struct GenericVirtualClass : virtual public GenericClass - { - typedef GenericVirtualClass* (GenericVirtualClass::*ProbePtrType)(); - GenericVirtualClass* GetThis() { return this; } - }; - - // __virtual_inheritance classes go here - template <> - struct SimplifyMemFunc - { - template - inline static GenericClass* xr_stdcall Convert(X* pthis, XFuncType function_to_bind, - GenericMemFuncType& bound_func) - { -#pragma pack(push) -#pragma pack(1) - union - { - XFuncType func; - GenericClass* (X::*ProbeFunc)(); - MicrosoftVirtualMFP s; - } u; -#pragma pack(pop) - - u.func = function_to_bind; - bound_func = reinterpret_cast(u.s.codeptr); - union - { - GenericVirtualClass::ProbePtrType virtfunc; - MicrosoftVirtualMFP s; - } u2; - // Check that the horrible_cast<>s will work - typedef int ERROR_CantUsehorrible_cast[sizeof(function_to_bind) == sizeof(u.s) - && sizeof(function_to_bind) == sizeof(u.ProbeFunc) - && sizeof(u2.virtfunc) == sizeof(u2.s) - ? 1 - : -1]; - // Unfortunately, taking the address of a MF prevents it from being inlined, so - // this next line can't be completely optimised away by the compiler. - u2.virtfunc = &GenericVirtualClass::GetThis; - u.s.codeptr = u2.s.codeptr; - return (pthis->*u.ProbeFunc)(); - } - }; - -#if (_MSC_VER <1300) - - // Nasty hack for Microsoft Visual C++ 6.0 - // unknown_inheritance classes go here -// There is a compiler bug in MSVC6 which generates incorrect code in this case!! +// We use unions to perform horrible_casts. I would like to use #pragma pack(push, 1) +// at the start of each function for extra safety, but VC6 seems to ICE +// intermittently if you do this inside a template. + +// __multiple_inheritance classes go here +// Nasty hack for Microsoft and Intel (IA32 and Itanium) +template<> +struct SimplifyMemFunc< SINGLE_MEMFUNCPTR_SIZE + sizeof(int) > { + template + inline static GenericClass *Convert(X *pthis, XFuncType function_to_bind, + GenericMemFuncType &bound_func) { + // We need to use a horrible_cast to do this conversion. + // In MSVC, a multiple inheritance member pointer is internally defined as: + union { + XFuncType func; + struct { + GenericMemFuncType funcaddress; // points to the actual member function + int delta; // #BYTES to be added to the 'this' pointer + }s; + } u; + // Check that the horrible_cast will work + static_assert(sizeof(function_to_bind)==sizeof(u.s), "Cannot use horrible_cast<>"); + u.func = function_to_bind; + bound_func = u.s.funcaddress; + return reinterpret_cast(reinterpret_cast(pthis) + u.s.delta); + } +}; + +// virtual inheritance is a real nuisance. It's inefficient and complicated. +// On MSVC and Intel, there isn't enough information in the pointer itself to +// enable conversion to a closure pointer. Earlier versions of this code didn't +// work for all cases, and generated a compile-time error instead. +// But a very clever hack invented by John M. Dlugosz solves this problem. +// My code is somewhat different to his: I have no asm code, and I make no +// assumptions about the calling convention that is used. + +// In VC++ and ICL, a virtual_inheritance member pointer +// is internally defined as: +struct MicrosoftVirtualMFP { + void (GenericClass::*codeptr)(); // points to the actual member function + int delta; // #bytes to be added to the 'this' pointer + int vtable_index; // or 0 if no virtual inheritance +}; +// The CRUCIAL feature of Microsoft/Intel MFPs which we exploit is that the +// m_codeptr member is *always* called, regardless of the values of the other +// members. (This is *not* true for other compilers, eg GCC, which obtain the +// function address from the vtable if a virtual function is being called). +// Dlugosz's trick is to make the codeptr point to a probe function which +// returns the 'this' pointer that was used. + +// Define a generic class that uses virtual inheritance. +// It has a trival member function that returns the value of the 'this' pointer. +struct GenericVirtualClass : virtual public GenericClass +{ + typedef GenericVirtualClass * (GenericVirtualClass::*ProbePtrType)(); + GenericVirtualClass * GetThis() { return this; } +}; + +// __virtual_inheritance classes go here +template <> +struct SimplifyMemFunc +{ + + template + inline static GenericClass *Convert(X *pthis, XFuncType function_to_bind, + GenericMemFuncType &bound_func) { + union { + XFuncType func; + GenericClass* (X::*ProbeFunc)(); + MicrosoftVirtualMFP s; + } u; + u.func = function_to_bind; + bound_func = reinterpret_cast(u.s.codeptr); + union { + GenericVirtualClass::ProbePtrType virtfunc; + MicrosoftVirtualMFP s; + } u2; + // Check that the horrible_cast<>s will work + static_assert(sizeof(function_to_bind)==sizeof(u.s) && sizeof(function_to_bind)==sizeof(u.ProbeFunc) && sizeof(u2.virtfunc)==sizeof(u2.s), "Cannot use horrible_cast<>"); + /*typedef int ERROR_CantUsehorrible_cast[sizeof(function_to_bind)==sizeof(u.s) + && sizeof(function_to_bind)==sizeof(u.ProbeFunc) + && sizeof(u2.virtfunc)==sizeof(u2.s) ? 1 : -1];*/ + // Unfortunately, taking the address of a MF prevents it from being inlined, so + // this next line can't be completely optimised away by the compiler. + u2.virtfunc = &GenericVirtualClass::GetThis; + u.s.codeptr = u2.s.codeptr; + return (pthis->*u.ProbeFunc)(); + } +}; + +// Nasty hack for Microsoft and Intel (IA32 and Itanium) +// unknown_inheritance classes go here +// This is probably the ugliest bit of code I've ever written. Look at the casts! +// There is a compiler bug in MSVC6 which prevents it from using this code. template <> struct SimplifyMemFunc { - template - inline static GenericClass * xr_stdcall Convert(X *pthis, XFuncType function_to_bind, - GenericMemFuncType &bound_func) { - // There is an apalling but obscure compiler bug in MSVC6 and earlier: - // vtable_index and 'vtordisp' are always set to 0 in the - // unknown_inheritance case! - // This means that an incorrect function could be called!!! - // Compiling with the /vmg option leads to potentially incorrect code. - // This is probably the reason that the IDE has a user interface for specifying - // the /vmg option, but it is disabled - you can only specify /vmg on - // the command line. In VC1.5 and earlier, the compiler would ICE if it ever - // encountered this situation. - // It is OK to use the /vmg option if /vmm or /vms is specified. - - // Fortunately, the wrong function is only called in very obscure cases. - // It only occurs when a derived class overrides a virtual function declared - // in a virtual base class, and the member function - // points to the *Derived* version of that function. The problem can be - // completely averted in 100% of cases by using the *Base class* for the - // member fpointer. Ie, if you use the base class as an interface, you'll - // stay out of trouble. - // Occasionally, you might want to point directly to a derived class function - // that isn't an override of a base class. In this case, both vtable_index - // and 'vtordisp' are zero, but a virtual_inheritance pointer will be generated. - // We can generate correct code in this case. To prevent an incorrect call from - // ever being made, on MSVC6 we generate a warning, and call a function to - // make the program crash instantly. - typedef char ERROR_VC6CompilerBug[-100]; - return 0; - } + template + inline static GenericClass *Convert(X *pthis, XFuncType function_to_bind, + GenericMemFuncType &bound_func) { + // The member function pointer is 16 bytes long. We can't use a normal cast, but + // we can use a union to do the conversion. + union { + XFuncType func; + // In VC++ and ICL, an unknown_inheritance member pointer + // is internally defined as: + struct { + GenericMemFuncType funcaddress; // points to the actual member function + int delta; // #bytes to be added to the 'this' pointer + int vtordisp; // #bytes to add to 'this' to find the vtable + int vtable_index; // or 0 if no virtual inheritance + } s; + } u; + // Check that the horrible_cast will work + static_assert(sizeof(XFuncType)==sizeof(u.s), "Cannot use horrible_cast<>"); + //typedef int ERROR_CantUsehorrible_cast[sizeof(XFuncType)==sizeof(u.s)? 1 : -1]; + u.func = function_to_bind; + bound_func = u.s.funcaddress; + int virtual_delta = 0; + if (u.s.vtable_index) { // Virtual inheritance is used + // First, get to the vtable. + // It is 'vtordisp' bytes from the start of the class. + const int * vtable = *reinterpret_cast( + reinterpret_cast(pthis) + u.s.vtordisp ); + + // 'vtable_index' tells us where in the table we should be looking. + virtual_delta = u.s.vtordisp + *reinterpret_cast( + reinterpret_cast(vtable) + u.s.vtable_index); + } + // The int at 'virtual_delta' gives us the amount to add to 'this'. + // Finally we can add the three components together. Phew! + return reinterpret_cast( + reinterpret_cast(pthis) + u.s.delta + virtual_delta); + }; }; +#endif // MS/Intel hacks -#else +} // namespace detail - // Nasty hack for Microsoft and Intel (IA32 and Itanium) - // unknown_inheritance classes go here - // This is probably the ugliest bit of code I've ever written. Look at the casts! - // There is a compiler bug in MSVC6 which prevents it from using this code. - template <> - struct SimplifyMemFunc - { - template - inline static GenericClass* xr_stdcall Convert(X* pthis, XFuncType function_to_bind, - GenericMemFuncType& bound_func) - { - // The member function pointer is 16 bytes long. We can't use a normal cast, but - // we can use a union to do the conversion. - union - { - XFuncType func; - - // In VC++ and ICL, an unknown_inheritance member pointer - // is internally defined as: - struct - { - GenericMemFuncType m_funcaddress; // points to the actual member function - int delta; // #bytes to be added to the 'this' pointer - int vtordisp; // #bytes to add to 'this' to find the vtable - int vtable_index; // or 0 if no virtual inheritance - } s; - } u; - // Check that the horrible_cast will work - typedef int ERROR_CantUsehorrible_cast[sizeof(XFuncType) == sizeof(u.s) ? 1 : -1]; - u.func = function_to_bind; - bound_func = u.s.funcaddress; - int virtual_delta = 0; - if (u.s.vtable_index) - { - // Virtual inheritance is used - // First, get to the vtable. - // It is 'vtordisp' bytes from the start of the class. - const int* vtable = *reinterpret_cast( - reinterpret_cast(pthis) + u.s.vtordisp); - - // 'vtable_index' tells us where in the table we should be looking. - virtual_delta = u.s.vtordisp + *reinterpret_cast( - reinterpret_cast(vtable) + u.s.vtable_index); - } - // The int at 'virtual_delta' gives us the amount to add to 'this'. - // Finally we can add the three components together. Phew! - return reinterpret_cast( - reinterpret_cast(pthis) + u.s.delta + virtual_delta); - }; - }; -#endif // MSVC 7 and greater +//////////////////////////////////////////////////////////////////////////////// +// Fast Delegates, part 2: +// +// Define the delegate storage, and cope with static functions +// +//////////////////////////////////////////////////////////////////////////////// -#endif // MS/Intel hacks - } // namespace detail - - //////////////////////////////////////////////////////////////////////////////// - // Fast Delegates, part 2: - // - // Define the delegate storage, and cope with static functions - // - //////////////////////////////////////////////////////////////////////////////// - - // DelegateMemento -- an opaque structure which can hold an arbitary delegate. - // It knows nothing about the calling convention or number of arguments used by - // the function pointed to. - // It supplies comparison operators so that it can be stored in STL collections. - // It cannot be set to anything other than null, nor invoked directly: - // it must be converted to a specific delegate. - - // Implementation: - // There are two possible implementations: the Safe method and the Evil method. - // DelegateMemento - Safe version - // - // This implementation is standard-compliant, but a bit tricky. - // A static function pointer is stored inside the class. - // Here are the valid values: - // +-- Static pointer --+--pThis --+-- pMemFunc-+-- Meaning------+ - // | 0 | 0 | 0 | Empty | - // | !=0 |(dontcare)| Invoker | Static function| - // | 0 | !=0 | !=0* | Method call | - // +--------------------+----------+------------+----------------+ - // * For Metrowerks, this can be 0. (first virtual function in a - // single_inheritance class). - // When stored stored inside a specific delegate, the 'dontcare' entries are replaced - // with a reference to the delegate itself. This complicates the = and == operators - // for the delegate class. - - // DelegateMemento - Evil version - // - // For compilers where data pointers are at least as big as code pointers, it is - // possible to store the function pointer in the this pointer, using another - // horrible_cast. In this case the DelegateMemento implementation is simple: - // +--pThis --+-- pMemFunc-+-- Meaning---------------------+ - // | 0 | 0 | Empty | - // | !=0 | !=0* | Static function or method call| - // +----------+------------+-------------------------------+ - // * For Metrowerks, this can be 0. (first virtual function in a - // single_inheritance class). - // Note that the Sun C++ and MSVC documentation explicitly state that they - // support static_cast between void * and function pointers. - - class DelegateMemento - { - protected: - // the data is protected, not private, because many - // compilers have problems with template friends. - typedef void (detail::GenericClass::*GenericMemFuncType)(); // arbitrary MFP. - detail::GenericClass* m_pthis; - GenericMemFuncType m_pFunction; +// DelegateMemento -- an opaque structure which can hold an arbitary delegate. +// It knows nothing about the calling convention or number of arguments used by +// the function pointed to. +// It supplies comparison operators so that it can be stored in STL collections. +// It cannot be set to anything other than null, nor invoked directly: +// it must be converted to a specific delegate. + +// Implementation: +// There are two possible implementations: the Safe method and the Evil method. +// DelegateMemento - Safe version +// +// This implementation is standard-compliant, but a bit tricky. +// A static function pointer is stored inside the class. +// Here are the valid values: +// +-- Static pointer --+--pThis --+-- pMemFunc-+-- Meaning------+ +// | 0 | 0 | 0 | Empty | +// | !=0 |(dontcare)| Invoker | Static function| +// | 0 | !=0 | !=0* | Method call | +// +--------------------+----------+------------+----------------+ +// * For Metrowerks, this can be 0. (first virtual function in a +// single_inheritance class). +// When stored stored inside a specific delegate, the 'dontcare' entries are replaced +// with a reference to the delegate itself. This complicates the = and == operators +// for the delegate class. + +// DelegateMemento - Evil version +// +// For compilers where data pointers are at least as big as code pointers, it is +// possible to store the function pointer in the this pointer, using another +// horrible_cast. In this case the DelegateMemento implementation is simple: +// +--pThis --+-- pMemFunc-+-- Meaning---------------------+ +// | 0 | 0 | Empty | +// | !=0 | !=0* | Static function or method call| +// +----------+------------+-------------------------------+ +// * For Metrowerks, this can be 0. (first virtual function in a +// single_inheritance class). +// Note that the Sun C++ and MSVC documentation explicitly state that they +// support static_cast between void * and function pointers. + +class DelegateMemento { +protected: + // the data is protected, not private, because many + // compilers have problems with template friends. + typedef void (detail::GenericClass::*GenericMemFuncType)(); // arbitrary MFP. + detail::GenericClass *m_pthis; + GenericMemFuncType m_pFunction; #if !defined(FASTDELEGATE_USESTATICFUNCTIONHACK) - typedef void (xr_stdcall *GenericFuncPtr)(); // arbitrary code pointer - GenericFuncPtr m_pStaticFunction; + typedef void (*GenericFuncPtr)(); // arbitrary code pointer + GenericFuncPtr m_pStaticFunction; #endif - public: +public: #if !defined(FASTDELEGATE_USESTATICFUNCTIONHACK) - DelegateMemento() : m_pthis(0), m_pFunction(0), m_pStaticFunction(0) {}; - void clear() { - m_pthis=0; m_pFunction=0; m_pStaticFunction=0; - } + DelegateMemento() : m_pthis(0), m_pFunction(0), m_pStaticFunction(0) {}; + void clear() { + m_pthis=0; m_pFunction=0; m_pStaticFunction=0; + } #else - DelegateMemento() : m_pthis(0), m_pFunction(0) - { - }; - - void clear() - { - m_pthis = 0; - m_pFunction = 0; - } + DelegateMemento() : m_pthis(0), m_pFunction(0) {}; + void clear() { m_pthis=0; m_pFunction=0; } #endif - public: +public: #if !defined(FASTDELEGATE_USESTATICFUNCTIONHACK) - inline bool IsEqual (const DelegateMemento &x) const{ - // We have to cope with the static function pointers as a special case - if (m_pFunction!=x.m_pFunction) return false; - // the static function ptrs must either both be equal, or both be 0. - if (m_pStaticFunction!=x.m_pStaticFunction) return false; - if (m_pStaticFunction!=0) return m_pthis==x.m_pthis; - else return true; - } + inline bool IsEqual (const DelegateMemento &x) const{ + // We have to cope with the static function pointers as a special case + if (m_pFunction!=x.m_pFunction) return false; + // the static function ptrs must either both be equal, or both be 0. + if (m_pStaticFunction!=x.m_pStaticFunction) return false; + if (m_pStaticFunction!=0) return m_pthis==x.m_pthis; + else return true; + } #else // Evil Method - inline bool IsEqual(const DelegateMemento& x) const - { - return m_pthis == x.m_pthis && m_pFunction == x.m_pFunction; - } + inline bool IsEqual (const DelegateMemento &x) const{ + return m_pthis==x.m_pthis && m_pFunction==x.m_pFunction; + } #endif - // Provide a strict weak ordering for DelegateMementos. - inline bool IsLess(const DelegateMemento& right) const - { - // deal with static function pointers first + // Provide a strict weak ordering for DelegateMementos. + inline bool IsLess(const DelegateMemento &right) const { + // deal with static function pointers first #if !defined(FASTDELEGATE_USESTATICFUNCTIONHACK) - if (m_pStaticFunction !=0 || right.m_pStaticFunction!=0) - return m_pStaticFunction < right.m_pStaticFunction; + if (m_pStaticFunction !=0 || right.m_pStaticFunction!=0) + return m_pStaticFunction < right.m_pStaticFunction; #endif - if (m_pthis != right.m_pthis) return m_pthis < right.m_pthis; - // There are no ordering operators for member function pointers, - // but we can fake one by comparing each byte. The resulting ordering is - // arbitrary (and compiler-dependent), but it permits storage in ordered STL containers. - return memcmp(&m_pFunction, &right.m_pFunction, sizeof(m_pFunction)) < 0; - } - - // BUGFIX (Mar 2005): - // We can't just compare m_pFunction because on Metrowerks, - // m_pFunction can be zero even if the delegate is not empty! - inline bool operator !() const // Is it bound to anything? - { - return m_pthis == 0 && m_pFunction == 0; - } - - inline bool empty() const // Is it bound to anything? - { - return m_pthis == 0 && m_pFunction == 0; - } - - public: - DelegateMemento& operator =(const DelegateMemento& right) - { - SetMementoFrom(right); - return *this; - } - - inline bool operator <(const DelegateMemento& right) - { - return IsLess(right); - } - - inline bool operator >(const DelegateMemento& right) - { - return right.IsLess(*this); - } - - DelegateMemento(const DelegateMemento& right) : - m_pFunction(right.m_pFunction), m_pthis(right.m_pthis) + if (m_pthis !=right.m_pthis) return m_pthis < right.m_pthis; + // There are no ordering operators for member function pointers, + // but we can fake one by comparing each byte. The resulting ordering is + // arbitrary (and compiler-dependent), but it permits storage in ordered STL containers. + return std::memcmp(&m_pFunction, &right.m_pFunction, sizeof(m_pFunction)) < 0; + + } + // Provide a simple hashing method. + inline size_t Hash() const { + return reinterpret_cast(m_pthis) ^ detail::unsafe_horrible_cast(m_pFunction); + } + // BUGFIX (Mar 2005): + // We can't just compare m_pFunction because on Metrowerks, + // m_pFunction can be zero even if the delegate is not empty! + inline bool operator ! () const // Is it bound to anything? + { return m_pthis==0 && m_pFunction==0; } + inline bool empty() const // Is it bound to anything? + { return m_pthis==0 && m_pFunction==0; } +public: + DelegateMemento & operator = (const DelegateMemento &right) { + SetMementoFrom(right); + return *this; + } + inline bool operator <(const DelegateMemento &right) { + return IsLess(right); + } + inline bool operator >(const DelegateMemento &right) { + return right.IsLess(*this); + } + DelegateMemento (const DelegateMemento &right) : + m_pthis(right.m_pthis), m_pFunction(right.m_pFunction) #if !defined(FASTDELEGATE_USESTATICFUNCTIONHACK) - , m_pStaticFunction (right.m_pStaticFunction) + , m_pStaticFunction (right.m_pStaticFunction) #endif - { - } - - protected: - void SetMementoFrom(const DelegateMemento& right) - { - m_pFunction = right.m_pFunction; - m_pthis = right.m_pthis; + {} +protected: + void SetMementoFrom(const DelegateMemento &right) { + m_pFunction = right.m_pFunction; + m_pthis = right.m_pthis; #if !defined(FASTDELEGATE_USESTATICFUNCTIONHACK) - m_pStaticFunction = right.m_pStaticFunction; + m_pStaticFunction = right.m_pStaticFunction; #endif - } - }; - - - // ClosurePtr<> - // - // A private wrapper class that adds function signatures to DelegateMemento. - // It's the class that does most of the actual work. - // The signatures are specified by: - // GenericMemFunc: must be a type of GenericClass member function pointer. - // StaticFuncPtr: must be a type of function pointer with the same signature - // as GenericMemFunc. - // UnvoidStaticFuncPtr: is the same as StaticFuncPtr, except on VC6 - // where it never returns void (returns DefaultVoid instead). - - // An outer class, FastDelegateN<>, handles the invoking and creates the - // necessary typedefs. - // This class does everything else. - - namespace detail - { - template - class ClosurePtr : public DelegateMemento - { - public: - // These functions are for setting the delegate to a member function. - - // Here's the clever bit: we convert an arbitrary member function into a - // standard form. XMemFunc should be a member function of class X, but I can't - // enforce that here. It needs to be enforced by the wrapper class. - template - inline void bindmemfunc(X* pthis, XMemFunc function_to_bind) - { - m_pthis = SimplifyMemFunc - ::Convert(pthis, function_to_bind, m_pFunction); + } +}; + + +// ClosurePtr<> +// +// A private wrapper class that adds function signatures to DelegateMemento. +// It's the class that does most of the actual work. +// The signatures are specified by: +// GenericMemFunc: must be a type of GenericClass member function pointer. +// StaticFuncPtr: must be a type of function pointer with the same signature +// as GenericMemFunc. +// UnvoidStaticFuncPtr: is the same as StaticFuncPtr, except on VC6 +// where it never returns void (returns DefaultVoid instead). + +// An outer class, FastDelegateN<>, handles the invoking and creates the +// necessary typedefs. +// This class does everything else. + +namespace detail { + +template < class GenericMemFunc, class StaticFuncPtr, class UnvoidStaticFuncPtr> +class ClosurePtr : public DelegateMemento { +public: + // These functions are for setting the delegate to a member function. + + // Here's the clever bit: we convert an arbitrary member function into a + // standard form. XMemFunc should be a member function of class X, but I can't + // enforce that here. It needs to be enforced by the wrapper class. + template < class X, class XMemFunc > + inline void bindmemfunc(X *pthis, XMemFunc function_to_bind ) { + m_pthis = SimplifyMemFunc< sizeof(function_to_bind) > + ::Convert(pthis, function_to_bind, m_pFunction); #if !defined(FASTDELEGATE_USESTATICFUNCTIONHACK) - m_pStaticFunction = 0; + m_pStaticFunction = 0; #endif - } - - // For const member functions, we only need a const class pointer. - // Since we know that the member function is const, it's safe to - // remove the const qualifier from the 'this' pointer with a const_cast. - // VC6 has problems if we just overload 'bindmemfunc', so we give it a different name. - template - inline void bindconstmemfunc(const X* pthis, XMemFunc function_to_bind) - { - m_pthis = SimplifyMemFunc - ::Convert(const_cast(pthis), function_to_bind, m_pFunction); + } + // For const member functions, we only need a const class pointer. + // Since we know that the member function is const, it's safe to + // remove the const qualifier from the 'this' pointer with a const_cast. + // VC6 has problems if we just overload 'bindmemfunc', so we give it a different name. + template < class X, class XMemFunc> + inline void bindconstmemfunc(const X *pthis, XMemFunc function_to_bind) { + m_pthis= SimplifyMemFunc< sizeof(function_to_bind) > + ::Convert(const_cast(pthis), function_to_bind, m_pFunction); #if !defined(FASTDELEGATE_USESTATICFUNCTIONHACK) - m_pStaticFunction = 0; + m_pStaticFunction = 0; #endif - } -#ifdef FASTDELEGATE_GCC_BUG_8271 // At present, GCC doesn't recognize constness of MFPs in templates - template < class X, class XMemFunc> - inline void bindmemfunc(const X *pthis, XMemFunc function_to_bind) { - bindconstmemfunc(pthis, function_to_bind); + } +#ifdef FASTDELEGATE_GCC_BUG_8271 // At present, GCC doesn't recognize constness of MFPs in templates + template < class X, class XMemFunc> + inline void bindmemfunc(const X *pthis, XMemFunc function_to_bind) { + bindconstmemfunc(pthis, function_to_bind); #if !defined(FASTDELEGATE_USESTATICFUNCTIONHACK) - m_pStaticFunction = 0; + m_pStaticFunction = 0; #endif - } + } #endif - // These functions are required for invoking the stored function - inline GenericClass* GetClosureThis() const { return m_pthis; } - inline GenericMemFunc GetClosureMemPtr() const { return reinterpret_cast(m_pFunction); } + // These functions are required for invoking the stored function + inline GenericClass *GetClosureThis() const { return m_pthis; } + inline GenericMemFunc GetClosureMemPtr() const { return reinterpret_cast(m_pFunction); } - // There are a few ways of dealing with static function pointers. - // There's a standard-compliant, but tricky method. - // There's also a straightforward hack, that won't work on DOS compilers using the - // medium memory model. It's so evil that I can't recommend it, but I've - // implemented it anyway because it produces very nice asm code. +// There are a few ways of dealing with static function pointers. +// There's a standard-compliant, but tricky method. +// There's also a straightforward hack, that won't work on DOS compilers using the +// medium memory model. It's so evil that I can't recommend it, but I've +// implemented it anyway because it produces very nice asm code. #if !defined(FASTDELEGATE_USESTATICFUNCTIONHACK) - // ClosurePtr<> - Safe version - // - // This implementation is standard-compliant, but a bit tricky. - // I store the function pointer inside the class, and the delegate then - // points to itself. Whenever the delegate is copied, these self-references +// ClosurePtr<> - Safe version +// +// This implementation is standard-compliant, but a bit tricky. +// I store the function pointer inside the class, and the delegate then +// points to itself. Whenever the delegate is copied, these self-references // must be transformed, and this complicates the = and == operators. public: - // The next two functions are for operator ==, =, and the copy constructor. - // We may need to convert the m_pthis pointers, so that - // they remain as self-references. - template< class DerivedClass > - inline void CopyFrom (DerivedClass *pParent, const DelegateMemento &x) { - SetMementoFrom(x); - if (m_pStaticFunction!=0) { - // transform self references... - m_pthis=reinterpret_cast(pParent); - } - } - // For static functions, the 'static_function_invoker' class in the parent - // will be called. The parent then needs to call GetStaticFunction() to find out - // the actual function to invoke. - template < class DerivedClass, class ParentInvokerSig > - inline void bindstaticfunc(DerivedClass *pParent, ParentInvokerSig static_function_invoker, - StaticFuncPtr function_to_bind ) { - if (function_to_bind==0) { // cope with assignment to 0 - m_pFunction=0; - } else { - bindmemfunc(pParent, static_function_invoker); + // The next two functions are for operator ==, =, and the copy constructor. + // We may need to convert the m_pthis pointers, so that + // they remain as self-references. + template< class DerivedClass > + inline void CopyFrom (DerivedClass *pParent, const DelegateMemento &x) { + SetMementoFrom(x); + if (m_pStaticFunction!=0) { + // transform self references... + m_pthis=reinterpret_cast(pParent); + } + } + // For static functions, the 'static_function_invoker' class in the parent + // will be called. The parent then needs to call GetStaticFunction() to find out + // the actual function to invoke. + template < class DerivedClass, class ParentInvokerSig > + inline void bindstaticfunc(DerivedClass *pParent, ParentInvokerSig static_function_invoker, + StaticFuncPtr function_to_bind ) { + if (function_to_bind==0) { // cope with assignment to 0 + m_pFunction=0; + } else { + bindmemfunc(pParent, static_function_invoker); } - m_pStaticFunction=reinterpret_cast(function_to_bind); - } - inline UnvoidStaticFuncPtr GetStaticFunction() const { - return reinterpret_cast(m_pStaticFunction); - } + m_pStaticFunction=reinterpret_cast(function_to_bind); + } + inline UnvoidStaticFuncPtr GetStaticFunction() const { + return reinterpret_cast(m_pStaticFunction); + } #else - // ClosurePtr<> - Evil version - // - // For compilers where data pointers are at least as big as code pointers, it is - // possible to store the function pointer in the this pointer, using another - // horrible_cast. Invocation isn't any faster, but it saves 4 bytes, and - // speeds up comparison and assignment. If C++ provided direct language support - // for delegates, they would produce asm code that was almost identical to this. - // Note that the Sun C++ and MSVC documentation explicitly state that they - // support static_cast between void * and function pointers. - - template - inline void CopyFrom(DerivedClass* pParent, const DelegateMemento& right) - { - SetMementoFrom(right); - } - - // For static functions, the 'static_function_invoker' class in the parent - // will be called. The parent then needs to call GetStaticFunction() to find out - // the actual function to invoke. - // ******** EVIL, EVIL CODE! ******* - template - inline void bindstaticfunc(DerivedClass* pParent, ParentInvokerSig static_function_invoker, - StaticFuncPtr function_to_bind) - { - if (function_to_bind == 0) - { - // cope with assignment to 0 - m_pFunction = 0; - } - else - { - // We'll be ignoring the 'this' pointer, but we need to make sure we pass - // a valid value to bindmemfunc(). - bindmemfunc(pParent, static_function_invoker); - } - - // WARNING! Evil hack. We store the function in the 'this' pointer! - // Ensure that there's a compilation failure if function pointers - // and data pointers have different sizes. - // If you get this error, you need to #undef FASTDELEGATE_USESTATICFUNCTIONHACK. - typedef int ERROR_CantUseEvilMethod[sizeof(GenericClass *) == sizeof(function_to_bind) ? 1 : -1]; - m_pthis = horrible_cast(function_to_bind); - // MSVC, SunC++ and DMC accept the following (non-standard) code: - // m_pthis = static_cast(static_cast(function_to_bind)); - // BCC32, Comeau and DMC accept this method. MSVC7.1 needs __int64 instead of long - // m_pthis = reinterpret_cast(reinterpret_cast(function_to_bind)); - } - - // ******** EVIL, EVIL CODE! ******* - // This function will be called with an invalid 'this' pointer!! - // We're just returning the 'this' pointer, converted into - // a function pointer! - inline UnvoidStaticFuncPtr GetStaticFunction() const - { - // Ensure that there's a compilation failure if function pointers - // and data pointers have different sizes. - // If you get this error, you need to #undef FASTDELEGATE_USESTATICFUNCTIONHACK. - typedef int ERROR_CantUseEvilMethod[sizeof(UnvoidStaticFuncPtr) == sizeof(this) ? 1 : -1]; - return horrible_cast(this); - } +// ClosurePtr<> - Evil version +// +// For compilers where data pointers are at least as big as code pointers, it is +// possible to store the function pointer in the this pointer, using another +// horrible_cast. Invocation isn't any faster, but it saves 4 bytes, and +// speeds up comparison and assignment. If C++ provided direct language support +// for delegates, they would produce asm code that was almost identical to this. +// Note that the Sun C++ and MSVC documentation explicitly state that they +// support static_cast between void * and function pointers. + + template< class DerivedClass > + inline void CopyFrom (DerivedClass * /*pParent*/, const DelegateMemento &right) { + SetMementoFrom(right); + } + // For static functions, the 'static_function_invoker' class in the parent + // will be called. The parent then needs to call GetStaticFunction() to find out + // the actual function to invoke. + // ******** EVIL, EVIL CODE! ******* + template < class DerivedClass, class ParentInvokerSig> + inline void bindstaticfunc(DerivedClass *pParent, ParentInvokerSig static_function_invoker, + StaticFuncPtr function_to_bind) { + if (function_to_bind==0) { // cope with assignment to 0 + m_pFunction=0; + } else { + // We'll be ignoring the 'this' pointer, but we need to make sure we pass + // a valid value to bindmemfunc(). + bindmemfunc(pParent, static_function_invoker); + } + + // WARNING! Evil hack. We store the function in the 'this' pointer! + // Ensure that there's a compilation failure if function pointers + // and data pointers have different sizes. + // If you get this error, you need to #undef FASTDELEGATE_USESTATICFUNCTIONHACK. + static_assert(sizeof(GenericClass *)==sizeof(function_to_bind), "Cannot use evil method"); + m_pthis = horrible_cast(function_to_bind); + // MSVC, SunC++ and DMC accept the following (non-standard) code: +// m_pthis = static_cast(static_cast(function_to_bind)); + // BCC32, Comeau and DMC accept this method. MSVC7.1 needs __int64 instead of long +// m_pthis = reinterpret_cast(reinterpret_cast(function_to_bind)); + } + // ******** EVIL, EVIL CODE! ******* + // This function will be called with an invalid 'this' pointer!! + // We're just returning the 'this' pointer, converted into + // a function pointer! + inline UnvoidStaticFuncPtr GetStaticFunction() const { + // Ensure that there's a compilation failure if function pointers + // and data pointers have different sizes. + // If you get this error, you need to #undef FASTDELEGATE_USESTATICFUNCTIONHACK. + static_assert(sizeof(UnvoidStaticFuncPtr)==sizeof(this), "Cannot use evil method"); + return horrible_cast(this); + } #endif // !defined(FASTDELEGATE_USESTATICFUNCTIONHACK) - // Does the closure contain this static function? - inline bool IsEqualToStaticFuncPtr(StaticFuncPtr funcptr) - { - if (funcptr == 0) return empty(); - // For the Evil method, if it doesn't actually contain a static function, this will return an arbitrary - // value that is not equal to any valid function pointer. - else return funcptr == reinterpret_cast(GetStaticFunction()); - } - }; - } // namespace detail - - //////////////////////////////////////////////////////////////////////////////// - // Fast Delegates, part 3: - // - // Wrapper classes to ensure type safety - // - //////////////////////////////////////////////////////////////////////////////// - - - // Once we have the member function conversion templates, it's easy to make the - // wrapper classes. So that they will work with as many compilers as possible, - // the classes are of the form - // FastDelegate3 - // They can cope with any combination of parameters. The max number of parameters - // allowed is 8, but it is trivial to increase this limit. - // Note that we need to treat const member functions seperately. - // All this class does is to enforce type safety, and invoke the delegate with - // the correct list of parameters. - - // Because of the weird rule about the class of derived member function pointers, - // you sometimes need to apply a downcast to the 'this' pointer. - // This is the reason for the use of "implicit_cast(pthis)" in the code below. - // If CDerivedClass is derived from CBaseClass, but doesn't override SimpleVirtualFunction, - // without this trick you'd need to write: - // MyDelegate(static_cast(&d), &CDerivedClass::SimpleVirtualFunction); - // but with the trick you can write - // MyDelegate(&d, &CDerivedClass::SimpleVirtualFunction); - - // RetType is the type the compiler uses in compiling the template. For VC6, - // it cannot be void. DesiredRetType is the real type which is returned from - // all of the functions. It can be void. - - // Implicit conversion to "bool" is achieved using the safe_bool idiom, - // using member data pointers (MDP). This allows "if (dg)..." syntax - // Because some compilers (eg codeplay) don't have a unique value for a zero - // MDP, an extra padding member is added to the SafeBool struct. - // Some compilers (eg VC6) won't implicitly convert from 0 to an MDP, so - // in that case the static function constructor is not made explicit; this - // allows "if (dg==0) ..." to compile. - - //N=0 - template - class FastDelegate0 - { - private: - typedef typename detail::DefaultVoidToVoid::type DesiredRetType; - typedef DesiredRetType (xr_stdcall *StaticFunctionPtr)(); - typedef RetType (xr_stdcall *UnvoidStaticFunctionPtr)(); - typedef RetType (xr_stdcall detail::GenericClass::*GenericMemFn)(); - typedef detail::ClosurePtr ClosureType; - ClosureType m_Closure; - public: - // Typedefs to aid generic programming - typedef FastDelegate0 type; - - // Construction and comparison functions - FastDelegate0() { clear(); } - - FastDelegate0(const FastDelegate0& x) - { - m_Closure.CopyFrom(this, x.m_Closure); - } - - void operator =(const FastDelegate0& x) - { - m_Closure.CopyFrom(this, x.m_Closure); - } - - bool operator ==(const FastDelegate0& x) const - { - return m_Closure.IsEqual(x.m_Closure); - } - - bool operator !=(const FastDelegate0& x) const - { - return !m_Closure.IsEqual(x.m_Closure); - } - - bool operator <(const FastDelegate0& x) const - { - return m_Closure.IsLess(x.m_Closure); - } - - bool operator >(const FastDelegate0& x) const - { - return x.m_Closure.IsLess(m_Closure); - } - - // Binding to non-const member functions - template - FastDelegate0(Y* pthis, DesiredRetType (xr_stdcall X::* function_to_bind)()) - { - m_Closure.bindmemfunc(detail::implicit_cast(pthis), function_to_bind); - } - - template - inline void bind(Y* pthis, DesiredRetType (xr_stdcall X::* function_to_bind)()) - { - m_Closure.bindmemfunc(detail::implicit_cast(pthis), function_to_bind); - } - - // Binding to const member functions. - template - FastDelegate0(const Y* pthis, DesiredRetType (xr_stdcall X::* function_to_bind)() const) - { - m_Closure.bindconstmemfunc(detail::implicit_cast(pthis), function_to_bind); - } - - template - inline void bind(const Y* pthis, DesiredRetType (xr_stdcall X::* function_to_bind)() const) - { - m_Closure.bindconstmemfunc(detail::implicit_cast(pthis), function_to_bind); - } - - // Static functions. We convert them into a member function call. - // This constructor also provides implicit conversion - FastDelegate0(DesiredRetType (xr_stdcall *function_to_bind)()) - { - bind(function_to_bind); - } - - // for efficiency, prevent creation of a temporary - void operator =(DesiredRetType (xr_stdcall *function_to_bind)()) - { - bind(function_to_bind); - } - - inline void bind(DesiredRetType (xr_stdcall *function_to_bind)()) - { - m_Closure.bindstaticfunc(this, &FastDelegate0::InvokeStaticFunction, - function_to_bind); - } - - // Invoke the delegate - RetType operator()() const - { - return (m_Closure.GetClosureThis()->*(m_Closure.GetClosureMemPtr()))(); - } - - // Implicit conversion to "bool" using the safe_bool idiom - private: - typedef struct SafeBoolStruct - { - int a_data_pointer_to_this_is_0_on_buggy_compilers; - StaticFunctionPtr m_nonzero; - } UselessTypedef; - - typedef StaticFunctionPtr SafeBoolStruct::* unspecified_bool_type; - public: - operator unspecified_bool_type() const - { - return empty() ? 0 : &SafeBoolStruct::m_nonzero; - } - - // necessary to allow ==0 to work despite the safe_bool idiom - inline bool operator==(StaticFunctionPtr funcptr) - { - return m_Closure.IsEqualToStaticFuncPtr(funcptr); - } - - inline bool operator!=(StaticFunctionPtr funcptr) - { - return !m_Closure.IsEqualToStaticFuncPtr(funcptr); - } - - inline bool operator !() const - { - // Is it bound to anything? - return !m_Closure; - } - - inline bool empty() const - { - return !m_Closure; - } - - void clear() { m_Closure.clear(); } - // Conversion to and from the DelegateMemento storage class - const DelegateMemento& GetMemento() { return m_Closure; } - void SetMemento(const DelegateMemento& any) { m_Closure.CopyFrom(this, any); } - - private: // Invoker for static functions - RetType xr_stdcall InvokeStaticFunction() const - { - return (*(m_Closure.GetStaticFunction()))(); - } - }; - - //N=1 - template - class FastDelegate1 - { - private: - typedef typename detail::DefaultVoidToVoid::type DesiredRetType; - typedef DesiredRetType (xr_stdcall *StaticFunctionPtr)(Param1 p1); - typedef RetType (xr_stdcall *UnvoidStaticFunctionPtr)(Param1 p1); - typedef RetType (xr_stdcall detail::GenericClass::*GenericMemFn)(Param1 p1); - typedef detail::ClosurePtr ClosureType; - ClosureType m_Closure; - public: - // Typedefs to aid generic programming - typedef FastDelegate1 type; - - // Construction and comparison functions - FastDelegate1() { clear(); } - - FastDelegate1(const FastDelegate1& x) - { - m_Closure.CopyFrom(this, x.m_Closure); - } - - void operator =(const FastDelegate1& x) - { - m_Closure.CopyFrom(this, x.m_Closure); - } - - bool operator ==(const FastDelegate1& x) const - { - return m_Closure.IsEqual(x.m_Closure); - } - - bool operator !=(const FastDelegate1& x) const - { - return !m_Closure.IsEqual(x.m_Closure); - } - - bool operator <(const FastDelegate1& x) const - { - return m_Closure.IsLess(x.m_Closure); - } - - bool operator >(const FastDelegate1& x) const - { - return x.m_Closure.IsLess(m_Closure); - } - - // Binding to non-const member functions - template - FastDelegate1(Y* pthis, DesiredRetType (xr_stdcall X::* function_to_bind)(Param1 p1)) - { - m_Closure.bindmemfunc(detail::implicit_cast(pthis), function_to_bind); - } - - template - inline void bind(Y* pthis, DesiredRetType (xr_stdcall X::* function_to_bind)(Param1 p1)) - { - m_Closure.bindmemfunc(detail::implicit_cast(pthis), function_to_bind); - } - - // Binding to const member functions. - template - FastDelegate1(const Y* pthis, DesiredRetType (xr_stdcall X::* function_to_bind)(Param1 p1) const) - { - m_Closure.bindconstmemfunc(detail::implicit_cast(pthis), function_to_bind); - } - - template - inline void bind(const Y* pthis, DesiredRetType (xr_stdcall X::* function_to_bind)(Param1 p1) const) - { - m_Closure.bindconstmemfunc(detail::implicit_cast(pthis), function_to_bind); - } - - // Static functions. We convert them into a member function call. - // This constructor also provides implicit conversion - FastDelegate1(DesiredRetType (xr_stdcall *function_to_bind)(Param1 p1)) - { - bind(function_to_bind); - } - - // for efficiency, prevent creation of a temporary - void operator =(DesiredRetType (xr_stdcall *function_to_bind)(Param1 p1)) - { - bind(function_to_bind); - } - - inline void bind(DesiredRetType (xr_stdcall *function_to_bind)(Param1 p1)) - { - m_Closure.bindstaticfunc(this, &FastDelegate1::InvokeStaticFunction, - function_to_bind); - } - - // Invoke the delegate - RetType operator()(Param1 p1) const - { - return (m_Closure.GetClosureThis()->*(m_Closure.GetClosureMemPtr()))(p1); - } - - // Implicit conversion to "bool" using the safe_bool idiom - private: - typedef struct SafeBoolStruct - { - int a_data_pointer_to_this_is_0_on_buggy_compilers; - StaticFunctionPtr m_nonzero; - } UselessTypedef; - - typedef StaticFunctionPtr SafeBoolStruct::* unspecified_bool_type; - public: - operator unspecified_bool_type() const - { - return empty() ? 0 : &SafeBoolStruct::m_nonzero; - } - - // necessary to allow ==0 to work despite the safe_bool idiom - inline bool operator==(StaticFunctionPtr funcptr) - { - return m_Closure.IsEqualToStaticFuncPtr(funcptr); - } - - inline bool operator!=(StaticFunctionPtr funcptr) - { - return !m_Closure.IsEqualToStaticFuncPtr(funcptr); - } - - inline bool operator !() const - { - // Is it bound to anything? - return !m_Closure; - } - - inline bool empty() const - { - return !m_Closure; - } - - void clear() { m_Closure.clear(); } - // Conversion to and from the DelegateMemento storage class - const DelegateMemento& GetMemento() { return m_Closure; } - void SetMemento(const DelegateMemento& any) { m_Closure.CopyFrom(this, any); } - - private: // Invoker for static functions - // this -- parameter, function - // p1 - function, parameter - RetType xr_stdcall InvokeStaticFunction(Param1 p1) const - { - return (*(m_Closure.GetStaticFunction()))(p1); - } - }; - - //N=2 - template - class FastDelegate2 - { - private: - typedef typename detail::DefaultVoidToVoid::type DesiredRetType; - typedef DesiredRetType (xr_stdcall *StaticFunctionPtr)(Param1 p1, Param2 p2); - typedef RetType (xr_stdcall *UnvoidStaticFunctionPtr)(Param1 p1, Param2 p2); - typedef RetType (xr_stdcall detail::GenericClass::*GenericMemFn)(Param1 p1, Param2 p2); - typedef detail::ClosurePtr ClosureType; - ClosureType m_Closure; - public: - // Typedefs to aid generic programming - typedef FastDelegate2 type; - - // Construction and comparison functions - FastDelegate2() { clear(); } - - FastDelegate2(const FastDelegate2& x) - { - m_Closure.CopyFrom(this, x.m_Closure); - } - - void operator =(const FastDelegate2& x) - { - m_Closure.CopyFrom(this, x.m_Closure); - } - - bool operator ==(const FastDelegate2& x) const - { - return m_Closure.IsEqual(x.m_Closure); - } - - bool operator !=(const FastDelegate2& x) const - { - return !m_Closure.IsEqual(x.m_Closure); - } - - bool operator <(const FastDelegate2& x) const - { - return m_Closure.IsLess(x.m_Closure); - } - - bool operator >(const FastDelegate2& x) const - { - return x.m_Closure.IsLess(m_Closure); - } - - // Binding to non-const member functions - template - FastDelegate2(Y* pthis, DesiredRetType (xr_stdcall X::* function_to_bind)(Param1 p1, Param2 p2)) - { - m_Closure.bindmemfunc(detail::implicit_cast(pthis), function_to_bind); - } - - template - inline void bind(Y* pthis, DesiredRetType (xr_stdcall X::* function_to_bind)(Param1 p1, Param2 p2)) - { - m_Closure.bindmemfunc(detail::implicit_cast(pthis), function_to_bind); - } - - // Binding to const member functions. - template - FastDelegate2(const Y* pthis, DesiredRetType (xr_stdcall X::* function_to_bind)(Param1 p1, Param2 p2) const) - { - m_Closure.bindconstmemfunc(detail::implicit_cast(pthis), function_to_bind); - } - - template - inline void bind(const Y* pthis, DesiredRetType (xr_stdcall X::* function_to_bind)(Param1 p1, Param2 p2) const) - { - m_Closure.bindconstmemfunc(detail::implicit_cast(pthis), function_to_bind); - } - - // Static functions. We convert them into a member function call. - // This constructor also provides implicit conversion - FastDelegate2(DesiredRetType (xr_stdcall *function_to_bind)(Param1 p1, Param2 p2)) - { - bind(function_to_bind); - } - - // for efficiency, prevent creation of a temporary - void operator =(DesiredRetType (xr_stdcall *function_to_bind)(Param1 p1, Param2 p2)) - { - bind(function_to_bind); - } - - inline void bind(DesiredRetType (xr_stdcall *function_to_bind)(Param1 p1, Param2 p2)) - { - m_Closure.bindstaticfunc(this, &FastDelegate2::InvokeStaticFunction, - function_to_bind); - } - - // Invoke the delegate - RetType operator()(Param1 p1, Param2 p2) const - { - return (m_Closure.GetClosureThis()->*(m_Closure.GetClosureMemPtr()))(p1, p2); - } - - // Implicit conversion to "bool" using the safe_bool idiom - private: - typedef struct SafeBoolStruct - { - int a_data_pointer_to_this_is_0_on_buggy_compilers; - StaticFunctionPtr m_nonzero; - } UselessTypedef; - - typedef StaticFunctionPtr SafeBoolStruct::* unspecified_bool_type; - public: - operator unspecified_bool_type() const - { - return empty() ? 0 : &SafeBoolStruct::m_nonzero; - } - - // necessary to allow ==0 to work despite the safe_bool idiom - inline bool operator==(StaticFunctionPtr funcptr) - { - return m_Closure.IsEqualToStaticFuncPtr(funcptr); - } - - inline bool operator!=(StaticFunctionPtr funcptr) - { - return !m_Closure.IsEqualToStaticFuncPtr(funcptr); - } - - inline bool operator !() const - { - // Is it bound to anything? - return !m_Closure; - } - - inline bool empty() const - { - return !m_Closure; - } - - void clear() { m_Closure.clear(); } - // Conversion to and from the DelegateMemento storage class - const DelegateMemento& GetMemento() { return m_Closure; } - void SetMemento(const DelegateMemento& any) { m_Closure.CopyFrom(this, any); } - - private: // Invoker for static functions - RetType xr_stdcall InvokeStaticFunction(Param1 p1, Param2 p2) const - { - return (*(m_Closure.GetStaticFunction()))(p1, p2); - } - }; - - //N=3 - template - class FastDelegate3 - { - private: - typedef typename detail::DefaultVoidToVoid::type DesiredRetType; - typedef DesiredRetType (xr_stdcall *StaticFunctionPtr)(Param1 p1, Param2 p2, Param3 p3); - typedef RetType (xr_stdcall *UnvoidStaticFunctionPtr)(Param1 p1, Param2 p2, Param3 p3); - typedef RetType (xr_stdcall detail::GenericClass::*GenericMemFn)(Param1 p1, Param2 p2, Param3 p3); - typedef detail::ClosurePtr ClosureType; - ClosureType m_Closure; - public: - // Typedefs to aid generic programming - typedef FastDelegate3 type; - - // Construction and comparison functions - FastDelegate3() { clear(); } - - FastDelegate3(const FastDelegate3& x) - { - m_Closure.CopyFrom(this, x.m_Closure); - } - - void operator =(const FastDelegate3& x) - { - m_Closure.CopyFrom(this, x.m_Closure); - } - - bool operator ==(const FastDelegate3& x) const - { - return m_Closure.IsEqual(x.m_Closure); - } - - bool operator !=(const FastDelegate3& x) const - { - return !m_Closure.IsEqual(x.m_Closure); - } - - bool operator <(const FastDelegate3& x) const - { - return m_Closure.IsLess(x.m_Closure); - } - - bool operator >(const FastDelegate3& x) const - { - return x.m_Closure.IsLess(m_Closure); - } - - // Binding to non-const member functions - template - FastDelegate3(Y* pthis, DesiredRetType (xr_stdcall X::* function_to_bind)(Param1 p1, Param2 p2, Param3 p3)) - { - m_Closure.bindmemfunc(detail::implicit_cast(pthis), function_to_bind); - } - - template - inline void bind(Y* pthis, DesiredRetType (xr_stdcall X::* function_to_bind)(Param1 p1, Param2 p2, Param3 p3)) - { - m_Closure.bindmemfunc(detail::implicit_cast(pthis), function_to_bind); - } - - // Binding to const member functions. - template - FastDelegate3(const Y* pthis, - DesiredRetType (xr_stdcall X::* function_to_bind)(Param1 p1, Param2 p2, Param3 p3) const) - { - m_Closure.bindconstmemfunc(detail::implicit_cast(pthis), function_to_bind); - } - - template - inline void bind(const Y* pthis, - DesiredRetType (xr_stdcall X::* function_to_bind)(Param1 p1, Param2 p2, Param3 p3) const) - { - m_Closure.bindconstmemfunc(detail::implicit_cast(pthis), function_to_bind); - } - - // Static functions. We convert them into a member function call. - // This constructor also provides implicit conversion - FastDelegate3(DesiredRetType (xr_stdcall *function_to_bind)(Param1 p1, Param2 p2, Param3 p3)) - { - bind(function_to_bind); - } - - // for efficiency, prevent creation of a temporary - void operator =(DesiredRetType (xr_stdcall *function_to_bind)(Param1 p1, Param2 p2, Param3 p3)) - { - bind(function_to_bind); - } - - inline void bind(DesiredRetType (xr_stdcall *function_to_bind)(Param1 p1, Param2 p2, Param3 p3)) - { - m_Closure.bindstaticfunc(this, &FastDelegate3::InvokeStaticFunction, - function_to_bind); - } - - // Invoke the delegate - RetType operator()(Param1 p1, Param2 p2, Param3 p3) const - { - return (m_Closure.GetClosureThis()->*(m_Closure.GetClosureMemPtr()))(p1, p2, p3); - } - - // Implicit conversion to "bool" using the safe_bool idiom - private: - typedef struct SafeBoolStruct - { - int a_data_pointer_to_this_is_0_on_buggy_compilers; - StaticFunctionPtr m_nonzero; - } UselessTypedef; - - typedef StaticFunctionPtr SafeBoolStruct::* unspecified_bool_type; - public: - operator unspecified_bool_type() const - { - return empty() ? 0 : &SafeBoolStruct::m_nonzero; - } - - // necessary to allow ==0 to work despite the safe_bool idiom - inline bool operator==(StaticFunctionPtr funcptr) - { - return m_Closure.IsEqualToStaticFuncPtr(funcptr); - } - - inline bool operator!=(StaticFunctionPtr funcptr) - { - return !m_Closure.IsEqualToStaticFuncPtr(funcptr); - } - - inline bool operator !() const - { - // Is it bound to anything? - return !m_Closure; - } - - inline bool empty() const - { - return !m_Closure; - } - - void clear() { m_Closure.clear(); } - // Conversion to and from the DelegateMemento storage class - const DelegateMemento& GetMemento() { return m_Closure; } - void SetMemento(const DelegateMemento& any) { m_Closure.CopyFrom(this, any); } - - private: // Invoker for static functions - RetType xr_stdcall InvokeStaticFunction(Param1 p1, Param2 p2, Param3 p3) const - { - return (*(m_Closure.GetStaticFunction()))(p1, p2, p3); - } - }; - - //N=4 - template - class FastDelegate4 - { - private: - typedef typename detail::DefaultVoidToVoid::type DesiredRetType; - typedef DesiredRetType (xr_stdcall *StaticFunctionPtr)(Param1 p1, Param2 p2, Param3 p3, Param4 p4); - typedef RetType (xr_stdcall *UnvoidStaticFunctionPtr)(Param1 p1, Param2 p2, Param3 p3, Param4 p4); - typedef RetType (xr_stdcall detail::GenericClass::*GenericMemFn)(Param1 p1, Param2 p2, Param3 p3, Param4 p4); - typedef detail::ClosurePtr ClosureType; - ClosureType m_Closure; - public: - // Typedefs to aid generic programming - typedef FastDelegate4 type; - - // Construction and comparison functions - FastDelegate4() { clear(); } - - FastDelegate4(const FastDelegate4& x) - { - m_Closure.CopyFrom(this, x.m_Closure); - } - - void operator =(const FastDelegate4& x) - { - m_Closure.CopyFrom(this, x.m_Closure); - } - - bool operator ==(const FastDelegate4& x) const - { - return m_Closure.IsEqual(x.m_Closure); - } - - bool operator !=(const FastDelegate4& x) const - { - return !m_Closure.IsEqual(x.m_Closure); - } - - bool operator <(const FastDelegate4& x) const - { - return m_Closure.IsLess(x.m_Closure); - } - - bool operator >(const FastDelegate4& x) const - { - return x.m_Closure.IsLess(m_Closure); - } - - // Binding to non-const member functions - template - FastDelegate4( - Y* pthis, DesiredRetType (xr_stdcall X::* function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4)) - { - m_Closure.bindmemfunc(detail::implicit_cast(pthis), function_to_bind); - } - - template - inline void bind( - Y* pthis, DesiredRetType (xr_stdcall X::* function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4)) - { - m_Closure.bindmemfunc(detail::implicit_cast(pthis), function_to_bind); - } - - // Binding to const member functions. - template - FastDelegate4(const Y* pthis, - DesiredRetType (xr_stdcall X::* function_to_bind)(Param1 p1, Param2 p2, Param3 p3, - Param4 p4) const) - { - m_Closure.bindconstmemfunc(detail::implicit_cast(pthis), function_to_bind); - } - - template - inline void bind(const Y* pthis, - DesiredRetType (xr_stdcall X::* function_to_bind)( - Param1 p1, Param2 p2, Param3 p3, Param4 p4) const) - { - m_Closure.bindconstmemfunc(detail::implicit_cast(pthis), function_to_bind); - } - - // Static functions. We convert them into a member function call. - // This constructor also provides implicit conversion - FastDelegate4(DesiredRetType (xr_stdcall *function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4)) - { - bind(function_to_bind); - } - - // for efficiency, prevent creation of a temporary - void operator =(DesiredRetType (xr_stdcall *function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4)) - { - bind(function_to_bind); - } - - inline void bind(DesiredRetType (xr_stdcall *function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4)) - { - m_Closure.bindstaticfunc(this, &FastDelegate4::InvokeStaticFunction, - function_to_bind); - } - - // Invoke the delegate - RetType operator()(Param1 p1, Param2 p2, Param3 p3, Param4 p4) const - { - return (m_Closure.GetClosureThis()->*(m_Closure.GetClosureMemPtr()))(p1, p2, p3, p4); - } - - // Implicit conversion to "bool" using the safe_bool idiom - private: - typedef struct SafeBoolStruct - { - int a_data_pointer_to_this_is_0_on_buggy_compilers; - StaticFunctionPtr m_nonzero; - } UselessTypedef; - - typedef StaticFunctionPtr SafeBoolStruct::* unspecified_bool_type; - public: - operator unspecified_bool_type() const - { - return empty() ? 0 : &SafeBoolStruct::m_nonzero; - } - - // necessary to allow ==0 to work despite the safe_bool idiom - inline bool operator==(StaticFunctionPtr funcptr) - { - return m_Closure.IsEqualToStaticFuncPtr(funcptr); - } - - inline bool operator!=(StaticFunctionPtr funcptr) - { - return !m_Closure.IsEqualToStaticFuncPtr(funcptr); - } - - inline bool operator !() const - { - // Is it bound to anything? - return !m_Closure; - } - - inline bool empty() const - { - return !m_Closure; - } - - void clear() { m_Closure.clear(); } - // Conversion to and from the DelegateMemento storage class - const DelegateMemento& GetMemento() { return m_Closure; } - void SetMemento(const DelegateMemento& any) { m_Closure.CopyFrom(this, any); } - - private: // Invoker for static functions - RetType xr_stdcall InvokeStaticFunction(Param1 p1, Param2 p2, Param3 p3, Param4 p4) const - { - return (*(m_Closure.GetStaticFunction()))(p1, p2, p3, p4); - } - }; - - //N=5 - template - class FastDelegate5 - { - private: - typedef typename detail::DefaultVoidToVoid::type DesiredRetType; - typedef DesiredRetType (xr_stdcall *StaticFunctionPtr)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5); - typedef RetType (xr_stdcall *UnvoidStaticFunctionPtr)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5); - typedef RetType (xr_stdcall detail::GenericClass::*GenericMemFn)( - Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5); - typedef detail::ClosurePtr ClosureType; - ClosureType m_Closure; - public: - // Typedefs to aid generic programming - typedef FastDelegate5 type; - - // Construction and comparison functions - FastDelegate5() { clear(); } - - FastDelegate5(const FastDelegate5& x) - { - m_Closure.CopyFrom(this, x.m_Closure); - } - - void operator =(const FastDelegate5& x) - { - m_Closure.CopyFrom(this, x.m_Closure); - } - - bool operator ==(const FastDelegate5& x) const - { - return m_Closure.IsEqual(x.m_Closure); - } - - bool operator !=(const FastDelegate5& x) const - { - return !m_Closure.IsEqual(x.m_Closure); - } - - bool operator <(const FastDelegate5& x) const - { - return m_Closure.IsLess(x.m_Closure); - } - - bool operator >(const FastDelegate5& x) const - { - return x.m_Closure.IsLess(m_Closure); - } - - // Binding to non-const member functions - template - FastDelegate5( - Y* pthis, DesiredRetType (xr_stdcall X::* function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, - Param5 p5)) - { - m_Closure.bindmemfunc(detail::implicit_cast(pthis), function_to_bind); - } - - template - inline void bind( - Y* pthis, DesiredRetType (xr_stdcall X::* function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, - Param5 p5)) - { - m_Closure.bindmemfunc(detail::implicit_cast(pthis), function_to_bind); - } - - // Binding to const member functions. - template - FastDelegate5(const Y* pthis, - DesiredRetType (xr_stdcall X::* function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, - Param5 p5) const) - { - m_Closure.bindconstmemfunc(detail::implicit_cast(pthis), function_to_bind); - } - - template - inline void bind(const Y* pthis, - DesiredRetType (xr_stdcall X::* function_to_bind)( - Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5) const) - { - m_Closure.bindconstmemfunc(detail::implicit_cast(pthis), function_to_bind); - } - - // Static functions. We convert them into a member function call. - // This constructor also provides implicit conversion - FastDelegate5( - DesiredRetType (xr_stdcall *function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5)) - { - bind(function_to_bind); - } - - // for efficiency, prevent creation of a temporary - void operator =( - DesiredRetType (xr_stdcall *function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5)) - { - bind(function_to_bind); - } - - inline void bind( - DesiredRetType (xr_stdcall *function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5)) - { - m_Closure.bindstaticfunc(this, &FastDelegate5::InvokeStaticFunction, - function_to_bind); - } - - // Invoke the delegate - RetType operator()(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5) const - { - return (m_Closure.GetClosureThis()->*(m_Closure.GetClosureMemPtr()))(p1, p2, p3, p4, p5); - } - - // Implicit conversion to "bool" using the safe_bool idiom - private: - typedef struct SafeBoolStruct - { - int a_data_pointer_to_this_is_0_on_buggy_compilers; - StaticFunctionPtr m_nonzero; - } UselessTypedef; - - typedef StaticFunctionPtr SafeBoolStruct::* unspecified_bool_type; - public: - operator unspecified_bool_type() const - { - return empty() ? 0 : &SafeBoolStruct::m_nonzero; - } - - // necessary to allow ==0 to work despite the safe_bool idiom - inline bool operator==(StaticFunctionPtr funcptr) - { - return m_Closure.IsEqualToStaticFuncPtr(funcptr); - } - - inline bool operator!=(StaticFunctionPtr funcptr) - { - return !m_Closure.IsEqualToStaticFuncPtr(funcptr); - } - - inline bool operator !() const - { - // Is it bound to anything? - return !m_Closure; - } - - inline bool empty() const - { - return !m_Closure; - } - - void clear() { m_Closure.clear(); } - // Conversion to and from the DelegateMemento storage class - const DelegateMemento& GetMemento() { return m_Closure; } - void SetMemento(const DelegateMemento& any) { m_Closure.CopyFrom(this, any); } - - private: // Invoker for static functions - RetType xr_stdcall InvokeStaticFunction(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5) const - { - return (*(m_Closure.GetStaticFunction()))(p1, p2, p3, p4, p5); - } - }; - - //N=6 - template - class FastDelegate6 - { - private: - typedef typename detail::DefaultVoidToVoid::type DesiredRetType; - typedef DesiredRetType (xr_stdcall *StaticFunctionPtr)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, - Param6 p6); - typedef RetType (xr_stdcall *UnvoidStaticFunctionPtr)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, - Param6 p6); - typedef RetType (xr_stdcall detail::GenericClass::*GenericMemFn)( - Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6); - typedef detail::ClosurePtr ClosureType; - ClosureType m_Closure; - public: - // Typedefs to aid generic programming - typedef FastDelegate6 type; - - // Construction and comparison functions - FastDelegate6() { clear(); } - - FastDelegate6(const FastDelegate6& x) - { - m_Closure.CopyFrom(this, x.m_Closure); - } - - void operator =(const FastDelegate6& x) - { - m_Closure.CopyFrom(this, x.m_Closure); - } - - bool operator ==(const FastDelegate6& x) const - { - return m_Closure.IsEqual(x.m_Closure); - } - - bool operator !=(const FastDelegate6& x) const - { - return !m_Closure.IsEqual(x.m_Closure); - } - - bool operator <(const FastDelegate6& x) const - { - return m_Closure.IsLess(x.m_Closure); - } - - bool operator >(const FastDelegate6& x) const - { - return x.m_Closure.IsLess(m_Closure); - } - - // Binding to non-const member functions - template - FastDelegate6( - Y* pthis, DesiredRetType (xr_stdcall X::* function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, - Param5 p5, Param6 p6)) - { - m_Closure.bindmemfunc(detail::implicit_cast(pthis), function_to_bind); - } - - template - inline void bind( - Y* pthis, DesiredRetType (xr_stdcall X::* function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, - Param5 p5, Param6 p6)) - { - m_Closure.bindmemfunc(detail::implicit_cast(pthis), function_to_bind); - } - - // Binding to const member functions. - template - FastDelegate6(const Y* pthis, - DesiredRetType (xr_stdcall X::* function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, - Param5 p5, Param6 p6) const) - { - m_Closure.bindconstmemfunc(detail::implicit_cast(pthis), function_to_bind); - } - - template - inline void bind(const Y* pthis, - DesiredRetType (xr_stdcall X::* function_to_bind)( - Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6) const) - { - m_Closure.bindconstmemfunc(detail::implicit_cast(pthis), function_to_bind); - } - - // Static functions. We convert them into a member function call. - // This constructor also provides implicit conversion - FastDelegate6( - DesiredRetType (xr_stdcall *function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, - Param6 p6)) - { - bind(function_to_bind); - } - - // for efficiency, prevent creation of a temporary - void operator =( - DesiredRetType (xr_stdcall *function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, - Param6 p6)) - { - bind(function_to_bind); - } - - inline void bind( - DesiredRetType (xr_stdcall *function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, - Param6 p6)) - { - m_Closure.bindstaticfunc(this, &FastDelegate6::InvokeStaticFunction, - function_to_bind); - } - - // Invoke the delegate - RetType operator()(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6) const - { - return (m_Closure.GetClosureThis()->*(m_Closure.GetClosureMemPtr()))(p1, p2, p3, p4, p5, p6); - } - - // Implicit conversion to "bool" using the safe_bool idiom - private: - typedef struct SafeBoolStruct - { - int a_data_pointer_to_this_is_0_on_buggy_compilers; - StaticFunctionPtr m_nonzero; - } UselessTypedef; - - typedef StaticFunctionPtr SafeBoolStruct::* unspecified_bool_type; - public: - operator unspecified_bool_type() const - { - return empty() ? 0 : &SafeBoolStruct::m_nonzero; - } - - // necessary to allow ==0 to work despite the safe_bool idiom - inline bool operator==(StaticFunctionPtr funcptr) - { - return m_Closure.IsEqualToStaticFuncPtr(funcptr); - } - - inline bool operator!=(StaticFunctionPtr funcptr) - { - return !m_Closure.IsEqualToStaticFuncPtr(funcptr); - } - - inline bool operator !() const - { - // Is it bound to anything? - return !m_Closure; - } - - inline bool empty() const - { - return !m_Closure; - } - - void clear() { m_Closure.clear(); } - // Conversion to and from the DelegateMemento storage class - const DelegateMemento& GetMemento() { return m_Closure; } - void SetMemento(const DelegateMemento& any) { m_Closure.CopyFrom(this, any); } - - private: // Invoker for static functions - RetType xr_stdcall InvokeStaticFunction(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6) const - { - return (*(m_Closure.GetStaticFunction()))(p1, p2, p3, p4, p5, p6); - } - }; - - //N=7 - template - class FastDelegate7 - { - private: - typedef typename detail::DefaultVoidToVoid::type DesiredRetType; - typedef DesiredRetType (xr_stdcall *StaticFunctionPtr)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, - Param6 p6, Param7 p7); - typedef RetType (xr_stdcall *UnvoidStaticFunctionPtr)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, - Param6 p6, Param7 p7); - typedef RetType (xr_stdcall detail::GenericClass::*GenericMemFn)( - Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7); - typedef detail::ClosurePtr ClosureType; - ClosureType m_Closure; - public: - // Typedefs to aid generic programming - typedef FastDelegate7 type; - - // Construction and comparison functions - FastDelegate7() { clear(); } - - FastDelegate7(const FastDelegate7& x) - { - m_Closure.CopyFrom(this, x.m_Closure); - } - - void operator =(const FastDelegate7& x) - { - m_Closure.CopyFrom(this, x.m_Closure); - } - - bool operator ==(const FastDelegate7& x) const - { - return m_Closure.IsEqual(x.m_Closure); - } - - bool operator !=(const FastDelegate7& x) const - { - return !m_Closure.IsEqual(x.m_Closure); - } - - bool operator <(const FastDelegate7& x) const - { - return m_Closure.IsLess(x.m_Closure); - } - - bool operator >(const FastDelegate7& x) const - { - return x.m_Closure.IsLess(m_Closure); - } - - // Binding to non-const member functions - template - FastDelegate7(Y* pthis, DesiredRetType (xr_stdcall X::* function_to_bind)( - Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7)) - { - m_Closure.bindmemfunc(detail::implicit_cast(pthis), function_to_bind); - } - - template - inline void bind(Y* pthis, DesiredRetType (xr_stdcall X::* function_to_bind)( - Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7)) - { - m_Closure.bindmemfunc(detail::implicit_cast(pthis), function_to_bind); - } - - // Binding to const member functions. - template - FastDelegate7(const Y* pthis, - DesiredRetType (xr_stdcall X::* function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, - Param5 p5, Param6 p6, Param7 p7) const) - { - m_Closure.bindconstmemfunc(detail::implicit_cast(pthis), function_to_bind); - } - - template - inline void bind(const Y* pthis, - DesiredRetType (xr_stdcall X::* function_to_bind)( - Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7) const) - { - m_Closure.bindconstmemfunc(detail::implicit_cast(pthis), function_to_bind); - } - - // Static functions. We convert them into a member function call. - // This constructor also provides implicit conversion - FastDelegate7( - DesiredRetType (xr_stdcall *function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, - Param6 p6, Param7 p7)) - { - bind(function_to_bind); - } - - // for efficiency, prevent creation of a temporary - void operator =( - DesiredRetType (xr_stdcall *function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, - Param6 p6, Param7 p7)) - { - bind(function_to_bind); - } - - inline void bind( - DesiredRetType (xr_stdcall *function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, - Param6 p6, Param7 p7)) - { - m_Closure.bindstaticfunc(this, &FastDelegate7::InvokeStaticFunction, - function_to_bind); - } - - // Invoke the delegate - RetType operator()(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7) const - { - return (m_Closure.GetClosureThis()->*(m_Closure.GetClosureMemPtr()))(p1, p2, p3, p4, p5, p6, p7); - } - - // Implicit conversion to "bool" using the safe_bool idiom - private: - typedef struct SafeBoolStruct - { - int a_data_pointer_to_this_is_0_on_buggy_compilers; - StaticFunctionPtr m_nonzero; - } UselessTypedef; - - typedef StaticFunctionPtr SafeBoolStruct::* unspecified_bool_type; - public: - operator unspecified_bool_type() const - { - return empty() ? 0 : &SafeBoolStruct::m_nonzero; - } - - // necessary to allow ==0 to work despite the safe_bool idiom - inline bool operator==(StaticFunctionPtr funcptr) - { - return m_Closure.IsEqualToStaticFuncPtr(funcptr); - } - - inline bool operator!=(StaticFunctionPtr funcptr) - { - return !m_Closure.IsEqualToStaticFuncPtr(funcptr); - } - - inline bool operator !() const - { - // Is it bound to anything? - return !m_Closure; - } - - inline bool empty() const - { - return !m_Closure; - } - - void clear() { m_Closure.clear(); } - // Conversion to and from the DelegateMemento storage class - const DelegateMemento& GetMemento() { return m_Closure; } - void SetMemento(const DelegateMemento& any) { m_Closure.CopyFrom(this, any); } - - private: // Invoker for static functions - RetType xr_stdcall InvokeStaticFunction(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, - Param7 p7) const - { - return (*(m_Closure.GetStaticFunction()))(p1, p2, p3, p4, p5, p6, p7); - } - }; - - //N=8 - template - class FastDelegate8 - { - private: - typedef typename detail::DefaultVoidToVoid::type DesiredRetType; - typedef DesiredRetType (xr_stdcall *StaticFunctionPtr)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, - Param6 p6, Param7 p7, Param8 p8); - typedef RetType (xr_stdcall *UnvoidStaticFunctionPtr)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, - Param6 p6, Param7 p7, Param8 p8); - typedef RetType (xr_stdcall detail::GenericClass::*GenericMemFn)( - Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7, Param8 p8); - typedef detail::ClosurePtr ClosureType; - ClosureType m_Closure; - public: - // Typedefs to aid generic programming - typedef FastDelegate8 type; - - // Construction and comparison functions - FastDelegate8() { clear(); } - - FastDelegate8(const FastDelegate8& x) - { - m_Closure.CopyFrom(this, x.m_Closure); - } - - void operator =(const FastDelegate8& x) - { - m_Closure.CopyFrom(this, x.m_Closure); - } - - bool operator ==(const FastDelegate8& x) const - { - return m_Closure.IsEqual(x.m_Closure); - } - - bool operator !=(const FastDelegate8& x) const - { - return !m_Closure.IsEqual(x.m_Closure); - } - - bool operator <(const FastDelegate8& x) const - { - return m_Closure.IsLess(x.m_Closure); - } - - bool operator >(const FastDelegate8& x) const - { - return x.m_Closure.IsLess(m_Closure); - } - - // Binding to non-const member functions - template - FastDelegate8(Y* pthis, DesiredRetType (xr_stdcall X::* function_to_bind)( - Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7, Param8 p8)) - { - m_Closure.bindmemfunc(detail::implicit_cast(pthis), function_to_bind); - } - - template - inline void bind(Y* pthis, DesiredRetType (xr_stdcall X::* function_to_bind)( - Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7, Param8 p8)) - { - m_Closure.bindmemfunc(detail::implicit_cast(pthis), function_to_bind); - } - - // Binding to const member functions. - template - FastDelegate8(const Y* pthis, - DesiredRetType (xr_stdcall X::* function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, - Param5 p5, Param6 p6, Param7 p7, - Param8 p8) const) - { - m_Closure.bindconstmemfunc(detail::implicit_cast(pthis), function_to_bind); - } - - template - inline void bind(const Y* pthis, - DesiredRetType (xr_stdcall X::* function_to_bind)( - Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7, - Param8 p8) const) - { - m_Closure.bindconstmemfunc(detail::implicit_cast(pthis), function_to_bind); - } - - // Static functions. We convert them into a member function call. - // This constructor also provides implicit conversion - FastDelegate8(DesiredRetType (xr_stdcall *function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, - Param5 p5, Param6 p6, Param7 p7, Param8 p8)) - { - bind(function_to_bind); - } - - // for efficiency, prevent creation of a temporary - void operator =(DesiredRetType (xr_stdcall *function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, - Param5 p5, Param6 p6, Param7 p7, Param8 p8)) - { - bind(function_to_bind); - } - - inline void bind(DesiredRetType (xr_stdcall *function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, - Param5 p5, Param6 p6, Param7 p7, Param8 p8)) - { - m_Closure.bindstaticfunc(this, &FastDelegate8::InvokeStaticFunction, - function_to_bind); - } - - // Invoke the delegate - RetType operator()(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7, Param8 p8) const - { - return (m_Closure.GetClosureThis()->*(m_Closure.GetClosureMemPtr()))(p1, p2, p3, p4, p5, p6, p7, p8); - } - - // Implicit conversion to "bool" using the safe_bool idiom - private: - typedef struct SafeBoolStruct - { - int a_data_pointer_to_this_is_0_on_buggy_compilers; - StaticFunctionPtr m_nonzero; - } UselessTypedef; - - typedef StaticFunctionPtr SafeBoolStruct::* unspecified_bool_type; - public: - operator unspecified_bool_type() const - { - return empty() ? 0 : &SafeBoolStruct::m_nonzero; - } - - // necessary to allow ==0 to work despite the safe_bool idiom - inline bool operator==(StaticFunctionPtr funcptr) - { - return m_Closure.IsEqualToStaticFuncPtr(funcptr); - } - - inline bool operator!=(StaticFunctionPtr funcptr) - { - return !m_Closure.IsEqualToStaticFuncPtr(funcptr); - } - - inline bool operator !() const - { - // Is it bound to anything? - return !m_Closure; - } - - inline bool empty() const - { - return !m_Closure; - } - - void clear() { m_Closure.clear(); } - // Conversion to and from the DelegateMemento storage class - const DelegateMemento& GetMemento() { return m_Closure; } - void SetMemento(const DelegateMemento& any) { m_Closure.CopyFrom(this, any); } - - private: // Invoker for static functions - RetType xr_stdcall InvokeStaticFunction(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, - Param7 p7, Param8 p8) const - { - return (*(m_Closure.GetStaticFunction()))(p1, p2, p3, p4, p5, p6, p7, p8); - } - }; - - - //////////////////////////////////////////////////////////////////////////////// - // Fast Delegates, part 4: - // - // FastDelegate<> class (Original author: Jody Hagins) - // Allows boost::function style syntax like: - // FastDelegate< double (int, long) > - // instead of: - // FastDelegate2< int, long, double > - // - //////////////////////////////////////////////////////////////////////////////// + // Does the closure contain this static function? + inline bool IsEqualToStaticFuncPtr(StaticFuncPtr funcptr){ + if (funcptr==0) return empty(); + // For the Evil method, if it doesn't actually contain a static function, this will return an arbitrary + // value that is not equal to any valid function pointer. + else return funcptr==reinterpret_cast(GetStaticFunction()); + } +}; + + +} // namespace detail + +//////////////////////////////////////////////////////////////////////////////// +// Fast Delegates, part 3: +// +// Wrapper classes to ensure type safety +// +//////////////////////////////////////////////////////////////////////////////// + + +// Once we have the member function conversion templates, it's easy to make the +// wrapper classes. So that they will work with as many compilers as possible, +// the classes are of the form +// FastDelegate3 +// They can cope with any combination of parameters. The max number of parameters +// allowed is 8, but it is trivial to increase this limit. +// Note that we need to treat const member functions seperately. +// All this class does is to enforce type safety, and invoke the delegate with +// the correct list of parameters. + +// Because of the weird rule about the class of derived member function pointers, +// you sometimes need to apply a downcast to the 'this' pointer. +// This is the reason for the use of "implicit_cast(pthis)" in the code below. +// If CDerivedClass is derived from CBaseClass, but doesn't override SimpleVirtualFunction, +// without this trick you'd need to write: +// MyDelegate(static_cast(&d), &CDerivedClass::SimpleVirtualFunction); +// but with the trick you can write +// MyDelegate(&d, &CDerivedClass::SimpleVirtualFunction); + +// RetType is the type the compiler uses in compiling the template. For VC6, +// it cannot be void. DesiredRetType is the real type which is returned from +// all of the functions. It can be void. + +// Implicit conversion to "bool" is achieved using the safe_bool idiom, +// using member data pointers (MDP). This allows "if (dg)..." syntax +// Because some compilers (eg codeplay) don't have a unique value for a zero +// MDP, an extra padding member is added to the SafeBool struct. +// Some compilers (eg VC6) won't implicitly convert from 0 to an MDP, so +// in that case the static function constructor is not made explicit; this +// allows "if (dg==0) ..." to compile. + +template +class FastDelegateImpl { +private: + typedef typename detail::DefaultVoidToVoid::type DesiredRetType; + typedef DesiredRetType (*StaticFunctionPtr)(Args...); + typedef RetType (*UnvoidStaticFunctionPtr)(Args...); + typedef RetType (detail::GenericClass::*GenericMemFn)(Args...); + typedef detail::ClosurePtr ClosureType; + ClosureType m_Closure; +public: + // Typedefs to aid generic programming + typedef FastDelegateImpl type; + + // Construction and comparison functions + FastDelegateImpl() { clear(); } + FastDelegateImpl(const FastDelegateImpl &x) { + m_Closure.CopyFrom(this, x.m_Closure); } + void operator = (const FastDelegateImpl &x) { + m_Closure.CopyFrom(this, x.m_Closure); } + bool operator ==(const FastDelegateImpl &x) const { + return m_Closure.IsEqual(x.m_Closure); } + bool operator !=(const FastDelegateImpl &x) const { + return !m_Closure.IsEqual(x.m_Closure); } + bool operator <(const FastDelegateImpl &x) const { + return m_Closure.IsLess(x.m_Closure); } + bool operator >(const FastDelegateImpl &x) const { + return x.m_Closure.IsLess(m_Closure); } + // Binding to non-const member functions + template < typename X, typename Y > + FastDelegateImpl(Y *pthis, DesiredRetType (X::* function_to_bind)(Args... args) ) { + m_Closure.bindmemfunc(detail::implicit_cast(pthis), function_to_bind); } + template < typename X, typename Y > + inline void bind(Y *pthis, DesiredRetType (X::* function_to_bind)(Args... args)) { + m_Closure.bindmemfunc(detail::implicit_cast(pthis), function_to_bind); } + // Binding to const member functions. + template < typename X, typename Y > + FastDelegateImpl(const Y *pthis, DesiredRetType (X::* function_to_bind)(Args... args) const) { + m_Closure.bindconstmemfunc(detail::implicit_cast(pthis), function_to_bind); } + template < typename X, typename Y > + inline void bind(const Y *pthis, DesiredRetType (X::* function_to_bind)(Args... args) const) { + m_Closure.bindconstmemfunc(detail::implicit_cast(pthis), function_to_bind); } + // Static functions. We convert them into a member function call. + // This constructor also provides implicit conversion + FastDelegateImpl(DesiredRetType (*function_to_bind)(Args... args) ) { + bind(function_to_bind); } + // for efficiency, prevent creation of a temporary + void operator = (DesiredRetType (*function_to_bind)(Args... args) ) { + bind(function_to_bind); } + inline void bind(DesiredRetType (*function_to_bind)(Args... args)) { + m_Closure.bindstaticfunc(this, &FastDelegateImpl::InvokeStaticFunction, + function_to_bind); } + // Invoke the delegate + RetType operator() (Args... args) const { + return (m_Closure.GetClosureThis()->*(m_Closure.GetClosureMemPtr()))(args...); } + // Implicit conversion to "bool" using the safe_bool idiom +private: + typedef struct SafeBoolStruct { + int a_data_pointer_to_this_is_0_on_buggy_compilers; + StaticFunctionPtr m_nonzero; + } UselessTypedef; + typedef StaticFunctionPtr SafeBoolStruct::*unspecified_bool_type; +public: + operator unspecified_bool_type() const { + return empty()? 0: &SafeBoolStruct::m_nonzero; + } + // necessary to allow ==0 to work despite the safe_bool idiom + inline bool operator==(StaticFunctionPtr funcptr) { + return m_Closure.IsEqualToStaticFuncPtr(funcptr); } + inline bool operator!=(StaticFunctionPtr funcptr) { + return !m_Closure.IsEqualToStaticFuncPtr(funcptr); } + inline bool operator ! () const { // Is it bound to anything? + return !m_Closure; } + inline bool empty() const { + return !m_Closure; } + void clear() { m_Closure.clear();} + // Conversion to and from the DelegateMemento storage class + const DelegateMemento & GetMemento() const { return m_Closure; } + void SetMemento(const DelegateMemento &any) { m_Closure.CopyFrom(this, any); } + +private: // Invoker for static functions + RetType InvokeStaticFunction(Args... args) const { + return (*(m_Closure.GetStaticFunction()))(args...); } +}; + +//////////////////////////////////////////////////////////////////////////////// +// Fast Delegates, part 4: +// +// FastDelegate<> class (Original author: Jody Hagins) +// Allows boost::function style syntax like: +// FastDelegate< double (int, long) > +// instead of: +// FastDelegate2< int, long, double > +// +//////////////////////////////////////////////////////////////////////////////// #ifdef FASTDELEGATE_ALLOW_FUNCTION_TYPE_SYNTAX - // Declare FastDelegate as a class template. It will be specialized - // later for all number of arguments. - template - class FastDelegate; - - //N=0 - // Specialization to allow use of - // FastDelegate< R ( ) > - // instead of - // FastDelegate0 < R > - template - class FastDelegate - // Inherit from FastDelegate0 so that it can be treated just like a FastDelegate0 - : public FastDelegate0 - { - public: - // Make using the base type a bit easier via typedef. - typedef FastDelegate0 BaseType; - - // Allow users access to the specific type of this delegate. - typedef FastDelegate SelfType; - - // Mimic the base class constructors. - FastDelegate() : BaseType() - { - } - - template - FastDelegate(Y* pthis, - R (xr_stdcall X::* function_to_bind)()) - : BaseType(pthis, function_to_bind) - { - } - - template - FastDelegate(const Y* pthis, - R (xr_stdcall X::* function_to_bind)() const) - : BaseType(pthis, function_to_bind) - { - } - - FastDelegate(R (xr_stdcall *function_to_bind)()) - : BaseType(function_to_bind) - { - } - - void operator =(const BaseType& x) - { - *static_cast(this) = x; - } - }; - - //N=1 - // Specialization to allow use of - // FastDelegate< R ( Param1 ) > - // instead of - // FastDelegate1 < Param1, R > - template - class FastDelegate - // Inherit from FastDelegate1 so that it can be treated just like a FastDelegate1 - : public FastDelegate1 - { - public: - // Make using the base type a bit easier via typedef. - typedef FastDelegate1 BaseType; - - // Allow users access to the specific type of this delegate. - typedef FastDelegate SelfType; - - // Mimic the base class constructors. - FastDelegate() : BaseType() - { - } - - template - FastDelegate(Y* pthis, - R (xr_stdcall X::* function_to_bind)(Param1 p1)) - : BaseType(pthis, function_to_bind) - { - } - - template - FastDelegate(const Y* pthis, - R (xr_stdcall X::* function_to_bind)(Param1 p1) const) - : BaseType(pthis, function_to_bind) - { - } - - FastDelegate(R (xr_stdcall *function_to_bind)(Param1 p1)) - : BaseType(function_to_bind) - { - } - - void operator =(const BaseType& x) - { - *static_cast(this) = x; - } - }; - - //N=2 - // Specialization to allow use of - // FastDelegate< R ( Param1, Param2 ) > - // instead of - // FastDelegate2 < Param1, Param2, R > - template - class FastDelegate - // Inherit from FastDelegate2 so that it can be treated just like a FastDelegate2 - : public FastDelegate2 - { - public: - // Make using the base type a bit easier via typedef. - typedef FastDelegate2 BaseType; - - // Allow users access to the specific type of this delegate. - typedef FastDelegate SelfType; - - // Mimic the base class constructors. - FastDelegate() : BaseType() - { - } - - template - FastDelegate(Y* pthis, - R (xr_stdcall X::* function_to_bind)(Param1 p1, Param2 p2)) - : BaseType(pthis, function_to_bind) - { - } - - template - FastDelegate(const Y* pthis, - R (xr_stdcall X::* function_to_bind)(Param1 p1, Param2 p2) const) - : BaseType(pthis, function_to_bind) - { - } - - FastDelegate(R (xr_stdcall *function_to_bind)(Param1 p1, Param2 p2)) - : BaseType(function_to_bind) - { - } - - void operator =(const BaseType& x) - { - *static_cast(this) = x; - } - }; - - //N=3 - // Specialization to allow use of - // FastDelegate< R ( Param1, Param2, Param3 ) > - // instead of - // FastDelegate3 < Param1, Param2, Param3, R > - template - class FastDelegate - // Inherit from FastDelegate3 so that it can be treated just like a FastDelegate3 - : public FastDelegate3 - { - public: - // Make using the base type a bit easier via typedef. - typedef FastDelegate3 BaseType; - - // Allow users access to the specific type of this delegate. - typedef FastDelegate SelfType; - - // Mimic the base class constructors. - FastDelegate() : BaseType() - { - } - - template - FastDelegate(Y* pthis, - R (xr_stdcall X::* function_to_bind)(Param1 p1, Param2 p2, Param3 p3)) - : BaseType(pthis, function_to_bind) - { - } - - template - FastDelegate(const Y* pthis, - R (xr_stdcall X::* function_to_bind)(Param1 p1, Param2 p2, Param3 p3) const) - : BaseType(pthis, function_to_bind) - { - } - - FastDelegate(R (xr_stdcall *function_to_bind)(Param1 p1, Param2 p2, Param3 p3)) - : BaseType(function_to_bind) - { - } - - void operator =(const BaseType& x) - { - *static_cast(this) = x; - } - }; - - //N=4 - // Specialization to allow use of - // FastDelegate< R ( Param1, Param2, Param3, Param4 ) > - // instead of - // FastDelegate4 < Param1, Param2, Param3, Param4, R > - template - class FastDelegate - // Inherit from FastDelegate4 so that it can be treated just like a FastDelegate4 - : public FastDelegate4 - { - public: - // Make using the base type a bit easier via typedef. - typedef FastDelegate4 BaseType; - - // Allow users access to the specific type of this delegate. - typedef FastDelegate SelfType; - - // Mimic the base class constructors. - FastDelegate() : BaseType() - { - } - - template - FastDelegate(Y* pthis, - R (xr_stdcall X::* function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4)) - : BaseType(pthis, function_to_bind) - { - } - - template - FastDelegate(const Y* pthis, - R (xr_stdcall X::* function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4) const) - : BaseType(pthis, function_to_bind) - { - } - - FastDelegate(R (xr_stdcall *function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4)) - : BaseType(function_to_bind) - { - } - - void operator =(const BaseType& x) - { - *static_cast(this) = x; - } - }; - - //N=5 - // Specialization to allow use of - // FastDelegate< R ( Param1, Param2, Param3, Param4, Param5 ) > - // instead of - // FastDelegate5 < Param1, Param2, Param3, Param4, Param5, R > - template - class FastDelegate - // Inherit from FastDelegate5 so that it can be treated just like a FastDelegate5 - : public FastDelegate5 - { - public: - // Make using the base type a bit easier via typedef. - typedef FastDelegate5 BaseType; - - // Allow users access to the specific type of this delegate. - typedef FastDelegate SelfType; - - // Mimic the base class constructors. - FastDelegate() : BaseType() - { - } - - template - FastDelegate(Y* pthis, - R (xr_stdcall X::* function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5)) - : BaseType(pthis, function_to_bind) - { - } - - template - FastDelegate(const Y* pthis, - R (xr_stdcall X::* function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5) const) - : BaseType(pthis, function_to_bind) - { - } - - FastDelegate(R (xr_stdcall *function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5)) - : BaseType(function_to_bind) - { - } - - void operator =(const BaseType& x) - { - *static_cast(this) = x; - } - }; - - //N=6 - // Specialization to allow use of - // FastDelegate< R ( Param1, Param2, Param3, Param4, Param5, Param6 ) > - // instead of - // FastDelegate6 < Param1, Param2, Param3, Param4, Param5, Param6, R > - template - class FastDelegate - // Inherit from FastDelegate6 so that it can be treated just like a FastDelegate6 - : public FastDelegate6 - { - public: - // Make using the base type a bit easier via typedef. - typedef FastDelegate6 BaseType; - - // Allow users access to the specific type of this delegate. - typedef FastDelegate SelfType; - - // Mimic the base class constructors. - FastDelegate() : BaseType() - { - } - - template - FastDelegate(Y* pthis, - R (xr_stdcall X::* function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, - Param6 p6)) - : BaseType(pthis, function_to_bind) - { - } - - template - FastDelegate(const Y* pthis, - R (xr_stdcall X::* function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, - Param6 p6) const) - : BaseType(pthis, function_to_bind) - { - } - - FastDelegate(R (xr_stdcall *function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6)) - : BaseType(function_to_bind) - { - } - - void operator =(const BaseType& x) - { - *static_cast(this) = x; - } - }; - - //N=7 - // Specialization to allow use of - // FastDelegate< R ( Param1, Param2, Param3, Param4, Param5, Param6, Param7 ) > - // instead of - // FastDelegate7 < Param1, Param2, Param3, Param4, Param5, Param6, Param7, R > - template - class FastDelegate - // Inherit from FastDelegate7 so that it can be treated just like a FastDelegate7 - : public FastDelegate7 - { - public: - // Make using the base type a bit easier via typedef. - typedef FastDelegate7 BaseType; - - // Allow users access to the specific type of this delegate. - typedef FastDelegate SelfType; - - // Mimic the base class constructors. - FastDelegate() : BaseType() - { - } - - template - FastDelegate(Y* pthis, - R (xr_stdcall X::* function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, - Param6 p6, Param7 p7)) - : BaseType(pthis, function_to_bind) - { - } - - template - FastDelegate(const Y* pthis, - R (xr_stdcall X::* function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, - Param6 p6, Param7 p7) const) - : BaseType(pthis, function_to_bind) - { - } - - FastDelegate(R (xr_stdcall *function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, - Param7 p7)) - : BaseType(function_to_bind) - { - } - - void operator =(const BaseType& x) - { - *static_cast(this) = x; - } - }; - - //N=8 - // Specialization to allow use of - // FastDelegate< R ( Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8 ) > - // instead of - // FastDelegate8 < Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, R > - template - class FastDelegate - // Inherit from FastDelegate8 so that it can be treated just like a FastDelegate8 - : public FastDelegate8 - { - public: - // Make using the base type a bit easier via typedef. - typedef FastDelegate8 BaseType; - - // Allow users access to the specific type of this delegate. - typedef FastDelegate SelfType; - - // Mimic the base class constructors. - FastDelegate() : BaseType() - { - } - - template - FastDelegate(Y* pthis, - R (xr_stdcall X::* function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, - Param6 p6, Param7 p7, Param8 p8)) - : BaseType(pthis, function_to_bind) - { - } - - template - FastDelegate(const Y* pthis, - R (xr_stdcall X::* function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, - Param6 p6, Param7 p7, Param8 p8) const) - : BaseType(pthis, function_to_bind) - { - } - - FastDelegate(R (xr_stdcall *function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, - Param7 p7, Param8 p8)) - : BaseType(function_to_bind) - { - } - - void operator =(const BaseType& x) - { - *static_cast(this) = x; - } - }; +// Declare FastDelegate as a class template. It will be specialized +// later for all number of arguments. +template +class FastDelegate; +template +class FastDelegate + // Inherit from FastDelegate1 so that it can be treated just like a FastDelegate1 + : public FastDelegateImpl < RetType, Args... > +{ +public: + // Make using the base type a bit easier via typedef. + typedef FastDelegateImpl < RetType, Args... > BaseType; + + // Allow users access to the specific type of this delegate. + typedef FastDelegate SelfType; + + // Mimic the base class constructors. + FastDelegate() : BaseType() { } + + template < typename X, typename Y > + FastDelegate(Y * pthis, + RetType (X::* function_to_bind)( Args... args )) + : BaseType(pthis, function_to_bind) { } + + template < typename X, typename Y > + FastDelegate(const Y *pthis, + RetType (X::* function_to_bind)( Args... args ) const) + : BaseType(pthis, function_to_bind) + { } + + FastDelegate(RetType (*function_to_bind)( Args... args )) + : BaseType(function_to_bind) { } + void operator = (const BaseType &x) { + *static_cast(this) = x; } +}; #endif //FASTDELEGATE_ALLOW_FUNCTION_TYPE_SYNTAX - //////////////////////////////////////////////////////////////////////////////// - // Fast Delegates, part 5: - // - // MakeDelegate() helper function - // - // MakeDelegate(&x, &X::func) returns a fastdelegate of the type - // necessary for calling x.func() with the correct number of arguments. - // This makes it possible to eliminate many typedefs from user code. - // - //////////////////////////////////////////////////////////////////////////////// - - // Also declare overloads of a MakeDelegate() global function to - // reduce the need for typedefs. - // We need seperate overloads for const and non-const member functions. - // Also, because of the weird rule about the class of derived member function pointers, - // implicit downcasts may need to be applied later to the 'this' pointer. - // That's why two classes (X and Y) appear in the definitions. Y must be implicitly - // castable to X. - - // Workaround for VC6. VC6 needs void return types converted into DefaultVoid. - // GCC 3.2 and later won't compile this unless it's preceded by 'typename', - // but VC6 doesn't allow 'typename' in this context. - // So, I have to use a macro. - -#ifdef FASTDLGT_VC6 -#define FASTDLGT_RETTYPE detail::VoidToDefaultVoid::type -#else -#define FASTDLGT_RETTYPE RetType -#endif - - //N=0 - template - FastDelegate0 MakeDelegate(Y* x, RetType (xr_stdcall X::*func)()) - { - return FastDelegate0(x, func); - } - - template - FastDelegate0 MakeDelegate(Y* x, RetType (xr_stdcall X::*func)() const) - { - return FastDelegate0(x, func); - } - - //N=1 - template - FastDelegate1 MakeDelegate(Y* x, RetType (xr_stdcall X::*func)(Param1 p1)) - { - return FastDelegate1(x, func); - } - - template - FastDelegate1 MakeDelegate(Y* x, RetType (xr_stdcall X::*func)(Param1 p1) const) - { - return FastDelegate1(x, func); - } - - //N=2 - template - FastDelegate2 MakeDelegate( - Y* x, RetType (xr_stdcall X::*func)(Param1 p1, Param2 p2)) - { - return FastDelegate2(x, func); - } - - template - FastDelegate2 MakeDelegate( - Y* x, RetType (xr_stdcall X::*func)(Param1 p1, Param2 p2) const) - { - return FastDelegate2(x, func); - } - - //N=3 - template - FastDelegate3 MakeDelegate( - Y* x, RetType (xr_stdcall X::*func)(Param1 p1, Param2 p2, Param3 p3)) - { - return FastDelegate3(x, func); - } - - template - FastDelegate3 MakeDelegate( - Y* x, RetType (xr_stdcall X::*func)(Param1 p1, Param2 p2, Param3 p3) const) - { - return FastDelegate3(x, func); - } - - //N=4 - template - FastDelegate4 MakeDelegate( - Y* x, RetType (xr_stdcall X::*func)(Param1 p1, Param2 p2, Param3 p3, Param4 p4)) - { - return FastDelegate4(x, func); - } - - template - FastDelegate4 MakeDelegate( - Y* x, RetType (xr_stdcall X::*func)(Param1 p1, Param2 p2, Param3 p3, Param4 p4) const) - { - return FastDelegate4(x, func); - } - - //N=5 - template - FastDelegate5 MakeDelegate( - Y* x, RetType (xr_stdcall X::*func)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5)) - { - return FastDelegate5(x, func); - } - - template - FastDelegate5 MakeDelegate( - Y* x, RetType (xr_stdcall X::*func)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5) const) - { - return FastDelegate5(x, func); - } - - //N=6 - template - FastDelegate6 MakeDelegate( - Y* x, RetType (xr_stdcall X::*func)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6)) - { - return FastDelegate6(x, func); - } - - template - FastDelegate6 MakeDelegate( - Y* x, RetType (xr_stdcall X::*func)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6) const) - { - return FastDelegate6(x, func); - } - - //N=7 - template - FastDelegate7 MakeDelegate( - Y* x, RetType (X::*func)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7)) - { - return FastDelegate7(x, func); - } - - template - FastDelegate7 MakeDelegate( - Y* x, RetType (X::*func)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7) const) - { - return FastDelegate7(x, func); - } - - //N=8 - template - FastDelegate8 MakeDelegate( - Y* x, RetType (X::*func)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7, - Param8 p8)) - { - return FastDelegate8(x, func); - } - - template - FastDelegate8 MakeDelegate( - Y* x, RetType (X::*func)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7, - Param8 p8) const) - { - return FastDelegate8(x, func); - } - -#ifdef __BORLANDC__ -template - A bind(B b) {A a; a.bind(b); return a;} -template - A bind(B b,C c) {A a; a.bind(b,c); return a;} -#endif +//////////////////////////////////////////////////////////////////////////////// +// Fast Delegates, part 5: +// +// MakeDelegate() helper function +// +// MakeDelegate(&x, &X::func) returns a fastdelegate of the type +// necessary for calling x.func() with the correct number of arguments. +// This makes it possible to eliminate many typedefs from user code. +// +//////////////////////////////////////////////////////////////////////////////// - // clean up after ourselves... +// Also declare overloads of a MakeDelegate() global function to +// reduce the need for typedefs. +// We need seperate overloads for const and non-const member functions. +// Also, because of the weird rule about the class of derived member function pointers, +// implicit downcasts may need to be applied later to the 'this' pointer. +// That's why two classes (X and Y) appear in the definitions. Y must be implicitly +// castable to X. + +template +FastDelegate MakeDelegate(RetType (*func)(Args...)) { + return FastDelegate(func); +} + +template +FastDelegate MakeDelegate(Y* x, RetType (X::*func)(Args...)) { + return FastDelegate(x, func); +} + +template +FastDelegate MakeDelegate(Y* x, RetType (X::*func)(Args...) const) { + return FastDelegate(x, func); +} + +// clean up after ourselves... #undef FASTDLGT_RETTYPE + } // namespace fastdelegate -#endif // !defined(FASTDELEGATE_H) +#endif // !defined(FASTDELEGATE_HPP) \ No newline at end of file diff --git a/src/3rd party/imgui/imgui.vcxproj b/src/3rd party/imgui/imgui.vcxproj index c78a8522a0..227f1c8568 100644 --- a/src/3rd party/imgui/imgui.vcxproj +++ b/src/3rd party/imgui/imgui.vcxproj @@ -9,6 +9,10 @@ Release-AVX x64 + + VerifiedDX11ASAN + x64 + Verified x64 @@ -33,6 +37,14 @@ Unicode x64 + + StaticLibrary + true + v143 + Unicode + x64 + true + StaticLibrary false @@ -66,6 +78,10 @@ + + + + @@ -85,6 +101,12 @@ $(xrIntDir)$(ProjectName)\ $(xrGameDir)bin_dbg\$(Platform)\$(Configuration)\;$(LibraryPath) + + $(IncludePath) + $(xrGameDir)bin_dbg\$(Platform)\$(Configuration)\ + $(xrIntDir)$(ProjectName)\ + $(xrGameDir)bin_dbg\$(Platform)\$(Configuration)\;$(LibraryPath) + $(IncludePath) $(xrGameDir)bin_dbg\$(Platform)\$(Configuration)\ @@ -125,6 +147,28 @@ true + + + Level3 + true + _DISABLE_VECTOR_ANNOTATION;_DISABLE_STRING_ANNOTATION;_DEBUG;_CONSOLE;USE_VERIFY_IN_RELEASE;%(PreprocessorDefinitions) + true + $(SolutionDir)3rd party\imgui\;%(AdditionalIncludeDirectories) + ProgramDatabase + false + Disabled + Disabled + Neither + false + MultiThreadedDLL + stdcpp17 + true + + + Console + true + + Level3 diff --git a/src/3rd party/lua-extensions/lua_extensions.vcxproj b/src/3rd party/lua-extensions/lua_extensions.vcxproj index a60aa82478..9a180cb429 100644 --- a/src/3rd party/lua-extensions/lua_extensions.vcxproj +++ b/src/3rd party/lua-extensions/lua_extensions.vcxproj @@ -13,6 +13,10 @@ Release x64 + + VerifiedDX11ASAN + x64 + VerifiedDX11 x64 @@ -59,6 +63,16 @@ v143 x64 + + StaticLibrary + false + false + MultiByte + false + v143 + x64 + true + StaticLibrary v143 @@ -84,6 +98,10 @@ + + + + @@ -121,6 +139,14 @@ $(xrGameDir)bin_dbg\$(Platform)\$(Configuration)\ $(xrIntDir)$(ProjectName)\ + + $(ProjectName) + $(VC_IncludePath);$(WindowsSDK_IncludePath); + $(VC_LibraryPath_x64);$(WindowsSDK_LibraryPath_x64); + true + $(xrGameDir)bin_dbg\$(Platform)\$(Configuration)\ + $(xrIntDir)$(ProjectName)\ + $(ProjectName) $(VC_IncludePath);$(WindowsSDK_IncludePath); @@ -251,6 +277,37 @@ Default + + + Disabled + false + $(SolutionDir)3rd party\luajit-2\src\;%(AdditionalIncludeDirectories) + Neither + _DISABLE_VECTOR_ANNOTATION;_DISABLE_STRING_ANNOTATION;USE_VERIFY_IN_RELEASE;_WINDLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + false + NotSet + 4996;4244;4018 + USE_LUAJIT_ONE + ProgramDatabase + false + Level3 + false + Disabled + SyncCThrow + stdcpp17 + true + + + true + true + $(SolutionDir)3rd party\luajit-2\src\;%(AdditionalLibraryDirectories) + true + false + $(xrLibDir)$(TargetName).lib + true + Default + + $(SolutionDir)3rd party\luajit-2\src\;%(AdditionalIncludeDirectories) diff --git a/src/3rd party/luabind/back_reference.hpp b/src/3rd party/luabind/back_reference.hpp index c0c7f353c3..e2abe4eb04 100644 --- a/src/3rd party/luabind/back_reference.hpp +++ b/src/3rd party/luabind/back_reference.hpp @@ -21,92 +21,90 @@ // OR OTHER DEALINGS IN THE SOFTWARE. #pragma once - #include #include #include -namespace luabind { +namespace luabind +{ template T* get_pointer(T& ref) { return &ref; } - namespace detail { - - template - struct extract_wrap_base - { - static wrap_base const* extract(T const* ptr) - { - return dynamic_cast(get_pointer(*ptr)); - } - - static wrap_base* extract(T* ptr) - { - return dynamic_cast(get_pointer(*ptr)); - } - }; - - struct default_back_reference {}; - - template - struct back_reference_impl : default_back_reference + namespace detail { - static bool extract(lua_State* L, T const* ptr) - { - if (!has_wrapper) return false; + template + struct extract_wrap_base + { + static wrap_base const* extract(T const* ptr) + { + return dynamic_cast(get_pointer(*ptr)); + } - if (wrap_base const* p = extract_wrap_base::extract(ptr)) + static wrap_base* extract(T* ptr) { - wrap_access::ref(*p).get(L); - return true; + return dynamic_cast(get_pointer(*ptr)); } + }; - return false; - } + struct default_back_reference {}; - static bool move(lua_State* L, T* ptr) + template + struct back_reference_impl : default_back_reference { - if (!has_wrapper) return false; - - if (wrap_base* p = extract_wrap_base::extract(ptr)) + static bool extract(lua_State* L, T const* ptr) { - assert(wrap_access::ref(*p).m_strong_ref.is_valid()); - wrap_access::ref(*p).get(L); - wrap_access::ref(*p).m_strong_ref.reset(); - return true; + if (!has_wrapper) return false; + + if (wrap_base const* p = extract_wrap_base::extract(ptr)) + { + wrap_access::ref(*p).get(L); + return true; + } + + return false; } - return false; - } + static bool move(lua_State* L, T* ptr) + { + if (!has_wrapper) return false; - static bool has_wrapper; - }; + if (wrap_base* p = extract_wrap_base::extract(ptr)) + { + assert(wrap_access::ref(*p).m_strong_ref.is_valid()); + wrap_access::ref(*p).get(L); + wrap_access::ref(*p).m_strong_ref.reset(); + return true; + } - template - bool back_reference_impl::has_wrapper = false; + return false; + } - template - struct back_reference_do_nothing - { - static bool extract(lua_State*, T const*) - { - return false; - } + static bool has_wrapper; + }; - static bool move(lua_State*, T*) + template + bool back_reference_impl::has_wrapper = false; + + template + struct back_reference_do_nothing { - return false; - } - }; + static bool extract(lua_State*, T const*) + { + return false; + } - } // namespace detail + static bool move(lua_State*, T*) + { + return false; + } + }; + } #ifndef LUABIND_NO_RTTI - template struct back_reference : std::conditional_t, @@ -117,13 +115,11 @@ namespace luabind { }; #else - template struct back_reference : detail::back_reference_do_nothing { }; - #endif -} // namespace luabind +} diff --git a/src/3rd party/luabind/class.hpp b/src/3rd party/luabind/class.hpp index d4075294c2..2708c46854 100644 --- a/src/3rd party/luabind/class.hpp +++ b/src/3rd party/luabind/class.hpp @@ -716,7 +716,7 @@ namespace luabind const char* name , std::function s); #else - void class_base::add_setter( + void add_setter( const char* name , std::function s , int (*match)(lua_State*, int) diff --git a/src/3rd party/luabind/class_info.hpp b/src/3rd party/luabind/class_info.hpp index ffc2817dca..b13c76a4f3 100644 --- a/src/3rd party/luabind/class_info.hpp +++ b/src/3rd party/luabind/class_info.hpp @@ -41,5 +41,5 @@ namespace luabind class_info get_class_info(const object&); - void bind_class_info(lua_State*); + LUABIND_API void bind_class_info(lua_State*); } diff --git a/src/3rd party/luabind/config.hpp b/src/3rd party/luabind/config.hpp index 07f5daa25d..fa93257397 100644 --- a/src/3rd party/luabind/config.hpp +++ b/src/3rd party/luabind/config.hpp @@ -21,6 +21,7 @@ // OR OTHER DEALINGS IN THE SOFTWARE. #pragma once +#include #define LUABIND_DONT_COPY_STRINGS @@ -69,7 +70,7 @@ // for all classes that you have type-info for. #ifndef LUABIND_TYPE_INFO -# define LUABIND_TYPE_INFO const type_info* +# define LUABIND_TYPE_INFO const std::type_info* # define LUABIND_TYPEID(t) &typeid(t) # define LUABIND_TYPE_INFO_EQUAL(i1, i2) *i1 == *i2 # define LUABIND_INVALID_TYPE_INFO &typeid(std::in_place_t) diff --git a/src/3rd party/luabind/detail/calc_has_arg.hpp b/src/3rd party/luabind/detail/calc_has_arg.hpp index 6dc7839933..ff122b8b22 100644 --- a/src/3rd party/luabind/detail/calc_has_arg.hpp +++ b/src/3rd party/luabind/detail/calc_has_arg.hpp @@ -17,7 +17,7 @@ struct calc_has_args template static constexpr int value() noexcept { - struct find_conversion_policy::type FindConversionsPolicyHack; + typename find_conversion_policy::type FindConversionsPolicyHack; using converter_policy = decltype(FindConversionsPolicyHack); return calc_has_args::template value(); } diff --git a/src/3rd party/luabind/detail/call_function.hpp b/src/3rd party/luabind/detail/call_function.hpp index 5f629fdd34..e14cf72029 100644 --- a/src/3rd party/luabind/detail/call_function.hpp +++ b/src/3rd party/luabind/detail/call_function.hpp @@ -101,6 +101,7 @@ namespace luabind assert(0 && "the lua function threw an error and exceptions are disabled." " If you want to handle the error you can use luabind::set_error_callback()"); + #endif } @@ -129,6 +130,7 @@ namespace luabind assert(0 && "the lua function threw an error and exceptions are disabled." " If you want to handle the error you can use luabind::set_error_callback()"); + #endif } @@ -147,6 +149,7 @@ namespace luabind assert(0 && "the lua function's return value could not be converted." " If you want to handle the error you can use luabind::set_error_callback()"); + #endif } #endif @@ -176,6 +179,7 @@ namespace luabind assert(0 && "the lua function threw an error and exceptions are disabled." " If you want to handle the error you can use luabind::set_error_callback()"); + #endif } @@ -194,6 +198,7 @@ namespace luabind assert(0 && "the lua function's return value could not be converted." " If you want to handle the error you can use luabind::set_error_callback()"); + #endif } #endif @@ -278,6 +283,7 @@ namespace luabind assert(0 && "the lua function threw an error and exceptions are disabled." " If you want to handle the error you can use luabind::set_error_callback()"); + #endif } // pops the return values from the function call @@ -304,6 +310,7 @@ namespace luabind assert(0 && "the lua function threw an error and exceptions are disabled." " If you want to handle the error you can use luabind::set_error_callback()"); + #endif } // pops the return values from the function call diff --git a/src/3rd party/luabind/detail/call_member.hpp b/src/3rd party/luabind/detail/call_member.hpp index f9360f5f9c..9380385df5 100644 --- a/src/3rd party/luabind/detail/call_member.hpp +++ b/src/3rd party/luabind/detail/call_member.hpp @@ -95,6 +95,7 @@ namespace luabind assert(0 && "the lua function threw an error and exceptions are disabled." "If you want to handle this error use luabind::set_error_callback()"); + #endif } // pops the return values from the function @@ -125,6 +126,7 @@ namespace luabind assert(0 && "the lua function threw an error and exceptions are disabled." "If you want to handle this error use luabind::set_error_callback()"); + #endif } @@ -144,6 +146,7 @@ namespace luabind assert(0 && "the lua function's return value could not be converted." "If you want to handle this error use luabind::set_error_callback()"); + #endif } #endif @@ -177,6 +180,7 @@ namespace luabind assert(0 && "the lua function threw an error and exceptions are disabled." "If you want to handle this error use luabind::set_error_callback()"); + #endif } @@ -196,6 +200,7 @@ namespace luabind assert(0 && "the lua function's return value could not be converted." "If you want to handle this error use luabind::set_error_callback()"); + #endif } #endif @@ -273,6 +278,7 @@ namespace luabind { assert(0 && "the lua function threw an error and exceptions are disabled." "If you want to handle this error use luabind::set_error_callback()"); + } #endif } @@ -304,6 +310,7 @@ namespace luabind assert(0 && "the lua function threw an error and exceptions are disabled." "If you want to handle this error use luabind::set_error_callback()"); + #endif } // pops the return values from the function diff --git a/src/3rd party/luabind/detail/class_registry.hpp b/src/3rd party/luabind/detail/class_registry.hpp index c49f1c2588..d598579eca 100644 --- a/src/3rd party/luabind/detail/class_registry.hpp +++ b/src/3rd party/luabind/detail/class_registry.hpp @@ -49,7 +49,7 @@ namespace luabind { namespace detail struct cmp { - bool operator()(const type_info* a, const type_info* b) const + bool operator()(const std::type_info* a, const std::type_info* b) const { return a->before(*b) != 0; } diff --git a/src/3rd party/luabind/detail/class_rep.hpp b/src/3rd party/luabind/detail/class_rep.hpp index 455061e15b..2651ea7f1a 100644 --- a/src/3rd party/luabind/detail/class_rep.hpp +++ b/src/3rd party/luabind/detail/class_rep.hpp @@ -309,6 +309,27 @@ namespace luabind { namespace detail }; typedef map_class STATIC_CONSTANTS; + +#pragma warning(push) +#pragma warning(disable:4251) + // ***** the maps below contains all members in this class ***** + // FX: Moved to public for make debug printing functional (IXR 18.08.2025) + + // list of methods. pointers into this list is put + // in the m_table_ref and m_default_table_ref + // for access. The struct contains the function- + // signatures for every overload + list_class m_methods; + + + // datamembers, some members may be readonly, and + // only have a getter function + map_class m_getters; + map_class m_setters; + + vector_class m_operators[number_of_operators]; // the operators in lua +#pragma warning(pop) + private: void cache_operators(lua_State*); @@ -406,27 +427,6 @@ namespace luabind { namespace detail // of this class. int m_instance_metatable; - // ***** the maps below contains all members in this class ***** - - // list of methods. pointers into this list is put - // in the m_table_ref and m_default_table_ref - // for access. The struct contains the function- - // signatures for every overload -#pragma warning(push) -#pragma warning(disable:4251) - list_class m_methods; -#pragma warning(pop) - - // datamembers, some members may be readonly, and - // only have a getter function -#pragma warning(push) -#pragma warning(disable:4251) - map_class m_getters; - map_class m_setters; - - vector_class m_operators[number_of_operators]; // the operators in lua -#pragma warning(pop) - void(*m_destructor)(void*); void(*m_const_holder_destructor)(void*); diff --git a/src/3rd party/luabind/detail/enum_maker.hpp b/src/3rd party/luabind/detail/enum_maker.hpp index 7c3643c37d..a2137469bd 100644 --- a/src/3rd party/luabind/detail/enum_maker.hpp +++ b/src/3rd party/luabind/detail/enum_maker.hpp @@ -22,6 +22,8 @@ #pragma once +#include +#include #include #include @@ -31,7 +33,6 @@ namespace luabind { struct value; - struct value_vector; struct value @@ -41,16 +42,16 @@ namespace luabind template value(const char* name, T v) : name_(name) - , val_(v) - {} + , val_(static_cast(v)) + { + } const char* name_; int val_; inline value_vector operator,(const value& rhs) const; - private: - + private: value() {} }; @@ -66,10 +67,8 @@ namespace luabind inline value_vector value::operator,(const value& rhs) const { value_vector v; - v.push_back(*this); v.push_back(rhs); - return v; } @@ -93,43 +92,93 @@ namespace luabind namespace detail { + template + struct is_value_type : std::false_type {}; + + template<> struct is_value_type : std::true_type {}; + template<> struct is_value_type : std::true_type {}; + + template + inline constexpr bool is_value_type_v = is_value_type>::value; + + template + using all_values_t = std::conjunction>...>; + template struct enum_maker { - explicit enum_maker(From&& from): from_(std::move(from)) {} + explicit enum_maker(From&& from) : from_(std::move(from)) {} - enum_maker(const enum_maker&) = delete; - enum_maker& operator= (const enum_maker&) = delete; + enum_maker(const enum_maker&) = delete; + enum_maker& operator= (const enum_maker&) = delete; - enum_maker(enum_maker&& that) noexcept - : from_(std::move(that.from_)) - { - } + enum_maker(enum_maker&& that) noexcept + : from_(std::move(that.from_)) + { + } - enum_maker& operator= (enum_maker&& that) noexcept - { - from_ = std::move(that.from_); - return *this; - } + enum_maker& operator= (enum_maker&& that) noexcept + { + from_ = std::move(that.from_); + return *this; + } - From operator[](const value& val) && + From operator[](const value& val)&& { - from_.add_static_constant(val.name_, val.val_); + add_value(val); return std::move(from_); } - From operator[](const value_vector& values) && + From operator[](const value_vector& values)&& { - for (value_vector::const_iterator i = values.begin(); i != values.end(); ++i) - { - from_.add_static_constant(i->name_, i->val_); - } + add_value(values); + return std::move(from_); + } + From& operator[](const value& val)& + { + add_value(val); + return from_; + } + + From& operator[](const value_vector& values)& + { + add_value(values); + return from_; + } + + + template::value>> + From operator[](Args&&... args)&& + { + // expands in left-to-right order + (add_value(std::forward(args)), ...); return std::move(from_); } + template::value>> + From & operator[](Args&&... args)& + { + (add_value(std::forward(args)), ...); + return from_; + } + + private: + void add_value(const value& v) + { + from_.add_static_constant(v.name_, v.val_); + } + + void add_value(const value_vector& vv) + { + for (auto const& v : vv) + from_.add_static_constant(v.name_, v.val_); + } + private: - From from_; + From from_; }; } } diff --git a/src/3rd party/luabind/detail/get_signature.hpp b/src/3rd party/luabind/detail/get_signature.hpp index ff0a32ee98..0bcccaba54 100644 --- a/src/3rd party/luabind/detail/get_signature.hpp +++ b/src/3rd party/luabind/detail/get_signature.hpp @@ -82,7 +82,7 @@ namespace luabind { namespace detail }; template<> - struct type_name_unless_void + struct type_name_unless_void { static void apply(string_class&, lua_State*, const bool) {} }; diff --git a/src/3rd party/luabind/detail/object_funs.hpp b/src/3rd party/luabind/detail/object_funs.hpp index 1ed81718be..8d2685dc2c 100644 --- a/src/3rd party/luabind/detail/object_funs.hpp +++ b/src/3rd party/luabind/detail/object_funs.hpp @@ -47,6 +47,7 @@ namespace luabind if (e) e(L, LUABIND_TYPEID(T)); assert(0 && "object_cast failed. If you want to handle this error use luabind::set_error_callback()"); + #endif } @@ -69,6 +70,7 @@ namespace luabind if (e) e(L, LUABIND_TYPEID(T)); assert(0 && "object_cast failed. If you want to handle this error use luabind::set_error_callback()"); + #endif } #endif @@ -88,11 +90,8 @@ namespace luabind lua_State* L = obj.lua_state(); detail::stack_pop p(L, 1); -#ifndef LUABIND_NO_ERROR_CHECKING - if (converter.match(L, LUABIND_DECORATE_TYPE(T), -1) < 0) return std::optional(); -#endif return std::optional(converter.apply(L, LUABIND_DECORATE_TYPE(T), -1)); } diff --git a/src/3rd party/luabind/detail/overload_rep.hpp b/src/3rd party/luabind/detail/overload_rep.hpp index 3940f18eef..9f7e271665 100644 --- a/src/3rd party/luabind/detail/overload_rep.hpp +++ b/src/3rd party/luabind/detail/overload_rep.hpp @@ -84,6 +84,12 @@ namespace luabind::detail bool has_static() const { return static_cast(call_fun_static); } + + // the types of the parameter it takes +#pragma warning(push) +#pragma warning(disable:4251) + vector_class m_params_; +#pragma warning(pop) private: template overload_rep(const bool isConst, const imdexlib::typelist, const std::integral_constant, const policy_cons) @@ -110,12 +116,6 @@ namespace luabind::detail #pragma warning(disable:4251) std::function call_fun_static; #pragma warning(pop) - - // the types of the parameter it takes -#pragma warning(push) -#pragma warning(disable:4251) - vector_class m_params_; -#pragma warning(pop) // is true if the overload is const (this is a part of the signature) bool m_const; }; diff --git a/src/3rd party/luabind/detail/overload_rep_base.hpp b/src/3rd party/luabind/detail/overload_rep_base.hpp index 45356b490a..e55feca47f 100644 --- a/src/3rd party/luabind/detail/overload_rep_base.hpp +++ b/src/3rd party/luabind/detail/overload_rep_base.hpp @@ -32,8 +32,6 @@ extern "C" namespace luabind::detail { // this class represents a specific overload of a member-function. - template class LUABIND_API std::function; - struct LUABIND_API overload_rep_base { #if !defined(LUABIND_NO_ERROR_CHECKING) @@ -75,11 +73,7 @@ namespace luabind::detail { m_get_signature_fun = f; } -#endif - protected: - -#ifndef LUABIND_NO_ERROR_CHECKING get_sig_ptr m_get_signature_fun; #endif diff --git a/src/3rd party/luabind/detail/policy.hpp b/src/3rd party/luabind/detail/policy.hpp index f949060901..8711aaf3fc 100644 --- a/src/3rd party/luabind/detail/policy.hpp +++ b/src/3rd party/luabind/detail/policy.hpp @@ -53,8 +53,8 @@ namespace luabind template struct conversion_policy : detail::conversion_policy_base { - static constexpr int index = N; - static constexpr bool has_arg = HasArg; + static constexpr int index = N; + static constexpr bool has_arg = HasArg; }; class index_map @@ -104,7 +104,7 @@ namespace luabind template struct is_user_defined { - static constexpr bool value = std::is_same_v; + static constexpr bool value = std::is_same_v; }; } @@ -122,12 +122,12 @@ namespace luabind { namespace detail std::true_type is_lua_functor_test(const functor&); template - std::false_type is_lua_functor_test(const T&); + std::false_type is_lua_functor_test(const T&); template struct is_lua_functor { - static constexpr bool value = decltype(is_lua_functor_test(std::declval()))::value; + static constexpr bool value = decltype(is_lua_functor_test(std::declval()))::value; }; namespace @@ -157,7 +157,7 @@ namespace luabind { namespace detail template struct is_primitive { - static constexpr bool value = std::is_array_v && std::is_convertible_v; + static constexpr bool value = std::is_array_v && std::is_convertible_v; }; #define LUABIND_INTEGER_TYPE(type) \ @@ -172,6 +172,7 @@ namespace luabind { namespace detail LUABIND_INTEGER_TYPE(short) LUABIND_INTEGER_TYPE(int) LUABIND_INTEGER_TYPE(long) + LUABIND_INTEGER_TYPE(long long) template<> struct is_primitive : std::true_type {}; \ template<> struct is_primitive : std::true_type {}; \ @@ -239,6 +240,7 @@ namespace luabind { namespace detail void apply(lua_State* L, unsigned char v) { lua_pushnumber(L, (lua_Number)v); } void apply(lua_State* L, unsigned long v) { lua_pushnumber(L, (lua_Number)v); } void apply(lua_State* L, unsigned long long v) { lua_pushnumber(L, (lua_Number)v); } + void apply(lua_State* L, long long v) { lua_pushnumber(L, (lua_Number)v); } void apply(lua_State* L, float v) { lua_pushnumber(L, (lua_Number)v); } void apply(lua_State* L, double v) { lua_pushnumber(L, (lua_Number)v); } void apply(lua_State* L, long double v) { lua_pushnumber(L, (lua_Number)v); } @@ -322,6 +324,29 @@ namespace luabind { namespace detail return -1; } + PRIMITIVE_CONVERTER(long long) + { + if (lua_isnil(L, index)) + { + return 0; + } + + return static_cast(lua_tonumber(L, index)); + } + + PRIMITIVE_MATCHER(long long) + { + if (lua_isnil(L, index)) + { + return 0; + } + + if (lua_type(L, index) == LUA_TNUMBER) + return 0; + + return -1; + } + PRIMITIVE_CONVERTER(char) { if (lua_isnil(L, index)) @@ -361,7 +386,7 @@ namespace luabind { namespace detail else return -1; } - + PRIMITIVE_CONVERTER(unsigned char) { if (lua_isnil(L, index)) @@ -450,8 +475,7 @@ namespace luabind { namespace detail } return static_cast(lua_tonumber(L, index)); } - PRIMITIVE_MATCHER(unsigned long) - { + PRIMITIVE_MATCHER(unsigned long) { if (lua_isnil(L, index)) { return 0; @@ -460,17 +484,15 @@ namespace luabind { namespace detail else return -1; } - - PRIMITIVE_CONVERTER(unsigned long long) - { + + PRIMITIVE_CONVERTER(unsigned long long) { if (lua_isnil(L, index)) { return 0; } return static_cast(lua_tonumber(L, index)); } - PRIMITIVE_MATCHER(unsigned long long) - { + PRIMITIVE_MATCHER(unsigned long long) { if (lua_isnil(L, index)) { return 0; @@ -486,8 +508,7 @@ namespace luabind { namespace detail { return 0; } - return static_cast(lua_tonumber(L, index)); - } + return static_cast(lua_tonumber(L, index)); } PRIMITIVE_MATCHER(float) { if (lua_isnil(L, index)) @@ -500,16 +521,13 @@ namespace luabind { namespace detail return -1; } - PRIMITIVE_CONVERTER(double) - { + PRIMITIVE_CONVERTER(double) { if (lua_isnil(L, index)) { return 0; } - return static_cast(lua_tonumber(L, index)); - } - PRIMITIVE_MATCHER(double) - { + return static_cast(lua_tonumber(L, index)); } + PRIMITIVE_MATCHER(double) { if (lua_isnil(L, index)) { return 0; @@ -521,9 +539,7 @@ namespace luabind { namespace detail } PRIMITIVE_CONVERTER(string_class) - { - return string_class(lua_tostring(L, index), lua_strlen(L, index)); - } + { return string_class(lua_tostring(L, index), lua_strlen(L, index)); } PRIMITIVE_MATCHER(string_class) { if (lua_type(L, index) == LUA_TSTRING) return 0; else return -1; } PRIMITIVE_CONVERTER(luabind::object) @@ -539,8 +555,8 @@ namespace luabind { namespace detail (void)index; (void)L; //return std::numeric_limits::max() / LUABIND_MAX_ARITY; - constexpr const int kMaxArity = 1000; - return std::numeric_limits::max() / kMaxArity; + constexpr const int kMaxArity = 1000; + return std::numeric_limits::max() / kMaxArity; } PRIMITIVE_CONVERTER(luabind::weak_ref) @@ -927,7 +943,7 @@ namespace luabind { namespace detail if (LUABIND_TYPE_INFO_EQUAL(obj->crep()->const_holder_type(), LUABIND_TYPEID(T))) return (obj->flags() & object_rep::constant)?0:1; - bool const_ = obj->flags() & object_rep::constant; + bool const_ = obj->flags() & object_rep::constant; ptrdiff_t d; return implicit_cast(obj->crep(), LUABIND_TYPEID(T), d) + !const_; } @@ -1085,7 +1101,7 @@ namespace luabind { namespace detail if (LUABIND_TYPE_INFO_EQUAL(obj->crep()->const_holder_type(), LUABIND_TYPEID(T))) return (obj->flags() & object_rep::constant)?0:1; - bool const_ = obj->flags() & object_rep::constant; + bool const_ = obj->flags() & object_rep::constant; ptrdiff_t d; return implicit_cast(obj->crep(), LUABIND_TYPEID(T), d) + !const_; } @@ -1186,111 +1202,114 @@ namespace luabind { namespace detail struct default_policy : converter_policy_tag { - static constexpr bool has_arg = true; + static constexpr bool has_arg = true; template static void precall(lua_State*, T, int) {} - template - struct generate_converter - { - using type = std::conditional_t< - is_user_defined::value, - user_defined_converter, - std::conditional_t< - is_primitive::value, - primitive_converter, - std::conditional_t< - is_lua_functor::value, - functor_converter, - std::conditional_t< - std::is_enum_v, - enum_converter, - std::conditional_t< - is_nonconst_pointer::value, - pointer_converter, - std::conditional_t< - is_const_pointer::value, - const_pointer_converter, - std::conditional_t< - is_nonconst_reference::value, - ref_converter, - std::conditional_t< - is_const_reference::value, - const_ref_converter, - value_converter - > - > - > - > - > - > - > - >; - }; + template + struct generate_converter + { + using type = std::conditional_t< + is_user_defined::value, + user_defined_converter, + std::conditional_t< + is_primitive::value, + primitive_converter, + std::conditional_t< + is_lua_functor::value, + functor_converter, + std::conditional_t< + std::is_enum_v, + enum_converter, + std::conditional_t< + is_nonconst_pointer::value, + pointer_converter, + std::conditional_t< + is_const_pointer::value, + const_pointer_converter, + std::conditional_t< + is_nonconst_reference::value, + ref_converter, + std::conditional_t< + is_const_reference::value, + const_ref_converter, + value_converter + > + > + > + > + > + > + > + >; + }; }; // ============== new policy system ================= - template - struct is_conversion_policy_with_index_impl : public std::false_type - { - }; + template + struct is_conversion_policy_with_index_impl : public std::false_type + { + }; - template - struct is_conversion_policy_with_index_impl : public std::bool_constant - { - }; + template + struct is_conversion_policy_with_index_impl : public std::bool_constant + { + }; - template - struct is_conversion_policy_with_index : public is_conversion_policy_with_index_impl, Policy, Index> - { - }; + template + struct is_conversion_policy_with_index : public is_conversion_policy_with_index_impl, Policy, Index> + { + }; - template + template struct find_conversion_policy; template struct find_conversion_policy { - using type = std::conditional_t< - is_conversion_policy_with_index::value, - Policy, - typename find_conversion_policy::type - >; + using type = std::conditional_t< + is_conversion_policy_with_index::value, + Policy, + typename find_conversion_policy::type + >; + }; + + template + struct find_conversion_policy + { + using type = default_policy; }; - template - struct find_conversion_policy - { - using type = default_policy; - }; - - template - struct policy_list_postcall; - - template - struct policy_list_postcall - { - static void apply(lua_State* L, const index_map& i) - { - Policy::postcall(L, i); - policy_list_postcall::apply(L, i); - } - }; - - template<> - struct policy_list_postcall<> - { - static void apply(lua_State*, const index_map&) noexcept {} - }; + template + struct policy_list_postcall; + + template + struct policy_list_postcall + { + static void apply(lua_State* L, const index_map& i) + { + Policy::postcall(L, i); + policy_list_postcall::apply(L, i); + } + }; + + template<> + struct policy_list_postcall<> + { + static void apply(lua_State*, const index_map&) noexcept {} + }; } } -namespace luabind { namespace +namespace luabind { - constexpr size_t return_value = 0; - constexpr size_t result = return_value; -}} + namespace + { + constexpr size_t return_value = 0; + constexpr size_t result = return_value; + } +} #include diff --git a/src/3rd party/luabind/detail/property.hpp b/src/3rd party/luabind/detail/property.hpp index f1009f5903..60a7f49ebb 100644 --- a/src/3rd party/luabind/detail/property.hpp +++ b/src/3rd party/luabind/detail/property.hpp @@ -82,7 +82,7 @@ namespace luabind { namespace detail } }; - using match_fun_ptr = int (*)(lua_State*, ptrdiff_t); + using match_fun_ptr = int (*)(lua_State*, int); template struct set_matcher diff --git a/src/3rd party/luabind/detail/ref.hpp b/src/3rd party/luabind/detail/ref.hpp index 7c5f074138..ca0564324c 100644 --- a/src/3rd party/luabind/detail/ref.hpp +++ b/src/3rd party/luabind/detail/ref.hpp @@ -106,6 +106,8 @@ namespace luabind { namespace detail std::swap(r.m_ref, m_ref); } + int get_ref() const { return m_ref; } + private: lua_State* L; int m_ref; diff --git a/src/3rd party/luabind/functor.hpp b/src/3rd party/luabind/functor.hpp index 1d4fc8e500..a7854861fb 100644 --- a/src/3rd party/luabind/functor.hpp +++ b/src/3rd party/luabind/functor.hpp @@ -32,6 +32,93 @@ namespace luabind { + template + class functor + { + public: + + functor(lua_State* L, const char* name) + : L_(L) + { + lua_pushstring(L, name); + lua_gettable(L, LUA_GLOBALSINDEX); + ref_.set(L_); + } + + functor() + : L_(nullptr) + { + } + + functor(const functor& obj) + : L_(obj.L_) + , ref_(obj.ref_) + { + } + + // this is a safe substitute for an implicit converter to bool + typedef void (functor::*member_ptr)() const; + operator member_ptr() const + { + if (is_valid()) return &functor::dummy; + return nullptr; + } + + const functor& operator=(const functor& rhs) + { + L_ = rhs.L_; + ref_ = rhs.ref_; + return *this; + } + + bool operator==(const functor& rhs) const + { + if (!ref_.is_valid() || !rhs.ref_.is_valid()) return false; + pushvalue(); + rhs.pushvalue(); + const bool result = lua_equal(L_, -1, -2) != 0; + lua_pop(L_, 2); + return result; + } + + bool operator!=(const functor& rhs) const + { + if (!ref_.is_valid() || !rhs.ref_.is_valid()) return true; + pushvalue(); + rhs.pushvalue(); + const bool result = lua_equal(L_, -1, -2) == 0; + lua_pop(L_, 2); + return result; + } + + bool is_valid() const { return ref_.is_valid(); } + + lua_State* lua_state() const { return L_; } + void pushvalue() const { ref_.get(L_); } + + void reset() + { + L_ = nullptr; + ref_.reset(); + } + + template + decltype(auto) operator()(const Args&... args) const; + + functor(lua_State* L, detail::lua_reference const& ref) + : L_(L) + , ref_(ref) + { + } + + private: + + void dummy() const {} + + lua_State* L_; + detail::lua_reference ref_; + }; + namespace detail { // if the proxy_functor_caller returns non-void @@ -92,6 +179,7 @@ namespace luabind assert(0 && "the lua function threw an error and exceptions are disabled." "if you want to handle this error use luabind::set_error_callback()"); + #endif } } @@ -113,6 +201,7 @@ namespace luabind assert(0 && "tried to call uninitialized functor object." "if you want to handle this error use luabind::set_error_callback()"); + #endif } #endif @@ -349,101 +438,18 @@ namespace luabind mutable bool m_called; }; - } // detail + } template - class functor - { - public: - - functor(lua_State* L, const char* name) - : L_(L) - { - lua_pushstring(L, name); - lua_gettable(L, LUA_GLOBALSINDEX); - ref_.set(L_); - } - - functor() - : L_(nullptr) - { - } - - functor(const functor& obj) - : L_(obj.L_) - , ref_(obj.ref_) - { - } - - // this is a safe substitute for an implicit converter to bool - typedef void (functor::*member_ptr)() const; - operator member_ptr() const - { - if (is_valid()) return &functor::dummy; - return nullptr; - } - - const functor& operator=(const functor& rhs) - { - L_ = rhs.L_; - ref_ = rhs.ref_; - return *this; - } - - bool operator==(const functor& rhs) const - { - if (!ref_.is_valid() || !rhs.ref_.is_valid()) return false; - pushvalue(); - rhs.pushvalue(); - const bool result = lua_equal(L_, -1, -2) != 0; - lua_pop(L_, 2); - return result; - } - - bool operator!=(const functor& rhs) const - { - if (!ref_.is_valid() || !rhs.ref_.is_valid()) return true; - pushvalue(); - rhs.pushvalue(); - const bool result = lua_equal(L_, -1, -2) == 0; - lua_pop(L_, 2); - return result; - } - - bool is_valid() const { return ref_.is_valid(); } - - lua_State* lua_state() const { return L_; } - void pushvalue() const { ref_.get(L_); } - - void reset() - { - L_ = nullptr; - ref_.reset(); - } - - template - decltype(auto) operator()(const Args&... args) const - { - using proxy_type = std::conditional_t< - std::is_void_v, - luabind::detail::proxy_functor_void_caller, - luabind::detail::proxy_functor_caller - >; - - return proxy_type(const_cast*>(this), std::make_tuple(&args...)); - } - - functor(lua_State* L, detail::lua_reference const& ref) - : L_(L) - , ref_(ref) - { - } - - private: - - void dummy() const {} - - lua_State* L_; - detail::lua_reference ref_; - }; + template + decltype(auto) functor::operator()(const Args&... args) const + { + using proxy_type = std::conditional_t< + std::is_void_v, + luabind::detail::proxy_functor_void_caller, + luabind::detail::proxy_functor_caller + >; + + return proxy_type(const_cast*>(this), std::make_tuple(&args...)); + } } diff --git a/src/3rd party/luabind/iterator_pair_policy.hpp b/src/3rd party/luabind/iterator_pair_policy.hpp index 06f5de0774..6fbdcf1bad 100644 --- a/src/3rd party/luabind/iterator_pair_policy.hpp +++ b/src/3rd party/luabind/iterator_pair_policy.hpp @@ -1,75 +1,58 @@ - -#pragma once - -#include -#include -#include -#include - -namespace luabind { namespace detail +namespace luabind::detail { - template + template struct iterator_pair_state { - typedef iterator_pair_state self_t; + using Iter = typename Container::const_iterator; + + iterator_pair_state(std::shared_ptr c) + : container(std::move(c)), start(container->begin()), end(container->end()) + { + } static int step(lua_State* L) { - self_t& state = *static_cast(lua_touserdata(L, lua_upvalueindex(1))); + auto* state = static_cast(lua_touserdata(L, lua_upvalueindex(1))); - if (state.start == state.end) + if (!state || state->start == state->end) { lua_pushnil(L); - - return 1; + return 1; } - else - { - convert_to_lua(L, (*state.start).first); - convert_to_lua(L, (*state.start).second); - ++state.start; - return 2; // number of return values - } + convert_to_lua(L, state->start->first); + convert_to_lua(L, state->start->second); + ++state->start; + return 2; } - iterator_pair_state(const Iter&& s, const Iter&& e) - : start(std::move(s)) - , end(std::move(e)) - {} - - private: + std::shared_ptr container; Iter start, end; }; struct iterator_pair_converter { - template - void apply(lua_State* L, const T& c) - { - auto it_begin = c.crbegin(); - using state_t = iterator_pair_state; - - // note that this should be destructed, for now.. just hope that iterator is a pod - void* iter = lua_newuserdata(L, sizeof(state_t)); - new (iter) state_t(std::move(it_begin), c.crend()); - lua_pushcclosure(L, state_t::step, 1); - } - - template + template void apply(lua_State* L, T& c) { - auto it_begin = c.rbegin(); - using state_t = iterator_pair_state; + auto container_ptr = std::make_shared(c); + void* udata = lua_newuserdata(L, sizeof(iterator_pair_state)); + new (udata) iterator_pair_state(container_ptr); + lua_pushcclosure(L, iterator_pair_state::step, 1); + } - // note that this should be destructed, for now.. just hope that iterator is a pod - void* iter = lua_newuserdata(L, sizeof(state_t)); - new (iter) state_t(std::move(it_begin), c.rend()); - lua_pushcclosure(L, state_t::step, 1); + template + void apply(lua_State* L, const T& c) + { + auto container_ptr = std::make_shared(c); + void* udata = lua_newuserdata(L, sizeof(iterator_pair_state)); + new (udata) iterator_pair_state(container_ptr); + lua_pushcclosure(L, iterator_pair_state::step, 1); } }; - struct iterator_pair_policy : conversion_policy<0> + struct iterator_pair_policy : + conversion_policy<0> { static void precall(lua_State*, const index_map&) {} static void postcall(lua_State*, const index_map&) {} @@ -77,11 +60,10 @@ namespace luabind { namespace detail template struct generate_converter { - typedef iterator_pair_converter type; + using type = iterator_pair_converter; }; }; - -}} +} namespace luabind { diff --git a/src/3rd party/luabind/luabind.vcxproj b/src/3rd party/luabind/luabind.vcxproj index a23952c56b..7092c6789c 100644 --- a/src/3rd party/luabind/luabind.vcxproj +++ b/src/3rd party/luabind/luabind.vcxproj @@ -16,6 +16,10 @@ Profiled x64 + + VerifiedDX11ASAN + x64 + Verified x64 @@ -55,6 +59,14 @@ false x64 + + StaticLibrary + v143 + MultiByte + false + x64 + true + @@ -214,6 +226,42 @@ false + + + $(xrSdkDir)include;$(ProjectDir)..\luajit-2\src\;$(xrSdkDir)include\luabind;$(ProjectDir)luabind\src;$(ProjectDir);%(AdditionalIncludeDirectories) + ProgramDatabase + 4073;4100;4390;4714;4127;4273;4595;4996;4005;4530 + NotSet + false + false + Neither + true + Disabled + false + stdcpp17 + true + false + Disabled + NotUsing + _DISABLE_VECTOR_ANNOTATION;_DISABLE_STRING_ANNOTATION;USE_VERIFY_IN_RELEASE;WIN32;NDEBUG;LUABIND_BUILDING;_SECURE_SCL=0;_HAS_ITERATOR_DEBUGGING=0;LUABIND_NO_EXCEPTIONS;%(PreprocessorDefinitions) + false + USE_LUAJIT_ONE;MBCS + false + + + lua51.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;comdlg32.lib;advapi32.lib + .\;$(ProjectDir)..\luajit-2\src\;%(AdditionalLibraryDirectories) + true + $(xrLibDir)$(TargetName).lib + true + Default + false + false + + + false + + @@ -225,7 +273,6 @@ - diff --git a/src/3rd party/luabind/luabind.vcxproj.filters b/src/3rd party/luabind/luabind.vcxproj.filters index 21cd56e0bd..20f86d9e7a 100644 --- a/src/3rd party/luabind/luabind.vcxproj.filters +++ b/src/3rd party/luabind/luabind.vcxproj.filters @@ -20,7 +20,6 @@ - diff --git a/src/3rd party/luabind/luabind/src/class.cpp b/src/3rd party/luabind/luabind/src/class.cpp index 056e7031c7..d2da97dd27 100644 --- a/src/3rd party/luabind/luabind/src/class.cpp +++ b/src/3rd party/luabind/luabind/src/class.cpp @@ -280,7 +280,7 @@ namespace luabind { namespace detail { #else void class_base::add_setter( const char* name - , std::function s + , std::function s , int (*match)(lua_State*, int) , void (*get_sig_ptr)(lua_State*, string_class&)) #endif @@ -380,7 +380,7 @@ namespace luabind { namespace detail { template void add_custom_name(T i, string_class& s) {} - void add_custom_name(type_info const* i, string_class& s) + void add_custom_name(std::type_info const* i, string_class& s) { s += " ["; s += i->name(); diff --git a/src/3rd party/luabind/luabind/src/class_rep.cpp b/src/3rd party/luabind/luabind/src/class_rep.cpp index 1a5eda991e..9ab28a0c8f 100644 --- a/src/3rd party/luabind/luabind/src/class_rep.cpp +++ b/src/3rd party/luabind/luabind/src/class_rep.cpp @@ -449,7 +449,7 @@ int luabind::detail::class_rep::constructor_dispatcher(lua_State* L) bool ambiguous = false; int match_index = -1; int min_match = std::numeric_limits::max(); - bool found; + [[maybe_unused]]bool found = false; #ifdef LUABIND_NO_ERROR_CHECKING @@ -613,7 +613,7 @@ int luabind::detail::class_rep::function_dispatcher(lua_State* L) bool ambiguous = false; int match_index = -1; int min_match = std::numeric_limits::max(); - bool found; + [[maybe_unused]]bool found; #ifdef LUABIND_NO_ERROR_CHECKING if (rep->overloads().size() == 1) @@ -902,7 +902,7 @@ int luabind::detail::class_rep::super_callback(lua_State* L) bool ambiguous = false; int match_index = -1; int min_match = std::numeric_limits::max(); - bool found; + [[maybe_unused]]bool found; #ifdef LUABIND_NO_ERROR_CHECKING @@ -1296,9 +1296,8 @@ int luabind::detail::class_rep::lua_class_settable(lua_State* L) if (j == crep->m_setters.end() || std::strlen(key) != lua_strlen(L, 2)) { - map_class::iterator k = crep->m_getters.find(key); - #ifndef LUABIND_NO_ERROR_CHECKING + map_class::iterator k = crep->m_getters.find(key); if (k != crep->m_getters.end()) { @@ -1312,7 +1311,6 @@ int luabind::detail::class_rep::lua_class_settable(lua_State* L) } lua_error(L); } - #endif detail::lua_reference const& tbl = obj->get_lua_table(); @@ -1370,6 +1368,14 @@ int luabind::detail::class_rep::static_class_gettable(lua_State* L) msg += "' in class '"; msg += crep->name(); msg += "'"; + + // log the callstack + luabind::object debug_space = luabind::get_globals(L)["debug"]; + luabind::object traceback = debug_space["traceback"]; + string_class tracebackstr = luabind::call_function(traceback); + msg += "\n traceback: \n"; + msg += tracebackstr; + lua_pushstring(L, msg.c_str()); } lua_error(L); diff --git a/src/3rd party/luabind/luabind/src/function.cpp b/src/3rd party/luabind/luabind/src/function.cpp index 4d2df1cf5f..5818b7e693 100644 --- a/src/3rd party/luabind/luabind/src/function.cpp +++ b/src/3rd party/luabind/luabind/src/function.cpp @@ -48,7 +48,7 @@ namespace luabind { namespace detail { namespace free_functions { bool ambiguous = false; int min_match = std::numeric_limits::max(); int match_index = -1; - bool ret; + [[maybe_unused]]bool ret; #ifdef LUABIND_NO_ERROR_CHECKING if (rep->overloads().size() == 1) @@ -170,3 +170,4 @@ namespace luabind { namespace detail { namespace free_functions { }}} // namespace luabind::detail::free_functions + diff --git a/src/3rd party/luabind/luabind/src/object.cpp b/src/3rd party/luabind/luabind/src/object.cpp index 9c9812b1c6..55049f6b2a 100644 --- a/src/3rd party/luabind/luabind/src/object.cpp +++ b/src/3rd party/luabind/luabind/src/object.cpp @@ -35,6 +35,17 @@ namespace luabind return L; } + LUABIND_API string_class DebugPrintStack(lua_State* L) + { + string_class msg(""); + luabind::object debug_space = luabind::get_globals(L)["debug"]; + luabind::object traceback = debug_space["traceback"]; + string_class tracebackstr = luabind::call_function(traceback); + msg += "\n traceback: \n"; + msg += tracebackstr; + + return msg; + } namespace detail { diff --git a/src/3rd party/luabind/luabind/src/pcall.cpp b/src/3rd party/luabind/luabind/src/pcall.cpp index 3dc06ebcfc..9e5f6c04b9 100644 --- a/src/3rd party/luabind/luabind/src/pcall.cpp +++ b/src/3rd party/luabind/luabind/src/pcall.cpp @@ -49,3 +49,5 @@ namespace luabind { namespace detail } }} +luabind::memory_allocation_function_pointer luabind::allocator = 0; +luabind::memory_allocation_function_parameter luabind::allocator_parameter = 0; \ No newline at end of file diff --git a/src/3rd party/luabind/luabind/src/scope.cpp b/src/3rd party/luabind/luabind/src/scope.cpp index 71348ddabf..50f5b4d67d 100644 --- a/src/3rd party/luabind/luabind/src/scope.cpp +++ b/src/3rd party/luabind/luabind/src/scope.cpp @@ -80,34 +80,17 @@ namespace luabind { namespace detail { void scope::register_(lua_State* L) const { + if (::luabind::get_pregister_callback()) ::luabind::get_pregister_callback()(L, true); + for (detail::registration* r = m_chain; r != nullptr; r = r->m_next) - { r->register_(L); - } + + if (::luabind::get_pregister_callback()) ::luabind::get_pregister_callback()(L, false); } } // namespace luabind namespace luabind { - - namespace { - - struct lua_pop_stack - { - lua_pop_stack(lua_State* L) - : m_state(L) - { - } - - ~lua_pop_stack() - { - lua_pop(m_state, 1); - } - - lua_State* m_state; - }; - - } // namespace unnamed module_::module_(lua_State* L, char const* name = 0) : m_state(L) @@ -115,7 +98,7 @@ namespace luabind { { } - void module_::operator[](scope&& s) + void module_::push_global_table() { if (m_name) { @@ -132,20 +115,7 @@ namespace luabind { lua_settable(m_state, LUA_GLOBALSINDEX); } } - else - { - lua_pushvalue(m_state, LUA_GLOBALSINDEX); - } - - lua_pop_stack guard(m_state); - - if (::luabind::get_pregister_callback()) - ::luabind::get_pregister_callback() (m_state,true); - - s.register_(m_state); - - if (::luabind::get_pregister_callback()) - ::luabind::get_pregister_callback() (m_state,false); + else { lua_pushvalue(m_state, LUA_GLOBALSINDEX); } } struct namespace_::registration_ : detail::registration diff --git a/src/3rd party/luabind/luabind_memory.cpp b/src/3rd party/luabind/luabind_memory.cpp deleted file mode 100644 index 5987e54c95..0000000000 --- a/src/3rd party/luabind/luabind_memory.cpp +++ /dev/null @@ -1,6 +0,0 @@ -#include "luabind_memory.h" - -namespace luabind { - // Define the global instance - allocator_func_t custom_allocator = luabind_allocator; -} diff --git a/src/3rd party/luabind/luabind_memory.h b/src/3rd party/luabind/luabind_memory.h index f22c4fa89d..c99867a494 100644 --- a/src/3rd party/luabind/luabind_memory.h +++ b/src/3rd party/luabind/luabind_memory.h @@ -22,36 +22,16 @@ namespace luabind { - static void* __cdecl luabind_allocator(const void* pointer, size_t const size) - { - if (!size) - { - void* non_const_pointer = const_cast(pointer); - free(non_const_pointer); - return nullptr; - } + typedef void* memory_allocation_function_parameter; + typedef void* (__cdecl *memory_allocation_function_pointer) (memory_allocation_function_parameter parameter, void const *, size_t); - if (!pointer) - { - return malloc(size); - } + extern LUABIND_API memory_allocation_function_pointer allocator; + extern LUABIND_API memory_allocation_function_parameter allocator_parameter; - void* non_const_pointer = const_cast(pointer); - return realloc(non_const_pointer, size); - } - - typedef void* (__cdecl* allocator_func_t)(const void* pointer, size_t const size); - LUABIND_API extern allocator_func_t custom_allocator; - - inline void* call_allocator(void const* buffer, size_t const size) - { - return custom_allocator(buffer, size); - } - - inline void set_allocator(allocator_func_t allocator) - { - custom_allocator = allocator ? allocator : luabind_allocator; - } + inline void* call_allocator (void const* buffer, size_t const size) + { + return (allocator(allocator_parameter, buffer, size)); + } } // namespace luabind #include diff --git a/src/3rd party/luabind/object.hpp b/src/3rd party/luabind/object.hpp index 1e6c018da5..1685d4575f 100644 --- a/src/3rd party/luabind/object.hpp +++ b/src/3rd party/luabind/object.hpp @@ -35,6 +35,8 @@ namespace luabind { + LUABIND_API string_class DebugPrintStack(lua_State* L); + class LUABIND_API object { template diff --git a/src/3rd party/luabind/proxy_object.hpp b/src/3rd party/luabind/proxy_object.hpp index 515f7034f8..f29fc26d93 100644 --- a/src/3rd party/luabind/proxy_object.hpp +++ b/src/3rd party/luabind/proxy_object.hpp @@ -140,7 +140,7 @@ namespace luabind void assign(const T& val, const Policies& p) { lua_State* L = GetFuckingLuaStateByObject(&m_obj); - detail::getref(L, m_key); + detail::getref(L, m_key.get_ref()); detail::convert_to_lua_p(L, val, p); lua_settable(L, -3); // pop table @@ -240,7 +240,7 @@ namespace luabind proxy_raw_object& operator=(const T& val) { lua_State* L = GetFuckingLuaStateByObject(&m_obj); - detail::getref(L, m_key); + detail::getref(L, m_key.get_ref()); detail::convert_to_lua(L, val); lua_rawset(L, -3); // pop table @@ -252,7 +252,7 @@ namespace luabind void assign(const T& val, const policy_cons p) { lua_State* L = GetFuckingLuaStateByObject(&m_obj); - detail::getref(L, m_key); + detail::getref(L, m_key.get_ref()); detail::convert_to_lua_p(L, val, p); lua_settable(L, -3); // pop table diff --git a/src/3rd party/luabind/scope.hpp b/src/3rd party/luabind/scope.hpp index 6092284bd8..a01f889db0 100644 --- a/src/3rd party/luabind/scope.hpp +++ b/src/3rd party/luabind/scope.hpp @@ -32,23 +32,20 @@ namespace luabind { } // namespace luabind -namespace luabind { namespace detail { - +namespace luabind::detail + { struct LUABIND_API registration { registration(); registration(const registration&) = delete; virtual ~registration(); - protected: - virtual void register_(lua_State*) const = 0; - - private: friend struct scope; registration* m_next; - }; -}} // namespace luabind::detail + virtual void register_(lua_State*) const = 0; + }; +} namespace luabind { @@ -113,11 +110,27 @@ namespace luabind { registration_* m_registration; }; - class LUABIND_API module_ + namespace + { + struct lua_pop_stack + { + lua_pop_stack(lua_State* L) : m_state(L) {} + ~lua_pop_stack() { lua_pop(m_state, 1); } + lua_State* m_state; + }; + } // namespace + + class LUABIND_API module_ { public: module_(lua_State* L_, char const* name); - void operator[](scope&& s); + + template void operator[](Args&&... args) + { + push_global_table(); + lua_pop_stack guard(m_state); + (std::forward(args).register_(m_state), ...); + } module_(const module_&) = delete; @@ -143,7 +156,8 @@ namespace luabind { private: lua_State* m_state; char const* m_name; - }; + void push_global_table(); + }; inline module_ module(lua_State* L, char const* name = 0) { diff --git a/src/3rd party/luajit-2/src/luajit.vcxproj b/src/3rd party/luajit-2/src/luajit.vcxproj index 5080e5eb7f..8f8a99e23d 100644 --- a/src/3rd party/luajit-2/src/luajit.vcxproj +++ b/src/3rd party/luajit-2/src/luajit.vcxproj @@ -13,6 +13,10 @@ Release-AVX x64 + + VerifiedDX11ASAN + x64 + Verified x64 @@ -38,6 +42,9 @@ true + + true + @@ -63,6 +70,11 @@ + + + + + @@ -164,6 +176,25 @@ Neither + + + _DISABLE_VECTOR_ANNOTATION;_DISABLE_STRING_ANNOTATION;USE_VERIFY_IN_RELEASE;WIN32;NDEBUG;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) + Disabled + true + true + true + false + true + false + false + false + false + false + true + Disabled + Neither + + Generating LuaJIT VM object and headers diff --git a/src/3rd party/magic_enum/magic_enum.hpp b/src/3rd party/magic_enum/magic_enum.hpp new file mode 100644 index 0000000000..c133042ca6 --- /dev/null +++ b/src/3rd party/magic_enum/magic_enum.hpp @@ -0,0 +1,1448 @@ +// __ __ _ ______ _____ +// | \/ | (_) | ____| / ____|_ _ +// | \ / | __ _ __ _ _ ___ | |__ _ __ _ _ _ __ ___ | | _| |_ _| |_ +// | |\/| |/ _` |/ _` | |/ __| | __| | '_ \| | | | '_ ` _ \ | | |_ _|_ _| +// | | | | (_| | (_| | | (__ | |____| | | | |_| | | | | | | | |____|_| |_| +// |_| |_|\__,_|\__, |_|\___| |______|_| |_|\__,_|_| |_| |_| \_____| +// __/ | https://github.com/Neargye/magic_enum +// |___/ version 0.9.3 +// +// Licensed under the MIT License . +// SPDX-License-Identifier: MIT +// Copyright (c) 2019 - 2023 Daniil Goncharov . +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#ifndef NEARGYE_MAGIC_ENUM_HPP +#define NEARGYE_MAGIC_ENUM_HPP + +#define MAGIC_ENUM_VERSION_MAJOR 0 +#define MAGIC_ENUM_VERSION_MINOR 9 +#define MAGIC_ENUM_VERSION_PATCH 3 + +#include +#include +#include +#include +#include +#include +#include + +#if defined(MAGIC_ENUM_CONFIG_FILE) +# include MAGIC_ENUM_CONFIG_FILE +#endif + +#if !defined(MAGIC_ENUM_USING_ALIAS_OPTIONAL) +# include +#endif +#if !defined(MAGIC_ENUM_USING_ALIAS_STRING) +# include +#endif +#if !defined(MAGIC_ENUM_USING_ALIAS_STRING_VIEW) +# include +#endif + +#if defined(MAGIC_ENUM_NO_ASSERT) +# define MAGIC_ENUM_ASSERT(...) static_cast(0) +#else +# include +# define MAGIC_ENUM_ASSERT(...) assert((__VA_ARGS__)) +#endif + +#if defined(__clang__) +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wunknown-warning-option" +# pragma clang diagnostic ignored "-Wenum-constexpr-conversion" +#elif defined(__GNUC__) +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wmaybe-uninitialized" // May be used uninitialized 'return {};'. +#elif defined(_MSC_VER) +# pragma warning(push) +# pragma warning(disable : 26495) // Variable 'static_str::chars_' is uninitialized. +# pragma warning(disable : 28020) // Arithmetic overflow: Using operator '-' on a 4 byte value and then casting the result to a 8 byte value. +# pragma warning(disable : 26451) // The expression '0<=_Param_(1)&&_Param_(1)<=1-1' is not true at this call. +# pragma warning(disable : 4514) // Unreferenced inline function has been removed. +#endif + +// Checks magic_enum compiler compatibility. +#if defined(__clang__) && __clang_major__ >= 5 || defined(__GNUC__) && __GNUC__ >= 9 || defined(_MSC_VER) && _MSC_VER >= 1910 || defined(__RESHARPER__) +# undef MAGIC_ENUM_SUPPORTED +# define MAGIC_ENUM_SUPPORTED 1 +#endif + +// Checks magic_enum compiler aliases compatibility. +#if defined(__clang__) && __clang_major__ >= 5 || defined(__GNUC__) && __GNUC__ >= 9 || defined(_MSC_VER) && _MSC_VER >= 1920 +# undef MAGIC_ENUM_SUPPORTED_ALIASES +# define MAGIC_ENUM_SUPPORTED_ALIASES 1 +#endif + +// Enum value must be greater or equals than MAGIC_ENUM_RANGE_MIN. By default MAGIC_ENUM_RANGE_MIN = -128. +// If need another min range for all enum types by default, redefine the macro MAGIC_ENUM_RANGE_MIN. +#if !defined(MAGIC_ENUM_RANGE_MIN) +# define MAGIC_ENUM_RANGE_MIN -128 +#endif + +// Enum value must be less or equals than MAGIC_ENUM_RANGE_MAX. By default MAGIC_ENUM_RANGE_MAX = 128. +// If need another max range for all enum types by default, redefine the macro MAGIC_ENUM_RANGE_MAX. +#if !defined(MAGIC_ENUM_RANGE_MAX) +# define MAGIC_ENUM_RANGE_MAX 127 +#endif + +// Improve ReSharper C++ intellisense performance with builtins, avoiding unnecessary template instantiations. +#if defined(__RESHARPER__) +# undef MAGIC_ENUM_GET_ENUM_NAME_BUILTIN +# undef MAGIC_ENUM_GET_TYPE_NAME_BUILTIN +# if __RESHARPER__ >= 20230100 +# define MAGIC_ENUM_GET_ENUM_NAME_BUILTIN(V) __rscpp_enumerator_name(V) +# define MAGIC_ENUM_GET_TYPE_NAME_BUILTIN(T) __rscpp_type_name() +# else +# define MAGIC_ENUM_GET_ENUM_NAME_BUILTIN(V) nullptr +# define MAGIC_ENUM_GET_TYPE_NAME_BUILTIN(T) nullptr +# endif +#endif + +namespace magic_enum { + +// If need another optional type, define the macro MAGIC_ENUM_USING_ALIAS_OPTIONAL. +#if defined(MAGIC_ENUM_USING_ALIAS_OPTIONAL) +MAGIC_ENUM_USING_ALIAS_OPTIONAL +#else +using std::optional; +#endif + +// If need another string_view type, define the macro MAGIC_ENUM_USING_ALIAS_STRING_VIEW. +#if defined(MAGIC_ENUM_USING_ALIAS_STRING_VIEW) +MAGIC_ENUM_USING_ALIAS_STRING_VIEW +#else +using std::string_view; +#endif + +// If need another string type, define the macro MAGIC_ENUM_USING_ALIAS_STRING. +#if defined(MAGIC_ENUM_USING_ALIAS_STRING) +MAGIC_ENUM_USING_ALIAS_STRING +#else +using std::string; +#endif + +using char_type = string_view::value_type; +static_assert(std::is_same_v, "magic_enum::customize requires same string_view::value_type and string::value_type"); +static_assert([] { + if constexpr (std::is_same_v) { + constexpr const char c[] = "abcdefghijklmnopqrstuvwxyz_ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789|"; + constexpr const wchar_t wc[] = L"abcdefghijklmnopqrstuvwxyz_ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789|"; + static_assert(std::size(c) == std::size(wc), "magic_enum::customize identifier characters are multichars in wchar_t."); + + for (std::size_t i = 0; i < std::size(c); ++i) { + if (c[i] != wc[i]) { + return false; + } + } + } + return true; +} (), "magic_enum::customize wchar_t is not compatible with ASCII."); + +namespace customize { + +// Enum value must be in range [MAGIC_ENUM_RANGE_MIN, MAGIC_ENUM_RANGE_MAX]. By default MAGIC_ENUM_RANGE_MIN = -128, MAGIC_ENUM_RANGE_MAX = 128. +// If need another range for all enum types by default, redefine the macro MAGIC_ENUM_RANGE_MIN and MAGIC_ENUM_RANGE_MAX. +// If need another range for specific enum type, add specialization enum_range for necessary enum type. +template +struct enum_range { + static_assert(std::is_enum_v, "magic_enum::customize::enum_range requires enum type."); + static constexpr int min = MAGIC_ENUM_RANGE_MIN; + static constexpr int max = MAGIC_ENUM_RANGE_MAX; + static_assert(max > min, "magic_enum::customize::enum_range requires max > min."); +}; + +static_assert(MAGIC_ENUM_RANGE_MAX > MAGIC_ENUM_RANGE_MIN, "MAGIC_ENUM_RANGE_MAX must be greater than MAGIC_ENUM_RANGE_MIN."); +static_assert((MAGIC_ENUM_RANGE_MAX - MAGIC_ENUM_RANGE_MIN) < (std::numeric_limits::max)(), "MAGIC_ENUM_RANGE must be less than UINT16_MAX."); + +namespace detail { + +enum class customize_tag { + default_tag, + invalid_tag, + custom_tag +}; + +} // namespace magic_enum::customize::detail + +class customize_t : public std::pair { + public: + constexpr customize_t(string_view srt) : std::pair{detail::customize_tag::custom_tag, srt} {} + constexpr customize_t(const char_type* srt) : customize_t{string_view{srt}} {} + constexpr customize_t(detail::customize_tag tag) : std::pair{tag, string_view{}} { + MAGIC_ENUM_ASSERT(tag != detail::customize_tag::custom_tag); + } +}; + +// Default customize. +inline constexpr auto default_tag = customize_t{detail::customize_tag::default_tag}; +// Invalid customize. +inline constexpr auto invalid_tag = customize_t{detail::customize_tag::invalid_tag}; + +// If need custom names for enum, add specialization enum_name for necessary enum type. +template +constexpr customize_t enum_name(E) noexcept { + return default_tag; +} + +// If need custom type name for enum, add specialization enum_type_name for necessary enum type. +template +constexpr customize_t enum_type_name() noexcept { + return default_tag; +} + +} // namespace magic_enum::customize + +namespace detail { + +template +struct supported +#if defined(MAGIC_ENUM_SUPPORTED) && MAGIC_ENUM_SUPPORTED || defined(MAGIC_ENUM_NO_CHECK_SUPPORT) + : std::true_type {}; +#else + : std::false_type {}; +#endif + +template , std::enable_if_t, int> = 0> +using enum_constant = std::integral_constant; + +template +inline constexpr bool always_false_v = false; + +template +struct has_is_flags : std::false_type {}; + +template +struct has_is_flags::is_flags)>> : std::bool_constant::is_flags)>>> {}; + +template +struct range_min : std::integral_constant {}; + +template +struct range_min::min)>> : std::integral_constant::min), customize::enum_range::min> {}; + +template +struct range_max : std::integral_constant {}; + +template +struct range_max::max)>> : std::integral_constant::max), customize::enum_range::max> {}; + +struct str_view { + const char* str_ = nullptr; + std::size_t size_ = 0; +}; + +template +class static_str { + public: + constexpr explicit static_str(str_view str) noexcept : static_str{str.str_, std::make_integer_sequence{}} { + MAGIC_ENUM_ASSERT(str.size_ == N); + } + + constexpr explicit static_str(string_view str) noexcept : static_str{str.data(), std::make_integer_sequence{}} { + MAGIC_ENUM_ASSERT(str.size() == N); + } + + constexpr const char_type* data() const noexcept { return chars_; } + + constexpr std::uint16_t size() const noexcept { return N; } + + constexpr operator string_view() const noexcept { return {data(), size()}; } + + private: + template + constexpr static_str(const char* str, std::integer_sequence) noexcept : chars_{static_cast(str[I])..., static_cast('\0')} {} + + template + constexpr static_str(string_view str, std::integer_sequence) noexcept : chars_{str[I]..., static_cast('\0')} {} + + char_type chars_[static_cast(N) + 1]; +}; + +template <> +class static_str<0> { + public: + constexpr explicit static_str() = default; + + constexpr explicit static_str(str_view) noexcept {} + + constexpr explicit static_str(string_view) noexcept {} + + constexpr const char_type* data() const noexcept { return nullptr; } + + constexpr std::uint16_t size() const noexcept { return 0; } + + constexpr operator string_view() const noexcept { return {}; } +}; + +template > +class case_insensitive { + static constexpr char_type to_lower(char_type c) noexcept { + return (c >= static_cast('A') && c <= static_cast('Z')) ? static_cast(c + (static_cast('a') - static_cast('A'))) : c; + } + + public: + template + constexpr auto operator()(L lhs, R rhs) const noexcept -> std::enable_if_t, char_type> && std::is_same_v, char_type>, bool> { + return Op{}(to_lower(lhs), to_lower(rhs)); + } +}; + +constexpr std::size_t find(string_view str, char_type c) noexcept { +#if defined(__clang__) && __clang_major__ < 9 && defined(__GLIBCXX__) || defined(_MSC_VER) && _MSC_VER < 1920 && !defined(__clang__) +// https://stackoverflow.com/questions/56484834/constexpr-stdstring-viewfind-last-of-doesnt-work-on-clang-8-with-libstdc +// https://developercommunity.visualstudio.com/content/problem/360432/vs20178-regression-c-failed-in-test.html + constexpr bool workaround = true; +#else + constexpr bool workaround = false; +#endif + + if constexpr (workaround) { + for (std::size_t i = 0; i < str.size(); ++i) { + if (str[i] == c) { + return i; + } + } + + return string_view::npos; + } else { + return str.find(c); + } +} + +template +constexpr bool is_default_predicate() noexcept { + return std::is_same_v, std::equal_to> || + std::is_same_v, std::equal_to<>>; +} + +template +constexpr bool is_nothrow_invocable() { + return is_default_predicate() || + std::is_nothrow_invocable_r_v; +} + +template +constexpr bool cmp_equal(string_view lhs, string_view rhs, [[maybe_unused]] BinaryPredicate&& p) noexcept(is_nothrow_invocable()) { +#if defined(_MSC_VER) && _MSC_VER < 1920 && !defined(__clang__) + // https://developercommunity.visualstudio.com/content/problem/360432/vs20178-regression-c-failed-in-test.html + // https://developercommunity.visualstudio.com/content/problem/232218/c-constexpr-string-view.html + constexpr bool workaround = true; +#else + constexpr bool workaround = false; +#endif + + if constexpr (!is_default_predicate() || workaround) { + if (lhs.size() != rhs.size()) { + return false; + } + + const auto size = lhs.size(); + for (std::size_t i = 0; i < size; ++i) { + if (!p(lhs[i], rhs[i])) { + return false; + } + } + + return true; + } else { + return lhs == rhs; + } +} + +template +constexpr bool cmp_less(L lhs, R rhs) noexcept { + static_assert(std::is_integral_v && std::is_integral_v, "magic_enum::detail::cmp_less requires integral type."); + + if constexpr (std::is_signed_v == std::is_signed_v) { + // If same signedness (both signed or both unsigned). + return lhs < rhs; + } else if constexpr (std::is_same_v) { // bool special case + return static_cast(lhs) < rhs; + } else if constexpr (std::is_same_v) { // bool special case + return lhs < static_cast(rhs); + } else if constexpr (std::is_signed_v) { + // If 'right' is negative, then result is 'false', otherwise cast & compare. + return rhs > 0 && lhs < static_cast>(rhs); + } else { + // If 'left' is negative, then result is 'true', otherwise cast & compare. + return lhs < 0 || static_cast>(lhs) < rhs; + } +} + +template +constexpr I log2(I value) noexcept { + static_assert(std::is_integral_v, "magic_enum::detail::log2 requires integral type."); + + if constexpr (std::is_same_v) { // bool special case + return MAGIC_ENUM_ASSERT(false), value; + } else { + auto ret = I{0}; + for (; value > I{1}; value >>= I{1}, ++ret) {} + + return ret; + } +} + +#if defined(__cpp_lib_array_constexpr) && __cpp_lib_array_constexpr >= 201603L +# define MAGIC_ENUM_ARRAY_CONSTEXPR 1 +#else +template +constexpr std::array, N> to_array(T (&a)[N], std::index_sequence) noexcept { + return {{a[I]...}}; +} +#endif + +template +inline constexpr bool is_enum_v = std::is_enum_v && std::is_same_v>; + +template +constexpr auto n() noexcept { + static_assert(is_enum_v, "magic_enum::detail::n requires enum type."); + + if constexpr (supported::value) { +#if defined(MAGIC_ENUM_GET_TYPE_NAME_BUILTIN) + constexpr auto name_ptr = MAGIC_ENUM_GET_TYPE_NAME_BUILTIN(E); + constexpr auto name = name_ptr ? str_view{name_ptr, std::char_traits::length(name_ptr)} : str_view{}; +#elif defined(__clang__) + auto name = str_view{__PRETTY_FUNCTION__ + 34, sizeof(__PRETTY_FUNCTION__) - 36}; +#elif defined(__GNUC__) + auto name = str_view{__PRETTY_FUNCTION__, sizeof(__PRETTY_FUNCTION__) - 1}; + if (name.str_[name.size_ - 1] == ']') { + name.size_ -= 50; + name.str_ += 49; + } else { + name.size_ -= 40; + name.str_ += 37; + } +#elif defined(_MSC_VER) + // CLI/C++ workaround (see https://github.com/Neargye/magic_enum/issues/284). + str_view name; + name.str_ = __FUNCSIG__; + name.str_ += 40; + name.size_ += sizeof(__FUNCSIG__) - 57; +#else + auto name = str_view{}; +#endif + std::size_t p = 0; + for (std::size_t i = name.size_; i > 0; --i) { + if (name.str_[i] == ':') { + p = i + 1; + break; + } + } + if (p > 0) { + name.size_ -= p; + name.str_ += p; + } + return name; + } else { + return str_view{}; // Unsupported compiler or Invalid customize. + } +} + +template +constexpr auto type_name() noexcept { + [[maybe_unused]] constexpr auto custom = customize::enum_type_name(); + static_assert(std::is_same_v, customize::customize_t>, "magic_enum::customize requires customize_t type."); + if constexpr (custom.first == customize::detail::customize_tag::custom_tag) { + constexpr auto name = custom.second; + static_assert(!name.empty(), "magic_enum::customize requires not empty string."); + return static_str{name}; + } else if constexpr (custom.first == customize::detail::customize_tag::invalid_tag) { + return static_str<0>{}; + } else if constexpr (custom.first == customize::detail::customize_tag::default_tag) { + constexpr auto name = n(); + return static_str{name}; + } else { + static_assert(always_false_v, "magic_enum::customize invalid."); + } +} + +template +inline constexpr auto type_name_v = type_name(); + +template +constexpr auto n() noexcept { + static_assert(is_enum_v, "magic_enum::detail::n requires enum type."); + + if constexpr (supported::value) { +#if defined(MAGIC_ENUM_GET_ENUM_NAME_BUILTIN) + constexpr auto name_ptr = MAGIC_ENUM_GET_ENUM_NAME_BUILTIN(V); + auto name = name_ptr ? str_view{name_ptr, std::char_traits::length(name_ptr)} : str_view{}; +#elif defined(__clang__) + auto name = str_view{__PRETTY_FUNCTION__ + 34, sizeof(__PRETTY_FUNCTION__) - 36}; + if (name.size_ > 22 && name.str_[0] == '(' && name.str_[1] == 'a' && name.str_[10] == ' ' && name.str_[22] == ':') { + name.size_ -= 23; + name.str_ += 23; + } + if (name.str_[0] == '(' || name.str_[0] == '-' || (name.str_[0] >= '0' && name.str_[0] <= '9')) { + name = str_view{}; + } +#elif defined(__GNUC__) + auto name = str_view{__PRETTY_FUNCTION__, sizeof(__PRETTY_FUNCTION__) - 1}; + if (name.str_[name.size_ - 1] == ']') { + name.size_ -= 55; + name.str_ += 54; + } else { + name.size_ -= 40; + name.str_ += 37; + } + if (name.str_[0] == '(') { + name = str_view{}; + } +#elif defined(_MSC_VER) + str_view name; + if ((__FUNCSIG__[5] == '_' && __FUNCSIG__[35] != '(') || (__FUNCSIG__[5] == 'c' && __FUNCSIG__[41] != '(')) { + // CLI/C++ workaround (see https://github.com/Neargye/magic_enum/issues/284). + name.str_ = __FUNCSIG__; + name.str_ += 35; + name.size_ = sizeof(__FUNCSIG__) - 52; + } +#else + auto name = str_view{}; +#endif + std::size_t p = 0; + for (std::size_t i = name.size_; i > 0; --i) { + if (name.str_[i] == ':') { + p = i + 1; + break; + } + } + if (p > 0) { + name.size_ -= p; + name.str_ += p; + } + return name; + } else { + return str_view{}; // Unsupported compiler or Invalid customize. + } +} + +#if defined(_MSC_VER) && !defined(__clang__) && _MSC_VER < 1920 +# define MAGIC_ENUM_VS_2017_WORKAROUND 1 +#endif + +#if defined(MAGIC_ENUM_VS_2017_WORKAROUND) +template +constexpr auto n() noexcept { + static_assert(is_enum_v, "magic_enum::detail::n requires enum type."); + +# if defined(MAGIC_ENUM_GET_ENUM_NAME_BUILTIN) + constexpr auto name_ptr = MAGIC_ENUM_GET_ENUM_NAME_BUILTIN(V); + auto name = name_ptr ? str_view{name_ptr, std::char_traits::length(name_ptr)} : str_view{}; +# else + // CLI/C++ workaround (see https://github.com/Neargye/magic_enum/issues/284). + str_view name; + name.str_ = __FUNCSIG__; + name.size_ = sizeof(__FUNCSIG__) - 17; + std::size_t p = 0; + for (std::size_t i = name.size_; i > 0; --i) { + if (name.str_[i] == ',' || name.str_[i] == ':') { + p = i + 1; + break; + } + } + if (p > 0) { + name.size_ -= p; + name.str_ += p; + } + if (name.str_[0] == '(' || name.str_[0] == '-' || (name.str_[0] >= '0' && name.str_[0] <= '9')) { + name = str_view{}; + } + return name; +# endif +} +#endif + +template +constexpr auto enum_name() noexcept { + [[maybe_unused]] constexpr auto custom = customize::enum_name(V); + static_assert(std::is_same_v, customize::customize_t>, "magic_enum::customize requires customize_t type."); + if constexpr (custom.first == customize::detail::customize_tag::custom_tag) { + constexpr auto name = custom.second; + static_assert(!name.empty(), "magic_enum::customize requires not empty string."); + return static_str{name}; + } else if constexpr (custom.first == customize::detail::customize_tag::invalid_tag) { + return static_str<0>{}; + } else if constexpr (custom.first == customize::detail::customize_tag::default_tag) { +#if defined(MAGIC_ENUM_VS_2017_WORKAROUND) + constexpr auto name = n(); +#else + constexpr auto name = n(); +#endif + return static_str{name}; + } else { + static_assert(always_false_v, "magic_enum::customize invalid."); + } +} + +template +inline constexpr auto enum_name_v = enum_name(); + +template +constexpr bool is_valid() noexcept { +#if defined(__clang__) && __clang_major__ >= 16 + // https://reviews.llvm.org/D130058, https://reviews.llvm.org/D131307 + constexpr E v = __builtin_bit_cast(E, V); +#else + constexpr E v = static_cast(V); +#endif + [[maybe_unused]] constexpr auto custom = customize::enum_name(v); + static_assert(std::is_same_v, customize::customize_t>, "magic_enum::customize requires customize_t type."); + if constexpr (custom.first == customize::detail::customize_tag::custom_tag) { + constexpr auto name = custom.second; + static_assert(!name.empty(), "magic_enum::customize requires not empty string."); + return name.size() != 0; + } else if constexpr (custom.first == customize::detail::customize_tag::default_tag) { +#if defined(MAGIC_ENUM_VS_2017_WORKAROUND) + return n().size_ != 0; +#else + return n().size_ != 0; +#endif + } else { + return false; + } +} + +enum class enum_subtype { + common, + flags +}; + +template > +constexpr U ualue(std::size_t i) noexcept { + if constexpr (std::is_same_v) { // bool special case + static_assert(O == 0, "magic_enum::detail::ualue requires valid offset."); + + return static_cast(i); + } else if constexpr (S == enum_subtype::flags) { + return static_cast(U{1} << static_cast(static_cast(i) + O)); + } else { + return static_cast(static_cast(i) + O); + } +} + +template > +constexpr E value(std::size_t i) noexcept { + return static_cast(ualue(i)); +} + +template > +constexpr int reflected_min() noexcept { + if constexpr (S == enum_subtype::flags) { + return 0; + } else { + constexpr auto lhs = range_min::value; + constexpr auto rhs = (std::numeric_limits::min)(); + + if constexpr (cmp_less(rhs, lhs)) { + return lhs; + } else { + return rhs; + } + } +} + +template > +constexpr int reflected_max() noexcept { + if constexpr (S == enum_subtype::flags) { + return std::numeric_limits::digits - 1; + } else { + constexpr auto lhs = range_max::value; + constexpr auto rhs = (std::numeric_limits::max)(); + + if constexpr (cmp_less(lhs, rhs)) { + return lhs; + } else { + return rhs; + } + } +} + +#define MAGIC_ENUM_FOR_EACH_256(T) \ + T( 0)T( 1)T( 2)T( 3)T( 4)T( 5)T( 6)T( 7)T( 8)T( 9)T( 10)T( 11)T( 12)T( 13)T( 14)T( 15)T( 16)T( 17)T( 18)T( 19)T( 20)T( 21)T( 22)T( 23)T( 24)T( 25)T( 26)T( 27)T( 28)T( 29)T( 30)T( 31) \ + T( 32)T( 33)T( 34)T( 35)T( 36)T( 37)T( 38)T( 39)T( 40)T( 41)T( 42)T( 43)T( 44)T( 45)T( 46)T( 47)T( 48)T( 49)T( 50)T( 51)T( 52)T( 53)T( 54)T( 55)T( 56)T( 57)T( 58)T( 59)T( 60)T( 61)T( 62)T( 63) \ + T( 64)T( 65)T( 66)T( 67)T( 68)T( 69)T( 70)T( 71)T( 72)T( 73)T( 74)T( 75)T( 76)T( 77)T( 78)T( 79)T( 80)T( 81)T( 82)T( 83)T( 84)T( 85)T( 86)T( 87)T( 88)T( 89)T( 90)T( 91)T( 92)T( 93)T( 94)T( 95) \ + T( 96)T( 97)T( 98)T( 99)T(100)T(101)T(102)T(103)T(104)T(105)T(106)T(107)T(108)T(109)T(110)T(111)T(112)T(113)T(114)T(115)T(116)T(117)T(118)T(119)T(120)T(121)T(122)T(123)T(124)T(125)T(126)T(127) \ + T(128)T(129)T(130)T(131)T(132)T(133)T(134)T(135)T(136)T(137)T(138)T(139)T(140)T(141)T(142)T(143)T(144)T(145)T(146)T(147)T(148)T(149)T(150)T(151)T(152)T(153)T(154)T(155)T(156)T(157)T(158)T(159) \ + T(160)T(161)T(162)T(163)T(164)T(165)T(166)T(167)T(168)T(169)T(170)T(171)T(172)T(173)T(174)T(175)T(176)T(177)T(178)T(179)T(180)T(181)T(182)T(183)T(184)T(185)T(186)T(187)T(188)T(189)T(190)T(191) \ + T(192)T(193)T(194)T(195)T(196)T(197)T(198)T(199)T(200)T(201)T(202)T(203)T(204)T(205)T(206)T(207)T(208)T(209)T(210)T(211)T(212)T(213)T(214)T(215)T(216)T(217)T(218)T(219)T(220)T(221)T(222)T(223) \ + T(224)T(225)T(226)T(227)T(228)T(229)T(230)T(231)T(232)T(233)T(234)T(235)T(236)T(237)T(238)T(239)T(240)T(241)T(242)T(243)T(244)T(245)T(246)T(247)T(248)T(249)T(250)T(251)T(252)T(253)T(254)T(255) + +template +constexpr void valid_count(bool* valid, std::size_t& count) noexcept { +#define MAGIC_ENUM_V(O) \ + if constexpr ((I + O) < Size) { \ + if constexpr (is_valid(I + O)>()) { \ + valid[I + O] = true; \ + ++count; \ + } \ + } + + MAGIC_ENUM_FOR_EACH_256(MAGIC_ENUM_V); + + if constexpr ((I + 256) < Size) { + valid_count(valid, count); + } +#undef MAGIC_ENUM_V +} + +template +struct valid_count_t { + std::size_t count = 0; + bool valid[N] = {}; +}; + +template +constexpr auto valid_count() noexcept { + valid_count_t vc; + valid_count(vc.valid, vc.count); + return vc; +} + +template +constexpr auto values() noexcept { + constexpr auto vc = valid_count(); + + if constexpr (vc.count > 0) { +#if defined(MAGIC_ENUM_ARRAY_CONSTEXPR) + std::array values = {}; +#else + E values[vc.count] = {}; +#endif + for (std::size_t i = 0, v = 0; v < vc.count; ++i) { + if (vc.valid[i]) { + values[v++] = value(i); + } + } +#if defined(MAGIC_ENUM_ARRAY_CONSTEXPR) + return values; +#else + return to_array(values, std::make_index_sequence{}); +#endif + } else { + return std::array{}; + } +} + +template > +constexpr auto values() noexcept { + constexpr auto min = reflected_min(); + constexpr auto max = reflected_max(); + constexpr auto range_size = max - min + 1; + static_assert(range_size > 0, "magic_enum::enum_range requires valid size."); + static_assert(range_size < (std::numeric_limits::max)(), "magic_enum::enum_range requires valid size."); + + return values(); +} + +template > +constexpr enum_subtype subtype(std::true_type) noexcept { + if constexpr (std::is_same_v) { // bool special case + return enum_subtype::common; + } else if constexpr (has_is_flags::value) { + return customize::enum_range::is_flags ? enum_subtype::flags : enum_subtype::common; + } else { +#if defined(MAGIC_ENUM_AUTO_IS_FLAGS) + constexpr auto flags_values = values(); + constexpr auto default_values = values(); + if (flags_values.size() == 0 || default_values.size() > flags_values.size()) { + return enum_subtype::common; + } + for (std::size_t i = 0; i < default_values.size(); ++i) { + const auto v = static_cast(default_values[i]); + if (v != 0 && (v & (v - 1)) != 0) { + return enum_subtype::common; + } + } + return enum_subtype::flags; +#else + return enum_subtype::common; +#endif + } +} + +template +constexpr enum_subtype subtype(std::false_type) noexcept { + // For non-enum type return default common subtype. + return enum_subtype::common; +} + +template > +inline constexpr auto subtype_v = subtype(std::is_enum{}); + +template +inline constexpr auto values_v = values(); + +template > +using values_t = decltype((values_v)); + +template +inline constexpr auto count_v = values_v.size(); + +template > +inline constexpr auto min_v = (count_v > 0) ? static_cast(values_v.front()) : U{0}; + +template > +inline constexpr auto max_v = (count_v > 0) ? static_cast(values_v.back()) : U{0}; + +template +constexpr auto names(std::index_sequence) noexcept { + return std::array{{enum_name_v[I]>...}}; +} + +template +inline constexpr auto names_v = names(std::make_index_sequence>{}); + +template > +using names_t = decltype((names_v)); + +template +constexpr auto entries(std::index_sequence) noexcept { + return std::array, sizeof...(I)>{{{values_v[I], enum_name_v[I]>}...}}; +} + +template +inline constexpr auto entries_v = entries(std::make_index_sequence>{}); + +template > +using entries_t = decltype((entries_v)); + +template > +constexpr bool is_sparse() noexcept { + if constexpr (count_v == 0) { + return false; + } else if constexpr (std::is_same_v) { // bool special case + return false; + } else { + constexpr auto max = (S == enum_subtype::flags) ? log2(max_v) : max_v; + constexpr auto min = (S == enum_subtype::flags) ? log2(min_v) : min_v; + constexpr auto range_size = max - min + 1; + + return range_size != count_v; + } +} + +template > +inline constexpr bool is_sparse_v = is_sparse(); + +template > +constexpr U values_ors() noexcept { + static_assert(S == enum_subtype::flags, "magic_enum::detail::values_ors requires valid subtype."); + + auto ors = U{0}; + for (std::size_t i = 0; i < count_v; ++i) { + ors |= static_cast(values_v[i]); + } + + return ors; +} + +template +struct enable_if_enum {}; + +template +struct enable_if_enum { + using type = R; + static_assert(supported::value, "magic_enum unsupported compiler (https://github.com/Neargye/magic_enum#compiler-compatibility)."); +}; + +template , typename D = std::decay_t> +using enable_if_t = typename enable_if_enum && std::is_invocable_r_v, R>::type; + +template >, int> = 0> +using enum_concept = T; + +template > +struct is_scoped_enum : std::false_type {}; + +template +struct is_scoped_enum : std::bool_constant>> {}; + +template > +struct is_unscoped_enum : std::false_type {}; + +template +struct is_unscoped_enum : std::bool_constant>> {}; + +template >> +struct underlying_type {}; + +template +struct underlying_type : std::underlying_type> {}; + +#if defined(MAGIC_ENUM_ENABLE_HASH) || defined(MAGIC_ENUM_ENABLE_HASH_SWITCH) + +template +struct constexpr_hash_t; + +template +struct constexpr_hash_t>> { + constexpr auto operator()(Value value) const noexcept { + using U = typename underlying_type::type; + if constexpr (std::is_same_v) { // bool special case + return static_cast(value); + } else { + return static_cast(value); + } + } + using secondary_hash = constexpr_hash_t; +}; + +template +struct constexpr_hash_t>> { + static constexpr std::uint32_t crc_table[256] { + 0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L, 0x706af48fL, 0xe963a535L, 0x9e6495a3L, + 0x0edb8832L, 0x79dcb8a4L, 0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L, 0x90bf1d91L, + 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL, 0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, + 0x136c9856L, 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L, 0xfa0f3d63L, 0x8d080df5L, + 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L, 0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL, + 0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L, 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, + 0x26d930acL, 0x51de003aL, 0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L, 0xb8bda50fL, + 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L, 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, + 0x76dc4190L, 0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL, 0x9fbfe4a5L, 0xe8b8d433L, + 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL, 0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L, + 0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL, 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, + 0x65b0d9c6L, 0x12b7e950L, 0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L, 0xfbd44c65L, + 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L, 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, + 0x4369e96aL, 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L, 0xaa0a4c5fL, 0xdd0d7cc9L, + 0x5005713cL, 0x270241aaL, 0xbe0b1010L, 0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL, + 0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L, 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, + 0xedb88320L, 0x9abfb3b6L, 0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L, 0x73dc1683L, + 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L, 0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, + 0xf00f9344L, 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL, 0x196c3671L, 0x6e6b06e7L, + 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL, 0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L, + 0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L, 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, + 0xd80d2bdaL, 0xaf0a1b4cL, 0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL, 0x4669be79L, + 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L, 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, + 0xc5ba3bbeL, 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L, 0x2cd99e8bL, 0x5bdeae1dL, + 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL, 0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L, + 0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL, 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, + 0x86d3d2d4L, 0xf1d4e242L, 0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L, 0x18b74777L, + 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL, 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, + 0xa00ae278L, 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L, 0x4969474dL, 0x3e6e77dbL, + 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L, 0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L, + 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L, 0xcdd70693L, 0x54de5729L, 0x23d967bfL, + 0xb3667a2eL, 0xc4614ab8L, 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL, 0x2d02ef8dL + }; + constexpr std::uint32_t operator()(string_view value) const noexcept { + auto crc = static_cast(0xffffffffL); + for (const auto c : value) { + crc = (crc >> 8) ^ crc_table[(crc ^ static_cast(c)) & 0xff]; + } + return crc ^ 0xffffffffL; + } + + struct secondary_hash { + constexpr std::uint32_t operator()(string_view value) const noexcept { + auto acc = static_cast(2166136261ULL); + for (const auto c : value) { + acc = ((acc ^ static_cast(c)) * static_cast(16777619ULL)) & (std::numeric_limits::max)(); + } + return static_cast(acc); + } + }; +}; + +template +inline constexpr Hash hash_v{}; + +template +constexpr auto calculate_cases(std::size_t Page) noexcept { + constexpr std::array values = *GlobValues; + constexpr std::size_t size = values.size(); + + using switch_t = std::invoke_result_t; + static_assert(std::is_integral_v && !std::is_same_v); + const std::size_t values_to = (std::min)(static_cast(256), size - Page); + + std::array result{}; + auto fill = result.begin(); + { + auto first = values.begin() + static_cast(Page); + auto last = values.begin() + static_cast(Page + values_to); + while (first != last) { + *fill++ = hash_v(*first++); + } + } + + // dead cases, try to avoid case collisions + for (switch_t last_value = result[values_to - 1]; fill != result.end() && last_value != (std::numeric_limits::max)(); *fill++ = ++last_value) { + } + + { + auto it = result.begin(); + auto last_value = (std::numeric_limits::min)(); + for (; fill != result.end(); *fill++ = last_value++) { + while (last_value == *it) { + ++last_value, ++it; + } + } + } + + return result; +} + +template +constexpr R invoke_r(F&& f, Args&&... args) noexcept(std::is_nothrow_invocable_r_v) { + if constexpr (std::is_void_v) { + std::forward(f)(std::forward(args)...); + } else { + return static_cast(std::forward(f)(std::forward(args)...)); + } +} + +enum class case_call_t { + index, + value +}; + +template +inline constexpr auto default_result_type_lambda = []() noexcept(std::is_nothrow_default_constructible_v) { return T{}; }; + +template <> +inline constexpr auto default_result_type_lambda = []() noexcept {}; + +template +constexpr bool has_duplicate() noexcept { + using value_t = std::decay_t; + using hash_value_t = std::invoke_result_t; + std::arraysize()> hashes{}; + std::size_t size = 0; + for (auto elem : *Arr) { + hashes[size] = hash_v(elem); + for (auto i = size++; i > 0; --i) { + if (hashes[i] < hashes[i - 1]) { + auto tmp = hashes[i]; + hashes[i] = hashes[i - 1]; + hashes[i - 1] = tmp; + } else if (hashes[i] == hashes[i - 1]) { + return false; + } else { + break; + } + } + } + return true; +} + +#define MAGIC_ENUM_CASE(val) \ + case cases[val]: \ + if constexpr ((val) + Page < size) { \ + if (!pred(values[val + Page], searched)) { \ + break; \ + } \ + if constexpr (CallValue == case_call_t::index) { \ + if constexpr (std::is_invocable_r_v>) { \ + return detail::invoke_r(std::forward(lambda), std::integral_constant{}); \ + } else if constexpr (std::is_invocable_v>) { \ + MAGIC_ENUM_ASSERT(false && "magic_enum::detail::constexpr_switch wrong result type."); \ + } \ + } else if constexpr (CallValue == case_call_t::value) { \ + if constexpr (std::is_invocable_r_v>) { \ + return detail::invoke_r(std::forward(lambda), enum_constant{}); \ + } else if constexpr (std::is_invocable_r_v>) { \ + MAGIC_ENUM_ASSERT(false && "magic_enum::detail::constexpr_switch wrong result type."); \ + } \ + } \ + break; \ + } else [[fallthrough]]; + +template ::value_type>, + typename BinaryPredicate = std::equal_to<>, + typename Lambda, + typename ResultGetterType> +constexpr decltype(auto) constexpr_switch( + Lambda&& lambda, + typename std::decay_t::value_type searched, + ResultGetterType&& def, + BinaryPredicate&& pred = {}) { + using result_t = std::invoke_result_t; + using hash_t = std::conditional_t(), Hash, typename Hash::secondary_hash>; + static_assert(has_duplicate(), "magic_enum::detail::constexpr_switch duplicated hash found, please report it: https://github.com/Neargye/magic_enum/issues."); + constexpr std::array values = *GlobValues; + constexpr std::size_t size = values.size(); + constexpr std::array cases = calculate_cases(Page); + + switch (hash_v(searched)) { + MAGIC_ENUM_FOR_EACH_256(MAGIC_ENUM_CASE) + default: + if constexpr (size > 256 + Page) { + return constexpr_switch(std::forward(lambda), searched, std::forward(def)); + } + break; + } + return def(); +} + +#undef MAGIC_ENUM_CASE + +#endif + +} // namespace magic_enum::detail + +// Checks is magic_enum supported compiler. +inline constexpr bool is_magic_enum_supported = detail::supported::value; + +template +using Enum = detail::enum_concept; + +// Checks whether T is an Unscoped enumeration type. +// Provides the member constant value which is equal to true, if T is an [Unscoped enumeration](https://en.cppreference.com/w/cpp/language/enum#Unscoped_enumeration) type. Otherwise, value is equal to false. +template +struct is_unscoped_enum : detail::is_unscoped_enum {}; + +template +inline constexpr bool is_unscoped_enum_v = is_unscoped_enum::value; + +// Checks whether T is an Scoped enumeration type. +// Provides the member constant value which is equal to true, if T is an [Scoped enumeration](https://en.cppreference.com/w/cpp/language/enum#Scoped_enumerations) type. Otherwise, value is equal to false. +template +struct is_scoped_enum : detail::is_scoped_enum {}; + +template +inline constexpr bool is_scoped_enum_v = is_scoped_enum::value; + +// If T is a complete enumeration type, provides a member typedef type that names the underlying type of T. +// Otherwise, if T is not an enumeration type, there is no member type. Otherwise (T is an incomplete enumeration type), the program is ill-formed. +template +struct underlying_type : detail::underlying_type {}; + +template +using underlying_type_t = typename underlying_type::type; + +template +using enum_constant = detail::enum_constant; + +// Returns type name of enum. +template +[[nodiscard]] constexpr auto enum_type_name() noexcept -> detail::enable_if_t { + constexpr string_view name = detail::type_name_v>; + static_assert(!name.empty(), "magic_enum::enum_type_name enum type does not have a name."); + + return name; +} + +// Returns number of enum values. +template > +[[nodiscard]] constexpr auto enum_count() noexcept -> detail::enable_if_t { + return detail::count_v, S>; +} + +// Returns enum value at specified index. +// No bounds checking is performed: the behavior is undefined if index >= number of enum values. +template > +[[nodiscard]] constexpr auto enum_value(std::size_t index) noexcept -> detail::enable_if_t> { + using D = std::decay_t; + + if constexpr (detail::is_sparse_v) { + return MAGIC_ENUM_ASSERT(index < detail::count_v), detail::values_v[index]; + } else { + constexpr auto min = (S == detail::enum_subtype::flags) ? detail::log2(detail::min_v) : detail::min_v; + + return MAGIC_ENUM_ASSERT(index < detail::count_v), detail::value(index); + } +} + +// Returns enum value at specified index. +template > +[[nodiscard]] constexpr auto enum_value() noexcept -> detail::enable_if_t> { + using D = std::decay_t; + static_assert(I < detail::count_v, "magic_enum::enum_value out of range."); + + return enum_value(I); +} + +// Returns std::array with enum values, sorted by enum value. +template > +[[nodiscard]] constexpr auto enum_values() noexcept -> detail::enable_if_t> { + return detail::values_v, S>; +} + +// Returns integer value from enum value. +template +[[nodiscard]] constexpr auto enum_integer(E value) noexcept -> detail::enable_if_t> { + return static_cast>(value); +} + +// Returns underlying value from enum value. +template +[[nodiscard]] constexpr auto enum_underlying(E value) noexcept -> detail::enable_if_t> { + return static_cast>(value); +} + +// Obtains index in enum values from enum value. +// Returns optional with index. +template > +[[nodiscard]] constexpr auto enum_index(E value) noexcept -> detail::enable_if_t> { + using D = std::decay_t; + using U = underlying_type_t; + + if constexpr (detail::count_v == 0) { + static_cast(value); + return {}; // Empty enum. + } else if constexpr (detail::is_sparse_v || (S == detail::enum_subtype::flags)) { +#if defined(MAGIC_ENUM_ENABLE_HASH) + return detail::constexpr_switch<&detail::values_v, detail::case_call_t::index>( + [](std::size_t i) { return optional{i}; }, + value, + detail::default_result_type_lambda>); +#else + for (std::size_t i = 0; i < detail::count_v; ++i) { + if (enum_value(i) == value) { + return i; + } + } + return {}; // Invalid value or out of range. +#endif + } else { + const auto v = static_cast(value); + if (v >= detail::min_v && v <= detail::max_v) { + return static_cast(v - detail::min_v); + } + return {}; // Invalid value or out of range. + } +} + +// Obtains index in enum values from enum value. +// Returns optional with index. +template +[[nodiscard]] constexpr auto enum_index(E value) noexcept -> detail::enable_if_t> { + using D = std::decay_t; + + return enum_index(value); +} + +// Obtains index in enum values from static storage enum variable. +template >> +[[nodiscard]] constexpr auto enum_index() noexcept -> detail::enable_if_t { + constexpr auto index = enum_index, S>(V); + static_assert(index, "magic_enum::enum_index enum value does not have a index."); + + return *index; +} + +// Returns name from static storage enum variable. +// This version is much lighter on the compile times and is not restricted to the enum_range limitation. +template +[[nodiscard]] constexpr auto enum_name() noexcept -> detail::enable_if_t { + constexpr string_view name = detail::enum_name_v, V>; + static_assert(!name.empty(), "magic_enum::enum_name enum value does not have a name."); + + return name; +} + +// Returns name from enum value. +// If enum value does not have name or value out of range, returns empty string. +template > +[[nodiscard]] constexpr auto enum_name(E value) noexcept -> detail::enable_if_t { + using D = std::decay_t; + + if (const auto i = enum_index(value)) { + return detail::names_v[*i]; + } + return {}; +} + +// Returns name from enum value. +// If enum value does not have name or value out of range, returns empty string. +template +[[nodiscard]] constexpr auto enum_name(E value) -> detail::enable_if_t { + using D = std::decay_t; + + return enum_name(value); +} + +// Returns std::array with names, sorted by enum value. +template > +[[nodiscard]] constexpr auto enum_names() noexcept -> detail::enable_if_t> { + return detail::names_v, S>; +} + +// Returns std::array with pairs (value, name), sorted by enum value. +template > +[[nodiscard]] constexpr auto enum_entries() noexcept -> detail::enable_if_t> { + return detail::entries_v, S>; +} + +// Allows you to write magic_enum::enum_cast("bar", magic_enum::case_insensitive); +inline constexpr auto case_insensitive = detail::case_insensitive<>{}; + +// Obtains enum value from integer value. +// Returns optional with enum value. +template > +[[nodiscard]] constexpr auto enum_cast(underlying_type_t value) noexcept -> detail::enable_if_t>> { + using D = std::decay_t; + + if constexpr (detail::count_v == 0) { + static_cast(value); + return {}; // Empty enum. + } else { + if constexpr (detail::is_sparse_v || (S == detail::enum_subtype::flags)) { +#if defined(MAGIC_ENUM_ENABLE_HASH) + return detail::constexpr_switch<&detail::values_v, detail::case_call_t::value>( + [](D v) { return optional{v}; }, + static_cast(value), + detail::default_result_type_lambda>); +#else + for (std::size_t i = 0; i < detail::count_v; ++i) { + if (value == static_cast>(enum_value(i))) { + return static_cast(value); + } + } + return {}; // Invalid value or out of range. +#endif + } else { + if (value >= detail::min_v && value <= detail::max_v) { + return static_cast(value); + } + return {}; // Invalid value or out of range. + } + } +} + +// Obtains enum value from name. +// Returns optional with enum value. +template , typename BinaryPredicate = std::equal_to<>> +[[nodiscard]] constexpr auto enum_cast(string_view value, [[maybe_unused]] BinaryPredicate p = {}) noexcept(detail::is_nothrow_invocable()) -> detail::enable_if_t>, BinaryPredicate> { + using D = std::decay_t; + + if constexpr (detail::count_v == 0) { + static_cast(value); + return {}; // Empty enum. +#if defined(MAGIC_ENUM_ENABLE_HASH) + } else if constexpr (detail::is_default_predicate()) { + return detail::constexpr_switch<&detail::names_v, detail::case_call_t::index>( + [](std::size_t i) { return optional{detail::values_v[i]}; }, + value, + detail::default_result_type_lambda>, + [&p](string_view lhs, string_view rhs) { return detail::cmp_equal(lhs, rhs, p); }); +#endif + } else { + for (std::size_t i = 0; i < detail::count_v; ++i) { + if (detail::cmp_equal(value, detail::names_v[i], p)) { + return enum_value(i); + } + } + return {}; // Invalid value or out of range. + } +} + +// Checks whether enum contains value with such value. +template > +[[nodiscard]] constexpr auto enum_contains(E value) noexcept -> detail::enable_if_t { + using D = std::decay_t; + using U = underlying_type_t; + + return static_cast(enum_cast(static_cast(value))); +} + +// Checks whether enum contains value with such value. +template +[[nodiscard]] constexpr auto enum_contains(E value) noexcept -> detail::enable_if_t { + using D = std::decay_t; + using U = underlying_type_t; + + return static_cast(enum_cast(static_cast(value))); +} + +// Checks whether enum contains value with such integer value. +template > +[[nodiscard]] constexpr auto enum_contains(underlying_type_t value) noexcept -> detail::enable_if_t { + using D = std::decay_t; + + return static_cast(enum_cast(value)); +} + +// Checks whether enum contains enumerator with such name. +template , typename BinaryPredicate = std::equal_to<>> +[[nodiscard]] constexpr auto enum_contains(string_view value, BinaryPredicate p = {}) noexcept(detail::is_nothrow_invocable()) -> detail::enable_if_t { + using D = std::decay_t; + + return static_cast(enum_cast(value, std::move(p))); +} + +template +inline constexpr auto as_flags = AsFlags ? detail::enum_subtype::flags : detail::enum_subtype::common; + +template +inline constexpr auto as_common = AsFlags ? detail::enum_subtype::common : detail::enum_subtype::flags; + +namespace bitwise_operators { + +template = 0> +constexpr E operator~(E rhs) noexcept { + return static_cast(~static_cast>(rhs)); +} + +template = 0> +constexpr E operator|(E lhs, E rhs) noexcept { + return static_cast(static_cast>(lhs) | static_cast>(rhs)); +} + +template = 0> +constexpr E operator&(E lhs, E rhs) noexcept { + return static_cast(static_cast>(lhs) & static_cast>(rhs)); +} + +template = 0> +constexpr E operator^(E lhs, E rhs) noexcept { + return static_cast(static_cast>(lhs) ^ static_cast>(rhs)); +} + +template = 0> +constexpr E& operator|=(E& lhs, E rhs) noexcept { + return lhs = (lhs | rhs); +} + +template = 0> +constexpr E& operator&=(E& lhs, E rhs) noexcept { + return lhs = (lhs & rhs); +} + +template = 0> +constexpr E& operator^=(E& lhs, E rhs) noexcept { + return lhs = (lhs ^ rhs); +} + +} // namespace magic_enum::bitwise_operators + +} // namespace magic_enum + +#if defined(__clang__) +# pragma clang diagnostic pop +#elif defined(__GNUC__) +# pragma GCC diagnostic pop +#elif defined(_MSC_VER) +# pragma warning(pop) +#endif + +#undef MAGIC_ENUM_GET_ENUM_NAME_BUILTIN +#undef MAGIC_ENUM_GET_TYPE_NAME_BUILTIN +#undef MAGIC_ENUM_VS_2017_WORKAROUND +#undef MAGIC_ENUM_ARRAY_CONSTEXPR +#undef MAGIC_ENUM_FOR_EACH_256 + +#endif // NEARGYE_MAGIC_ENUM_HPP diff --git a/src/3rd party/magic_enum/magic_enum_all.hpp b/src/3rd party/magic_enum/magic_enum_all.hpp new file mode 100644 index 0000000000..c34dad3e42 --- /dev/null +++ b/src/3rd party/magic_enum/magic_enum_all.hpp @@ -0,0 +1,44 @@ +// __ __ _ ______ _____ +// | \/ | (_) | ____| / ____|_ _ +// | \ / | __ _ __ _ _ ___ | |__ _ __ _ _ _ __ ___ | | _| |_ _| |_ +// | |\/| |/ _` |/ _` | |/ __| | __| | '_ \| | | | '_ ` _ \ | | |_ _|_ _| +// | | | | (_| | (_| | | (__ | |____| | | | |_| | | | | | | | |____|_| |_| +// |_| |_|\__,_|\__, |_|\___| |______|_| |_|\__,_|_| |_| |_| \_____| +// __/ | https://github.com/Neargye/magic_enum +// |___/ version 0.9.3 +// +// Licensed under the MIT License . +// SPDX-License-Identifier: MIT +// Copyright (c) 2019 - 2023 Daniil Goncharov . +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#ifndef NEARGYE_MAGIC_ENUM_ALL_HPP +#define NEARGYE_MAGIC_ENUM_ALL_HPP + +#include "magic_enum.hpp" +#include "magic_enum_containers.hpp" +#include "magic_enum_flags.hpp" +#include "magic_enum_format.hpp" +#include "magic_enum_fuse.hpp" +#include "magic_enum_iostream.hpp" +#include "magic_enum_switch.hpp" +#include "magic_enum_utility.hpp" + +#endif // NEARGYE_MAGIC_ENUM_ALL_HPP diff --git a/src/3rd party/magic_enum/magic_enum_containers.hpp b/src/3rd party/magic_enum/magic_enum_containers.hpp new file mode 100644 index 0000000000..5d72c60c7a --- /dev/null +++ b/src/3rd party/magic_enum/magic_enum_containers.hpp @@ -0,0 +1,1174 @@ +// __ __ _ ______ _____ +// | \/ | (_) | ____| / ____|_ _ +// | \ / | __ _ __ _ _ ___ | |__ _ __ _ _ _ __ ___ | | _| |_ _| |_ +// | |\/| |/ _` |/ _` | |/ __| | __| | '_ \| | | | '_ ` _ \ | | |_ _|_ _| +// | | | | (_| | (_| | | (__ | |____| | | | |_| | | | | | | | |____|_| |_| +// |_| |_|\__,_|\__, |_|\___| |______|_| |_|\__,_|_| |_| |_| \_____| +// __/ | https://github.com/Neargye/magic_enum +// |___/ version 0.9.3 +// +// Licensed under the MIT License . +// SPDX-License-Identifier: MIT +// Copyright (c) 2019 - 2023 Daniil Goncharov . +// Copyright (c) 2022 - 2023 Bela Schaum . +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#ifndef NEARGYE_MAGIC_ENUM_CONTAINERS_HPP +#define NEARGYE_MAGIC_ENUM_CONTAINERS_HPP + +#include "magic_enum.hpp" + +#if !defined(MAGIC_ENUM_NO_EXCEPTION) && (defined(__cpp_exceptions) || defined(__EXCEPTIONS) || defined(_CPPUNWIND)) +# include +# define MAGIC_ENUM_THROW(...) throw (__VA_ARGS__) +#else +# include +# define MAGIC_ENUM_THROW(...) std::abort() +#endif + +namespace magic_enum::containers { + +namespace detail { + +template +static constexpr bool is_transparent_v{}; + +template +static constexpr bool is_transparent_v>{true}; + +template , typename T1, typename T2> +constexpr bool equal(T1&& t1, T2&& t2, Eq&& eq = {}) { + auto first1 = t1.begin(); + auto last1 = t1.end(); + auto first2 = t2.begin(); + auto last2 = t2.end(); + + for (; first1 != last1; ++first1, ++first2) { + if (first2 == last2 || !eq(*first1, *first2)) { + return false; + } + } + return first2 == last2; +} + +template , typename T1, typename T2> +constexpr bool lexicographical_compare(T1&& t1, T2&& t2, Cmp&& cmp = {}) noexcept { + auto first1 = t1.begin(); + auto last1 = t1.end(); + auto first2 = t2.begin(); + auto last2 = t2.end(); + + // copied from std::lexicographical_compare + for (; (first1 != last1) && (first2 != last2); ++first1, (void)++first2) { + if (cmp(*first1, *first2)) { + return true; + } + if (cmp(*first2, *first1)) { + return false; + } + } + return (first1 == last1) && (first2 != last2); +} + +template +constexpr std::size_t popcount(T x) noexcept { + std::size_t c = 0; + while (x > 0) { + c += x & 1; + x >>= 1; + } + return c; +} + +template , typename ForwardIt, typename E> +constexpr ForwardIt lower_bound(ForwardIt first, ForwardIt last, E&& e, Cmp&& comp = {}) { + auto count = std::distance(first, last); + for (auto it = first; count > 0;) { + auto step = count / 2; + std::advance(it, step); + if (comp(*it, e)) { + first = ++it; + count -= step + 1; + } else { + count = step; + } + } + return first; +} + +template , typename BidirIt, typename E> +constexpr auto equal_range(BidirIt begin, BidirIt end, E&& e, Cmp&& comp = {}) { + const auto first = lower_bound(begin, end, e, comp); + return std::pair{first, lower_bound(std::make_reverse_iterator(end), std::make_reverse_iterator(first), e, [&comp](auto&& lhs, auto&& rhs) { return comp(rhs, lhs); }).base()}; +} + +template , typename = void> +class indexing { + [[nodiscard]] static constexpr auto get_indices() noexcept { + // reverse result index mapping + std::array()> rev_res{}; + + // std::iota + for (std::size_t i = 0; i < enum_count(); ++i) { + rev_res[i] = i; + } + + constexpr auto orig_values = enum_values(); + constexpr Cmp cmp{}; + + // ~std::sort + for (std::size_t i = 0; i < enum_count(); ++i) { + for (std::size_t j = i + 1; j < enum_count(); ++j) { + if (cmp(orig_values[rev_res[j]], orig_values[rev_res[i]])) { + auto tmp = rev_res[i]; + rev_res[i] = rev_res[j]; + rev_res[j] = tmp; + } + } + } + + std::array()> sorted_values{}; + // reverse the sorted indices + std::array()> res{}; + for (std::size_t i = 0; i < enum_count(); ++i) { + res[rev_res[i]] = i; + sorted_values[i] = orig_values[rev_res[i]]; + } + + return std::pair{sorted_values, res}; + } + + static constexpr auto indices = get_indices(); + + public: + [[nodiscard]] static constexpr const E* begin() noexcept { return indices.first.data(); } + + [[nodiscard]] static constexpr const E* end() noexcept { return indices.first.data() + indices.first.size(); } + + [[nodiscard]] static constexpr const E* it(std::size_t i) noexcept { return indices.first.data() + i; } + + [[nodiscard]] static constexpr optional at(E val) noexcept { + if (auto i = enum_index(val)) { + return indices.second[*i]; + } + return {}; + } +}; + +template +class indexing> && (std::is_same_v> || std::is_same_v>)>> { + static constexpr auto& values = enum_values(); + + public: + [[nodiscard]] static constexpr const E* begin() noexcept { return values.data(); } + + [[nodiscard]] static constexpr const E* end() noexcept { return values.data() + values.size(); } + + [[nodiscard]] static constexpr const E* it(std::size_t i) noexcept { return values.data() + i; } + + [[nodiscard]] static constexpr optional at(E val) noexcept { return enum_index(val); } +}; + +template +struct indexing { + using is_transparent = std::true_type; + + template + [[nodiscard]] static constexpr optional at(E val) noexcept { + return indexing::at(val); + } +}; + +template , typename = void> +struct name_sort_impl { + [[nodiscard]] constexpr bool operator()(E e1, E e2) const noexcept { return Cmp{}(enum_name(e1), enum_name(e2)); } +}; + +template +struct name_sort_impl { + using is_transparent = std::true_type; + + template + struct FullCmp : C {}; + + template + struct FullCmp && std::is_invocable_v>> { + [[nodiscard]] constexpr bool operator()(string_view s1, string_view s2) const noexcept { return lexicographical_compare(s1, s2); } + }; + + template + [[nodiscard]] constexpr std::enable_if_t< + // at least one of need to be an enum type + (std::is_enum_v> || std::is_enum_v>) && + // if both is enum, only accept if the same enum + (!std::is_enum_v> || !std::is_enum_v> || std::is_same_v) && + // is invocable with comparator + (std::is_invocable_r_v, std::conditional_t>, string_view, E1>, std::conditional_t>, string_view, E2>>), + bool> + operator()(E1 e1, E2 e2) const noexcept { + using D1 = std::decay_t; + using D2 = std::decay_t; + constexpr FullCmp<> cmp{}; + + if constexpr (std::is_enum_v && std::is_enum_v) { + return cmp(enum_name(e1), enum_name(e2)); + } else if constexpr (std::is_enum_v) { + return cmp(enum_name(e1), e2); + } else /* if constexpr (std::is_enum_v) */ { + return cmp(e1, enum_name(e2)); + } + } +}; + +struct raw_access_t {}; + +template +struct FilteredIterator { + Parent parent; + Iterator first; + Iterator last; + Iterator current; + Getter getter; + Predicate predicate; + + using iterator_category = std::bidirectional_iterator_tag; + using value_type = std::remove_reference_t>; + using difference_type = std::ptrdiff_t; + using pointer = value_type*; + using reference = value_type&; + + constexpr FilteredIterator() noexcept = default; + constexpr FilteredIterator(const FilteredIterator&) = default; + constexpr FilteredIterator& operator=(const FilteredIterator&) = default; + constexpr FilteredIterator(FilteredIterator&&) noexcept = default; + constexpr FilteredIterator& operator=(FilteredIterator&&) noexcept = default; + + template && std::is_convertible_v>*> + constexpr explicit FilteredIterator(const FilteredIterator& other) + : parent(other.parent), first(other.first), last(other.last), current(other.current), getter(other.getter), predicate(other.predicate) {} + + constexpr FilteredIterator(Parent p, Iterator begin, Iterator end, Iterator curr, Getter getter = {}, Predicate pred = {}) + : parent(p), first(std::move(begin)), last(std::move(end)), current(std::move(curr)), getter{std::move(getter)}, predicate{std::move(pred)} { + if (current == first && !predicate(parent, current)) { + ++*this; + } + } + + [[nodiscard]] constexpr reference operator*() const { return getter(parent, current); } + + [[nodiscard]] constexpr pointer operator->() const { return std::addressof(**this); } + + constexpr FilteredIterator& operator++() { + do { + ++current; + } while (current != last && !predicate(parent, current)); + return *this; + } + + [[nodiscard]] constexpr FilteredIterator operator++(int) { + FilteredIterator cp = *this; + ++*this; + return cp; + } + + constexpr FilteredIterator& operator--() { + do { + --current; + } while (current != first && !predicate(parent, current)); + return *this; + } + + [[nodiscard]] constexpr FilteredIterator operator--(int) { + FilteredIterator cp = *this; + --*this; + return cp; + } + + [[nodiscard]] friend constexpr bool operator==(const FilteredIterator& lhs, const FilteredIterator& rhs) { return lhs.current == rhs.current; } + + [[nodiscard]] friend constexpr bool operator!=(const FilteredIterator& lhs, const FilteredIterator& rhs) { return lhs.current != rhs.current; } +}; + +} // namespace detail + +template +using name_less = detail::name_sort_impl; + +template +using name_greater = detail::name_sort_impl>; + +using name_less_case_insensitive = detail::name_sort_impl>>; + +using name_greater_case_insensitive = detail::name_sort_impl>>; + +template +using default_indexing = detail::indexing; + +template > +using comparator_indexing = detail::indexing; + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// ARRAY // +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +template > +struct array { + static_assert(std::is_enum_v); + static_assert(std::is_trivially_constructible_v); + static_assert(enum_count() == 0 || Index::at(enum_values().front())); // check Index is constexpr + + using index_type = Index; + using container_type = std::array()>; + + using value_type = typename container_type::value_type; + using size_type = typename container_type::size_type; + using difference_type = typename container_type::difference_type; + using reference = typename container_type::reference; + using const_reference = typename container_type::const_reference; + using pointer = typename container_type::pointer; + using const_pointer = typename container_type::const_pointer; + using iterator = typename container_type::iterator; + using const_iterator = typename container_type::const_iterator; + using reverse_iterator = typename container_type::reverse_iterator; + using const_reverse_iterator = typename container_type::const_reverse_iterator; + + constexpr reference at(E pos) { + if (auto index = index_type::at(pos)) { + return a[*index]; + } + MAGIC_ENUM_THROW(std::out_of_range("magic_enum::containers::array::at Unrecognized position")); + } + + constexpr const_reference at(E pos) const { + if (auto index = index_type::at(pos)) { + return a[*index]; + } + MAGIC_ENUM_THROW(std::out_of_range("magic_enum::containers::array::at: Unrecognized position")); + } + + [[nodiscard]] constexpr reference operator[](E pos) { + auto i = index_type::at(pos); + return MAGIC_ENUM_ASSERT(i), a[*i]; + } + + [[nodiscard]] constexpr const_reference operator[](E pos) const { + auto i = index_type::at(pos); + return MAGIC_ENUM_ASSERT(i), a[*i]; + } + + [[nodiscard]] constexpr reference front() noexcept { return a.front(); } + + [[nodiscard]] constexpr const_reference front() const noexcept { return a.front(); } + + [[nodiscard]] constexpr reference back() noexcept { return a.back(); } + + [[nodiscard]] constexpr const_reference back() const noexcept { return a.back(); } + + [[nodiscard]] constexpr pointer data() noexcept { return a.data(); } + + [[nodiscard]] constexpr const_pointer data() const noexcept { return a.data(); } + + [[nodiscard]] constexpr iterator begin() noexcept { return a.begin(); } + + [[nodiscard]] constexpr const_iterator begin() const noexcept { return a.begin(); } + + [[nodiscard]] constexpr const_iterator cbegin() const noexcept { return a.cbegin(); } + + [[nodiscard]] constexpr iterator end() noexcept { return a.end(); } + + [[nodiscard]] constexpr const_iterator end() const noexcept { return a.end(); } + + [[nodiscard]] constexpr const_iterator cend() const noexcept { return a.cend(); } + + [[nodiscard]] constexpr iterator rbegin() noexcept { return a.rbegin(); } + + [[nodiscard]] constexpr const_iterator rbegin() const noexcept { return a.rbegin(); } + + [[nodiscard]] constexpr const_iterator crbegin() const noexcept { return a.crbegin(); } + + [[nodiscard]] constexpr iterator rend() noexcept { return a.rend(); } + + [[nodiscard]] constexpr const_iterator rend() const noexcept { return a.rend(); } + + [[nodiscard]] constexpr const_iterator crend() const noexcept { return a.crend(); } + + [[nodiscard]] constexpr bool empty() const noexcept { return a.empty(); } + + [[nodiscard]] constexpr size_type size() const noexcept { return a.size(); } + + [[nodiscard]] constexpr size_type max_size() const noexcept { return a.max_size(); } + + constexpr void fill(const V& value) { + for (auto& v : a) { + v = value; + } + } + + constexpr void swap(array& other) noexcept(std::is_nothrow_swappable_v) { + for (std::size_t i = 0; i < a.size(); ++i) { + auto v = std::move(other.a[i]); + other.a[i] = std::move(a[i]); + a[i] = std::move(v); + } + } + + [[nodiscard]] friend constexpr bool operator==(const array& a1, const array& a2) { return detail::equal(a1, a2); } + + [[nodiscard]] friend constexpr bool operator!=(const array& a1, const array& a2) { return !detail::equal(a1, a2); } + + [[nodiscard]] friend constexpr bool operator<(const array& a1, const array& a2) { return detail::lexicographical_compare(a1, a2); } + + [[nodiscard]] friend constexpr bool operator<=(const array& a1, const array& a2) { return !detail::lexicographical_compare(a2, a1); } + + [[nodiscard]] friend constexpr bool operator>(const array& a1, const array& a2) { return detail::lexicographical_compare(a2, a1); } + + [[nodiscard]] friend constexpr bool operator>=(const array& a1, const array& a2) { return !detail::lexicographical_compare(a1, a2); } + + container_type a; +}; + +namespace detail { + +template +constexpr array> to_array_impl(T (&a)[N], std::index_sequence) { + return {{a[I]...}}; +} + +template +constexpr array> to_array_impl(T(&&a)[N], std::index_sequence) { + return {{std::move(a[I])...}}; +} + +} // namespace detail + +template +constexpr std::enable_if_t<(enum_count() == N), array>> to_array(T (&a)[N]) { + return detail::to_array_impl(a, std::make_index_sequence{}); +} + +template +constexpr std::enable_if_t<(enum_count() == N), array>> to_array(T(&&a)[N]) { + return detail::to_array_impl(std::move(a), std::make_index_sequence{}); +} + +template +constexpr std::enable_if_t<(enum_count() == sizeof...(Ts)), array>>> make_array(Ts&&... ts) { + return {{std::forward(ts)...}}; +} + +inline constexpr detail::raw_access_t raw_access{}; + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// BITSET // +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +template > +class bitset { + static_assert(std::is_enum_v); + static_assert(std::is_trivially_constructible_v); + static_assert(enum_count() == 0 || Index::at(enum_values().front())); // check Index is constexpr + + using base_type = std::conditional_t() <= 8, std::uint_least8_t, + std::conditional_t() <= 16, std::uint_least16_t, + std::conditional_t() <= 32, std::uint_least32_t, + std::uint_least64_t>>>; + + static constexpr std::size_t bits_per_base = sizeof(base_type) * 8; + static constexpr std::size_t base_type_count = (enum_count() > 0 ? (enum_count() - 1) / bits_per_base + 1 : 0); + static constexpr std::size_t not_interested = base_type_count * bits_per_base - enum_count(); + static constexpr base_type last_value_max = (base_type{1} << (bits_per_base - not_interested)) - 1; + + template + class reference_impl { + friend class bitset; + + parent_t parent; + std::size_t num_index; + base_type bit_index; + + constexpr reference_impl(parent_t parent, std::size_t ix) noexcept : reference_impl(parent, std::pair{ix / bits_per_base, base_type{1} << (ix % bits_per_base)}) {} + + constexpr reference_impl(parent_t parent, std::pair ix) noexcept : parent(parent), num_index(std::get<0>(ix)), bit_index(std::get<1>(ix)) {} + + public: + constexpr reference_impl& operator=(bool v) noexcept { + if (v) { + parent->a[num_index] |= bit_index; + } else { + parent->a[num_index] &= ~bit_index; + } + return *this; + } + + constexpr reference_impl& operator=(const reference_impl& v) noexcept { + if (this == &v) { + return *this; + } + *this = static_cast(v); + return *this; + } + + [[nodiscard]] constexpr explicit operator bool() const noexcept { return (parent->a[num_index] & bit_index) > 0; } + + [[nodiscard]] constexpr bool operator~() const noexcept { return !static_cast(*this); } + + constexpr reference_impl& flip() noexcept { + *this = ~*this; + return *this; + } + }; + + template + [[nodiscard]] constexpr T to_(detail::raw_access_t) const { + T res{}; + T flag{1}; + for (std::size_t i = 0; i < size(); ++i, flag <<= 1) { + if (const_reference{this, i}) { + if (i >= sizeof(T) * 8) { + MAGIC_ENUM_THROW(std::overflow_error("magic_enum::containers::bitset::to: Cannot represent enum in this type")); + } + res |= flag; + } + } + return res; + } + + public: + using index_type = Index; + using container_type = std::array; + using reference = reference_impl<>; + using const_reference = reference_impl; + + constexpr explicit bitset(detail::raw_access_t = raw_access) noexcept : a{{}} {} + + constexpr explicit bitset(detail::raw_access_t, unsigned long long val) : a{{}} { + unsigned long long bit{1}; + for (std::size_t i = 0; i < (sizeof(val) * 8); ++i, bit <<= 1) { + if ((val & bit) > 0) { + if (i >= enum_count()) { + MAGIC_ENUM_THROW(std::out_of_range("magic_enum::containers::bitset::constructor: Upper bit set in raw number")); + } + + reference{this, i} = true; + } + } + } + + constexpr explicit bitset(detail::raw_access_t, string_view sv, string_view::size_type pos = 0, string_view::size_type n = string_view::npos, char_type zero = static_cast('0'), char_type one = static_cast('1')) + : a{{}} { + std::size_t i = 0; + for (auto c : sv.substr(pos, n)) { + if (c == one) { + if (i >= enum_count()) { + MAGIC_ENUM_THROW(std::out_of_range("magic_enum::containers::bitset::constructor: Upper bit set in raw string")); + } + reference{this, i} = true; + } else if (c != zero) { + MAGIC_ENUM_THROW(std::invalid_argument("magic_enum::containers::bitset::constructor: Unrecognized character in raw string")); + } + ++i; + } + } + + constexpr explicit bitset(detail::raw_access_t, const char_type* str, std::size_t n = ~std::size_t{0}, char_type zero = static_cast('0'), char_type one = static_cast('1')) + : bitset(string_view{str, (std::min)(std::char_traits::length(str), n)}, 0, n, zero, one) {} + + constexpr bitset(std::initializer_list starters) : a{{}} { + if constexpr (magic_enum::detail::subtype_v == magic_enum::detail::enum_subtype::flags) { + for (auto& f : starters) { + *this |= bitset(f); + } + } else { + for (auto& f : starters) { + set(f); + } + } + } + template && magic_enum::detail::subtype_v == magic_enum::detail::enum_subtype::flags, int> = 0> + constexpr explicit bitset(V starter) : a{{}} { + auto u = enum_underlying(starter); + for (E v : enum_values()) { + if (auto ul = enum_underlying(v); (ul & u) != 0) { + u &= ~ul; + (*this)[v] = true; + } + } + if (u != 0) { + MAGIC_ENUM_THROW(std::invalid_argument("magic_enum::containers::bitset::constructor: Unrecognized enum value in flag")); + } + } + + template > + constexpr explicit bitset(string_view sv, Cmp&& cmp = {}, char_type sep = static_cast('|')) { + for (std::size_t to = 0; (to = magic_enum::detail::find(sv, sep)) != string_view::npos; sv.remove_prefix(to + 1)) { + if (auto v = enum_cast(sv.substr(0, to), cmp)) { + set(v); + } else { + MAGIC_ENUM_THROW(std::invalid_argument("magic_enum::containers::bitset::constructor: Unrecognized enum value in string")); + } + } + if (!sv.empty()) { + if (auto v = enum_cast(sv, cmp)) { + set(v); + } else { + MAGIC_ENUM_THROW(std::invalid_argument("magic_enum::containers::bitset::constructor: Unrecognized enum value in string")); + } + } + } + + [[nodiscard]] friend constexpr bool operator==(const bitset& lhs, const bitset& rhs) noexcept { return detail::equal(lhs.a, rhs.a); } + + [[nodiscard]] friend constexpr bool operator!=(const bitset& lhs, const bitset& rhs) noexcept { return !detail::equal(lhs.a, rhs.a); } + + [[nodiscard]] constexpr bool operator[](E pos) const { + auto i = index_type::at(pos); + return MAGIC_ENUM_ASSERT(i), static_cast(const_reference(this, *i)); + } + + [[nodiscard]] constexpr reference operator[](E pos) { + auto i = index_type::at(pos); + return MAGIC_ENUM_ASSERT(i), reference{this, *i}; + } + + constexpr bool test(E pos) const { + if (auto i = index_type::at(pos)) { + return static_cast(const_reference(this, *i)); + } + MAGIC_ENUM_THROW(std::out_of_range("magic_enum::containers::bitset::test: Unrecognized position")); + } + + [[nodiscard]] constexpr bool all() const noexcept { + if constexpr (base_type_count == 0) { + return true; + } + + for (std::size_t i = 0; i < base_type_count - (not_interested > 0); ++i) { + auto check = ~a[i]; + if (check) { + return false; + } + } + + if constexpr (not_interested > 0) { + return a[base_type_count - 1] == last_value_max; + } + } + + [[nodiscard]] constexpr bool any() const noexcept { + for (auto& v : a) { + if (v > 0) { + return true; + } + } + return false; + } + + [[nodiscard]] constexpr bool none() const noexcept { return !any(); } + + [[nodiscard]] constexpr std::size_t count() const noexcept { + std::size_t c = 0; + for (auto& v : a) { + c += detail::popcount(v); + } + return c; + } + + [[nodiscard]] constexpr std::size_t size() const noexcept { return enum_count(); } + + [[nodiscard]] constexpr std::size_t max_size() const noexcept { return enum_count(); } + + constexpr bitset& operator&=(const bitset& other) noexcept { + for (std::size_t i = 0; i < base_type_count; ++i) { + a[i] &= other.a[i]; + } + return *this; + } + + constexpr bitset& operator|=(const bitset& other) noexcept { + for (std::size_t i = 0; i < base_type_count; ++i) { + a[i] |= other.a[i]; + } + return *this; + } + + constexpr bitset& operator^=(const bitset& other) noexcept { + for (std::size_t i = 0; i < base_type_count; ++i) { + a[i] ^= other.a[i]; + } + return *this; + } + + [[nodiscard]] constexpr bitset operator~() const noexcept { + bitset res; + for (std::size_t i = 0; i < base_type_count - (not_interested > 0); ++i) { + res.a[i] = ~a[i]; + } + + if constexpr (not_interested > 0) { + res.a[base_type_count - 1] = ~a[base_type_count - 1] & last_value_max; + } + return res; + } + + constexpr bitset& set() noexcept { + for (std::size_t i = 0; i < base_type_count - (not_interested > 0); ++i) { + a[i] = ~base_type{0}; + } + + if constexpr (not_interested > 0) { + a[base_type_count - 1] = last_value_max; + } + return *this; + } + + constexpr bitset& set(E pos, bool value = true) { + if (auto i = index_type::at(pos)) { + reference{this, *i} = value; + return *this; + } + MAGIC_ENUM_THROW(std::out_of_range("magic_enum::containers::bitset::set: Unrecognized position")); + } + + constexpr bitset& reset() noexcept { return *this = bitset{}; } + + constexpr bitset& reset(E pos) { + if (auto i = index_type::at(pos)) { + reference{this, *i} = false; + return *this; + } + MAGIC_ENUM_THROW(std::out_of_range("magic_enum::containers::bitset::reset: Unrecognized position")); + } + + constexpr bitset& flip() noexcept { return *this = ~*this; } + + [[nodiscard]] friend constexpr bitset operator&(const bitset& lhs, const bitset& rhs) noexcept { + bitset cp = lhs; + cp &= rhs; + return cp; + } + + [[nodiscard]] friend constexpr bitset operator|(const bitset& lhs, const bitset& rhs) noexcept { + bitset cp = lhs; + cp |= rhs; + return cp; + } + + [[nodiscard]] friend constexpr bitset operator^(const bitset& lhs, const bitset& rhs) noexcept { + bitset cp = lhs; + cp ^= rhs; + return cp; + } + + template + [[nodiscard]] constexpr explicit operator std::enable_if_t == magic_enum::detail::enum_subtype::flags, E>() const { + E res{}; + for (const auto& e : enum_values()) { + if (test(e)) { + res |= e; + } + } + return res; + } + + [[nodiscard]] string to_string(char_type sep = static_cast('|')) const { + string name; + + for (const auto& e : enum_values()) { + if (test(e)) { + if (!name.empty()) { + name.append(1, sep); + } + auto n = enum_name(e); + name.append(n.data(), n.size()); + } + } + return name; + } + + [[nodiscard]] string to_string(detail::raw_access_t, char_type zero = static_cast('0'), char_type one = static_cast('1')) const { + string name; + name.reserve(size()); + for (std::size_t i = 0; i < size(); ++i) { + name.append(1, const_reference{this, i} ? one : zero); + } + return name; + } + + [[nodiscard]] constexpr unsigned long long to_ullong(detail::raw_access_t raw) const { return to_(raw); } + + [[nodiscard]] constexpr unsigned long long to_ulong(detail::raw_access_t raw) const { return to_(raw); } + + friend std::ostream& operator<<(std::ostream& o, const bitset& bs) { return o << bs.to_string(); } + + friend std::istream& operator>>(std::istream& i, bitset& bs) { + string s; + if (i >> s; !s.empty()) { + bs = bitset(string_view{s}); + } + return i; + } + + private: + container_type a; +}; + +template +explicit bitset(V starter) -> bitset; + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// SET // +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +template > +class set { + using index_type = detail::indexing; + struct Getter { + constexpr const E& operator()(const set*, const E* p) const noexcept { return *p; } + }; + struct Predicate { + constexpr bool operator()(const set* h, const E* e) const noexcept { return h->a[*e]; } + }; + + public: + using container_type = bitset; + using key_type = E; + using value_type = E; + using size_type = std::size_t; + using difference_type = std::ptrdiff_t; + using key_compare = Cmp; + using value_compare = Cmp; + using reference = value_type&; + using const_reference = const value_type&; + using pointer = value_type*; + using const_pointer = const value_type*; + using iterator = detail::FilteredIterator; + using const_iterator = detail::FilteredIterator; + using reverse_iterator = std::reverse_iterator; + using const_reverse_iterator = std::reverse_iterator; + + constexpr set() noexcept = default; + + template + constexpr set(InputIt first, InputIt last) { + while (first != last) { + insert(*first++); + } + } + + constexpr set(std::initializer_list ilist) { + for (auto e : ilist) { + insert(e); + } + } + template && magic_enum::detail::subtype_v == magic_enum::detail::enum_subtype::flags, int> = 0> + constexpr explicit set(V starter) { + auto u = enum_underlying(starter); + for (E v : enum_values()) { + if ((enum_underlying(v) & u) != 0) { + insert(v); + } + } + } + + constexpr set(const set&) noexcept = default; + constexpr set(set&&) noexcept = default; + + constexpr set& operator=(const set&) noexcept = default; + constexpr set& operator=(set&&) noexcept = default; + constexpr set& operator=(std::initializer_list ilist) { + for (auto e : ilist) { + insert(e); + } + } + + constexpr const_iterator begin() const noexcept { + return const_iterator{this, index_type::begin(), index_type::end(), index_type::begin()}; + } + + constexpr const_iterator end() const noexcept { + return const_iterator{this, index_type::begin(), index_type::end(), index_type::end()}; + } + + constexpr const_iterator cbegin() const noexcept { return begin(); } + + constexpr const_iterator cend() const noexcept { return end(); } + + constexpr const_reverse_iterator rbegin() const noexcept { return {end()}; } + + constexpr const_reverse_iterator rend() const noexcept { return {begin()}; } + + constexpr const_reverse_iterator crbegin() const noexcept { return rbegin(); } + + constexpr const_reverse_iterator crend() const noexcept { return rend(); } + + [[nodiscard]] constexpr bool empty() const noexcept { return s == 0; } + + [[nodiscard]] constexpr size_type size() const noexcept { return s; } + + [[nodiscard]] constexpr size_type max_size() const noexcept { return a.max_size(); } + + constexpr void clear() noexcept { + a.reset(); + s = 0; + } + + constexpr std::pair insert(const value_type& value) noexcept { + if (auto i = index_type::at(value)) { + typename container_type::reference ref = a[value]; + bool r = !ref; + if (r) { + ref = true; + ++s; + } + + return {iterator{this, index_type::begin(), index_type::end(), index_type::it(*i)}, r}; + } + return {end(), false}; + } + + constexpr std::pair insert(value_type&& value) noexcept { return insert(value); } + + constexpr iterator insert(const_iterator, const value_type& value) noexcept { return insert(value).first; } + + constexpr iterator insert(const_iterator hint, value_type&& value) noexcept { return insert(hint, value); } + + template + constexpr void insert(InputIt first, InputIt last) noexcept { + while (first != last) { + insert(*first++); + } + } + + constexpr void insert(std::initializer_list ilist) noexcept { + for (auto v : ilist) { + insert(v); + } + } + + template + constexpr std::pair emplace(Args&&... args) noexcept { + return insert({std::forward(args)...}); + } + + template + constexpr iterator emplace_hint(const_iterator, Args&&... args) noexcept { + return emplace(std::forward(args)...).first; + } + + constexpr iterator erase(const_iterator pos) noexcept { + erase(*pos++); + return pos; + } + + constexpr iterator erase(const_iterator first, const_iterator last) noexcept { + while ((first = erase(first)) != last) { + } + return first; + } + + constexpr size_type erase(const key_type& key) noexcept { + typename container_type::reference ref = a[key]; + bool res = ref; + if (res) { + --s; + } + ref = false; + return res; + } + + template + constexpr std::enable_if_t, size_type> erase(K&& x) noexcept { + size_type c = 0; + for (auto [first, last] = detail::equal_range(index_type::begin(), index_type::end(), x, key_compare{}); first != last;) { + c += erase(*first++); + } + return c; + } + + void swap(set& other) noexcept { + set cp = *this; + *this = other; + other = cp; + } + + [[nodiscard]] constexpr size_type count(const key_type& key) const noexcept { return index_type::at(key) && a[key]; } + + template + [[nodiscard]] constexpr std::enable_if_t, size_type> count(const K& x) const { + size_type c = 0; + for (auto [first, last] = detail::equal_range(index_type::begin(), index_type::end(), x, key_compare{}); first != last; ++first) { + c += count(*first); + } + return c; + } + + [[nodiscard]] constexpr const_iterator find(const key_type& key) const noexcept { + if (auto i = index_type::at(key); i && a.test(key)) { + return const_iterator{this, index_type::begin(), index_type::end(), index_type::it(*i)}; + } + return end(); + } + + template + [[nodiscard]] constexpr std::enable_if_t, const_iterator> find(const K& x) const { + for (auto [first, last] = detail::equal_range(index_type::begin(), index_type::end(), x, key_compare{}); first != last; ++first) { + if (a.test(*first)) { + return find(*first); + } + } + return end(); + } + + [[nodiscard]] constexpr bool contains(const key_type& key) const noexcept { return count(key); } + + template + [[nodiscard]] constexpr std::enable_if_t, bool> contains(const K& x) const noexcept { + return count(x) > 0; + } + + [[nodiscard]] constexpr std::pair equal_range(const key_type& key) const noexcept { return {lower_bound(key), upper_bound(key)}; } + + template + [[nodiscard]] constexpr std::enable_if_t, std::pair> equal_range(const K& x) const noexcept { + return {lower_bound(x), upper_bound(x)}; + } + + [[nodiscard]] constexpr const_iterator lower_bound(const key_type& key) const noexcept { + if (auto i = index_type::at(key)) { + auto it = const_iterator{this, index_type::begin(), index_type::end(), index_type::it(*i)}; + return a.test(key) ? it : std::next(it); + } + return end(); + } + + template + [[nodiscard]] constexpr std::enable_if_t, const_iterator> lower_bound(const K& x) const noexcept { + auto [first, last] = detail::equal_range(index_type::begin(), index_type::end(), x, key_compare{}); + return first != last ? lower_bound(*first) : end(); + } + + [[nodiscard]] constexpr const_iterator upper_bound(const key_type& key) const noexcept { + if (auto i = index_type::at(key)) { + return std::next(const_iterator{this, index_type::begin(), index_type::end(), index_type::it(*i)}); + } + return end(); + } + + template + [[nodiscard]] constexpr std::enable_if_t, const_iterator> upper_bound(const K& x) const noexcept { + auto [first, last] = detail::equal_range(index_type::begin(), index_type::end(), x, key_compare{}); + return first != last ? upper_bound(*std::prev(last)) : end(); + } + + [[nodiscard]] constexpr key_compare key_comp() const { return {}; } + + [[nodiscard]] constexpr value_compare value_comp() const { return {}; } + + [[nodiscard]] constexpr friend bool operator==(const set& lhs, const set& rhs) noexcept { return lhs.a == rhs.a; } + + [[nodiscard]] constexpr friend bool operator!=(const set& lhs, const set& rhs) noexcept { return lhs.a != rhs.a; } + + [[nodiscard]] constexpr friend bool operator<(const set& lhs, const set& rhs) noexcept { + if (lhs.s < rhs.s) { + return true; + } + if (rhs.s < lhs.s) { + return false; + } + + for (auto it = index_type::begin(); it != index_type::end(); ++it) { + if (auto c = rhs.contains(*it); c != lhs.contains(*it)) { + return c; + } + } + return false; + } + + [[nodiscard]] constexpr friend bool operator<=(const set& lhs, const set& rhs) noexcept { return !(rhs < lhs); } + + [[nodiscard]] constexpr friend bool operator>(const set& lhs, const set& rhs) noexcept { return rhs < lhs; } + + [[nodiscard]] constexpr friend bool operator>=(const set& lhs, const set& rhs) noexcept { return !(lhs < rhs); } + + template + size_type erase_if(Pred pred) { + auto old_size = size(); + for (auto i = begin(), last = end(); i != last;) { + if (pred(*i)) { + i = erase(i); + } else { + ++i; + } + } + return old_size - size(); + } + + private: + container_type a; + std::size_t s = 0; +}; + +template +explicit set(V starter) -> set; + +} // namespace magic_enum::containers + +namespace std { + +template +constexpr std::enable_if_t<(std::is_integral_v && I < magic_enum::enum_count()), V&> get(magic_enum::containers::array& a) noexcept { + return a.a[I]; +} + +template +constexpr std::enable_if_t<(std::is_integral_v && I < magic_enum::enum_count()), V&&> get(magic_enum::containers::array&& a) noexcept { + return std::move(a.a[I]); +} + +template +constexpr std::enable_if_t<(std::is_integral_v && I < magic_enum::enum_count()), const V&> get(const magic_enum::containers::array& a) noexcept { + return a.a[I]; +} + +template +constexpr std::enable_if_t<(std::is_integral_v && I < magic_enum::enum_count()), const V&&> get(const magic_enum::containers::array&& a) noexcept { + return std::move(a.a[I]); +} + +template +constexpr std::enable_if_t && magic_enum::enum_contains(Enum), V&> get(magic_enum::containers::array& a) noexcept { + return a[Enum]; +} + +template +constexpr std::enable_if_t && magic_enum::enum_contains(Enum), V&&> get(magic_enum::containers::array&& a) noexcept { + return std::move(a[Enum]); +} + +template +constexpr std::enable_if_t && magic_enum::enum_contains(Enum), const V&> get(const magic_enum::containers::array& a) noexcept { + return a[Enum]; +} + +template +constexpr std::enable_if_t && magic_enum::enum_contains(Enum), const V&&> get(const magic_enum::containers::array&& a) noexcept { + return std::move(a[Enum]); +} + +} // namespace std + +#endif // NEARGYE_MAGIC_ENUM_CONTAINERS_HPP diff --git a/src/3rd party/magic_enum/magic_enum_flags.hpp b/src/3rd party/magic_enum/magic_enum_flags.hpp new file mode 100644 index 0000000000..a45ed78ff0 --- /dev/null +++ b/src/3rd party/magic_enum/magic_enum_flags.hpp @@ -0,0 +1,203 @@ +// __ __ _ ______ _____ +// | \/ | (_) | ____| / ____|_ _ +// | \ / | __ _ __ _ _ ___ | |__ _ __ _ _ _ __ ___ | | _| |_ _| |_ +// | |\/| |/ _` |/ _` | |/ __| | __| | '_ \| | | | '_ ` _ \ | | |_ _|_ _| +// | | | | (_| | (_| | | (__ | |____| | | | |_| | | | | | | | |____|_| |_| +// |_| |_|\__,_|\__, |_|\___| |______|_| |_|\__,_|_| |_| |_| \_____| +// __/ | https://github.com/Neargye/magic_enum +// |___/ version 0.9.3 +// +// Licensed under the MIT License . +// SPDX-License-Identifier: MIT +// Copyright (c) 2019 - 2023 Daniil Goncharov . +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#ifndef NEARGYE_MAGIC_ENUM_FLAGS_HPP +#define NEARGYE_MAGIC_ENUM_FLAGS_HPP + +#include "magic_enum.hpp" + +#if defined(__clang__) +# pragma clang diagnostic push +#elif defined(__GNUC__) +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wmaybe-uninitialized" // May be used uninitialized 'return {};'. +#elif defined(_MSC_VER) +# pragma warning(push) +#endif + +namespace magic_enum { + +// Returns name from enum-flags value. +// If enum-flags value does not have name or value out of range, returns empty string. +template +[[nodiscard]] auto enum_flags_name(E value, char_type sep = static_cast('|')) -> detail::enable_if_t { + using D = std::decay_t; + using U = underlying_type_t; + constexpr auto S = detail::enum_subtype::flags; + + string name; + auto check_value = U{0}; + for (std::size_t i = 0; i < detail::count_v; ++i) { + if (const auto v = static_cast(enum_value(i)); (static_cast(value) & v) != 0) { + if (const auto n = detail::names_v[i]; !n.empty()) { + check_value |= v; + if (!name.empty()) { + name.append(1, sep); + } + name.append(n.data(), n.size()); + } else { + return {}; // Value out of range. + } + } + } + + if (check_value != 0 && check_value == static_cast(value)) { + return name; + } + return {}; // Invalid value or out of range. +} + +// Obtains enum-flags value from integer value. +// Returns optional with enum-flags value. +template +[[nodiscard]] constexpr auto enum_flags_cast(underlying_type_t value) noexcept -> detail::enable_if_t>> { + using D = std::decay_t; + using U = underlying_type_t; + constexpr auto S = detail::enum_subtype::flags; + + if constexpr (detail::count_v == 0) { + static_cast(value); + return {}; // Empty enum. + } else { + if constexpr (detail::is_sparse_v) { + auto check_value = U{0}; + for (std::size_t i = 0; i < detail::count_v; ++i) { + if (const auto v = static_cast(enum_value(i)); (value & v) != 0) { + check_value |= v; + } + } + + if (check_value != 0 && check_value == value) { + return static_cast(value); + } + } else { + constexpr auto min = detail::min_v; + constexpr auto max = detail::values_ors(); + + if (value >= min && value <= max) { + return static_cast(value); + } + } + return {}; // Invalid value or out of range. + } +} + +// Obtains enum-flags value from name. +// Returns optional with enum-flags value. +template > +[[nodiscard]] constexpr auto enum_flags_cast(string_view value, [[maybe_unused]] BinaryPredicate p = {}) noexcept(detail::is_nothrow_invocable()) -> detail::enable_if_t>, BinaryPredicate> { + using D = std::decay_t; + using U = underlying_type_t; + constexpr auto S = detail::enum_subtype::flags; + + if constexpr (detail::count_v == 0) { + static_cast(value); + return {}; // Empty enum. + } else { + auto result = U{0}; + while (!value.empty()) { + const auto d = detail::find(value, '|'); + const auto s = (d == string_view::npos) ? value : value.substr(0, d); + auto f = U{0}; + for (std::size_t i = 0; i < detail::count_v; ++i) { + if (detail::cmp_equal(s, detail::names_v[i], p)) { + f = static_cast(enum_value(i)); + result |= f; + break; + } + } + if (f == U{0}) { + return {}; // Invalid value or out of range. + } + value.remove_prefix((d == string_view::npos) ? value.size() : d + 1); + } + + if (result != U{0}) { + return static_cast(result); + } + return {}; // Invalid value or out of range. + } +} + +// Checks whether enum-flags contains value with such value. +template +[[nodiscard]] constexpr auto enum_flags_contains(E value) noexcept -> detail::enable_if_t { + using D = std::decay_t; + using U = underlying_type_t; + + return static_cast(enum_flags_cast(static_cast(value))); +} + +// Checks whether enum-flags contains value with such integer value. +template +[[nodiscard]] constexpr auto enum_flags_contains(underlying_type_t value) noexcept -> detail::enable_if_t { + using D = std::decay_t; + + return static_cast(enum_flags_cast(value)); +} + +// Checks whether enum-flags contains enumerator with such name. +template > +[[nodiscard]] constexpr auto enum_flags_contains(string_view value, BinaryPredicate p = {}) noexcept(detail::is_nothrow_invocable()) -> detail::enable_if_t { + using D = std::decay_t; + + return static_cast(enum_flags_cast(value, std::move(p))); +} + +// Checks whether `flags set` contains `flag`. +// Note: If `flag` equals 0, it returns false, as 0 is not a flag. +template +constexpr auto enum_flags_test(E flags, E flag) noexcept -> detail::enable_if_t { + using U = underlying_type_t; + + return static_cast(flag) && ((static_cast(flags) & static_cast(flag)) == static_cast(flag)); +} + +// Checks whether `lhs flags set` and `rhs flags set` have common flags. +// Note: If `lhs flags set` or `rhs flags set` equals 0, it returns false, as 0 is not a flag, and therfore cannot have any matching flag. +template +constexpr auto enum_flags_test_any(E lhs, E rhs) noexcept -> detail::enable_if_t { + using U = underlying_type_t; + + return (static_cast(lhs) & static_cast(rhs)) != 0; +} + +} // namespace magic_enum + +#if defined(__clang__) +# pragma clang diagnostic pop +#elif defined(__GNUC__) +# pragma GCC diagnostic pop +#elif defined(_MSC_VER) +# pragma warning(pop) +#endif + +#endif // NEARGYE_MAGIC_ENUM_FLAGS_HPP diff --git a/src/3rd party/magic_enum/magic_enum_format.hpp b/src/3rd party/magic_enum/magic_enum_format.hpp new file mode 100644 index 0000000000..bd725b5ea2 --- /dev/null +++ b/src/3rd party/magic_enum/magic_enum_format.hpp @@ -0,0 +1,110 @@ +// __ __ _ ______ _____ +// | \/ | (_) | ____| / ____|_ _ +// | \ / | __ _ __ _ _ ___ | |__ _ __ _ _ _ __ ___ | | _| |_ _| |_ +// | |\/| |/ _` |/ _` | |/ __| | __| | '_ \| | | | '_ ` _ \ | | |_ _|_ _| +// | | | | (_| | (_| | | (__ | |____| | | | |_| | | | | | | | |____|_| |_| +// |_| |_|\__,_|\__, |_|\___| |______|_| |_|\__,_|_| |_| |_| \_____| +// __/ | https://github.com/Neargye/magic_enum +// |___/ version 0.9.3 +// +// Licensed under the MIT License . +// SPDX-License-Identifier: MIT +// Copyright (c) 2019 - 2023 Daniil Goncharov . +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#ifndef NEARGYE_MAGIC_ENUM_FORMAT_HPP +#define NEARGYE_MAGIC_ENUM_FORMAT_HPP + +#include "magic_enum.hpp" +#include "magic_enum_flags.hpp" + +#if !defined(MAGIC_ENUM_DEFAULT_ENABLE_ENUM_FORMAT) +# define MAGIC_ENUM_DEFAULT_ENABLE_ENUM_FORMAT 1 +# define MAGIC_ENUM_DEFAULT_ENABLE_ENUM_FORMAT_AUTO_DEFINE +#endif + +namespace magic_enum::customize { + // customize enum to enable/disable automatic std::format + template + constexpr bool enum_format_enabled() noexcept { + return MAGIC_ENUM_DEFAULT_ENABLE_ENUM_FORMAT; + } +} // magic_enum::customize + +#if defined(__cpp_lib_format) + +#include + +template +struct std::formatter> && magic_enum::customize::enum_format_enabled(), char>> : std::formatter { + auto format(E e, format_context& ctx) const { + static_assert(std::is_same_v, "formatter requires string_view::value_type type same as char."); + using D = std::decay_t; + + if constexpr (magic_enum::detail::supported::value) { + if constexpr (magic_enum::detail::subtype_v == magic_enum::detail::enum_subtype::flags) { + if (const auto name = magic_enum::enum_flags_name(e); !name.empty()) { + return formatter::format(std::string_view{name.data(), name.size()}, ctx); + } + } else { + if (const auto name = magic_enum::enum_name(e); !name.empty()) { + return formatter::format(std::string_view{name.data(), name.size()}, ctx); + } + } + } + return formatter::format(std::to_string(magic_enum::enum_integer(e)), ctx); + } +}; + +#endif + +#if defined(FMT_VERSION) + +#include + +template +struct fmt::formatter> && magic_enum::customize::enum_format_enabled(), char>> : fmt::formatter { + auto format(E e, format_context& ctx) { + static_assert(std::is_same_v, "formatter requires string_view::value_type type same as char."); + using D = std::decay_t; + + if constexpr (magic_enum::detail::supported::value) { + if constexpr (magic_enum::detail::subtype_v == magic_enum::detail::enum_subtype::flags) { + if (const auto name = magic_enum::enum_flags_name(e); !name.empty()) { + return formatter::format(std::string_view{name.data(), name.size()}, ctx); + } + } else { + if (const auto name = magic_enum::enum_name(e); !name.empty()) { + return formatter::format(std::string_view{name.data(), name.size()}, ctx); + } + } + } + return formatter::format(std::to_string(magic_enum::enum_integer(e)), ctx); + } +}; + +#endif + +#if defined(MAGIC_ENUM_DEFAULT_ENABLE_ENUM_FORMAT_AUTO_DEFINE) +# undef MAGIC_ENUM_DEFAULT_ENABLE_ENUM_FORMAT +# undef MAGIC_ENUM_DEFAULT_ENABLE_ENUM_FORMAT_AUTO_DEFINE +#endif + +#endif // NEARGYE_MAGIC_ENUM_FORMAT_HPP diff --git a/src/3rd party/magic_enum/magic_enum_fuse.hpp b/src/3rd party/magic_enum/magic_enum_fuse.hpp new file mode 100644 index 0000000000..8773404f5c --- /dev/null +++ b/src/3rd party/magic_enum/magic_enum_fuse.hpp @@ -0,0 +1,98 @@ +// __ __ _ ______ _____ +// | \/ | (_) | ____| / ____|_ _ +// | \ / | __ _ __ _ _ ___ | |__ _ __ _ _ _ __ ___ | | _| |_ _| |_ +// | |\/| |/ _` |/ _` | |/ __| | __| | '_ \| | | | '_ ` _ \ | | |_ _|_ _| +// | | | | (_| | (_| | | (__ | |____| | | | |_| | | | | | | | |____|_| |_| +// |_| |_|\__,_|\__, |_|\___| |______|_| |_|\__,_|_| |_| |_| \_____| +// __/ | https://github.com/Neargye/magic_enum +// |___/ version 0.9.3 +// +// Licensed under the MIT License . +// SPDX-License-Identifier: MIT +// Copyright (c) 2019 - 2023 Daniil Goncharov . +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#ifndef NEARGYE_MAGIC_ENUM_FUSE_HPP +#define NEARGYE_MAGIC_ENUM_FUSE_HPP + +#include "magic_enum.hpp" + +namespace magic_enum { + +namespace detail { + +template +inline constexpr auto subtypes_v = subtype_v; + +template +constexpr optional fuse_one_enum(optional hash, E value) noexcept { + if (hash) { + if (const auto index = enum_index(value)) { + return (*hash << log2(enum_count() + 1)) | *index; + } + } + return {}; +} + +template +constexpr optional fuse_enum(E value) noexcept { + return fuse_one_enum(0, value); +} + +template +constexpr optional fuse_enum(E head, Es... tail) noexcept { + return fuse_one_enum(fuse_enum(tail...), head); +} + +template +constexpr auto typesafe_fuse_enum(Es... values) noexcept { + enum class enum_fuse_t : std::uintmax_t; + const auto fuse = fuse_enum(values...); + if (fuse) { + return optional{static_cast(*fuse)}; + } + return optional{}; +} + +} // namespace magic_enum::detail + +// Returns a bijective mix of several enum values. This can be used to emulate 2D switch/case statements. +template +[[nodiscard]] constexpr auto enum_fuse(Es... values) noexcept { + static_assert((std::is_enum_v> && ...), "magic_enum::enum_fuse requires enum type."); + static_assert(sizeof...(Es) >= 2, "magic_enum::enum_fuse requires at least 2 values."); + static_assert((detail::log2(enum_count, S>() + 1) + ...) <= (sizeof(std::uintmax_t) * 8), "magic_enum::enum_fuse does not work for large enums"); +#if defined(MAGIC_ENUM_NO_TYPESAFE_ENUM_FUSE) + const auto fuse = detail::fuse_enum...>(values...); +#else + const auto fuse = detail::typesafe_fuse_enum...>(values...); +#endif + return MAGIC_ENUM_ASSERT(fuse), fuse; +} + +// Returns a bijective mix of several enum values. This can be used to emulate 2D switch/case statements. +template +[[nodiscard]] constexpr auto enum_fuse(Es... values) noexcept { + return enum_fuse...>>(values...); +} + +} // namespace magic_enum + +#endif // NEARGYE_MAGIC_ENUM_FUSE_HPP diff --git a/src/3rd party/magic_enum/magic_enum_iostream.hpp b/src/3rd party/magic_enum/magic_enum_iostream.hpp new file mode 100644 index 0000000000..d2907bf81f --- /dev/null +++ b/src/3rd party/magic_enum/magic_enum_iostream.hpp @@ -0,0 +1,115 @@ +// __ __ _ ______ _____ +// | \/ | (_) | ____| / ____|_ _ +// | \ / | __ _ __ _ _ ___ | |__ _ __ _ _ _ __ ___ | | _| |_ _| |_ +// | |\/| |/ _` |/ _` | |/ __| | __| | '_ \| | | | '_ ` _ \ | | |_ _|_ _| +// | | | | (_| | (_| | | (__ | |____| | | | |_| | | | | | | | |____|_| |_| +// |_| |_|\__,_|\__, |_|\___| |______|_| |_|\__,_|_| |_| |_| \_____| +// __/ | https://github.com/Neargye/magic_enum +// |___/ version 0.9.3 +// +// Licensed under the MIT License . +// SPDX-License-Identifier: MIT +// Copyright (c) 2019 - 2023 Daniil Goncharov . +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#ifndef NEARGYE_MAGIC_ENUM_IOSTREAM_HPP +#define NEARGYE_MAGIC_ENUM_IOSTREAM_HPP + +#include "magic_enum.hpp" +#include "magic_enum_flags.hpp" + +#include + +namespace magic_enum { + +namespace ostream_operators { + +template = 0> +std::basic_ostream& operator<<(std::basic_ostream& os, E value) { + using D = std::decay_t; + using U = underlying_type_t; + + if constexpr (detail::supported::value) { + if constexpr (detail::subtype_v == detail::enum_subtype::flags) { + if (const auto name = enum_flags_name(value); !name.empty()) { + for (const auto c : name) { + os.put(c); + } + return os; + } + } else { + if (const auto name = enum_name(value); !name.empty()) { + for (const auto c : name) { + os.put(c); + } + return os; + } + } + } + return (os << static_cast(value)); +} + +template = 0> +std::basic_ostream& operator<<(std::basic_ostream& os, optional value) { + return value ? (os << *value) : os; +} + +} // namespace magic_enum::ostream_operators + +namespace istream_operators { + +template = 0> +std::basic_istream& operator>>(std::basic_istream& is, E& value) { + using D = std::decay_t; + + std::basic_string s; + is >> s; + if constexpr (detail::supported::value) { + if constexpr (detail::subtype_v == detail::enum_subtype::flags) { + if (const auto v = enum_flags_cast(s)) { + value = *v; + } else { + is.setstate(std::basic_ios::failbit); + } + } else { + if (const auto v = enum_cast(s)) { + value = *v; + } else { + is.setstate(std::basic_ios::failbit); + } + } + } else { + is.setstate(std::basic_ios::failbit); + } + return is; +} + +} // namespace magic_enum::istream_operators + +namespace iostream_operators { + +using namespace ostream_operators; +using namespace istream_operators; + +} // namespace magic_enum::iostream_operators + +} // namespace magic_enum + +#endif // NEARGYE_MAGIC_ENUM_IOSTREAM_HPP diff --git a/src/3rd party/magic_enum/magic_enum_switch.hpp b/src/3rd party/magic_enum/magic_enum_switch.hpp new file mode 100644 index 0000000000..e91a753375 --- /dev/null +++ b/src/3rd party/magic_enum/magic_enum_switch.hpp @@ -0,0 +1,202 @@ +// __ __ _ ______ _____ +// | \/ | (_) | ____| / ____|_ _ +// | \ / | __ _ __ _ _ ___ | |__ _ __ _ _ _ __ ___ | | _| |_ _| |_ +// | |\/| |/ _` |/ _` | |/ __| | __| | '_ \| | | | '_ ` _ \ | | |_ _|_ _| +// | | | | (_| | (_| | | (__ | |____| | | | |_| | | | | | | | |____|_| |_| +// |_| |_|\__,_|\__, |_|\___| |______|_| |_|\__,_|_| |_| |_| \_____| +// __/ | https://github.com/Neargye/magic_enum +// |___/ version 0.9.3 +// +// Licensed under the MIT License . +// SPDX-License-Identifier: MIT +// Copyright (c) 2019 - 2023 Daniil Goncharov . +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#ifndef NEARGYE_MAGIC_ENUM_SWITCH_HPP +#define NEARGYE_MAGIC_ENUM_SWITCH_HPP + +#include "magic_enum.hpp" + +namespace magic_enum { + +namespace detail { + +struct default_result_type {}; + +template +struct identity { + using type = T; +}; + +struct nonesuch {}; + +template > +struct invoke_result : identity {}; + +template +struct invoke_result : std::invoke_result {}; + +template +using invoke_result_t = typename invoke_result::type; + +template +constexpr auto common_invocable(std::index_sequence) noexcept { + static_assert(is_enum_v, "magic_enum::detail::invocable_index requires enum type."); + + if constexpr (count_v == 0) { + return identity{}; + } else { + return std::common_type[I]>>...>{}; + } +} + +template +constexpr auto result_type() noexcept { + static_assert(is_enum_v, "magic_enum::detail::result_type requires enum type."); + + constexpr auto seq = std::make_index_sequence>{}; + using R = typename decltype(common_invocable(seq))::type; + if constexpr (std::is_same_v) { + if constexpr (std::is_same_v) { + return identity{}; + } else { + return identity{}; + } + } else { + if constexpr (std::is_convertible_v) { + return identity{}; + } else if constexpr (std::is_convertible_v) { + return identity{}; + } else { + return identity{}; + } + } +} + +template , typename R = typename decltype(result_type())::type> +using result_t = std::enable_if_t && !std::is_same_v, R>; + +#if !defined(MAGIC_ENUM_ENABLE_HASH) && !defined(MAGIC_ENUM_ENABLE_HASH_SWITCH) + +template +inline constexpr auto default_result_type_lambda = []() noexcept(std::is_nothrow_default_constructible_v) { return T{}; }; + +template <> +inline constexpr auto default_result_type_lambda = []() noexcept {}; + +template +constexpr R invoke_r(F&& f, Args&&... args) noexcept(std::is_nothrow_invocable_r_v) { + if constexpr (std::is_void_v) { + std::forward(f)(std::forward(args)...); + } else { + return static_cast(std::forward(f)(std::forward(args)...)); + } +} + +template +constexpr decltype(auto) constexpr_switch_impl(F&& f, E value, Def&& def) { + if constexpr(I < End) { + constexpr auto v = enum_constant()>{}; + if (value == v) { + if constexpr (std::is_invocable_r_v) { + return invoke_r(std::forward(f), v); + } else { + return def(); + } + } else { + return constexpr_switch_impl(std::forward(f), value, std::forward(def)); + } + } else { + return def(); + } +} + +template +constexpr decltype(auto) constexpr_switch(F&& f, E value, Def&& def) { + static_assert(is_enum_v, "magic_enum::detail::constexpr_switch requires enum type."); + + if constexpr (count_v == 0) { + return def(); + } else { + return constexpr_switch_impl<0, count_v, R, E, S>(std::forward(f), value, std::forward(def)); + } +} +#endif + +} // namespace magic_enum::detail + +template , typename F, typename R = detail::result_t> +constexpr decltype(auto) enum_switch(F&& f, E value) { + using D = std::decay_t; + static_assert(std::is_enum_v, "magic_enum::enum_switch requires enum type."); + +#if defined(MAGIC_ENUM_ENABLE_HASH) || defined(MAGIC_ENUM_ENABLE_HASH_SWITCH) + return detail::constexpr_switch<&detail::values_v, detail::case_call_t::value>( + std::forward(f), + value, + detail::default_result_type_lambda); +#else + return detail::constexpr_switch( + std::forward(f), + value, + detail::default_result_type_lambda); +#endif +} + +template > +constexpr decltype(auto) enum_switch(F&& f, E value) { + return enum_switch(std::forward(f), value); +} + +template , typename F, typename R = detail::result_t> +constexpr decltype(auto) enum_switch(F&& f, E value, Result&& result) { + using D = std::decay_t; + static_assert(std::is_enum_v, "magic_enum::enum_switch requires enum type."); + +#if defined(MAGIC_ENUM_ENABLE_HASH) || defined(MAGIC_ENUM_ENABLE_HASH_SWITCH) + return detail::constexpr_switch<&detail::values_v, detail::case_call_t::value>( + std::forward(f), + value, + [&result]() -> R { return std::forward(result); }); +#else + return detail::constexpr_switch( + std::forward(f), + value, + [&result]() -> R { return std::forward(result); }); +#endif +} + +template > +constexpr decltype(auto) enum_switch(F&& f, E value, Result&& result) { + return enum_switch(std::forward(f), value, std::forward(result)); +} + +} // namespace magic_enum + +template <> +struct std::common_type : magic_enum::detail::identity {}; + +template +struct std::common_type : magic_enum::detail::identity {}; + +template +struct std::common_type : magic_enum::detail::identity {}; + +#endif // NEARGYE_MAGIC_ENUM_SWITCH_HPP diff --git a/src/3rd party/magic_enum/magic_enum_utility.hpp b/src/3rd party/magic_enum/magic_enum_utility.hpp new file mode 100644 index 0000000000..42f0ec1467 --- /dev/null +++ b/src/3rd party/magic_enum/magic_enum_utility.hpp @@ -0,0 +1,137 @@ +// __ __ _ ______ _____ +// | \/ | (_) | ____| / ____|_ _ +// | \ / | __ _ __ _ _ ___ | |__ _ __ _ _ _ __ ___ | | _| |_ _| |_ +// | |\/| |/ _` |/ _` | |/ __| | __| | '_ \| | | | '_ ` _ \ | | |_ _|_ _| +// | | | | (_| | (_| | | (__ | |____| | | | |_| | | | | | | | |____|_| |_| +// |_| |_|\__,_|\__, |_|\___| |______|_| |_|\__,_|_| |_| |_| \_____| +// __/ | https://github.com/Neargye/magic_enum +// |___/ version 0.9.3 +// +// Licensed under the MIT License . +// SPDX-License-Identifier: MIT +// Copyright (c) 2019 - 2023 Daniil Goncharov . +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#ifndef NEARGYE_MAGIC_ENUM_UTILITY_HPP +#define NEARGYE_MAGIC_ENUM_UTILITY_HPP + +#include "magic_enum.hpp" + +namespace magic_enum { + +namespace detail { + +template +constexpr auto for_each(F&& f, std::index_sequence) { + constexpr bool has_void_return = (std::is_void_v[I]>>> || ...); + constexpr bool all_same_return = (std::is_same_v[0]>>, std::invoke_result_t[I]>>> && ...); + + if constexpr (has_void_return) { + (f(enum_constant[I]>{}), ...); + } else if constexpr (all_same_return) { + return std::array{f(enum_constant[I]>{})...}; + } else { + return std::tuple{f(enum_constant[I]>{})...}; + } +} + +template +constexpr bool all_invocable(std::index_sequence) { + if constexpr (count_v == 0) { + return false; + } else { + return (std::is_invocable_v[I]>> && ...); + } +} + +} // namespace magic_enum::detail + +template , typename F, detail::enable_if_t = 0> +constexpr auto enum_for_each(F&& f) { + using D = std::decay_t; + static_assert(std::is_enum_v, "magic_enum::enum_for_each requires enum type."); + constexpr auto sep = std::make_index_sequence>{}; + + if constexpr (detail::all_invocable(sep)) { + return detail::for_each(std::forward(f), sep); + } else { + static_assert(detail::always_false_v, "magic_enum::enum_for_each requires invocable of all enum value."); + } +} + +template > +[[nodiscard]] constexpr auto enum_next_value(E value, std::ptrdiff_t n = 1) noexcept -> detail::enable_if_t>> { + using D = std::decay_t; + constexpr std::ptrdiff_t count = detail::count_v; + + if (const auto i = enum_index(value)) { + const std::ptrdiff_t index = (static_cast(*i) + n); + if (index >= 0 && index < count) { + return enum_value(index); + } + } + return {}; +} + +template > +[[nodiscard]] constexpr auto enum_next_value_circular(E value, std::ptrdiff_t n = 1) noexcept -> detail::enable_if_t> { + using D = std::decay_t; + constexpr std::ptrdiff_t count = detail::count_v; + + if (const auto i = enum_index(value)) { + const std::ptrdiff_t index = ((((static_cast(*i) + n) % count) + count) % count); + if (index >= 0 && index < count) { + return enum_value(index); + } + } + return MAGIC_ENUM_ASSERT(false), value; +} + +template > +[[nodiscard]] constexpr auto enum_prev_value(E value, std::ptrdiff_t n = 1) noexcept -> detail::enable_if_t>> { + using D = std::decay_t; + constexpr std::ptrdiff_t count = detail::count_v; + + if (const auto i = enum_index(value)) { + const std::ptrdiff_t index = (static_cast(*i) - n); + if (index >= 0 && index < count) { + return enum_value(index); + } + } + return {}; +} + +template > +[[nodiscard]] constexpr auto enum_prev_value_circular(E value, std::ptrdiff_t n = 1) noexcept -> detail::enable_if_t> { + using D = std::decay_t; + constexpr std::ptrdiff_t count = detail::count_v; + + if (const auto i = enum_index(value)) { + const std::ptrdiff_t index = ((((static_cast(*i) - n) % count) + count) % count); + if (index >= 0 && index < count) { + return enum_value(index); + } + } + return MAGIC_ENUM_ASSERT(false), value; +} + +} // namespace magic_enum + +#endif // NEARGYE_MAGIC_ENUM_UTILITY_HPP diff --git a/src/3rd party/ode/contrib/msvc7/ode_default/default.vcxproj b/src/3rd party/ode/contrib/msvc7/ode_default/default.vcxproj index 9f4deebb0e..434af92add 100644 --- a/src/3rd party/ode/contrib/msvc7/ode_default/default.vcxproj +++ b/src/3rd party/ode/contrib/msvc7/ode_default/default.vcxproj @@ -13,6 +13,10 @@ Release x64 + + VerifiedDX11ASAN + x64 + VerifiedDX11 x64 @@ -59,6 +63,15 @@ false x64 + + StaticLibrary + v143 + false + MultiByte + false + x64 + true + StaticLibrary false @@ -89,6 +102,11 @@ + + + + + @@ -126,6 +144,13 @@ $(xrGameDir)bin_dbg\$(Platform)\$(Configuration)\ $(xrIntDir)$(ProjectName)\ + + true + false + false + $(xrGameDir)bin_dbg\$(Platform)\$(Configuration)\ + $(xrIntDir)$(ProjectName)\ + true false @@ -334,6 +359,57 @@ regsvr32 /s /c "$(TargetPath)" + + + NDEBUG;%(PreprocessorDefinitions) + false + true + $(IntDir)default.tlb + default.h + + + default_i.c + default_p.c + + + Disabled + false + Neither + false + false + ../../../include;%(AdditionalIncludeDirectories) + _DISABLE_VECTOR_ANNOTATION;_DISABLE_STRING_ANNOTATION;USE_VERIFY_IN_RELEASE;WIN32;_WINDOWS;NDEBUG;dSINGLE;MSVC;dNODEBUG;_SECURE_SCL=0;%(PreprocessorDefinitions) + NotSet + ProgramDatabase + 4100;4505;%(DisableSpecificWarnings) + Level3 + false + Disabled + false + stdcpp17 + true + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + $(IntDir);%(AdditionalIncludeDirectories) + + + ../../config/msvcdefs.def + true + Windows + true + true + true + Default + false + $(xrLibDir)$(TargetName).lib + + + Performing registration + regsvr32 /s /c "$(TargetPath)" + + NDEBUG;%(PreprocessorDefinitions) @@ -440,6 +516,7 @@ 4244;%(DisableSpecificWarnings) 4244;%(DisableSpecificWarnings) 4244;%(DisableSpecificWarnings) + 4244;%(DisableSpecificWarnings) 4244;%(DisableSpecificWarnings) @@ -448,6 +525,7 @@ 4244;%(DisableSpecificWarnings) 4244;%(DisableSpecificWarnings) 4244;%(DisableSpecificWarnings) + 4244;%(DisableSpecificWarnings) 4244;%(DisableSpecificWarnings) diff --git a/src/3rd party/ode/ode/src/step.cpp b/src/3rd party/ode/ode/src/step.cpp index 14f14884c7..ab1a8570de 100644 --- a/src/3rd party/ode/ode/src/step.cpp +++ b/src/3rd party/ode/ode/src/step.cpp @@ -745,16 +745,17 @@ void dInternalStepIsland_x2 (dxWorld *world, dxBody * const *body, int nb, // get joint numbers and ensure ofs[j1] >= ofs[j2] int j1 = n1->joint->tag; int j2 = n2->joint->tag; + + // if either joint was tagged as -1 then it is an inactive (m=0) + // joint that should not be considered + if (j1==-1 || j2==-1) continue; + if (ofs[j1] < ofs[j2]) { int tmp = j1; j1 = j2; j2 = tmp; } - // if either joint was tagged as -1 then it is an inactive (m=0) - // joint that should not be considered - if (j1==-1 || j2==-1) continue; - // determine if body i is the 1st or 2nd body of joints j1 and j2 int jb1 = (joint[j1]->node[1].body == body[i]); int jb2 = (joint[j2]->node[1].body == body[i]); @@ -811,11 +812,16 @@ void dInternalStepIsland_x2 (dxWorld *world, dxBody * const *body, int nb, //dSetZero (rhs,m); for (i=0; inode[0].body->tag, info[i].m); - if (joint[i]->node[1].body) { - MultiplyAdd0_p81 (rhs+ofs[i],JJ + 8*info[i].m, - tmp1 + 8*joint[i]->node[1].body->tag, info[i].m); + + if (joint[i]->node[0].body) + { + Multiply0_p81(rhs + ofs[i], JJ, + tmp1 + 8 * joint[i]->node[0].body->tag, info[i].m); + } + if (joint[i]->node[1].body) + { + MultiplyAdd0_p81(rhs + ofs[i], JJ + 8 * info[i].m, + tmp1 + 8 * joint[i]->node[1].body->tag, info[i].m); } } // complete rhs diff --git a/src/3rd party/optick/optick.vcxproj b/src/3rd party/optick/optick.vcxproj index 1efcf7b6ce..1af68a7b67 100644 --- a/src/3rd party/optick/optick.vcxproj +++ b/src/3rd party/optick/optick.vcxproj @@ -25,6 +25,14 @@ Release x64 + + VerifiedDX11ASAN + Win32 + + + VerifiedDX11ASAN + x64 + Verified Win32 @@ -122,9 +130,19 @@ Unicode x64 + + v143 + StaticLibrary + Unicode + x64 + true + v143 + + v143 + @@ -158,6 +176,10 @@ + + + + $(IncludePath) @@ -183,6 +205,12 @@ $(xrGameDir)bin_dbg\$(Platform)\$(Configuration)\ $(xrIntDir)$(ProjectName)\ + + $(IncludePath) + $(xrGameDir)bin_dbg\$(Platform)\$(Configuration)\;$(LibraryPath) + $(xrGameDir)bin_dbg\$(Platform)\$(Configuration)\ + $(xrIntDir)$(ProjectName)\ + Level3 @@ -333,6 +361,22 @@ stdcpp17 + + + $(SolutionDir)3rd party\optick-git\src\;%(AdditionalIncludeDirectories) + Level3 + true + Disabled + Disabled + false + _DISABLE_VECTOR_ANNOTATION;_DISABLE_STRING_ANNOTATION;USE_VERIFY_IN_RELEASE;OPTICK_ENABLE_GPU_VULKAN=0;DEBUG;_LIB;_DISABLE_CONSTEXPR_MUTEX_CONSTRUCTOR;%(PreprocessorDefinitions) + true + USE_LUAJIT_ONE + true + stdcpp17 + ProgramDatabase + + diff --git a/src/Include/xrRender/Kinematics.h b/src/Include/xrRender/Kinematics.h index 6888a48b93..9d232618db 100644 --- a/src/Include/xrRender/Kinematics.h +++ b/src/Include/xrRender/Kinematics.h @@ -3,6 +3,7 @@ #pragma once #include "RenderVisual.h" +#include "../../xrCore/intrusive_ptr.h" typedef void (* UpdateCallback)(IKinematics* P); @@ -14,12 +15,15 @@ class ISpatial; class CBoneInstance; struct SEnumVerticesCallback; +using ISpatialShared = intrusive_ptr; + // 10 fps #define UCalc_Interval (u32(100)) class IKinematics { public: + xrCriticalSection UCalc_Mutex; typedef xr_vector> accel; struct pick_result @@ -32,7 +36,7 @@ class IKinematics public: #ifdef OPTIMIZE_CALCULATE_BONES - ISpatial* spatialParent = nullptr; + ISpatialShared spatialParent = nullptr; #endif virtual void Bone_Calculate(CBoneData* bd, Fmatrix* parent) = 0; @@ -60,7 +64,13 @@ class IKinematics virtual u16 LL_VisibleBoneCount() = 0; virtual ICF Fmatrix& _BCL LL_GetTransform(u16 bone_id) = 0; + virtual ICF Fmatrix& _BCL LL_GetTransform_safed(u16 bone_id) = 0; virtual ICF const Fmatrix& _BCL LL_GetTransform(u16 bone_id) const = 0; + virtual ICF void _BCL LL_GetBoneLocalPosition(u16 bone_id, Fvector& result) {} + virtual ICF void _BCL LL_GetBoneLocalTransform(u16 bone_id, Fmatrix& result) {} + virtual ICF void _BCL LL_GetBoneWorldPosition(u16 bone_id, const Fmatrix& xform, Fvector& result) {} + virtual ICF void _BCL LL_GetBoneWorldTransform(u16 bone_id, const Fmatrix& xform, Fmatrix& result) {} + virtual ICF void _BCL CalculateBBox(BOOL bforce = TRUE) {} virtual ICF Fmatrix& LL_GetTransform_R(u16 bone_id) = 0; virtual Fobb& LL_GetBox(u16 bone_id) = 0; @@ -101,8 +111,8 @@ class IKinematics // debug #ifdef DEBUG virtual void DebugRender (Fmatrix& XFORM) = 0; - virtual shared_str _BCL getDebugName () = 0; #endif + virtual shared_str getDebugName() = 0; }; IC IKinematics* PKinematics(IRenderVisual* V) { return V ? V->dcast_PKinematics() : 0; } diff --git a/src/Include/xrRender/KinematicsAnimated.h b/src/Include/xrRender/KinematicsAnimated.h index f9ecb333f1..2c8a28f9b2 100644 --- a/src/Include/xrRender/KinematicsAnimated.h +++ b/src/Include/xrRender/KinematicsAnimated.h @@ -105,6 +105,7 @@ class IKinematicsAnimated virtual MotionID ID_FX_Safe(LPCSTR N) = 0; virtual CBlend* PlayFX(LPCSTR N, float power_scale) = 0; virtual CBlend* PlayFX(MotionID M, float power_scale) = 0; + virtual CBlend* PlayFX_Safe (LPCSTR N, float power_scale) = 0; virtual const CPartition& partitions() const = 0; diff --git a/src/Include/xrRender/ParticleCustom.h b/src/Include/xrRender/ParticleCustom.h index 898c723367..12d270edc2 100644 --- a/src/Include/xrRender/ParticleCustom.h +++ b/src/Include/xrRender/ParticleCustom.h @@ -25,6 +25,8 @@ class IParticleCustom virtual const shared_str Name() =0; virtual void SetHudMode(BOOL b) =0; virtual BOOL GetHudMode() =0; + virtual void SetLiveUpdate(BOOL b) =0; + virtual BOOL GetLiveUpdate() =0; }; #endif // ParticleCustom_included diff --git a/src/Include/xrRender/RenderVisual.h b/src/Include/xrRender/RenderVisual.h index 80e4a2c866..90f764c4d6 100644 --- a/src/Include/xrRender/RenderVisual.h +++ b/src/Include/xrRender/RenderVisual.h @@ -9,7 +9,7 @@ struct vis_data; enum IRenderVisualFlags { - eIgnoreOptimization = (1 << 0), + eIgnoreOptimization = (1 << 0), // Used for geometry culling optimization eNoShadow = (1 << 1), }; @@ -28,7 +28,7 @@ class IRenderVisual Flags16 flags; #ifdef DEBUG - virtual shared_str _BCL getDebugName() = 0; + virtual shared_str getDebugName() = 0; #endif virtual u32 _BCL getID() { return 1; } virtual LPCSTR _BCL getDebugShader() { return nullptr; } @@ -44,6 +44,20 @@ class IRenderVisual virtual void ResetShaderTexture() {}; virtual void MarkAsHot(bool is_hot) {}; //--DSR-- HeatVision virtual void MarkAsGlowing(bool is_glowing) {}; //--DSR-- SilencerOverheat + virtual void MarkIgnoreOptimization(BOOL value) + { + flags.set(IRenderVisualFlags::eIgnoreOptimization, value); + xr_vector* children = get_children(); + if (children) + { + for (auto it = children->begin(); it != children->end(); it++) + { + IRenderVisual* v = *it; + if (v) + v->MarkIgnoreOptimization(value); + } + } + } virtual IRenderVisual* _BCL dcast_RenderVisual() { return this; } virtual IKinematics* _BCL dcast_PKinematics() { return 0; } diff --git a/src/Include/xrRender/particles_systems_library_interface.hpp b/src/Include/xrRender/particles_systems_library_interface.hpp index 7a74c0f6ae..ba3165d783 100644 --- a/src/Include/xrRender/particles_systems_library_interface.hpp +++ b/src/Include/xrRender/particles_systems_library_interface.hpp @@ -23,6 +23,7 @@ namespace particles_systems virtual PS::CPGDef const* const* particles_group_end() const = 0; virtual void particles_group_next(PS::CPGDef const* const*& iterator) const = 0; virtual shared_str const& particles_group_id(PS::CPGDef const& particles_group) const = 0; + virtual xr_vector const& vec_all_particles() const = 0; }; // class library_interface } // namespace particles_systems diff --git a/src/Layers/xrAPI/xrAPI.vcxproj b/src/Layers/xrAPI/xrAPI.vcxproj index ddb0838fc8..88a801010e 100644 --- a/src/Layers/xrAPI/xrAPI.vcxproj +++ b/src/Layers/xrAPI/xrAPI.vcxproj @@ -13,6 +13,10 @@ Release x64 + + VerifiedDX11ASAN + x64 + VerifiedDX11 x64 @@ -57,6 +61,14 @@ false x64 + + StaticLibrary + v143 + Unicode + false + x64 + true + StaticLibrary v143 @@ -83,6 +95,10 @@ + + + + @@ -111,6 +127,11 @@ $(xrGameDir)bin_dbg\$(Platform)\$(Configuration)\ $(xrIntDir)$(ProjectName)\ + + false + $(xrGameDir)bin_dbg\$(Platform)\$(Configuration)\ + $(xrIntDir)$(ProjectName)\ + false $(xrGameDir)bin_dbg\$(Platform)\$(Configuration)\ @@ -179,7 +200,7 @@ Neither false false - USE_VERIFY_IN_RELEASE;WIN32;NDEBUG;_WINDOWS;_USRDLL;XRAPI_EXPORTS;%(PreprocessorDefinitions) + XRCORE_PROFILER;USE_VERIFY_IN_RELEASE;WIN32;NDEBUG;_WINDOWS;_USRDLL;XRAPI_EXPORTS;%(PreprocessorDefinitions) NotSet Use EditAndContinue @@ -211,7 +232,7 @@ Neither false false - USE_VERIFY_IN_RELEASE;WIN32;NDEBUG;_WINDOWS;_USRDLL;XRAPI_EXPORTS;%(PreprocessorDefinitions) + XRCORE_PROFILER;USE_VERIFY_IN_RELEASE;WIN32;NDEBUG;_WINDOWS;_USRDLL;XRAPI_EXPORTS;%(PreprocessorDefinitions) NotSet Use EditAndContinue @@ -236,6 +257,38 @@ Default + + + Disabled + false + Neither + false + false + XRCORE_PROFILER;_DISABLE_VECTOR_ANNOTATION;_DISABLE_STRING_ANNOTATION;USE_VERIFY_IN_RELEASE;WIN32;NDEBUG;_WINDOWS;_USRDLL;XRAPI_EXPORTS;%(PreprocessorDefinitions) + NotSet + Use + ProgramDatabase + USE_LUAJIT_ONE + Disabled + false + true + Level4 + false + MultiThreadedDLL + false + stdcpp17 + true + + + Windows + true + true + false + $(xrLibDir)$(TargetName).lib + true + Default + + WIN32;NDEBUG;_WINDOWS;_USRDLL;XRAPI_EXPORTS;%(PreprocessorDefinitions) @@ -271,6 +324,7 @@ Create Create Create + Create Create diff --git a/src/Layers/xrRender/CHudInitializer.cpp b/src/Layers/xrRender/CHudInitializer.cpp new file mode 100644 index 0000000000..facf7cb86e --- /dev/null +++ b/src/Layers/xrRender/CHudInitializer.cpp @@ -0,0 +1,73 @@ +#include "stdafx.h" + +#include "CHudInitializer.h" + +void CHudInitializer::set(int setup) +{ + b_auto_setup = setup; + + mView_saved = Device.mView; + mProject_saved = Device.mProject; + mFullTransform_saved = Device.mFullTransform; +} + +CHudInitializer::CHudInitializer(bool setup) +{ + set(setup); + if (!b_auto_setup) return; + + SetHudMode(); +} + +CHudInitializer::CHudInitializer(int setup) +{ + set(setup); + if (!b_auto_setup) return; + + switch (b_auto_setup) + { + case 1: + SetHudMode(); + break; + case 2: + SetCamMode(); + break; + } +} + +CHudInitializer::~CHudInitializer() +{ + if (!b_auto_setup) return; + + SetDefaultMode(); +} + +void CHudInitializer::SetHudMode() +{ + Device.mView.set(Device.mViewHud); + Device.mProject.set(Device.mProjectHud); + Device.mFullTransform.set(Device.mFullTransformHud); + + Device.m_pRender->SetCacheXform(Device.mView, Device.mProject); + Device.m_pRender->SetCacheXform_prev(Device.mViewHud_prev, Device.mProjectHud_prev); +} + +void CHudInitializer::SetCamMode() +{ + Device.mView.set(Device.mViewCam); + Device.mProject.set(Device.mProjectCam); + Device.mFullTransform.set(Device.mFullTransformCam); + + Device.m_pRender->SetCacheXform(Device.mView, Device.mProject); + Device.m_pRender->SetCacheXform_prev(Device.mViewCam_prev, Device.mProjectCam_prev); +} + +void CHudInitializer::SetDefaultMode() +{ + Device.mView.set(mView_saved); + Device.mProject.set(mProject_saved); + Device.mFullTransform.set(mFullTransform_saved); + + Device.m_pRender->SetCacheXform(Device.mView, Device.mProject); + Device.m_pRender->SetCacheXform_prev(Device.mView_prev, Device.mProject_prev); +} diff --git a/src/Layers/xrRender/CHudInitializer.h b/src/Layers/xrRender/CHudInitializer.h new file mode 100644 index 0000000000..fe760d35ce --- /dev/null +++ b/src/Layers/xrRender/CHudInitializer.h @@ -0,0 +1,18 @@ +#pragma once + +class CHudInitializer { +public: + CHudInitializer(bool setup); + CHudInitializer(int setup); + ~CHudInitializer(); + + void SetHudMode(); + void SetCamMode(); + void SetDefaultMode(); +private: + void set(int); + int b_auto_setup; + Fmatrix mView_saved; + Fmatrix mProject_saved; + Fmatrix mFullTransform_saved; +}; diff --git a/src/Layers/xrRender/D3DUtils.h b/src/Layers/xrRender/D3DUtils.h index ef169601db..65337a4325 100644 --- a/src/Layers/xrRender/D3DUtils.h +++ b/src/Layers/xrRender/D3DUtils.h @@ -22,7 +22,7 @@ struct SPrimitiveBuffer u32 i_cnt; D3DPRIMITIVETYPE p_type; u32 p_cnt; - typedef fastdelegate::FastDelegate0<> TOnRender; + typedef xr_delegate TOnRender; TOnRender OnRender; void xr_stdcall RenderDIP() diff --git a/src/Layers/xrRender/DetailManager.cpp b/src/Layers/xrRender/DetailManager.cpp index 7e875844ac..4737e4bec9 100644 --- a/src/Layers/xrRender/DetailManager.cpp +++ b/src/Layers/xrRender/DetailManager.cpp @@ -8,6 +8,8 @@ #include "DetailManager.h" #include "cl_intersect.h" +#include "../../xrCore/profiler.h" + #ifdef _EDITOR # include "ESceneClassList.h" # include "Scene.h" @@ -90,6 +92,9 @@ CDetailManager::CDetailManager() m_time_pos = 0; m_global_time_old = 0; + m_frame_calc = 0; + m_frame_rendered.store(0, std::memory_order_relaxed); + #ifdef DETAIL_RADIUS // KD: variable detail radius dm_size = dm_current_size; @@ -252,10 +257,21 @@ void CDetailManager::Load() swing_desc[1].rot1 = pSettings->r_float("details", "swing_fast_rot1"); swing_desc[1].rot2 = pSettings->r_float("details", "swing_fast_rot2"); swing_desc[1].speed = pSettings->r_float("details", "swing_fast_speed"); + + if (ps_r2_ls_flags.test(R2FLAG_EXP_MT_CALC)) + { + // MT-details (@front) + Device.seqParallelRender.push_back(xr_make_delegate(this, &CDetailManager::MT_CALC)); + } } #endif void CDetailManager::Unload() { + auto I = std::find(Device.seqParallelRender.begin(), Device.seqParallelRender.end(), xr_make_delegate(this, &CDetailManager::MT_CALC)); + + if (I != Device.seqParallelRender.end()) + Device.seqParallelRender.erase(I); + if (UseVS()) hw_Unload(); else soft_Unload(); @@ -274,7 +290,8 @@ void CDetailManager::Unload() } extern ECORE_API float r_ssaDISCARD; - +extern float ps_r__ssaDISCARD_exp; +extern float ps_r__ssaDISCARD_fade_k; void CDetailManager::UpdateVisibleM() { Fvector EYE = RDEVICE.vCameraPosition_saved; @@ -292,6 +309,7 @@ void CDetailManager::UpdateVisibleM() fade_start = fade_start * fade_start; float fade_range = fade_limit - fade_start; float r_ssaCHEAP = 16 * r_ssaDISCARD; + float fade_start_ssa = r_ssaDISCARD * ps_r__ssaDISCARD_fade_k; // Initialize 'vis' and 'cache' // Collect objects for rendering @@ -360,7 +378,12 @@ void CDetailManager::UpdateVisibleM() float alpha_i = 1.f - alpha; float dist_sq_rcp = 1.f / dist_sq; - S.frame = RDEVICE.dwFrame + Random.randI(15, 30); + if(ps_r2_ls_flags.test(R2FLAG_FAST_DETAILS_UPDATE)) + S.frame = RDEVICE.dwFrame+1; + else + S.frame = RDEVICE.dwFrame+Random.randI(15,30); + + u32 slot_hash = GetFvectorHash(S.vis.sphere.P); for (int sp_id = 0; sp_id < dm_obj_in_slot; sp_id++) { SlotPart& sp = S.G[sp_id]; @@ -378,17 +401,49 @@ void CDetailManager::UpdateVisibleM() { SlotItem& Item = *(*siIT); float scale = psDeviceFlags2.test(rsNoScale) - ? (Item.scale_calculated = Item.scale) - : (Item.scale_calculated = Item.scale * alpha_i); + ? (Item.scale) + : (Item.scale * alpha_i); float ssa = psDeviceFlags2.test(rsNoScale) ? scale : scale * scale * Rq_drcp; if (ssa < r_ssaDISCARD) { Item.alpha_target = 0; continue; } + + // demonized: same logic as in r_dsgraph_insert_static + if (ssa < fade_start_ssa) + { + // Base probability of survival + float survival_chance = (ssa - r_ssaDISCARD) / (fade_start_ssa - r_ssaDISCARD); + + // Get the index of this specific grass blade inside the slot + u32 item_index = (u32)(siIT - &(*sp.items.begin())); + + // Mix the Slot's world position with the Item's index using a prime multiplier + // This ensures every blade of grass in the level has a unique, stable seed + u32 blade_hash = slot_hash ^ (item_index * 0x9E3779B9u); + + // Convert to [0.0, 1.0) float + constexpr float hash_to_float = 1.0f / 4294967296.0f; + float val = blade_hash * hash_to_float; + + // If the object's hash value is higher than its survival chance, cull it + if (val > _powf(survival_chance, ps_r__ssaDISCARD_exp)) + { + Item.alpha_target = 0; + continue; + } + } + u32 vis_id = 0; if (ssa > r_ssaCHEAP) vis_id = Item.vis_ID; + Fmatrix& M = Item.mRotY_calculated; + M = Item.mRotY; + M._11*=scale; M._21*=scale; M._31*=scale; + M._12*=scale; M._22*=scale; M._32*=scale; + M._13*=scale; M._23*=scale; M._33*=scale; + sp.r_items[vis_id].push_back(*siIT); if (S.hidden) @@ -428,13 +483,16 @@ void CDetailManager::UpdateVisibleM() void CDetailManager::Render() { + PROF_EVENT("Render details"); + #ifndef _EDITOR if (0 == dtFS) return; if (!psDeviceFlags.is(rsDetails)) return; #endif - // MT - MT_SYNC(); + // Always ensure per-frame detail visibility/cache are prepared before drawing. + // In MT mode this acts as a synchronization point with the worker task. + MT_CALC(); RDEVICE.Statistic->RenderDUMP_DT_Render.Begin(); g_pGamePersistent->m_pGShaderConstants->m_blender_mode.w = 1.0f; //--#SM+#-- Флaa нaчaлa ?aндa?a o?aвu [begin of grass render] @@ -455,12 +513,12 @@ void CDetailManager::Render() g_pGamePersistent->m_pGShaderConstants->m_blender_mode.w = 0.0f; //--#SM+#-- Флaa eонцa ?aндa?a o?aвu [end of grass render] RDEVICE.Statistic->RenderDUMP_DT_Render.End(); - m_frame_rendered = RDEVICE.dwFrame; + m_frame_rendered.store(RDEVICE.dwFrame, std::memory_order_release); } void __stdcall CDetailManager::MT_CALC() { - if (!this || !MT.IsValid()) return; // DIIIRTY HACK !!! + PROF_EVENT("MT_CALC details"); #ifndef _EDITOR if (0 == RImplementation.Details) return; // possibly deleted @@ -468,27 +526,31 @@ void __stdcall CDetailManager::MT_CALC() if (!psDeviceFlags.is(rsDetails)) return; #endif - MT.Enter(); - if (m_frame_calc != RDEVICE.dwFrame) - if ((m_frame_rendered + 1) == RDEVICE.dwFrame) //already rendered - { - Fvector EYE = RDEVICE.vCameraPosition_saved; + xrCriticalSectionGuard guard(m_mt_calc_guard); + const u32 current_frame = RDEVICE.dwFrame; + const u32 frame_calc = m_frame_calc; + const u32 frame_rendered = m_frame_rendered.load(std::memory_order_acquire); - int s_x = iFloor(EYE.x / dm_slot_size + .5f); - int s_z = iFloor(EYE.z / dm_slot_size + .5f); + if (frame_calc != current_frame && (frame_rendered + 1) == current_frame) + { + Fvector EYE = RDEVICE.vCameraPosition_saved; - RDEVICE.Statistic->RenderDUMP_DT_Cache.Begin(); - cache_Update(s_x, s_z, EYE, dm_max_decompress); - RDEVICE.Statistic->RenderDUMP_DT_Cache.End(); + int s_x = iFloor(EYE.x / dm_slot_size + .5f); + int s_z = iFloor(EYE.z / dm_slot_size + .5f); - UpdateVisibleM(); - m_frame_calc = RDEVICE.dwFrame; - } - MT.Leave(); + RDEVICE.Statistic->RenderDUMP_DT_Cache.Begin(); + cache_Update(s_x, s_z, EYE, dm_max_decompress); + RDEVICE.Statistic->RenderDUMP_DT_Cache.End(); + + UpdateVisibleM(); + m_frame_calc = current_frame; + } } void CDetailManager::details_clear() { + PROF_EVENT("details_clear"); + // Disable fade, next render will be scene fade_distance = 99999; diff --git a/src/Layers/xrRender/DetailManager.h b/src/Layers/xrRender/DetailManager.h index 5149dbd708..cf14153eb0 100644 --- a/src/Layers/xrRender/DetailManager.h +++ b/src/Layers/xrRender/DetailManager.h @@ -9,6 +9,7 @@ #include "../../xrCore/xrpool.h" #include "detailformat.h" #include "detailmodel.h" +#include "light.h" #ifdef _EDITOR //. #include "ESceneClassList.h" @@ -74,8 +75,8 @@ class ECORE_API CDetailManager { // один кустик float scale; - float scale_calculated; Fmatrix mRotY; + Fmatrix mRotY_calculated; u32 vis_ID; // индекс в visibility списке он же тип [не качается, качается1, качается2] float c_hemi; float c_sun; @@ -238,11 +239,11 @@ class ECORE_API CDetailManager void hw_Load_Geom(); void hw_Load_Shaders(); void hw_Unload(); - void hw_Render(); + void hw_Render(light* L = nullptr); #if defined(USE_DX10) || defined(USE_DX11) - void hw_Render_dump(const Fvector4 &consts, const Fvector4 &wave, const Fvector4 &wind, const Fvector4& prev_wave, const Fvector4& prev_wind, u32 var_id, u32 lod_id); + void hw_Render_dump(const Fvector4 &consts, const Fvector4 &wave, const Fvector4 &wind, const Fvector4& prev_wave, const Fvector4& prev_wind, u32 var_id, u32 lod_id, light* L = nullptr); #else // USE_DX10 - void hw_Render_dump(ref_constant array, u32 var_id, u32 lod_id, u32 c_base); + void hw_Render_dump(ref_constant array, u32 var_id, u32 lod_id, u32 c_base, light* L = nullptr); #endif // USE_DX10 public: @@ -267,18 +268,10 @@ class ECORE_API CDetailManager void Render(); /// MT stuff - xrCriticalSection MT; - volatile u32 m_frame_calc; - volatile u32 m_frame_rendered; - + u32 m_frame_calc; + xr_atomic_u32 m_frame_rendered; + xrCriticalSection m_mt_calc_guard; void __stdcall MT_CALC(); - ICF void MT_SYNC() - { - if (m_frame_calc == RDEVICE.dwFrame) - return; - - MT_CALC(); - } CDetailManager(); virtual ~CDetailManager(); diff --git a/src/Layers/xrRender/DetailManager_CACHE.cpp b/src/Layers/xrRender/DetailManager_CACHE.cpp index 8aab53a345..c4a3d6231d 100644 --- a/src/Layers/xrRender/DetailManager_CACHE.cpp +++ b/src/Layers/xrRender/DetailManager_CACHE.cpp @@ -157,47 +157,59 @@ void CDetailManager::cache_Update(int v_x, int v_z, Fvector& view, int limit) } // Task performer - BOOL bFullUnpack = FALSE; - if (cache_task.size() == dm_cache_size) + if(ps_r2_ls_flags.test(R2FLAG_FAST_DETAILS_UPDATE)) { - limit = dm_cache_size; - bFullUnpack = TRUE; + for (u32 iteration=0; iterationtype); - // Estimate - Fvector C; - S->vis.box.getcenter(C); - float D = view.distance_to_sqr(C); + for (int iteration = 0; cache_task.size() && (iteration < limit); iteration++) + { + u32 best_id = 0; + float best_dist = flt_max; - // Select - if (D < best_dist) + if (bFullUnpack) + { + best_id = cache_task.size() - 1; + } + else + { + for (u32 entry = 0; entry < cache_task.size(); entry++) { - best_dist = D; - best_id = entry; + // Gain access to data + Slot* S = cache_task[entry]; + VERIFY(stPending == S->type); + + // Estimate + Fvector C; + S->vis.box.getcenter(C); + float D = view.distance_to_sqr(C); + + // Select + if (D < best_dist) + { + best_dist = D; + best_id = entry; + } } } - } - // Decompress and remove task - cache_Decompress(cache_task[best_id]); - cache_task.erase(best_id); + // Decompress and remove task + cache_Decompress(cache_task[best_id]); + cache_task.erase(best_id); + } } if (bNeedMegaUpdate) diff --git a/src/Layers/xrRender/DetailManager_Decompress.cpp b/src/Layers/xrRender/DetailManager_Decompress.cpp index 40452d3188..1e3975b086 100644 --- a/src/Layers/xrRender/DetailManager_Decompress.cpp +++ b/src/Layers/xrRender/DetailManager_Decompress.cpp @@ -202,6 +202,7 @@ void CDetailManager::cache_Decompress(Slot* S) Fvector3 terrain_normal; float r_u, r_v, r_range; + bool no_push = false; for (u32 tid = 0; tid < triCount; tid++) { #ifdef _EDITOR @@ -223,9 +224,21 @@ RDEVICE.Statistic->TEST0.End (); #else CDB::TRI& T = tris[xrc.r_begin()[tid].id]; SGameMtl* mtl = GMLib.GetMaterialByIdx(T.material); + if (mtl->Flags.test(SGameMtl::flPassable)) continue; + //Detect sector + if (RImplementation.pOutdoorSector) + { + CSector* sector = (CSector*)RImplementation.getSector(T.sector); + if (sector != RImplementation.pOutdoorSector) + { + no_push = true; + break; + } + } + Fvector Tv[3] = {verts[T.verts[0]], verts[T.verts[1]], verts[T.verts[2]]}; if (CDB::TestRayTri(Item_P, dir, Tv, r_u, r_v, r_range,TRUE)) { @@ -233,8 +246,9 @@ RDEVICE.Statistic->TEST0.End (); { float y_test = Item_P.y - r_range; if (y_test > y) y = y_test; - terrain_normal.mknormal(Tv[0], Tv[1], Tv[2]); } + terrain_normal.mknormal(Tv[0], Tv[1], Tv[2]); + break; } #endif } @@ -243,6 +257,7 @@ RDEVICE.Statistic->TEST0.End (); float DotP = terrain_normal.dotproduct(dir); if (DotP > -(1.0f - r_scale.randF(ps_ssfx_terrain_grass_slope * 0.8f, ps_ssfx_terrain_grass_slope))) continue; + if (no_push) continue; if (y < D.vis.box.min.y) continue; Item_P.y = y; Item.normal = terrain_normal; // Save terrain normal here to feed the grass shader later. diff --git a/src/Layers/xrRender/DetailManager_VS.cpp b/src/Layers/xrRender/DetailManager_VS.cpp index 99227c24e9..cae9626547 100644 --- a/src/Layers/xrRender/DetailManager_VS.cpp +++ b/src/Layers/xrRender/DetailManager_VS.cpp @@ -177,8 +177,9 @@ void CDetailManager::hw_Load_Shaders() hwc_s_array = T1.get("array"); } -void CDetailManager::hw_Render() +void CDetailManager::hw_Render(light* L) { + PROF_EVENT("CDetailManager::hw_Render"); // Render-prepare // Update timer // Can't use RDEVICE.fTimeDelta since it is smoothed! Don't know why, but smoothed value looks more choppy! @@ -210,23 +211,28 @@ void CDetailManager::hw_Render() RCache.set_c(&*hwc_consts, scale, scale, ps_r__Detail_l_aniso, ps_r__Detail_l_ambient); // consts RCache.set_c(&*hwc_wave, wave.div(PI_MUL_2)); // wave RCache.set_c(&*hwc_wind, dir1); // wind-dir - hw_Render_dump(&*hwc_array, 1, 0, c_hdr); + hw_Render_dump(&*hwc_array, 1, 0, c_hdr, L); // Wave1 //wave.set (1.f/3.f, 1.f/7.f, 1.f/5.f, RDEVICE.fTimeGlobal*swing_current.speed); wave.set(1.f / 3.f, 1.f / 7.f, 1.f / 5.f, m_time_pos); RCache.set_c(&*hwc_wave, wave.div(PI_MUL_2)); // wave RCache.set_c(&*hwc_wind, dir2); // wind-dir - hw_Render_dump(&*hwc_array, 2, 0, c_hdr); + hw_Render_dump(&*hwc_array, 2, 0, c_hdr, L); // Still RCache.set_c(&*hwc_s_consts, scale, scale, scale, 1.f); RCache.set_c(&*hwc_s_xform, RDEVICE.mFullTransform); - hw_Render_dump(&*hwc_s_array, 0, 1, c_hdr); + hw_Render_dump(&*hwc_s_array, 0, 1, c_hdr, L); } -void CDetailManager::hw_Render_dump(ref_constant x_array, u32 var_id, u32 lod_id, u32 c_offset) +void CDetailManager::hw_Render_dump(ref_constant x_array, u32 var_id, u32 lod_id, u32 c_offset, light* L) { +#if RENDER==R_R2 + if (RImplementation.phase == CRender::PHASE_SMAP && var_id == 0) + return; +#endif + RDEVICE.Statistic->RenderDUMP_DT_Count = 0; // Matrices and offsets @@ -275,14 +281,28 @@ void CDetailManager::hw_Render_dump(ref_constant x_array, u32 var_id, u32 lod_id for (; _iI != _iE; _iI++) { SlotItem& Instance = **_iI; + + if (!RImplementation.GMBase.is_sector_visible(RImplementation.pOutdoorSector)) + continue; + +#if RENDER==R_R2 + if (RImplementation.phase == CRender::PHASE_SMAP && L) + { + if (!L->GMLight.is_sector_visible(RImplementation.pOutdoorSector)) + continue; + + if (L->position.distance_to_sqr(Instance.position) >= _sqr(L->range)) + continue; + } +#endif + u32 base = dwBatch * 4; // Build matrix ( 3x4 matrix, last row - color ) - float scale = Instance.scale_calculated; - Fmatrix& M = Instance.mRotY; - c_storage[base + 0].set(M._11 * scale, M._21 * scale, M._31 * scale, M._41); - c_storage[base + 1].set(M._12 * scale, M._22 * scale, M._32 * scale, M._42); - c_storage[base + 2].set(M._13 * scale, M._23 * scale, M._33 * scale, M._43); + Fmatrix& M = Instance.mRotY_calculated; + c_storage[base+0].set(M._11, M._21, M._31, M._41); + c_storage[base+1].set(M._12, M._22, M._32, M._42); + c_storage[base+2].set(M._13, M._23, M._33, M._43); // Build color #if RENDER==R_R1 @@ -329,12 +349,7 @@ void CDetailManager::hw_Render_dump(ref_constant x_array, u32 var_id, u32 lod_id // Clean up // KD: we must not clear vis on r2 since we want details shadows #if RENDER==R_R2 - if (!psDeviceFlags2.test(rsGrassShadow) || ((ps_r2_ls_flags.test(R2FLAG_SUN_DETAILS) && (RImplementation.PHASE_SMAP == - RImplementation.phase)) // phase smap with shadows - || (ps_r2_ls_flags.test(R2FLAG_SUN_DETAILS) && (RImplementation.PHASE_NORMAL == RImplementation.phase) - && (!RImplementation.is_sun())) // phase normal with shadows without sun - || (!ps_r2_ls_flags.test(R2FLAG_SUN_DETAILS) && (RImplementation.PHASE_NORMAL == RImplementation.phase)) - )) // phase normal without shadows + if (!psDeviceFlags2.test(rsGrassShadow) || RImplementation.PHASE_NORMAL == RImplementation.phase) // phase normal without shadows #endif vis.clear_not_free(); } diff --git a/src/Layers/xrRender/DetailManager_soft.cpp b/src/Layers/xrRender/DetailManager_soft.cpp index 845a248562..a1eef036fd 100644 --- a/src/Layers/xrRender/DetailManager_soft.cpp +++ b/src/Layers/xrRender/DetailManager_soft.cpp @@ -77,26 +77,13 @@ void CDetailManager::soft_Render() for (u32 item_idx = item_start; item_idx < item_end; ++item_idx) { SlotItem& Instance = *items->at(item_idx); - float scale = Instance.scale_calculated; // Build matrix - Fmatrix& M = Instance.mRotY; - mXform._11 = M._11 * scale; - mXform._12 = M._12 * scale; - mXform._13 = M._13 * scale; - mXform._14 = M._14; - mXform._21 = M._21 * scale; - mXform._22 = M._22 * scale; - mXform._23 = M._23 * scale; - mXform._24 = M._24; - mXform._31 = M._31 * scale; - mXform._32 = M._32 * scale; - mXform._33 = M._33 * scale; - mXform._34 = M._34; - mXform._41 = M._41; - mXform._42 = M._42; - mXform._43 = M._43; - mXform._44 = 1; + Fmatrix& M = Instance.mRotY_calculated; + mXform._11 = M._11; mXform._12 = M._12; mXform._13 = M._13; mXform._14 = M._14; + mXform._21 = M._21; mXform._22 = M._22; mXform._23 = M._23; mXform._24 = M._24; + mXform._31 = M._31; mXform._32 = M._32; mXform._33 = M._33; mXform._34 = M._34; + mXform._41 = M._41; mXform._42 = M._42; mXform._43 = M._43; mXform._44 = 1; // Transfer vertices { diff --git a/src/Layers/xrRender/FBasicVisual.cpp b/src/Layers/xrRender/FBasicVisual.cpp index 0df66047e2..59161c1ed6 100644 --- a/src/Layers/xrRender/FBasicVisual.cpp +++ b/src/Layers/xrRender/FBasicVisual.cpp @@ -44,8 +44,8 @@ void dxRender_Visual::Load(const char* N, IReader* data, u32) { dbg_name = N; dbg_id = 1; - skinning = ::Render->m_skinning; - hud = ::Render->hud_loading; + skinning = Engine.External.GetSkinningMode(); + hud = ::Render->hud_loading; // header VERIFY(data); @@ -145,11 +145,11 @@ void dxRender_Visual::SetShaderTexture(LPCSTR s_shader, LPCSTR s_texture) dbg_texture = s_texture; } - ::Render->m_skinning = skinning; - bool prev_hud = ::Render->hud_loading; - ::Render->hud_loading = hud; - shader.create(*dbg_shader, *dbg_texture); - ::Render->hud_loading = prev_hud; + Engine.External.SetSkinningMode(skinning); + bool prev_hud = ::Render->hud_loading; + ::Render->hud_loading = hud; + shader.create(*dbg_shader, *dbg_texture); + ::Render->hud_loading = prev_hud; } void dxRender_Visual::ResetShaderTexture() diff --git a/src/Layers/xrRender/FBasicVisual.h b/src/Layers/xrRender/FBasicVisual.h index 12bd433fe8..c6037b2eee 100644 --- a/src/Layers/xrRender/FBasicVisual.h +++ b/src/Layers/xrRender/FBasicVisual.h @@ -56,7 +56,7 @@ class ECORE_API dxRender_Visual : public IRenderVisual shared_str dbg_texture_def ; virtual void setID(u32 id) { dbg_id = id; } virtual u32 _BCL getID() { return dbg_id; } - virtual shared_str _BCL getDebugName() { return dbg_name; } + virtual shared_str getDebugName() { return dbg_name; } virtual LPCSTR _BCL getDebugShader() { return *dbg_shader; } virtual LPCSTR _BCL getDebugTexture() { return *dbg_texture; } virtual LPCSTR _BCL getDebugShaderDef() { return *dbg_shader_def; } diff --git a/src/Layers/xrRender/FProgressive.cpp b/src/Layers/xrRender/FProgressive.cpp index 63ae9722ce..61c5b8c05e 100644 --- a/src/Layers/xrRender/FProgressive.cpp +++ b/src/Layers/xrRender/FProgressive.cpp @@ -70,6 +70,7 @@ void FProgressive::Load(const char* N, IReader* data, u32 dwFlags) void FProgressive::Render(float LOD) { + PROF_EVENT("FProgressive::Render"); #if RENDER!=R_R1 if (m_fast && RImplementation.phase == CRender::PHASE_SMAP) { diff --git a/src/Layers/xrRender/FSkinned.cpp b/src/Layers/xrRender/FSkinned.cpp index ff3512eb19..7a369f3a1d 100644 --- a/src/Layers/xrRender/FSkinned.cpp +++ b/src/Layers/xrRender/FSkinned.cpp @@ -401,6 +401,7 @@ void CSkeletonX_ST::Copy(dxRender_Visual* P) ////////////////////////////////////////////////////////////////////// void CSkeletonX_PM::Render(float LOD) { + PROF_EVENT("CSkeletonX_PM::Render"); int lod_id = inherited1::last_lod; if (LOD >= 0.f) { @@ -415,6 +416,7 @@ void CSkeletonX_PM::Render(float LOD) void CSkeletonX_ST::Render(float LOD) { + PROF_EVENT("CSkeletonX_ST::Render"); _Render(rm_geom, vCount, 0, dwPrimitives); } @@ -435,7 +437,7 @@ void CSkeletonX_PM::Load(const char* N, IReader* data, u32 dwFlags) _Load(N, data, vCount); void* _verts_ = data->pointer(); inherited1::Load(N, data, dwFlags | VLOAD_NOVERTICES); - ::Render->shader_option_skinning(-1); + Engine.External.SetSkinningMode(); #if defined(USE_DX10) || defined(USE_DX11) _DuplicateIndices(N, data); #endif // USE_DX10 @@ -448,7 +450,7 @@ void CSkeletonX_ST::Load(const char* N, IReader* data, u32 dwFlags) _Load(N, data, vCount); void* _verts_ = data->pointer(); inherited1::Load(N, data, dwFlags | VLOAD_NOVERTICES); - ::Render->shader_option_skinning(-1); + Engine.External.SetSkinningMode(); #if defined(USE_DX10) || defined(USE_DX11) _DuplicateIndices(N, data); #endif // USE_DX10 @@ -796,7 +798,7 @@ static void verify_vertex( const vertex_type& v, const Fvisual* V, const CKinema Msg( " iBase: %d, iCount: %d, V->iBase %d, V->iCount %d, V->vBase: %d, V->vCount %d, vertex_idx: %d, idx: %d", iBase, iCount, V->iBase, V->iCount, V->vBase, V->vCount, vertex_idx, idx ); Msg( " v.P: %s , v.N: %s, v.T: %s, v.B: %s", get_string( v.P ).c_str(),get_string( v.N ).c_str(),get_string( v.T ).c_str(),get_string( v.B ).c_str()); Msg( "Parent->dbg_name: %s ", Parent->dbg_name.c_str() ); - FlushLog(); + xrLogger::FlushLog(); FATAL( "v.get_bone_id(i) >= Parent->LL_BoneCount()" ); } #endif diff --git a/src/Layers/xrRender/FTreeVisual.cpp b/src/Layers/xrRender/FTreeVisual.cpp index 3ce6c579c6..75e53f7a49 100644 --- a/src/Layers/xrRender/FTreeVisual.cpp +++ b/src/Layers/xrRender/FTreeVisual.cpp @@ -150,6 +150,7 @@ struct FTreeVisual_setup void FTreeVisual::Render(float LOD) { + PROF_EVENT("FTreeVisual::Render"); static FTreeVisual_setup tvs, prev_tvs; if (tvs.dwFrame != Device.dwFrame) { diff --git a/src/Layers/xrRender/FVisual.cpp b/src/Layers/xrRender/FVisual.cpp index 9d68ab9abb..4cf7491d7f 100644 --- a/src/Layers/xrRender/FVisual.cpp +++ b/src/Layers/xrRender/FVisual.cpp @@ -211,6 +211,7 @@ void Fvisual::Load(const char* N, IReader* data, u32 dwFlags) void Fvisual::Render(float) { + PROF_EVENT("Fvisual::Render"); #if (RENDER==R_R2) || (RENDER==R_R3) || (RENDER==R_R4) if (m_fast && RImplementation.phase == CRender::PHASE_SMAP && !RCache.is_TessEnabled()) { diff --git a/src/Layers/xrRender/HOM.cpp b/src/Layers/xrRender/HOM.cpp index 18781ab987..ea71da4eb6 100644 --- a/src/Layers/xrRender/HOM.cpp +++ b/src/Layers/xrRender/HOM.cpp @@ -7,25 +7,33 @@ #include "occRasterizer.h" #include "../../xrEngine/GameFont.h" -#include "dxRenderDeviceRender.h" +#include "../../xrCore/profiler.h" -#include -#include +#include "dxRenderDeviceRender.h" float psOSSR = .001f; void __stdcall CHOM::MT_RENDER() { - MT.Enter(); + PROF_EVENT("Render HOM"); + + xrCriticalSectionGuard guard(m_mt_render_guard); + const u32 current_frame = Device.dwFrame; + bool b_main_menu_is_active = (g_pGamePersistent->m_pMainMenu && g_pGamePersistent->m_pMainMenu->IsActive()); - if (MT_frame_rendered != Device.dwFrame && !b_main_menu_is_active) + if (b_main_menu_is_active) + { + MT_frame_rendered.store(current_frame, std::memory_order_release); + return; + } + + if (MT_frame_rendered.load(std::memory_order_acquire) != current_frame) { CFrustum ViewBase; ViewBase.CreateFromMatrix(Device.mFullTransform, FRUSTUM_P_LRTB + FRUSTUM_P_FAR); Enable(); Render(ViewBase); } - MT.Leave(); } ////////////////////////////////////////////////////////////////////// @@ -37,6 +45,7 @@ CHOM::CHOM() bEnabled = FALSE; m_pModel = 0; m_pTris = 0; + MT_frame_rendered.store(0, std::memory_order_relaxed); #ifdef DEBUG Device.seqRender.Add(this,REG_PRIORITY_LOW-1000); #endif @@ -128,6 +137,12 @@ void CHOM::Load() bEnabled = TRUE; S->close(); FS.r_close(fs); + + if (ps_r2_ls_flags.test(R2FLAG_EXP_MT_CALC)) + { + // MT-HOM (@front) + Device.seqParallelRender.push_back(xr_make_delegate(this, &CHOM::MT_RENDER)); + } } void CHOM::Unload() @@ -135,6 +150,10 @@ void CHOM::Unload() xr_delete(m_pModel); xr_free(m_pTris); bEnabled = FALSE; + + auto I = std::find(Device.seqParallelRender.begin(), Device.seqParallelRender.end(), xr_make_delegate(this, &CHOM::MT_RENDER)); + if (I != Device.seqParallelRender.end()) + Device.seqParallelRender.erase(I); } class pred_fb @@ -265,7 +284,7 @@ void CHOM::Render(CFrustum& base) Raster.clear(); Render_DB(base); Raster.propagade(); - MT_frame_rendered = Device.dwFrame; + MT_frame_rendered.store(Device.dwFrame, std::memory_order_release); Device.Statistic->RenderCALC_HOM.End(); } @@ -326,6 +345,13 @@ BOOL CHOM::visible(Fbox2& B, float depth) return Raster.test(B.min.x, B.min.y, B.max.x, B.max.y, depth); } +BOOL CHOM::visible(Fsphere& S) +{ + Fbox B; + B.setb(S.P,Fvector().set(S.R, S.R, S.R)); + return visible(B); +} + BOOL CHOM::visible(vis_data& vis) { if (Device.dwFrame < vis.hom_frame) return TRUE; // not at this time :) diff --git a/src/Layers/xrRender/HOM.h b/src/Layers/xrRender/HOM.h index 1b21221bfb..863a806035 100644 --- a/src/Layers/xrRender/HOM.h +++ b/src/Layers/xrRender/HOM.h @@ -24,8 +24,8 @@ class CHOM u32 tris_in_frame ; #endif - xrCriticalSection MT; - volatile u32 MT_frame_rendered; + xr_atomic_u32 MT_frame_rendered; + xrCriticalSection m_mt_render_guard; void Render_DB(CFrustum& base); public: @@ -43,16 +43,10 @@ class CHOM void Enable(); void __stdcall MT_RENDER(); - ICF void MT_SYNC() - { - if (g_pGamePersistent->m_pMainMenu && g_pGamePersistent->m_pMainMenu->IsActive()) - return; - - MT_RENDER(); - } BOOL visible(vis_data& vis); BOOL visible(Fbox3& B); + BOOL visible(Fsphere& S); BOOL visible(sPoly& P); BOOL visible(Fbox2& B, float depth); // viewport-space (0..1) diff --git a/src/Layers/xrRender/HW.cpp b/src/Layers/xrRender/HW.cpp index 6da54095bd..a2d2a51482 100644 --- a/src/Layers/xrRender/HW.cpp +++ b/src/Layers/xrRender/HW.cpp @@ -366,7 +366,7 @@ void CHW::CreateDevice(HWND m_hWnd, bool move_window) "Please try to restart the game.\n" "Can not find matching format for back buffer." ); - FlushLog(); + xrLogger::FlushLog(); MessageBox(NULL, "Failed to initialize graphics hardware.\nPlease try to restart the game.", "Error!", MB_OK | MB_ICONERROR); TerminateProcess(GetCurrentProcess(), 0); @@ -437,7 +437,7 @@ void CHW::CreateDevice(HWND m_hWnd, bool move_window) Msg("Failed to initialize graphics hardware.\n" "Please try to restart the game.\n" "CreateDevice returned 0x%08x(D3DERR_DEVICELOST)", R); - FlushLog(); + xrLogger::FlushLog(); MessageBox(NULL, "Failed to initialize graphics hardware.\nPlease try to restart the game.", "Error!", MB_OK | MB_ICONERROR); TerminateProcess(GetCurrentProcess(), 0); @@ -563,7 +563,7 @@ u32 CHW::selectGPU() u32 CHW::selectRefresh(u32 dwWidth, u32 dwHeight, D3DFORMAT fmt) { - if (psDeviceFlags.is(rsRefresh60hz) || strstr(Core.Params, "-60hz")) + if (psDeviceFlags.is(rsRefresh60hz) || Core.ParamsData.test(ECoreParams::_60hz)) { refresh_rate = 1.f / 60.f; return D3DPRESENT_RATE_DEFAULT; @@ -596,13 +596,6 @@ BOOL CHW::support(D3DFORMAT fmt, DWORD type, DWORD usage) void CHW::updateWindowProps(HWND m_hWnd) { - // BOOL bWindowed = strstr(Core.Params,"-dedicated") ? TRUE : !psDeviceFlags.is (rsFullscreen); - //#ifndef DEDICATED_SERVER - // BOOL bWindowed = !psDeviceFlags.is (rsFullscreen); - //#else - // BOOL bWindowed = TRUE; - //#endif - BOOL bWindowed = TRUE; #ifndef _EDITOR if (!g_dedicated_server) @@ -622,7 +615,7 @@ void CHW::updateWindowProps(HWND m_hWnd) else { dwWindowStyle |= WS_BORDER | WS_OVERLAPPEDWINDOW; - if (!strstr(Core.Params, "-no_dialog_header")) + if (!Core.ParamsData.test(ECoreParams::no_dialog_header)) dwWindowStyle |= WS_DLGFRAME | WS_SYSMENU | WS_MINIMIZEBOX; } diff --git a/src/Layers/xrRender/HWCaps.cpp b/src/Layers/xrRender/HWCaps.cpp index e9fb2b805d..9227ffa38c 100644 --- a/src/Layers/xrRender/HWCaps.cpp +++ b/src/Layers/xrRender/HWCaps.cpp @@ -102,7 +102,7 @@ namespace #else u32 GetGpuNum() { - return 1; + return 2; } #endif } diff --git a/src/Layers/xrRender/LightTrack.cpp b/src/Layers/xrRender/LightTrack.cpp index b78fda999e..3e9c33a82e 100644 --- a/src/Layers/xrRender/LightTrack.cpp +++ b/src/Layers/xrRender/LightTrack.cpp @@ -15,6 +15,8 @@ # include "../../xrEngine/environment.h" #endif +#include "../xrServerEntities/smart_cast.h" + ////////////////////////////////////////////////////////////////////// // Construction/Destruction ////////////////////////////////////////////////////////////////////// @@ -50,16 +52,17 @@ CROS_impl::CROS_impl() void CROS_impl::add(light* source) { // Search - for (xr_vector::iterator I = track.begin(); I != track.end(); I++) - if (source == I->source) + for (Item& item : track) + { + if (source == item.source) { - I->frame_touched = Device.dwFrame; + item.frame_touched = Device.dwFrame; return; } + } // Register _new_ - track.push_back(Item()); - Item& L = track.back(); + Item& L = track.emplace_back(); L.frame_touched = Device.dwFrame; L.source = source; L.cache.verts[0].set(0, 0, 0); @@ -69,7 +72,7 @@ void CROS_impl::add(light* source) L.energy = 0.f; } -IC bool pred_energy(const CROS_impl::Light& L1, const CROS_impl::Light& L2) { return L1.energy > L2.energy; } + ////////////////////////////////////////////////////////////////////////// #pragma warning(push) #pragma warning(disable:4305) @@ -184,20 +187,16 @@ void CROS_impl::update(IRenderable* O) dwFrame = Device.dwFrame; if (0 == O) return; if (0 == O->renderable.visual) return; - VERIFY(fast_dynamic_cast (O->renderable_ROS())); + VERIFY(smart_cast (O->renderable_ROS())); //float dt = Device.fTimeDelta; - - CObject* _object = fast_dynamic_cast(O); + PROF_EVENT("CROS_impl::update"); + CObject* _object = O->dcast_CObject(); // select sample, randomize position inside object vis_data& vis = O->renderable.visual->getVisData(); Fvector position; O->renderable.xform.transform_tiny(position, vis.sphere.P); position.y += .3f * vis.sphere.R; - Fvector direction; - direction.random_dir(); - //. position.mad(direction,0.25f*radius); - //. position.mad(direction,0.025f*radius); //function call order is important at least for r1 for (size_t i = 0; i < NUM_FACES; ++i) @@ -311,7 +310,7 @@ void CROS_impl::smart_update(IRenderable* O) // Acquire current position Fvector position; - VERIFY(fast_dynamic_cast (O->renderable_ROS())); + VERIFY(smart_cast (O->renderable_ROS())); vis_data& vis = O->renderable.visual->getVisData(); O->renderable.xform.transform_tiny(position, vis.sphere.P); @@ -354,7 +353,7 @@ void CROS_impl::update_smooth(IRenderable* O) return; dwFrameSmooth = Device.dwFrame; - + PROF_EVENT("CROS_impl::update_smooth"); #if RENDER==R_R1 if (O && (0 == result_count)) update(O); // First time only @@ -448,7 +447,7 @@ void CROS_impl::calc_sky_hemi_value(Fvector& position, CObject* _object) void CROS_impl::prepare_lights(Fvector& position, IRenderable* O) { - CObject* _object = fast_dynamic_cast(O); + CObject* _object = O->dcast_CObject(); float dt = Device.fTimeDelta; vis_data& vis = O->renderable.visual->getVisData(); @@ -463,13 +462,13 @@ void CROS_impl::prepare_lights(Fvector& position, IRenderable* O) Fvector bb_size = {radius, radius, radius}; #if RENDER!=R_R1 - g_SpatialSpace->q_box(RImplementation.lstSpatial, 0, STYPE_LIGHTSOURCEHEMI, position, bb_size); + g_SpatialSpaceLights->q_box(lstSpatial, 0, STYPE_LIGHTSOURCEHEMI, position, bb_size); #else - g_SpatialSpace->q_box(RImplementation.lstSpatial, 0, STYPE_LIGHTSOURCE, position, bb_size); + g_SpatialSpaceLights->q_box(lstSpatial, 0, STYPE_LIGHTSOURCE, position, bb_size); #endif - for (u32 o_it = 0; o_it < RImplementation.lstSpatial.size(); o_it++) + for (u32 o_it = 0; o_it < lstSpatial.size(); o_it++) { - ISpatial* spatial = RImplementation.lstSpatial[o_it]; + ISpatialShared spatial = lstSpatial[o_it]; light* source = (light*)(spatial->dcast_Light()); VERIFY(source); // sanity check float R = radius + source->range; @@ -523,11 +522,10 @@ void CROS_impl::prepare_lights(Fvector& position, IRenderable* O) if (E > EPS) { // Select light - lights.push_back(CROS_impl::Light()); - CROS_impl::Light& L = lights.back(); + CROS_impl::Light& L = lights.emplace_back(); L.source = xrL; - L.color.mul_rgb(xrL->color, I->energy / 2); - L.energy = I->energy / 2; + L.color.mul_rgb(xrL->color, I->energy*.5f); + L.energy = I->energy*.5f; if (!xrL->flags.bStatic) { L.color.mul_rgb(.5f); @@ -544,14 +542,13 @@ void CROS_impl::prepare_lights(Fvector& position, IRenderable* O) if (E > EPS) { // Select light - lights.push_back(CROS_impl::Light()); - CROS_impl::Light& L = lights.back(); + CROS_impl::Light& L = lights.emplace_back(); L.source = sun; - L.color.mul_rgb(sun->color, sun_smooth / 2); + L.color.mul_rgb(sun->color, sun_smooth*.5f); L.energy = sun_smooth; } #endif // Sort lights by importance - important for R1-shadows - std::sort(lights.begin(), lights.end(), pred_energy); + std::sort(lights.begin(), lights.end(), [](const CROS_impl::Light & L1, const CROS_impl::Light & L2) { return L1.energy > L2.energy; }); } } diff --git a/src/Layers/xrRender/LightTrack.h b/src/Layers/xrRender/LightTrack.h index d592f28a50..d987538c99 100644 --- a/src/Layers/xrRender/LightTrack.h +++ b/src/Layers/xrRender/LightTrack.h @@ -72,6 +72,8 @@ class CROS_impl : public IRender_ObjectSpecific Fvector approximate; + xr_vector lstSpatial; + #if RENDER!=R_R1 Fvector last_position; s32 ticks_to_update; diff --git a/src/Layers/xrRender/Light_DB.cpp b/src/Layers/xrRender/Light_DB.cpp index f98718a7f9..e15f39fdb6 100644 --- a/src/Layers/xrRender/Light_DB.cpp +++ b/src/Layers/xrRender/Light_DB.cpp @@ -21,6 +21,8 @@ void CLight_DB::Load(IReader* fs) // Lights itself sun_original = NULL; sun_adapted = NULL; + rain_light = xr_new(); + rain_light->set_type(IRender_Light::DIRECT); { F = fs->open_chunk(fsL_LIGHT_DYNAMIC); @@ -145,7 +147,7 @@ void CLight_DB::LoadHemi() L->set_active(true); L->set_attenuation_params(Ldata.attenuation0, Ldata.attenuation1, Ldata.attenuation2, Ldata.falloff); - L->spatial.type = STYPE_LIGHTSOURCEHEMI; + L->SpatialComponent->spatial.type = STYPE_LIGHTSOURCEHEMI; // R_ASSERT (L->spatial.sector ); } } @@ -165,6 +167,8 @@ void CLight_DB::Unload() v_hemi.clear(); sun_original.destroy(); sun_adapted.destroy(); + rain_light->destroy(false); + rain_light = nullptr; } light* CLight_DB::Create() @@ -193,7 +197,9 @@ void CLight_DB::add_light(light* L) L->frame_render = Device.dwFrame; if (RImplementation.o.noshadows) L->flags.bShadow = FALSE; if (L->flags.bStatic && !ps_r2_ls_flags.test(R2FLAG_R1LIGHTS)) return; - L->export_(package); + if(Device.vCameraPosition.distance_to_sqr(L->SpatialComponent->spatial.sphere.P)>_sqr(g_pGamePersistent->Environment().CurrentEnv->fog_distance)) return; + + L->export_(); } #endif // (RENDER==R_R2) || (RENDER==R_R3) || (RENDER==R_R4) @@ -257,7 +263,4 @@ void CLight_DB::Update() sun_adapted->set_position(OP); } } - - // Clear selection - package.clear(); } diff --git a/src/Layers/xrRender/Light_DB.h b/src/Layers/xrRender/Light_DB.h index 50404a7a6d..3981ebd25d 100644 --- a/src/Layers/xrRender/Light_DB.h +++ b/src/Layers/xrRender/Light_DB.h @@ -11,7 +11,7 @@ class CLight_DB public: ref_light sun_original; ref_light sun_adapted; - light_Package package; + light* rain_light; public: void add_light(light* L); diff --git a/src/Layers/xrRender/Light_Package.cpp b/src/Layers/xrRender/Light_Package.cpp index 392c87a753..529aa73bc8 100644 --- a/src/Layers/xrRender/Light_Package.cpp +++ b/src/Layers/xrRender/Light_Package.cpp @@ -7,27 +7,3 @@ void light_Package::clear() v_spot.clear(); v_shadowed.clear(); } - -#if (RENDER==R_R2) || (RENDER==R_R3) || (RENDER==R_R4) -IC bool pred_light_cmp(light* _1, light* _2) -{ - if (_1->vis.pending) - { - if (_2->vis.pending) return _1->vis.query_order > _2->vis.query_order; // q-order - else return false; // _2 should be first - } - else - { - if (_2->vis.pending) return true; // _1 should be first - else return _1->range > _2->range; // sort by range - } -} - -void light_Package::sort() -{ - // resort lights (pending -> at the end), maintain stable order - std::stable_sort(v_point.begin(), v_point.end(), pred_light_cmp); - std::stable_sort(v_spot.begin(), v_spot.end(), pred_light_cmp); - std::stable_sort(v_shadowed.begin(), v_shadowed.end(), pred_light_cmp); -} -#endif // (RENDER==R_R2) || (RENDER==R_R3) || (RENDER==R_R4) diff --git a/src/Layers/xrRender/Light_Package.h b/src/Layers/xrRender/Light_Package.h index 216b5fb168..452137d558 100644 --- a/src/Layers/xrRender/Light_Package.h +++ b/src/Layers/xrRender/Light_Package.h @@ -10,5 +10,4 @@ class light_Package xr_vector v_shadowed; public: void clear(); - void sort(); }; diff --git a/src/Layers/xrRender/ModelPool.cpp b/src/Layers/xrRender/ModelPool.cpp index 5fb3be408d..4d7c10d4b5 100644 --- a/src/Layers/xrRender/ModelPool.cpp +++ b/src/Layers/xrRender/ModelPool.cpp @@ -87,14 +87,16 @@ dxRender_Visual* CModelPool::Instance_Duplicate(dxRender_Visual* V) dxRender_Visual* N = Instance_Create(V->Type); N->Copy(V); N->Spawn(); - // inc ref counter - for (xr_vector::iterator I = Models.begin(); I != Models.end(); I++) - if (I->model == V) + { + // inc ref counter + xrSRWLockGuard g(ModelsLock, true); + auto it = std::lower_bound(Models.begin(), Models.end(), V, std::less<>{}); + if (it != Models.end() && it->model == V) { - I->refs++; - break; + it->refs++; } - return N; + return N; + } } dxRender_Visual* CModelPool::Instance_Load(const char* N, BOOL allow_register, bool assert) @@ -143,7 +145,8 @@ dxRender_Visual* CModelPool::Instance_Load(const char* N, BOOL allow_register, b g_pGamePersistent->RegisterModel(V); // Registration - if (allow_register) Instance_Register(N, V); + if (allow_register) + V = Instance_Register(N, V); return V; } @@ -158,17 +161,42 @@ dxRender_Visual* CModelPool::Instance_Load(LPCSTR name, IReader* data, BOOL allo V->Load(name, data, 0); // Registration - if (allow_register) Instance_Register(name, V); + if (allow_register) + V = Instance_Register(name, V); return V; } -void CModelPool::Instance_Register(LPCSTR N, dxRender_Visual* V) +dxRender_Visual* CModelPool::Instance_Register(LPCSTR N, dxRender_Visual* V) { // Registration + shared_str S(N); + xrSRWLockGuard g(ModelsLock); + + // Double-check for duplicate model + for (auto& M : Models) + { + if (M.name == S) + { + // Increment the reference count + M.refs++; + + // Destroy the redundant one we just loaded + V->Release(); + xr_delete(V); + + // Return the existing model + return M.model; + } + } + ModelDef M; - M.name = N; + M.name = S; M.model = V; - Models.push_back(M); + + auto it = std::lower_bound(Models.begin(), Models.end(), V, std::less<>{}); + Models.insert(it, std::move(M)); + + return V; } @@ -182,6 +210,11 @@ void CModelPool::Destroy() { REGISTRY_IT it = Registry.begin(); dxRender_Visual* V = (dxRender_Visual*)it->first; + if (!V) + { + Registry.erase(it); + continue; + } #ifdef _DEBUG Msg ("ModelPool: Destroy object: '%s'",*V->dbg_name); #endif @@ -189,16 +222,16 @@ void CModelPool::Destroy() } // Base/Reference - xr_vector::iterator I = Models.begin(); - xr_vector::iterator E = Models.end(); - for (; I != E; I++) { - I->model->Release(); - xr_delete(I->model); + xrSRWLockGuard g(ModelsLock); + for (auto& M : Models) + { + M.model->Release(); + xr_delete(M.model); + } + Models.clear(); } - Models.clear(); - // cleanup motions container g_pMotionsContainer->clean(false); } @@ -219,13 +252,15 @@ CModelPool::~CModelPool() dxRender_Visual* CModelPool::Instance_Find(LPCSTR N) { + shared_str S(N); dxRender_Visual* Model = 0; - xr_vector::iterator I; - for (I = Models.begin(); I != Models.end(); I++) + xrSRWLockGuard g(ModelsLock, true); + + for (auto& M : Models) { - if (I->name[0] && (0 == xr_strcmp(*I->name, N))) + if (S == M.name) { - Model = I->model; + Model = M.model; break; } } @@ -302,7 +337,7 @@ dxRender_Visual* CModelPool::CreateChild(LPCSTR name, IReader* data) return Model; } -extern BOOL ENGINE_API g_bRendering; +extern xr_atomic_bool ENGINE_API g_bRendering; void CModelPool::DeleteInternal(dxRender_Visual* & V, BOOL bDiscard) { @@ -338,9 +373,22 @@ void CModelPool::DeleteInternal(dxRender_Visual* & V, BOOL bDiscard) V = NULL; } -void CModelPool::Delete(dxRender_Visual* & V, BOOL bDiscard) +void CModelPool::DeleteDeffered(dxRender_Visual* &V) { - if (NULL == V) return; + if (nullptr==V) + return; + + xrCriticalSectionGuard guard(&deffered_del_lock); + + if (std::find(ModelsToDeleteDeffer.begin(), ModelsToDeleteDeffer.end(), V) == ModelsToDeleteDeffer.end()) + ModelsToDeleteDeffer.push_back(V); + V = nullptr; +} + +void CModelPool::Delete(dxRender_Visual* &V, BOOL bDiscard) +{ + if (nullptr==V) + return; if (g_bRendering) { VERIFY(!bDiscard); @@ -348,9 +396,9 @@ void CModelPool::Delete(dxRender_Visual* & V, BOOL bDiscard) } else { - DeleteInternal(V, bDiscard); + DeleteInternal(V,bDiscard); } - V = NULL; + V = nullptr; } void CModelPool::DeleteQueue() @@ -360,6 +408,19 @@ void CModelPool::DeleteQueue() ModelsToDelete.clear(); } +void CModelPool::DeleteQueuedDeffer() +{ + xrCriticalSectionGuard guard(&deffered_del_lock); + + for (dxRender_Visual* Vis : ModelsToDeleteDeffer) + { + if (Vis) + DeleteInternal(Vis); + } + + ModelsToDeleteDeffer.clear(); +} + void CModelPool::Discard(dxRender_Visual* & V, BOOL b_complete) { // @@ -368,11 +429,11 @@ void CModelPool::Discard(dxRender_Visual* & V, BOOL b_complete) { // Base const shared_str& name = it->second; - xr_vector::iterator I = Models.begin(); - xr_vector::iterator I_e = Models.end(); + xrSRWLockGuard g(ModelsLock); - for (; I != I_e; ++I) + for (u32 i = 0; i < Models.size(); i++) { + auto I = Models.begin() + i; if (I->name == name) { if (b_complete || strchr(*name, '#')) @@ -491,6 +552,7 @@ void CModelPool::dump() Log("--- model pool --- begin:"); u32 sz = 0; u32 k = 0; + xrSRWLockGuard g(ModelsLock, true); for (xr_vector::iterator I = Models.begin(); I != Models.end(); I++) { CKinematics* K = PCKinematics(I->model); @@ -531,6 +593,7 @@ void CModelPool::memory_stats(u32& vb_mem_video, u32& vb_mem_system, u32& ib_mem xr_vector::iterator it = Models.begin(); xr_vector::const_iterator en = Models.end(); + xrSRWLockGuard g(ModelsLock, true); for (; it != en; ++it) { diff --git a/src/Layers/xrRender/ModelPool.h b/src/Layers/xrRender/ModelPool.h index eab7561751..b8de6ae108 100644 --- a/src/Layers/xrRender/ModelPool.h +++ b/src/Layers/xrRender/ModelPool.h @@ -1,7 +1,5 @@ // ModelPool.h: interface for the CModelPool class. ////////////////////////////////////////////////////////////////////// -#ifndef ModelPoolH -#define ModelPoolH #pragma once // refs @@ -37,6 +35,11 @@ class ECORE_API CModelPool refs = 0; model = 0; } + + // Order by pointer + bool operator<(const ModelDef& other) const { return model < other.model; } + bool operator<(const dxRender_Visual* other) const { return model < other; } + friend bool operator<(dxRender_Visual* ptr, const ModelDef& other) { return ptr < other.model; } }; typedef xr_multimap POOL; @@ -46,11 +49,14 @@ class ECORE_API CModelPool private: xr_vector Models; // Reference / Base xr_vector ModelsToDelete; // + xr_vector ModelsToDeleteDeffer; // REGISTRY Registry; // Just pairing of pointer / Name POOL Pool; // Unused / Inactive BOOL bLogging; BOOL bForceDiscard; BOOL bAllowChildrenDuplicate; + xrCriticalSection deffered_del_lock; + xrSRWLock ModelsLock; void Destroy(); public: @@ -60,17 +66,19 @@ class ECORE_API CModelPool dxRender_Visual* Instance_Duplicate(dxRender_Visual* V); dxRender_Visual* Instance_Load(LPCSTR N, BOOL allow_register, bool assert = true); dxRender_Visual* Instance_Load(LPCSTR N, IReader* data, BOOL allow_register); - void Instance_Register(LPCSTR N, dxRender_Visual* V); + dxRender_Visual* Instance_Register(LPCSTR N, dxRender_Visual* V); dxRender_Visual* Instance_Find(LPCSTR N); dxRender_Visual* CreatePE(PS::CPEDef* source); dxRender_Visual* CreatePG(PS::CPGDef* source); dxRender_Visual* Create(LPCSTR name, IReader* data = 0, bool assert = true); dxRender_Visual* CreateChild(LPCSTR name, IReader* data); + void DeleteDeffered(dxRender_Visual* &V); void Delete(dxRender_Visual* & V, BOOL bDiscard = FALSE); void Discard(dxRender_Visual* & V, BOOL b_complete); void DeleteInternal(dxRender_Visual* & V, BOOL bDiscard = FALSE); void DeleteQueue(); + void DeleteQueuedDeffer(); void Logging(BOOL bEnable) { bLogging = bEnable; } @@ -88,4 +96,3 @@ class ECORE_API CModelPool void RenderSingle (dxRender_Visual* m_pVisual, const Fmatrix& mTransform, float m_fLOD); #endif }; -#endif //ModelPoolH diff --git a/src/Layers/xrRender/PSLibrary.cpp b/src/Layers/xrRender/PSLibrary.cpp index 0241631148..566d8a377b 100644 --- a/src/Layers/xrRender/PSLibrary.cpp +++ b/src/Layers/xrRender/PSLibrary.cpp @@ -48,6 +48,7 @@ void CPSLibrary::OnDestroy() for (PS::PGDIt g_it = m_PGDs.begin(); g_it != m_PGDs.end(); ++g_it) xr_delete(*g_it); m_PGDs.clear(); + m_all_ps.clear(); } //---------------------------------------------------- @@ -158,7 +159,10 @@ bool CPSLibrary::Load2() PS::CPEDef* def = xr_new(); def->m_Name = _path; if (def->Load2(ini)) - m_PEDs.push_back(def); + { + m_all_ps.push_back(def->m_Name); + m_PEDs.push_back(def); + } else xr_delete(def); } @@ -167,7 +171,10 @@ bool CPSLibrary::Load2() PS::CPGDef* def = xr_new(); def->m_Name = _path; if (def->Load2(ini)) - m_PGDs.push_back(def); + { + m_all_ps.push_back(def->m_Name); + m_PGDs.push_back(def); + } else xr_delete(def); } @@ -216,7 +223,10 @@ bool CPSLibrary::Load(const char* nm) PS::CPEDef* def = xr_new(); def->m_Name = _path; if (def->Load2(ini)) - m_PEDs.push_back(def); + { + m_all_ps.push_back(def->m_Name); + m_PEDs.push_back(def); + } else xr_delete(def); } @@ -225,7 +235,10 @@ bool CPSLibrary::Load(const char* nm) PS::CPGDef* def = xr_new(); def->m_Name = _path; if (def->Load2(ini)) - m_PGDs.push_back(def); + { + m_all_ps.push_back(def->m_Name); + m_PGDs.push_back(def); + } else xr_delete(def); } diff --git a/src/Layers/xrRender/PSLibrary.h b/src/Layers/xrRender/PSLibrary.h index 3773a06148..728105e3a0 100644 --- a/src/Layers/xrRender/PSLibrary.h +++ b/src/Layers/xrRender/PSLibrary.h @@ -19,6 +19,7 @@ class ECORE_API CPSLibrary : public particles_systems::library_interface { PS::PEDVec m_PEDs; PS::PGDVec m_PGDs; + xr_vector m_all_ps; #ifdef _EDITOR AnsiString m_CurrentParticles; @@ -63,6 +64,7 @@ class ECORE_API CPSLibrary : public particles_systems::library_interface virtual PS::CPGDef const* const* particles_group_end() const; virtual void particles_group_next(PS::CPGDef const* const*& iterator) const; virtual shared_str const& particles_group_id(PS::CPGDef const& particles_group) const; + virtual xr_vector const& vec_all_particles() const { return m_all_ps; } }; #define PS_LIB_SIGN "PS_LIB" diff --git a/src/Layers/xrRender/ParticleEffect.cpp b/src/Layers/xrRender/ParticleEffect.cpp index d1a8215873..c798ea534a 100644 --- a/src/Layers/xrRender/ParticleEffect.cpp +++ b/src/Layers/xrRender/ParticleEffect.cpp @@ -2,6 +2,7 @@ #pragma hdrstop #include "ParticleEffect.h" +#include "CHudInitializer.h" #include #include @@ -127,52 +128,101 @@ void CParticleEffect::UpdateParent(const Fmatrix& m, const Fvector& velocity, BO void CParticleEffect::OnFrame(u32 frame_dt) { - if (m_Def && m_RT_Flags.is(flRT_Playing)) + if (0==m_RT_Flags.is(flRT_LiveUpdate)) { - m_MemDT += frame_dt; - - int StepCount = 0; - u32 uDT_STEP = m_Def->GetUStep(); - float fDT_STEP = m_Def->GetFStep(); - if (m_MemDT >= uDT_STEP) + if (m_Def && m_RT_Flags.is(flRT_Playing)) { - // allow maximum of three steps (99ms) to avoid slowdown after loading - // it will really skip updates at less than 10fps, which is unplayable - StepCount = m_MemDT / uDT_STEP; - m_MemDT = m_MemDT % uDT_STEP; - clamp(StepCount, 0, 3); - } + m_MemDT += frame_dt; - for (; StepCount; StepCount--) - { - if (m_Def->m_Flags.is(CPEDef::dfTimeLimit)) + int StepCount = 0; + u32 uDT_STEP = m_Def->GetUStep(); + float fDT_STEP = m_Def->GetFStep(); + if (m_MemDT >= uDT_STEP) { - if (!m_RT_Flags.is(flRT_DefferedStop)) + // allow maximum of three steps (99ms) to avoid slowdown after loading + // it will really skip updates at less than 10fps, which is unplayable + StepCount = m_MemDT / uDT_STEP; + m_MemDT = m_MemDT % uDT_STEP; + clamp(StepCount, 0, 3); + } + + for (; StepCount; StepCount--) + { + if (m_Def->m_Flags.is(CPEDef::dfTimeLimit)) { - m_fElapsedLimit -= fDT_STEP; - if (m_fElapsedLimit < 0.f) + if (!m_RT_Flags.is(flRT_DefferedStop)) { - m_fElapsedLimit = m_Def->m_fTimeLimit; - Stop(true); - break; + m_fElapsedLimit -= fDT_STEP; + if (m_fElapsedLimit < 0.f) + { + m_fElapsedLimit = m_Def->m_fTimeLimit; + Stop(true); + break; + } } } + ParticleManager()->Update(m_HandleEffect, m_HandleActionList, fDT_STEP); + + PAPI::Particle* particles; + u32 p_cnt; + ParticleManager()->GetParticles(m_HandleEffect, particles, p_cnt); + + // our actions + if (m_Def->m_Flags.is(CPEDef::dfFramed | CPEDef::dfAnimated)) + m_Def->ExecuteAnimate(particles, p_cnt, fDT_STEP); + if (m_Def->m_Flags.is(CPEDef::dfCollision)) + m_Def->ExecuteCollision(particles, p_cnt, fDT_STEP, this, m_CollisionCallback); + + //-move action + if (p_cnt) + { + vis.box.invalidate(); + float p_size = 0.f; + for (u32 i = 0; i < p_cnt; i++) + { + Particle& m = particles[i]; + if(!RImplementation.ViewBase.testSphere_dirty(vis.sphere.P, vis.sphere.R)) + { + m.posI.set(m.pos); + m.rotI.set(m.rot); + m.velI.set(m.vel); + m.sizeI.set(m.size); + } + vis.box.modify((Fvector&)m.pos); + if (m.size.x > p_size) p_size = m.size.x; + if (m.size.y > p_size) p_size = m.size.y; + if (m.size.z > p_size) p_size = m.size.z; + } + vis.box.grow(p_size); + vis.box.getsphere(vis.sphere.P, vis.sphere.R); + } + if (m_RT_Flags.is(flRT_DefferedStop) && (0 == p_cnt)) + { + m_RT_Flags.set(flRT_Playing | flRT_DefferedStop, FALSE); + break; + } } - ParticleManager()->Update(m_HandleEffect, m_HandleActionList, fDT_STEP); - - PAPI::Particle* particles; - u32 p_cnt; + } + else + { + vis.box.set(m_InitialPosition, m_InitialPosition); + vis.box.grow(EPS_L); + vis.box.getsphere(vis.sphere.P, vis.sphere.R); + } + } + else + { + if (m_Def && m_RT_Flags.is(flRT_Playing)) + { + ParticleManager()->Update(m_HandleEffect, m_HandleActionList, Device.fTimeDelta); + PAPI::Particle* particles = NULL; + u32 p_cnt = 0; ParticleManager()->GetParticles(m_HandleEffect, particles, p_cnt); - - // our actions + if (!particles) return; if (m_Def->m_Flags.is(CPEDef::dfFramed | CPEDef::dfAnimated)) - m_Def->ExecuteAnimate( - particles, p_cnt, fDT_STEP); + m_Def->ExecuteAnimate(particles, p_cnt, Device.fTimeDelta); if (m_Def->m_Flags.is(CPEDef::dfCollision)) - m_Def->ExecuteCollision( - particles, p_cnt, fDT_STEP, this, m_CollisionCallback); - - //-move action + m_Def->ExecuteCollision(particles, p_cnt, Device.fTimeDelta, this, m_CollisionCallback); if (p_cnt) { vis.box.invalidate(); @@ -180,7 +230,8 @@ void CParticleEffect::OnFrame(u32 frame_dt) for (u32 i = 0; i < p_cnt; i++) { Particle& m = particles[i]; - vis.box.modify((Fvector&)m.pos); + if (!_valid(m.pos)) continue; + vis.box.modify(Fvector(m.pos)); if (m.size.x > p_size) p_size = m.size.x; if (m.size.y > p_size) p_size = m.size.y; if (m.size.z > p_size) p_size = m.size.z; @@ -188,18 +239,30 @@ void CParticleEffect::OnFrame(u32 frame_dt) vis.box.grow(p_size); vis.box.getsphere(vis.sphere.P, vis.sphere.R); } - if (m_RT_Flags.is(flRT_DefferedStop) && (0 == p_cnt)) + + bool deffered_stop = true; + if (m_Def->m_Flags.is(CPEDef::dfTimeLimit)) { - m_RT_Flags.set(flRT_Playing | flRT_DefferedStop,FALSE); - break; + if (!m_RT_Flags.is(flRT_DefferedStop)) + { + m_fElapsedLimit -= Device.fTimeDelta; + if (m_fElapsedLimit < 0.f) + { + m_fElapsedLimit = m_Def->m_fTimeLimit; + Stop(true); + deffered_stop = false; + } + } } + if (deffered_stop && m_RT_Flags.is(flRT_DefferedStop) && (0 == p_cnt)) + m_RT_Flags.set(flRT_Playing | flRT_DefferedStop, FALSE); + } + else + { + vis.box.set(m_InitialPosition, m_InitialPosition); + vis.box.grow(EPS_L); + vis.box.getsphere(vis.sphere.P, vis.sphere.R); } - } - else - { - vis.box.set(m_InitialPosition, m_InitialPosition); - vis.box.grow(EPS_L); - vis.box.getsphere(vis.sphere.P, vis.sphere.R); } } @@ -447,7 +510,7 @@ __forceinline void magnitude_sse(Fvector& vec, float& res) _mm_store_ss((float*)&res, tv); } -void ParticleRenderStream(FVF::LIT* pv, u32 count, PAPI::Particle * particles, CParticleEffect * pPE) +bool ParticleRenderStream(FVF::LIT* pv, u32 count, PAPI::Particle * particles, CParticleEffect * pPE) { float sina = 0.0f, cosa = 0.0f; // Xottab_DUTY: changed angle to be float instead of DWORD @@ -458,115 +521,132 @@ void ParticleRenderStream(FVF::LIT* pv, u32 count, PAPI::Particle * particles, C for (u32 i = 0; i != count; ++i) { PAPI::Particle& m = particles[i]; + { + if (pPE->m_RT_Flags.is(CParticleEffect::flRT_LiveUpdate)) + { + m.posI.set(m.pos); + m.rotI.set(m.rot); + m.velI.set(m.vel); + m.sizeI.set(m.size); + } + else + { + float dt = 1.f-10.f*Device.fTimeDelta; + clamp(dt,0.f,0.99f); + m.posI.inertion(m.pos, dt); + m.rotI.inertion(m.rot, dt); + m.velI.inertion(m.vel, dt); + m.sizeI.inertion(m.size, dt); + } + } + + Fvector wp_eff; + pPE->m_XFORM.transform_tiny(wp_eff, m.posI); + + if (Device.vCameraPosition.distance_to_sqr(wp_eff) > _sqr(g_pGamePersistent->Environment().CurrentEnv->fog_distance)) + { + return true; + } + Fvector2 lt, rb; lt.set(0.f, 0.f); rb.set(1.f, 1.f); - _mm_prefetch((char*)&particles[i + 1], _MM_HINT_NTA); - - if (angle != m.rot.x) + if (angle != m.rotI.x) { - angle = m.rot.x; - sina = std::sinf(*(float*)&angle); - cosa = std::cosf(*(float*)&angle); + angle = m.rotI.x; + sina = std::sinf(angle); + cosa = std::cosf(angle); } - _mm_prefetch(64 + (char*)&particles[i + 1], _MM_HINT_NTA); - if (pPE->m_Def->m_Flags.is(CPEDef::dfFramed)) pPE->m_Def->m_Frame.CalculateTC(iFloor(float(m.frame) / 255.f), lt, rb); - float r_x = m.size.x * 0.5f; - float r_y = m.size.y * 0.5f; + float r_x = m.sizeI.x * 0.5f; + float r_y = m.sizeI.y * 0.5f; float speed = 0.f; bool speed_calculated = false; if (pPE->m_Def->m_Flags.is(CPEDef::dfVelocityScale)) { - magnitude_sse(m.vel, speed); + magnitude_sse(m.velI, speed); speed_calculated = true; r_x += speed * pPE->m_Def->m_VelocityScale.x; r_y += speed * pPE->m_Def->m_VelocityScale.y; } - if (pPE->m_Def->m_Flags.is(CPEDef::dfAlignToPath)) + if (pPE->m_Def->m_Flags.is(CPEDef::dfAlignToPath)) + { + if (!speed_calculated) + magnitude_sse(m.velI, speed); + if ((speed < EPS_S) && pPE->m_Def->m_Flags.is(CPEDef::dfWorldAlign)) { - if (!speed_calculated) - magnitude_sse(m.vel, speed); - if ((speed < EPS_S) && pPE->m_Def->m_Flags.is(CPEDef::dfWorldAlign)) + Fmatrix M; + M.setXYZ(pPE->m_Def->m_APDefaultRotation); + if (pPE->m_RT_Flags.is(CParticleEffect::flRT_XFORM)) { - Fmatrix M; - M.setXYZ(pPE->m_Def->m_APDefaultRotation); - if (pPE->m_RT_Flags.is(CParticleEffect::flRT_XFORM)) - { - Fvector p; - pPE->m_XFORM.transform_tiny(p, m.pos); - M.mulA_43(pPE->m_XFORM); - FillSprite(pv, M.k, M.i, p, lt, rb, r_x, r_y, color_rgba_f(m.colorR, m.colorG, m.colorB, m.colorA), sina, cosa); - } - else - { - FillSprite(pv, M.k, M.i, m.pos, lt, rb, r_x, r_y, color_rgba_f(m.colorR, m.colorG, m.colorB, m.colorA), sina, cosa); - } + M.mulA_43(pPE->m_XFORM); + FillSprite(pv, M.k, M.i, wp_eff, lt, rb, r_x, r_y, color_rgba_f(m.colorR, m.colorG, m.colorB, m.colorA), sina, cosa); } - else if ((speed >= EPS_S) && pPE->m_Def->m_Flags.is(CPEDef::dfFaceAlign)) + else { - Fmatrix M; - M.identity(); - M.k.div(m.vel, speed); - M.j.set(0, 1, 0); - if (_abs(M.j.dotproduct(M.k)) > .99f) - M.j.set(0, 0, 1); - M.i.crossproduct(M.j, M.k); - M.i.normalize(); - M.j.crossproduct(M.k, M.i); - M.j.normalize(); - if (pPE->m_RT_Flags.is(CParticleEffect::flRT_XFORM)) - { - Fvector p; - pPE->m_XFORM.transform_tiny(p, m.pos); - M.mulA_43(pPE->m_XFORM); - FillSprite(pv, M.j, M.i, p, lt, rb, r_x, r_y, color_rgba_f(m.colorR, m.colorG, m.colorB, m.colorA), sina, cosa); - } - else - { - FillSprite(pv, M.j, M.i, m.pos, lt, rb, r_x, r_y, color_rgba_f(m.colorR, m.colorG, m.colorB, m.colorA), sina, cosa); - } + FillSprite(pv, M.k, M.i, m.posI, lt, rb, r_x, r_y, color_rgba_f(m.colorR, m.colorG, m.colorB, m.colorA), sina, cosa); + } + } + else if ((speed >= EPS_S) && pPE->m_Def->m_Flags.is(CPEDef::dfFaceAlign)) + { + Fmatrix M; + M.identity(); + M.k.div(m.velI, speed); + M.j.set(0, 1, 0); + if (_abs(M.j.dotproduct(M.k)) > .99f) + M.j.set(0, 0, 1); + M.i.crossproduct(M.j, M.k); + M.i.normalize(); + M.j.crossproduct(M.k, M.i); + M.j.normalize(); + if (pPE->m_RT_Flags.is(CParticleEffect::flRT_XFORM)) + { + M.mulA_43(pPE->m_XFORM); + FillSprite(pv, M.j, M.i, wp_eff, lt, rb, r_x, r_y, color_rgba_f(m.colorR, m.colorG, m.colorB, m.colorA), sina, cosa); } else { - Fvector dir; - if (speed >= EPS_S) - dir.div(m.vel, speed); - else - dir.setHP(-pPE->m_Def->m_APDefaultRotation.y, -pPE->m_Def->m_APDefaultRotation.x); - if (pPE->m_RT_Flags.is(CParticleEffect::flRT_XFORM)) - { - Fvector p, d; - pPE->m_XFORM.transform_tiny(p, m.pos); - pPE->m_XFORM.transform_dir(d, dir); - FillSprite(pv, p, d, lt, rb, r_x, r_y, color_rgba_f(m.colorR, m.colorG, m.colorB, m.colorA), sina, cosa); - } - else - { - FillSprite(pv, m.pos, dir, lt, rb, r_x, r_y, color_rgba_f(m.colorR, m.colorG, m.colorB, m.colorA), sina, cosa); - } + FillSprite(pv, M.j, M.i, m.posI, lt, rb, r_x, r_y, color_rgba_f(m.colorR, m.colorG, m.colorB, m.colorA), sina, cosa); } } else { + Fvector dir; + if (speed >= EPS_S) + dir.div(m.velI, speed); + else + dir.setHP(-pPE->m_Def->m_APDefaultRotation.y, -pPE->m_Def->m_APDefaultRotation.x); if (pPE->m_RT_Flags.is(CParticleEffect::flRT_XFORM)) { - Fvector p; - pPE->m_XFORM.transform_tiny(p, m.pos); - FillSprite(pv, RDEVICE.vCameraTop, RDEVICE.vCameraRight, p, lt, rb, r_x, r_y, color_rgba_f(m.colorR, m.colorG, m.colorB, m.colorA), sina, cosa); + Fvector d; + pPE->m_XFORM.transform_dir(d, dir); + FillSprite(pv, wp_eff, d, lt, rb, r_x, r_y, color_rgba_f(m.colorR, m.colorG, m.colorB, m.colorA), sina, cosa); } else { - FillSprite(pv, RDEVICE.vCameraTop, RDEVICE.vCameraRight, m.pos, lt, rb, r_x, r_y, color_rgba_f(m.colorR, m.colorG, m.colorB, m.colorA), sina, cosa); + FillSprite(pv, m.posI, dir, lt, rb, r_x, r_y, color_rgba_f(m.colorR, m.colorG, m.colorB, m.colorA), sina, cosa); } } } + else + { + if (pPE->m_RT_Flags.is(CParticleEffect::flRT_XFORM)) + { + FillSprite(pv, RDEVICE.vCameraTop, RDEVICE.vCameraRight, wp_eff, lt, rb, r_x, r_y, color_rgba_f(m.colorR, m.colorG, m.colorB, m.colorA), sina, cosa); + } + else + { + FillSprite(pv, RDEVICE.vCameraTop, RDEVICE.vCameraRight, m.posI, lt, rb, r_x, r_y, color_rgba_f(m.colorR, m.colorG, m.colorB, m.colorA), sina, cosa); + } + } + } + return false; } void CParticleEffect::Render(float) @@ -586,19 +666,22 @@ void CParticleEffect::Render(float) if (m_Def && m_Def->m_Flags.is(CPEDef::dfSprite)) { FVF::LIT* pv_start = (FVF::LIT*)RCache.Vertex.Lock(p_cnt * 4 * 4, geom->vb_stride, dwOffset); - ParticleRenderStream(pv_start, p_cnt, particles, this); + bool NeedExit = ParticleRenderStream(pv_start, p_cnt, particles, this); dwCount = p_cnt << 2; RCache.Vertex.Unlock(dwCount, geom->vb_stride); + + if (NeedExit) + return; + if (dwCount) { #ifndef _EDITOR - Fmatrix FTold = Device.mFullTransform; + CHudInitializer initalizer(false); if (GetHudMode()) { - Device.mFullTransform = Device.mFullTransformHud; - RCache.set_xform_project(Device.mProjectHud); + initalizer.SetHudMode(); RImplementation.rmNear(); ApplyTexgen(Device.mFullTransform); } @@ -616,8 +699,7 @@ void CParticleEffect::Render(float) if (GetHudMode()) { RImplementation.rmNormal(); - Device.mFullTransform = FTold; - RCache.set_xform_project(Device.mProject); + initalizer.SetDefaultMode(); ApplyTexgen(Device.mFullTransform); } #endif @@ -760,12 +842,11 @@ void CParticleEffect::Render(float ) if (dwCount) { #ifndef _EDITOR - Fmatrix FTold = Device.mFullTransform; - if(GetHudMode()) + CHudInitializer initalizer(false); + if (GetHudMode()) { - Device.mFullTransform = Device.mFullTransformHud; - RCache.set_xform_project(Device.mProjectHud); - RImplementation.rmNear (); + initalizer.SetHudMode(); + RImplementation.rmNear(); ApplyTexgen(Device.mFullTransform); } #endif @@ -779,9 +860,8 @@ void CParticleEffect::Render(float ) #ifndef _EDITOR if(GetHudMode()) { - RImplementation.rmNormal (); - Device.mFullTransform = FTold; - RCache.set_xform_project (Device.mProject); + RImplementation.rmNormal(); + initalizer.SetDefaultMode(); ApplyTexgen(Device.mFullTransform); } #endif diff --git a/src/Layers/xrRender/ParticleEffect.h b/src/Layers/xrRender/ParticleEffect.h index 5c69ff61d5..c59f541c03 100644 --- a/src/Layers/xrRender/ParticleEffect.h +++ b/src/Layers/xrRender/ParticleEffect.h @@ -41,6 +41,7 @@ namespace PS flRT_DefferedStop = (1 << 1), flRT_XFORM = (1 << 2), flRT_HUDmode = (1 << 3), + flRT_LiveUpdate = (1 << 4), }; Flags8 m_RT_Flags; @@ -77,6 +78,9 @@ namespace PS virtual void SetHudMode(BOOL b) { m_RT_Flags.set(flRT_HUDmode, b); } virtual BOOL GetHudMode() { return m_RT_Flags.is(flRT_HUDmode); } + virtual void SetLiveUpdate(BOOL b) { m_RT_Flags.set(flRT_LiveUpdate, b); } + virtual BOOL GetLiveUpdate() { return m_RT_Flags.is(flRT_LiveUpdate); } + virtual float GetTimeLimit() { VERIFY(m_Def); diff --git a/src/Layers/xrRender/ParticleGroup.cpp b/src/Layers/xrRender/ParticleGroup.cpp index 7eec255bfc..e313f991cc 100644 --- a/src/Layers/xrRender/ParticleGroup.cpp +++ b/src/Layers/xrRender/ParticleGroup.cpp @@ -50,7 +50,8 @@ void CPGDef::Clone (CPGDef* source) //------------------------------------------------------------------------------ BOOL CPGDef::Load(IReader& F) { - R_ASSERT(F.find_chunk(PGD_CHUNK_VERSION)); + bool FoundedChunk = !!F.find_chunk(PGD_CHUNK_VERSION); + R_ASSERT2(FoundedChunk, "Not found chunk PGD_CHUNK_VERSION"); u16 version = F.r_u16(); if (version != PGD_VERSION) @@ -59,7 +60,8 @@ BOOL CPGDef::Load(IReader& F) return FALSE; } - R_ASSERT(F.find_chunk(PGD_CHUNK_NAME)); + FoundedChunk = !!F.find_chunk(PGD_CHUNK_NAME); + R_ASSERT2(FoundedChunk, "Not found chunk PGD_CHUNK_NAME"); F.r_stringZ(m_Name); F.r_chunk(PGD_CHUNK_FLAGS, &m_Flags); @@ -180,6 +182,28 @@ void CPGDef::Save2(CInifile& ini) ini.w_float("_group", "timelimit", m_fTimeLimit); } +PS::CParticleGroup::SItem::~SItem() +{ + if (_children_destroy.empty()) + return; + + auto Callback = xr_make_delegate(this, &PS::CParticleGroup::SItem::DelayDeleteChilds); + xrCriticalSectionGuard guard(&Device.seqParallelBeforRenderCS); + auto Iter = std::find(Device.seqParallelBeforRender.begin(), Device.seqParallelBeforRender.end(), Callback); + if (Iter != Device.seqParallelBeforRender.end()) + { + // Cancel in place rather than erasing. This destructor can run from + // inside the main thread's drain loop in CRenderDevice::on_idle, when + // an invoked callback destroys an object owning this particle group + // (CObjectList::ProcessDestroyQueue is registered in the same vector). + // Erasing there would invalidate the loop's iteration; clearing the + // entry leaves the size untouched. The drain skips cleared entries and + // clear()s the whole vector once it finishes, so the callback is never + // invoked on a destroyed SItem either way. + Iter->clear(); + } +} + //------------------------------------------------------------------------------ // Particle Group item //------------------------------------------------------------------------------ @@ -194,9 +218,18 @@ void CParticleGroup::SItem::Clear() GetVisuals(visuals); for (VisualVecIt it = visuals.begin(); it != visuals.end(); it++) { - //::Render->model_Delete(*it); - IRenderVisual* pVisual = smart_cast(*it); - ::Render->model_Delete(pVisual); + auto Iter = std::find(_children_destroy.begin(), _children_destroy.end(), *it); + if (_children_destroy.empty() || Iter == _children_destroy.end()) + { + IRenderVisual* pVisual = smart_cast(*it); + ::Render->model_Delete_Deffered(pVisual); + } +#ifdef DEBUG + else + { + Msg("!Found deleted model"); + } +#endif *it = 0; } @@ -217,7 +250,7 @@ void CParticleGroup::SItem::StartRelatedChild(CParticleEffect* emitter, LPCSTR e M.identity(); Fvector vel; vel.sub(m.pos, m.posB); - vel.div(C->m_Def->GetFStep()); + vel.div(C->m_RT_Flags.is(CParticleEffect::flRT_LiveUpdate) ? Device.fTimeDelta : C->m_Def->GetFStep()); if (emitter->m_RT_Flags.is(CParticleEffect::flRT_XFORM)) { M.set(emitter->m_XFORM); @@ -251,7 +284,7 @@ void CParticleGroup::SItem::StartFreeChild(CParticleEffect* emitter, LPCSTR nm, M.identity(); Fvector vel; vel.sub(m.pos, m.posB); - vel.div(C->m_Def->GetFStep()); + vel.div(C->m_RT_Flags.is(CParticleEffect::flRT_LiveUpdate) ? Device.fTimeDelta : C->m_Def->GetFStep()); if (emitter->m_RT_Flags.is(CParticleEffect::flRT_XFORM)) { M.set(emitter->m_XFORM); @@ -276,43 +309,40 @@ void CParticleGroup::SItem::StartFreeChild(CParticleEffect* emitter, LPCSTR nm, void CParticleGroup::SItem::Play() { - CParticleEffect* E = static_cast(_effect); - if (E) E->Play(); + if (_effect == nullptr) + return; + + static_cast(_effect)->Play(); } void CParticleGroup::SItem::Stop(BOOL def_stop) { - // stop all effects - CParticleEffect* E = static_cast(_effect); - if (E) E->Stop(def_stop); - VisualVecIt it; - for (it = _children_related.begin(); it != _children_related.end(); it++) - static_cast(*it)->Stop(def_stop); - for (it = _children_free.begin(); it != _children_free.end(); it++) - static_cast(*it)->Stop(def_stop); - // and delete if !deffered - if (!def_stop) + /// stop all effects + if (CParticleEffect* E = static_cast(_effect)) { - for (it = _children_related.begin(); it != _children_related.end(); it++) + E->Stop(def_stop); + } + + for (dxRender_Visual* ChildPart : _children_related) + { + static_cast(ChildPart)->Stop(def_stop); + if (!def_stop) { - //::Render->model_Delete(*it); - IRenderVisual* pVisual = smart_cast(*it); - ::Render->model_Delete(pVisual); - *it = 0; + _children_destroy.insert(ChildPart); } - for (it = _children_free.begin(); it != _children_free.end(); it++) + } + + for (dxRender_Visual* ChildPart : _children_free) + { + static_cast(ChildPart)->Stop(def_stop); + if (!def_stop) { - //::Render->model_Delete(*it); - IRenderVisual* pVisual = smart_cast(*it); - ::Render->model_Delete(pVisual); - *it = 0; + _children_destroy.insert(ChildPart); } - _children_related.clear(); - _children_free.clear(); } } -BOOL CParticleGroup::SItem::IsPlaying() +BOOL CParticleGroup::SItem::IsPlaying() const { CParticleEffect* E = static_cast(_effect); return E ? E->IsPlaying() : FALSE; @@ -389,7 +419,7 @@ void CParticleGroup::SItem::OnFrame(u32 u_dt, const CPGDef::SEffect& def, Fbox& M.translate(m.pos); Fvector vel; vel.sub(m.pos, m.posB); - vel.div(C->m_Def->GetFStep()); + vel.div(C->m_RT_Flags.is(CParticleEffect::flRT_LiveUpdate) ? Device.fTimeDelta : C->m_Def->GetFStep()); C->UpdateParent(M, vel,FALSE); } } @@ -437,18 +467,20 @@ void CParticleGroup::SItem::OnFrame(u32 u_dt, const CPGDef::SEffect& def, Fbox& else { rem_cnt++; - //::Render->model_Delete(*it); IRenderVisual* pVisual = smart_cast(*it); - ::Render->model_Delete(pVisual); - *it = 0; + _children_destroy.insert(*it); } } } - // remove if stopped - if (rem_cnt) + + if (!_children_destroy.empty()) { - VisualVecIt new_end = std::remove_if(_children_free.begin(), _children_free.end(), zero_vis_pred()); - _children_free.erase(new_end, _children_free.end()); + auto Callback = xr_make_delegate(this, &PS::CParticleGroup::SItem::DelayDeleteChilds); + xrCriticalSectionGuard guard(&Device.seqParallelBeforRenderCS); + if (std::find(Device.seqParallelBeforRender.begin(), Device.seqParallelBeforRender.end(), Callback) == Device.seqParallelBeforRender.end()) + { + Device.seqParallelBeforRender.emplace_back(std::move(Callback)); + } } } // Msg("C: %d CS: %d",_children.size(),_children_stopped.size()); @@ -480,6 +512,31 @@ u32 CParticleGroup::SItem::ParticlesCount() return p_count; } +void PS::CParticleGroup::SItem::DelayDeleteChilds() +{ + for (dxRender_Visual* Vis : _children_destroy) + { + auto Iter = std::find(_children_free.begin(), _children_free.end(), Vis); + if (Iter != _children_free.end()) + { + _children_free.erase(Iter); + } + else + { + Iter = std::find(_children_related.begin(), _children_related.end(), Vis); + if (Iter != _children_related.end()) + { + _children_related.erase(Iter); + } + } + + IRenderVisual* pVisual = smart_cast(Vis); + ::Render->model_Delete_Deffered(pVisual); + } + + _children_destroy.clear(); +} + //------------------------------------------------------------------------------ // Particle Group part @@ -492,6 +549,7 @@ CParticleGroup::CParticleGroup() CParticleGroup::~CParticleGroup() { + xrCriticalSectionGuard guard(&onframe_lock); // Msg ("!!! destoy PG"); for (u32 i = 0; i < items.size(); i++) items[i].Clear(); items.clear(); @@ -499,43 +557,61 @@ CParticleGroup::~CParticleGroup() void CParticleGroup::OnFrame(u32 u_dt) { + xrCriticalSectionGuard guard(&onframe_lock); if (m_Def && m_RT_Flags.is(flRT_Playing)) { - float ct = m_CurrentTime; - float f_dt = float(u_dt) / 1000.f; - for (CPGDef::EffectVec::const_iterator e_it = m_Def->m_Effects.begin(); e_it != m_Def->m_Effects.end(); e_it++) + float fdeltaTime = float(u_dt) / 1000.f; + u32 iter = 0; + + for (PS::CPGDef::SEffect* pEffect : m_Def->m_Effects) { - if ((*e_it)->m_Flags.is(CPGDef::SEffect::flEnabled)) + if (pEffect->m_Flags.is(CPGDef::SEffect::flEnabled)) { - VERIFY(items.size()==m_Def->m_Effects.size()); - SItem& I = items[e_it - m_Def->m_Effects.begin()]; - if (I.IsPlaying()) + VERIFY(items.size() == m_Def->m_Effects.size()); + + SItem& particleRenderItem = items[iter]; + if (particleRenderItem.IsPlaying()) { - if ((ct <= (*e_it)->m_Time1) && (ct + f_dt >= (*e_it)->m_Time1)) - I.Stop((*e_it)->m_Flags.is(CPGDef::SEffect::flDefferedStop)); + if ((m_CurrentTime <= pEffect->m_Time1) && (m_CurrentTime + fdeltaTime >= pEffect->m_Time1)) + { + particleRenderItem.Stop(pEffect->m_Flags.is(CPGDef::SEffect::flDefferedStop)); + } } else { if (!m_RT_Flags.is(flRT_DefferedStop)) - if ((ct <= (*e_it)->m_Time0) && (ct + f_dt >= (*e_it)->m_Time0)) - I.Play(); + { + if ((m_CurrentTime <= pEffect->m_Time0) && (m_CurrentTime + fdeltaTime >= pEffect->m_Time0)) + { + particleRenderItem.Play(); + } + } } } + ++iter; + } + + m_CurrentTime += fdeltaTime; + if ((m_Def->m_fTimeLimit > 0.f) && (m_CurrentTime > m_Def->m_fTimeLimit)) + { + if (!m_RT_Flags.is(flRT_DefferedStop)) + { + Stop(true); + } } - m_CurrentTime += f_dt; - if ((m_CurrentTime > m_Def->m_fTimeLimit) && (m_Def->m_fTimeLimit > 0.f)) - if (!m_RT_Flags.is(flRT_DefferedStop)) Stop(true); bool bPlaying = false; - Fbox box; - box.invalidate(); - for (SItemVecIt i_it = items.begin(); i_it != items.end(); i_it++) + Fbox box; box.invalidate(); + for (auto i_it = items.begin(); i_it != items.end(); i_it++) + { i_it->OnFrame(u_dt, *m_Def->m_Effects[i_it - items.begin()], box, bPlaying); + } if (m_RT_Flags.is(flRT_DefferedStop) && !bPlaying) { - m_RT_Flags.set(flRT_Playing | flRT_DefferedStop,FALSE); + m_RT_Flags.set(flRT_Playing | flRT_DefferedStop, FALSE); } + if (box.is_valid()) { vis.box.set(box); @@ -552,17 +628,19 @@ void CParticleGroup::OnFrame(u32 u_dt) void CParticleGroup::UpdateParent(const Fmatrix& m, const Fvector& velocity, BOOL bXFORM) { + xrCriticalSectionGuard guard(&onframe_lock); m_InitialPosition = m.c; - for (SItemVecIt i_it = items.begin(); i_it != items.end(); i_it++) - i_it->UpdateParent(m, velocity, bXFORM); + for (SItem& item : items) + item.UpdateParent(m, velocity, bXFORM); } BOOL CParticleGroup::Compile(CPGDef* def) { + xrCriticalSectionGuard guard(&onframe_lock); m_Def = def; // destroy existing - for (SItemVecIt i_it = items.begin(); i_it != items.end(); i_it++) - i_it->Clear(); + for (SItem& item : items) + item.Clear(); items.clear(); // create new if (m_Def) @@ -587,6 +665,7 @@ void CParticleGroup::Play() void CParticleGroup::Stop(BOOL bDefferedStop) { + xrCriticalSectionGuard guard(&onframe_lock); if (bDefferedStop) { m_RT_Flags.set(flRT_DefferedStop,TRUE); @@ -595,43 +674,73 @@ void CParticleGroup::Stop(BOOL bDefferedStop) { m_RT_Flags.set(flRT_Playing,FALSE); } - for (SItemVecIt i_it = items.begin(); i_it != items.end(); i_it++) i_it->Stop(bDefferedStop); + for (SItem& item : items) + item.Stop(bDefferedStop); } void CParticleGroup::OnDeviceCreate() { - for (SItemVecIt i_it = items.begin(); i_it != items.end(); i_it++) i_it->OnDeviceCreate(); + xrCriticalSectionGuard guard(&onframe_lock); + for (SItem& item : items) + item.OnDeviceCreate(); } void CParticleGroup::OnDeviceDestroy() { - for (SItemVecIt i_it = items.begin(); i_it != items.end(); i_it++) i_it->OnDeviceDestroy(); + xrCriticalSectionGuard guard(&onframe_lock); + for (SItem& item : items) + item.OnDeviceDestroy(); } u32 CParticleGroup::ParticlesCount() { + xrCriticalSectionGuard guard(&onframe_lock); int p_count = 0; - for (SItemVecIt i_it = items.begin(); i_it != items.end(); i_it++) - p_count += i_it->ParticlesCount(); + for (SItem& item : items) + p_count += item.ParticlesCount(); return p_count; } void CParticleGroup::SetHudMode(BOOL b) { - for (SItemVecIt i_it = items.begin(); i_it != items.end(); ++i_it) + xrCriticalSectionGuard guard(&onframe_lock); + for (SItem& item : items) { - CParticleEffect* E = static_cast(i_it->_effect); + CParticleEffect* E = static_cast(item._effect); E->SetHudMode(b); } } BOOL CParticleGroup::GetHudMode() { + xrCriticalSectionGuard guard(&onframe_lock); if (items.size()) { CParticleEffect* E = static_cast(items[0]._effect); return E->GetHudMode(); } - else - return FALSE; + + return FALSE; +} + +void CParticleGroup::SetLiveUpdate(BOOL b) +{ + xrCriticalSectionGuard guard(&onframe_lock); + for (SItem& item : items) + { + CParticleEffect* E = static_cast(item._effect); + E->SetLiveUpdate(b); + } +} + +BOOL CParticleGroup::GetLiveUpdate() +{ + xrCriticalSectionGuard guard(&onframe_lock); + if(items.size()) + { + CParticleEffect* E = static_cast(items[0]._effect); + return E->GetLiveUpdate(); + } + + return FALSE; } diff --git a/src/Layers/xrRender/ParticleGroup.h b/src/Layers/xrRender/ParticleGroup.h index 9699c7b1d1..230159c6ba 100644 --- a/src/Layers/xrRender/ParticleGroup.h +++ b/src/Layers/xrRender/ParticleGroup.h @@ -81,24 +81,32 @@ namespace PS float m_CurrentTime; Fvector m_InitialPosition; public: - DEFINE_VECTOR(dxRender_Visual*, VisualVec, VisualVecIt); + xrCriticalSection onframe_lock; + using VisualVec = xr_vector; + using VisualVecIt = VisualVec::iterator; struct SItem { dxRender_Visual* _effect; VisualVec _children_related; VisualVec _children_free; + xr_set _children_destroy; + public: + ~SItem(); + void Set(dxRender_Visual* e); void Clear(); IC u32 GetVisuals(xr_vector& visuals) { visuals.reserve(_children_related.size() + _children_free.size() + 1); - if (_effect) visuals.push_back(_effect); + if (_effect) + visuals.push_back(_effect); + visuals.insert(visuals.end(), _children_related.begin(), _children_related.end()); visuals.insert(visuals.end(), _children_free.begin(), _children_free.end()); - return visuals.size(); + return u32(visuals.size()); } void OnDeviceCreate(); @@ -110,9 +118,10 @@ namespace PS void UpdateParent(const Fmatrix& m, const Fvector& velocity, BOOL bXFORM); void OnFrame(u32 u_dt, const CPGDef::SEffect& def, Fbox& box, bool& bPlaying); + void DelayDeleteChilds(); u32 ParticlesCount(); - BOOL IsPlaying(); + BOOL IsPlaying() const; void Play(); void Stop(BOOL def_stop); }; @@ -153,6 +162,9 @@ namespace PS virtual void SetHudMode(BOOL b); virtual BOOL GetHudMode(); + virtual void SetLiveUpdate(BOOL b); + virtual BOOL GetLiveUpdate(); + virtual float GetTimeLimit() { VERIFY(m_Def); diff --git a/src/Layers/xrRender/QueryHelper.h b/src/Layers/xrRender/QueryHelper.h index 30563e1ccb..a9677b13d0 100644 --- a/src/Layers/xrRender/QueryHelper.h +++ b/src/Layers/xrRender/QueryHelper.h @@ -2,12 +2,6 @@ #define QueryHelper_included #pragma once -// Interface -IC HRESULT CreateQuery(ID3DQuery** ppQuery, D3DQUERYTYPE Type); -IC HRESULT GetData(ID3DQuery* pQuery, void* pData, UINT DataSize); -IC HRESULT BeginQuery(ID3DQuery* pQuery); -IC HRESULT EndQuery(ID3DQuery* pQuery); - // Implementation #if defined(USE_DX11) @@ -29,10 +23,10 @@ IC HRESULT CreateQuery ( ID3DQuery **ppQuery, D3DQUERYTYPE Type) return HW.pDevice->CreateQuery( &desc, ppQuery); } -IC HRESULT GetData( ID3DQuery *pQuery, void *pData, UINT DataSize ) +IC HRESULT GetData( ID3DQuery *pQuery, void *pData, UINT DataSize, UINT Flags = 0 ) { // Use D3Dxx_ASYNC_GETDATA_DONOTFLUSH for prevent flushing - return HW.pContext->GetData(pQuery, pData, DataSize, 0); + return HW.pContext->GetData(pQuery, pData, DataSize, Flags); } IC HRESULT BeginQuery( ID3DQuery *pQuery) @@ -66,10 +60,10 @@ IC HRESULT CreateQuery(ID3DQuery** ppQuery, D3DQUERYTYPE Type) return HW.pDevice->CreateQuery(&desc, ppQuery); } -IC HRESULT GetData(ID3DQuery* pQuery, void* pData, UINT DataSize) +IC HRESULT GetData(ID3DQuery* pQuery, void* pData, UINT DataSize, UINT Flags = 0) { // Use D3Dxx_ASYNC_GETDATA_DONOTFLUSH for prevent flushing - return pQuery->GetData(pData, DataSize, 0); + return pQuery->GetData(pData, DataSize, Flags); } IC HRESULT BeginQuery(ID3DQuery* pQuery) @@ -91,7 +85,7 @@ IC HRESULT CreateQuery ( ID3DQuery **ppQuery, D3DQUERYTYPE Type) return HW.pDevice->CreateQuery(Type, ppQuery); } -IC HRESULT GetData( ID3DQuery *pQuery, void *pData, UINT DataSize ) +IC HRESULT GetData( ID3DQuery *pQuery, void *pData, UINT DataSize, UINT Flags = 0 ) { return pQuery->GetData( pData, DataSize, D3DGETDATA_FLUSH); } diff --git a/src/Layers/xrRender/R_Backend.cpp b/src/Layers/xrRender/R_Backend.cpp index ce2932669c..4ae6745d94 100644 --- a/src/Layers/xrRender/R_Backend.cpp +++ b/src/Layers/xrRender/R_Backend.cpp @@ -16,9 +16,9 @@ void CBackend::RestoreQuadIBData() void CBackend::CreateQuadIB() { - static const u32 dwTriCount = 4 * 1024; - static const u32 dwIdxCount = dwTriCount * 2 * 3; - u16 IndexBuffer[dwIdxCount]; + constexpr u32 dwTriCount = 4 * (4096 * 8); + constexpr u32 dwIdxCount = dwTriCount * 2 * 3; + static u16 IndexBuffer[dwIdxCount]; u16* Indices = IndexBuffer; D3D_BUFFER_DESC desc; diff --git a/src/Layers/xrRender/R_Backend.h b/src/Layers/xrRender/R_Backend.h index 7bbe6624cc..24b4575bc3 100644 --- a/src/Layers/xrRender/R_Backend.h +++ b/src/Layers/xrRender/R_Backend.h @@ -222,24 +222,26 @@ class ECORE_API CBackend public: IC CTexture* get_ActiveTexture(u32 stage) { - if (stage < CTexture::rstVertex) return textures_ps[stage]; - else if (stage < CTexture::rstGeometry) return textures_vs[stage - CTexture::rstVertex]; + CTexture* T = NULL; + if (stage < CTexture::rstVertex) T = textures_ps[stage]; + else if (stage < CTexture::rstGeometry) T = textures_vs[stage - CTexture::rstVertex]; #ifdef USE_DX10 - else return textures_gs[stage - CTexture::rstGeometry]; + else T = textures_gs[stage - CTexture::rstGeometry]; #elif USE_DX11 - else if (stage < CTexture::rstHull) return textures_gs[stage - CTexture::rstGeometry]; - else if (stage < CTexture::rstDomain) return textures_hs[stage - CTexture::rstHull]; - else if (stage < CTexture::rstCompute) return textures_ds[stage - CTexture::rstDomain]; - else if (stage < CTexture::rstInvalid) return textures_cs[stage - CTexture::rstCompute]; + else if (stage < CTexture::rstHull) T = textures_gs[stage - CTexture::rstGeometry]; + else if (stage < CTexture::rstDomain) T = textures_hs[stage - CTexture::rstHull]; + else if (stage < CTexture::rstCompute) T = textures_ds[stage - CTexture::rstDomain]; + else if (stage < CTexture::rstInvalid) T = textures_cs[stage - CTexture::rstCompute]; else { VERIFY(!"Invalid texture stage"); - return 0; } -#else // USE_DX10 - VERIFY(!"Invalid texture stage"); - return 0; -#endif // USE_DX10 +#endif + while (T&&!T->flags.bLoaded) + { + SwitchToThread(); + } + return T; } #if defined(USE_DX10) || defined(USE_DX11) diff --git a/src/Layers/xrRender/R_Backend_Runtime.cpp b/src/Layers/xrRender/R_Backend_Runtime.cpp index adca0cf5fe..e04c895ca0 100644 --- a/src/Layers/xrRender/R_Backend_Runtime.cpp +++ b/src/Layers/xrRender/R_Backend_Runtime.cpp @@ -208,6 +208,7 @@ void CBackend::set_ClipPlanes(u32 _enable, Fmatrix* _xform /*=NULL */, u32 fmask void CBackend::set_Textures(STextureList* _T) { + PROF_EVENT("set_Textures"); if (T == _T) return; T = _T; // If resources weren't set at all we should clear from resource #0. diff --git a/src/Layers/xrRender/R_Backend_Runtime.h b/src/Layers/xrRender/R_Backend_Runtime.h index 662be456db..3a94ef2963 100644 --- a/src/Layers/xrRender/R_Backend_Runtime.h +++ b/src/Layers/xrRender/R_Backend_Runtime.h @@ -133,7 +133,8 @@ IC ID3DDepthStencilView* CBackend::get_ZB() } ICF void CBackend::set_States(ID3DState* _state) -{ + { + PROF_EVENT("CBackend::set_States"); // DX10 Manages states using it's own algorithm. Don't mess with it. #if !defined(USE_DX10) && !defined(USE_DX11) if (state != _state) @@ -172,7 +173,10 @@ IC void CBackend::set_Matrices (SMatrixList* _M) #endif IC void CBackend::set_Element(ShaderElement* S, u32 pass) -{ + { + PROF_EVENT("CBackend::set_Element"); + if (!S->passes[pass]) + return; SPass& P = *(S->passes[pass]); set_States(P.state); set_PS(P.ps); diff --git a/src/Layers/xrRenderPC_R3/r2_R_calculate.cpp b/src/Layers/xrRender/R_calculate.cpp similarity index 53% rename from src/Layers/xrRenderPC_R3/r2_R_calculate.cpp rename to src/Layers/xrRender/R_calculate.cpp index 10bc156d00..89e762f8e9 100644 --- a/src/Layers/xrRenderPC_R3/r2_R_calculate.cpp +++ b/src/Layers/xrRender/R_calculate.cpp @@ -29,7 +29,7 @@ void CRender::Calculate() // Detect camera-sector if (!vLastCameraPos.similar(Device.vCameraPosition, EPS_S)) { - CSector* pSector = (CSector*)detectSector(Device.vCameraPosition); + CSector* pSector = (CSector*)detectLastSector(Device.vCameraPosition); if (pSector && (pSector != pLastSector)) g_pGamePersistent->OnSectorChanged(translateSector(pSector)); @@ -38,38 +38,5 @@ void CRender::Calculate() vLastCameraPos.set(Device.vCameraPosition); } - // Check if camera is too near to some portal - if so force DualRender - if (rmPortals) - { - float eps = VIEWPORT_NEAR + EPS_L; - Fvector box_radius; - box_radius.set(eps, eps, eps); - Sectors_xrc.box_options(CDB::OPT_FULL_TEST); - Sectors_xrc.box_query(rmPortals, Device.vCameraPosition, box_radius); - for (int K = 0; K < Sectors_xrc.r_count(); K++) - { - CPortal* pPortal = (CPortal*)Portals[rmPortals->get_tris()[Sectors_xrc.r_begin()[K].id].dummy]; - pPortal->bDualRender = TRUE; - } - } - - // Lights.Update(); - - // Check if we touch some light even trough portal - lstRenderables.clear(); - g_SpatialSpace->q_sphere(lstRenderables, 0, STYPE_LIGHTSOURCE, Device.vCameraPosition, EPS_L); - for (u32 _it = 0; _it < lstRenderables.size(); _it++) - { - ISpatial* spatial = lstRenderables[_it]; - spatial->spatial_updatesector(); - CSector* sector = (CSector*)spatial->spatial.sector; - if (0 == sector) continue; // disassociated from S/P structure - - VERIFY(spatial->spatial.type & STYPE_LIGHTSOURCE); - // lightsource - light* L = (light*)(spatial->dcast_Light()); - VERIFY(L); - Lights.add_light(L); - } } diff --git a/src/Layers/xrRender/R_sun.cpp b/src/Layers/xrRender/R_sun.cpp new file mode 100644 index 0000000000..970eece9d6 --- /dev/null +++ b/src/Layers/xrRender/R_sun.cpp @@ -0,0 +1,365 @@ +#include "stdafx.h" +#include "../../xrEngine/igame_persistent.h" +#include "../../xrEngine/irenderable.h" +#include "FBasicVisual.h" + +#include "R_sun_support.h" + +constexpr float tweak_COP_initial_offs = 1200.f; + +float OLES_SUN_LIMIT_27_01_07 = 100.f; + +////////////////////////////////////////////////////////////////////////// +// tables to calculate view-frustum bounds in world space +// note: D3D uses [0..1] range for Z +static Fvector3 corners[8] = { + {-1, -1, 0}, {-1, -1, +1}, + {-1, +1, +1}, {-1, +1, 0}, + {+1, +1, +1}, {+1, +1, 0}, + {+1, -1, +1}, {+1, -1, 0} +}; +static int facetable[6][4] = { + {6, 7, 5, 4}, {1, 0, 7, 6}, + {1, 2, 3, 0}, {3, 2, 4, 5}, + // near and far planes + {0, 3, 5, 7}, {1, 6, 4, 2}, +}; + +////////////////////////////////////////////////////////////////////////// +Fvector3 wform(Fmatrix& m, Fvector3 const& v) +{ + Fvector4 r; + r.x = v.x * m._11 + v.y * m._21 + v.z * m._31 + m._41; + r.y = v.x * m._12 + v.y * m._22 + v.z * m._32 + m._42; + r.z = v.x * m._13 + v.y * m._23 + v.z * m._33 + m._43; + r.w = v.x * m._14 + v.y * m._24 + v.z * m._34 + m._44; + // VERIFY (r.w>0.f); + float invW = 1.0f / r.w; + Fvector3 r3 = { r.x * invW, r.y * invW, r.z * invW }; + return r3; +} + +void CRender::init_cacades() +{ + u32 cascade_count = 3; + m_sun_cascades.resize(cascade_count); + + float fBias = -0.0000025f; + // float size = MAP_SIZE_START; + m_sun_cascades[0].reset_chain = true; + m_sun_cascades[0].size = ps_ssfx_shadow_cascades.x; //20 + m_sun_cascades[0].bias = m_sun_cascades[0].size * fBias; + + m_sun_cascades[1].size = ps_ssfx_shadow_cascades.y; //40 + m_sun_cascades[1].bias = m_sun_cascades[1].size * fBias; + + m_sun_cascades[2].size = ps_ssfx_shadow_cascades.z; //160 + m_sun_cascades[2].bias = m_sun_cascades[2].size * fBias; + + // for( u32 i = 0; i < cascade_count; ++i ) + // { + // m_sun_cascades[i].size = size; + // size *= MAP_GROW_FACTOR; + // } + /// m_sun_cascades[m_sun_cascades.size()-1].size = 80; +} + +void CRender::render_sun_cascades() +{ + bool b_need_to_render_sunshafts = Target->need_to_render_sunshafts(); + bool last_cascade_chain_mode = m_sun_cascades.back().reset_chain; + if (b_need_to_render_sunshafts) + m_sun_cascades[m_sun_cascades.size() - 1].reset_chain = true; + + for (u32 i = 0; i < m_sun_cascades.size(); ++i) + render_sun_cascade(i); + + if (b_need_to_render_sunshafts) + m_sun_cascades[m_sun_cascades.size() - 1].reset_chain = last_cascade_chain_mode; +} + +void CRender::render_sun_cascade(u32 cascade_ind) +{ + PROF_EVENT("Render Cascade"); + light* fuckingsun = (light*)Lights.sun_adapted._get(); + sun::cascade& cascade = m_sun_cascades[cascade_ind]; + + CFrustum& cull_frustum = cascade.cull_frustum; + xr_vector cull_planes; + Fvector3& cull_COP = cascade.cull_COP; + Fmatrix& cull_xform = cascade.cull_xform; + + { + PROF_EVENT("Render Cascade: Prepass"); + + // calculate view-frustum bounds in world space + Fmatrix ex_project, ex_full, ex_full_inverse; + { + ex_project = Device.mProject; + ex_full.mul(ex_project, Device.mView); + D3DXMatrixInverse((D3DXMATRIX*)&ex_full_inverse, 0, (D3DXMATRIX*)&ex_full); + } + + // Compute volume(s) - something like a frustum for infinite directional light + // Also compute virtual light position and sector it is inside + { + FPU::m64r(); + // Lets begin from base frustum + Fmatrix fullxform_inv = ex_full_inverse; + //******************************* Need to be placed after cuboid built ************************** + + // COP - 100 km away + cull_COP.mad(Device.vCameraPosition, fuckingsun->direction, -tweak_COP_initial_offs); + + // Create approximate ortho-xform + // view: auto find 'up' and 'right' vectors + Fmatrix mdir_View, mdir_Project; + Fvector L_dir, L_up, L_right, L_pos; + L_pos.set(fuckingsun->position); + L_dir.set(fuckingsun->direction).normalize(); + L_right.set(1, 0, 0); + if (_abs(L_right.dotproduct(L_dir)) > .99f) L_right.set(0, 0, 1); + L_up.crossproduct(L_dir, L_right).normalize(); + L_right.crossproduct(L_up, L_dir).normalize(); + mdir_View.build_camera_dir(L_pos, L_dir, L_up); + + + ////////////////////////////////////////////////////////////////////////// + #ifdef _DEBUG + typedef FixedConvexVolume t_cuboid; + #else + typedef FixedConvexVolume t_cuboid; + #endif + + static t_cuboid light_cuboid; + light_cuboid.view_frustum_rays.clear(); + { + // Initialize the first cascade rays, then each cascade will initialize rays for next one. + if (cascade_ind == 0 || cascade.reset_chain) + { + Fvector3 near_p, edge_vec; + for (int p = 0; p < 4; p++) + { + // Fvector asd = Device.vCameraDirection; + // asd.mul(-2); + // asd.add(Device.vCameraPosition); + // near_p = Device.vCameraPosition;//wform (fullxform_inv,asd); // + near_p = wform(fullxform_inv, corners[facetable[4][p]]); + + edge_vec = wform(fullxform_inv, corners[facetable[5][p]]); + edge_vec.sub(near_p); + edge_vec.normalize(); + + light_cuboid.view_frustum_rays.push_back(sun::ray(near_p, edge_vec)); + } + } + else + light_cuboid.view_frustum_rays = cascade.rays; + + light_cuboid.view_ray.P = Device.vCameraPosition; + light_cuboid.view_ray.D = Device.vCameraDirection; + light_cuboid.light_ray.P = L_pos; + light_cuboid.light_ray.D = L_dir; + } + + // THIS NEED TO BE A CONSTATNT + Fplane light_top_plane; + light_top_plane.build_unit_normal(L_pos, L_dir); + float dist = light_top_plane.classify(Device.vCameraPosition); + + float map_size = cascade.size; + D3DXMatrixOrthoOffCenterLH((D3DXMATRIX*)&mdir_Project, -map_size * 0.5f, map_size * 0.5f, -map_size * 0.5f, + map_size * 0.5f, 0.1, dist + map_size); + + // build viewport xform + float view_dim = float(o.smapsize); + Fmatrix m_viewport = { + view_dim / 2.f, 0.0f, 0.0f, 0.0f, + 0.0f, -view_dim / 2.f, 0.0f, 0.0f, + 0.0f, 0.0f, 1.0f, 0.0f, + view_dim / 2.f, view_dim / 2.f, 0.0f, 1.0f + }; + Fmatrix m_viewport_inv; + D3DXMatrixInverse((D3DXMATRIX*)&m_viewport_inv, 0, (D3DXMATRIX*)&m_viewport); + + // snap view-position to pixel + cull_xform.mul(mdir_Project, mdir_View); + Fmatrix cull_xform_inv; + cull_xform_inv.invert(cull_xform); + + + // light_cuboid.light_cuboid_points.reserve (9); + for (int p = 0; p < 8; p++) + light_cuboid.light_cuboid_points[p] = wform(cull_xform_inv, corners[p]); + + // only side planes + for (int plane = 0; plane < 4; plane++) + { + for (int pt = 0; pt < 4; pt++) + light_cuboid.light_cuboid_polys[plane].points[pt] = facetable[plane][pt]; + } + + + Fvector lightXZshift; + light_cuboid.compute_caster_model_fixed(cull_planes, lightXZshift, cascade.size, cascade.reset_chain); + Fvector proj_view = Device.vCameraDirection; + proj_view.y = 0; + proj_view.normalize(); + // lightXZshift.mad(proj_view, 20); + + // Initialize rays for the next cascade + if (cascade_ind < m_sun_cascades.size() - 1) + m_sun_cascades[cascade_ind + 1].rays = light_cuboid.view_frustum_rays; + +#ifdef _DEBUG + static bool draw_debug = false; + if (draw_debug && cascade_ind == 0) + for (u32 it = 0; it < cull_planes.size(); it++) + Target->dbg_addplane(cull_planes[it], it * 0xFFF); +#endif + + Fvector cam_shifted = L_pos; + cam_shifted.add(lightXZshift); + + // rebuild the view transform with the shift. + mdir_View.identity(); + mdir_View.build_camera_dir(cam_shifted, L_dir, L_up); + cull_xform.identity(); + cull_xform.mul(mdir_Project, mdir_View); + cull_xform_inv.invert(cull_xform); + + + // Create frustum for query + cull_frustum._clear(); + for (u32 p = 0; p < cull_planes.size(); p++) + cull_frustum._add(cull_planes[p]); + + { + Fvector cam_proj = Device.vCameraPosition; + const float align_aim_step_coef = 4.f; + cam_proj.set(floorf(cam_proj.x / align_aim_step_coef) + align_aim_step_coef / 2, + floorf(cam_proj.y / align_aim_step_coef) + align_aim_step_coef / 2, + floorf(cam_proj.z / align_aim_step_coef) + align_aim_step_coef / 2); + cam_proj.mul(align_aim_step_coef); + Fvector cam_pixel = wform(cull_xform, cam_proj); + cam_pixel = wform(m_viewport, cam_pixel); + Fvector shift_proj = lightXZshift; + cull_xform.transform_dir(shift_proj); + m_viewport.transform_dir(shift_proj); + + const float align_granularity = 4.f; + shift_proj.x = shift_proj.x > 0 ? align_granularity : -align_granularity; + shift_proj.y = shift_proj.y > 0 ? align_granularity : -align_granularity; + shift_proj.z = 0; + + cam_pixel.x = cam_pixel.x / align_granularity - floorf(cam_pixel.x / align_granularity); + cam_pixel.y = cam_pixel.y / align_granularity - floorf(cam_pixel.y / align_granularity); + cam_pixel.x *= align_granularity; + cam_pixel.y *= align_granularity; + cam_pixel.z = 0; + + cam_pixel.sub(shift_proj); + + m_viewport_inv.transform_dir(cam_pixel); + cull_xform_inv.transform_dir(cam_pixel); + Fvector diff = cam_pixel; + static float sign_test = -1.f; + diff.mul(sign_test); + Fmatrix adjust; + adjust.translate(diff); + cull_xform.mulB_44(adjust); + } + + cascade.xform = cull_xform; + + s32 limit = o.smapsize - 1; + fuckingsun->X.D.minX = 0; + fuckingsun->X.D.maxX = limit; + fuckingsun->X.D.minY = 0; + fuckingsun->X.D.maxY = limit; + + // full-xform + FPU::m24r(); + } + } + + // Begin SMAP-render + { + PROF_EVENT("Render Cascade: SMAP traverse"); + phase = PHASE_SMAP; + cascade.GMCascade.traverse(pOutdoorSector, cascade.cull_frustum, cascade.cull_COP, cascade.cull_xform); + cascade.GMCascade.r_dsgraph_capture(false, true); + } + + // Finalize & Cleanup + { + PROF_EVENT("Render Cascade: SMAP Finalize"); + + fuckingsun->X.D.combine = cull_xform; + + // Render shadow-map + //. !!! We should clip based on shrinked frustum (again) + { + bool bDeffered_Shadows = cascade.GMCascade.RGraph.mapStaticPasses[0][0].size() || cascade.GMCascade.RGraph.mapDynamicPasses[0][0].size(); + bool bForward_Shadows = cascade.GMCascade.RGraph.mapStaticPasses[1][0].size() || cascade.GMCascade.RGraph.mapDynamicPasses[1][0].size() || cascade.GMCascade.RGraph.mapStaticSorted.Sorted.size() || cascade.GMCascade.RGraph.mapDynamicSorted.Sorted.size(); + if (bDeffered_Shadows || bForward_Shadows) + { + Target->phase_smap_direct(fuckingsun, SE_SUN_FAR); + RCache.set_xform_world(Fidentity); + RCache.set_xform_view(Fidentity); + RCache.set_xform_project(fuckingsun->X.D.combine); + cascade.GMCascade.r_dsgraph_render_graph(0); + + if (psDeviceFlags2.test(rsGrassShadow) && cascade_ind <= ps_ssfx_grass_shadows.x) + { + Details->fade_distance = dm_fade * dm_fade * ps_ssfx_grass_shadows.y; + Details->Render(); + } + + fuckingsun->X.D.transluent = FALSE; + if (bForward_Shadows) + { + fuckingsun->X.D.transluent = TRUE; + Target->phase_smap_direct_tsh(fuckingsun, SE_SUN_FAR); + cascade.GMCascade.r_dsgraph_render_graph(1); // normal level, secondary priority + cascade.GMCascade.r_dsgraph_render_sorted(); // strict-sorted geoms + } + } + } + + // End SMAP-render + } + + // Accumulate + PROF_EVENT("Render Cascade: Accumulate"); + Target->phase_accumulator(); + +#if defined(USE_DX10) || defined(USE_DX11) + if (Target->use_minmax_sm_this_frame()) + { +#if defined(USE_DX10) || defined(USE_DX11) + PIX_EVENT(SE_SUN_NEAR_MINMAX_GENERATE); +#endif + Target->create_minmax_SM(); + } +#endif + +#if defined(USE_DX10) || defined(USE_DX11) + PIX_EVENT(SE_SUN_NEAR); +#endif + + if (cascade_ind == 0) + Target->accum_direct_cascade(SE_SUN_NEAR, cascade.xform, cascade.xform, + cascade.bias); + else if (cascade_ind < m_sun_cascades.size() - 1) + Target->accum_direct_cascade(SE_SUN_MIDDLE, cascade.xform, + m_sun_cascades[cascade_ind - 1].xform, cascade.bias); + else + Target->accum_direct_cascade(SE_SUN_FAR, cascade.xform, + m_sun_cascades[cascade_ind - 1].xform, cascade.bias); + + // Restore XForms + RCache.set_xform_world(Fidentity); + RCache.set_xform_view(Device.mView); + RCache.set_xform_project(Device.mProject); +} diff --git a/src/Layers/xrRender/R_sun_support.cpp b/src/Layers/xrRender/R_sun_support.cpp new file mode 100644 index 0000000000..567e53169f --- /dev/null +++ b/src/Layers/xrRender/R_sun_support.cpp @@ -0,0 +1,2 @@ +#include "stdafx.h" +#include "R_sun_support.h" diff --git a/src/Layers/xrRenderPC_R3/r3_R_sun_support.h b/src/Layers/xrRender/R_sun_support.h similarity index 93% rename from src/Layers/xrRenderPC_R3/r3_R_sun_support.h rename to src/Layers/xrRender/R_sun_support.h index 7c064e5f28..925e18a42c 100644 --- a/src/Layers/xrRenderPC_R3/r3_R_sun_support.h +++ b/src/Layers/xrRender/R_sun_support.h @@ -1,5 +1,3 @@ -#ifndef r3_R_sun_support_included -#define r3_R_sun_support_included #pragma once const u32 LIGHT_CUBOIDSIDEPOLYS_COUNT = 4; @@ -319,6 +317,7 @@ class DumbConvexVolume t1.sub(points[P.points[0]], points[P.points[1]]); t2.sub(points[P.points[0]], points[P.points[2]]); +#if defined(USE_DX10) || defined(USE_DX11) P.planeN.crossproduct(t1, t2); len = P.planeN.magnitude(); @@ -344,8 +343,10 @@ class DumbConvexVolume continue; } } - - P.planeD = - P.planeN.dotproduct(points[P.points[0]]); +#else + P.planeN.crossproduct(t1, t2).normalize(); +#endif + P.planeD = -P.planeN.dotproduct(points[P.points[0]]); // verify if (_debug) @@ -364,33 +365,6 @@ class DumbConvexVolume p301.build(p3, p0, p1); VERIFY(p012.n.similar(p123.n) && p012.n.similar(p230.n) && p012.n.similar(p301.n)); } - - /* - t1.sub (points[P.points[0]], points[P.points[1]]); - - - // HACK: Igor: just make sure we calculated the plane - - t2.sub (points[P.points[0]], points[P.points[2]]); - P.planeN.crossproduct (t1,t2).normalize(); - - - P.planeD = - P.planeN.dotproduct(points[P.points[0]]); - - // verify - if (_debug) - { - Fvector& p0 = points[P.points[0]]; - Fvector& p1 = points[P.points[1]]; - Fvector& p2 = points[P.points[2]]; - Fvector& p3 = points[P.points[3]]; - Fplane p012; p012.build(p0,p1,p2); - Fplane p123; p123.build(p1,p2,p3); - Fplane p230; p230.build(p2,p3,p0); - Fplane p301; p301.build(p3,p0,p1); - VERIFY (p012.n.similar(p123.n) && p012.n.similar(p230.n) && p012.n.similar(p301.n)); - } - */ } } @@ -488,5 +462,3 @@ class DumbConvexVolume } } }; - -#endif // r3_R_sun_support_included diff --git a/src/Layers/xrRender/ResourceManager.cpp b/src/Layers/xrRender/ResourceManager.cpp index 7c2d340db7..6b9e46ac8a 100644 --- a/src/Layers/xrRender/ResourceManager.cpp +++ b/src/Layers/xrRender/ResourceManager.cpp @@ -1,8 +1,9 @@ -// TextureManager.cpp: implementation of the CResourceManager class. + // ////////////////////////////////////////////////////////////////////// #include "stdafx.h" +#include "xrRender_console.h" #pragma hdrstop #pragma warning(disable:4995) @@ -13,7 +14,7 @@ #include "tss.h" #include "blenders\blender.h" #include "blenders\blender_recorder.h" -#include +#include "../../xrCore/_thread_types.h" // Already defined in Texture.cpp void fix_texture_name(LPSTR fn); @@ -153,6 +154,7 @@ ShaderElement* CResourceManager::_CreateElement(ShaderElement& S) // Create _new_ entry ShaderElement* N = xr_new(S); + //N->_copy(S); N->dwFlags |= xr_resource_flagged::RF_REGISTERED; v_elements.push_back(N); return N; @@ -271,10 +273,8 @@ Shader* CResourceManager::_cpp_Create(IBlender* B, LPCSTR s_shader, LPCSTR s_tex if (S.equal(v_shaders[it])) return v_shaders[it]; // Create _new_ entry - Shader* N = xr_new(S); - N->dwFlags |= xr_resource_flagged::RF_REGISTERED; - v_shaders.push_back(N); - return N; + Shader* ResultShader = _CreateShader(&S); + return ResultShader; } Shader* CResourceManager::_cpp_Create(LPCSTR s_shader, LPCSTR s_textures, LPCSTR s_constants, LPCSTR s_matrices) @@ -370,9 +370,14 @@ Shader* CResourceManager::Create(LPCSTR s_shader, LPCSTR s_textures, LPCSTR s_co void CResourceManager::Delete(const Shader* S) { + if (0 == (S->dwFlags & xr_resource_flagged::RF_REGISTERED)) + return; + xrCriticalSectionGuard guard(creationGuard); - if (0 == (S->dwFlags & xr_resource_flagged::RF_REGISTERED)) return; - if (reclaim(v_shaders, S)) return; + + if (reclaim(v_shaders, S)) + return; + Msg("! ERROR: Failed to find complete shader"); } @@ -385,7 +390,13 @@ void CResourceManager::DeferredUpload() CTimer timer; timer.Start(); - tbb::parallel_for_each(m_textures, [&](auto m_tex) { m_tex.second->Load(); }); + static DWORD this_thread_id = 0; + this_thread_id = GetCurrentThreadId(); + xr_parallel_foreach(m_textures.begin(), m_textures.end(), [](auto& pair) + { + if (this_thread_id != GetCurrentThreadId()) { PROF_THREAD("X-Ray PPL Thread") } + pair.second->Load(); + }); Msg("texture loading time: %d", timer.GetElapsed_ms()); } @@ -395,7 +406,45 @@ void CResourceManager::DeferredUnload() if (!RDEVICE.b_is_Ready) return; - tbb::parallel_for_each(m_textures, [&](auto m_tex) { m_tex.second->Unload(); }); + xr_parallel_foreach(m_textures.begin(), m_textures.end(), [](auto& pair) + { + pair.second->Unload(); + }); +} + +void CResourceManager::UnloadAllTexturesOnLevelUnload() +{ + if (!RDEVICE.b_is_Ready) + return; + + xrCriticalSectionGuard guard(creationGuard); + + xr_vector textures_to_unload; + textures_to_unload.reserve(m_textures.size()); + + for (const auto& pair : m_textures) + { + CTexture* texture = pair.second; + if (!texture) + continue; + + if (texture->flags.bUser) + continue; + + // Keep $ textures alive since they are bound to runtime render targets or other important parts + if (strstr(*texture->cName, "$")) + continue; + + // Keep UI textures + LPCSTR name = pair.first; + if (strncmp(name, "ui\\", 3) == 0 || strncmp(name, "ui/", 3) == 0) + continue; + + textures_to_unload.push_back(texture); + } + + for (CTexture* texture : textures_to_unload) + texture->Unload(); } #ifdef _EDITOR @@ -418,6 +467,26 @@ void CResourceManager::ED_UpdateTextures(AStringVec* names) } #endif +Shader* CResourceManager::_CreateShader(Shader* InShader) +{ + xrCriticalSectionGuard guard(creationGuard); + + // Search equal in shaders array + for (Shader* it : v_shaders) + { + if (InShader->equal(it)) + return it; + } + + // Create _new_ entry + Shader* N = xr_new(*InShader); + //N->_copy(*InShader); + N->dwFlags |= xr_resource_flagged::RF_REGISTERED; + v_shaders.push_back(N); + + return N; +} + void CResourceManager::_GetMemoryUsage(u32& m_base, u32& c_base, u32& m_lmaps, u32& c_lmaps) { m_base = c_base = m_lmaps = c_lmaps = 0; @@ -473,6 +542,116 @@ void CResourceManager::Evict() #endif // USE_DX10 } +void CResourceManager::EvictStalledTextures() { +#if defined(USE_DX11) + if (!ps_r__tex_evict_enabled) + return; +#ifdef DEBUG + Msg("* [TexEvict] pass called, frame=%u", RDEVICE.dwFrame); +#endif // DEBUG + if (!RDEVICE.b_is_Ready) + return; + + u32 cur_frame = RDEVICE.dwFrame; + u32 max_age = (u32)ps_r__tex_evict_age_frames; +#ifdef DEBUG + u32 evicted = 0; + u32 evicted_kb = 0; + u32 skip_user = 0; + u32 skip_name = 0; + u32 skip_unloaded = 0; + u32 skip_refs = 0; + u32 skip_recent = 0; +#endif // DEBUG + + static xr_string s_evict_cursor; + const u32 batch_size = (u32)ps_r__tex_evict_batch_size; + + creationGuard.Enter(); + + map_Texture::iterator I; + if (s_evict_cursor.empty()) { + I = m_textures.begin(); + } else { + I = m_textures.lower_bound(s_evict_cursor.c_str()); + if (I == m_textures.end()) + I = m_textures.begin(); + } + + u32 scanned = 0; + for (; I != m_textures.end() && scanned < batch_size; ++I, ++scanned) { + CTexture *tex = I->second; + if (tex->flags.bUser) { +#ifdef DEBUG + skip_user++; +#endif // DEBUG + continue; + } + if (tex->cName.size() && strstr(tex->cName.c_str(), "$user$")) { +#ifdef DEBUG + skip_user++; +#endif // DEBUG + continue; + } + if (tex->cName.size() && strstr(tex->cName.c_str(), "$null")) { +#ifdef DEBUG + skip_user++; +#endif // DEBUG + continue; + } + if (!tex->flags.bLoaded) { +#ifdef DEBUG + skip_unloaded++; +#endif // DEBUG + continue; + } + // UI textures — PDA, inventory icons, etc. — must never be evicted + LPCSTR name = I->first; + if (strncmp(name, "ui\\", 3) == 0 || strncmp(name, "ui/", 3) == 0) { +#ifdef DEBUG + skip_name++; +#endif // DEBUG + continue; + } + if (tex->dwReference.load(std::memory_order_relaxed) > 1) { +#ifdef DEBUG + u32 refs = tex->dwReference.load(std::memory_order_relaxed); + if (refs > 2) + Msg("* [TexEvict] stuck: [%4d] %s", refs, tex->cName.c_str()); + skip_refs++; +#endif // DEBUG + continue; + } + if (cur_frame - tex->dwLastUsedFrame < max_age) { +#ifdef DEBUG + skip_recent++; +#endif // DEBUG + continue; + } + +#ifdef DEBUG + evicted_kb += tex->flags.MemoryUsage / 1024; +#endif // DEBUG + tex->Unload(); +#ifdef DEBUG + evicted++; +#endif // DEBUG + } + + s_evict_cursor = (I != m_textures.end()) ? xr_string(I->first) : xr_string(); + + creationGuard.Leave(); + +#ifdef DEBUG + Msg("* [TexEvict] frame=%u total=%u scanned=%u evicted=%u skip_user=%u " + "skip_name=%u skip_unloaded=%u skip_refs=%u skip_recent=%u freed_kb=%u", + cur_frame, (u32)m_textures.size(), scanned, evicted, skip_user, skip_name, + skip_unloaded, skip_refs, skip_recent, evicted_kb); +#endif // DEBUG +#endif +} + + /* BOOL CResourceManager::_GetDetailTexture(LPCSTR Name,LPCSTR& T, R_constant_setup* &CS) { diff --git a/src/Layers/xrRender/ResourceManager.h b/src/Layers/xrRender/ResourceManager.h index 16babc14ec..39883b59cd 100644 --- a/src/Layers/xrRender/ResourceManager.h +++ b/src/Layers/xrRender/ResourceManager.h @@ -92,7 +92,6 @@ class ECORE_API CResourceManager public: CTextureDescrMngr m_textures_description; - //. CInifile* m_textures_description; xr_vector> v_constant_setup; lua_State* LSVM; BOOL bDeferredLoad; @@ -116,8 +115,6 @@ class ECORE_API CResourceManager // Editor cooperation void ED_UpdateBlender(LPCSTR Name, IBlender* data); - void ED_UpdateMatrix(LPCSTR Name, CMatrix* data); - void ED_UpdateConstant(LPCSTR Name, CConstant* data); #ifdef _EDITOR void ED_UpdateTextures (AStringVec* names); #endif @@ -190,6 +187,8 @@ class ECORE_API CResourceManager SMatrixList* _CreateMatrixList(SMatrixList& L); void _DeleteMatrixList(const SMatrixList* L); + Shader* _CreateShader(Shader* InShader); + SConstantList* _CreateConstantList(SConstantList& L); void _DeleteConstantList(const SConstantList* L); @@ -232,7 +231,9 @@ class ECORE_API CResourceManager void DeferredLoad(BOOL E) { bDeferredLoad = E; } void DeferredUpload(); void DeferredUnload(); + void UnloadAllTexturesOnLevelUnload(); void Evict(); + void EvictStalledTextures(); void StoreNecessaryTextures(); void DestroyNecessaryTextures(); void Dump(bool bBrief); diff --git a/src/Layers/xrRender/ResourceManager_Resources.cpp b/src/Layers/xrRender/ResourceManager_Resources.cpp index 35893f0fe8..00918a8ddc 100644 --- a/src/Layers/xrRender/ResourceManager_Resources.cpp +++ b/src/Layers/xrRender/ResourceManager_Resources.cpp @@ -18,7 +18,7 @@ void fix_texture_name(LPSTR fn); void simplify_texture(string_path& fn) { - if (strstr(Core.Params, "-game_designer")) + if (Core.ParamsData.test(ECoreParams::game_designer)) { if (strstr(fn, "$user")) return; if (strstr(fn, "ui\\")) return; @@ -149,13 +149,15 @@ void CResourceManager::_DeleteDecl(const SDeclaration* dcl) SVS* CResourceManager::_CreateVS(LPCSTR _name) { xrCriticalSectionGuard guard(creationGuard); - string_path name; - xr_strcpy(name, _name); - if (0 == ::Render->m_skinning) xr_strcat(name, "_0"); - if (1 == ::Render->m_skinning) xr_strcat(name, "_1"); - if (2 == ::Render->m_skinning) xr_strcat(name, "_2"); - if (3 == ::Render->m_skinning) xr_strcat(name, "_3"); - if (4 == ::Render->m_skinning) xr_strcat(name, "_4"); + xr_string res_name = _name; + + const int m_skinning = Engine.External.GetSkinningMode(); + if (m_skinning > 0) + { + res_name += "_" + xr_string::ToString(m_skinning); + } + + LPCSTR name = res_name.c_str(); LPSTR N = LPSTR(name); map_VS::iterator I = m_vs.find(N); if (I != m_vs.end()) return I->second; @@ -210,7 +212,7 @@ SVS* CResourceManager::_CreateVS(LPCSTR _name) if (FAILED(_hr)) { - FlushLog(); + xrLogger::FlushLog(); } CHECK_OR_EXIT( @@ -306,7 +308,7 @@ SPS* CResourceManager::_CreatePS(LPCSTR name) if (FAILED(_hr)) { - FlushLog(); + xrLogger::FlushLog(); } CHECK_OR_EXIT( @@ -336,12 +338,17 @@ void CResourceManager::_DeletePS(const SPS* ps) R_constant_table* CResourceManager::_CreateConstantTable(R_constant_table& C) { if (C.empty()) return NULL; + xrCriticalSectionGuard guard(creationGuard); for (u32 it = 0; it < v_constant_tables.size(); it++) - if (v_constant_tables[it]->equal(C)) return v_constant_tables[it]; - v_constant_tables.push_back(xr_new(C)); - v_constant_tables.back()->dwFlags |= xr_resource_flagged::RF_REGISTERED; - return v_constant_tables.back(); + if (v_constant_tables[it]->equal(C)) + return v_constant_tables[it]; + + auto NewElem = xr_new(C); + //NewElem->_copy(C); + NewElem->dwFlags |= xr_resource_flagged::RF_REGISTERED; + v_constant_tables.push_back(NewElem); + return NewElem; } void CResourceManager::_DeleteConstantTable(const R_constant_table* C) @@ -386,38 +393,6 @@ void CResourceManager::_DeleteRT(const CRT* RT) Msg("! ERROR: Failed to find render-target '%s'", *RT->cName); } -// DX10 cut -/* -//-------------------------------------------------------------------------------------------------------------- -CRTC* CResourceManager::_CreateRTC (LPCSTR Name, u32 size, D3DFORMAT f) -{ - R_ASSERT(Name && Name[0] && size); - - // ***** first pass - search already created RTC - LPSTR N = LPSTR(Name); - map_RTC::iterator I = m_rtargets_c.find (N); - if (I!=m_rtargets_c.end()) return I->second; - else - { - CRTC *RT = xr_new(); - RT->dwFlags |= xr_resource_flagged::RF_REGISTERED; - m_rtargets_c.insert (mk_pair(RT->set_name(Name),RT)); - if (RDEVICE.b_is_Ready) RT->create (Name,size,f); - return RT; - } -} -void CResourceManager::_DeleteRTC (const CRTC* RT) -{ - if (0==(RT->dwFlags&xr_resource_flagged::RF_REGISTERED)) return; - LPSTR N = LPSTR (*RT->cName); - map_RTC::iterator I = m_rtargets_c.find (N); - if (I!=m_rtargets_c.end()) { - m_rtargets_c.erase(I); - return; - } - Msg ("! ERROR: Failed to find render-target '%s'",*RT->cName); -} -*/ //-------------------------------------------------------------------------------------------------------------- void CResourceManager::DBG_VerifyGeoms() { @@ -463,8 +438,8 @@ SGeometry* CResourceManager::CreateGeom(D3DVERTEXELEMENT9* decl, IDirect3DVertex SGeometry* CResourceManager::CreateGeom(u32 FVF, IDirect3DVertexBuffer9* vb, IDirect3DIndexBuffer9* ib) { - xrCriticalSectionGuard guard(creationGuard); D3DVERTEXELEMENT9 dcl [MAX_FVF_DECL_SIZE]; + xrCriticalSectionGuard guard(creationGuard); CHK_DX(D3DXDeclaratorFromFVF(FVF,dcl)); SGeometry* g = CreateGeom(dcl, vb, ib); return g; @@ -479,6 +454,7 @@ void CResourceManager::DeleteGeom(const SGeometry* Geom) } //-------------------------------------------------------------------------------------------------------------- +xr_task_group textures_load_tasks; CTexture* CResourceManager::_CreateTexture(LPCSTR _Name) { // DBG_VerifyTextures (); @@ -503,7 +479,16 @@ CTexture* CResourceManager::_CreateTexture(LPCSTR _Name) T->dwFlags |= xr_resource_flagged::RF_REGISTERED; m_textures.insert(mk_pair(T->set_name(Name), T)); T->Preload(); - if (RDEVICE.b_is_Ready && !bDeferredLoad) T->Load(); + if (Device.b_is_Ready) + { + static DWORD this_thread_id = 0; + this_thread_id = GetCurrentThreadId(); + textures_load_tasks.run([=]() + { + if (this_thread_id != GetCurrentThreadId()) { PROF_THREAD("X-Ray PPL Thread") } + T->Load(); + }); + } return T; } } @@ -573,12 +558,6 @@ void CResourceManager::_DeleteMatrix(const CMatrix* M) Msg("! ERROR: Failed to find xform-def '%s'", *M->cName); } -void CResourceManager::ED_UpdateMatrix(LPCSTR Name, CMatrix* data) -{ - CMatrix* M = _CreateMatrix(Name); - *M = *data; -} - //-------------------------------------------------------------------------------------------------------------- CConstant* CResourceManager::_CreateConstant(LPCSTR Name) { @@ -613,12 +592,6 @@ void CResourceManager::_DeleteConstant(const CConstant* C) Msg("! ERROR: Failed to find R1-constant-def '%s'", *C->cName); } -void CResourceManager::ED_UpdateConstant(LPCSTR Name, CConstant* data) -{ - CConstant* C = _CreateConstant(Name); - *C = *data; -} - //-------------------------------------------------------------------------------------------------------------- bool cmp_tl(const std::pair& _1, const std::pair& _2) { @@ -635,6 +608,7 @@ STextureList* CResourceManager::_CreateTextureList(STextureList& L) if (L.equal(*base)) return base; } STextureList* lst = xr_new(L); + //lst->_copy(L); lst->dwFlags |= xr_resource_flagged::RF_REGISTERED; lst_textures.push_back(lst); return lst; @@ -658,8 +632,8 @@ SMatrixList* CResourceManager::_CreateMatrixList(SMatrixList& L) bEmpty = FALSE; break; } + if (bEmpty) return nullptr; xrCriticalSectionGuard guard(creationGuard); - if (bEmpty) return NULL; for (u32 it = 0; it < lst_matrices.size(); it++) { @@ -667,6 +641,7 @@ SMatrixList* CResourceManager::_CreateMatrixList(SMatrixList& L) if (L.equal(*base)) return base; } SMatrixList* lst = xr_new(L); + //lst->_copy(L); lst->dwFlags |= xr_resource_flagged::RF_REGISTERED; lst_matrices.push_back(lst); return lst; @@ -690,8 +665,8 @@ SConstantList* CResourceManager::_CreateConstantList(SConstantList& L) bEmpty = FALSE; break; } + if (bEmpty) return nullptr; xrCriticalSectionGuard guard(creationGuard); - if (bEmpty) return NULL; for (u32 it = 0; it < lst_constants.size(); it++) { @@ -699,6 +674,7 @@ SConstantList* CResourceManager::_CreateConstantList(SConstantList& L) if (L.equal(*base)) return base; } SConstantList* lst = xr_new(L); + //lst->_copy(L); lst->dwFlags |= xr_resource_flagged::RF_REGISTERED; lst_constants.push_back(lst); return lst; diff --git a/src/Layers/xrRender/ResourceManager_Scripting.cpp b/src/Layers/xrRender/ResourceManager_Scripting.cpp index b55e695c30..3471fabc78 100644 --- a/src/Layers/xrRender/ResourceManager_Scripting.cpp +++ b/src/Layers/xrRender/ResourceManager_Scripting.cpp @@ -548,6 +548,7 @@ Shader* CResourceManager::_lua_Create(LPCSTR d_shader, LPCSTR s_textures) // Create _new_ entry Shader* N = xr_new(S); + //N->_copy(S); N->dwFlags |= xr_resource_flagged::RF_REGISTERED; v_shaders.push_back(N); return N; diff --git a/src/Layers/xrRender/SH_Constant.h b/src/Layers/xrRender/SH_Constant.h index 8299ecc7f5..9ab1f43437 100644 --- a/src/Layers/xrRender/SH_Constant.h +++ b/src/Layers/xrRender/SH_Constant.h @@ -23,6 +23,11 @@ class ECORE_API CConstant : public xr_resource_named WaveForm _B; WaveForm _A; + // Non-Copyable (mt-safe) + /*CConstant& operator=(const CConstant& Other) = delete; + CConstant& operator=(CConstant&& Other) = delete; + CConstant(const CConstant& Other) = delete;*/ + CConstant() { Memory.mem_fill(this, 0, sizeof(CConstant)); diff --git a/src/Layers/xrRender/SH_Matrix.h b/src/Layers/xrRender/SH_Matrix.h index f4d8ebc33a..2eb204a722 100644 --- a/src/Layers/xrRender/SH_Matrix.h +++ b/src/Layers/xrRender/SH_Matrix.h @@ -36,6 +36,11 @@ class ECORE_API CMatrix : public xr_resource_named WaveForm rotate; WaveForm scrollU, scrollV; + // Non-Copyable (mt-safe) + /*CMatrix& operator=(const CMatrix& Other) = delete; + CMatrix& operator=(CMatrix&& Other) = delete; + CMatrix(const CMatrix& Other) = delete;*/ + CMatrix() { Memory.mem_fill(this, 0, sizeof(CMatrix)); diff --git a/src/Layers/xrRender/SH_Texture.cpp b/src/Layers/xrRender/SH_Texture.cpp index e0d647d162..b0ec73a42e 100644 --- a/src/Layers/xrRender/SH_Texture.cpp +++ b/src/Layers/xrRender/SH_Texture.cpp @@ -37,10 +37,11 @@ CTexture::CTexture() seqMSPF = 0; flags.MemoryUsage = 0; flags.bLoaded = false; + flags.bLoading = false; flags.bUser = false; flags.seqCycles = FALSE; m_material = 1.0f; - bind = fastdelegate::FastDelegate1(this, &CTexture::apply_load); + bind = xr_make_delegate(this, &CTexture::apply_load); } CTexture::~CTexture() @@ -53,6 +54,10 @@ CTexture::~CTexture() void CTexture::surface_set(ID3DBaseTexture* surf) { + while (flags.bLoading) + { + SwitchToThread(); + } if (surf) surf->AddRef(); _RELEASE(pSurface); @@ -62,28 +67,46 @@ void CTexture::surface_set(ID3DBaseTexture* surf) ID3DBaseTexture* CTexture::surface_get() { + while (flags.bLoading) + { + SwitchToThread(); + } if (pSurface) pSurface->AddRef(); return pSurface; } void CTexture::PostLoad() { - if (pTheora) bind = fastdelegate::FastDelegate1(this, &CTexture::apply_theora); - else if (pAVI) bind = fastdelegate::FastDelegate1(this, &CTexture::apply_avi); - else if (!seqDATA.empty()) bind = fastdelegate::FastDelegate1(this, &CTexture::apply_seq); - else if (gifPlayer) bind = fastdelegate::FastDelegate1(this, &CTexture::apply_gif); - else bind = fastdelegate::FastDelegate1(this, &CTexture::apply_normal); + if (pTheora) bind = xr_make_delegate(this, &CTexture::apply_theora); + else if (pAVI) bind = xr_make_delegate(this, &CTexture::apply_avi); + else if (!seqDATA.empty()) bind = xr_make_delegate(this, &CTexture::apply_seq); + else if (gifPlayer) bind = xr_make_delegate(this, &CTexture::apply_gif); + else bind = xr_make_delegate(this, &CTexture::apply_normal); } void CTexture::apply_load(u32 dwStage) { - if (!flags.bLoaded) Load(); - else PostLoad(); - bind(dwStage); + if (!flags.bLoaded) Load(); + else PostLoad(); + if (bind == xr_make_delegate(this, &CTexture::apply_load)) + { + // This should not happen - if bind is still apply_load, fall back to apply_normal + // which will just apply the (potentially unloaded) surface + apply_normal(dwStage); + } + else + { + bind(dwStage); + } }; + void CTexture::apply_theora(u32 dwStage) { + while (flags.bLoading) + { + SwitchToThread(); + } if (pTheora->Update(m_play_time != 0xFFFFFFFF ? m_play_time : RDEVICE.dwTimeContinual)) { R_ASSERT(D3DRTYPE_TEXTURE == pSurface->GetType()); @@ -109,6 +132,10 @@ void CTexture::apply_theora(u32 dwStage) void CTexture::apply_avi(u32 dwStage) { + while (flags.bLoading) + { + SwitchToThread(); + } if (pAVI->NeedUpdate()) { R_ASSERT(D3DRTYPE_TEXTURE == pSurface->GetType()); @@ -131,6 +158,10 @@ void CTexture::apply_avi(u32 dwStage) void CTexture::apply_seq(u32 dwStage) { + while (flags.bLoading) + { + SwitchToThread(); + } // SEQ u32 frame = RDEVICE.dwTimeContinual / seqMSPF; //RDEVICE.dwTimeGlobal u32 frame_data = seqDATA.size(); @@ -150,6 +181,10 @@ void CTexture::apply_seq(u32 dwStage) void CTexture::apply_gif(u32 dwStage) { + while (flags.bLoading) + { + SwitchToThread(); + } if (gifPlayer->UpdateFrame()) { const CGIFAnimationPlayer::Frame* const gifFrame = gifPlayer->GetActiveFrame(); @@ -162,6 +197,11 @@ void CTexture::apply_gif(u32 dwStage) void CTexture::apply_normal(u32 dwStage) { + while (flags.bLoading) + { + SwitchToThread(); + } + dwLastUsedFrame = Device.dwFrame; CHK_DX(HW.pDevice->SetTexture(dwStage,pSurface)); }; @@ -173,16 +213,31 @@ void CTexture::Preload() void CTexture::Load() { - flags.bLoaded = true; + PROF_EVENT("CTexture::Load"); + if (flags.bLoaded || flags.bLoading) return; + flags.bLoading = true; + flags.bLoaded = false; desc_cache = 0; - if (pSurface) return; + if (pSurface) + { + flags.bLoading = false; + flags.bLoaded = true; + return; + } flags.bUser = false; flags.MemoryUsage = 0; - if (0 == stricmp(*cName, "$null")) return; - if (0 != strstr(*cName, "$user$")) + if (0==_stricmp(*cName,"$null")) + { + flags.bLoading = false; + flags.bLoaded = true; + return; + } + if (0!=strstr(*cName,"$user$")) { - flags.bUser = true; + flags.bUser = true; + flags.bLoading = false; + flags.bLoaded = true; return; } @@ -329,10 +384,21 @@ void CTexture::Load() //#endif } PostLoad(); + flags.bLoading = false; + flags.bLoaded = true; } void CTexture::Unload() { + while (flags.bLoading) + { + SwitchToThread(); + } + + // Already unloaded or never loaded: nothing to do. + if (!flags.bLoaded) + return; + #ifdef DEBUG string_path msg_buff; xr_sprintf (msg_buff,sizeof(msg_buff),"* Unloading texture [%s] pSurface RefCount=",cName.c_str()); @@ -367,11 +433,15 @@ void CTexture::Unload() xr_delete(pAVI); xr_delete(pTheora); - bind = fastdelegate::FastDelegate1(this, &CTexture::apply_load); + bind = xr_make_delegate(this, &CTexture::apply_load); } void CTexture::desc_update() { + while (flags.bLoading) + { + SwitchToThread(); + } desc_cache = pSurface; if (pSurface && (D3DRTYPE_TEXTURE == pSurface->GetType())) { @@ -382,20 +452,36 @@ void CTexture::desc_update() void CTexture::video_Play(BOOL looped, u32 _time) { + while (flags.bLoading) + { + SwitchToThread(); + } if (pTheora) pTheora->Play(looped, (_time != 0xFFFFFFFF) ? (m_play_time = _time) : RDEVICE.dwTimeContinual); } void CTexture::video_Pause(BOOL state) { + while (flags.bLoading) + { + SwitchToThread(); + } if (pTheora) pTheora->Pause(state); } void CTexture::video_Stop() { + while (flags.bLoading) + { + SwitchToThread(); + } if (pTheora) pTheora->Stop(); } BOOL CTexture::video_IsPlaying() { + while (flags.bLoading) + { + SwitchToThread(); + } return (pTheora) ? pTheora->IsPlaying() : FALSE; } diff --git a/src/Layers/xrRender/SH_Texture.h b/src/Layers/xrRender/SH_Texture.h index 429204f7f6..ef921bbc2a 100644 --- a/src/Layers/xrRender/SH_Texture.h +++ b/src/Layers/xrRender/SH_Texture.h @@ -69,8 +69,9 @@ class ECORE_API CTexture : public xr_resource_named #endif // USE_DX10 private: - IC BOOL desc_valid() { return pSurface == desc_cache; } - IC void desc_enshure() { if (!desc_valid()) desc_update(); } + IC void wait_for_loading() const { while (flags.bLoading){SwitchToThread();} } + IC BOOL desc_valid() { wait_for_loading(); return pSurface==desc_cache; } + IC void desc_enshure() { wait_for_loading(); if (!desc_valid()) desc_update(); } void desc_update(); #if defined(USE_DX10) || defined(USE_DX11) void Apply (u32 dwStage); @@ -83,15 +84,18 @@ class ECORE_API CTexture : public xr_resource_named struct { u32 bLoaded : 1; + u32 bLoading : 1; u32 bUser : 1; u32 seqCycles : 1; - u32 MemoryUsage : 28; + u32 MemoryUsage : 27; #if defined(USE_DX10) || defined(USE_DX11) u32 bLoadedAsStaging: 1; #endif // USE_DX10 } flags; - fastdelegate::FastDelegate1 bind; + u32 dwLastUsedFrame = 0; // frame index of last Apply() call — used for eviction + + xr_delegate bind; CAviPlayerCustom* pAVI; @@ -130,8 +134,8 @@ struct resptrcode_texture : public resptr_base { void create(LPCSTR _name); void destroy() { _set(NULL); } - shared_str bump_get() { return _get()->m_bumpmap; } - bool bump_exist() { return 0 != bump_get().size(); } + shared_str bump_get() { while (_get() && _get()->flags.bLoading) { SwitchToThread(); }return _get()->m_bumpmap; } + bool bump_exist() { while (_get() && _get()->flags.bLoading) { SwitchToThread(); }return 0!=bump_get().size(); } }; typedef resptr_core diff --git a/src/Layers/xrRender/Shader.cpp b/src/Layers/xrRender/Shader.cpp index 0d33fe0543..937ff77450 100644 --- a/src/Layers/xrRender/Shader.cpp +++ b/src/Layers/xrRender/Shader.cpp @@ -209,3 +209,61 @@ u32 STextureList::find_texture_stage(const shared_str& TexName) const return dwTextureStage; } + +//STextureList::STextureList() +//{ +//} + +void STextureList::_copy(const STextureList& Other) +{ + assign(Other.begin(), Other.end()); +} + +//Shader::Shader() +//{ +//} + +void Shader::_copy(Shader& Other) +{ + for (size_t i = 0; i < SHADER_ELEMENTS_MAX; i++) + { + E[i] = Other.E[i]; + } +} + +//SConstantList::SConstantList() +//{ +//} + +void SConstantList::_copy(const SConstantList& Other) +{ + clear(); + for (size_t i = 0; i < Other.size(); i++) + { + push_back(Other[i]); + } +} + +void SMatrixList::_copy(const SMatrixList& Other) +{ + clear(); + for (size_t i = 0; i < Other.size(); i++) + { + push_back(Other[i]); + } +} + +//SMatrixList::SMatrixList() +//{ +//} + +void ShaderElement::_copy(const ShaderElement& Other) +{ + flags = Other.flags; + + passes.clear(); + for (size_t i = 0; i < Other.passes.size(); i++) + { + passes.push_back(Other.passes[i]); + } +} diff --git a/src/Layers/xrRender/Shader.h b/src/Layers/xrRender/Shader.h index 9b9795b6d2..76fa848888 100644 --- a/src/Layers/xrRender/Shader.h +++ b/src/Layers/xrRender/Shader.h @@ -18,12 +18,15 @@ typedef xr_vector sh_list; class CBlender_Compile; class IBlender; -#define SHADER_PASSES_MAX 2 +#define SHADER_PASSES_MAX 2 +#define SHADER_ELEMENTS_MAX 6 #pragma pack(push,4) ////////////////////////////////////////////////////////////////////////// -struct ECORE_API STextureList : public xr_resource_flagged, public xr_vector> +struct ECORE_API STextureList : + public xr_resource_flagged, + public xr_vector > { typedef xr_vector> inherited_vec; ~STextureList(); @@ -45,22 +48,33 @@ struct ECORE_API STextureList : public xr_resource_flagged, public xr_vector> ref_texture_list; + //STextureList(); + //STextureList& operator=(const STextureList& Other) = delete; + + void _copy(const STextureList& Other); +}; +typedef resptr_core> ref_texture_list; ////////////////////////////////////////////////////////////////////////// struct ECORE_API SMatrixList : public xr_resource_flagged, public svector { + //SMatrixList(); + //SMatrixList& operator=(const SMatrixList& Other) = delete; ~SMatrixList(); -}; -typedef resptr_core> ref_matrix_list; + void _copy(const SMatrixList& Other); +}; +typedef resptr_core> ref_matrix_list; ////////////////////////////////////////////////////////////////////////// -struct ECORE_API SConstantList : public xr_resource_flagged, public svector +struct ECORE_API SConstantList : public xr_resource_flagged, public svector { ~SConstantList(); + //SConstantList(); + + //SConstantList& operator=(const SConstantList& Other) = delete; + void _copy(const SConstantList& Other); }; typedef resptr_core> ref_constant_list; @@ -73,6 +87,7 @@ struct ECORE_API SGeometry : public xr_resource_flagged ID3DIndexBuffer* ib; u32 vb_stride; ~SGeometry(); + //SGeometry& operator=(const SGeometry& Other) = delete; }; struct ECORE_API resptrcode_geom : public resptr_base @@ -139,8 +154,12 @@ struct ECORE_API ShaderElement : public xr_resource_flagged ShaderElement(); ~ShaderElement(); + + //ShaderElement& operator=(const ShaderElement& Other) = delete; + BOOL equal(ShaderElement& S); BOOL equal(ShaderElement* S); + void _copy(const ShaderElement& Other); }; typedef resptr_core> ref_selement; @@ -149,11 +168,16 @@ typedef resptr_core> ref_selement; struct ECORE_API Shader : public xr_resource_flagged { public: - ref_selement E [6]; // R1 - 0=norm_lod0(det), 1=norm_lod1(normal), 2=L_point, 3=L_spot, 4=L_for_models, + ref_selement E [SHADER_ELEMENTS_MAX]; // R1 - 0=norm_lod0(det), 1=norm_lod1(normal), 2=L_point, 3=L_spot, 4=L_for_models, // R2 - 0=deffer, 1=norm_lod1(normal), 2=psm, 3=ssm, 4=dsm + //Shader(); + //Shader& operator=(const Shader& Other) = delete; + ~Shader(); BOOL equal(Shader& S); BOOL equal(Shader* S); + + void _copy(Shader& Other); }; struct ECORE_API resptrcode_shader : public resptr_base diff --git a/src/Layers/xrRender/SkeletonAnimated.cpp b/src/Layers/xrRender/SkeletonAnimated.cpp index 7066940e06..910630756e 100644 --- a/src/Layers/xrRender/SkeletonAnimated.cpp +++ b/src/Layers/xrRender/SkeletonAnimated.cpp @@ -22,6 +22,7 @@ void CBlendInstance::construct() void CBlendInstance::blend_add(CBlend* H) { + xrSRWLockGuard guard(&blend_lock, false); if (Blend.size() == MAX_BLENDED) { if (H->fall_at_end) @@ -37,6 +38,7 @@ void CBlendInstance::blend_add(CBlend* H) void CBlendInstance::blend_remove(CBlend* H) { + xrSRWLockGuard guard(&blend_lock, false); CBlend** I = std::find(Blend.begin(), Blend.end(), H); if (I != Blend.end()) Blend.erase(I); } @@ -215,7 +217,7 @@ MotionID CKinematicsAnimated::ID_Cycle_Safe(LPCSTR N) MotionID CKinematicsAnimated::ID_Cycle(shared_str N) { MotionID motion_ID = ID_Cycle_Safe(N); - R_ASSERT3(motion_ID.valid(), "! MODEL: can't find cycle: ", N.c_str()); + R_ASSERT2(motion_ID.valid(), make_string("! MODEL [%s]: can't find cycle: [%s]", dbg_name.c_str(), N.c_str()).c_str()); return motion_ID; } @@ -238,7 +240,7 @@ MotionID CKinematicsAnimated::ID_Cycle_Safe(shared_str N) MotionID CKinematicsAnimated::ID_Cycle(LPCSTR N) { MotionID motion_ID = ID_Cycle_Safe(N); - R_ASSERT3(motion_ID.valid(), "! MODEL: can't find cycle: ", N); + R_ASSERT2(motion_ID.valid(), make_string("! MODEL [%s]: can't find cycle: [%s]", dbg_name.c_str(), N).c_str()); return motion_ID; } @@ -431,7 +433,7 @@ CBlend* CKinematicsAnimated::PlayCycle(LPCSTR N, BOOL bMixIn, PlayCallback Callb if (motion_ID.valid()) return PlayCycle(motion_ID, bMixIn, Callback, CallbackParam, channel); else { - Debug.fatal(DEBUG_INFO, "! MODEL: can't find cycle: %s", N); + Debug.fatal(DEBUG_INFO, "! MODEL [%s]: can't find cycle: [%s]", dbg_name.c_str(), N); return 0; } } @@ -440,6 +442,8 @@ CBlend* CKinematicsAnimated::PlayCycle(MotionID motion_ID, BOOL bMixIn, PlayCall u8 channel /*= 0*/) { VERIFY(motion_ID.valid()); + if (!motion_ID.valid()) return NULL; + CMotionDef* m_def = m_Motions[motion_ID.slot].motions.motion_def(motion_ID.idx); VERIFY(m_def); if (!m_def) return NULL; @@ -928,12 +932,13 @@ void CKinematicsAnimated::LL_BuldBoneMatrixDequatize(const CBoneData* bd, u8 cha { u16 SelfID = bd->GetSelfID(); CBlendInstance& BLEND_INST = LL_GetBlendInstance(SelfID); + xrSRWLockGuard guard(&BLEND_INST.blend_lock, true); const CBlendInstance::BlendSVec& Blend = BLEND_INST.blend_vector(); CKey BK[MAX_CHANNELS][MAX_BLENDED]; //base keys BlendSVecCIt BI; - for (BI = Blend.begin(); BI != Blend.end(); BI++) + for (CBlend* BI : Blend) { - CBlend* B = *BI; + CBlend* B = BI; int& b_count = keys.chanel_blend_conts[B->channel]; CKey* D = &keys.keys[B->channel][b_count]; if (!(channel_mask & (1 << B->channel))) @@ -1126,3 +1131,11 @@ MotionID CKinematicsAnimated::ID_Motion(LPCSTR N, u16 slot) return motion_ID; } #endif + +CBlend* CKinematicsAnimated::PlayFX_Safe(LPCSTR N, float power_scale) +{ + MotionID motion_ID = ID_FX_Safe(N); + if (motion_ID.valid()) + return PlayFX(motion_ID, power_scale); + return nullptr; +} diff --git a/src/Layers/xrRender/SkeletonAnimated.h b/src/Layers/xrRender/SkeletonAnimated.h index 77e5dfbfcb..5ebb594107 100644 --- a/src/Layers/xrRender/SkeletonAnimated.h +++ b/src/Layers/xrRender/SkeletonAnimated.h @@ -16,6 +16,7 @@ class CBlendInstance // Bone Instance Blend List (per-bone data) typedef svector BlendSVec; typedef BlendSVec::iterator BlendSVecIt; typedef BlendSVec::const_iterator BlendSVecCIt; + xrSRWLock blend_lock; private: BlendSVec Blend; public: @@ -28,9 +29,10 @@ class CBlendInstance // Bone Instance Blend List (per-bone data) u32 mem_usage() { + xrSRWLockGuard guard(&blend_lock, true); u32 sz = sizeof(*this); - for (BlendSVecIt it = Blend.begin(); it != Blend.end(); it++) - sz += (*it)->mem_usage(); + for (CBlend* B : Blend) + sz += B->mem_usage(); return sz; } }; @@ -175,7 +177,8 @@ class ECORE_API CKinematicsAnimated : public CKinematics, public IKinematicsAnim MotionID ID_FX(LPCSTR N); MotionID ID_FX_Safe(LPCSTR N); CBlend* PlayFX(LPCSTR N, float power_scale); - CBlend* PlayFX(MotionID M, float power_scale); + CBlend* PlayFX(MotionID M, float power_scale) override; + CBlend* PlayFX_Safe (LPCSTR N, float power_scale) override; const CPartition& partitions() const { return *m_Partition; }; diff --git a/src/Layers/xrRender/SkeletonCustom.cpp b/src/Layers/xrRender/SkeletonCustom.cpp index cf7708510e..d48b522d90 100644 --- a/src/Layers/xrRender/SkeletonCustom.cpp +++ b/src/Layers/xrRender/SkeletonCustom.cpp @@ -8,12 +8,9 @@ #ifndef _EDITOR #include "../../xrEngine/Render.h" #endif + int psSkeletonUpdate = 32; -xrCriticalSection UCalc_Mutex -#ifdef PROFILE_CRITICAL_SECTIONS - (MUTEX_PROFILE_ID(UCalc_Mutex)) -#endif // PROFILE_CRITICAL_SECTIONS -; +xrCriticalSection wallmarks_cs; #ifndef _EDITOR #include "../../xrServerEntities/smart_cast.h" @@ -211,7 +208,8 @@ void CKinematics::Load(const char* N, IReader* data, u32 dwFlags) bone_map_N = xr_new(); bone_map_P = xr_new(); bones = xr_new(); - bone_instances = NULL; + bone_instances = nullptr; + bones_size = u16(0); // Load bones #pragma todo("container is created in stack!") @@ -332,6 +330,8 @@ void CKinematics::Load(const char* N, IReader* data, u32 dwFlags) wm_frame = u32(-1); LL_Validate(); + + bones_size = bones->size(); } //--DSR-- SilencerOverheat_start @@ -424,10 +424,11 @@ void CKinematics::Copy(dxRender_Visual* P) { inherited::Copy(P); - CKinematics* pFrom = fast_dynamic_cast(P); + CKinematics* pFrom = (CKinematics*)P->dcast_PKinematics(); VERIFY(pFrom); pUserData = pFrom->pUserData; bones = pFrom->bones; + bones_size = pFrom->bones_size; iRoot = pFrom->iRoot; bone_map_N = pFrom->bone_map_N; bone_map_P = pFrom->bone_map_P; @@ -571,7 +572,7 @@ void CKinematics::Visibility_Update() // check visible for (u32 c_it = 0; c_it < children.size(); c_it++) { - CSkeletonX* _c = fast_dynamic_cast(children[c_it]); + CSkeletonX* _c = smart_cast(children[c_it]); VERIFY(_c); if (!_c->has_visible_bones()) { @@ -586,7 +587,7 @@ void CKinematics::Visibility_Update() // check invisible for (u32 _it = 0; _it < children_invisible.size(); _it++) { - CSkeletonX* _c = fast_dynamic_cast(children_invisible[_it]); + CSkeletonX* _c = smart_cast(children_invisible[_it]); VERIFY(_c) ; if (_c->has_visible_bones()) { @@ -722,6 +723,7 @@ void CKinematics::AddWallmark(const Fmatrix* parent_xform, const Fvector3& start } } + xrCriticalSectionGuard guard(wallmarks_cs); // find similar wm for (u32 wm_idx = 0; wm_idx < wallmarks.size(); wm_idx++) { @@ -769,37 +771,48 @@ struct zero_wm_pred void CKinematics::CalculateWallmarks() { + PROF_EVENT("Calculate Wallmarks"); + xrCriticalSectionGuard guard(wallmarks_cs); if (!wallmarks.empty() && (wm_frame != RDEVICE.dwFrame)) { wm_frame = RDEVICE.dwFrame; - bool need_remove = false; - for (SkeletonWMVecIt it = wallmarks.begin(); it != wallmarks.end(); it++) + for (SkeletonWMVecIt it = wallmarks.begin(); it != wallmarks.end();) { intrusive_ptr& wm = *it; + + if (wm == 0) + { + it = wallmarks.erase(it); + continue; + } + float w = wm->TimeEnd() == -1.f ? 0.f : (RDEVICE.fTimeGlobal - wm->TimeStart()) / wm->TimeEnd(); if (w < 1.f) { // append wm to WallmarkEngine if (::Render->ViewBase.testSphere_dirty(wm->m_Bounds.P, wm->m_Bounds.R)) - //::Render->add_SkeletonWallmark (wm); - ::RImplementation.add_SkeletonWallmark(wm); + { + ::RImplementation.add_SkeletonWallmark(std::move(wm)); + it = wallmarks.erase(it); + } + else + { + it++; + } + } else { // remove wallmark - need_remove = true; + it = wallmarks.erase(it); } } - if (need_remove) - { - SkeletonWMVecIt new_end = std::remove_if(wallmarks.begin(), wallmarks.end(), zero_wm_pred()); - wallmarks.erase(new_end, wallmarks.end()); - } } } void CKinematics::RenderWallmark(intrusive_ptr wm, FVF::LIT* & V) { + PROF_EVENT("CKinematics::RenderWallmark"); VERIFY(wm); VERIFY(V); VERIFY2(bones, "Invalid visual. Bones already released."); @@ -885,6 +898,7 @@ void CKinematics::RenderWallmark(intrusive_ptr wm, FVF::LIT* void CKinematics::ClearWallmarks() { + xrCriticalSectionGuard guard(wallmarks_cs); // for (SkeletonWMVecIt it=wallmarks.begin(); it!=wallmarks.end(); it++) // xr_delete (*it); wallmarks.clear(); diff --git a/src/Layers/xrRender/SkeletonCustom.h b/src/Layers/xrRender/SkeletonCustom.h index 5a3d611020..e79e83dafd 100644 --- a/src/Layers/xrRender/SkeletonCustom.h +++ b/src/Layers/xrRender/SkeletonCustom.h @@ -118,7 +118,7 @@ class CKinematics : public FHierrarhyVisual, public IKinematics #ifdef OPTIMIZE_CALCULATE_BONES IC bool canBeOptimized() { - return spatialParent && spatialParent->canOptimizeCalculateBones(); + return spatialParent && spatialParent->canOptimizeCalculateBones; } #endif @@ -133,6 +133,7 @@ class CKinematics : public FHierrarhyVisual, public IKinematics CInifile* pUserData; CBoneInstance* bone_instances; // bone instances vecBones* bones; // all bones (shared) + u16 bones_size; u16 iRoot; // Root bone index // Fast search @@ -142,11 +143,9 @@ class CKinematics : public FHierrarhyVisual, public IKinematics BOOL Update_Visibility; u32 UCalc_Time; s32 UCalc_Visibox; + u32 Visibox_frame = 0; bool UCalc_ThisFrame; - xrCriticalSection UCalc_Mutex; - xrCriticalSection UCalc_Mutex2; - Flags64 visimask; Flags64 hidden_bones; @@ -241,7 +240,68 @@ class CKinematics : public FHierrarhyVisual, public IKinematics } ICF Fmatrix& _BCL LL_GetTransform(u16 bone_id) { return LL_GetBoneVisible(bone_id) ? LL_GetBoneInstance(bone_id).mTransform : LL_GetBoneInstance(bone_id).mTransformHidden; } + ICF Fmatrix& _BCL LL_GetTransform_safed(u16 bone_id) { xrCriticalSectionGuard guard(&UCalc_Mutex); return LL_GetBoneVisible(bone_id) ? LL_GetBoneInstance(bone_id).mTransform : LL_GetBoneInstance(bone_id).mTransformHidden; } ICF const Fmatrix& _BCL LL_GetTransform(u16 bone_id) const { return LL_GetBoneVisible(bone_id) ? LL_GetBoneInstance(bone_id).mTransform : LL_GetBoneInstance(bone_id).mTransformHidden; } + ICF void _BCL LL_GetBoneLocalPosition(u16 bone_id, Fvector& result) + { + xrCriticalSectionGuard guard(&UCalc_Mutex); + result = LL_GetBoneInstance(bone_id).mTransform.c; + } + ICF void _BCL LL_GetBoneLocalTransform(u16 bone_id, Fmatrix& result) + { + xrCriticalSectionGuard guard(&UCalc_Mutex); + result = LL_GetBoneInstance(bone_id).mTransform; + } + ICF void _BCL LL_GetBoneWorldPosition(u16 bone_id, const Fmatrix& xform, Fvector& result) + { + LL_GetBoneLocalPosition(bone_id, result); + xform.transform_tiny(result); + } + ICF void _BCL LL_GetBoneWorldTransform(u16 bone_id, const Fmatrix& xform, Fmatrix& result) + { + LL_GetBoneLocalTransform(bone_id, result); + result.mulA_43(xform); + } + ICF void _BCL CalculateBBox(BOOL bforce = TRUE) + { + if (!bforce && Device.dwFrame == Visibox_frame) + return; + + Visibox_frame = Device.dwFrame; + + Fbox Box; + Box.invalidate(); + for (u32 b = 0; b < bones->size(); b++) + { + if (!LL_GetBoneVisible(u16(b))) + continue; + + Fobb& obb = (*bones)[b]->obb; + Fmatrix& Mbone = LL_GetBoneInstance((u16)b).mTransform; + Fmatrix Mbox; + obb.xform_get(Mbox); + Fmatrix X; + X.mul_43(Mbone, Mbox); + Fvector& S = obb.m_halfsize; + + Fvector P, A; + A.set(-S.x, -S.y, -S.z); X.transform_tiny(P, A); Box.modify(P); + A.set(-S.x, -S.y, S.z); X.transform_tiny(P, A); Box.modify(P); + A.set(S.x, -S.y, S.z); X.transform_tiny(P, A); Box.modify(P); + A.set(S.x, -S.y, -S.z); X.transform_tiny(P, A); Box.modify(P); + A.set(-S.x, S.y, -S.z); X.transform_tiny(P, A); Box.modify(P); + A.set(-S.x, S.y, S.z); X.transform_tiny(P, A); Box.modify(P); + A.set(S.x, S.y, S.z); X.transform_tiny(P, A); Box.modify(P); + A.set(S.x, S.y, -S.z); X.transform_tiny(P, A); Box.modify(P); + } + + if (bones->size()) + { + vis.box.min = (Box.min); + vis.box.max = (Box.max); + vis.box.getsphere(vis.sphere.P, vis.sphere.R); + } + } ICF Fmatrix& LL_GetTransform_R(u16 bone_id) { return LL_GetBoneInstance(bone_id).mRenderTransform; } // rendering only Fobb& LL_GetBox(u16 bone_id) @@ -302,7 +362,7 @@ class CKinematics : public FHierrarhyVisual, public IKinematics void DebugRender (Fmatrix& XFORM); #endif protected: - virtual shared_str _BCL getDebugName() { return dbg_name; } + virtual shared_str getDebugName() { return dbg_name; } public: // General "Visual" stuff diff --git a/src/Layers/xrRender/SkeletonRigid.cpp b/src/Layers/xrRender/SkeletonRigid.cpp index 00a54c7f91..d62545848a 100644 --- a/src/Layers/xrRender/SkeletonRigid.cpp +++ b/src/Layers/xrRender/SkeletonRigid.cpp @@ -104,68 +104,21 @@ void CKinematics::CalculateBones(BOOL bForceExact) // mark UCalc_Visibox = -(::Random.randI(psSkeletonUpdate - 1)); UCalc_ThisFrame = true; - - // the update itself - Fbox Box; - Box.invalidate(); - for (u32 b = 0; b < bones->size(); b++) - { - if (!LL_GetBoneVisible(u16(b))) continue; - Fobb& obb = (*bones)[b]->obb; - Fmatrix& Mbone = bone_instances[b].mTransform; - Fmatrix Mbox; - obb.xform_get(Mbox); - Fmatrix X; - X.mul_43(Mbone, Mbox); - Fvector& S = obb.m_halfsize; - - Fvector P, A; - A.set(-S.x, -S.y, -S.z); - X.transform_tiny(P, A); - Box.modify(P); - A.set(-S.x, -S.y, S.z); - X.transform_tiny(P, A); - Box.modify(P); - A.set(S.x, -S.y, S.z); - X.transform_tiny(P, A); - Box.modify(P); - A.set(S.x, -S.y, -S.z); - X.transform_tiny(P, A); - Box.modify(P); - A.set(-S.x, S.y, -S.z); - X.transform_tiny(P, A); - Box.modify(P); - A.set(-S.x, S.y, S.z); - X.transform_tiny(P, A); - Box.modify(P); - A.set(S.x, S.y, S.z); - X.transform_tiny(P, A); - Box.modify(P); - A.set(S.x, S.y, -S.z); - X.transform_tiny(P, A); - Box.modify(P); - } - if (bones->size()) - { - // previous frame we have updated box - update sphere - vis.box.min = (Box.min); - vis.box.max = (Box.max); - vis.box.getsphere(vis.sphere.P, vis.sphere.R); - } + CalculateBBox(); #ifdef DEBUG // Validate - VERIFY3 (_valid(vis.box.min)&&_valid(vis.box.max), "Invalid bones-xform in model", dbg_name.c_str()); - if(vis.sphere.R>1000.f) + VERIFY3(_valid(vis.box.min) && _valid(vis.box.max), "Invalid bones-xform in model", dbg_name.c_str()); + if (vis.sphere.R > 1000.f) { - for(u16 ii=0; iiLL_GetBoneInstance(K->LL_GetBoneRoot()).mTransform; - if(MrootBone.c.y >10000) - { - Msg("all bones transform:--------[%s]",s); - - for(u16 ii=0; iiLL_BoneCount();++ii){ + Fmatrix& MrootBone = K->LL_GetBoneInstance(K->LL_GetBoneRoot()).mTransform; + if (MrootBone.c.y > 10000) + { + Msg("all bones transform:--------[%s]", s); + + for (u16 ii = 0; ii < K->LL_BoneCount(); ++ii) { Fmatrix tr; tr = K->LL_GetTransform(ii); - Log("bone ",K->LL_BoneName_dbg(ii)); - Log("bone_matrix",tr); + Log("bone ", K->LL_BoneName_dbg(ii)); + Log("bone_matrix", tr); } Log("end-------"); - VERIFY3(0,"check_kinematics failed for ", s); + VERIFY3(0, "check_kinematics failed for ", s); } } #endif void CKinematics::BuildBoneMatrix(const CBoneData* bd, CBoneInstance& bi, const Fmatrix* parent, - u8 channel_mask/* = (1<<0)*/) + u8 channel_mask/* = (1<<0)*/) { if (LL_GetBoneVisible(bd->GetSelfID())) { @@ -224,24 +177,24 @@ void CKinematics::CLBone(const CBoneData* bd, CBoneInstance& bi, const Fmatrix* void CKinematics::Bone_GetAnimPos(Fmatrix& pos, u16 id, u8 mask_channel, bool ignore_callbacks) { - R_ASSERT(idGetSelfID(); CBoneInstance& BONE_INST = LL_GetBoneInstance(SelfID); CLBone(bd, BONE_INST, parent, u8(-1)); // Calculate children - for (xr_vector::iterator C = bd->children.begin(); C != bd->children.end(); C++) - Bone_Calculate(*C, &BONE_INST.mTransform); + for (CBoneData* bd : bd->children) + Bone_Calculate(bd, &BONE_INST.mTransform); } void CKinematics::BoneChain_Calculate(const CBoneData* bd, CBoneInstance& bi, u8 mask_channel, bool ignore_callbacks) diff --git a/src/Layers/xrRender/SkeletonX.cpp b/src/Layers/xrRender/SkeletonX.cpp index 197a41a5a4..f4e4cd25ab 100644 --- a/src/Layers/xrRender/SkeletonX.cpp +++ b/src/Layers/xrRender/SkeletonX.cpp @@ -58,6 +58,8 @@ void CSkeletonX::_Copy(CSkeletonX* B) ////////////////////////////////////////////////////////////////////// void CSkeletonX::_Render(ref_geom& hGeom, u32 vCount, u32 iOffset, u32 pCount) { + xrCriticalSectionGuard guard(&Parent->UCalc_Mutex); + PROF_EVENT("CSkeletonX::_Render"); Fmatrix p_WV, p_WVP; #ifdef USE_DX11 // @@ -110,6 +112,7 @@ void CSkeletonX::_Render(ref_geom& hGeom, u32 vCount, u32 iOffset, u32 pCount) break; case RM_SINGLE: { + PROF_EVENT("RM_SINGLE"); Fmatrix W; W.mul_43(RCache.xforms.m_w, Parent->LL_GetTransform_R(u16(RMS_boneid))); RCache.set_xform_world(W); @@ -124,29 +127,36 @@ void CSkeletonX::_Render(ref_geom& hGeom, u32 vCount, u32 iOffset, u32 pCount) case RM_SKINNING_3B: case RM_SKINNING_4B: { + PROF_EVENT("RM_SKINNING"); // Transfer matrices ( current and previous ) R_constant* array = RCache.get_c(s_bones_array_const); - R_constant* array_prev = RCache.get_c(s_bones_array_prev_const); + R_constant* array_prev = RImplementation.phase == RImplementation.PHASE_NORMAL ? RCache.get_c(s_bones_array_prev_const) : array; - u32 count = RMS_bonecount; - for (u32 mid = 0; mid < count; mid++) { - Fmatrix& M = Parent->LL_GetTransform_R(u16(mid)); - u32 id = mid * 3; - RCache.set_ca(&*array, id + 0, M._11, M._21, M._31, M._41); - RCache.set_ca(&*array, id + 1, M._12, M._22, M._32, M._42); - RCache.set_ca(&*array, id + 2, M._13, M._23, M._33, M._43); + PROF_EVENT("SEND_MATRICES"); + u32 count = RMS_bonecount; + for (u32 mid = 0; mid < count; mid++) + { + Fmatrix& M = Parent->LL_GetTransform_R(u16(mid)); + u32 id = mid * 3; + RCache.set_ca(&*array, id + 0, M._11, M._21, M._31, M._41); + RCache.set_ca(&*array, id + 1, M._12, M._22, M._32, M._42); + RCache.set_ca(&*array, id + 2, M._13, M._23, M._33, M._43); #ifdef USE_DX11 - if (RImplementation.o.ssfx_motionvectors) - { - // Save previous transform - Fmatrix& Mprev = Parent->LL_GetBoneInstance(u16(mid)).mRenderTransform_prev; - RCache.set_ca(&*array_prev, id + 0, Mprev._11, Mprev._21, Mprev._31, Mprev._41); - RCache.set_ca(&*array_prev, id + 1, Mprev._12, Mprev._22, Mprev._32, Mprev._42); - RCache.set_ca(&*array_prev, id + 2, Mprev._13, Mprev._23, Mprev._33, Mprev._43); - } + if (RImplementation.phase == RImplementation.PHASE_NORMAL) + { + if (RImplementation.o.ssfx_motionvectors) + { + // Save previous transform + Fmatrix& Mprev = Parent->LL_GetBoneInstance(u16(mid)).mRenderTransform_prev; + RCache.set_ca(&*array_prev, id + 0, Mprev._11, Mprev._21, Mprev._31, Mprev._41); + RCache.set_ca(&*array_prev, id + 1, Mprev._12, Mprev._22, Mprev._32, Mprev._42); + RCache.set_ca(&*array_prev, id + 2, Mprev._13, Mprev._23, Mprev._33, Mprev._43); + } + } #endif + } } // render @@ -167,6 +177,7 @@ void CSkeletonX::_Render(ref_geom& hGeom, u32 vCount, u32 iOffset, u32 pCount) void CSkeletonX::_Render_soft(ref_geom& hGeom, u32 vCount, u32 iOffset, u32 pCount) { + PROF_EVENT("CSkeletonX::_Render_soft"); u32 vOffset = cache_vOffset; _VertexStream& _VS = RCache.Vertex; @@ -253,7 +264,7 @@ void CSkeletonX::_Load(const char* N, IReader* data, u32& dwVertCount) dwVertCount = data->r_u32(); RenderMode = RM_SKINNING_SOFT; - Render->shader_option_skinning(-1); + Engine.External.SetSkinningMode(); switch (dwVertType) { @@ -283,21 +294,21 @@ void CSkeletonX::_Load(const char* N, IReader* data, u32& dwVertCount) // HW- single bone RenderMode = RM_SINGLE; RMS_boneid = *bids.begin(); - Render->shader_option_skinning(0); + Engine.External.SetSkinningMode(0); } else if (sw_bones_cnt <= hw_bones_cnt) { // HW- one weight RenderMode = RM_SKINNING_1B; RMS_bonecount = sw_bones_cnt + 1; - Render->shader_option_skinning(1); + Engine.External.SetSkinningMode(1); } else { // software crc = crc32(data->pointer(), size); Vertices1W.create(crc, dwVertCount, (vertBoned1W*)data->pointer()); - Render->shader_option_skinning(-1); + Engine.External.SetSkinningMode(); } #endif } @@ -326,14 +337,14 @@ void CSkeletonX::_Load(const char* N, IReader* data, u32& dwVertCount) // HW- two weights RenderMode = RM_SKINNING_2B; RMS_bonecount = sw_bones_cnt + 1; - Render->shader_option_skinning(2); + Engine.External.SetSkinningMode(2); } else { // software crc = crc32(data->pointer(), size); Vertices2W.create(crc, dwVertCount, (vertBoned2W*)data->pointer()); - Render->shader_option_skinning(-1); + Engine.External.SetSkinningMode(); } } break; @@ -359,13 +370,13 @@ void CSkeletonX::_Load(const char* N, IReader* data, u32& dwVertCount) { RenderMode = RM_SKINNING_3B; RMS_bonecount = sw_bones_cnt + 1; - Render->shader_option_skinning(3); + Engine.External.SetSkinningMode(3); } else { crc = crc32(data->pointer(), size); Vertices3W.create(crc, dwVertCount, (vertBoned3W*)data->pointer()); - Render->shader_option_skinning(-1); + Engine.External.SetSkinningMode(); } } break; @@ -392,13 +403,13 @@ void CSkeletonX::_Load(const char* N, IReader* data, u32& dwVertCount) { RenderMode = RM_SKINNING_4B; RMS_bonecount = sw_bones_cnt + 1; - Render->shader_option_skinning(4); + Engine.External.SetSkinningMode(4); } else { crc = crc32(data->pointer(), size); Vertices4W.create(crc, dwVertCount, (vertBoned4W*)data->pointer()); - Render->shader_option_skinning(-1); + Engine.External.SetSkinningMode(); } } break; diff --git a/src/Layers/xrRender/WallmarksEngine.cpp b/src/Layers/xrRender/WallmarksEngine.cpp index 31b1f8a6a3..cf4677852a 100644 --- a/src/Layers/xrRender/WallmarksEngine.cpp +++ b/src/Layers/xrRender/WallmarksEngine.cpp @@ -15,41 +15,41 @@ float wallmark_range_skeleton = 50.f; namespace WallmarksEngine { - struct wm_slot - { - typedef CWallmarksEngine::StaticWMVec StaticWMVec; - ref_shader shader; - StaticWMVec static_items; - xr_vector> skeleton_items; - - wm_slot(ref_shader sh) - { - shader = sh; - static_items.reserve(256); - skeleton_items.reserve(256); - } - }; + struct wm_slot + { + typedef CWallmarksEngine::StaticWMVec StaticWMVec; + typedef CWallmarksEngine::StaticWMSectorMap StaticWMSectorMap; + ref_shader shader; + StaticWMSectorMap static_items; + xr_vector> skeleton_items; + + wm_slot(ref_shader sh) + { + shader = sh; + skeleton_items.reserve(256); + } + }; } // #include "xr_effsun.h" -const float W_DIST_FADE = 15.f; -const float W_DIST_FADE_SQR = W_DIST_FADE * W_DIST_FADE; -const float I_DIST_FADE_SQR = 1.f / W_DIST_FADE_SQR; -const int MAX_TRIS = 1024 * 16; +constexpr const float W_DIST_FADE = 15.f; +constexpr const float W_DIST_FADE_SQR = W_DIST_FADE * W_DIST_FADE; +constexpr const float I_DIST_FADE_SQR = 1.f / W_DIST_FADE_SQR; +constexpr const int MAX_TRIS = 1024 * 16; IC bool operator ==(const CWallmarksEngine::wm_slot* slot, const ref_shader& shader) { return slot->shader == shader; } CWallmarksEngine::wm_slot* CWallmarksEngine::FindSlot(ref_shader shader) { - WMSlotVecIt it = std::find(marks.begin(), marks.end(), shader); - return (it != marks.end()) ? *it : 0; + auto it = std::find(marks.begin(), marks.end(), shader); + return (it != marks.end()) ? *it : 0; } CWallmarksEngine::wm_slot* CWallmarksEngine::AppendSlot(ref_shader shader) { - marks.push_back(xr_new(shader)); - return marks.back(); + marks.push_back(xr_new(shader)); + return marks.back(); } ////////////////////////////////////////////////////////////////////// @@ -58,27 +58,29 @@ CWallmarksEngine::wm_slot* CWallmarksEngine::AppendSlot(ref_shader shader) CWallmarksEngine::CWallmarksEngine() #ifdef PROFILE_CRITICAL_SECTIONS - :lock(MUTEX_PROFILE_ID(CWallmarksEngine)) + :lock(MUTEX_PROFILE_ID(CWallmarksEngine)) #endif // PROFILE_CRITICAL_SECTIONS { - static_pool.reserve(256); - marks.reserve(256); - hGeom.create(FVF::F_LIT, RCache.Vertex.Buffer(), NULL); + hGeom.create(FVF::F_LIT, RCache.Vertex.Buffer(), NULL); } CWallmarksEngine::~CWallmarksEngine() { - clear(); - hGeom.destroy(); + clear(); + hGeom.destroy(); } void CWallmarksEngine::clear() { - { - for (WMSlotVecIt p_it = marks.begin(); p_it != marks.end(); p_it++) - { - for (StaticWMVecIt m_it = (*p_it)->static_items.begin(); m_it != (*p_it)->static_items.end(); m_it++) - static_wm_destroy(*m_it); + { + for (auto p_it = marks.begin(); p_it != marks.end(); p_it++) + { + for (auto& [sector, static_vec] : (*p_it)->static_items) + { + for (auto m_it = static_vec.begin(); m_it != static_vec.end(); m_it++) + static_wm_destroy(*m_it); + } + xr_delete(*p_it); } marks.clear(); @@ -211,29 +213,29 @@ void CWallmarksEngine::AddWallmark_internal(CDB::TRI* pTri, const Fvector* pVert { // query for polygons in bounding box // calculate adjacency - { - Fbox bb_query; - Fvector bbc, bbd; - bb_query.set(contact_point, contact_point); - bb_query.grow(sz * 2.5f); - bb_query.get_CD(bbc, bbd); - xrc.box_options(CDB::OPT_FULL_TEST); - xrc.box_query(g_pGameLevel->ObjectSpace.GetStaticModel(), bbc, bbd); - u32 triCount = xrc.r_count(); - if (0 == triCount) - return; - - CDB::TRI* tris = g_pGameLevel->ObjectSpace.GetStaticTris(); - sml_collector.clear(); - sml_collector.add_face_packed_D(pVerts[pTri->verts[0]], pVerts[pTri->verts[1]], pVerts[pTri->verts[2]], 0); - for (u32 t = 0; t < triCount; t++) - { - CDB::TRI* T = tris + xrc.r_begin()[t].id; - if (T == pTri) continue; - sml_collector.add_face_packed_D(pVerts[T->verts[0]], pVerts[T->verts[1]], pVerts[T->verts[2]], 0); - } - sml_collector.calc_adjacency(sml_adjacency); - } + Fbox bb_query; + Fvector bbc, bbd; + bb_query.set(contact_point, contact_point); + bb_query.grow(sz * 2.5f); + bb_query.get_CD(bbc, bbd); + xrc.box_options(CDB::OPT_FULL_TEST); + xrc.box_query(g_pGameLevel->ObjectSpace.GetStaticModel(), bbc, bbd); + u32 triCount = xrc.r_count(); + if (0 == triCount) + return; + + u32 real_tcnt = triCount + 1u; + CDB::TRI* tris = g_pGameLevel->ObjectSpace.GetStaticTris(); + sml_collector.clear(); + sml_collector.reserve(real_tcnt); + sml_collector.add_face_packed_D(pVerts[pTri->verts[0]], pVerts[pTri->verts[1]], pVerts[pTri->verts[2]], 0); + for (u32 t = 0; t < triCount; t++) + { + CDB::TRI* T = tris + xrc.r_begin()[t].id; + if (T == pTri) continue; + sml_collector.add_face_packed_D(pVerts[T->verts[0]], pVerts[T->verts[1]], pVerts[T->verts[2]], 0); + } + sml_collector.calc_adjacency(sml_adjacency); // calc face normal Fvector N; @@ -250,6 +252,7 @@ void CWallmarksEngine::AddWallmark_internal(CDB::TRI* pTri, const Fvector* pVert // create wallmark static_wallmark* W = static_wm_allocate(); if (ttl) W->m_fTimeEnd = ttl; + W->verts.reserve(real_tcnt * 3); RecurseTri(0, mView, *W); // calc sphere @@ -269,14 +272,17 @@ void CWallmarksEngine::AddWallmark_internal(CDB::TRI* pTri, const Fvector* pVert bb.getsphere(W->bounds.P, W->bounds.R); } + IRender_Sector* S = RImplementation.detectLastSector(W->bounds.P); + // if (W->bounds.R < 1.f) { // search if similar wallmark exists wm_slot* slot = FindSlot(hShader); if (slot) { - StaticWMVecIt it = slot->static_items.begin(); - StaticWMVecIt end = slot->static_items.end(); + StaticWMVec& sector_items = slot->static_items[S]; + auto it = sector_items.begin(); + auto end = sector_items.end(); for (; it != end; it++) { static_wallmark* wm = *it; @@ -295,7 +301,8 @@ void CWallmarksEngine::AddWallmark_internal(CDB::TRI* pTri, const Fvector* pVert } // no similar - register _new_ - slot->static_items.push_back(W); + slot->static_items[S].push_back(W); + } //else //{ @@ -309,6 +316,8 @@ void CWallmarksEngine::AddWallmark_internal(CDB::TRI* pTri, const Fvector* pVert AddWallmark_internal(pTri, pVerts, contact_point, hShader, sz, ttl, random_rotation ? ::Random.randF(-20.f, 20.f) : 0.f); } +BOOL r_wallmarks_static = TRUE; +BOOL r_wallmarks_dynamic = TRUE; void CWallmarksEngine::AddStaticWallmark(CDB::TRI* pTri, const Fvector* pVerts, const Fvector& contact_point, ref_shader hShader, float sz, float ttl, bool ignore_opt, bool random_rotation) { @@ -318,9 +327,8 @@ void CWallmarksEngine::AddStaticWallmark(CDB::TRI* pTri, const Fvector* pVerts, void CWallmarksEngine::AddStaticWallmark(CDB::TRI* pTri, const Fvector* pVerts, const Fvector& contact_point, ref_shader hShader, float sz, float ttl, bool ignore_opt, float rotation) { - // optimization cheat: don't allow wallmarks more than 100 m from viewer/actor - if (!ignore_opt && contact_point.distance_to_sqr(Device.vCameraPosition) > _sqr(wallmark_range_static)) - return; + if (!r_wallmarks_static) + return; // Physics may add wallmarks in parallel with rendering lock.Enter(); @@ -331,9 +339,8 @@ void CWallmarksEngine::AddStaticWallmark(CDB::TRI* pTri, const Fvector* pVerts, void CWallmarksEngine::AddSkeletonWallmark(const Fmatrix* xf, CKinematics* obj, ref_shader& sh, const Fvector& start, const Fvector& dir, float size, float ttl, bool ignore_opt) { - if (::RImplementation.phase != CRender::PHASE_NORMAL) return; - // optimization cheat: don't allow wallmarks more than 50 m from viewer/actor - if (!ignore_opt && xf->c.distance_to_sqr(Device.vCameraPosition) > _sqr(wallmark_range_skeleton)) return; + if (!r_wallmarks_dynamic) + return; VERIFY(obj&&xf&&(size>EPS_L)); lock.Enter(); @@ -343,26 +350,25 @@ void CWallmarksEngine::AddSkeletonWallmark(const Fmatrix* xf, CKinematics* obj, void CWallmarksEngine::AddSkeletonWallmark(intrusive_ptr wm) { - if (::RImplementation.phase != CRender::PHASE_NORMAL) return; - - if (!::RImplementation.val_bHUD) - { - lock.Enter(); - // search if similar wallmark exists - wm_slot* slot = FindSlot(wm->Shader()); - if (0 == slot) slot = AppendSlot(wm->Shader()); - // no similar - register _new_ - slot->skeleton_items.push_back(wm); + if (!r_wallmarks_dynamic) + return; + + lock.Enter (); + // search if similar wallmark exists + wm_slot* slot = FindSlot (wm->Shader()); + if (0==slot) slot = AppendSlot(wm->Shader()); + // no similar - register _new_ + slot->skeleton_items.push_back(wm); #ifdef DEBUG - wm->used_in_render = Device.dwFrame; + wm->used_in_render = Device.dwFrame; #endif - lock.Leave(); - } + lock.Leave (); } extern float r_ssaDISCARD; ICF void BeginStream(ref_geom hGeom, u32& w_offset, FVF::LIT*& w_verts, FVF::LIT*& w_start) { + PROF_EVENT("BeginStream"); w_offset = 0; w_verts = (FVF::LIT*)RCache.Vertex.Lock(MAX_TRIS * 3, hGeom->vb_stride, w_offset); w_start = w_verts; @@ -371,6 +377,7 @@ ICF void BeginStream(ref_geom hGeom, u32& w_offset, FVF::LIT*& w_verts, FVF::LIT ICF void FlushStream(ref_geom hGeom, ref_shader shader, u32& w_offset, FVF::LIT*& w_verts, FVF::LIT*& w_start, BOOL bSuppressCull) { + PROF_EVENT("FlushStream"); u32 w_count = u32(w_verts - w_start); RCache.Vertex.Unlock(w_count, hGeom->vb_stride); if (w_count) @@ -384,6 +391,74 @@ ICF void FlushStream(ref_geom hGeom, ref_shader shader, u32& w_offset, FVF::LIT* } } +void CWallmarksEngine::RemoveSkeletonWallmarksFromObject(CKinematics* obj) +{ + xrCriticalSectionGuard g(lock); + for (wm_slot* slot : marks) + { + slot->skeleton_items.erase(std::remove_if + ( + slot->skeleton_items.begin(), + slot->skeleton_items.end(), + [obj](const intrusive_ptr& wm) { return wm && wm->Parent() == obj; } + ), + slot->skeleton_items.end() + ); + } +} + +// demonized: Remove expired wallmarks before rendering +void CWallmarksEngine::UpdateWallmarks() +{ + if (marks.empty()) + return; + + // Toggle the lock if update is going to be in a separate thread + // xrCriticalSectionGuard g(lock); + for (wm_slot* slot : marks) + { + // static wallmarks + for (auto it_sect = slot->static_items.begin(); it_sect != slot->static_items.end();) + { + auto& [sector, static_vec] = *it_sect; + + for (u32 i = 0; i < static_vec.size();) + { + static_wallmark* W = static_vec[i]; + + if (W->TimeEnd() != -1.f && RDEVICE.fTimeGlobal > (W->TimeStart() + W->TimeEnd())) + { + static_wm_destroy(W); + static_vec[i] = static_vec.back(); + static_vec.pop_back(); + continue; + } + + i++; + } + + if (static_vec.empty()) + { + it_sect = slot->static_items.erase(it_sect); + continue; + } + + ++it_sect; + } + + // dynamic wallmarks + slot->skeleton_items.erase( + std::remove_if( + slot->skeleton_items.begin(), + slot->skeleton_items.end(), + [](const intrusive_ptr& wm) { return wm->TimeEnd() != -1.f && RDEVICE.fTimeGlobal > (wm->TimeStart() + wm->TimeEnd()); } + ), + slot->skeleton_items.end() + ); + } +} + +float r_wallmarks_ssa_k = 0.5f; void CWallmarksEngine::Render() { // if (marks.empty()) return; @@ -404,114 +479,122 @@ void CWallmarksEngine::Render() Device.Statistic->RenderDUMP_WMD_Count = 0; Device.Statistic->RenderDUMP_WMT_Count = 0; - float ssaCLIP = r_ssaDISCARD / 4; - - lock.Enter(); // Physics may add wallmarks in parallel with rendering - - for (WMSlotVecIt slot_it = marks.begin(); slot_it != marks.end(); slot_it++) - { - u32 w_offset; - FVF::LIT *w_verts, *w_start; - BeginStream(hGeom, w_offset, w_verts, w_start); - wm_slot* slot = *slot_it; - // static wallmarks - for (StaticWMVecIt w_it = slot->static_items.begin(); w_it != slot->static_items.end();) - { - static_wallmark* W = *w_it; - if (RImplementation.ViewBase.testSphere_dirty(W->bounds.P, W->bounds.R)) - { - Device.Statistic->RenderDUMP_WMS_Count++; - float dst = Device.vCameraPosition.distance_to_sqr(W->bounds.P); - float ssa = W->bounds.R * W->bounds.R / dst; - if (ssa >= ssaCLIP) - { - u32 w_count = u32(w_verts - w_start); - if ((w_count + W->verts.size()) >= (MAX_TRIS * 3)) - { - FlushStream(hGeom, slot->shader, w_offset, w_verts, w_start,FALSE); - BeginStream(hGeom, w_offset, w_verts, w_start); - } - static_wm_render(W, w_verts); - } - } - - // don't need to check wallmarks with infinite lifetime - if (W->TimeEnd() == -1.f) - { - w_it++; - continue; - } - - float w = W->TimeEnd() == -1.f ? 0.f : (RDEVICE.fTimeGlobal - W->TimeStart()) / W->TimeEnd(); - if (w < 1.f) - { - w_it++; - } - else - { - static_wm_destroy(W); - *w_it = slot->static_items.back(); - slot->static_items.pop_back(); - } - } - // Flush stream - FlushStream(hGeom, slot->shader, w_offset, w_verts, w_start,FALSE); //. remove line if !(suppress cull needed) - BeginStream(hGeom, w_offset, w_verts, w_start); - - // dynamic wallmarks - for (xr_vector>::iterator w_it = slot->skeleton_items.begin(); w_it != slot - -> - skeleton_items - .end(); - w_it++) - { - intrusive_ptr W = *w_it; - if (!W) - { - continue ; - } + constexpr const u32 max_verts = MAX_TRIS * 3; + + if ((r_wallmarks_static || r_wallmarks_dynamic) && !marks.empty()) + { + const float ssaCLIP = r_ssaDISCARD * r_wallmarks_ssa_k; + xrCriticalSectionGuard g(lock); // Physics may add wallmarks in parallel with rendering + + for (int i = 0; i < marks.size(); i++) + { + wm_slot* slot = marks[i]; + bool static_empty = !r_wallmarks_static || slot->static_items.empty(); + bool skeleton_empty = !r_wallmarks_dynamic || slot->skeleton_items.empty(); + if (static_empty && skeleton_empty) + continue; + + u32 w_offset; + FVF::LIT* w_verts, * w_start; + BeginStream(hGeom, w_offset, w_verts, w_start); + + // static wallmarks + if (!static_empty) + { + PROF_EVENT("STATIC_WALLMARKS"); + for (auto& [sector, static_vec] : slot->static_items) + { + if (!RImplementation.GMBase.is_sector_visible(static_cast(sector))) + continue; + + for (int j = 0; j < static_vec.size(); j++) + { + static_wallmark* W = static_vec[j]; + if (!RImplementation.ViewBase.testSphere_dirty(W->bounds.P, W->bounds.R)) + continue; + + Device.Statistic->RenderDUMP_WMS_Count++; + float dst = Device.vCameraPosition.distance_to_sqr(W->bounds.P); + float ssa = W->bounds.R * W->bounds.R / dst; + if (ssa >= ssaCLIP) + { + u32 w_count = u32(w_verts - w_start); + if ((w_count + W->verts.size()) >= max_verts) + { + FlushStream(hGeom, slot->shader, w_offset, w_verts, w_start, FALSE); + BeginStream(hGeom, w_offset, w_verts, w_start); + } + static_wm_render(W, w_verts); + } + } + } + + if (!skeleton_empty) + { + // Flush stream + FlushStream(hGeom, slot->shader, w_offset, w_verts, w_start, FALSE); //. remove line if !(suppress cull needed) + BeginStream(hGeom, w_offset, w_verts, w_start); + } + } + + // dynamic wallmarks + if (!skeleton_empty) + { + PROF_EVENT("DYNAMIC_WALLMARKS"); + for (int j = 0; j < slot->skeleton_items.size(); j++) + { + intrusive_ptr W = slot->skeleton_items[j]; + if (!W) continue; #ifdef DEBUG - if(W->used_in_render != Device.dwFrame) - { - Log("W->used_in_render",W->used_in_render); - Log("Device.dwFrame",Device.dwFrame); - VERIFY(W->used_in_render == Device.dwFrame); - } + if (W->used_in_render != Device.dwFrame) + { + Log("W->used_in_render", W->used_in_render); + Log("Device.dwFrame", Device.dwFrame); + VERIFY(W->used_in_render == Device.dwFrame); + } #endif - Device.Statistic->RenderDUMP_WMD_Count++; - u32 w_count = u32(w_verts - w_start); - if ((w_count + W->VCount()) >= (MAX_TRIS * 3)) - { - FlushStream(hGeom, slot->shader, w_offset, w_verts, w_start, TRUE); - BeginStream(hGeom, w_offset, w_verts, w_start); - } - - FVF::LIT* w_save = w_verts; - try - { - W->Parent()->RenderWallmark(W, w_verts); - } - catch (...) - { - Msg("! Failed to render dynamic wallmark"); - w_verts = w_save; - } + if (!RImplementation.ViewBase.testSphere_dirty(W->m_Bounds.P, W->m_Bounds.R)) + continue; + + Device.Statistic->RenderDUMP_WMD_Count++; + float dst = Device.vCameraPosition.distance_to_sqr(W->m_Bounds.P); + float ssa = W->m_Bounds.R * W->m_Bounds.R / dst; + if (ssa < ssaCLIP) + continue; + + u32 w_count = u32(w_verts - w_start); + if ((w_count + W->VCount()) >= max_verts) + { + FlushStream(hGeom, slot->shader, w_offset, w_verts, w_start, TRUE); + BeginStream(hGeom, w_offset, w_verts, w_start); + } + + FVF::LIT* w_save = w_verts; + try + { + W->Parent()->RenderWallmark(W, w_verts); + } + catch (...) + { + Msg("! Failed to render dynamic wallmark"); + w_verts = w_save; + } #ifdef DEBUG - W->used_in_render = u32(-1); + W->used_in_render = u32(-1); #endif - } - slot->skeleton_items.clear(); - // Flush stream - FlushStream(hGeom, slot->shader, w_offset, w_verts, w_start,TRUE); - } - - lock.Leave(); // Physics may add wallmarks in parallel with rendering - + } + } + + // Flush stream + FlushStream(hGeom, slot->shader, w_offset, w_verts, w_start, !skeleton_empty); + } + } + // Level-wmarks - RImplementation.r_dsgraph_render_wmarks(); + RImplementation.GMBase.r_dsgraph_render_wmarks(); Device.Statistic->RenderDUMP_WM.End(); // Projection diff --git a/src/Layers/xrRender/WallmarksEngine.h b/src/Layers/xrRender/WallmarksEngine.h index 2b30c50368..35f04f3269 100644 --- a/src/Layers/xrRender/WallmarksEngine.h +++ b/src/Layers/xrRender/WallmarksEngine.h @@ -29,8 +29,9 @@ class CWallmarksEngine IC float TimeEnd() { return m_fTimeEnd; } }; - DEFINE_VECTOR(static_wallmark*, StaticWMVec, StaticWMVecIt); - DEFINE_VECTOR(wm_slot*, WMSlotVec, WMSlotVecIt); + typedef xr_vector StaticWMVec; + typedef xr_unordered_map StaticWMSectorMap; + typedef xr_vector< wm_slot* > WMSlotVec; private: StaticWMVec static_pool; WMSlotVec marks; @@ -73,6 +74,10 @@ class CWallmarksEngine void AddSkeletonWallmark(const Fmatrix* xf, CKinematics* obj, ref_shader& sh, const Fvector& start, const Fvector& dir, float size, float ttl = 0.f, bool ignore_opt = false); + void RemoveSkeletonWallmarksFromObject(CKinematics* obj); + + void UpdateWallmarks(); + // render void Render(); diff --git a/src/Layers/xrRender/blenders/Blender_Recorder.cpp b/src/Layers/xrRender/blenders/Blender_Recorder.cpp index a39e6c0f2c..2c665d782c 100644 --- a/src/Layers/xrRender/blenders/Blender_Recorder.cpp +++ b/src/Layers/xrRender/blenders/Blender_Recorder.cpp @@ -252,9 +252,6 @@ void CBlender_Compile::PassSET_ablend_aref(BOOL bATest, u32 aRef) void CBlender_Compile::PassSET_Blend(BOOL bABlend, u32 abSRC, u32 abDST, BOOL bATest, u32 aRef) { PassSET_ablend_mode(bABlend, abSRC, abDST); -#ifdef DEBUG - if (strstr(Core.Params,"-noaref")) {bATest=FALSE; aRef=0; } -#endif PassSET_ablend_aref(bATest, aRef); } diff --git a/src/Layers/xrRender/dxDebugRender.cpp b/src/Layers/xrRender/dxDebugRender.cpp index c0580ee623..49fd423ea3 100644 --- a/src/Layers/xrRender/dxDebugRender.cpp +++ b/src/Layers/xrRender/dxDebugRender.cpp @@ -22,7 +22,7 @@ void dxDebugRender::Render() for (auto& m_vert : m_line_vertices_hud) { const u32& color = m_vert.first; - std::vector& vert_vec = m_vert.second; + xr_vector& vert_vec = m_vert.second; auto& ind_vec = m_line_indices_hud.at(color); #if defined(USE_DX10) || defined(USE_DX11) @@ -48,7 +48,7 @@ void dxDebugRender::Render() for (auto& m_vert : m_line_vertices) { const u32& color = m_vert.first; - std::vector& vert_vec = m_vert.second; + xr_vector& vert_vec = m_vert.second; auto& ind_vec = m_line_indices.at(color); #if defined(USE_DX10) || defined(USE_DX11) @@ -68,7 +68,7 @@ void dxDebugRender::add_lines(Fvector const* vertices, u32 const& vertex_count, for (auto& m_vert : m_line_vertices) { const u32& color = m_vert.first; - const std::vector& vert_vec = m_vert.second; + const xr_vector& vert_vec = m_vert.second; all_verts_count += vert_vec.size(); all_inds_count += m_line_indices.at(color).size(); } @@ -76,7 +76,7 @@ void dxDebugRender::add_lines(Fvector const* vertices, u32 const& vertex_count, for (auto& m_vert : m_line_vertices_hud) { const u32& color = m_vert.first; - const std::vector& vert_vec = m_vert.second; + const xr_vector& vert_vec = m_vert.second; all_verts_count += vert_vec.size(); all_inds_count += m_line_indices_hud.at(color).size(); } diff --git a/src/Layers/xrRender/dxDebugRender.h b/src/Layers/xrRender/dxDebugRender.h index ba3cdb5b2c..00bba342dc 100644 --- a/src/Layers/xrRender/dxDebugRender.h +++ b/src/Layers/xrRender/dxDebugRender.h @@ -25,10 +25,10 @@ class dxDebugRender : public IDebugRender virtual void dbg_DrawTRI(Fmatrix& T, Fvector& p1, Fvector& p2, Fvector& p3, u32 C); private: - xr_unordered_map> m_line_vertices; - xr_unordered_map> m_line_indices; - xr_unordered_map> m_line_vertices_hud; - xr_unordered_map> m_line_indices_hud; + xr_unordered_map> m_line_vertices; + xr_unordered_map> m_line_indices; + xr_unordered_map> m_line_vertices_hud; + xr_unordered_map> m_line_indices_hud; ref_shader m_dbgShaders[dbgShaderCount]; }; diff --git a/src/Layers/xrRender/dxEnvironmentRender.cpp b/src/Layers/xrRender/dxEnvironmentRender.cpp index 80d11602e8..e2f57a5be4 100644 --- a/src/Layers/xrRender/dxEnvironmentRender.cpp +++ b/src/Layers/xrRender/dxEnvironmentRender.cpp @@ -100,7 +100,16 @@ void dxEnvDescriptorRender::Copy(IEnvDescriptorRender& _in) void dxEnvDescriptorMixerRender::Copy(IEnvDescriptorMixerRender& _in) { - *this = *(dxEnvDescriptorMixerRender*)&_in; + dxEnvDescriptorMixerRender* other = (dxEnvDescriptorMixerRender*)&_in; + + clouds_r_textures.assign(other->clouds_r_textures.begin(), other->clouds_r_textures.end()); + clouds_r_textures.dwReference++; + + sky_r_textures.assign(other->sky_r_textures.begin(), other->sky_r_textures.end()); + sky_r_textures.dwReference++; + + sky_r_textures_env.assign(other->sky_r_textures_env.begin(), other->sky_r_textures_env.end()); + sky_r_textures_env.dwReference++; } void dxEnvironmentRender::Copy(IEnvironmentRender& _in) @@ -212,6 +221,7 @@ dxEnvironmentRender::dxEnvironmentRender() void dxEnvironmentRender::OnFrame(CEnvironment& env) { + PROF_EVENT("EnvironmentRender::OnFrame"); dxEnvDescriptorMixerRender& mixRen = *(dxEnvDescriptorMixerRender*)&*env.CurrentEnv->m_pDescriptorMixer; if (::Render->get_generation() == IRender_interface::GENERATION_R2) @@ -272,6 +282,7 @@ void dxEnvironmentRender::OnUnload() void dxEnvironmentRender::RenderSky(CEnvironment& env, bool OnlyMV) { + PROF_EVENT("EnvironmentRender::RenderSky"); // clouds_sh.create ("clouds","null"); //. this is the bug-fix for the case when the sky is broken //. for some unknown reason the geoms happen to be invalid sometimes @@ -357,6 +368,7 @@ void dxEnvironmentRender::RenderSky(CEnvironment& env, bool OnlyMV) void dxEnvironmentRender::RenderClouds(CEnvironment& env) { + PROF_EVENT("EnvironmentRender::RenderClouds"); ::Render->rmFar(); Fmatrix mXFORM, mScale; diff --git a/src/Layers/xrRender/dxFontRender.cpp b/src/Layers/xrRender/dxFontRender.cpp index cdd0578d8a..9f4f92a00e 100644 --- a/src/Layers/xrRender/dxFontRender.cpp +++ b/src/Layers/xrRender/dxFontRender.cpp @@ -19,7 +19,7 @@ void dxFontRender::Initialize(LPCSTR cShader, LPCSTR cTexture) pGeom.create(FVF::F_TL, RCache.Vertex.Buffer(), RCache.QuadIB); } -extern ENGINE_API BOOL g_bRendering; +extern ENGINE_API xr_atomic_bool g_bRendering; extern ENGINE_API Fvector2 g_current_font_scale; void dxFontRender::OnRender(CGameFont& owner) diff --git a/src/Layers/xrRender/dxLensFlareRender.cpp b/src/Layers/xrRender/dxLensFlareRender.cpp index 3afccb0587..27fcdaa975 100644 --- a/src/Layers/xrRender/dxLensFlareRender.cpp +++ b/src/Layers/xrRender/dxLensFlareRender.cpp @@ -29,6 +29,7 @@ void dxLensFlareRender::Copy(ILensFlareRender& _in) void dxLensFlareRender::Render(CLensFlare& owner, BOOL bSun, BOOL bFlares, BOOL bGradient) { + PROF_EVENT("dxLensFlareRender::Render"); Fcolor dwLight; Fcolor color; Fvector vec, vecSx, vecSy; diff --git a/src/Layers/xrRender/dxRainRender.cpp b/src/Layers/xrRender/dxRainRender.cpp index b3be94aa63..982b0f15bf 100644 --- a/src/Layers/xrRender/dxRainRender.cpp +++ b/src/Layers/xrRender/dxRainRender.cpp @@ -21,8 +21,9 @@ const int max_particles = 1000; const int particles_cache = 400; const float particles_time = .3f; -int current_items; - +xr_atomic_u32 current_items; +extern float r_rain_exp; +extern float r_rain_k; dxRainRender::dxRainRender() { current_items = 0; @@ -61,6 +62,7 @@ void dxRainRender::Render(CEffect_Rain& owner) { float factor = g_pGamePersistent->Environment().CurrentEnv->rain_density; if (factor < EPS_L) return; + factor = _powf(factor, r_rain_exp); float _drop_len = drop_length; float _drop_width = drop_width; @@ -84,117 +86,32 @@ void dxRainRender::Render(CEffect_Rain& owner) } #endif - u32 desired_items = iFloor(0.01f * (1.f + factor * 99.0f) * float(rain_max_particles)); + u32 desired_items = iFloor(0.01f * (1.f + factor * r_rain_k) * float(rain_max_particles)); + u32 render_items = _min(desired_items, (u32)owner.items.size()); + if (!render_items) + return; // Get to the desired items - if (current_items < desired_items) - current_items += desired_items - current_items; + u32 local_current = current_items.load(std::memory_order_relaxed); + if (local_current < desired_items) + { + u32 delta = desired_items - local_current; + current_items.fetch_add(delta, std::memory_order_relaxed); + } // visual float factor_visual = factor / 2.f + .5f; Fvector3 f_rain_color = g_pGamePersistent->Environment().CurrentEnv->rain_color; u32 u_rain_color = color_rgba_f(f_rain_color.x, f_rain_color.y, f_rain_color.z, factor_visual); - // born _new_ if needed - float b_radius_wrap_sqr = _sqr((rain_radius * 1.5f)); - if (owner.items.size() < current_items) - { - // owner.items.reserve (desired_items); - while (owner.items.size() < current_items) - { - CEffect_Rain::Item one; - owner.Born(one, rain_radius, _drop_speed); - owner.items.push_back(one); - } - } - - // build source plane - Fplane src_plane; - Fvector norm = {0.f, -1.f, 0.f}; - Fvector upper; - upper.set(Device.vCameraPosition.x, Device.vCameraPosition.y + source_offset, Device.vCameraPosition.z); - src_plane.build(upper, norm); - // perform update u32 vOffset; - FVF::LIT* verts = (FVF::LIT *)RCache.Vertex.Lock(desired_items * 4, hGeom_Rain->vb_stride, vOffset); + FVF::LIT* verts = (FVF::LIT *)RCache.Vertex.Lock(render_items * 4, hGeom_Rain->vb_stride, vOffset); FVF::LIT* start = verts; const Fvector& vEye = Device.vCameraPosition; - for (u32 I = 0; I < current_items; I++) + u32 rendered_items = 0; + for (CEffect_Rain::Item& one : owner.items) { - // physics and time control - CEffect_Rain::Item& one = owner.items[I]; - - if (one.dwTime_Hit < Device.dwTimeGlobal) - { - owner.Hit(one.Phit); - if (current_items > desired_items) current_items--; // Hit something - } - if (one.dwTime_Life < Device.dwTimeGlobal) - { - owner.Born(one, rain_radius, _drop_speed); - if (current_items > desired_items) current_items--; // Out of life ( invalidated, never hit something, etc. ) - } - - // последняя дельта ?? - //. float xdt = float(one.dwTime_Hit-Device.dwTimeGlobal)/1000.f; - //. float dt = Device.fTimeDelta;//xdtTEST1.Begin(); - Fvector wdir; - wdir.set(one.P.x - vEye.x, 0, one.P.z - vEye.z); - float wlen = wdir.square_magnitude(); - if (wlen > b_radius_wrap_sqr) - { - wlen = _sqrt(wlen); - //. Device.Statistic->TEST3.Begin(); - if ((one.P.y - vEye.y) < sink_offset) - { - // need born - one.invalidate(); - } - else - { - Fvector inv_dir, src_p; - inv_dir.invert(one.D); - wdir.div(wlen); - one.P.mad(one.P, wdir, -(wlen + rain_radius)); - if (src_plane.intersectRayPoint(one.P, inv_dir, src_p)) - { - float dist_sqr = one.P.distance_to_sqr(src_p); - float height = max_distance; - if (owner.RayPick(src_p, one.D, height, collide::rqtBoth)) - { - if (_sqr(height) <= dist_sqr) - { - one.invalidate(); // need born - // Log("1"); - } - else - { - owner.RenewItem(one, height - _sqrt(dist_sqr),TRUE); // fly to point - // Log("2",height-dist); - } - } - else - { - owner.RenewItem(one, max_distance - _sqrt(dist_sqr),FALSE); // fly ... - // Log("3",1.5f*b_height-dist); - } - } - else - { - // need born - one.invalidate(); - // Log("4"); - } - } - //. Device.Statistic->TEST3.End(); - } - Device.Statistic->TEST1.End(); - // Build line Fvector& pos_head = one.P; Fvector pos_trail; @@ -234,6 +151,9 @@ void dxRainRender::Render(CEffect_Rain& owner) P.mad(pos_head, lineTop, w); verts->set(P, u_rain_color, UV[s][3].x, UV[s][3].y); verts++; + + if (++rendered_items >= render_items) + break; } u32 vCount = (u32)(verts - start); RCache.Vertex.Unlock(vCount, hGeom_Rain->vb_stride); diff --git a/src/Layers/xrRender/dxRenderDeviceRender.cpp b/src/Layers/xrRender/dxRenderDeviceRender.cpp index 75edd477c7..911bfaea5f 100644 --- a/src/Layers/xrRender/dxRenderDeviceRender.cpp +++ b/src/Layers/xrRender/dxRenderDeviceRender.cpp @@ -282,8 +282,10 @@ void dxRenderDeviceRender::ResourcesPrefetchCreateTexture(LPCSTR name) Resources->_CreateTexture(name); } +xrCriticalSection resources_lock; void dxRenderDeviceRender::ResourcesGetMemoryUsage(u32& m_base, u32& c_base, u32& m_lmaps, u32& c_lmaps) { + xrCriticalSectionGuard g(resources_lock); if (Resources) Resources->_GetMemoryUsage(m_base, c_base, m_lmaps, c_lmaps); } @@ -348,6 +350,7 @@ void dxRenderDeviceRender::Begin() #if !defined(USE_DX10) && !defined(USE_DX11) CHK_DX(HW.pDevice->BeginScene()); #endif // USE_DX10 + RCache.OnFrameBegin(); RCache.set_CullMode(CULL_CW); RCache.set_CullMode(CULL_CCW); @@ -386,7 +389,10 @@ void dxRenderDeviceRender::End() RCache.OnFrameEnd(); Memory.dbg_check(); - DoAsyncScreenshot(); + { + PROF_EVENT("Async Screenshot"); + DoAsyncScreenshot(); + } #if defined(USE_DX10) || defined(USE_DX11) UINT present_flags = 0; diff --git a/src/Layers/xrRender/dxStatsRender.cpp b/src/Layers/xrRender/dxStatsRender.cpp index b90605b63c..520e0b3d36 100644 --- a/src/Layers/xrRender/dxStatsRender.cpp +++ b/src/Layers/xrRender/dxStatsRender.cpp @@ -43,6 +43,33 @@ void dxStatsRender::OutData4(CGameFont& F) F.OutNext(" dynamic_3B: %3.1f/%d", RCache.stat.r.s_dynamic_3B.verts / 1024.f, RCache.stat.r.s_dynamic_3B.dips); F.OutNext(" dynamic_4B: %3.1f/%d", RCache.stat.r.s_dynamic_4B.verts / 1024.f, RCache.stat.r.s_dynamic_4B.dips); F.OutNext("details: %3.1f/%d", RCache.stat.r.s_details.verts / 1024.f, RCache.stat.r.s_details.dips); + + if (ps_r__portal_traverse_stats) + { + const PortalTraverseDebugStats& pstats = PortalTraverseDbg_Peek(); + F.OutSkip(); + F.OutNext(" **** Portal Traverse (%u) **** ", pstats.frame_id); + F.OutNext("trv: all[%u] opt[%u] noopt[%u]", pstats.traverse_calls, pstats.traverse_calls_with_options, pstats.traverse_calls_without_options); + F.OutNext("frustum: push[%u] o[%u] n[%u] max[%u] o[%u] n[%u]", pstats.frustums_pushed, pstats.frustums_pushed_opt, + pstats.frustums_pushed_noopt, pstats.max_frustums_in_sector, pstats.max_frustums_in_sector_opt, pstats.max_frustums_in_sector_noopt); + F.OutNext("portal: chk[%u] o[%u] n[%u] rec[%u] o[%u] n[%u]", pstats.portals_checked, pstats.portals_checked_opt, + pstats.portals_checked_noopt, pstats.portals_recursed, pstats.portals_recursed_opt, pstats.portals_recursed_noopt); + F.OutNext("portal: visSkip[%u]", pstats.portals_skipped_already_visited); + F.OutNext("rej: sph[%u] sec[%u] ssa[%u] clip[%u] hom[%u]", pstats.portals_rejected_sphere, pstats.portals_rejected_sector, + pstats.portals_rejected_ssa, pstats.portals_rejected_clip, pstats.portals_rejected_hom); + F.OutNext("dbg branch: taken[%u] precedence[%u]", pstats.portals_debug_branch_taken, pstats.portals_debug_branch_precedence_hits); + F.OutNext("static: sec[%u] o[%u] n[%u] fr[%u] o[%u] n[%u] root[%u] o[%u] n[%u]", pstats.static_sector_nodes, + pstats.static_sector_nodes_opt, pstats.static_sector_nodes_noopt, pstats.static_frustum_nodes, pstats.static_frustum_nodes_opt, + pstats.static_frustum_nodes_noopt, pstats.static_add_root_calls, pstats.static_add_root_calls_opt, pstats.static_add_root_calls_noopt); + F.OutNext("dynamic: sp[%u] o[%u] n[%u] tst[%u] o[%u] n[%u]", pstats.dynamic_spatials, pstats.dynamic_spatials_opt, + pstats.dynamic_spatials_noopt, pstats.dynamic_frustum_tests, pstats.dynamic_frustum_tests_opt, pstats.dynamic_frustum_tests_noopt); + F.OutNext("dynamic: hit[%u] o[%u] n[%u] rnd[%u] o[%u] n[%u]", pstats.dynamic_frustum_hits, pstats.dynamic_frustum_hits_opt, + pstats.dynamic_frustum_hits_noopt, pstats.dynamic_rendered, pstats.dynamic_rendered_opt, pstats.dynamic_rendered_noopt); + F.OutNext("queue: st[%u] o[%u] n[%u] dyn[%u] o[%u] n[%u]", pstats.queue_static_packets, pstats.queue_static_packets_opt, + pstats.queue_static_packets_noopt, pstats.queue_dynamic_packets, pstats.queue_dynamic_packets_opt, pstats.queue_dynamic_packets_noopt); + F.OutNext("dedup: seen[%u] o[%u] n[%u] skip[%u] o[%u] n[%u]", pstats.static_dedup_seen, pstats.static_dedup_seen_opt, + pstats.static_dedup_seen_noopt, pstats.static_dedup_skipped, pstats.static_dedup_skipped_opt, pstats.static_dedup_skipped_noopt); + } } void dxStatsRender::GuardVerts(CGameFont& F) diff --git a/src/Layers/xrRender/dxThunderboltDescRender.cpp b/src/Layers/xrRender/dxThunderboltDescRender.cpp index c9640a4646..a22699159b 100644 --- a/src/Layers/xrRender/dxThunderboltDescRender.cpp +++ b/src/Layers/xrRender/dxThunderboltDescRender.cpp @@ -10,7 +10,7 @@ void dxThunderboltDescRender::CreateModel(LPCSTR m_name) { IReader* F = 0; F = FS.r_open("$game_meshes$", m_name); - R_ASSERT2(F, "Empty 'lightning_model'."); + R_ASSERT3(F, "Cannot open 'lightning_model' path=[%s].", m_name); l_model = ::RImplementation.model_CreateDM(F); FS.r_close(F); } diff --git a/src/Layers/xrRender/dxUIRender.cpp b/src/Layers/xrRender/dxUIRender.cpp index 1b0cbd2757..2ac8e1f6eb 100644 --- a/src/Layers/xrRender/dxUIRender.cpp +++ b/src/Layers/xrRender/dxUIRender.cpp @@ -164,7 +164,6 @@ LPCSTR dxUIRender::UpdateShaderName(LPCSTR tex_name, LPCSTR sh_name) string_path buff; u32 v_dev = CAP_VERSION(HW.Caps.raster_major, HW.Caps.raster_minor); u32 v_need = CAP_VERSION(2, 0); - //strstr(Core.Params,"-ps_movie") && if ((v_dev >= v_need) && FS.exist(buff, "$game_textures$", tex_name, ".ogm")) return "hud\\movie"; else diff --git a/src/Layers/xrRender/dxUIShader.cpp b/src/Layers/xrRender/dxUIShader.cpp index 5323c94b36..a2b490b8de 100644 --- a/src/Layers/xrRender/dxUIShader.cpp +++ b/src/Layers/xrRender/dxUIShader.cpp @@ -1,11 +1,11 @@ #include "stdafx.h" #include "dxUIShader.h" -xr_unordered_map g_UIShadersCache; +xr_unordered_flat_map g_UIShadersCache; static ref_shader& GetCachedUIShader(const char* sh, const char* tex) { - std::string key{ tex ? tex : "" }; + xr_string key{ tex ? tex : "" }; key += "_"; key += sh; diff --git a/src/Layers/xrRender/dxUIShader.h b/src/Layers/xrRender/dxUIShader.h index 61f3d5c3df..60f6273ac0 100644 --- a/src/Layers/xrRender/dxUIShader.h +++ b/src/Layers/xrRender/dxUIShader.h @@ -4,7 +4,7 @@ #include "..\..\Include\xrRender\UIShader.h" -extern xr_unordered_map g_UIShadersCache; +extern xr_unordered_flat_map g_UIShadersCache; class dxUIShader : public IUIShader { diff --git a/src/Layers/xrRender/light.cpp b/src/Layers/xrRender/light.cpp index 7f74a62c94..a51f56be73 100644 --- a/src/Layers/xrRender/light.cpp +++ b/src/Layers/xrRender/light.cpp @@ -1,18 +1,23 @@ #include "StdAfx.h" #include "light.h" -static const float SQRT2 = 1.4142135623730950488016887242097f; -static const float RSQRTDIV2 = 0.70710678118654752440084436210485f; +#include "QueryHelper.h" +#include "../../xrEngine/IGame_Level.h" -light::light(void) : ISpatial(g_SpatialSpace) +extern int ps_r2_shadow_omnipart_vischeck; + +light::light() { - spatial.type = STYPE_LIGHTSOURCE; + ISpatialOwner::spatial_create(g_SpatialSpaceLights, this, STYPE_LIGHTSOURCE); + //ISpatialOwner::spatial_create(g_SpatialSpace, this, STYPE_LIGHTSOURCE); flags.type = POINT; flags.bStatic = false; flags.bActive = false; flags.bShadow = false; flags.bVolumetric = false; flags.bHudMode = false; + flags.bOccq = true; + position.set(0, -1000, 0); direction.set(0, -1, 0); right.set(0, 0, 0); @@ -26,10 +31,14 @@ light::light(void) : ISpatial(g_SpatialSpace) m_volumetric_distance = 1; frame_render = 0; + ignore_object = nullptr; + for (int f=0; f<6; f++) decor_object[f] = nullptr; + m_parent = nullptr; virtual_size = 0.1f; omnipart_num = 0; sss_id = -1; sss_refresh = 0; + sss_remove_latency = 0; #if (RENDER==R_R2) || (RENDER==R_R3) || (RENDER==R_R4) @@ -37,30 +46,49 @@ light::light(void) : ISpatial(g_SpatialSpace) s_spot = NULL; s_point = NULL; vis.frame2test = 0; // xffffffff; - vis.query_id = 0; - vis.query_order = 0; + CHK_DX(CreateQuery(&vis.Q, D3DQUERYTYPE_OCCLUSION)); vis.visible = true; vis.pending = false; + m_sectors = {}; + X.S.posX = 0; + X.S.posY = 0; + X.S.size = SMAP_adapt_max; + RImplementation.v_all_lights.emplace(this); #endif // (RENDER==R_R2) || (RENDER==R_R3) || (RENDER==R_R4) } light::~light() { + m_parent = nullptr; #if (RENDER==R_R2) || (RENDER==R_R3) || (RENDER==R_R4) + RImplementation.v_all_lights.erase(this); for (int f = 0; f < 6; f++) xr_delete(omnipart[f]); + _RELEASE(vis.Q); #endif // (RENDER==R_R2) || (RENDER==R_R3) || (RENDER==R_R4) set_active(false); // remove from Lights_LastFrame #if (RENDER==R_R2) || (RENDER==R_R3) || (RENDER==R_R4) - for (u32 it = 0; it < RImplementation.Lights_LastFrame.size(); it++) - if (this == RImplementation.Lights_LastFrame[it]) RImplementation.Lights_LastFrame[it] = 0; + m_sectors.clear(); #endif // (RENDER==R_R2) || (RENDER==R_R3) || (RENDER==R_R4) - + ignore_object = nullptr; + for (int f=0; f<6; f++) decor_object[f] = nullptr; if (sss_on_light_destroy) sss_on_light_destroy(this); } +void light::destroy(bool deffered) +{ + set_active(false); + if (deffered) + { + if (std::find(RImplementation.v_all_lights_dque.begin(), RImplementation.v_all_lights_dque.end(), this) == RImplementation.v_all_lights_dque.end()) + RImplementation.v_all_lights_dque.push_back(this); + } + else + xr_delete(this); +} + #if (RENDER==R_R2) || (RENDER==R_R3) || (RENDER==R_R4) void light::set_texture(LPCSTR name) { @@ -113,47 +141,56 @@ void light::set_active(bool a) { if (a) { - if (flags.bActive) return; + if (flags.bActive) + return; + flags.bActive = true; spatial_register(); spatial_move(); - //Msg ("!!! L-register: %X",u32(this)); + //Msg("!!! L-register: %X",u32(this)); #ifdef DEBUG - Fvector zero = {0,-1000,0} ; - if (position.similar(zero)) { - Msg ("- Uninitialized light position."); + Fvector zero = { 0,-1000,0 }; + if (position.similar(zero)) { + Msg("- Uninitialized light position."); } #endif // DEBUG } else { - if (!flags.bActive) return; + if (!flags.bActive) + return; + flags.bActive = false; - spatial_move(); spatial_unregister(); - //Msg ("!!! L-unregister: %X",u32(this)); } } void light::set_position(const Fvector& P, const float eps) { - if (position.similar(P, eps))return; + if (position.similar(P, eps)) + return; + position.set(P); spatial_move(); } void light::set_range(float R) { - float eps = _max(range * 0.1f, EPS_L); - if (fsimilar(range, R, eps)) return; + float eps = _max(range * 0.1f, EPS); + + if (fsimilar(range, R, eps)) + return; + range = R; spatial_move(); }; void light::set_cone(float angle) { - if (fsimilar(cone, angle)) return; + if (fsimilar(cone, angle)) + return; + VERIFY(cone < deg2rad(121.f)); // 120 is hard limit for lights cone = angle; spatial_move(); @@ -165,66 +202,156 @@ void light::set_rotation(const Fvector& D, const Fvector& R, const float eps) direction.normalize(D); right.normalize(R); - if (!fsimilar(1.f, old_D.dotproduct(D), eps)) + if (!fsimilar(1.f, old_D.dotproduct(D), eps)) spatial_move(); } -void light::spatial_move() +// +X, -X, +Y, -Y, +Z, -Z +static Fvector cmNorm[6] = { {0.f,1.f,0.f}, {0.f,1.f,0.f}, {0.f,0.f,-1.f},{0.f,0.f,1.f}, {0.f,1.f,0.f}, {0.f,1.f,0.f} }; +static Fvector cmDir[6] = { {1.f,0.f,0.f}, {-1.f,0.f,0.f},{0.f,1.f,0.f}, {0.f,-1.f,0.f},{0.f,0.f,1.f}, {0.f,0.f,-1.f} }; + +void light::set_shadow(bool b) { - switch (flags.type) + flags.bShadow=b; +#if RENDER!=R_R1 + if (flags.type==IRender_Light::POINT) { - case IRender_Light::REFLECTED: - case IRender_Light::POINT: - { - spatial.sphere.set(position, range); - } - break; - case IRender_Light::SPOT: + if(flags.bShadow) { - // minimal enclosing sphere around cone - VERIFY2(cone < deg2rad(121.f), "Too large light-cone angle. Maybe you have passed it in 'degrees'?"); - if (cone >= PI_DIV_2) + // tough: create 6 shadowed lights + if (!omnipart[0]) { - // obtused-angled - spatial.sphere.P.mad(position, direction, range); - spatial.sphere.R = range * tanf(cone / 2.f); + for (int f=0; f<6; f++) + { + omnipart[f] = xr_new(); + omnipart[f]->m_parent = this; + omnipart[f]->set_type(IRender_Light::OMNIPART); + omnipart[f]->set_shadow(true); + omnipart[f]->set_cone(PI_DIV_2); + omnipart[f]->set_virtual_size(virtual_size); + Fvector R; + R.crossproduct(cmNorm[f], cmDir[f]); + omnipart[f]->set_rotation(cmDir[f], R); + omnipart[f]->s_spot = s_spot; + omnipart[f]->s_point = s_point; + } } - else + } + else + { + // tough: delete 6 shadowed lights + if (omnipart[0]) { - // acute-angled - spatial.sphere.R = range / (2.f * _sqr(_cos(cone / 2.f))); - spatial.sphere.P.mad(position, direction, spatial.sphere.R); + for (int f=0; f<6; f++) xr_delete(omnipart[f]); } } - break; - case IRender_Light::OMNIPART: + } +#endif +} + +#if RENDER!=R_R1 +void light::get_sectors() +{ + if(RImplementation.SectorsCount()<=1) return; + xrCriticalSectionGuard guard(§ors_lc); + if(0==SpatialComponent->spatial.sector) + SpatialComponent->spatial_updatesector(); + + CSector* sector = (CSector*)SpatialComponent->spatial.sector; + if(0==sector) return; + + if(flags.type == IRender_Light::SPOT/* || flags.type == IRender_Light::OMNIPART*/) + { + RImplementation.detectSectors_frustum(sector, m_sectors, &X.S.frustum); + } + if(flags.type == IRender_Light::POINT) + { + RImplementation.detectSectors_sphere(sector, m_sectors, position, Fvector().set(range, range, range)); + } +} + +bool light::has_light_visible_from_sectors(CDSGraphManager& DM) +{ + if (RImplementation.SectorsCount() <= 1) return true; + xrCriticalSectionGuard guard(§ors_lc); + if (!m_sectors.size())get_sectors(); + for (auto& node : m_sectors) + { + CSector* sector_ = (CSector*)node.key; + if (DM.is_sector_visible(sector_)) { - // is it optimal? seems to be... - //spatial.sphere.P.mad (position,direction,range); - //spatial.sphere.R = range; - // This is optimal. - const float fSphereR = range * RSQRTDIV2; - spatial.sphere.P.mad(position, direction, fSphereR); - spatial.sphere.R = fSphereR; + return true; } - break; + } + return false; +} + +bool light::has_outdoor_light() +{ + xrCriticalSectionGuard guard(§ors_lc); + return m_sectors.find(RImplementation.pOutdoorSector); +} +#endif + +void light::spatial_move() +{ + switch (flags.type) + { + case IRender_Light::DIRECT: return;//sun ? + case IRender_Light::REFLECTED: + case IRender_Light::POINT: + { + SpatialComponent->spatial.sphere.set(position, range); + } + break; + case IRender_Light::SPOT: + { + // minimal enclosing sphere around cone + VERIFY2(cone < deg2rad(121.f), "Too large light-cone angle. Maybe you have passed it in 'degrees'?"); + if (cone >= PI_DIV_2) + { + // obtused-angled + SpatialComponent->spatial.sphere.P.mad(position, direction, range); + SpatialComponent->spatial.sphere.R = range * tanf(cone / 2.f); + } + else + { + // acute-angled + SpatialComponent->spatial.sphere.R = range / (2.f * _sqr(_cos(cone / 2.f))); + SpatialComponent->spatial.sphere.P.mad(position, direction, SpatialComponent->spatial.sphere.R); + } + } + break; + case IRender_Light::OMNIPART: + { + // is it optimal? seems to be... + //spatial.sphere.P.mad (position,direction,range); + //spatial.sphere.R = range; + // This is optimal. + const float fSphereR = range*M_SQRT1_2; + SpatialComponent->spatial.sphere.P.mad(position, direction, fSphereR); + SpatialComponent->spatial.sphere.R = fSphereR; + } + break; } // update spatial DB - ISpatial::spatial_move(); + ISpatialOwner::spatial_move(); #if (RENDER==R_R2) || (RENDER==R_R3) || (RENDER==R_R4) if (flags.bActive) gi_generate(); - svis.invalidate(); + get_sectors(); #endif // (RENDER==R_R2) || (RENDER==R_R3) || (RENDER==R_R4) + + m_moving_frames = 0; } vis_data& light::get_homdata() { // commit vis-data - hom.sphere.set(spatial.sphere.P, spatial.sphere.R); - hom.box.set(spatial.sphere.P, spatial.sphere.P); - hom.box.grow(spatial.sphere.R); + hom.sphere.set(SpatialComponent->spatial.sphere.P, SpatialComponent->spatial.sphere.R); + hom.box.set(SpatialComponent->spatial.sphere.P, SpatialComponent->spatial.sphere.P); + hom.box.grow(SpatialComponent->spatial.sphere.R); return hom; }; @@ -238,8 +365,8 @@ Fvector light::spatial_sector_point() // Xforms void light::xform_calc() { - if (Device.dwFrame == m_xform_frame) return; - m_xform_frame = Device.dwFrame; + if (Device.dwFrame == m_parent_u_frame) return; + m_parent_u_frame = Device.dwFrame; // build final rotation / translation Fvector L_dir, L_up, L_right; @@ -317,47 +444,109 @@ void light::xform_calc() m_xform.identity(); break; } + + if(flags.type == IRender_Light::SPOT || flags.type == IRender_Light::OMNIPART) + { + // make N pixel border + X.S.view.build_camera_dir (position,L_dir,L_up); + + // _min(L->cone + deg2rad(4.5f), PI*0.98f) - Here, it is needed to enlarge the shadow map frustum to include also + // displaced pixels and the pixels neighbor to the examining one. + /* Ray Twitty */ + float tan_shift; +#if RENDER == R_R4 + if (flags.type == IRender_Light::OMNIPART) // [ SSS ] 0.3f fix almost all frustum problems... 0.5f was the old value ( SSS 19 ) but was causing issues? + tan_shift = 0.3f; + else if (flags.type == IRender_Light::POINT) + tan_shift = 0.2007129f; // deg2rad(11.5f); + else + tan_shift = 0.0610865f; //deg2rad(3.5f); +#else + if (flags.type == IRender_Light::POINT) + tan_shift = 0.2007129f; // deg2rad(11.5f); + else + tan_shift = 0.0610865f; //deg2rad(3.5f); +#endif + /* Ray Twitty end */ + X.S.project.build_projection(cone + tan_shift, 1.f, virtual_size, range + EPS_S); + + X.S.combine.mul(X.S.project,X.S.view); + + X.S.frustum.CreateFromMatrix(X.S.combine, FRUSTUM_P_LRTB | FRUSTUM_P_FAR); + } } -// +X, -X, +Y, -Y, +Z, -Z -static Fvector cmNorm[6] = { - {0.f, 1.f, 0.f}, {0.f, 1.f, 0.f}, {0.f, 0.f, -1.f}, {0.f, 0.f, 1.f}, {0.f, 1.f, 0.f}, {0.f, 1.f, 0.f} -}; -static Fvector cmDir[6] = { - {1.f, 0.f, 0.f}, {-1.f, 0.f, 0.f}, {0.f, 1.f, 0.f}, {0.f, -1.f, 0.f}, {0.f, 0.f, 1.f}, {0.f, 0.f, -1.f} -}; +void light::optimize_smap_size() +{ + if (flags.bHudMode) return; + int _cached_size = X.S.size; + X.S.posX = 0; + X.S.posY = 0; + X.S.size = SMAP_adapt_max; + X.S.transluent = FALSE; + // Compute approximate screen area (treating it as an point light) - R*R/dist_sq + // Note: we clamp screen space area to ONE, although it is not correct at all + // + //float dist = Device.vCameraPosition.distance_to(SpatialComponent->spatial.sphere.P) - SpatialComponent->spatial.sphere.R; + //if (dist < 0) dist = 0; + //float ssa = clampr(range * range / (1.f + dist * dist), 0.f, 1.f); + + float dist_sqr = Device.vCameraPosition.distance_to_sqr(SpatialComponent->spatial.sphere.P); + float R = SpatialComponent->spatial.sphere.R; + float R_sqr = _sqr(R); + float ssa = dist_sqr < R_sqr ? 1.f : clampr(_sqr(range) / (1.f + (dist_sqr - R_sqr)), 0.f, 1.f); + + // compute intensity + //float intensity0 = (L->color.r + L->color.g + L->color.b)/3.f; + //float intensity1 = (L->color.r * 0.2125f + L->color.g * 0.7154f + L->color.b * 0.0721f); + //float intensity = (intensity0+intensity1)/2.f; // intensity1 tends to underestimate... + + // compute how much duelling frusta occurs [-1..1]-> 1 + [-0.5 .. +0.5] + float duel_dot = 1.f - 0.5f*Device.vCameraDirection.dotproduct(direction); + + // compute how large the light is - give more texels to larger lights, assume 8m as being optimal radius + float sizefactor = range/8.f; // 4m = .5, 8m=1.f, 16m=2.f, 32m=4.f + + // compute how wide the light frustum is - assume 90deg as being optimal + float widefactor = cone/deg2rad(90.f); // + + // factors + float factor0 = powf (ssa, 0.5f); // ssa is quadratic + //float factor1 = powf (intensity, 0.0625f); // less perceptually important? + float factor2 = powf (duel_dot, 0.25f); // difficult to fast-change this -> visible + float factor3 = powf (sizefactor, 0.25f); // this shouldn't make much difference + float factor4 = powf (widefactor, 0.5f); // make it linear ??? + float factor = ps_r2_ls_squality * factor0 /** factor1*/ * factor2 * factor3 * factor4; + + // final size calc + u32 _size = iFloor( factor * SMAP_adapt_optimal ); + if (_sizeSMAP_adapt_max) _size = SMAP_adapt_max; + int _epsilon = iCeil (float(_size)*0.01f); + int _diff = _abs (int(_size)-int(_cached_size)); + X.S.size = (_diff>=_epsilon)?_size:_cached_size; +} -void light::export_(light_Package& package) +void light::export_() { + xform_calc(); if (flags.bShadow) { switch (flags.type) { case IRender_Light::POINT: { - // tough: create/update 6 shadowed lights - if (0 == omnipart[0]) for (int f = 0; f < 6; f++) omnipart[f] = xr_new(); + // tough: update 6 shadowed lights + vis_prepare(); for (int f = 0; f < 6; f++) { light* L = omnipart[f]; - Fvector R; - R.crossproduct(cmNorm[f], cmDir[f]); - L->set_type(IRender_Light::OMNIPART); - L->set_shadow(true); L->set_position(position); - L->set_rotation(cmDir[f], R); - //L->set_cone(PI_DIV_2 + 0.5f); // SSS : Deprecated - L->set_cone(PI_DIV_2); + L->SpatialComponent->spatial.sector = SpatialComponent->spatial.sector; L->set_range(range); L->set_color(color); - L->spatial.sector = spatial.sector; //. dangerous? - L->s_spot = s_spot; - L->s_point = s_point; - L->set_virtual_size(virtual_size); //Set virtual size - L->set_hud_mode(get_hud_mode()); L->omnipart_num = f; L->omipart_parent = omnipart[0]; - L->flags.bActive = true; // Holger - do we need to export msaa stuff as well ? #if (RENDER==R_R3) || (RENDER==R_R4) @@ -377,21 +566,45 @@ void light::export_(light_Package& package) } #endif // (RENDER==R_R3) || (RENDER==R_R4) + L->flags.bActive = flags.bActive; + // Igor: add volumetric support - if (ps_ssfx_volumetric.x <= 0) - L->set_volumetric(flags.bVolumetric); + L->set_volumetric(flags.bVolumetric); L->set_volumetric_quality(m_volumetric_quality); L->set_volumetric_intensity(m_volumetric_intensity); L->set_volumetric_distance(m_volumetric_distance); - - package.v_shadowed.push_back(L); + L->set_ignore_object(ignore_object); + for (int f=0; f<6; f++) L->set_decor_object(decor_object[f],f); + L->set_occq_mode(flags.bOccq); + L->set_hud_mode(flags.bHudMode); + L->xform_calc(); + if (ps_r2_shadow_omnipart_vischeck) + { + L->vis_prepare(); + } + else + { + L->vis.pending = vis.pending; + L->vis.visible = vis.visible; + } + if (L->vis.pending && !L->vis.visible) + RImplementation.LP_pending.v_shadowed.push_back(L); + else + RImplementation.LP_normal.v_shadowed.push_back(L); } } break; case IRender_Light::SPOT: - this->set_volumetric_intensity(m_volumetric_intensity); - package.v_shadowed.push_back(this); + { + this->set_volumetric_intensity(m_volumetric_intensity); + vis_prepare(); + + if (vis.pending && !vis.visible) + RImplementation.LP_pending.v_shadowed.push_back(this); + else + RImplementation.LP_normal.v_shadowed.push_back(this); + } break; } } @@ -399,10 +612,24 @@ void light::export_(light_Package& package) { switch (flags.type) { - case IRender_Light::POINT: package.v_point.push_back(this); - break; - case IRender_Light::SPOT: package.v_spot.push_back(this); - break; + case IRender_Light::POINT: + { + vis_prepare(); + if (vis.pending && !vis.visible) + RImplementation.LP_pending.v_point.push_back(this); + else + RImplementation.LP_normal.v_point.push_back(this); + } + break; + case IRender_Light::SPOT: + { + vis_prepare(); + if (vis.pending && !vis.visible) + RImplementation.LP_pending.v_spot.push_back(this); + else + RImplementation.LP_normal.v_spot.push_back(this); + } + break; } } } @@ -423,9 +650,9 @@ extern float ps_r2_slight_fade; float light::get_LOD() { if (!flags.bShadow) return 1; - float distSQ = Device.vCameraPosition.distance_to_sqr(spatial.sphere.P) + EPS; + float distSQ = Device.vCameraPosition.distance_to_sqr(SpatialComponent->spatial.sphere.P) + EPS; distance = distSQ; - float ssa = ps_r2_slight_fade * spatial.sphere.R / distSQ; + float ssa = ps_r2_slight_fade * SpatialComponent->spatial.sphere.R / distSQ; float lod = _sqrt(clampr((ssa - r_ssaGLOD_end) / (r_ssaGLOD_start - r_ssaGLOD_end), 0.f, 1.f)); return lod; } diff --git a/src/Layers/xrRender/light.h b/src/Layers/xrRender/light.h index dc8a077c62..e8a4ea464a 100644 --- a/src/Layers/xrRender/light.h +++ b/src/Layers/xrRender/light.h @@ -3,15 +3,19 @@ #include "../../xrcdb/ispatial.h" +//#include "../../xrEngine/xr_object.h" + #if (RENDER==R_R2) || (RENDER==R_R3) || (RENDER==R_R4) # include "light_package.h" -# include "light_smapvis.h" # include "light_GI.h" +#include "../xrRender/r__dsgraph_manager.h" #endif //(RENDER==R_R2) || (RENDER==R_R3) || (RENDER==R_R4) extern Fvector4 ps_ssfx_volumetric; +class CObject; -class light : public IRender_Light, public ISpatial +class light : + public IRender_Light { public: struct @@ -22,6 +26,7 @@ class light : public IRender_Light, public ISpatial u32 bShadow : 1; u32 bVolumetric:1; u32 bHudMode: 1; + u32 bOccq: 1; } flags; Fvector position; @@ -31,24 +36,45 @@ class light : public IRender_Light, public ISpatial float cone; Fcolor color; + CObject *ignore_object, *decor_object[6]; + vis_data hom; u32 frame_render; + light* m_parent; + u8 m_moving_frames; int omnipart_num; int sss_id; int sss_refresh; + int sss_remove_latency; s8 sss_priority; bool sss_is_playerlight; - fastdelegate::FastDelegate1 sss_on_light_destroy; + xr_delegate sss_on_light_destroy; light* omipart_parent; float distance; float distance_lpos; +#if RENDER!=R_R1 && !XRCPU_PIPE_EXPORTS + FixedSet m_sectors; +#endif // RENDER!=R_R1 + float m_volumetric_quality; float m_volumetric_intensity; float m_volumetric_distance; +#ifndef XRCPU_PIPE_EXPORTS +#ifndef _EDITOR + CDSGraphManager GMLight = CDSGraphManager(u32(0), +#if RENDER==R_R1 + u32(STYPE_RENDERABLE), +#else + u32(STYPE_RENDERABLE + STYPE_RENDERABLESHADOW), +#endif + { true,false,false,false,true,false,false }); +#endif +#endif + float virtual_size; #if (RENDER==R_R2) || (RENDER==R_R3) || (RENDER==R_R4) @@ -61,8 +87,6 @@ class light : public IRender_Light, public ISpatial xr_vector indirect ; u32 indirect_photons; - smapvis svis; // used for 6-cubemap faces - ref_shader s_spot; ref_shader s_point; ref_shader s_volumetric; @@ -73,13 +97,12 @@ class light : public IRender_Light, public ISpatial ref_shader s_volumetric_msaa[8]; #endif // (RENDER==R_R3) || (RENDER==R_R4) - u32 m_xform_frame; + u32 m_xform_frame, m_parent_p_frame, m_parent_u_frame; Fmatrix m_xform; struct _vis { u32 frame2test; // frame the test is sheduled to - u32 query_id; // ID of occlusion query - u32 query_order; // order of occlusion query + ID3DQuery* Q; bool visible; // visible/invisible bool pending; // test is still pending u16 smap_ID; @@ -107,20 +130,25 @@ class light : public IRender_Light, public ISpatial u32 posX ; u32 posY ; BOOL transluent ; + CFrustum frustum; } S; } X; #endif // (RENDER==R_R2) || (RENDER==R_R3) || (RENDER==R_R4) public: virtual void set_type(LT type) { flags.type = type; } + virtual LT get_type() { return (LT)flags.type; } virtual void set_active(bool b); virtual bool get_active() { return flags.bActive; } - virtual void set_shadow(bool b) - { - flags.bShadow = b; - } +#if RENDER!=R_R1 && !XRCPU_PIPE_EXPORTS + void get_sectors(); + bool has_light_visible_from_sectors(CDSGraphManager& DM); + bool has_outdoor_light(); + xrCriticalSection sectors_lc; +#endif // RENDER!=R_R1 + virtual void set_shadow(bool b); virtual void set_volumetric(bool b) { if (ps_ssfx_volumetric.x > 0) @@ -149,6 +177,15 @@ class light : public IRender_Light, public ISpatial virtual void set_hud_mode(bool b) { flags.bHudMode = b; } virtual bool get_hud_mode() { return flags.bHudMode; }; + virtual void set_occq_mode(bool b) { flags.bOccq = b; } + virtual bool get_occq_mode() { return flags.bOccq; } + + virtual void set_ignore_object(CObject* O) { ignore_object = O; }; + virtual CObject* get_ignore_object() { return ignore_object; }; + + virtual void set_decor_object(CObject* O, int index = 0) { decor_object[index] = O; }; + virtual CObject* get_decor_object(int index = 0) { return decor_object[index]; }; + virtual void set_is_playerlight(bool b) { sss_is_playerlight = b; }; virtual void spatial_move(); @@ -156,20 +193,22 @@ class light : public IRender_Light, public ISpatial virtual IRender_Light* dcast_Light() { return this; } - vis_data& get_homdata(); + virtual vis_data& get_homdata(); #if (RENDER==R_R2) || (RENDER==R_R3) || (RENDER==R_R4) void gi_generate (); void xform_calc (); void vis_prepare (); void vis_update (); - void export_ (light_Package& dest); + void export_ (); void set_attenuation_params (float a0, float a1, float a2, float fo); + void optimize_smap_size (); #endif // (RENDER==R_R2) || (RENDER==R_R3) || (RENDER==R_R4) float get_LOD(); light(); virtual ~light(); + virtual void destroy(bool deffered = true); }; #endif // #define LAYERS_XRRENDER_LIGHT_H_INCLUDED diff --git a/src/Layers/xrRender/light_vis.cpp b/src/Layers/xrRender/light_vis.cpp new file mode 100644 index 0000000000..6e79683db5 --- /dev/null +++ b/src/Layers/xrRender/light_vis.cpp @@ -0,0 +1,116 @@ +#include "StdAfx.h" +#include "light.h" +#include "QueryHelper.h" +#include "../../xrEngine/cl_intersect.h" + +const u32 delay_small_min = 1; +const u32 delay_small_max = 3; +const u32 delay_large_min = 10; +const u32 delay_large_max = 20; +const u32 cullfragments = 4; + +void light::vis_prepare() +{ + if (int(indirect_photons) != ps_r2_GI_photons) + gi_generate(); + + // . test is sheduled for future = keep old result + // . test time comes :) + // . camera inside light volume = visible, shedule for 'small' interval + // . perform testing = ???, pending + if (!flags.bActive) + { + vis.visible = false; + vis.pending = false; + return; + } + if (!flags.bOccq || flags.bHudMode) + { + vis.visible = true; + vis.pending = false; + return; + } + + u32 frame = Device.dwFrame; + if (frame < vis.frame2test) + return; + + float safe_area = VIEWPORT_NEAR; + { + float a0 = deg2rad(Device.fFOV * Device.fASPECT * 0.5f); + float a1 = deg2rad(Device.fFOV * 0.5f); + float x0 = VIEWPORT_NEAR / _cos(a0); + float x1 = VIEWPORT_NEAR / _cos(a1); + float c = _sqrt(x0 * x0 + x1 * x1); + safe_area = _max(_max(VIEWPORT_NEAR, _max(x0, x1)), c); + } + + //Msg ("sc[%f,%f,%f]/c[%f,%f,%f] - sr[%f]/r[%f]",VPUSH(spatial.center),VPUSH(position),spatial.radius,range); + //Msg ("dist:%f, sa:%f",Device.vCameraPosition.distance_to(spatial.center),safe_area); + bool skiptest = false; + if (ps_r2_ls_flags.test(R2FLAG_EXP_DONT_TEST_UNSHADOWED) && !flags.bShadow) skiptest = true; + if (ps_r2_ls_flags.test(R2FLAG_EXP_DONT_TEST_SHADOWED) && flags.bShadow) skiptest = true; +#ifdef USE_DX11 + //if (ps_ssfx_volumetric.x > 0 && flags.bShadow) skiptest = true; // Temp Fix +#endif + + vis.distance = Device.vCameraPosition.distance_to(SpatialComponent->spatial.sphere.P); + + if (skiptest || vis.distance <= (SpatialComponent->spatial.sphere.R * 1.01f + safe_area + (SpatialComponent->spatial.sphere.R * 0.1f))) // small error + { + // small error + vis.visible = true; + vis.pending = false; + vis.frame2test = frame + ::Random.randI(delay_small_min, delay_small_max); + return; + } + + // testing + if (vis.pending) + return; + + vis.pending = true; + RCache.set_xform_world(m_xform); + CHK_DX(BeginQuery(vis.Q)); + // Hack: Igor. Light is visible if it's frutum is visible. (Only for volumetric) + // Hope it won't slow down too much since there's not too much volumetric lights + // TODO: sort for performance improvement if this technique hurts + if ((flags.type == IRender_Light::SPOT) && flags.bShadow && flags.bVolumetric) + RCache.set_Stencil(FALSE); + else + RCache.set_Stencil(TRUE, D3DCMP_LESSEQUAL, 0x01, 0xff, 0x00); + RImplementation.Target->draw_volume(this); + CHK_DX(EndQuery(vis.Q)); +} + +void light::vis_update() +{ + // . not pending ->>> return (early out) + // . test-result: visible: + // . shedule for 'large' interval + // . test-result: invisible: + // . shedule for 'next-frame' interval + + if (!vis.pending) return; + + u32 frame = Device.dwFrame; + R_occlusion::occq_result fragments = 0; + HRESULT hr = GetData(vis.Q, &fragments, sizeof(fragments), 0x1 /*D3D11_ASYNC_GETDATA_DONOTFLUSH*/); + + vis.pending = hr != S_OK; + if (hr != S_OK) + { + vis.frame2test = frame + 1; + if (hr != S_FALSE) + { + // Fail-open on timeout/device/query errors to avoid popping. + vis.visible = true; + vis.pending = false; + vis.frame2test = frame + ::Random.randI(delay_small_min, delay_small_max); + } + return; + } + + vis.visible = (fragments > cullfragments); + vis.frame2test = vis.visible ? (frame + ::Random.randI(delay_large_min, delay_large_max)) : (frame + 1); +} diff --git a/src/Layers/xrRender/lights_render.cpp b/src/Layers/xrRender/lights_render.cpp new file mode 100644 index 0000000000..a28276c44b --- /dev/null +++ b/src/Layers/xrRender/lights_render.cpp @@ -0,0 +1,376 @@ +#include "stdafx.h" +#include "../../xrEngine/xr_object.h" +#include "FBasicVisual.h" +#include "SkeletonCustom.h" + +extern int ps_r2_shadow_omnipart_vischeck; + +bool check_grass_shadow(light* L, CFrustum VB) +{ + // Grass shadows are allowed? + if (ps_ssfx_grass_shadows.x < 3 || !psDeviceFlags2.test(rsGrassShadow)) + return false; + + // Inside the range? + if (L->vis.distance > ps_ssfx_grass_shadows.z) + return false; + + // Is in view? L->vis.visible? + u32 mask = 0xff; + if (!VB.testSphere(L->position, L->range * 0.6f, mask)) + return false; + + return true; +} + +IC void hud_light_apply(xr_map>& saved_pos, xr_vector& source) +{ + for (u32 it = 0; it < source.size(); it++) + { + light* L = source[it]; + if (!L->get_hud_mode()) continue; + + saved_pos.emplace(L, mk_pair(L->position, L->direction)); + + Device.hud_to_world(L->position); + Device.hud_to_world_dir(L->direction); + } +} + +IC void hud_light_restore(xr_map>& saved_pos, xr_vector& source) +{ + for (const auto& saved : saved_pos) + { + light* L = saved.first; + if (!L->get_hud_mode()) continue; + + L->position = saved.second.first; + L->direction = saved.second.second; + } +} + +void CRender::render_lights(light_Package& LP) +{ + xr_map> saved_pos; + stats.ls_shadowed_in += (u32)LP.v_shadowed.size(); + stats.ls_unshadowed_point_in += (u32)LP.v_point.size(); + stats.ls_unshadowed_spot_in += (u32)LP.v_spot.size(); + stats.ls_shadowed_peak_in = _max(stats.ls_shadowed_peak_in, (u32)LP.v_shadowed.size()); + ////////////////////////////////////////////////////////////////////////// + // 0. apply hud_mode projection if necessary + hud_light_apply(saved_pos, LP.v_shadowed); + hud_light_apply(saved_pos, LP.v_point); + hud_light_apply(saved_pos, LP.v_spot); + + { +#if defined(USE_DX10) || defined(USE_DX11) + PIX_EVENT(SHADOWED_LIGHTS); +#endif + { +#if defined(USE_DX10) || defined(USE_DX11) + PIX_EVENT(PHASE_VIS_UPDATE); +#endif + xr_vector& source = LP.v_shadowed; + source.erase(std::remove_if(source.begin(), source.end(), [](light* L) + { + if(L->m_parent) + { + if (ps_r2_shadow_omnipart_vischeck) + { + L->vis_update(); + } + else if(L->m_parent->omnipart[0] == L) + { + L->m_parent->vis_update(); + for (int f = 0; f < 6; f++) + { + L->m_parent->omnipart[f]->vis.pending = L->m_parent->vis.pending; + L->m_parent->omnipart[f]->vis.visible = L->m_parent->vis.visible; + } + } + } + else + L->vis_update(); + if (!L->vis.visible) + { + RImplementation.stats.ls_shadowed_invisible_skipped++; + return true; + } + + L->optimize_smap_size(); + + return false; + }), source.end()); + stats.ls_shadowed_after_vis += (u32)source.size(); + stats.ls_shadowed_peak_after_vis = _max(stats.ls_shadowed_peak_after_vis, (u32)source.size()); + } + + { +#if defined(USE_DX10) || defined(USE_DX11) + PIX_EVENT(PHASE_CALC_POOLS); +#endif + xr_vector& source = LP.v_shadowed; + static xr_vector refactored; + refactored.clear(); + u32 total = (u32)source.size(); + + for (u16 smap_ID = 0; refactored.size() != total; smap_ID++) + { + LP_smap_pool.initialize(o.smapsize); + std::sort(source.begin(), source.end(), [](light* _1, light* _2) {return _1->X.S.size > _2->X.S.size; }); + source.erase(std::remove_if(source.begin(), source.end(), [smap_ID](light* L) + { + SMAP_Rect R; + if (RImplementation.LP_smap_pool.push(R, L->X.S.size)) + { + L->X.S.posX = R.min.x; + L->X.S.posY = R.min.y; + L->vis.smap_ID = smap_ID; + refactored.push_back(L); + return true; + } + return false; + }), source.end()); + } + + std::reverse(refactored.begin(), refactored.end()); + LP.v_shadowed = refactored; + } + + ////////////////////////////////////////////////////////////////////////// + // sort lights by importance??? + // while (has_any_lights_that_cast_shadows) { + // if (has_point_shadowed) -> generate point shadowmap + // if (has_spot_shadowed) -> generate spot shadowmap + // switch-to-accumulator + // if (has_point_unshadowed) -> accum point unshadowed + // if (has_spot_unshadowed) -> accum spot unshadowed + // if (was_point_shadowed) -> accum point shadowed + // if (was_spot_shadowed) -> accum spot shadowed + // } + // if (left_some_lights_that_doesn't cast shadows) + // accumulate them + while (!LP.v_shadowed.empty()) + { + // if (has_spot_shadowed) + static xr_vector L_spot_s; + { +#if defined(USE_DX10) || defined(USE_DX11) + PIX_EVENT(GENERATE_SHMAPS); +#endif + // generate spot shadowmap + Target->phase_smap_spot_clear(); + xr_vector& source = LP.v_shadowed; + light* L = source.back(); + u16 sid = L->vis.smap_ID; + while (!source.empty()) + { + if (source.empty()) break; + L = source.back(); + if (L->vis.smap_ID != sid) break; + source.pop_back(); + // render + phase = PHASE_SMAP; +#if defined(USE_DX10) || defined(USE_DX11) + PIX_EVENT(RENDER_SHADOWS); +#endif + bool decorative_light = false; + { + if ((L->decor_object[0] && !L->decor_object[0]->getDestroy()) || (L->decor_object[1] && !L->decor_object[1]->getDestroy()) || (L->decor_object[2] && !L->decor_object[2]->getDestroy()) || (L->decor_object[3] && !L->decor_object[3]->getDestroy()) || (L->decor_object[4] && !L->decor_object[4]->getDestroy()) || (L->decor_object[5] && !L->decor_object[5]->getDestroy())) + { + for (int f = 0; f < 6; f++) + { + if (L->decor_object[f] && !L->decor_object[f]->getDestroy()) + { + L->decor_object[f]->renderable_Render(&L->GMLight); + decorative_light = true; + } + } + } + else + { + if (L->m_moving_frames<32u) + { + L->GMLight.RGraph.clear_static(); + L->GMLight.traverse((CSector*)L->SpatialComponent->spatial.sector, L->X.S.frustum, L->position, L->X.S.combine); + L->GMLight.r_dsgraph_capture_static(); + L->m_moving_frames++; + } + L->GMLight.r_dsgraph_capture_dynamic(L->ignore_object); + } + } + + bool bDeffered_Shadows = L->GMLight.RGraph.mapStaticPasses[0][0].size() || L->GMLight.RGraph.mapDynamicPasses[0][0].size(); + bool bForward_Shadows = L->GMLight.RGraph.mapStaticPasses[1][0].size() || L->GMLight.RGraph.mapDynamicPasses[1][0].size() || L->GMLight.RGraph.mapStaticSorted.Sorted.size() || L->GMLight.RGraph.mapDynamicSorted.Sorted.size(); + if (bDeffered_Shadows || bForward_Shadows) + { + L_spot_s.push_back(L); + Target->phase_smap_spot(L); + RCache.set_xform_world(Fidentity); + RCache.set_xform_view(L->X.S.view); + RCache.set_xform_project(L->X.S.project); + L->GMLight.r_dsgraph_render_static(0, false); + L->GMLight.r_dsgraph_render_dynamic(0, true); + if (Details && Details->dtFS && check_grass_shadow(L, ViewBase) && L->flags.bShadow && !decorative_light) + { + Details->fade_distance = -1; // Use light position to calc "fade" + Details->light_position.set(L->position); + Details->hw_Render(L); + } + + L->X.S.transluent = FALSE; + if (bForward_Shadows) + { + L->X.S.transluent = TRUE; + Target->phase_smap_spot_tsh(L); + + L->GMLight.r_dsgraph_render_static(1, false); + L->GMLight.r_dsgraph_render_dynamic(1, true); + + L->GMLight.r_dsgraph_render_sorted(); // strict-sorted geoms + } + } + else if (L->flags.bVolumetric && ps_r2_ls_flags.test(R2FLAG_VOLUMETRIC_LIGHTS)) + { + L_spot_s.push_back(L); + } + } + } + // if (was_spot_shadowed) -> accum spot shadowed + if (!L_spot_s.empty()) + { + PROF_EVENT("ACCUM_SPOT"); + stats.ls_shadowed_rendered += (u32)L_spot_s.size(); + for (light* L : L_spot_s) + { + Target->accum_spot(L); + render_indirect(L); + if (L->flags.bVolumetric && RImplementation.o.advancedpp && ps_r2_ls_flags.is(R2FLAG_VOLUMETRIC_LIGHTS)) + { +#ifdef USE_DX11 + float w = float(Device.dwWidth); + float h = float(Device.dwHeight); + + if (RImplementation.o.ssfx_volumetric) + Target->set_viewport_size(HW.pContext, w / RImplementation.o.volsize, h / RImplementation.o.volsize); +#endif + + if (ps_pfx_volumetric_mode == 1) + Target->accum_volumetric_lv(L); + else + Target->accum_volumetric(L); + +#ifdef USE_DX11 + // Restore resolution + if (RImplementation.o.ssfx_volumetric) + Target->set_viewport_size(HW.pContext, w, h); +#endif + } + } + + L_spot_s.clear(); + } + } + } + + { +#if defined(USE_DX10) || defined(USE_DX11) + PIX_EVENT(UNSHADOWED_LIGHTS); +#endif + PROF_EVENT("UNSHADOWED_LIGHTS"); + { +#if defined(USE_DX10) || defined(USE_DX11) + PIX_EVENT(POINT_LIGHTS_ACCUM_UNSH); +#endif + // Point lighting (unshadowed, if left) + if (!LP.v_point.empty()) + { + for (light* L : LP.v_point) + { + L->vis_update(); + if (!L->vis.visible) + continue; + + Target->accum_point(L); + ++stats.ls_unshadowed_point_rendered; + render_indirect(L); + } + LP.v_point.clear(); + } + } + { +#if defined(USE_DX10) || defined(USE_DX11) + PIX_EVENT(SPOT_LIGHTS_ACCUM_UNSH); +#endif + // Spot lighting (unshadowed, if left) + if (!LP.v_spot.empty()) + { + for (light* L : LP.v_spot) + { + L->vis_update(); + if (!L->vis.visible) + continue; + + Target->accum_spot(L); + ++stats.ls_unshadowed_spot_rendered; + render_indirect(L); + } + LP.v_spot.clear(); + } + } + } + + // restore world projection if necessary + { + PROF_EVENT("hud_light_restore"); + hud_light_restore(saved_pos, LP.v_shadowed); + hud_light_restore(saved_pos, LP.v_point); + hud_light_restore(saved_pos, LP.v_spot); + } + +} + +void CRender::render_indirect(light* L) +{ + if (!ps_r2_ls_flags.test(R2FLAG_GI)) return; + + light LIGEN; + LIGEN.set_type(IRender_Light::REFLECTED); + LIGEN.set_shadow(false); + LIGEN.set_cone(PI_DIV_2 * 2.f); + + xr_vector& Lvec = L->indirect; + if (Lvec.empty()) return; + float LE = L->color.intensity(); + for (u32 it = 0; it < Lvec.size(); it++) + { + light_indirect& LI = Lvec[it]; + + // energy and color + float LIE = LE * LI.E; + if (LIE < ps_r2_GI_clip) continue; + Fvector T; + T.set(L->color.r, L->color.g, L->color.b).mul(LI.E); + LIGEN.set_color(T.x, T.y, T.z); + + // geometric + Fvector L_up, L_right; + L_up.set(0, 1, 0); + if (_abs(L_up.dotproduct(LI.D)) > .99f) L_up.set(0, 0, 1); + L_right.crossproduct(L_up, LI.D).normalize(); + LIGEN.SpatialComponent->spatial.sector = LI.S; + LIGEN.set_position(LI.P); + LIGEN.set_rotation(LI.D, L_right); + + // range + // dist^2 / range^2 = A - has infinity number of solutions + // approximate energy by linear fallof Emax / (1 + x) = Emin + float Emax = LIE; + float Emin = 1.f / 255.f; + float x = (Emax - Emin) / Emin; + if (x < 0.1f) continue; + LIGEN.set_range(x); + + Target->accum_reflected(&LIGEN); + } +} diff --git a/src/Layers/xrRender/occRasterizer.cpp b/src/Layers/xrRender/occRasterizer.cpp index 50a6c445bd..84c2ec0f80 100644 --- a/src/Layers/xrRender/occRasterizer.cpp +++ b/src/Layers/xrRender/occRasterizer.cpp @@ -199,17 +199,10 @@ void occRasterizer::on_dbg_render() IC BOOL test_Level(occD* depth, int dim, float _x0, float _y0, float _x1, float _y1, occD z) { - int x0 = iFloor(_x0 * dim + .5f); - clamp(x0, 0, dim - 1); - int x1 = iFloor(_x1 * dim + .5f); - clamp(x1, x0, dim - 1); - int y0 = iFloor(_y0 * dim + .5f); - clamp(y0, 0, dim - 1); - int y1 = iFloor(_y1 * dim + .5f); - clamp(y1, y0, dim - 1); - - // MT-Sync (delayed as possible) - RImplementation.HOM.MT_SYNC(); + int x0 = iFloor(_x0 * dim + .5f); clamp(x0, 0, dim - 1); + int x1 = iFloor(_x1 * dim + .5f); clamp(x1, x0, dim - 1); + int y0 = iFloor(_y0 * dim + .5f); clamp(y0, 0, dim - 1); + int y1 = iFloor(_y1 * dim + .5f); clamp(y1, y0, dim - 1); for (int y = y0; y <= y1; y++) { @@ -222,6 +215,7 @@ IC BOOL test_Level(occD* depth, int dim, float _x0, float _y0, float _x1, float return FALSE; } + BOOL occRasterizer::test(float _x0, float _y0, float _x1, float _y1, float _z) { occD z = df_2_s32up(_z) + 1; diff --git a/src/Layers/xrRenderPC_R2/r2_blenders.cpp b/src/Layers/xrRender/r2_blenders.cpp similarity index 100% rename from src/Layers/xrRenderPC_R2/r2_blenders.cpp rename to src/Layers/xrRender/r2_blenders.cpp diff --git a/src/Layers/xrRender/r__dsgraph_build.cpp b/src/Layers/xrRender/r__dsgraph_build.cpp index 212e9b95c8..003c9be7e3 100644 --- a/src/Layers/xrRender/r__dsgraph_build.cpp +++ b/src/Layers/xrRender/r__dsgraph_build.cpp @@ -1,4 +1,4 @@ -#include "stdafx.h" +#include "stdafx.h" #include "fhierrarhyvisual.h" #include "SkeletonCustom.h" @@ -20,59 +20,74 @@ float r_ssaLOD_A, r_ssaLOD_B; float r_ssaGLOD_start, r_ssaGLOD_end; float r_ssaHZBvsTEX; -ICF float CalcSSA(float& distSQ, Fvector& C, dxRender_Visual* V) +ICF float CalcSSA(float& distSQ, Fvector& C, float R) { - float R = V->vis.sphere.R + 0; distSQ = Device.vCameraPosition.distance_to_sqr(C) + EPS; - return R / distSQ; + return (R * R / distSQ); } -ICF float CalcSSA(float& distSQ, Fvector& C, float R) +ICF float CalcSSA(float& distSQ, Fvector& C, dxRender_Visual* V) { - distSQ = Device.vCameraPosition.distance_to_sqr(C) + EPS; - return R / distSQ; + return CalcSSA(distSQ, C, V->vis.sphere.R); } -void R_dsgraph_structure::r_dsgraph_insert_dynamic(dxRender_Visual* pVisual, Fvector& Center) +void CDSGraphManager::r_dsgraph_insert_dynamic(dxRender_Visual *pVisual, Fmatrix* xform) { - CRender& RI = RImplementation; - - if (pVisual->vis.marker == RI.marker) return; - pVisual->vis.marker = RI.marker; - -#if RENDER==R_R1 - if (RI.o.vis_intersect && (pVisual->vis.accept_frame != Device.dwFrame)) return; - pVisual->vis.accept_frame = Device.dwFrame; -#endif + Fvector Center; + xform->transform_tiny(Center, pVisual->vis.sphere.P); float distSQ; float SSA = CalcSSA(distSQ, Center, pVisual); - if (SSA <= r_ssaDISCARD) return; + Flags16& flags = pVisual->flags; + ShaderElement* sh_d = &*pVisual->shader->E[4]; + if (!(flags.test(IRenderVisualFlags::eIgnoreOptimization) || (sh_d && sh_d->flags.bEmissive))) + { + if (SSA < r_ssaDISCARD) + { + //Msg("SSA %.2f discarded", SSA); + return; + } + } + + + // HOM occlusion culling for dynamic objects + if (ps_r__common_flags.test(RFLAG_HOM_DYNAMIC)) + { +#if RENDER!=R_R1 + if (i_mask[CDSGraphManager::fl_normal]) +#endif + { + Fbox world_bb; + world_bb.xform(pVisual->vis.box, *xform); + if (!RImplementation.HOM.visible(world_bb)) + return; + } + } // Distortive geometry should be marked and R2 special-cases it // a) Allow to optimize RT order // b) Should be rendered to special distort buffer in another pass VERIFY(pVisual->shader._get()); - ShaderElement* sh_d = &*pVisual->shader->E[4]; - if (RImplementation.o.distortion && sh_d && sh_d->flags.bDistort && pmask[sh_d->flags.iPriority / 2]) + + if (sh_d && sh_d->flags.bDistort && i_mask[sh_d->flags.iPriority/2]) { - mapSorted_T& test = RI.val_bHUD ? mapHUDDistort : mapDistort; - mapSorted_Node* N = test.insertInAnyWay(distSQ); - N->val.ssa = SSA; - N->val.pObject = RI.val_pObject; - N->val.pVisual = pVisual; - N->val.Matrix = *RI.val_pTransform; - N->val.se = sh_d; // 4=L_special + if (i_mask[CDSGraphManager::fl_hud]) + RGraph.mapHUDSorted.Distort.emplace_back(distSQ, SSA, val_pObject, pVisual, xform, sh_d, i_mask[CDSGraphManager::fl_hud]); + else + RGraph.mapDynamicSorted.Distort.emplace_back(distSQ, SSA, val_pObject, pVisual, xform, sh_d, i_mask[CDSGraphManager::fl_hud]); } // Select shader ShaderElement* sh = RImplementation.rimp_select_sh_dynamic(pVisual, distSQ); - if (0 == sh) return; - if (!pmask[sh->flags.iPriority / 2]) return; + + if (0==sh) + return; + u32 shader_priority = sh->flags.iPriority/2; + if (!i_mask[shader_priority]) + return; // Create common node // NOTE: Invisible elements exist only in R1 - _MatrixItem item = {SSA, RI.val_pObject, pVisual, *RI.val_pTransform}; #if defined(USE_DX11) // Redotix99: for 3D Shader Based Scopes switch (sh->flags.iScopeLense) { @@ -80,12 +95,7 @@ void R_dsgraph_structure::r_dsgraph_insert_dynamic(dxRender_Visual* pVisual, Fve break; case 1: { - mapHUD_Node* N = mapHUD.insertInAnyWay(EPS); - N->val.ssa = SSA; - N->val.pObject = RI.val_pObject; - N->val.pVisual = pVisual; - N->val.Matrix = *RI.val_pTransform; - N->val.se = sh; + RGraph.mapHUD.emplace_back(EPS, SSA, val_pObject, pVisual, xform, sh, i_mask[CDSGraphManager::fl_hud]); // SSS: Deprecated /*if (!sh->passes[0]->ps->hud_disabled) @@ -101,59 +111,43 @@ void R_dsgraph_structure::r_dsgraph_insert_dynamic(dxRender_Visual* pVisual, Fve } case 2: { - mapHUD_Node * N = mapScopeHUD.insertInAnyWay(distSQ); - N->val.ssa = SSA; - N->val.pObject = RI.val_pObject; - N->val.pVisual = pVisual; - N->val.Matrix = *RI.val_pTransform; - N->val.se = sh; + RGraph.mapScopeHUD.emplace_back(distSQ, SSA, val_pObject, pVisual, xform, sh, i_mask[CDSGraphManager::fl_hud]); return; } case 3: { - mapSorted_Node * N = mapScopeHUDSorted.insertInAnyWay(distSQ); - N->val.ssa = SSA; - N->val.pObject = RI.val_pObject; - N->val.pVisual = pVisual; - N->val.Matrix = *RI.val_pTransform; - N->val.se = sh; + RGraph.mapScopeHUDSorted.emplace_back(distSQ, SSA, val_pObject, pVisual, xform, sh, i_mask[CDSGraphManager::fl_hud]); return; } } #endif - // HUD rendering - if (RI.val_bHUD) + if (i_mask[CDSGraphManager::fl_hud]) { if (sh->flags.bStrictB2F) { #if RENDER!=R_R1 if (sh->flags.bEmissive) { - mapSorted_Node* N = RI.val_bCamAttached ? mapCamAttachedEmissive.insertInAnyWay(distSQ) : mapHUDEmissive.insertInAnyWay(distSQ); - N->val.ssa = SSA; - N->val.pObject = RI.val_pObject; - N->val.pVisual = pVisual; - N->val.Matrix = *RI.val_pTransform; - N->val.se = &*pVisual->shader->E[4]; // 4=L_special + if (i_mask[CDSGraphManager::fl_cam]) + RGraph.mapCamAttachedSorted.Emissive.emplace_back(distSQ, SSA, val_pObject, pVisual, xform, sh_d, i_mask[CDSGraphManager::fl_cam]); + else + RGraph.mapHUDSorted.Emissive.emplace_back(distSQ, SSA, val_pObject, pVisual, xform, sh_d, i_mask[CDSGraphManager::fl_hud]); } #endif // RENDER!=R_R1 - mapSorted_Node* N = RI.val_bCamAttached ? mapCamAttachedSorted.insertInAnyWay(distSQ) : mapHUDSorted.insertInAnyWay(distSQ); - N->val.ssa = SSA; - N->val.pObject = RI.val_pObject; - N->val.pVisual = pVisual; - N->val.Matrix = *RI.val_pTransform; - N->val.se = sh; + if (i_mask[CDSGraphManager::fl_cam]) + RGraph.mapCamAttachedSorted.Sorted.emplace_back(distSQ, SSA, val_pObject, pVisual, xform, sh, i_mask[CDSGraphManager::fl_cam]); + else + RGraph.mapHUDSorted.Sorted.emplace_back(distSQ, SSA, val_pObject, pVisual, xform, sh, i_mask[CDSGraphManager::fl_hud]); return; } else { - mapHUD_Node* N = RI.val_bCamAttached ? mapCamAttached.insertInAnyWay(distSQ) : mapHUD.insertInAnyWay(distSQ); - N->val.ssa = SSA; - N->val.pObject = RI.val_pObject; - N->val.pVisual = pVisual; - N->val.Matrix = *RI.val_pTransform; - N->val.se = sh; + if (i_mask[CDSGraphManager::fl_cam]) + RGraph.mapCamAttached.emplace_back(distSQ, SSA, val_pObject, pVisual, xform, sh, i_mask[CDSGraphManager::fl_cam]); + else + RGraph.mapHUD.emplace_back(distSQ, SSA, val_pObject, pVisual, xform, sh, i_mask[CDSGraphManager::fl_hud]); + /* #if RENDER==R_R4 if (RImplementation.o.ssfx_core && !sh->passes[0]->ps->hud_disabled) @@ -170,33 +164,31 @@ void R_dsgraph_structure::r_dsgraph_insert_dynamic(dxRender_Visual* pVisual, Fve #if RENDER!=R_R1 if (sh->flags.bEmissive) { - mapSorted_Node* N = RI.val_bCamAttached ? mapCamAttachedEmissive.insertInAnyWay(distSQ) : mapHUDEmissive.insertInAnyWay(distSQ); - N->val.ssa = SSA; - N->val.pObject = RI.val_pObject; - N->val.pVisual = pVisual; - N->val.Matrix = *RI.val_pTransform; - N->val.se = &*pVisual->shader->E[4]; // 4=L_special + if (i_mask[CDSGraphManager::fl_cam]) + RGraph.mapCamAttachedSorted.Emissive.emplace_back(distSQ, SSA, val_pObject, pVisual, xform, sh_d, i_mask[CDSGraphManager::fl_cam]); + else + RGraph.mapHUDSorted.Emissive.emplace_back(distSQ, SSA, val_pObject, pVisual, xform, sh_d, i_mask[CDSGraphManager::fl_hud]); } + #endif // RENDER!=R_R1 + return; } } // Shadows registering #if RENDER==R_R1 - RI.L_Shadows->add_element(item); + DSGraphItem item = { 0, SSA, val_pObject, pVisual, xform, nullptr, i_mask[CDSGraphManager::fl_hud] }; + R_dsgraph::mapDSGraphItemsMap::TNode N = { 0, item }; + RImplementation.L_Shadows->add_element(N); #endif - if (RI.val_bInvisible) return; + if (i_mask[CDSGraphManager::fl_invisible]) + return; // strict-sorting selection - if (sh->flags.bStrictB2F) + if (sh->flags.bStrictB2F && !pVisual->dcast_ParticleCustom()) { - mapSorted_Node* N = mapSorted.insertInAnyWay(distSQ); - N->val.ssa = SSA; - N->val.pObject = RI.val_pObject; - N->val.pVisual = pVisual; - N->val.Matrix = *RI.val_pTransform; - N->val.se = sh; + RGraph.mapDynamicSorted.Sorted.emplace_back(distSQ, SSA, val_pObject, pVisual, xform, sh, i_mask[CDSGraphManager::fl_hud]); return; } @@ -207,22 +199,14 @@ void R_dsgraph_structure::r_dsgraph_insert_dynamic(dxRender_Visual* pVisual, Fve // c) Should not cast shadows // d) Should be rendered to accumulation buffer in the second pass if (sh->flags.bEmissive) + RGraph.mapDynamicSorted.Emissive.emplace_back(distSQ, SSA, val_pObject, pVisual, xform, sh_d, i_mask[CDSGraphManager::fl_hud]); + + if (sh->flags.bWmark && i_mask[CDSGraphManager::fl_wmarks]) { - mapSorted_Node* N = mapEmissive.insertInAnyWay(distSQ); - N->val.ssa = SSA; - N->val.pObject = RI.val_pObject; - N->val.pVisual = pVisual; - N->val.Matrix = *RI.val_pTransform; - N->val.se = &*pVisual->shader->E[4]; // 4=L_special - } - if (sh->flags.bWmark && pmask_wmark) - { - mapSorted_Node* N = mapWmark.insertInAnyWay(distSQ); - N->val.ssa = SSA; - N->val.pObject = RI.val_pObject; - N->val.pVisual = pVisual; - N->val.Matrix = *RI.val_pTransform; - N->val.se = sh; + if (i_mask[CDSGraphManager::fl_hud]) + RGraph.mapHUDSorted.Wmark.emplace_back(distSQ, SSA, val_pObject, pVisual, xform, sh, i_mask[CDSGraphManager::fl_hud]); + else + RGraph.mapDynamicSorted.Wmark.emplace_back(distSQ, SSA, val_pObject, pVisual, xform, sh, i_mask[CDSGraphManager::fl_hud]); return; } #endif @@ -230,150 +214,108 @@ void R_dsgraph_structure::r_dsgraph_insert_dynamic(dxRender_Visual* pVisual, Fve for (u32 iPass = 0; iPass < sh->passes.size(); ++iPass) { // the most common node - //SPass& pass = *sh->passes.front (); - //mapMatrix_T& map = mapMatrix [sh->flags.iPriority/2]; + + if (sh->passes[iPass] == nullptr) + { + continue; + } + SPass& pass = *sh->passes[iPass]; - mapMatrix_T& map = mapMatrixPasses[sh->flags.iPriority / 2][iPass]; - - -#ifdef USE_RESOURCE_DEBUGGER -#if defined(USE_DX10) || defined(USE_DX11) - mapMatrixVS::TNode* Nvs = map.insert (pass.vs); - mapMatrixGS::TNode* Ngs = Nvs->val.insert (pass.gs); - mapMatrixPS::TNode* Nps = Ngs->val.insert (pass.ps); -#else // USE_DX10 - mapMatrixVS::TNode* Nvs = map.insert (pass.vs); - mapMatrixPS::TNode* Nps = Nvs->val.insert (pass.ps); -#endif // USE_DX10 -#else -#if defined(USE_DX10) || defined(USE_DX11) - mapMatrixVS::TNode* Nvs = map.insert(&*pass.vs); - mapMatrixGS::TNode* Ngs = Nvs->val.insert(pass.gs->gs); - mapMatrixPS::TNode* Nps = Ngs->val.insert(pass.ps->ps); -#else // USE_DX10 - mapMatrixVS::TNode* Nvs = map.insert(pass.vs->vs); - mapMatrixPS::TNode* Nps = Nvs->val.insert(pass.ps->ps); -#endif // USE_DX10 -#endif -#ifdef USE_DX11 -# ifdef USE_RESOURCE_DEBUGGER - Nps->val.hs = pass.hs; - Nps->val.ds = pass.ds; - mapMatrixCS::TNode* Ncs = Nps->val.mapCS.insert (pass.constants._get()); -# else - Nps->val.hs = pass.hs->sh; - Nps->val.ds = pass.ds->sh; - mapMatrixCS::TNode* Ncs = Nps->val.mapCS.insert(pass.constants._get()); -# endif +#if RENDER==R_R1 + AddToRenderQueue(RGraph.mapDynamicPasses[shader_priority][iPass], item, pass); #else - mapMatrixCS::TNode* Ncs = Nps->val.insert(pass.constants._get()); + AddToRenderQueue(RGraph.mapDynamicPasses[shader_priority][iPass], { 0, SSA, val_pObject, pVisual, xform, nullptr, i_mask[CDSGraphManager::fl_hud] }, pass); #endif - mapMatrixStates::TNode* Nstate = Ncs->val.insert(pass.state->state); - mapMatrixTextures::TNode* Ntex = Nstate->val.insert(pass.T._get()); - mapMatrixItems& items = Ntex->val; - items.push_back(item); + } +} - // Need to sort for HZB efficient use - if (SSA > Ntex->val.ssa) +extern float ps_r__ssaDISCARD_exp; +extern float ps_r__ssaDISCARD_fade_k; +void CDSGraphManager::r_dsgraph_insert_static(dxRender_Visual *pVisual) +{ + if (m_static_seen.find(pVisual) != m_static_seen.end()) + { + if (PortalTraverseDbg_Enabled()) { - Ntex->val.ssa = SSA; - if (SSA > Nstate->val.ssa) - { - Nstate->val.ssa = SSA; - if (SSA > Ncs->val.ssa) - { - Ncs->val.ssa = SSA; -#ifdef USE_DX11 - if (SSA > Nps->val.mapCS.ssa) - { - Nps->val.mapCS.ssa = SSA; -#else - if (SSA > Nps->val.ssa) - { - Nps->val.ssa = SSA; -#endif -#if defined(USE_DX10) || defined(USE_DX11) - if (SSA > Ngs->val.ssa) - { - Ngs->val.ssa = SSA; -#endif // USE_DX10 - if (SSA > Nvs->val.ssa) - { - Nvs->val.ssa = SSA; -#if defined(USE_DX10) || defined(USE_DX11) - } - } - } - } - } - } -#else // USE_DX10 - } - } - } - } + PortalTraverseDebugStats& dbg = PortalTraverseDbg_Get(); + const bool opt_bucket = PortalTraverseDbg_IsOptions(i_options); + ++dbg.static_dedup_skipped; + if (opt_bucket) + ++dbg.static_dedup_skipped_opt; + else + ++dbg.static_dedup_skipped_noopt; } -#endif // USE_DX10 + return; } - -#if RENDER!=R_R1 - if (val_recorder) + m_static_seen.insert(pVisual); + if (PortalTraverseDbg_Enabled()) { - Fbox3 temp; - Fmatrix& xf = *RI.val_pTransform; - temp.xform(pVisual->vis.box, xf); - val_recorder->push_back(temp); + PortalTraverseDebugStats& dbg = PortalTraverseDbg_Get(); + const bool opt_bucket = PortalTraverseDbg_IsOptions(i_options); + ++dbg.static_dedup_seen; + if (opt_bucket) + ++dbg.static_dedup_seen_opt; + else + ++dbg.static_dedup_seen_noopt; } -#endif -} - -void R_dsgraph_structure::r_dsgraph_insert_static(dxRender_Visual* pVisual) -{ - CRender& RI = RImplementation; - - if (pVisual->vis.marker == RI.marker) return; - pVisual->vis.marker = RI.marker; - -#if RENDER==R_R1 - if (RI.o.vis_intersect && (pVisual->vis.accept_frame != Device.dwFrame)) return; - pVisual->vis.accept_frame = Device.dwFrame; -#endif float distSQ; float SSA = CalcSSA(distSQ, pVisual->vis.sphere.P, pVisual); - if (SSA <= r_ssaDISCARD) return; + Flags16& flags = pVisual->flags; + ShaderElement* sh_d = &*pVisual->shader->E[4]; + if (!(flags.test(IRenderVisualFlags::eIgnoreOptimization) || (sh_d && sh_d->flags.bEmissive))) + { + if (SSA < r_ssaDISCARD) + return; + + // demonized: Replace hard cutoff with gradient cutoff + // Smaller objects that fail the SSA test will still render depending on how much smaller they are than the discard limit. + // Reduces the "rendering radius" effect and makes pop-in less noticeable + // Allows to increase the discard limit for better performance without making pop-in much worse + // Define where the "thinning" begins. + // E.g., objects 4x the size of the discard limit start fading. + float fade_start = r_ssaDISCARD * ps_r__ssaDISCARD_fade_k; + + // The Gradient Zone + if (SSA < fade_start) + { + // Calculate a linear survival probability between 0.0 and 1.0 + float survival_chance = (SSA - r_ssaDISCARD) / (fade_start - r_ssaDISCARD); + + // Convert the 32-bit hash to a float between 0.0 and 1.0 + // Multiplying by 1.0 / 2^32 is faster than float division + u32 hash = GetFvectorHash(pVisual->vis.sphere.P); + constexpr float hash_to_float = 1.0f / 4294967296.0f; + float val = hash * hash_to_float; + + // If the object's hash value is higher than its survival chance, cull it + if (val > _powf(survival_chance, ps_r__ssaDISCARD_exp)) + return; + } + } // Distortive geometry should be marked and R2 special-cases it // a) Allow to optimize RT order // b) Should be rendered to special distort buffer in another pass VERIFY(pVisual->shader._get()); - ShaderElement* sh_d = &*pVisual->shader->E[4]; - if (RImplementation.o.distortion && sh_d && sh_d->flags.bDistort && pmask[sh_d->flags.iPriority / 2]) - { - mapSorted_Node* N = mapDistort.insertInAnyWay(distSQ); - N->val.ssa = SSA; - N->val.pObject = NULL; - N->val.pVisual = pVisual; - N->val.Matrix = Fidentity; - N->val.se = &*pVisual->shader->E[4]; // 4=L_special - } + if (sh_d && sh_d->flags.bDistort && i_mask[sh_d->flags.iPriority/2]) + RGraph.mapStaticSorted.Distort.emplace_back(distSQ, SSA, nullptr, pVisual, &Fidentity, sh_d, false); // Select shader ShaderElement* sh = RImplementation.rimp_select_sh_static(pVisual, distSQ); - if (0 == sh) return; - if (!pmask[sh->flags.iPriority / 2]) return; + + if (0 == sh) + return; + u32 shader_priority = sh->flags.iPriority / 2; + if (!i_mask[shader_priority]) + return; // Water rendering #if RENDER==R_R4 if (sh->flags.isWater && RImplementation.o.ssfx_water) { - mapWater_Node* N = mapWater.insertInAnyWay(distSQ); - N->val.ssa = SSA; - N->val.pObject = NULL; - N->val.pVisual = pVisual; - N->val.Matrix = Fidentity; - N->val.se = sh; + RGraph.mapWater.emplace_back(distSQ, SSA, nullptr, pVisual, &Fidentity, sh, false); return; } #endif @@ -381,11 +323,7 @@ void R_dsgraph_structure::r_dsgraph_insert_static(dxRender_Visual* pVisual) // strict-sorting selection if (sh->flags.bStrictB2F) { - mapSorted_Node* N = mapSorted.insertInAnyWay(distSQ); - N->val.pObject = NULL; - N->val.pVisual = pVisual; - N->val.Matrix = Fidentity; - N->val.se = sh; + RGraph.mapStaticSorted.Sorted.emplace_back(distSQ, SSA, nullptr, pVisual, &Fidentity, sh, false); return; } @@ -396,877 +334,462 @@ void R_dsgraph_structure::r_dsgraph_insert_static(dxRender_Visual* pVisual) // c) Should not cast shadows // d) Should be rendered to accumulation buffer in the second pass if (sh->flags.bEmissive) - { - mapSorted_Node* N = mapEmissive.insertInAnyWay(distSQ); - N->val.ssa = SSA; - N->val.pObject = NULL; - N->val.pVisual = pVisual; - N->val.Matrix = Fidentity; - N->val.se = &*pVisual->shader->E[4]; // 4=L_special - } - if (sh->flags.bWmark && pmask_wmark) - { - mapSorted_Node* N = mapWmark.insertInAnyWay(distSQ); - N->val.ssa = SSA; - N->val.pObject = NULL; - N->val.pVisual = pVisual; - N->val.Matrix = Fidentity; - N->val.se = sh; - return; - } -#endif + RGraph.mapStaticSorted.Emissive.emplace_back(distSQ, SSA, nullptr, pVisual, &Fidentity, sh_d, false ); - if (val_feedback && counter_S == val_feedback_breakp) val_feedback->rfeedback_static(pVisual); - - counter_S ++; - - if (sh->flags.bLandscape && RI.phase == CRender::PHASE_NORMAL) + if (sh->flags.bWmark && i_mask[CDSGraphManager::fl_wmarks]) { - mapLandscape_Node* N = mapLandscape.insertInAnyWay(distSQ); - N->val.ssa = SSA; - N->val.pObject = NULL; - N->val.pVisual = pVisual; - N->val.Matrix = Fidentity; - N->val.se = sh; + RGraph.mapStaticSorted.Wmark.emplace_back(distSQ, SSA, nullptr, pVisual, &Fidentity, sh, false); return; } +#endif for (u32 iPass = 0; iPass < sh->passes.size(); ++iPass) { - //SPass& pass = *sh->passes.front (); - //mapNormal_T& map = mapNormal [sh->flags.iPriority/2]; - SPass& pass = *sh->passes[iPass]; - mapNormal_T& map = mapNormalPasses[sh->flags.iPriority / 2][iPass]; - - //#ifdef USE_RESOURCE_DEBUGGER - // mapNormalVS::TNode* Nvs = map.insert (pass.vs); - // mapNormalPS::TNode* Nps = Nvs->val.insert (pass.ps); - //#else - //#if defined(USE_DX10) || defined(USE_DX11) - // mapNormalVS::TNode* Nvs = map.insert (&*pass.vs); - //#else // USE_DX10 - // mapNormalVS::TNode* Nvs = map.insert (pass.vs->vs); - //#endif // USE_DX10 - // mapNormalPS::TNode* Nps = Nvs->val.insert (pass.ps->ps); - //#endif - -#ifdef USE_RESOURCE_DEBUGGER -# if defined(USE_DX10) || defined(USE_DX11) - mapNormalVS::TNode* Nvs = map.insert (pass.vs); - mapNormalGS::TNode* Ngs = Nvs->val.insert (pass.gs); - mapNormalPS::TNode* Nps = Ngs->val.insert (pass.ps); -# else // USE_DX10 - mapNormalVS::TNode* Nvs = map.insert (pass.vs); - mapNormalPS::TNode* Nps = Nvs->val.insert (pass.ps); -# endif // USE_DX10 -#else // USE_RESOURCE_DEBUGGER -# if defined(USE_DX10) || defined(USE_DX11) - mapNormalVS::TNode* Nvs = map.insert(&*pass.vs); - mapNormalGS::TNode* Ngs = Nvs->val.insert(pass.gs->gs); - mapNormalPS::TNode* Nps = Ngs->val.insert(pass.ps->ps); -# else // USE_DX10 - mapNormalVS::TNode* Nvs = map.insert(pass.vs->vs); - mapNormalPS::TNode* Nps = Nvs->val.insert(pass.ps->ps); -# endif // USE_DX10 -#endif // USE_RESOURCE_DEBUGGER - -#ifdef USE_DX11 -# ifdef USE_RESOURCE_DEBUGGER - Nps->val.hs = pass.hs; - Nps->val.ds = pass.ds; - mapNormalCS::TNode* Ncs = Nps->val.mapCS.insert (pass.constants._get()); -# else - Nps->val.hs = pass.hs->sh; - Nps->val.ds = pass.ds->sh; - mapNormalCS::TNode* Ncs = Nps->val.mapCS.insert(pass.constants._get()); -# endif -#else - mapNormalCS::TNode* Ncs = Nps->val.insert(pass.constants._get()); -#endif - mapNormalStates::TNode* Nstate = Ncs->val.insert(pass.state->state); - mapNormalTextures::TNode* Ntex = Nstate->val.insert(pass.T._get()); - mapNormalItems& items = Ntex->val; - _NormalItem item = {SSA, pVisual}; - items.push_back(item); - - // Need to sort for HZB efficient use - if (SSA > Ntex->val.ssa) - { - Ntex->val.ssa = SSA; - if (SSA > Nstate->val.ssa) - { - Nstate->val.ssa = SSA; - if (SSA > Ncs->val.ssa) - { - Ncs->val.ssa = SSA; -#ifdef USE_DX11 - if (SSA > Nps->val.mapCS.ssa) - { - Nps->val.mapCS.ssa = SSA; -#else - if (SSA > Nps->val.ssa) - { - Nps->val.ssa = SSA; -#endif - // if (SSA>Nvs->val.ssa) { Nvs->val.ssa = SSA; - // } } } } } -#if defined(USE_DX10) || defined(USE_DX11) - if (SSA > Ngs->val.ssa) - { - Ngs->val.ssa = SSA; -#endif // USE_DX10 - if (SSA > Nvs->val.ssa) - { - Nvs->val.ssa = SSA; -#if defined(USE_DX10) || defined(USE_DX11) - } - } - } - } - } - } -#else // USE_DX10 - } - } - } - } - } -#endif // USE_DX10 - } + // the most common node + if (sh->passes[iPass] == nullptr) + continue; -#if RENDER!=R_R1 - if (val_recorder) - { - val_recorder->push_back(pVisual->vis.box); - } -#endif -} + SPass& pass = *sh->passes[iPass]; -// Static geometry optimization -#define O_S_L1_S_LOW 10.f // geometry 3d volume size -#define O_S_L1_D_LOW 150.f // distance, after which it is not rendered -#define O_S_L2_S_LOW 100.f -#define O_S_L2_D_LOW 200.f -#define O_S_L3_S_LOW 500.f -#define O_S_L3_D_LOW 250.f -#define O_S_L4_S_LOW 2500.f -#define O_S_L4_D_LOW 350.f -#define O_S_L5_S_LOW 7000.f -#define O_S_L5_D_LOW 400.f - -#define O_S_L1_S_MED 25.f -#define O_S_L1_D_MED 50.f -#define O_S_L2_S_MED 200.f -#define O_S_L2_D_MED 150.f -#define O_S_L3_S_MED 1000.f -#define O_S_L3_D_MED 200.f -#define O_S_L4_S_MED 2500.f -#define O_S_L4_D_MED 300.f -#define O_S_L5_S_MED 7000.f -#define O_S_L5_D_MED 400.f - -#define O_S_L1_S_HII 50.f -#define O_S_L1_D_HII 50.f -#define O_S_L2_S_HII 400.f -#define O_S_L2_D_HII 150.f -#define O_S_L3_S_HII 1500.f -#define O_S_L3_D_HII 200.f -#define O_S_L4_S_HII 5000.f -#define O_S_L4_D_HII 300.f -#define O_S_L5_S_HII 20000.f -#define O_S_L5_D_HII 350.f - -#define O_S_L1_S_ULT 50.f -#define O_S_L1_D_ULT 35.f -#define O_S_L2_S_ULT 500.f -#define O_S_L2_D_ULT 125.f -#define O_S_L3_S_ULT 1750.f -#define O_S_L3_D_ULT 175.f -#define O_S_L4_S_ULT 5250.f -#define O_S_L4_D_ULT 250.f -#define O_S_L5_S_ULT 25000.f -#define O_S_L5_D_ULT 300.f - -// Dyn geometry optimization - -#define O_D_L1_S_LOW 1.f // geometry 3d volume size -#define O_D_L1_D_LOW 80.f // distance, after which it is not rendered -#define O_D_L2_S_LOW 3.f -#define O_D_L2_D_LOW 150.f -#define O_D_L3_S_LOW 4000.f -#define O_D_L3_D_LOW 250.f - -#define O_D_L1_S_MED 1.f -#define O_D_L1_D_MED 40.f -#define O_D_L2_S_MED 4.f -#define O_D_L2_D_MED 100.f -#define O_D_L3_S_MED 4000.f -#define O_D_L3_D_MED 200.f - -#define O_D_L1_S_HII 1.4f -#define O_D_L1_D_HII 30.f -#define O_D_L2_S_HII 4.f -#define O_D_L2_D_HII 80.f -#define O_D_L3_S_HII 4000.f -#define O_D_L3_D_HII 150.f - -#define O_D_L1_S_ULT 2.0f -#define O_D_L1_D_ULT 30.f -#define O_D_L2_S_ULT 8.f -#define O_D_L2_D_ULT 50.f -#define O_D_L3_S_ULT 4000.f -#define O_D_L3_D_ULT 110.f - -Fvector4 o_optimize_static_l1_dist = {O_S_L1_D_LOW, O_S_L1_D_MED, O_S_L1_D_HII, O_S_L1_D_ULT}; -Fvector4 o_optimize_static_l1_size = {O_S_L1_S_LOW, O_S_L1_S_MED, O_S_L1_S_HII, O_S_L1_S_ULT}; -Fvector4 o_optimize_static_l2_dist = {O_S_L2_D_LOW, O_S_L2_D_MED, O_S_L2_D_HII, O_S_L2_D_ULT}; -Fvector4 o_optimize_static_l2_size = {O_S_L2_S_LOW, O_S_L2_S_MED, O_S_L2_S_HII, O_S_L2_S_ULT}; -Fvector4 o_optimize_static_l3_dist = {O_S_L3_D_LOW, O_S_L3_D_MED, O_S_L3_D_HII, O_S_L3_D_ULT}; -Fvector4 o_optimize_static_l3_size = {O_S_L3_S_LOW, O_S_L3_S_MED, O_S_L3_S_HII, O_S_L3_S_ULT}; -Fvector4 o_optimize_static_l4_dist = {O_S_L4_D_LOW, O_S_L4_D_MED, O_S_L4_D_HII, O_S_L4_D_ULT}; -Fvector4 o_optimize_static_l4_size = {O_S_L4_S_LOW, O_S_L4_S_MED, O_S_L4_S_HII, O_S_L4_S_ULT}; -Fvector4 o_optimize_static_l5_dist = {O_S_L5_D_LOW, O_S_L5_D_MED, O_S_L5_D_HII, O_S_L5_D_ULT}; -Fvector4 o_optimize_static_l5_size = {O_S_L5_S_LOW, O_S_L5_S_MED, O_S_L5_S_HII, O_S_L5_S_ULT}; - -Fvector4 o_optimize_dynamic_l1_dist = {O_D_L1_D_LOW, O_D_L1_D_MED, O_D_L1_D_HII, O_D_L1_D_ULT}; -Fvector4 o_optimize_dynamic_l1_size = {O_D_L1_S_LOW, O_D_L1_S_MED, O_D_L1_S_HII, O_D_L1_S_ULT}; -Fvector4 o_optimize_dynamic_l2_dist = {O_D_L2_D_LOW, O_D_L2_D_MED, O_D_L2_D_HII, O_D_L2_D_ULT}; -Fvector4 o_optimize_dynamic_l2_size = {O_D_L2_S_LOW, O_D_L2_S_MED, O_D_L2_S_HII, O_D_L2_S_ULT}; -Fvector4 o_optimize_dynamic_l3_dist = {O_D_L3_D_LOW, O_D_L3_D_MED, O_D_L3_D_HII, O_D_L3_D_ULT}; -Fvector4 o_optimize_dynamic_l3_size = {O_D_L3_S_LOW, O_D_L3_S_MED, O_D_L3_S_HII, O_D_L3_S_ULT}; - -#define BASE_FOV 67.f - -IC float GetDistFromCamera(const Fvector& from_position) -// Aproximate, adjusted by fov, distance from camera to position (For right work when looking though binoculars and scopes) -{ - float distance = Device.vCameraPosition.distance_to(from_position); - float fov_K = BASE_FOV / Device.fFOV; - float adjusted_distane = distance / fov_K; - - return adjusted_distane; + AddToRenderQueue(RGraph.mapStaticPasses[shader_priority][iPass], { 0, SSA, nullptr, pVisual, nullptr, nullptr, false }, pass); + } } -IC bool IsValuableToRender(dxRender_Visual* pVisual, bool isStatic, bool sm, Fmatrix& transform_matrix) +void CDSGraphManager::AddToRenderQueue(R_dsgraph::RenderQueue& queue, const R_dsgraph::DSGraphItem& item, const SPass& pass) { - if ((isStatic && opt_static >= 1) || (!isStatic && opt_dynamic >= 1)) + if (PortalTraverseDbg_Enabled()) { - float sphere_volume = pVisual->getVisData().sphere.volume(); - - float adjusted_distane = 0; - - if (isStatic) - adjusted_distane = GetDistFromCamera(pVisual->vis.sphere.P); - else - // dynamic geometry position needs to be transformed by transform matrix, to get world coordinates, dont forget ;) - { - Fvector pos; - transform_matrix.transform_tiny(pos, pVisual->vis.sphere.P); - - adjusted_distane = GetDistFromCamera(pos); - } - - if (sm && !!psDeviceFlags2.test(rsOptShadowGeom)) // Highest cut off for shadow map - { - if (sphere_volume < 50000.f && adjusted_distane > ps_ssfx_shadow_cascades.z) - // don't need geometry behind the farest sun shadow cascade - return false; - - if ((sphere_volume < o_optimize_static_l1_size.z) && (adjusted_distane > o_optimize_static_l1_dist.z)) - return false; - else if ((sphere_volume < o_optimize_static_l2_size.z) && (adjusted_distane > o_optimize_static_l2_dist.z)) - return false; - else if ((sphere_volume < o_optimize_static_l3_size.z) && (adjusted_distane > o_optimize_static_l3_dist.z)) - return false; - else if ((sphere_volume < o_optimize_static_l4_size.z) && (adjusted_distane > o_optimize_static_l4_dist.z)) - return false; - else if ((sphere_volume < o_optimize_static_l5_size.z) && (adjusted_distane > o_optimize_static_l5_dist.z)) - return false; - - return true; - } - - if (isStatic) + PortalTraverseDebugStats& dbg = PortalTraverseDbg_Get(); + const bool opt_bucket = PortalTraverseDbg_IsOptions(i_options); + // Static items use nullptr matrix/object in current pipeline. + if (item.pMatrix == nullptr && item.pObject == nullptr) { - - if (pVisual->Type == MT_LOD || pVisual->Type == MT_TREE_PM || pVisual->Type == MT_TREE_ST) - return true; - - if (opt_static == 2) - { - if ((sphere_volume < o_optimize_static_l1_size.y) && (adjusted_distane > o_optimize_static_l1_dist.y)) - return false; - else if ((sphere_volume < o_optimize_static_l2_size.y) && (adjusted_distane > o_optimize_static_l2_dist. - y)) - return false; - else if ((sphere_volume < o_optimize_static_l3_size.y) && (adjusted_distane > o_optimize_static_l3_dist. - y)) - return false; - else if ((sphere_volume < o_optimize_static_l4_size.y) && (adjusted_distane > o_optimize_static_l4_dist. - y)) - return false; - else if ((sphere_volume < o_optimize_static_l5_size.y) && (adjusted_distane > o_optimize_static_l5_dist. - y)) - return false; - } - else if (opt_static == 3) - { - if ((sphere_volume < o_optimize_static_l1_size.z) && (adjusted_distane > o_optimize_static_l1_dist.z)) - return false; - else if ((sphere_volume < o_optimize_static_l2_size.z) && (adjusted_distane > o_optimize_static_l2_dist. - z)) - return false; - else if ((sphere_volume < o_optimize_static_l3_size.z) && (adjusted_distane > o_optimize_static_l3_dist. - z)) - return false; - else if ((sphere_volume < o_optimize_static_l4_size.z) && (adjusted_distane > o_optimize_static_l4_dist. - z)) - return false; - else if ((sphere_volume < o_optimize_static_l5_size.z) && (adjusted_distane > o_optimize_static_l5_dist. - z)) - return false; - } - else if (opt_static == 4) - { - if ((sphere_volume < o_optimize_static_l1_size.w) && (adjusted_distane > o_optimize_static_l1_dist.w)) - return false; - else if ((sphere_volume < o_optimize_static_l2_size.w) && (adjusted_distane > o_optimize_static_l2_dist. - w)) - return false; - else if ((sphere_volume < o_optimize_static_l3_size.w) && (adjusted_distane > o_optimize_static_l3_dist. - w)) - return false; - else if ((sphere_volume < o_optimize_static_l4_size.w) && (adjusted_distane > o_optimize_static_l4_dist. - w)) - return false; - else if ((sphere_volume < o_optimize_static_l5_size.w) && (adjusted_distane > o_optimize_static_l5_dist. - w)) - return false; - } + ++dbg.queue_static_packets; + if (opt_bucket) + ++dbg.queue_static_packets_opt; else - { - if ((sphere_volume < o_optimize_static_l1_size.x) && (adjusted_distane > o_optimize_static_l1_dist.x)) - return false; - else if ((sphere_volume < o_optimize_static_l2_size.x) && (adjusted_distane > o_optimize_static_l2_dist. - x)) - return false; - else if ((sphere_volume < o_optimize_static_l3_size.x) && (adjusted_distane > o_optimize_static_l3_dist. - x)) - return false; - else if ((sphere_volume < o_optimize_static_l4_size.x) && (adjusted_distane > o_optimize_static_l4_dist. - x)) - return false; - else if ((sphere_volume < o_optimize_static_l5_size.x) && (adjusted_distane > o_optimize_static_l5_dist. - x)) - return false; - } + ++dbg.queue_static_packets_noopt; } else { - if (opt_dynamic == 2) - { - if ((sphere_volume < o_optimize_dynamic_l1_size.y) && (adjusted_distane > o_optimize_dynamic_l1_dist.y)) - return false; - else if ((sphere_volume < o_optimize_dynamic_l2_size.y) && (adjusted_distane > - o_optimize_dynamic_l2_dist.y)) - return false; - else if ((sphere_volume < o_optimize_dynamic_l3_size.y) && (adjusted_distane > - o_optimize_dynamic_l3_dist.y)) - return false; - } - else if (opt_dynamic == 3) - { - if ((sphere_volume < o_optimize_dynamic_l1_size.z) && (adjusted_distane > o_optimize_dynamic_l1_dist.z)) - return false; - else if ((sphere_volume < o_optimize_dynamic_l2_size.z) && (adjusted_distane > - o_optimize_dynamic_l2_dist.z)) - return false; - else if ((sphere_volume < o_optimize_dynamic_l3_size.z) && (adjusted_distane > - o_optimize_dynamic_l3_dist.z)) - return false; - } - else if (opt_dynamic == 4) - { - if ((sphere_volume < o_optimize_dynamic_l1_size.w) && (adjusted_distane > o_optimize_dynamic_l1_dist.w)) - return false; - else if ((sphere_volume < o_optimize_dynamic_l2_size.w) && (adjusted_distane > - o_optimize_dynamic_l2_dist.w)) - return false; - else if ((sphere_volume < o_optimize_dynamic_l3_size.w) && (adjusted_distane > - o_optimize_dynamic_l3_dist.w)) - return false; - } + ++dbg.queue_dynamic_packets; + if (opt_bucket) + ++dbg.queue_dynamic_packets_opt; else - { - if ((sphere_volume < o_optimize_dynamic_l1_size.x) && (adjusted_distane > o_optimize_dynamic_l1_dist.x)) - return false; - else if ((sphere_volume < o_optimize_dynamic_l2_size.x) && (adjusted_distane > - o_optimize_dynamic_l2_dist.x)) - return false; - else if ((sphere_volume < o_optimize_dynamic_l3_size.x) && (adjusted_distane > - o_optimize_dynamic_l3_dist.x)) - return false; - } + ++dbg.queue_dynamic_packets_noopt; } } - return true; + queue.emplace_back(item, pass); } //////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////// -void CRender::add_leafs_Dynamic(dxRender_Visual* pVisual) +void CDSGraphManager::add_Dynamic(IRenderVisual* piVisual, Fmatrix* xform) { - if (!pVisual) - return; + + dxRender_Visual* pVisual = (dxRender_Visual*)piVisual; + if (!pVisual) return; - Flags16& flags = pVisual->flags; + Flags16& flags = piVisual->flags; - if (phase != PHASE_NORMAL && !!flags.test(IRenderVisualFlags::eNoShadow)) - return; - - if (!!!flags.test(IRenderVisualFlags::eIgnoreOptimization) && !IsValuableToRender(pVisual, false, phase == 1, *val_pTransform)) + if (!i_mask[CDSGraphManager::fl_normal] && !!flags.test(IRenderVisualFlags::eNoShadow)) return; // Visual is 100% visible - simply add it - xr_vector::iterator I, E; // it may be useful for 'hierrarhy' visual - switch (pVisual->Type) { case MT_PARTICLE_GROUP: + { + // Add all children, doesn't perform any tests + PS::CParticleGroup* pG = (PS::CParticleGroup*)pVisual->dcast_ParticleCustom(); + xrCriticalSectionGuard guard(&pG->onframe_lock); + for (PS::CParticleGroup::SItem& I_ : pG->items) { - // Add all children, doesn't perform any tests - PS::CParticleGroup* pG = (PS::CParticleGroup*)pVisual; - for (PS::CParticleGroup::SItemVecIt i_it = pG->items.begin(); i_it != pG->items.end(); ++i_it) - { - PS::CParticleGroup::SItem& I = *i_it; - if (I._effect) add_leafs_Dynamic(I._effect); - for (xr_vector::iterator pit = I._children_related.begin(); pit != I - ._children_related. - end(); ++pit) - add_leafs_Dynamic(*pit); - for (xr_vector::iterator pit = I._children_free.begin(); pit != I._children_free.end() - ; ++pit) - add_leafs_Dynamic(*pit); - } + add_Dynamic(I_._effect, xform); + add_leafs_Dynamic(I_._children_related, xform); + add_leafs_Dynamic(I_._children_free, xform); } - return; + }return; + case MT_HIERRARHY: - { - // Add all children, doesn't perform any tests - FHierrarhyVisual* pV = (FHierrarhyVisual*)pVisual; - I = pV->children.begin(); - E = pV->children.end(); - for (; I != E; ++I) add_leafs_Dynamic((dxRender_Visual*)*I); - } - return; + { + // Add all children, doesn't perform any tests + FHierrarhyVisual* pV = (FHierrarhyVisual*)pVisual; + add_leafs_Dynamic(pV->children, xform); + }return; + case MT_SKELETON_ANIM: case MT_SKELETON_RIGID: + { + // Add all children, doesn't perform any tests + CKinematics* pV = (CKinematics*)pVisual; + BOOL _use_lod = FALSE; + if (pV->m_lod) { - // Add all children, doesn't perform any tests - CKinematics* pV = (CKinematics*)pVisual; - BOOL _use_lod = FALSE; - if (pV->m_lod) - { - Fvector Tpos; - float D; - val_pTransform->transform_tiny(Tpos, pV->vis.sphere.P); - float ssa = CalcSSA(D, Tpos, pV->vis.sphere.R / 2.f); // assume dynamics never consume full sphere - if (ssa < r_ssaLOD_A) _use_lod = TRUE; - } - if (_use_lod) - { - add_leafs_Dynamic(pV->m_lod); - } - else - { - pV->CalculateBones(TRUE); - pV->CalculateWallmarks(); //. bug? - I = pV->children.begin(); - E = pV->children.end(); - for (; I != E; ++I) add_leafs_Dynamic((dxRender_Visual*)*I); - } + Fvector Tpos; + float D; + xform->transform_tiny(Tpos, pV->vis.sphere.P); + float ssa = CalcSSA(D, Tpos, pV->vis.sphere.R * 0.5f); // assume dynamics never consume full sphere + if (ssa < r_ssaLOD_A) + _use_lod = TRUE; } - return; - default: + if (_use_lod) + add_Dynamic(pV->m_lod, xform); + else { - // General type of visual - // Calculate distance to it's center - Fvector Tpos; - val_pTransform->transform_tiny(Tpos, pVisual->vis.sphere.P); - r_dsgraph_insert_dynamic(pVisual, Tpos); + //pV->CalculateBones(TRUE); + if (i_mask[CDSGraphManager::fl_normal]) + pV->CalculateWallmarks(); + add_leafs_Dynamic(pV->children, xform); } - return; + }return; + + default: + { + // General type of visual + // Calculate distance to it's center + r_dsgraph_insert_dynamic(pVisual, xform); + }return; } } -void CRender::add_leafs_Static(dxRender_Visual* pVisual) +void CDSGraphManager::add_Dynamic(dxRender_Visual* pVisual, Fmatrix* xform) { - if (!HOM.visible(pVisual->vis)) - return; + if (!pVisual) return; Flags16& flags = pVisual->dcast_RenderVisual()->flags; - if (phase != PHASE_NORMAL && !!flags.test(IRenderVisualFlags::eNoShadow)) - return; - - if (!!!flags.test(IRenderVisualFlags::eIgnoreOptimization) && !IsValuableToRender(pVisual, true, phase == 1, *val_pTransform)) + if (!i_mask[CDSGraphManager::fl_normal] && !!flags.test(IRenderVisualFlags::eNoShadow)) return; // Visual is 100% visible - simply add it - xr_vector::iterator I, E; // it may be usefull for 'hierrarhy' visuals - switch (pVisual->Type) { case MT_PARTICLE_GROUP: + { + // Add all children, doesn't perform any tests + PS::CParticleGroup* pG = (PS::CParticleGroup*)pVisual->dcast_ParticleCustom(); + xrCriticalSectionGuard guard(&pG->onframe_lock); + for (PS::CParticleGroup::SItem& I_ : pG->items) { - // Add all children, doesn't perform any tests - PS::CParticleGroup* pG = (PS::CParticleGroup*)pVisual; - for (PS::CParticleGroup::SItemVecIt i_it = pG->items.begin(); i_it != pG->items.end(); ++i_it) - { - PS::CParticleGroup::SItem& I = *i_it; - if (I._effect) add_leafs_Dynamic(I._effect); - for (xr_vector::iterator pit = I._children_related.begin(); pit != I - ._children_related. - end(); ++pit) - add_leafs_Dynamic(*pit); - for (xr_vector::iterator pit = I._children_free.begin(); pit != I._children_free.end() - ; ++pit) - add_leafs_Dynamic(*pit); - } + add_Dynamic(I_._effect, xform); + add_leafs_Dynamic(I_._children_related, xform); + add_leafs_Dynamic(I_._children_free, xform); } - return; + }break; + case MT_HIERRARHY: - { - // Add all children, doesn't perform any tests - FHierrarhyVisual* pV = (FHierrarhyVisual*)pVisual; - I = pV->children.begin(); - E = pV->children.end(); - for (; I != E; ++I) add_leafs_Static((dxRender_Visual*)*I); - } - return; + { + // Add all children, doesn't perform any tests + FHierrarhyVisual* pV = (FHierrarhyVisual*)pVisual; + add_leafs_Dynamic(pV->children, xform); + }break; + case MT_SKELETON_ANIM: case MT_SKELETON_RIGID: + { + // Add all children, doesn't perform any tests + CKinematics* pV = (CKinematics*)pVisual; + BOOL _use_lod = FALSE; + if (pV->m_lod) { - // Add all children, doesn't perform any tests - CKinematics* pV = (CKinematics*)pVisual; - pV->CalculateBones(TRUE); - I = pV->children.begin(); - E = pV->children.end(); - for (; I != E; ++I) add_leafs_Static((dxRender_Visual*)*I); - } - return; - case MT_LOD: - { - FLOD* pV = (FLOD*)pVisual; + Fvector Tpos; float D; - float ssa = CalcSSA(D, pV->vis.sphere.P, pV); - ssa *= pV->lod_factor; + xform->transform_tiny(Tpos, pV->vis.sphere.P); + float ssa = CalcSSA(D, Tpos, pV->vis.sphere.R * 0.5f); // assume dynamics never consume full sphere if (ssa < r_ssaLOD_A) - { - if (ssa < r_ssaDISCARD) return; - mapLOD_Node* N = mapLOD.insertInAnyWay(D); - N->val.ssa = ssa; - N->val.pVisual = pVisual; - } -#if RENDER!=R_R1 - if (ssa > r_ssaLOD_B || phase == PHASE_SMAP) -#else - if (ssa > r_ssaLOD_B) -#endif - { - // Add all children, doesn't perform any tests - I = pV->children.begin(); - E = pV->children.end(); - for (; I != E; ++I) add_leafs_Static((dxRender_Visual*)*I); - } + _use_lod = TRUE; } - return; - case MT_TREE_PM: - case MT_TREE_ST: + if (_use_lod) + add_Dynamic(pV->m_lod, xform); + else { - // General type of visual - r_dsgraph_insert_static(pVisual); + //pV->CalculateBones(TRUE); + if (i_mask[CDSGraphManager::fl_normal]) + pV->CalculateWallmarks(); + add_leafs_Dynamic(pV->children, xform); } - return; + }break; + default: - { - // General type of visual - r_dsgraph_insert_static(pVisual); - } - return; + { + // General type of visual + // Calculate distance to it's center + r_dsgraph_insert_dynamic(pVisual, xform); + }break; + } +} + +void CDSGraphManager::add_leafs_Dynamic(xr_vector& children, Fmatrix* xform) +{ + for (dxRender_Visual* pVisual : children) + { + add_Dynamic(pVisual, xform); + } +} + +void CDSGraphManager::add_leafs_Dynamic(xr_vector& children, Fmatrix* xform) +{ + for (IRenderVisual* pVisual : children) + { + add_Dynamic(pVisual, xform); } } //////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////// -BOOL CRender::add_Dynamic(dxRender_Visual* pVisual, u32 planes) +void CDSGraphManager::add_Static(IRenderVisual* piVisual, CFrustum& frustum, u32 planes) { - Flags16& flags = pVisual->dcast_RenderVisual()->flags; - - if (phase != PHASE_NORMAL && !!flags.test(IRenderVisualFlags::eNoShadow)) - return FALSE; + dxRender_Visual* pVisual = (dxRender_Visual*)piVisual; + if (!pVisual) return; - if (!!!flags.test(IRenderVisualFlags::eIgnoreOptimization) && !IsValuableToRender(pVisual, false, phase == 1, *val_pTransform)) - return FALSE; + Flags16& flags = piVisual->flags; + if (!i_mask[CDSGraphManager::fl_normal] && !!flags.test(IRenderVisualFlags::eNoShadow)) + return; // Check frustum visibility and calculate distance to visual's center - Fvector Tpos; // transformed position - EFC_Visible VIS; + vis_data& vis = pVisual->vis; + EFC_Visible VIS = frustum.testSAABB(vis.sphere.P, vis.sphere.R, vis.box.data(), planes); - val_pTransform->transform_tiny(Tpos, pVisual->vis.sphere.P); - VIS = View->testSphere(Tpos, pVisual->vis.sphere.R, planes); - if (fcvNone == VIS) return FALSE; + if (fcvNone == VIS) + return; - // If we get here visual is visible or partially visible - xr_vector::iterator I, E; // it may be usefull for 'hierrarhy' visuals +#if RENDER!=R_R1 + if (i_mask[CDSGraphManager::fl_normal])//phase normal +#endif + if (!RImplementation.HOM.visible(vis)) + return; + // If we get here visual is visible or partially visible switch (pVisual->Type) { - case MT_PARTICLE_GROUP: - { - // Add all children, doesn't perform any tests - PS::CParticleGroup* pG = (PS::CParticleGroup*)pVisual; - for (PS::CParticleGroup::SItemVecIt i_it = pG->items.begin(); i_it != pG->items.end(); i_it++) - { - PS::CParticleGroup::SItem& I = *i_it; - if (fcvPartial == VIS) - { - if (I._effect) add_Dynamic(I._effect, planes); - for (xr_vector::iterator pit = I._children_related.begin(); pit != I - . - _children_related - .end(); ++pit) - add_Dynamic(*pit, planes); - for (xr_vector::iterator pit = I._children_free.begin(); pit != I - ._children_free. - end(); ++pit) - add_Dynamic(*pit, planes); - } - else - { - if (I._effect) add_leafs_Dynamic(I._effect); - for (xr_vector::iterator pit = I._children_related.begin(); pit != I - . - _children_related - .end(); ++pit) - add_leafs_Dynamic(*pit); - for (xr_vector::iterator pit = I._children_free.begin(); pit != I - ._children_free. - end(); ++pit) - add_leafs_Dynamic(*pit); - } - } - } - break; case MT_HIERRARHY: + { + // Add all children + FHierrarhyVisual* pV = (FHierrarhyVisual*)pVisual; + if (fcvPartial == VIS) { - // Add all children - FHierrarhyVisual* pV = (FHierrarhyVisual*)pVisual; - I = pV->children.begin(); - E = pV->children.end(); - if (fcvPartial == VIS) - { - for (; I != E; ++I) add_Dynamic((dxRender_Visual*)*I, planes); - } - else - { - for (; I != E; ++I) add_leafs_Dynamic((dxRender_Visual*)*I); - } + for (auto V : pV->children) + add_Static(V, frustum, planes); } - break; - case MT_SKELETON_ANIM: - case MT_SKELETON_RIGID: + else + add_leafs_Static(pV->children); + }break; + + case MT_LOD: + { + FLOD* pV = (FLOD*)pVisual; + float D; + float ssa = CalcSSA(D, pV->vis.sphere.P, pV) * pV->lod_factor; + + if (ssa < r_ssaLOD_A) { - // Add all children, doesn't perform any tests - CKinematics* pV = (CKinematics*)pVisual; - BOOL _use_lod = FALSE; - if (pV->m_lod) - { - Fvector Tpos; - float D; - val_pTransform->transform_tiny(Tpos, pV->vis.sphere.P); - float ssa = CalcSSA(D, Tpos, pV->vis.sphere.R / 2.f); // assume dynamics never consume full sphere - if (ssa < r_ssaLOD_A) _use_lod = TRUE; - } - if (_use_lod) - { - add_leafs_Dynamic(pV->m_lod); - } - else - { - pV->CalculateBones(TRUE); - pV->CalculateWallmarks(); //. bug? - I = pV->children.begin(); - E = pV->children.end(); - for (; I != E; ++I) add_leafs_Dynamic((dxRender_Visual*)*I); - } - /* - I = pV->children.begin (); - E = pV->children.end (); - if (fcvPartial==VIS) { - for (; I!=E; I++) add_Dynamic (*I,planes); - } else { - for (; I!=E; I++) add_leafs_Dynamic (*I); - } - */ + if (ssa < r_ssaDISCARD) + return; + + RGraph.mapLOD.emplace_back(D, ssa, nullptr, pVisual, nullptr, nullptr, false); } - break; - default: + +#if RENDER!=R_R1 + if (ssa > r_ssaLOD_B || i_mask[CDSGraphManager::fl_shmap])//phase shmap +#else + if (ssa > r_ssaLOD_B) +#endif { - // General type of visual - r_dsgraph_insert_dynamic(pVisual, Tpos); + // Add all children, perform tests + add_leafs_Static(pV->children); } - break; + }break; + + case MT_TREE_ST: + case MT_TREE_PM: + default: + { + // General type of visual + r_dsgraph_insert_static(pVisual); + }return; } - return TRUE; } -void CRender::add_Static(dxRender_Visual* pVisual, u32 planes) +void CDSGraphManager::add_Static_MultiFrustum(IRenderVisual* piVisual, const xr_vector& frustums, const xr_vector& masks) { - Flags16& flags = pVisual->dcast_RenderVisual()->flags; + constexpr u32 FULLY_VISIBLE_MASK = u32(-1); - if (phase != PHASE_NORMAL && !!flags.test(IRenderVisualFlags::eNoShadow)) - return; + dxRender_Visual* pVisual = (dxRender_Visual*)piVisual; + if (!pVisual) return; - if (!!!flags.test(IRenderVisualFlags::eIgnoreOptimization) && !IsValuableToRender(pVisual, true, phase == 1, *val_pTransform)) + Flags16& flags = piVisual->flags; + if (!i_mask[CDSGraphManager::fl_normal] && !!flags.test(IRenderVisualFlags::eNoShadow)) return; - // Check frustum visibility and calculate distance to visual's center - EFC_Visible VIS; + // Check visibility against all active frustums and propagate per-frustum masks. vis_data& vis = pVisual->vis; - VIS = View->testSAABB(vis.sphere.P, vis.sphere.R, vis.box.data(), planes); - if (VIS == fcvNone) - return; + bool anyVisible = false; + bool hasFullyVisibleFrustum = false; + xr_vector childMasks; + childMasks.resize(masks.size(), 0); - if (!HOM.visible(vis)) - return; + for (u32 i = 0; i < masks.size(); ++i) + { + u32 planeMask = masks[i]; + if (!planeMask) + continue; - // If we get here visual is visible or partially visible - xr_vector::iterator I, E; // it may be usefull for 'hierrarhy' visuals + // Propagated from parent: this visual is fully visible in this frustum. + if (planeMask == FULLY_VISIBLE_MASK) + { + anyVisible = true; + hasFullyVisibleFrustum = true; + childMasks[i] = FULLY_VISIBLE_MASK; + continue; + } - switch (pVisual->Type) - { - case MT_PARTICLE_GROUP: + EFC_Visible VIS = frustums[i].testSAABB(vis.sphere.P, vis.sphere.R, vis.box.data(), planeMask); + if (VIS == fcvNone) { - // Add all children, doesn't perform any tests - PS::CParticleGroup* pG = (PS::CParticleGroup*)pVisual; - for (PS::CParticleGroup::SItem& I : pG->items) - { - if (fcvPartial == VIS) - { - if (I._effect) add_Dynamic(I._effect, planes); - - for (dxRender_Visual* childRelated : I._children_related) - { - add_Dynamic(childRelated, planes); - } - - for (dxRender_Visual* childFree : I._children_free) - { - add_Dynamic(childFree, planes); - } - } - else - { - if (I._effect) add_leafs_Dynamic(I._effect); - - for (dxRender_Visual* childRelated : I._children_related) - { - add_leafs_Dynamic(childRelated); - } - - for (dxRender_Visual* childFree : I._children_free) - { - add_leafs_Dynamic(childFree); - } - } - } + continue; } - break; - case MT_HIERRARHY: + + anyVisible = true; + if (VIS == fcvFully) { - // Add all children - FHierrarhyVisual* pV = (FHierrarhyVisual*)pVisual; - if (VIS == fcvPartial) - { - for (IRenderVisual* childRenderable : pV->children) - { - add_Static((dxRender_Visual*)childRenderable, planes); - } - } - else - { - for (IRenderVisual* childRenderable : pV->children) - { - add_leafs_Static((dxRender_Visual*)childRenderable); - } - } + // In original per-frustum traversal this path immediately adds leafs. + // Preserve union semantics by marking this frustum as fully visible. + hasFullyVisibleFrustum = true; + childMasks[i] = FULLY_VISIBLE_MASK; } - break; - case MT_SKELETON_ANIM: - case MT_SKELETON_RIGID: + else { - // Add all children, doesn't perform any tests - CKinematics* pV = (CKinematics*)pVisual; - pV->CalculateBones(TRUE); - if (VIS == fcvPartial) - { - for (IRenderVisual* childRenderable : pV->children) - { - add_Static((dxRender_Visual*)childRenderable, planes); - } - } - else - { - for (IRenderVisual* childRenderable : pV->children) - { - add_leafs_Static((dxRender_Visual*)childRenderable); - } - } + childMasks[i] = planeMask; } - break; + } + + if (!anyVisible) + return; + +#if RENDER!=R_R1 + if (i_mask[CDSGraphManager::fl_normal])//phase normal +#endif + if (!RImplementation.HOM.visible(vis)) + return; + + // If we get here visual is visible in at least one frustum + switch (pVisual->Type) + { + case MT_HIERRARHY: + { + FHierrarhyVisual* pV = (FHierrarhyVisual*)pVisual; + if (hasFullyVisibleFrustum) + add_leafs_Static(pV->children); + else + { + for (auto V : pV->children) + add_Static_MultiFrustum(V, frustums, childMasks); + } + }break; + case MT_LOD: + { + FLOD* pV = (FLOD*)pVisual; + float D; + float ssa = CalcSSA(D, pV->vis.sphere.P, pV) * pV->lod_factor; + + if (ssa < r_ssaLOD_A) { - FLOD* pV = (FLOD*)pVisual; - float D; - float ssa = CalcSSA(D, pV->vis.sphere.P, pV); - ssa *= pV->lod_factor; - if (ssa < r_ssaLOD_A) - { - if (ssa < r_ssaDISCARD) return; - mapLOD_Node* N = mapLOD.insertInAnyWay(D); - N->val.ssa = ssa; - N->val.pVisual = pVisual; - } + if (ssa < r_ssaDISCARD) + return; + + RGraph.mapLOD.emplace_back(D, ssa, nullptr, pVisual, nullptr, nullptr, false); + } + #if RENDER!=R_R1 - if (ssa > r_ssaLOD_B || phase == PHASE_SMAP) + if (ssa > r_ssaLOD_B || i_mask[CDSGraphManager::fl_shmap])//phase shmap #else - if (ssa > r_ssaLOD_B) + if (ssa > r_ssaLOD_B) #endif - { - // Add all children, perform tests - for (IRenderVisual* childRenderable : pV->children) - { - add_leafs_Static((dxRender_Visual*)childRenderable); - } - } + { + add_leafs_Static(pV->children); } - break; + }break; + case MT_TREE_ST: case MT_TREE_PM: + default: + { + r_dsgraph_insert_static(pVisual); + }return; + } +} + +void CDSGraphManager::add_leaf_Static(dxRender_Visual* pVisual) +{ +#if RENDER!=R_R1 + if (i_mask[CDSGraphManager::fl_normal])//phase normal +#endif + if (!RImplementation.HOM.visible(pVisual->vis)) + return; + + // Visual is 100% visible - simply add it + switch (pVisual->Type) + { + case MT_HIERRARHY: + { + FHierrarhyVisual* pV = (FHierrarhyVisual*)pVisual; + add_leafs_Static(pV->children); + }break; + + case MT_LOD: + { + FLOD* pV = (FLOD*)pVisual; + float D; + float ssa = CalcSSA(D, pV->vis.sphere.P, pV) * pV->lod_factor; + + if (ssa < r_ssaLOD_A) { - // General type of visual - r_dsgraph_insert_static(pVisual); + if (ssa < r_ssaDISCARD) + break; + + RGraph.mapLOD.emplace_back(D, ssa, nullptr, pVisual, nullptr, nullptr, false); } - return; - default: + +#if RENDER!=R_R1 + if (ssa > r_ssaLOD_B || i_mask[CDSGraphManager::fl_shmap])//phase shmap +#else + if (ssa > r_ssaLOD_B) +#endif { - // General type of visual - r_dsgraph_insert_static(pVisual); + // Add all children, doesn't perform any tests + add_leafs_Static(pV->children); } - break; + }break; + + case MT_TREE_PM: + case MT_TREE_ST: + default: + { + // General type of visual + r_dsgraph_insert_static(pVisual); + }break; + } +} + +void CDSGraphManager::add_leafs_Static(xr_vector& children) +{ + for (dxRender_Visual* pVisual : children) + { + add_leaf_Static(pVisual); + } +} + +void CDSGraphManager::add_leafs_Static(xr_vector& children) +{ + for (IRenderVisual* pVisual : children) + { + dxRender_Visual* pV = (dxRender_Visual*)pVisual; + if (!pV) continue; + add_leaf_Static(pV); } } diff --git a/src/Layers/xrRender/r__dsgraph_manager.cpp b/src/Layers/xrRender/r__dsgraph_manager.cpp new file mode 100644 index 0000000000..917a1b5e71 --- /dev/null +++ b/src/Layers/xrRender/r__dsgraph_manager.cpp @@ -0,0 +1,183 @@ +#include "stdafx.h" +#include "../../xrEngine/IGame_Persistent.h" +#include "../../xrEngine/Environment.h" +#include "FVF.h" +#include "../../xrEngine/xr_object.h" +#include "../../xrEngine/PS_instance.h" +#include "LightTrack.h" +#include "xrRender_console.h" +#include "../xrServerEntities/smart_cast.h" + +static PortalTraverseDebugStats g_portal_traverse_dbg_stats; +static u32 g_portal_traverse_dbg_last_frame = u32(-1); + +bool PortalTraverseDbg_Enabled() +{ + return !!ps_r__portal_traverse_stats; +} + +bool PortalTraverseDbg_IsOptions(u32 options) +{ + return !!(options & (CDSGraphManager::VQ_HOM | CDSGraphManager::VQ_SSA | CDSGraphManager::VQ_FADE)); +} + +PortalTraverseDebugStats& PortalTraverseDbg_Get() +{ + const u32 frame = Device.dwFrame; + if (g_portal_traverse_dbg_last_frame != frame) + { + g_portal_traverse_dbg_last_frame = frame; + g_portal_traverse_dbg_stats.reset(frame); + } + + return g_portal_traverse_dbg_stats; +} + +const PortalTraverseDebugStats& PortalTraverseDbg_Peek() +{ + return g_portal_traverse_dbg_stats; +} + +void CDSGraphManager::traverse(CSector* start, CFrustum& F, Fvector& vBase, Fmatrix& mXFORM) +{ + if (!start) return; + PROF_EVENT("CDSGraphManager::traverse") + + if (i_options & VQ_FADE) + { + xrCriticalSectionGuard guard(&P_CS); + f_portals.clear(); + } + + i_vBase = vBase; + i_frustum = F; + i_mXFORM = mXFORM; + i_start = start; + + xrSRWLockGuard guard(&S_LC,false); + if(m_sector_frustums.size()) + { + for (auto& pair : m_sector_frustums) + { + pair.val.first.clear(); + pair.val.second.clear(); + } + } + // Keep sector-frustum map frame-local: stale sector keys from previous + // frames create empty-frustum entries and skew static capture decisions. + m_sector_frustums.clear(); + m_static_seen.clear(); + i_start->traverse(std::move(F),*this); +} + +void CDSGraphManager::set_Object(IRenderable* O) +{ + val_pObject = O; // nullptr is OK, trust me :) +#if RENDER==R_R1 + if (val_pObject) + { + VERIFY(smart_cast(O) || smart_cast(O)); + if (O->renderable.pROS) { VERIFY(smart_cast(O->renderable.pROS)); } + } + if (CRender::PHASE_NORMAL == RImplementation.phase) + { + if (RImplementation.L_Shadows) + RImplementation.L_Shadows->set_object(O, *this); + + if (RImplementation.L_Projector) + RImplementation.L_Projector->set_object(O, *this); + } + else + { + if (RImplementation.L_Shadows) + RImplementation.L_Shadows->set_object(0, *this); + + if (RImplementation.L_Projector) + RImplementation.L_Projector->set_object(0, *this); + } +#endif // RENDER==R_R1 +} + +void CDSGraphManager::fade_portal (CPortal* _p, float ssa) +{ + if(RImplementation.HOM.visible(_p->S)) + { + xrCriticalSectionGuard guard(&P_CS); + f_portals.insert(_p, ssa); + } +} +void CDSGraphManager::initialize () +{ + f_shader.create ("portal"); + f_geom.create (FVF::F_L, RCache.Vertex.Buffer(), 0); +} +void CDSGraphManager::destroy () +{ + f_geom.destroy (); + f_shader.destroy (); +} +extern float r_ssaDISCARD ; +extern float r_ssaLOD_A, r_ssaLOD_B ; +void CDSGraphManager::fade_render () +{ + xrCriticalSectionGuard guard(&P_CS); + if (!f_portals.size()) return; + + // re-sort, back to front + if(!psDeviceFlags.test(rsDrawPortals)) + { + std::sort(f_portals.begin(), f_portals.end(), + [&](const auto& _1, const auto& _2) + { + float d1 = i_vBase.distance_to_sqr(_1.key->S.P); + float d2 = i_vBase.distance_to_sqr(_2.key->S.P); + return d2 > d1; // descending, back to front + }); + } + + // calc poly-count + u32 _pcount = 0; + for (auto& fp : f_portals) _pcount += fp.key->getPoly().size()-2; + + // fill buffers + u32 _offset = 0; + FVF::L* _v = (FVF::L*)RCache.Vertex.Lock(_pcount*3,f_geom.stride(),_offset); + float ssaRange = r_ssaLOD_A - r_ssaLOD_B; + Fvector _ambient_f = g_pGamePersistent->Environment().CurrentEnv->ambient; + u32 _ambient = psDeviceFlags.test(rsDrawPortals) ? u32(-1) : color_rgba_f(_ambient_f.x,_ambient_f.y,_ambient_f.z,0.f); + for (auto& fp : f_portals) + { + CPortal* _P = fp.key; + u32 _clr=u32(-1); + if(psDeviceFlags.test(rsDrawPortals)) + _clr = color_rgba(0,255,100,255); + else + { + float _ssa = fp.val; + float ssaDiff = _ssa-r_ssaLOD_B ; + float ssaScale = ssaDiff/ssaRange ; + int iA = iFloor((1-ssaScale)*255.5f); clamp(iA,0,255); + _clr = subst_alpha(_ambient,u32(iA)); + } + + // fill polys + u32 _polys = _P->getPoly().size()-2; + for (u32 _pit=0; _pit<_polys; _pit++) { + _v->set (_P->getPoly()[0], _clr); _v++; + _v->set (_P->getPoly()[_pit+1],_clr); _v++; + _v->set (_P->getPoly()[_pit+2],_clr); _v++; + } + } + RCache.Vertex.Unlock (_pcount*3,f_geom.stride()); + + // render + RCache.set_xform_world (Fidentity); + RCache.set_Shader (f_shader); + RCache.set_Geometry (f_geom); + RCache.set_CullMode (CULL_NONE); + RCache.Render (D3DPT_TRIANGLELIST,_offset,_pcount); + RCache.set_CullMode (CULL_CCW); + + // cleanup + f_portals.clear (); +} diff --git a/src/Layers/xrRender/r__dsgraph_manager.h b/src/Layers/xrRender/r__dsgraph_manager.h new file mode 100644 index 0000000000..ec358b80d7 --- /dev/null +++ b/src/Layers/xrRender/r__dsgraph_manager.h @@ -0,0 +1,218 @@ +#if !defined(_DSGMANAGE_H_) +#define _DSGMANAGE_H_ +#pragma once +#include "r__dsgraph_types.h" +#include "r__sector.h" +#include "../../xrCore/FixedMap.h" +class CDSGraphManager : public IDSGraphManager +{ +public: + enum + { + VQ_HOM = (1 << 0), + VQ_SSA = (1 << 1), + VQ_FADE = (1 << 2), // requires SSA to work + }; + + R_dsgraph::DynamicSceneRgraph RGraph; + u32 i_options; // input: culling options + u32 i_doptions; + Fvector i_vBase; // input: "view" point + CFrustum i_frustum; // input: "view" frustum + Fmatrix i_mXFORM; // input: 4x4 xform + CSector* i_start; // input: starting point + xrCriticalSection P_CS; + xrSRWLock S_LC; + + FixedMAP, FixedSet>> m_sector_frustums; + xr_unordered_flat_set m_static_seen; + xr_vector lstRenderables, lstLights; + FixedMAP f_portals; + sPoly S, D; + ref_shader f_shader; + ref_geom f_geom; + + CDSGraphManager(u32 options, u32 doptions, bool(&& mask)[7]) : i_options(options), i_doptions(doptions) + { + std::copy(mask, mask + 7, i_mask); + } + void initialize(); + void destroy(); + void traverse(CSector* start, CFrustum& F, Fvector& vBase, Fmatrix& mXFORM); + IC bool is_sector_visible(CSector* sector) + { + if (sector == i_start) return true; + + { + xrSRWLockGuard guard(&S_LC, true); + if(m_sector_frustums.size()) + { + if (auto node = m_sector_frustums.find(sector)) + return !node->val.first.empty(); + } + } + + return false; + }; + CDSGraphManager& get_traverser_safed() { xrSRWLockGuard guard(&S_LC, false); return *this; }; + void fade_portal(CPortal* _p, float ssa); + void fade_render(); + + virtual void set_Object(IRenderable* O = nullptr); + + virtual void add_Static(IRenderVisual* pVisual, CFrustum& frustum, u32 planes); + virtual void add_Static_MultiFrustum(IRenderVisual* pVisual, const xr_vector& frustums, const xr_vector& masks); + void add_leaf_Static(dxRender_Visual* pVisual); + void add_leafs_Static(xr_vector& children); + void add_leafs_Static(xr_vector& children); + void r_dsgraph_insert_static(dxRender_Visual* pVisual); + + virtual void add_Dynamic(IRenderVisual* piVisual, Fmatrix* xform); + void add_Dynamic(dxRender_Visual* pVisual, Fmatrix* xform); + void add_leafs_Dynamic(xr_vector& children, Fmatrix* xform); + void add_leafs_Dynamic(xr_vector& children, Fmatrix* xform); + void r_dsgraph_insert_dynamic(dxRender_Visual* pVisual, Fmatrix* xform); + + void AddToRenderQueue(R_dsgraph::RenderQueue& queue, const R_dsgraph::DSGraphItem& item, const SPass& pass); + void r_dsgraph_render_graph(R_dsgraph::RenderQueueArray& queue, u32 _priority, bool _clear = true, bool static_geometry = true); + IC void r_dsgraph_render_graph(u32 _priority, bool _clear = true) + { + r_dsgraph_render_static(_priority, _clear); + r_dsgraph_render_dynamic(_priority, _clear); + } + IC void r_dsgraph_render_static(u32 _priority, bool _clear = true) + { + PROF_EVENT("r_dsgraph_render_static"); + r_dsgraph_render_graph(RGraph.mapStaticPasses, _priority, _clear); + }; + IC void r_dsgraph_render_dynamic(u32 _priority, bool _clear = true) + { + PROF_EVENT("r_dsgraph_render_dynamic"); + r_dsgraph_render_graph(RGraph.mapDynamicPasses, _priority, _clear, false); + }; + + template + void r_dsgraph_render_graph_sorted(R_dsgraph::mapDSGraphItems& graph, bool _clear = true); + void r_dsgraph_capture_hud(); + void r_dsgraph_render_hud(); + void r_dsgraph_render_hud_ui(); + void r_dsgraph_render_lods(bool _setup_zb, bool _clear); + void r_dsgraph_render_sorted(bool render_hud = true); + void r_dsgraph_render_sorted_hud(); + void r_dsgraph_render_emissive(bool clear = true, bool renderHUD = false); + void r_dsgraph_render_wmarks(); + void r_dsgraph_render_distort(); + + // Anomaly +#if defined(USE_DX11) + void r_dsgraph_render_ScopeSorted(); +#endif + void r_dsgraph_render_cam_ui(); + void r_dsgraph_render_water_ssr(); + void r_dsgraph_render_water(); + + void r_dsgraph_capture(bool lights = false, bool dynamic = false, CObject* O = nullptr); + void r_dsgraph_capture_lights(); + void r_dsgraph_capture_static(); + void r_dsgraph_capture_dynamic(CObject* O = nullptr); + + void clear() + { + xrSRWLockGuard guard(&S_LC, false); + RGraph.clear(); + if (m_sector_frustums.size()) + { + for (auto& pair : m_sector_frustums) + { + pair.val.first.clear(); + pair.val.second.clear(); + } + m_sector_frustums.clear(); + } + lstRenderables.clear(); + lstLights.clear(); + f_portals.clear(); + m_static_seen.clear(); + } +}; + +struct PortalTraverseDebugStats +{ + u32 frame_id = 0; + + u32 traverse_calls = 0; + u32 traverse_calls_with_options = 0; + u32 traverse_calls_without_options = 0; + u32 frustums_pushed = 0; + u32 max_frustums_in_sector = 0; + u32 frustums_pushed_opt = 0; + u32 frustums_pushed_noopt = 0; + u32 max_frustums_in_sector_opt = 0; + u32 max_frustums_in_sector_noopt = 0; + + u32 portals_checked = 0; + u32 portals_checked_opt = 0; + u32 portals_checked_noopt = 0; + u32 portals_skipped_already_visited = 0; + u32 portals_rejected_sphere = 0; + u32 portals_rejected_sector = 0; + u32 portals_rejected_ssa = 0; + u32 portals_rejected_clip = 0; + u32 portals_rejected_hom = 0; + u32 portals_recursed = 0; + u32 portals_recursed_opt = 0; + u32 portals_recursed_noopt = 0; + + u32 portals_debug_branch_taken = 0; + u32 portals_debug_branch_precedence_hits = 0; + + u32 static_sector_nodes = 0; + u32 static_frustum_nodes = 0; + u32 static_add_root_calls = 0; + u32 static_sector_nodes_opt = 0; + u32 static_sector_nodes_noopt = 0; + u32 static_frustum_nodes_opt = 0; + u32 static_frustum_nodes_noopt = 0; + u32 static_add_root_calls_opt = 0; + u32 static_add_root_calls_noopt = 0; + + u32 dynamic_spatials = 0; + u32 dynamic_frustum_tests = 0; + u32 dynamic_frustum_hits = 0; + u32 dynamic_rendered = 0; + u32 dynamic_spatials_opt = 0; + u32 dynamic_spatials_noopt = 0; + u32 dynamic_frustum_tests_opt = 0; + u32 dynamic_frustum_tests_noopt = 0; + u32 dynamic_frustum_hits_opt = 0; + u32 dynamic_frustum_hits_noopt = 0; + u32 dynamic_rendered_opt = 0; + u32 dynamic_rendered_noopt = 0; + + u32 queue_static_packets = 0; + u32 queue_dynamic_packets = 0; + u32 queue_static_packets_opt = 0; + u32 queue_static_packets_noopt = 0; + u32 queue_dynamic_packets_opt = 0; + u32 queue_dynamic_packets_noopt = 0; + + u32 static_dedup_seen = 0; + u32 static_dedup_skipped = 0; + u32 static_dedup_seen_opt = 0; + u32 static_dedup_seen_noopt = 0; + u32 static_dedup_skipped_opt = 0; + u32 static_dedup_skipped_noopt = 0; + + void reset(u32 frame) + { + *this = {}; + frame_id = frame; + } +}; + +bool PortalTraverseDbg_Enabled(); +bool PortalTraverseDbg_IsOptions(u32 options); +PortalTraverseDebugStats& PortalTraverseDbg_Get(); +const PortalTraverseDebugStats& PortalTraverseDbg_Peek(); + +#endif // !defined(AFX_PORTAL_H__1FC2D371_4A19_49EA_BD1E_2D0F8DEBBF15__INCLUDED_) diff --git a/src/Layers/xrRender/r__dsgraph_render.cpp b/src/Layers/xrRender/r__dsgraph_render.cpp index 2050e8fc73..eb2664b506 100644 --- a/src/Layers/xrRender/r__dsgraph_render.cpp +++ b/src/Layers/xrRender/r__dsgraph_render.cpp @@ -7,6 +7,14 @@ #include "../../xrEngine/CustomHUD.h" #include "FBasicVisual.h" +#include "CHudInitializer.h" + +#include "fhierrarhyvisual.h" +#include "SkeletonCustom.h" +#include "../../xrEngine/fmesh.h" +#include "flod.h" + +#include "../../xrEngine/xr_object.h" using namespace R_dsgraph; @@ -20,1052 +28,705 @@ ICF float calcLOD(float ssa/*fDistSq*/, float R) return _sqrt(clampr((ssa - r_ssaGLOD_end) / (r_ssaGLOD_start - r_ssaGLOD_end), 0.f, 1.f)); } -// NORMAL -IC bool cmp_normal_items(const _NormalItem& N1, const _NormalItem& N2) +template +void CDSGraphManager::r_dsgraph_render_graph_sorted(R_dsgraph::mapDSGraphItems& graph, bool _clear) { - return (N1.ssa > N2.ssa); -} + if (graph.empty()) + return; -void __fastcall mapNormal_Render(mapNormalItems& N) -{ - // *** DIRECT *** - std::sort(N.begin(), N.end(), cmp_normal_items); - _NormalItem *I = &*N.begin(), *E = &*N.end(); - for (; I != E; I++) - { - _NormalItem& Ni = *I; - float LOD = calcLOD(Ni.ssa, Ni.pVisual->vis.sphere.R); -#ifdef USE_DX11 - RCache.LOD.set_LOD(LOD); -#endif - Ni.pVisual->Render(LOD); - } -} - -// Matrix -IC bool cmp_matrix_items(const _MatrixItem& N1, const _MatrixItem& N2) -{ - return (N1.ssa > N2.ssa); -} + std::sort(graph.begin(), graph.end()); -void __fastcall mapMatrix_Render(mapMatrixItems& N) -{ - // *** DIRECT *** - std::sort(N.begin(), N.end(), cmp_matrix_items); - _MatrixItem *I = &*N.begin(), *E = &*N.end(); - for (; I != E; I++) + for (auto& item : graph) { - _MatrixItem& Ni = *I; - RCache.set_xform_world(Ni.Matrix); - RImplementation.apply_object(Ni.pObject); + dxRender_Visual* V = item.pVisual; + VERIFY(V && V->shader._get()); + RCache.set_Element(item.pSE); + RCache.set_xform_world(*item.pMatrix); + RImplementation.apply_object(item.pObject); RImplementation.apply_lmaterial(); - - float LOD = calcLOD(Ni.ssa, Ni.pVisual->vis.sphere.R); -#ifdef USE_DX11 - RCache.LOD.set_LOD(LOD); -#endif - Ni.pVisual->Render(LOD); + //if (item.b_hud_mode) + //{ + // //new feature + //} + V->Render(calcLOD(item.ssa, V->vis.sphere.R)); } - N.clear(); -} -// ALPHA -void __fastcall sorted_L1(mapSorted_Node* N) -{ - VERIFY(N); - dxRender_Visual* V = N->val.pVisual; - VERIFY(V && V->shader._get()); - RCache.set_Element(N->val.se); - RCache.set_xform_world(N->val.Matrix); - RImplementation.apply_object(N->val.pObject); - RImplementation.apply_lmaterial(); - V->Render(calcLOD(N->key, V->vis.sphere.R)); -} - -void __fastcall water_node_ssr(mapSorted_Node* N) -{ -#ifdef USE_DX11 - VERIFY(N); - dxRender_Visual* V = N->val.pVisual; - VERIFY(V); - - RCache.set_Shader(RImplementation.Target->s_ssfx_water_ssr); - - RCache.set_xform_world(N->val.Matrix); - RImplementation.apply_object(N->val.pObject); - RImplementation.apply_lmaterial(); - - RCache.set_c("cam_pos", RImplementation.Target->Position_previous.x, RImplementation.Target->Position_previous.y, RImplementation.Target->Position_previous.z, 0.0f); - - // Previous matrix data - RCache.set_c("m_current", RImplementation.Target->Matrix_current); - RCache.set_c("m_previous", RImplementation.Target->Matrix_previous); + if (_clear) + graph.clear(); - V->Render(calcLOD(N->key, V->vis.sphere.R)); -#endif + RCache.set_xform_world(Fidentity); } -void __fastcall water_node(mapSorted_Node* N) +void CDSGraphManager::r_dsgraph_render_graph(RenderQueueArray& queues, u32 _priority, bool _clear, bool static_geometry) { - VERIFY(N); - dxRender_Visual* V = N->val.pVisual; - VERIFY(V); + RCache.set_xform_world(Fidentity); -#ifdef USE_DX11 - if (RImplementation.o.ssfx_water) + for (u32 iPass = 0; iPass < SHADER_PASSES_MAX; ++iPass) { - RCache.set_Shader(RImplementation.Target->s_ssfx_water); - } -#endif - - RCache.set_xform_world(N->val.Matrix); - RImplementation.apply_object(N->val.pObject); - RImplementation.apply_lmaterial(); - - // Wind settings - float WindDir = g_pGamePersistent->Environment().CurrentEnv->wind_direction; - float WindVel = g_pGamePersistent->Environment().CurrentEnv->wind_velocity; - RCache.set_c("wind_setup", WindDir, WindVel, 0, 0); - - V->Render(calcLOD(N->key, V->vis.sphere.R)); -} - -/*void __fastcall hud_node(mapSorted_Node* N) -{ - VERIFY(N); - dxRender_Visual* V = N->val.pVisual; - VERIFY(V && V->shader._get()); - RCache.set_xform_world(N->val.Matrix); - -#ifdef USE_DX11 - - if (N->val.se->passes[0]->ps->hud_disabled) - return; - - int skinning = N->val.se->passes[0]->vs->skinning; - RCache.set_Shader(RImplementation.Target->s_ssfx_hud[skinning]); + auto& queue = queues[_priority][iPass]; + if (queue.empty()) + continue; - RImplementation.Target->Matrix_HUD_previous.set(N->val.PrevMatrix); - N->val.PrevMatrix.set(RCache.xforms.m_wvp); + // 1. Sort by generated sort key to replicate previous fixed map behaviour + if (queue.size() < 4096) + std::sort(queue.begin(), queue.end()); + else + xr_parallel_sort(queue.begin(), queue.end()); - RImplementation.Target->RVelocity = true; + // 2. Render + vs_type pVS = nullptr; +#if defined(USE_DX10) || defined(USE_DX11) + gs_type pGS = nullptr; #endif - V->Render(calcLOD(N->key, V->vis.sphere.R)); + ps_type pPS = nullptr; #ifdef USE_DX11 - RImplementation.Target->RVelocity = false; + hs_type pHS = nullptr; + ds_type pDS = nullptr; #endif -}*/ + + R_constant_table* pCS = nullptr; + ID3DState* pState = nullptr; + STextureList* pTextures = nullptr; -IC bool cmp_vs_nrm(mapNormalVS::TNode* N1, mapNormalVS::TNode* N2) -{ - return (N1->val.ssa > N2->val.ssa); -} + u64 high = 0; -IC bool cmp_vs_mat(mapMatrixVS::TNode* N1, mapMatrixVS::TNode* N2) -{ - return (N1->val.ssa > N2->val.ssa); -} + for (auto& packet : queue) + { + auto& currentKey = packet.sortKey; + if (currentKey.high != high) + { + high = currentKey.high; -IC bool cmp_ps_nrm(mapNormalPS::TNode* N1, mapNormalPS::TNode* N2) -{ -#ifdef USE_DX11 - return (N1->val.mapCS.ssa > N2->val.mapCS.ssa); -#else - return (N1->val.ssa > N2->val.ssa); + if (packet.pState != pState) + { + pState = packet.pState; + RCache.set_States(pState); + } + +#if defined(USE_DX10) || defined(USE_DX11) + if (packet.pGS != pGS) + { + pGS = packet.pGS; + RCache.set_GS(pGS); + } #endif -} -IC bool cmp_ps_mat(mapMatrixPS::TNode* N1, mapMatrixPS::TNode* N2) -{ #ifdef USE_DX11 - return (N1->val.mapCS.ssa > N2->val.mapCS.ssa); -#else - return (N1->val.ssa > N2->val.ssa); + if (packet.pHS != pHS) + { + pHS = packet.pHS; + RCache.set_HS(pHS); + } + if (packet.pDS != pDS) + { + pDS = packet.pDS; + RCache.set_DS(pDS); + } #endif -} - -#if defined(USE_DX10) || defined(USE_DX11) -IC bool cmp_gs_nrm(mapNormalGS::TNode* N1, mapNormalGS::TNode* N2) { return (N1->val.ssa > N2->val.ssa); } -IC bool cmp_gs_mat(mapMatrixGS::TNode* N1, mapMatrixGS::TNode* N2) { return (N1->val.ssa > N2->val.ssa); } -#endif // USE_DX10 - -IC bool cmp_cs_nrm(mapNormalCS::TNode* N1, mapNormalCS::TNode* N2) { return (N1->val.ssa > N2->val.ssa); } -IC bool cmp_cs_mat(mapMatrixCS::TNode* N1, mapMatrixCS::TNode* N2) { return (N1->val.ssa > N2->val.ssa); } - -IC bool cmp_states_nrm(mapNormalStates::TNode* N1, mapNormalStates::TNode* N2) { return (N1->val.ssa > N2->val.ssa); } -IC bool cmp_states_mat(mapMatrixStates::TNode* N1, mapMatrixStates::TNode* N2) { return (N1->val.ssa > N2->val.ssa); } - -IC bool cmp_textures_lex2_nrm(mapNormalTextures::TNode* N1, mapNormalTextures::TNode* N2) -{ - STextureList* t1 = N1->key; - STextureList* t2 = N2->key; - if ((*t1)[0] < (*t2)[0]) return true; - if ((*t1)[0] > (*t2)[0]) return false; - if ((*t1)[1] < (*t2)[1]) return true; - else return false; -} - -IC bool cmp_textures_lex2_mat(mapMatrixTextures::TNode* N1, mapMatrixTextures::TNode* N2) -{ - STextureList* t1 = N1->key; - STextureList* t2 = N2->key; - if ((*t1)[0] < (*t2)[0]) return true; - if ((*t1)[0] > (*t2)[0]) return false; - if ((*t1)[1] < (*t2)[1]) return true; - else return false; -} - -IC bool cmp_textures_lex3_nrm(mapNormalTextures::TNode* N1, mapNormalTextures::TNode* N2) -{ - STextureList* t1 = N1->key; - STextureList* t2 = N2->key; - if ((*t1)[0] < (*t2)[0]) return true; - if ((*t1)[0] > (*t2)[0]) return false; - if ((*t1)[1] < (*t2)[1]) return true; - if ((*t1)[1] > (*t2)[1]) return false; - if ((*t1)[2] < (*t2)[2]) return true; - else return false; -} - -IC bool cmp_textures_lex3_mat(mapMatrixTextures::TNode* N1, mapMatrixTextures::TNode* N2) -{ - STextureList* t1 = N1->key; - STextureList* t2 = N2->key; - if ((*t1)[0] < (*t2)[0]) return true; - if ((*t1)[0] > (*t2)[0]) return false; - if ((*t1)[1] < (*t2)[1]) return true; - if ((*t1)[1] > (*t2)[1]) return false; - if ((*t1)[2] < (*t2)[2]) return true; - else return false; -} - -IC bool cmp_textures_lexN_nrm(mapNormalTextures::TNode* N1, mapNormalTextures::TNode* N2) -{ - STextureList* t1 = N1->key; - STextureList* t2 = N2->key; - return std::lexicographical_compare(t1->begin(), t1->end(), t2->begin(), t2->end()); -} - -IC bool cmp_textures_lexN_mat(mapMatrixTextures::TNode* N1, mapMatrixTextures::TNode* N2) -{ - STextureList* t1 = N1->key; - STextureList* t2 = N2->key; - return std::lexicographical_compare(t1->begin(), t1->end(), t2->begin(), t2->end()); -} - -IC bool cmp_textures_ssa_nrm(mapNormalTextures::TNode* N1, mapNormalTextures::TNode* N2) -{ - return (N1->val.ssa > N2->val.ssa); -} - -IC bool cmp_textures_ssa_mat(mapMatrixTextures::TNode* N1, mapMatrixTextures::TNode* N2) -{ - return (N1->val.ssa > N2->val.ssa); -} - -void sort_tlist_nrm -( - xr_vector>& lst, - xr_vector>& temp, - mapNormalTextures& textures, - BOOL bSSA -) -{ - int amount = textures.begin()->key->size(); - if (bSSA) - { - if (amount <= 1) - { - // Just sort by SSA - textures.getANY_P(lst); - std::sort(lst.begin(), lst.end(), cmp_textures_ssa_nrm); - } - else - { - // Split into 2 parts - mapNormalTextures::TNode* _it = textures.begin(); - mapNormalTextures::TNode* _end = textures.end(); - for (; _it != _end; _it++) + } + + // Compare low key stuff regardless, too high collision probability + if (packet.pVS != pVS) + { + pVS = packet.pVS; + RCache.set_VS(pVS); + } + + if (packet.pPS != pPS) + { + pPS = packet.pPS; + RCache.set_PS(pPS); + } + + if (packet.pCS != pCS) + { + pCS = packet.pCS; + RCache.set_Constants(pCS); + } + + if (packet.pTextures != pTextures) + { + pTextures = packet.pTextures; + RCache.set_Textures(pTextures); + RImplementation.apply_lmaterial(); + } + + auto& item = packet.item; + if (!static_geometry) { - if (_it->val.ssa > r_ssaHZBvsTEX) lst.push_back(_it); - else temp.push_back(_it); + RCache.set_xform_world(*item.pMatrix); + RImplementation.apply_object(item.pObject); + RImplementation.apply_lmaterial(); } - // 1st - part - SSA, 2nd - lexicographically - std::sort(lst.begin(), lst.end(), cmp_textures_ssa_nrm); - if (2 == amount) std::sort(temp.begin(), temp.end(), cmp_textures_lex2_nrm); - else if (3 == amount) std::sort(temp.begin(), temp.end(), cmp_textures_lex3_nrm); - else std::sort(temp.begin(), temp.end(), cmp_textures_lexN_nrm); - - // merge lists - lst.insert(lst.end(), temp.begin(), temp.end()); - } - } - else - { - textures.getANY_P(lst); - if (2 == amount) std::sort(lst.begin(), lst.end(), cmp_textures_lex2_nrm); - else if (3 == amount) std::sort(lst.begin(), lst.end(), cmp_textures_lex3_nrm); - else std::sort(lst.begin(), lst.end(), cmp_textures_lexN_nrm); - } -} - -void sort_tlist_mat -( - xr_vector>& lst, - xr_vector>& temp, - mapMatrixTextures& textures, - BOOL bSSA -) -{ - int amount = textures.begin()->key->size(); - if (bSSA) - { - if (amount <= 1) - { - // Just sort by SSA - textures.getANY_P(lst); - std::sort(lst.begin(), lst.end(), cmp_textures_ssa_mat); - } - else - { - // Split into 2 parts - mapMatrixTextures::TNode* _it = textures.begin(); - mapMatrixTextures::TNode* _end = textures.end(); - for (; _it != _end; _it++) - { - if (_it->val.ssa > r_ssaHZBvsTEX) lst.push_back(_it); - else temp.push_back(_it); - } - - // 1st - part - SSA, 2nd - lexicographically - std::sort(lst.begin(), lst.end(), cmp_textures_ssa_mat); - if (2 == amount) std::sort(temp.begin(), temp.end(), cmp_textures_lex2_mat); - else if (3 == amount) std::sort(temp.begin(), temp.end(), cmp_textures_lex3_mat); - else std::sort(temp.begin(), temp.end(), cmp_textures_lexN_mat); - - // merge lists - lst.insert(lst.end(), temp.begin(), temp.end()); - } - } - else - { - textures.getANY_P(lst); - if (2 == amount) std::sort(lst.begin(), lst.end(), cmp_textures_lex2_mat); - else if (3 == amount) std::sort(lst.begin(), lst.end(), cmp_textures_lex3_mat); - else std::sort(lst.begin(), lst.end(), cmp_textures_lexN_mat); - } -} - -void R_dsgraph_structure::r_dsgraph_render_graph(u32 _priority, bool _clear) -{ - //PIX_EVENT(r_dsgraph_render_graph); - Device.Statistic->RenderDUMP.Begin(); - - // **************************************************** NORMAL - // Perform sorting based on ScreenSpaceArea - // Sorting by SSA and changes minimizations - { - RCache.set_xform_world(Fidentity); - - // Render several passes - for (u32 iPass = 0; iPass < SHADER_PASSES_MAX; ++iPass) - { - //mapNormalVS& vs = mapNormal [_priority]; - mapNormalVS& vs = mapNormalPasses[_priority][iPass]; - vs.getANY_P(nrmVS); - std::sort(nrmVS.begin(), nrmVS.end(), cmp_vs_nrm); - for (u32 vs_id = 0; vs_id < nrmVS.size(); vs_id++) - { - mapNormalVS::TNode* Nvs = nrmVS[vs_id]; - RCache.set_VS(Nvs->key); - -#if defined(USE_DX10) || defined(USE_DX11) - // GS setup - mapNormalGS& gs = Nvs->val; - gs.ssa = 0; - - gs.getANY_P(nrmGS); - std::sort(nrmGS.begin(), nrmGS.end(), cmp_gs_nrm); - for (u32 gs_id = 0; gs_id < nrmGS.size(); gs_id++) - { - mapNormalGS::TNode* Ngs = nrmGS[gs_id]; - RCache.set_GS(Ngs->key); - - mapNormalPS& ps = Ngs->val; - ps.ssa = 0; -#else // USE_DX10 - mapNormalPS& ps = Nvs->val; - ps.ssa = 0; -#endif // USE_DX10 - - ps.getANY_P(nrmPS); - std::sort(nrmPS.begin(), nrmPS.end(), cmp_ps_nrm); - for (u32 ps_id = 0; ps_id < nrmPS.size(); ps_id++) - { - mapNormalPS::TNode* Nps = nrmPS[ps_id]; - RCache.set_PS(Nps->key); + float LOD = calcLOD(item.ssa, item.pVisual->vis.sphere.R); #ifdef USE_DX11 - mapNormalCS& cs = Nps->val.mapCS; - cs.ssa = 0; - RCache.set_HS(Nps->val.hs); - RCache.set_DS(Nps->val.ds); -#else - mapNormalCS& cs = Nps->val; - cs.ssa = 0; + RCache.LOD.set_LOD(LOD); #endif - cs.getANY_P(nrmCS); - std::sort(nrmCS.begin(), nrmCS.end(), cmp_cs_nrm); - for (u32 cs_id = 0; cs_id < nrmCS.size(); cs_id++) - { - mapNormalCS::TNode* Ncs = nrmCS[cs_id]; - RCache.set_Constants(Ncs->key); - - mapNormalStates& states = Ncs->val; - states.ssa = 0; - states.getANY_P(nrmStates); - std::sort(nrmStates.begin(), nrmStates.end(), cmp_states_nrm); - for (u32 state_id = 0; state_id < nrmStates.size(); state_id++) - { - mapNormalStates::TNode* Nstate = nrmStates[state_id]; - RCache.set_States(Nstate->key); - - mapNormalTextures& tex = Nstate->val; - tex.ssa = 0; - sort_tlist_nrm(nrmTextures, nrmTexturesTemp, tex, true); - for (u32 tex_id = 0; tex_id < nrmTextures.size(); tex_id++) - { - mapNormalTextures::TNode* Ntex = nrmTextures[tex_id]; - RCache.set_Textures(Ntex->key); - RImplementation.apply_lmaterial(); - - mapNormalItems& items = Ntex->val; - items.ssa = 0; - mapNormal_Render(items); - if (_clear) items.clear(); - } - nrmTextures.clear(); - nrmTexturesTemp.clear(); - if (_clear) tex.clear(); - } - nrmStates.clear(); - if (_clear) states.clear(); - } - nrmCS.clear(); - if (_clear) cs.clear(); - } - nrmPS.clear(); - if (_clear) ps.clear(); -#if defined(USE_DX10) || defined(USE_DX11) - } - nrmGS.clear(); - if (_clear) gs.clear(); -#endif // USE_DX10 - } - nrmVS.clear(); - if (_clear) vs.clear(); + item.pVisual->Render(LOD); } - } - - // **************************************************** MATRIX - // Perform sorting based on ScreenSpaceArea - // Sorting by SSA and changes minimizations - // Render several passes - for (u32 iPass = 0; iPass < SHADER_PASSES_MAX; ++iPass) - { - //mapMatrixVS& vs = mapMatrix [_priority]; - mapMatrixVS& vs = mapMatrixPasses[_priority][iPass]; - vs.getANY_P(matVS); - std::sort(matVS.begin(), matVS.end(), cmp_vs_mat); - for (u32 vs_id = 0; vs_id < matVS.size(); vs_id++) - { - mapMatrixVS::TNode* Nvs = matVS[vs_id]; - RCache.set_VS(Nvs->key); - -#if defined(USE_DX10) || defined(USE_DX11) - mapMatrixGS& gs = Nvs->val; - gs.ssa = 0; - - gs.getANY_P(matGS); - std::sort(matGS.begin(), matGS.end(), cmp_gs_mat); - for (u32 gs_id = 0; gs_id < matGS.size(); gs_id++) - { - mapMatrixGS::TNode* Ngs = matGS[gs_id]; - RCache.set_GS(Ngs->key); - - mapMatrixPS& ps = Ngs->val; - ps.ssa = 0; -#else // USE_DX10 - mapMatrixPS& ps = Nvs->val; - ps.ssa = 0; -#endif // USE_DX10 - - ps.getANY_P(matPS); - std::sort(matPS.begin(), matPS.end(), cmp_ps_mat); - for (u32 ps_id = 0; ps_id < matPS.size(); ps_id++) - { - mapMatrixPS::TNode* Nps = matPS[ps_id]; - RCache.set_PS(Nps->key); - -#ifdef USE_DX11 - mapMatrixCS& cs = Nps->val.mapCS; - cs.ssa = 0; - RCache.set_HS(Nps->val.hs); - RCache.set_DS(Nps->val.ds); -#else - mapMatrixCS& cs = Nps->val; - cs.ssa = 0; -#endif - cs.getANY_P(matCS); - std::sort(matCS.begin(), matCS.end(), cmp_cs_mat); - for (u32 cs_id = 0; cs_id < matCS.size(); cs_id++) - { - mapMatrixCS::TNode* Ncs = matCS[cs_id]; - RCache.set_Constants(Ncs->key); - - mapMatrixStates& states = Ncs->val; - states.ssa = 0; - states.getANY_P(matStates); - std::sort(matStates.begin(), matStates.end(), cmp_states_mat); - for (u32 state_id = 0; state_id < matStates.size(); state_id++) - { - mapMatrixStates::TNode* Nstate = matStates[state_id]; - RCache.set_States(Nstate->key); - - mapMatrixTextures& tex = Nstate->val; - tex.ssa = 0; - sort_tlist_mat(matTextures, matTexturesTemp, tex, true); - for (u32 tex_id = 0; tex_id < matTextures.size(); tex_id++) - { - mapMatrixTextures::TNode* Ntex = matTextures[tex_id]; - RCache.set_Textures(Ntex->key); - RImplementation.apply_lmaterial(); - mapMatrixItems& items = Ntex->val; - items.ssa = 0; - mapMatrix_Render(items); - } - matTextures.clear(); - matTexturesTemp.clear(); - if (_clear) tex.clear(); - } - matStates.clear(); - if (_clear) states.clear(); - } - matCS.clear(); - if (_clear) cs.clear(); - } - matPS.clear(); - if (_clear) ps.clear(); -#if defined(USE_DX10) || defined(USE_DX11) - } - matGS.clear(); - if (_clear) gs.clear(); -#endif // USE_DX10 - } - matVS.clear(); - if (_clear) vs.clear(); + if (_clear) + queue.clear(); } - - Device.Statistic->RenderDUMP.End(); } ////////////////////////////////////////////////////////////////////////// // HUD render -void R_dsgraph_structure::r_dsgraph_render_hud(bool NoPS) +void CDSGraphManager::r_dsgraph_render_hud() { - //PIX_EVENT(r_dsgraph_render_hud); + PROF_EVENT("r_dsgraph_render_hud"); + CHudInitializer initializer(true); - // Change projection - Fmatrix FTold = Device.mFullTransform; - - Device.mFullTransform = Device.mFullTransformHud; - RCache.set_xform_project(Device.mProjectHud); + // Rendering + RImplementation.rmNear(); + r_dsgraph_render_graph_sorted(RGraph.mapHUD); - // Apply HUD Matrix - Fmatrix Pold_prev = Device.mProject_prev; - RCache.set_xform_project_prev(Device.mProjectHud); + RImplementation.rmNormal(); - // Rendering - rmNear(); - if (!NoPS) +#if defined(USE_DX11) // Redotix99: for 3D Shader Based Scopes + if (scope_3D_fake_enabled) { - mapHUD.traverseLR(sorted_L1); - mapHUD.clear(); + RCache.set_RT(RImplementation.Target->rt_ssfx_temp->pRT, 3); // Render scope_3D to any buffer - rmNormal(); - -#if defined(USE_DX11) // Redotix99: for 3D Shader Based Scopes + r_dsgraph_render_graph_sorted(RGraph.mapScopeHUD); - if (scope_3D_fake_enabled) - { - RCache.set_RT(RImplementation.Target->rt_ssfx_temp->pRT, 3); // Render scope_3D to any buffer - - mapScopeHUD.traverseLR(sorted_L1); - - if (!RImplementation.o.ssfx_motionvectors) - RCache.set_RT(NULL, 3); - else - RCache.set_RT(RImplementation.Target->rt_ssfx_motion_vectors->pRT, 3); - } - mapScopeHUD.clear(); + if (!RImplementation.o.ssfx_motionvectors) + RCache.set_RT(NULL, 3); + else + RCache.set_RT(RImplementation.Target->rt_ssfx_motion_vectors->pRT, 3); + } #endif - if (mapCamAttached.size()) - { - rmNear(); - - // Change projection - Fmatrix camproj; - camproj.build_projection( - deg2rad(83.f), - Device.fASPECT, R_VIEWPORT_NEAR, - g_pGamePersistent->Environment().CurrentEnv->far_plane); - - Device.mFullTransform.mul(camproj, Device.mView); - RCache.set_xform_project(camproj); - - // Rendering - mapCamAttached.traverseLR(sorted_L1); - mapCamAttached.clear(); - - rmNormal(); - } - } - /*else + if (RGraph.mapCamAttached.size()) { - HUDMask.traverseLR(hud_node); - HUDMask.clear(); - - if (HUDMaskCamAttached.size()) - { - rmNear(); - - // Change projection - Fmatrix camproj; - camproj.build_projection( - deg2rad(83.f), - Device.fASPECT, R_VIEWPORT_NEAR, - g_pGamePersistent->Environment().CurrentEnv->far_plane); - - Device.mFullTransform.mul(camproj, Device.mView); - RCache.set_xform_project(camproj); - - // Rendering - HUDMaskCamAttached.traverseLR(hud_node); - HUDMaskCamAttached.clear(); - } - - rmNormal(); - }*/ + RImplementation.rmNear(); + // Change projection + initializer.SetCamMode(); - // Restore projection - Device.mFullTransform = FTold; - RCache.set_xform_project(Device.mProject); + // Rendering + r_dsgraph_render_graph_sorted(RGraph.mapCamAttached); - // Restore Prev Matrix - RCache.set_xform_project_prev(Pold_prev); + RImplementation.rmNormal(); + } } -void R_dsgraph_structure::r_dsgraph_render_hud_ui() +void CDSGraphManager::r_dsgraph_render_hud_ui() { - // Change projection - Fmatrix FTold = Device.mFullTransform; + PROF_EVENT("r_dsgraph_render_hud_ui"); + CHudInitializer initializer(true); - Device.mFullTransform = Device.mFullTransformHud; - RCache.set_xform_project(Device.mProjectHud); - - rmNear(); + RImplementation.rmNear(); g_hud->RenderActiveItemUI(); - rmNormal(); - - // Restore projection - Device.mFullTransform = FTold; - RCache.set_xform_project(Device.mProject); + RImplementation.rmNormal(); } -void R_dsgraph_structure::r_dsgraph_render_cam_ui() +void CDSGraphManager::r_dsgraph_render_cam_ui() { - // Change projection - Fmatrix FTold = Device.mFullTransform; - - Fmatrix camproj; - camproj.build_projection( - deg2rad(83.f), - Device.fASPECT, R_VIEWPORT_NEAR, - g_pGamePersistent->Environment().CurrentEnv->far_plane); - - Device.mFullTransform.mul(camproj, Device.mView); - RCache.set_xform_project(camproj); + PROF_EVENT("r_dsgraph_render_cam_ui"); + // Change projection + CHudInitializer initializer(2); + // Rendering - rmNear(); + RImplementation.rmNear(); g_hud->RenderCamAttachedUI(); - rmNormal(); - - // Restore projection - Device.mFullTransform = FTold; - RCache.set_xform_project(Device.mProject); + RImplementation.rmNormal(); } ////////////////////////////////////////////////////////////////////////// // strict-sorted render -void R_dsgraph_structure::r_dsgraph_render_sorted() +void CDSGraphManager::r_dsgraph_render_sorted(bool render_hud) { - // Sorted (back to front) - mapSorted.traverseRL(sorted_L1); - mapSorted.clear(); - - // Change projection - Fmatrix FTold = Device.mFullTransform; - - Device.mFullTransform = Device.mFullTransformHud; - RCache.set_xform_project(Device.mProjectHud); + { + PROF_EVENT("r_dsgraph_render_sorted"); + // Rendering + r_dsgraph_render_graph_sorted(RGraph.mapStaticSorted.Sorted, true); + r_dsgraph_render_graph_sorted(RGraph.mapDynamicSorted.Sorted, true); + } - // Rendering - rmNear(); - mapHUDSorted.traverseRL(sorted_L1); - mapHUDSorted.clear(); + if (render_hud) + r_dsgraph_render_sorted_hud(); // Camera Script Attachments - if (mapCamAttachedSorted.size()) + if (RGraph.mapCamAttachedSorted.Sorted.size()) { + RImplementation.rmNear(); // Change projection - Fmatrix camproj; - camproj.build_projection( - deg2rad(83.f), - Device.fASPECT, R_VIEWPORT_NEAR, - g_pGamePersistent->Environment().CurrentEnv->far_plane); - - Device.mFullTransform.mul(camproj, Device.mView); - RCache.set_xform_project(camproj); + CHudInitializer initializer(2); // Rendering - mapCamAttachedSorted.traverseRL(sorted_L1); - mapCamAttachedSorted.clear(); + r_dsgraph_render_graph_sorted(RGraph.mapCamAttachedSorted.Sorted, true); + RImplementation.rmNormal(); } +} - rmNormal(); - - // Restore projection - Device.mFullTransform = FTold; - RCache.set_xform_project(Device.mProject); +void CDSGraphManager::r_dsgraph_capture_hud() +{ + if (g_hud) + { + g_hud->Render_Last(dcast_IPortalTraverser()); + set_Object(); + } } #if defined(USE_DX11) ////////////////////////////////////////////////////////////////////////// // strict-sorted render -void R_dsgraph_structure::r_dsgraph_render_ScopeSorted() // Redotix99: for 3D Shader Based Scopes +void CDSGraphManager::r_dsgraph_render_ScopeSorted() // Redotix99: for 3D Shader Based Scopes { // Change projection - Fmatrix FTold = Device.mFullTransform; - - Device.mFullTransform = Device.mFullTransformHud; - RCache.set_xform_project(Device.mProjectHud); + CHudInitializer initializer(true); // Rendering - rmNear(); - mapScopeHUDSorted.traverseRL(sorted_L1); - mapScopeHUDSorted.clear(); - rmNormal(); - - // Restore projection - Device.mFullTransform = FTold; - RCache.set_xform_project(Device.mProject); + RImplementation.rmNear(); + r_dsgraph_render_graph_sorted(RGraph.mapScopeHUDSorted, true); + RImplementation.rmNormal(); } #endif +void CDSGraphManager::r_dsgraph_render_sorted_hud() +{ + PROF_EVENT("r_dsgraph_render_sorted_hud"); +#if RENDER==R_R4 + HW.pContext->CopyResource(RImplementation.Target->rt_Accumulator->pSurface, RImplementation.Target->rt_Generic_0->pSurface); +#endif + CHudInitializer initializer(true); + + RImplementation.rmNear(); + r_dsgraph_render_graph_sorted(RGraph.mapHUDSorted.Sorted, true); + RImplementation.rmNormal(); +} + ////////////////////////////////////////////////////////////////////////// // strict-sorted render -void R_dsgraph_structure::r_dsgraph_render_emissive(bool clear, bool renderHUD) +void CDSGraphManager::r_dsgraph_render_emissive(bool clear, bool renderHUD) { + PROF_EVENT("r_dsgraph_render_emissive"); #if RENDER!=R_R1 - // Sorted (back to front) - mapEmissive.traverseLR(sorted_L1); - if (clear) - mapEmissive.clear(); - - // Change projection - Fmatrix FTold = Device.mFullTransform; + r_dsgraph_render_graph_sorted(RGraph.mapStaticSorted.Emissive, clear); + r_dsgraph_render_graph_sorted(RGraph.mapDynamicSorted.Emissive, clear); - Device.mFullTransform = Device.mFullTransformHud; - RCache.set_xform_project(Device.mProjectHud); + // HACK: Calculate this only once + CHudInitializer initializer(true); - // Rendering - rmNear(); - // Sorted (back to front) - mapHUDEmissive.traverseLR(sorted_L1); + RImplementation.rmNear(); + r_dsgraph_render_graph_sorted(RGraph.mapHUDSorted.Emissive, clear); - if (clear) - mapHUDEmissive.clear(); - if (renderHUD) - mapHUDSorted.traverseRL(sorted_L1); - - rmNormal(); + r_dsgraph_render_graph_sorted(RGraph.mapHUDSorted.Sorted, false); - // Restore projection - Device.mFullTransform = FTold; - RCache.set_xform_project(Device.mProject); + RImplementation.rmNormal(); #endif } -void R_dsgraph_structure::r_dsgraph_render_water_ssr() +void CDSGraphManager::r_dsgraph_render_water_ssr() { - mapWater.traverseLR(water_node_ssr); +#ifdef USE_DX11 + PROF_EVENT("r_dsgraph_render_water_ssr"); + std::sort(RGraph.mapWater.begin(), RGraph.mapWater.end()); + for (auto& N : RGraph.mapWater) + { + dxRender_Visual* V = N.pVisual; + VERIFY(V); + + RCache.set_Shader(RImplementation.Target->s_ssfx_water_ssr); + + RCache.set_xform_world(*N.pMatrix); + RImplementation.apply_object(N.pObject); + RImplementation.apply_lmaterial(); + + RCache.set_c("cam_pos", RImplementation.Target->Position_previous.x, RImplementation.Target->Position_previous.y, RImplementation.Target->Position_previous.z, 0.0f); + + // Previous matrix data + RCache.set_c("m_current", RImplementation.Target->Matrix_current); + RCache.set_c("m_previous", RImplementation.Target->Matrix_previous); + + V->Render(calcLOD(N.ssa, V->vis.sphere.R)); + } +#endif } -void R_dsgraph_structure::r_dsgraph_render_water() +void CDSGraphManager::r_dsgraph_render_water() { - mapWater.traverseLR(water_node); - mapWater.clear(); + PROF_EVENT("r_dsgraph_render_water_ssr"); + std::sort(RGraph.mapWater.begin(), RGraph.mapWater.end()); + for (auto& N : RGraph.mapWater) + { + dxRender_Visual* V = N.pVisual; + VERIFY(V); + +#ifdef USE_DX11 + if (RImplementation.o.ssfx_water) + { + RCache.set_Shader(RImplementation.Target->s_ssfx_water); + } +#endif + + RCache.set_xform_world(*N.pMatrix); + RImplementation.apply_object(N.pObject); + RImplementation.apply_lmaterial(); + + // Wind settings + float WindDir = g_pGamePersistent->Environment().CurrentEnv->wind_direction; + float WindVel = g_pGamePersistent->Environment().CurrentEnv->wind_velocity; + RCache.set_c("wind_setup", WindDir, WindVel, 0, 0); + + V->Render(calcLOD(N.ssa, V->vis.sphere.R)); + } + RGraph.mapWater.clear(); } ////////////////////////////////////////////////////////////////////////// // strict-sorted render -void R_dsgraph_structure::r_dsgraph_render_wmarks() +void CDSGraphManager::r_dsgraph_render_wmarks() { + PROF_EVENT("r_dsgraph_render_wmarks"); #if RENDER!=R_R1 - // Sorted (back to front) - mapWmark.traverseLR(sorted_L1); - mapWmark.clear(); + // Rendering + r_dsgraph_render_graph_sorted(RGraph.mapStaticSorted.Wmark); + r_dsgraph_render_graph_sorted(RGraph.mapDynamicSorted.Wmark); + // HACK: Calculate this only once + CHudInitializer initalizer(true); + + RImplementation.rmNear(); + r_dsgraph_render_graph_sorted(RGraph.mapHUDSorted.Wmark); + RImplementation.rmNormal(); #endif } ////////////////////////////////////////////////////////////////////////// // strict-sorted render -void R_dsgraph_structure::r_dsgraph_render_distort() +void CDSGraphManager::r_dsgraph_render_distort() { - // Sorted (back to front) - mapDistort.traverseRL(sorted_L1); - mapDistort.clear(); - - // Change projection - Fmatrix FTold = Device.mFullTransform; - Device.mFullTransform = Device.mFullTransformHud; - RCache.set_xform_project(Device.mProjectHud); - - rmNear(); - mapHUDDistort.traverseLR(sorted_L1); - mapHUDDistort.clear(); - rmNormal(); - - // Restore projection - Device.mFullTransform = FTold; - RCache.set_xform_project(Device.mProject); -} + PROF_EVENT("r_dsgraph_render_distort"); + // Rendering + r_dsgraph_render_graph_sorted(RGraph.mapStaticSorted.Distort, true); + r_dsgraph_render_graph_sorted(RGraph.mapDynamicSorted.Distort, true); + // HACK: Calculate this only once + CHudInitializer initalizer(true); -////////////////////////////////////////////////////////////////////////// -// sub-space rendering - shortcut to render with frustum extracted from matrix -void R_dsgraph_structure::r_dsgraph_render_subspace(IRender_Sector* _sector, Fmatrix& mCombined, Fvector& _cop, - BOOL _dynamic, BOOL _precise_portals) -{ - CFrustum temp; - temp.CreateFromMatrix(mCombined, FRUSTUM_P_ALL & (~FRUSTUM_P_NEAR)); - r_dsgraph_render_subspace(_sector, &temp, mCombined, _cop, _dynamic, _precise_portals); + RImplementation.rmNear(); + r_dsgraph_render_graph_sorted(RGraph.mapHUDSorted.Distort); + RImplementation.rmNormal(); } -// sub-space rendering - main procedure -void R_dsgraph_structure::r_dsgraph_render_subspace(IRender_Sector* _sector, CFrustum* _frustum, Fmatrix& mCombined, - Fvector& _cop, BOOL _dynamic, BOOL _precise_portals) +#include"LightTrack.h" +void CDSGraphManager::r_dsgraph_capture_static() { - VERIFY(_sector); - RImplementation.marker ++; // !!! critical here + PROF_EVENT("r_dsgraph_capture_static") + const bool dbg_enabled = PortalTraverseDbg_Enabled(); + PortalTraverseDebugStats* dbg = dbg_enabled ? &PortalTraverseDbg_Get() : nullptr; + const bool opt_bucket = PortalTraverseDbg_IsOptions(i_options); - // Save and build new frustum, disable HOM - CFrustum ViewSave = ViewBase; - ViewBase = *_frustum; - View = &ViewBase; - - if (_precise_portals && RImplementation.rmPortals) + if (i_start) { - // Check if camera is too near to some portal - if so force DualRender - Fvector box_radius; - box_radius.set(EPS_L * 20, EPS_L * 20, EPS_L * 20); - RImplementation.Sectors_xrc.box_options(CDB::OPT_FULL_TEST); - RImplementation.Sectors_xrc.box_query(RImplementation.rmPortals, _cop, box_radius); - for (int K = 0; K < RImplementation.Sectors_xrc.r_count(); K++) + // Traverse sector/portal structure + if (psDeviceFlags.test(rsDrawStatic)) { - CPortal* pPortal = (CPortal*)RImplementation.Portals[RImplementation.rmPortals->get_tris()[RImplementation - .Sectors_xrc. - r_begin()[K].id]. - dummy]; - pPortal->bDualRender = TRUE; - } - } + if (dbg) + { + const u32 sector_nodes = u32(m_sector_frustums.size()); + dbg->static_sector_nodes += sector_nodes; + if (opt_bucket) + dbg->static_sector_nodes_opt += sector_nodes; + else + dbg->static_sector_nodes_noopt += sector_nodes; + } - // Traverse sector/portal structure - PortalTraverser.traverse(_sector, ViewBase, _cop, mCombined, 0); + // Determine visibility for static geometry hierrarhy + for (auto& pair : m_sector_frustums) + { + xr_vector& frustums = pair.val.first; + if (frustums.empty()) + continue; - // Determine visibility for static geometry hierrarhy - for (u32 s_it = 0; s_it < PortalTraverser.r_sectors.size(); s_it++) - { - CSector* sector = (CSector*)PortalTraverser.r_sectors[s_it]; - dxRender_Visual* root = sector->root(); - for (u32 v_it = 0; v_it < sector->r_frustums.size(); v_it++) - { - set_Frustum(&(sector->r_frustums[v_it])); - add_Geometry(root); - } - } + if (frustums.size() == 1) + { + if (dbg) + { + ++dbg->static_frustum_nodes; + ++dbg->static_add_root_calls; + if (opt_bucket) + { + ++dbg->static_frustum_nodes_opt; + ++dbg->static_add_root_calls_opt; + } + else + { + ++dbg->static_frustum_nodes_noopt; + ++dbg->static_add_root_calls_noopt; + } + } + add_Static((IRenderVisual*)pair.key->root(), frustums.front(), frustums.front().getMask()); + continue; + } - if (_dynamic) - { - set_Object(0); - - // Traverse object database - g_SpatialSpace->q_frustum - ( - lstRenderables, - ISpatial_DB::O_ORDERED, - STYPE_RENDERABLE, - ViewBase - ); - - // Determine visibility for dynamic part of scene - for (u32 o_it = 0; o_it < lstRenderables.size(); o_it++) - { - ISpatial* spatial = lstRenderables[o_it]; - CSector* sector = (CSector*)spatial->spatial.sector; - if (0 == sector) continue; // disassociated from S/P structure - if (PortalTraverser.i_marker != sector->r_marker) continue; // inactive (untouched) sector - for (u32 v_it = 0; v_it < sector->r_frustums.size(); v_it++) - { - set_Frustum(&(sector->r_frustums[v_it])); - if (!View->testSphere_dirty(spatial->spatial.sphere.P, spatial->spatial.sphere.R)) continue; + xr_vector masks; + masks.reserve(frustums.size()); + for (CFrustum& frustum_node : frustums) + masks.push_back(frustum_node.getMask()); - // renderable - IRenderable* renderable = spatial->dcast_Renderable(); - if (0 == renderable) continue; // unknown, but renderable object (r1_glow???) + if (dbg) + { + dbg->static_frustum_nodes += u32(frustums.size()); + ++dbg->static_add_root_calls; + if (opt_bucket) + { + dbg->static_frustum_nodes_opt += u32(frustums.size()); + ++dbg->static_add_root_calls_opt; + } + else + { + dbg->static_frustum_nodes_noopt += u32(frustums.size()); + ++dbg->static_add_root_calls_noopt; + } + } - renderable->renderable_Render(); + add_Static_MultiFrustum((IRenderVisual*)pair.key->root(), frustums, masks); } } } - - // Restore - ViewBase = ViewSave; - View = 0; } -#include "fhierrarhyvisual.h" -#include "SkeletonCustom.h" -#include "../../xrEngine/fmesh.h" -#include "flod.h" - -void R_dsgraph_structure::r_dsgraph_render_R1_box(IRender_Sector* _S, Fbox& BB, int sh) +void CDSGraphManager::r_dsgraph_capture_lights() { - CSector* S = (CSector*)_S; - lstVisuals.clear(); - lstVisuals.push_back(S->root()); + PROF_EVENT("r_dsgraph_capture_lights") + g_SpatialSpaceLights->q_frustum + ( + lstLights, + ISpatial_DB::O_ORDERED, + STYPE_LIGHTSOURCE, + i_frustum + ); - for (u32 test = 0; test < lstVisuals.size(); test++) +#if RENDER==R_R1 + std::sort(lstLights.begin(), lstLights.end(), [](const ISpatialShared& _1, const ISpatialShared& _2) noexcept { - dxRender_Visual* V = lstVisuals[test]; + if (!_1.get() || !_2.get()) return false; - // Visual is 100% visible - simply add it - xr_vector::iterator I, E; // it may be usefull for 'hierrarhy' visuals + return _1->spatial.sphere.P.distance_to_sqr(Device.vCameraPosition_saved) < _2->spatial.sphere.P.distance_to_sqr(Device.vCameraPosition_saved); + }); +#endif - switch (V->Type) + for (ISpatialShared spatial : lstLights) + { + if (0 == spatial) continue; spatial->spatial_updatesector(); + CSector* sector = (CSector*)spatial->spatial.sector; + if (0 == sector) continue; + + if (!RImplementation.HOM.visible(spatial->spatial.sphere)) continue; + + if ((spatial->spatial.type & STYPE_LIGHTSOURCE)) { - case MT_HIERRARHY: + // lightsource + if (light* L = (light*)(spatial->dcast_Light())) { - // Add all children - FHierrarhyVisual* pV = (FHierrarhyVisual*)V; - I = pV->children.begin(); - E = pV->children.end(); - for (; I != E; ++I) +#if RENDER==R_R1 + RImplementation.L_DB->add_light(L); +#else + if (L->get_LOD() > ps_r2_shadow_lod_min && L->has_light_visible_from_sectors(*this)) { - dxRender_Visual* T = (dxRender_Visual*)*I; - if (BB.intersect(T->vis.box)) lstVisuals.push_back(T); + RImplementation.Lights.add_light(L); } +#endif } - break; - case MT_SKELETON_ANIM: - case MT_SKELETON_RIGID: + } + } +} + +void CDSGraphManager::r_dsgraph_capture_dynamic(CObject* O) +{ + PROF_EVENT("r_dsgraph_capture_dynamic") + const bool dbg_enabled = PortalTraverseDbg_Enabled(); + PortalTraverseDebugStats* dbg = dbg_enabled ? &PortalTraverseDbg_Get() : nullptr; + const bool opt_bucket = PortalTraverseDbg_IsOptions(i_options); + + if (i_start) + { + if (psDeviceFlags.test(rsDrawDynamic)) + { + // Traverse object database + g_SpatialSpace->q_frustum + ( + lstRenderables, + ISpatial_DB::O_ORDERED, + i_doptions, + i_frustum + ); + if (dbg) { - // Add all children (s) - CKinematics* pV = (CKinematics*)V; - pV->CalculateBones(TRUE); - I = pV->children.begin(); - E = pV->children.end(); - for (; I != E; ++I) - { - dxRender_Visual* T = (dxRender_Visual*)*I; - if (BB.intersect(T->vis.box)) lstVisuals.push_back(T); - } + const u32 spatial_count = u32(lstRenderables.size()); + dbg->dynamic_spatials += spatial_count; + if (opt_bucket) + dbg->dynamic_spatials_opt += spatial_count; + else + dbg->dynamic_spatials_noopt += spatial_count; } - break; - case MT_LOD: + set_Object(); +#if RENDER==R_R1 + if (i_mask[CDSGraphManager::fl_normal])//normal phase { - FLOD* pV = (FLOD*)V; - I = pV->children.begin(); - E = pV->children.end(); - for (; I != E; ++I) + std::sort(lstRenderables.begin(), lstRenderables.end(), [](const ISpatialShared& _1, const ISpatialShared& _2) noexcept { - dxRender_Visual* T = (dxRender_Visual*)*I; - if (BB.intersect(T->vis.box)) lstVisuals.push_back(T); - } + if (!_1.get() || !_2.get()) return false; + + return _1->spatial.sphere.P.distance_to_sqr(Device.vCameraPosition_saved) < _2->spatial.sphere.P.distance_to_sqr(Device.vCameraPosition_saved); + }); + + if (ps_actor_shadow_flags.test(1)) + g_hud->Render_First(dcast_IPortalTraverser()); + + r_dsgraph_capture_hud(); } - break; - default: +#endif + u32 uID_LTRACK = u32(-1); + if (i_mask[CDSGraphManager::fl_normal])//normal phase { - // Renderable visual - ShaderElement* E = V->shader->E[sh]._get(); - if (E && !(E->flags.bDistort)) + // update light-vis for current entity / actor + if (CObject* O = g_pGameLevel->CurrentViewEntity()) { - for (u32 pass = 0; pass < E->passes.size(); pass++) + if (!O->getDestroy()) { - RCache.set_Element(E, pass); - V->Render(-1.f); + if (CROS_impl* R = (CROS_impl*)O->ROS()) + R->update(O); } } + + RImplementation.uLastLTRACK++; + if (!lstRenderables.empty()) + { + uID_LTRACK = RImplementation.uLastLTRACK % lstRenderables.size(); +#if RENDER!=R_R1 + // update light-vis for selected entity + // track lighting environment + if (IRenderable* renderable = (IRenderable*)lstRenderables[uID_LTRACK]->dcast_Renderable()) + { + if (CROS_impl* T = (CROS_impl*)renderable->renderable_ROS()) + T->update(renderable); + } +#endif + } + } - break; - } - } -} -void __fastcall pLandscape_0(mapLandscape_Node *N) -{ - VERIFY(N); - dxRender_Visual *V = N->val.pVisual; - VERIFY(V && V->shader._get()); - RCache.set_Element(N->val.se, 0); - float LOD = calcLOD(N->val.ssa, V->vis.sphere.R); -#ifdef USE_DX11 - RCache.LOD.set_LOD(LOD); + // Determine visibility for dynamic part of scene + for (u32 o_it = 0; o_it < lstRenderables.size(); o_it++) + { + ISpatialShared spatial = lstRenderables[o_it]; + if (0 == spatial) continue; + CSector* sector = (CSector*)spatial->spatial.sector; + if (0 == sector) continue; + + if (i_mask[CDSGraphManager::fl_normal] && !RImplementation.HOM.visible(spatial->spatial.sphere)) + continue; + +#if RENDER==R_R1 + if ((spatial->spatial.type & STYPE_GLOW)) + { + if (CGlow* glow = spatial->dcast_CGlow()) + { + // It may be an glow + RImplementation.L_Glows->add(glow); + } + continue; + } #endif - V->Render(LOD); -} -void __fastcall pLandscape_1(mapLandscape_Node *N) -{ - VERIFY(N); - dxRender_Visual *V = N->val.pVisual; - VERIFY(V && V->shader._get()); - RCache.set_Element(N->val.se, 1); - RImplementation.apply_lmaterial(); - float LOD = calcLOD(N->val.ssa, V->vis.sphere.R); -#ifdef USE_DX11 - RCache.LOD.set_LOD(LOD); +// if ((spatial->spatial.type & STYPE_LIGHTSOURCE)) +// { +// // lightsource +// if (light* L = (light*)(spatial->dcast_Light())) +// { +//#if RENDER==R_R1 +// RImplementation.L_DB->add_light(L); +//#else +// if (L->get_LOD() > EPS_L && L->has_light_visible_from_sectors(PT)) +// { +// RImplementation.Lights.add_light(L); +// } +//#endif +// } +// continue; +// } + + if(!(spatial->spatial.type & STYPE_RENDERABLE) && !(spatial->spatial.type & STYPE_PARTICLE) && !(spatial->spatial.type & STYPE_RENDERABLESHADOW)) + continue; + if (!is_sector_visible(sector)) + continue; + + for (CFrustum& frustum : m_sector_frustums.find(sector)->val.first) + { + if (dbg) + { + ++dbg->dynamic_frustum_tests; + if (opt_bucket) + ++dbg->dynamic_frustum_tests_opt; + else + ++dbg->dynamic_frustum_tests_noopt; + } + + if (frustum.testSphere_dirty(spatial->spatial.sphere.P, spatial->spatial.sphere.R)) + { + if (dbg) + { + ++dbg->dynamic_frustum_hits; + if (opt_bucket) + ++dbg->dynamic_frustum_hits_opt; + else + ++dbg->dynamic_frustum_hits_noopt; + } + + // renderable + IRenderable* renderable = spatial->dcast_Renderable(); + if (0 == renderable) break; + + if (O && O->dcast_Renderable() == renderable) break; + + // Rendering +#if RENDER==R_R1 + if (i_mask[CDSGraphManager::fl_normal] && o_it == uID_LTRACK && renderable->renderable_ROS()) + { + // track lighting environment + if(CROS_impl* T = (CROS_impl*)renderable->renderable_ROS()) + T->update(renderable); + } #endif - V->Render(LOD); + if (i_mask[CDSGraphManager::fl_normal] && !(spatial->spatial.type & STYPE_PARTICLE)) + set_Object(renderable); + + renderable->renderable_Render(dcast_IPortalTraverser()); + if (dbg) + { + ++dbg->dynamic_rendered; + if (opt_bucket) + ++dbg->dynamic_rendered_opt; + else + ++dbg->dynamic_rendered_noopt; + } + + if (i_mask[CDSGraphManager::fl_normal] && !(spatial->spatial.type & STYPE_PARTICLE)) + set_Object(); + break; + } + } + } + } + } } -void R_dsgraph_structure::r_dsgraph_render_landscape(u32 pass, bool _clear) +void CDSGraphManager::r_dsgraph_capture(bool lights, bool dynamic, CObject* O) { - RCache.set_xform_world(Fidentity); + PROF_EVENT("r_dsgraph_capture") + r_dsgraph_capture_static(); - if (pass == 0) - mapLandscape.traverseLR(pLandscape_0); - else - mapLandscape.traverseLR(pLandscape_1); + if(lights) + r_dsgraph_capture_lights(); - if (_clear) - mapLandscape.clear(); + if (dynamic) + r_dsgraph_capture_dynamic(O); } diff --git a/src/Layers/xrRender/r__dsgraph_render_lods.cpp b/src/Layers/xrRender/r__dsgraph_render_lods.cpp index feee5439f3..efd570dd31 100644 --- a/src/Layers/xrRender/r__dsgraph_render_lods.cpp +++ b/src/Layers/xrRender/r__dsgraph_render_lods.cpp @@ -12,17 +12,22 @@ extern float r_ssaLOD_A; extern float r_ssaLOD_B; -ICF bool pred_dot(const std::pair& _1, const std::pair& _2) { return _1.first < _2.first; } - -void R_dsgraph_structure::r_dsgraph_render_lods(bool _setup_zb, bool _clear) +xr_vector lstLODgroups; +void CDSGraphManager::r_dsgraph_render_lods(bool _setup_zb, bool _clear) { - if (_setup_zb) mapLOD.getLR(lstLODs); // front-to-back - else mapLOD.getRL(lstLODs); // back-to-front - if (lstLODs.empty()) return; + PROF_EVENT("LODS: Render"); + if (RGraph.mapLOD.empty()) + return; + + static auto sortFuncReverse = [](const auto& a, const auto& b) { return b < a; }; + if (_setup_zb) + std::sort(RGraph.mapLOD.begin(), RGraph.mapLOD.end()); + else + std::sort(RGraph.mapLOD.begin(), RGraph.mapLOD.end(), sortFuncReverse); // *** Fill VB and generate groups u32 shid = _setup_zb ? SE_R1_LMODELS : SE_R1_NORMAL_LQ; - FLOD* firstV = (FLOD*)lstLODs[0].pVisual; + FLOD* firstV = (FLOD*)RGraph.mapLOD[0].pVisual; ref_selement cur_S = firstV->shader->E[shid]; float ssaRange = r_ssaLOD_A - r_ssaLOD_B; if (ssaRange < EPS_S) ssaRange = EPS_S; @@ -35,9 +40,9 @@ void R_dsgraph_structure::r_dsgraph_render_lods(bool _setup_zb, bool _clear) //Msg ("dbg_lods: shader[%X]",u32((void*)firstV->shader._get())); //Msg ("dbg_lods: shader_E[%X]",u32((void*)cur_S._get())); - for (u32 i = 0; i < lstLODs.size(); i++) + for (u32 i = 0; i < RGraph.mapLOD.size(); i++) { - const u32 iBatchSize = _min(lstLODs.size() - i, uiImpostersFit); + const u32 iBatchSize = _min((u32)RGraph.mapLOD.size() - i, uiImpostersFit); int cur_count = 0; u32 vOffset; FLOD::_hw* V = (FLOD::_hw*)RCache.Vertex.Lock(iBatchSize * uiVertexPerImposter, firstV->geom->vb_stride, @@ -46,8 +51,10 @@ void R_dsgraph_structure::r_dsgraph_render_lods(bool _setup_zb, bool _clear) for (u32 j = 0; j < iBatchSize; ++j, ++i) { // sort out redundancy - R_dsgraph::_LodItem& P = lstLODs[i]; - if (P.pVisual->shader->E[shid] == cur_S) cur_count++; + auto& P = RGraph.mapLOD[i]; + + if (P.pVisual->shader->E[shid] == cur_S) + cur_count++; else { lstLODgroups.push_back(cur_count); @@ -71,7 +78,8 @@ void R_dsgraph_structure::r_dsgraph_render_lods(bool _setup_zb, bool _clear) FLOD::_face* facets = lodV->facets; svector, 8> selector; for (u32 s = 0; s < 8; s++) selector.push_back(mk_pair(Ldir.dotproduct(facets[s].N), s)); - std::sort(selector.begin(), selector.end(), pred_dot); + static auto sort_pred = [](const std::pair& _1, const std::pair& _2) { return _1.first < _2.first; }; + std::sort(selector.begin(), selector.end(), sort_pred); float dot_best = selector[selector.size() - 1].first; float dot_next = selector[selector.size() - 2].first; @@ -88,7 +96,7 @@ void R_dsgraph_structure::r_dsgraph_render_lods(bool _setup_zb, bool _clear) // Fill VB FLOD::_face& FA = facets[id_best]; FLOD::_face& FB = facets[id_next]; - static int vid [4] = {3, 0, 2, 1}; + static int vid[4] = {3, 0, 2, 1}; for (u32 vit = 0; vit < 4; vit++) { int id = vid[vit]; @@ -114,13 +122,12 @@ void R_dsgraph_structure::r_dsgraph_render_lods(bool _setup_zb, bool _clear) int current = 0; u32 vCurOffset = vOffset; - for (u32 g = 0; g < lstLODgroups.size(); g++) + for (int& p_count : lstLODgroups) { - int p_count = lstLODgroups[g]; - u32 uiNumPasses = lstLODs[current].pVisual->shader->E[shid]->passes.size(); + u32 uiNumPasses = RGraph.mapLOD[current].pVisual->shader->E[shid]->passes.size(); if (uiPass < uiNumPasses) { - RCache.set_Element(lstLODs[current].pVisual->shader->E[shid], uiPass); + RCache.set_Element(RGraph.mapLOD[current].pVisual->shader->E[shid], uiPass); RCache.set_Geometry(firstV->geom); RCache.Render(D3DPT_TRIANGLELIST, vCurOffset, 0, 4 * p_count, 0, 2 * p_count); } @@ -133,7 +140,6 @@ void R_dsgraph_structure::r_dsgraph_render_lods(bool _setup_zb, bool _clear) lstLODgroups.clear(); } - lstLODs.clear(); - - if (_clear) mapLOD.clear(); + if (_clear) + RGraph.mapLOD.clear(); } diff --git a/src/Layers/xrRender/r__dsgraph_structure.h b/src/Layers/xrRender/r__dsgraph_structure.h deleted file mode 100644 index b0dd5dacf9..0000000000 --- a/src/Layers/xrRender/r__dsgraph_structure.h +++ /dev/null @@ -1,245 +0,0 @@ -#pragma once - -#include "../../xrEngine/render.h" -#include "../../xrcdb/ispatial.h" -#include "r__dsgraph_types.h" -#include "r__sector.h" - -////////////////////////////////////////////////////////////////////////// -// feedback for receiving visuals // -////////////////////////////////////////////////////////////////////////// -class R_feedback -{ -public: - virtual void rfeedback_static(dxRender_Visual* V) = 0; -}; - -////////////////////////////////////////////////////////////////////////// -// common part of interface implementation for all D3D renderers // -////////////////////////////////////////////////////////////////////////// -class R_dsgraph_structure : public IRender_interface, public pureFrame -{ -public: - IRenderable* val_pObject; - Fmatrix* val_pTransform; - BOOL val_bHUD; - BOOL val_bCamAttached; - BOOL val_bInvisible; - BOOL val_bRecordMP; // record nearest for multi-pass - R_feedback* val_feedback; // feedback for geometry being rendered - u32 val_feedback_breakp; // breakpoint - xr_vector>* val_recorder; // coarse structure recorder - u32 phase; - u32 marker; - bool pmask [2]; - bool pmask_wmark; -public: - // Dynamic scene graph - //R_dsgraph::mapNormal_T mapNormal [2] ; // 2==(priority/2) - R_dsgraph::mapNormalPasses_T mapNormalPasses [2]; // 2==(priority/2) - //R_dsgraph::mapMatrix_T mapMatrix [2] ; - R_dsgraph::mapMatrixPasses_T mapMatrixPasses [2]; - R_dsgraph::mapSorted_T mapSorted; - R_dsgraph::mapHUD_T mapHUD; - R_dsgraph::mapHUD_T mapCamAttached; - R_dsgraph::mapLOD_T mapLOD; - R_dsgraph::mapSorted_T mapDistort; - R_dsgraph::mapHUD_T mapHUDSorted; - R_dsgraph::mapHUD_T mapCamAttachedSorted; -#if defined(USE_DX11) - R_dsgraph::mapScopeHUD_T mapScopeHUD; // Redotix99: for 3D Shader Based Scopes - R_dsgraph::mapScopeHUD_T mapScopeHUDSorted; -#endif - R_dsgraph::mapLandscape_T mapLandscape; - //R_dsgraph::HUDMask_T HUDMask; // SSS 23: Deprecated - R_dsgraph::HUDMask_T HUDMaskCamAttached; - R_dsgraph::mapWater_T mapWater; - -#if RENDER!=R_R1 - R_dsgraph::mapSorted_T mapWmark; // sorted - R_dsgraph::mapSorted_T mapEmissive; - R_dsgraph::mapSorted_T mapHUDEmissive; - R_dsgraph::mapSorted_T mapCamAttachedEmissive; -#endif - R_dsgraph::mapSorted_T mapHUDDistort; - - // Runtime structures - xr_vector> nrmVS; -#if defined(USE_DX10) || defined(USE_DX11) - xr_vector > nrmGS; -#endif // USE_DX10 - xr_vector> nrmPS; - xr_vector> nrmCS; - xr_vector> nrmStates; - xr_vector> nrmTextures; - xr_vector> nrmTexturesTemp; - - xr_vector> matVS; -#if defined(USE_DX10) || defined(USE_DX11) - xr_vector > matGS; -#endif // USE_DX10 - xr_vector> matPS; - xr_vector> matCS; - xr_vector> matStates; - xr_vector> matTextures; - xr_vector> matTexturesTemp; - - xr_vector> lstLODs; - xr_vector> lstLODgroups; - xr_vector/**/> lstRenderables; - xr_vector/**/> lstSpatial; - xr_vector> lstVisuals; - - xr_vector> lstRecorded; - - u32 counter_S; - u32 counter_D; - BOOL b_loaded; -public: - virtual void set_Transform(Fmatrix* M) - { - VERIFY(M); - val_pTransform = M; - } - - virtual void set_HUD(BOOL V) { val_bHUD = V; } - virtual BOOL get_HUD() { return val_bHUD; } - virtual void set_CamAttached(BOOL V) { val_bCamAttached = V; } - virtual BOOL get_CamAttached() { return val_bCamAttached; } - virtual void set_Invisible(BOOL V) { val_bInvisible = V; } - - void set_Feedback(R_feedback* V, u32 id) - { - val_feedback_breakp = id; - val_feedback = V; - } - - void set_Recorder(xr_vector>* dest) - { - val_recorder = dest; - if (dest) dest->clear(); - } - - void get_Counters(u32& s, u32& d) - { - s = counter_S; - d = counter_D; - } - - void clear_Counters() { counter_S = counter_D = 0; } -public: - R_dsgraph_structure() - { - val_pObject = NULL; - val_pTransform = NULL; - val_bHUD = FALSE; - val_bCamAttached = FALSE; - val_bInvisible = FALSE; - val_bRecordMP = FALSE; - val_feedback = 0; - val_feedback_breakp = 0; - val_recorder = 0; - marker = 0; - r_pmask(true, true); - b_loaded = FALSE; - }; - - void r_dsgraph_destroy() - { - nrmVS.clear(); - nrmPS.clear(); - nrmCS.clear(); - nrmStates.clear(); - nrmTextures.clear(); - nrmTexturesTemp.clear(); - - matVS.clear(); - matPS.clear(); - matCS.clear(); - matStates.clear(); - matTextures.clear(); - matTexturesTemp.clear(); - - lstLODs.clear(); - lstLODgroups.clear(); - lstRenderables.clear(); - lstSpatial.clear(); - lstVisuals.clear(); - - lstRecorded.clear(); - - //mapNormal[0].destroy (); - //mapNormal[1].destroy (); - //mapMatrix[0].destroy (); - //mapMatrix[1].destroy (); - for (int i = 0; i < SHADER_PASSES_MAX; ++i) - { - mapNormalPasses[0][i].destroy(); - mapNormalPasses[1][i].destroy(); - mapMatrixPasses[0][i].destroy(); - mapMatrixPasses[1][i].destroy(); - } - mapSorted.destroy(); - mapHUD.destroy(); - mapCamAttached.destroy(); - mapLOD.destroy(); - mapDistort.destroy(); - mapHUDSorted.destroy(); - mapHUDDistort.destroy(); - mapCamAttachedSorted.destroy(); - mapLandscape.destroy(); - //HUDMask.destroy(); // SSS 23: Deprecated - HUDMaskCamAttached.destroy(); - mapWater.destroy(); - -#if RENDER!=R_R1 - mapWmark.destroy(); - mapEmissive.destroy(); - mapHUDEmissive.destroy(); - mapCamAttachedEmissive.destroy(); -#endif - } - - void r_pmask(bool _1, bool _2, bool _wm = false) - { - pmask[0] = _1; - pmask[1] = _2; - pmask_wmark = _wm; - } - - void r_dsgraph_insert_dynamic(dxRender_Visual* pVisual, Fvector& Center); - void r_dsgraph_insert_static(dxRender_Visual* pVisual); - - void r_dsgraph_render_graph(u32 _priority, bool _clear = true); - void r_dsgraph_render_hud(bool NoPS = false); - void r_dsgraph_render_hud_ui(); - void r_dsgraph_render_cam_ui(); - void r_dsgraph_render_lods(bool _setup_zb, bool _clear); - void r_dsgraph_render_sorted(); -#if defined(USE_DX11) - void r_dsgraph_render_ScopeSorted(); // Redotix99: for 3D Shader Based Scopes -#endif - void r_dsgraph_render_emissive(bool clear = true, bool renderHUD = false); - void r_dsgraph_render_wmarks(); - void r_dsgraph_render_distort(); - void r_dsgraph_render_subspace(IRender_Sector* _sector, CFrustum* _frustum, Fmatrix& mCombined, Fvector& _cop, - BOOL _dynamic, BOOL _precise_portals = FALSE); - void r_dsgraph_render_subspace(IRender_Sector* _sector, Fmatrix& mCombined, Fvector& _cop, BOOL _dynamic, - BOOL _precise_portals = FALSE); - void r_dsgraph_render_R1_box(IRender_Sector* _sector, Fbox& _bb, int _element); - - void r_dsgraph_render_landscape(u32 pass, bool _clear); - void r_dsgraph_render_water_ssr(); - void r_dsgraph_render_water(); - - -public: - virtual u32 memory_usage() - { -#ifdef USE_DOUG_LEA_ALLOCATOR_FOR_RENDER - return (g_render_lua_allocator.get_allocated_size()); -#else // USE_DOUG_LEA_ALLOCATOR_FOR_RENDER - return (0); -#endif // USE_DOUG_LEA_ALLOCATOR_FOR_RENDER - } -}; diff --git a/src/Layers/xrRender/r__dsgraph_types.h b/src/Layers/xrRender/r__dsgraph_types.h index 62bb233e5e..21b9e6b1bb 100644 --- a/src/Layers/xrRender/r__dsgraph_types.h +++ b/src/Layers/xrRender/r__dsgraph_types.h @@ -12,17 +12,17 @@ template class doug_lea_alloc { public: - typedef size_t size_type; - typedef ptrdiff_t difference_type; - typedef T* pointer; - typedef const T* const_pointer; - typedef T& reference; - typedef const T& const_reference; - typedef T value_type; + using size_type = size_t; + using difference_type = ptrdiff_t; + using pointer = T*; + using const_pointer = const T*; + using reference = T&; + using const_reference = const T&; + using value_type = T; public: template - struct rebind { typedef doug_lea_alloc<_Other> other; }; + struct rebind { using other = doug_lea_alloc<_Other>; }; public: pointer address (reference _Val) const { return (&_Val); } const_pointer address (const_reference _Val) const { return (&_Val); } @@ -45,7 +45,7 @@ struct doug_lea_allocator_wrapper { template struct helper { - typedef doug_lea_alloc result; + using result = doug_lea_alloc; }; static void *alloc (const u32 &n) { return g_render_lua_allocator.malloc_impl((u32)n); } @@ -54,186 +54,323 @@ }; # define render_alloc doug_lea_alloc - typedef doug_lea_allocator_wrapper render_allocator; + using render_allocator = doug_lea_allocator_wrapper; #else // USE_DOUG_LEA_ALLOCATOR_FOR_RENDER # define render_alloc xalloc -typedef xr_allocator render_allocator; +using render_allocator = xr_allocator; #endif // USE_DOUG_LEA_ALLOCATOR_FOR_RENDER class dxRender_Visual; +struct SPass; // #define USE_RESOURCE_DEBUGGER namespace R_dsgraph { - // Elementary types - struct _NormalItem + template + struct DSGraphItem { - float ssa; - dxRender_Visual* pVisual; + T sortKey; + float ssa = 0.0f; + IRenderable* pObject = nullptr; + dxRender_Visual* pVisual = nullptr; + Fmatrix* pMatrix = nullptr; + ShaderElement* pSE = nullptr; + bool b_hud_mode = false; + + DSGraphItem(T key, float _ssa, IRenderable* obj, dxRender_Visual* vis, + Fmatrix* mat, ShaderElement* se, bool hud) + : sortKey(key), ssa(_ssa), pObject(obj), pVisual(vis), + pMatrix(mat), pSE(se), b_hud_mode(hud) { + } + + bool operator<(const DSGraphItem& other) const noexcept + { + if constexpr (Reverse) + return other.sortKey < sortKey; + else + return sortKey < other.sortKey; + } }; - struct _MatrixItem - { - float ssa; - IRenderable* pObject; - dxRender_Visual* pVisual; - Fmatrix Matrix; // matrix (copy) - Fmatrix PrevMatrix; - }; - - struct _MatrixItemS : public _MatrixItem - { - ShaderElement* se; - }; - - struct _LodItem - { - float ssa; - dxRender_Visual* pVisual; - }; - -#ifdef USE_RESOURCE_DEBUGGER - typedef ref_vs vs_type; - typedef ref_ps ps_type; -# if defined(USE_DX10) || defined(USE_DX11) - typedef ref_gs gs_type; -# ifdef USE_DX11 - typedef ref_hs hs_type; - typedef ref_ds ds_type; -# endif -# endif // USE_DX10 -#else #if defined(USE_DX10) || defined(USE_DX11) // DX10 needs shader signature to propperly bind deometry to shader - typedef SVS* vs_type; - typedef ID3DGeometryShader* gs_type; + using vs_type = SVS*; + using gs_type = ID3DGeometryShader*; #ifdef USE_DX11 - typedef ID3D11HullShader* hs_type; - typedef ID3D11DomainShader* ds_type; + using hs_type = ID3D11HullShader*; + using ds_type = ID3D11DomainShader*; #endif #else // USE_DX10 - typedef ID3DVertexShader* vs_type; + using vs_type = ID3DVertexShader*; #endif // USE_DX10 - typedef ID3DPixelShader* ps_type; -#endif + using ps_type = ID3DPixelShader*; - // NORMAL - typedef xr_vector<_NormalItem, render_allocator::helper<_NormalItem>::result> mapNormalDirect; + template + using mapDSGraphItems = xr_vector, typename render_allocator::template helper>::result>; - struct mapNormalItems : public mapNormalDirect - { - float ssa; - }; + template + using mapDSGraphItemsMap = FixedMAP, render_allocator>; - struct mapNormalTextures : public FixedMAP + struct alignas(16) RenderPacketSortKey { - float ssa; + // Calculated key for sorting + u64 high; // VS, GS, PS, HS + u64 low; // DS, Constants, State, Textures + + bool operator<(const RenderPacketSortKey& other) const noexcept + { + if (high != other.high) + return high < other.high; + return low < other.low; + } + + bool operator!=(const RenderPacketSortKey& other) const noexcept + { + return (high != other.high) || (low != other.low); + } + + bool operator==(const RenderPacketSortKey& other) const noexcept + { + return (high == other.high) && (low == other.low); + } }; - struct mapNormalStates : public FixedMAP + struct RenderPacket { - float ssa; - }; + // Sorting key + RenderPacketSortKey sortKey; + + // Visual data + DSGraphItem item; + + // Pointers to resources (previously keys in FixedMAPs) + ID3DState* pState; + +#if defined(USE_DX10) || defined(USE_DX11) + gs_type pGS; +#else + u64 _unused_pad_gs; +#endif - struct mapNormalCS : public FixedMAP - { - float ssa; - }; #ifdef USE_DX11 - struct mapNormalAdvStages - { - hs_type hs; - ds_type ds; - mapNormalCS mapCS; - }; - struct mapNormalPS : public FixedMAP { float ssa; }; + hs_type pHS; + ds_type pDS; #else - struct mapNormalPS : public FixedMAP - { - float ssa; - }; -#endif // USE_DX11 + u64 _unused_pad_hs, _unused_pad_ds; +#endif + + vs_type pVS; + ps_type pPS; + R_constant_table* pCS; + STextureList* pTextures; + + RenderPacket(const DSGraphItem& _item, const SPass& pass) : item(_item) + { + // Extract resource pointers from shader pass (previously used as map keys) #if defined(USE_DX10) || defined(USE_DX11) - struct mapNormalGS : public FixedMAP { float ssa; }; - struct mapNormalVS : public FixedMAP { }; -#else // USE_DX10 - struct mapNormalVS : public FixedMAP - { - }; -#endif // USE_DX10 - typedef mapNormalVS mapNormal_T; - typedef mapNormal_T mapNormalPasses_T[SHADER_PASSES_MAX]; + pVS = &*pass.vs; + pGS = pass.gs->gs; +#else + pVS = pass.vs->vs; +#endif - // MATRIX - typedef xr_vector<_MatrixItem, render_allocator::helper<_MatrixItem>::result> mapMatrixDirect; + pPS = pass.ps->ps; - struct mapMatrixItems : public mapMatrixDirect - { - float ssa; - }; +#ifdef USE_DX11 + pHS = pass.hs->sh; + pDS = pass.ds->sh; +#endif - struct mapMatrixTextures : public FixedMAP - { - float ssa; - }; + pCS = pass.constants._get(); + pState = pass.state->state; + pTextures = pass.T._get(); - struct mapMatrixStates : public FixedMAP - { - float ssa; - }; + // Build sort key + // Optimized grouping based on profiling, example: + // States:4, GS:0, HS:0, DS:0 they are pretty much unused and/or unchanged + // VS:13, PS:28, CS:93, Tex:179. Grouping based on increasing change of state + // Low key is used just for sorting + u64 keyHigh = 0; + u64 keyLow = 0; + + keyHigh |= ((u64)pState >> 4 & 0xFFFF) << 48; - struct mapMatrixCS : public FixedMAP - { - float ssa; - }; -#ifdef USE_DX11 - struct mapMatrixAdvStages - { - hs_type hs; - ds_type ds; - mapMatrixCS mapCS; - }; - struct mapMatrixPS : public FixedMAP { float ssa; }; -#else - struct mapMatrixPS : public FixedMAP - { - float ssa; - }; -#endif // USE_DX11 #if defined(USE_DX10) || defined(USE_DX11) - struct mapMatrixGS : public FixedMAP { float ssa; }; - struct mapMatrixVS : public FixedMAP { }; -#else // USE_DX10 - struct mapMatrixVS : public FixedMAP - { + keyHigh |= ((u64)pGS >> 4 & 0xFFFF) << 32; +#endif + +#ifdef USE_DX11 + keyHigh |= ((u64)pHS >> 4 & 0xFFFF) << 16; + keyHigh |= ((u64)pDS >> 4 & 0xFFFF); +#endif + + keyLow |= ((u64)pVS >> 4 & 0xFFFF) << 48; + keyLow |= ((u64)pPS >> 4 & 0xFFFF) << 32; + keyLow |= ((u64)pCS >> 4 & 0xFFFF) << 16; + keyLow |= ((u64)pTextures >> 4 & 0xFFFF); + + sortKey = { keyHigh, keyLow }; + } + + bool operator<(const RenderPacket& other) const noexcept + { + return sortKey < other.sortKey; + } }; -#endif // USE_DX10 - typedef mapMatrixVS mapMatrix_T; - typedef mapMatrix_T mapMatrixPasses_T[SHADER_PASSES_MAX]; - // Top level - typedef FixedMAP mapSorted_T; - typedef mapSorted_T::TNode mapSorted_Node; + using RenderQueue = xr_vector::result>; + using RenderQueueArray = xr_array, 2>; + + struct DynamicSceneRgraph + { + template + struct mapSorted + { + mapDSGraphItems Sorted; + + mapDSGraphItems Wmark; + mapDSGraphItems Emissive; + mapDSGraphItems Distort; + }; - typedef FixedMAP mapHUD_T; - typedef mapHUD_T::TNode mapHUD_Node; + mapSorted mapStaticSorted; + mapSorted mapDynamicSorted; -#if defined(USE_DX11) - typedef FixedMAP mapScopeHUD_T; // Redotix99: for 3D Shader Based Scopes - typedef mapScopeHUD_T::TNode mapScopeHUD_T_Node; -#endif + RenderQueueArray mapStaticPasses; + RenderQueueArray mapDynamicPasses; - typedef FixedMAP HUDMask_T; - typedef HUDMask_T::TNode HUDMask_Node; + mapDSGraphItems mapHUD; + mapSorted mapHUDSorted; - typedef FixedMAP mapLOD_T; - typedef mapLOD_T::TNode mapLOD_Node; + mapDSGraphItems mapLOD; - typedef FixedMAP mapLandscape_T; - typedef mapLandscape_T::TNode mapLandscape_Node; + // Anomaly + mapDSGraphItems mapCamAttached; + mapSorted mapCamAttachedSorted; + mapDSGraphItems mapWater; +#ifdef USE_DX11 + mapDSGraphItems mapScopeHUDSorted; + mapDSGraphItems mapScopeHUD; +#endif + template + IC void clear_graph(RenderQueueArray& queue, u32 _priority) + { + PROF_EVENT("r_dsgraph_clear_graph"); + for (u32 iPass = 0; iPass < SHADER_PASSES_MAX; ++iPass) + { + if constexpr (free) + queue[_priority][iPass].clear_and_free(); + else + queue[_priority][iPass].clear(); + } + } + + template + IC void clear_dynamic() + { + clear_graph(mapDynamicPasses, 0); + clear_graph(mapDynamicPasses, 1); + + if constexpr (free) + { + mapDynamicSorted.Wmark.clear_and_free(); + mapDynamicSorted.Emissive.clear_and_free(); + mapDynamicSorted.Sorted.clear_and_free(); + mapDynamicSorted.Distort.clear_and_free(); + } + else + { + mapDynamicSorted.Wmark.clear(); + mapDynamicSorted.Emissive.clear(); + mapDynamicSorted.Sorted.clear(); + mapDynamicSorted.Distort.clear(); + } + } + + template + IC void clear_static() + { + clear_graph(mapStaticPasses, 0); + clear_graph(mapStaticPasses, 1); + + if constexpr (free) + { + mapStaticSorted.Wmark.clear_and_free(); + mapStaticSorted.Emissive.clear_and_free(); + mapStaticSorted.Sorted.clear_and_free(); + mapStaticSorted.Distort.clear_and_free(); + } + else + { + mapStaticSorted.Wmark.clear(); + mapStaticSorted.Emissive.clear(); + mapStaticSorted.Sorted.clear(); + mapStaticSorted.Distort.clear(); + } + } + + template + IC void clear_hud() + { + if constexpr (free) + { + mapHUD.clear_and_free(); + mapHUDSorted.Wmark.clear_and_free(); + mapHUDSorted.Emissive.clear_and_free(); + mapHUDSorted.Sorted.clear_and_free(); + mapHUDSorted.Distort.clear_and_free(); + mapCamAttached.clear_and_free(); + mapCamAttachedSorted.Wmark.clear_and_free(); + mapCamAttachedSorted.Emissive.clear_and_free(); + mapCamAttachedSorted.Sorted.clear_and_free(); + mapCamAttachedSorted.Distort.clear_and_free(); - typedef FixedMAP mapWater_T; - typedef mapWater_T::TNode mapWater_Node; +#ifdef USE_DX11 + mapScopeHUD.clear_and_free(); + mapScopeHUDSorted.clear_and_free(); +#endif + } + else + { + mapHUD.clear(); + mapHUDSorted.Wmark.clear(); + mapHUDSorted.Emissive.clear(); + mapHUDSorted.Sorted.clear(); + mapHUDSorted.Distort.clear(); + mapCamAttached.clear(); + mapCamAttachedSorted.Wmark.clear(); + mapCamAttachedSorted.Emissive.clear(); + mapCamAttachedSorted.Sorted.clear(); + mapCamAttachedSorted.Distort.clear(); +#ifdef USE_DX11 + mapScopeHUD.clear(); + mapScopeHUDSorted.clear(); +#endif + } + } + + template + IC void clear_lods() + { + if constexpr (free) + mapLOD.clear_and_free(); + else + mapLOD.clear(); + } + + template + IC void clear() + { + clear_dynamic(); + clear_static(); + clear_hud(); + clear_lods(); + if constexpr (free) + mapWater.clear_and_free(); + else + mapWater.clear(); + } + }; }; diff --git a/src/Layers/xrRender/r__occlusion.cpp b/src/Layers/xrRender/r__occlusion.cpp index 1fc7d19205..5deed54d87 100644 --- a/src/Layers/xrRender/r__occlusion.cpp +++ b/src/Layers/xrRender/r__occlusion.cpp @@ -3,6 +3,8 @@ #include "QueryHelper.h" +extern ECORE_API BOOL occq_debug; + R_occlusion::R_occlusion(void) { enabled = TRUE; @@ -15,7 +17,7 @@ R_occlusion::~R_occlusion(void) void R_occlusion::occq_create(u32 limit) { - enabled = strstr(Core.Params, "-no_occq") ? FALSE : TRUE; + enabled = !Core.ParamsData.test(ECoreParams::no_occq); pool.reserve(limit); used.reserve(limit); fids.reserve(limit); @@ -46,16 +48,51 @@ void R_occlusion::occq_destroy() fids.clear(); } +void R_occlusion::occq_refresh() +{ + if (!enabled) return; + + PROF_EVENT("R_occlusion::occq_refresh"); + if (!used.empty()) + { + while (!used.empty()) { + _RELEASE(used.back().Q); + used.pop_back (); + } + used.clear (); + } + if (!fids.empty()) + fids.clear (); +} + +void R_occlusion::occq_stats() +{ + if (occq_debug) + Msg("R_occlusion::occq_stats: pool: %d fids: %d used: %d", pool.size(), fids.size(), used.size()); +} + u32 R_occlusion::occq_begin(u32& ID) { + PROF_EVENT("R_occlusion::occq_begin"); if (!enabled) return 0; // Igor: prevent release crash if we issue too many queries if (pool.empty()) { - // if ((Device.dwFrame % 40) == 0) - // Msg(" RENDER [Warning]: Too many occlusion queries were issued(>1536)!!!"); + if (occq_debug && Device.dwFrame % 40 == 0) + Msg(" RENDER [Warning]: Too many occlusion queries were issued(>1536)!!!"); ID = iInvalidHandle; + + //HACK: recreate HWOCC + occq_destroy(); + occq_create(occq_size); + + if (pool.empty()) //error in recreating stage :( + { + occq_destroy(); + enabled = FALSE; + } + return 0; } @@ -84,6 +121,7 @@ u32 R_occlusion::occq_begin(u32& ID) void R_occlusion::occq_end(u32& ID) { + PROF_EVENT("R_occlusion::occq_end"); if (!enabled) return; // Igor: prevent release crash if we issue too many queries @@ -96,6 +134,7 @@ void R_occlusion::occq_end(u32& ID) R_occlusion::occq_result R_occlusion::occq_get(u32& ID) { + PROF_EVENT("R_occlusion::occq_get"); if (!enabled) return 0xffffffff; // Igor: prevent release crash if we issue too many queries @@ -112,6 +151,7 @@ R_occlusion::occq_result R_occlusion::occq_get(u32& ID) VERIFY2(IDsize()>6) { + F.SimplifyPoly_AABB(poly,P); + P.build_precise ((*poly)[0],(*poly)[1],(*poly)[2]); + } + + // Check plane orientation relative to viewer + // and reverse if needed + if (P.classify(vBase)<0) + { + std::reverse(poly->begin(),poly->end()); + P.build_precise ((*poly)[0],(*poly)[1],(*poly)[2]); + } + + // Base creation + F.CreateFromPoints(poly->begin(),poly->size(),vBase); + + // Near clipping plane + F._add (P); + + // Far clipping plane + Fmatrix &M = mFullXFORM; + P.n.x = -(M._14 - M._13); + P.n.y = -(M._24 - M._23); + P.n.z = -(M._34 - M._33); + P.d = -(M._44 - M._43); + float denom = 1.0f / P.n.magnitude(); + P.n.x *= denom; + P.n.y *= denom; + P.n.z *= denom; + P.d *= denom; + F._add (P); + + return F; +} + +void CSector::traverse(CFrustum &&F, CDSGraphManager& DM) { + PROF_EVENT("CSector::traverse") + const bool dbg_enabled = PortalTraverseDbg_Enabled(); + PortalTraverseDebugStats* dbg = dbg_enabled ? &PortalTraverseDbg_Get() : nullptr; + const bool opt_bucket = PortalTraverseDbg_IsOptions(DM.i_options); + if (dbg) + { + ++dbg->traverse_calls; + if (opt_bucket) + ++dbg->traverse_calls_with_options; + else + ++dbg->traverse_calls_without_options; + } + // Register traversal process - if (r_marker != PortalTraverser.i_marker) + auto SNODE = DM.m_sector_frustums.insert(this); + SNODE->val.first.push_back(F); + if (dbg) { - r_marker = PortalTraverser.i_marker; - PortalTraverser.r_sectors.push_back(this); - r_frustums.clear(); - r_scissors.clear(); + ++dbg->frustums_pushed; + if (opt_bucket) + ++dbg->frustums_pushed_opt; + else + ++dbg->frustums_pushed_noopt; + + const u32 frustum_count = u32(SNODE->val.first.size()); + if (frustum_count > dbg->max_frustums_in_sector) + dbg->max_frustums_in_sector = frustum_count; + if (opt_bucket) + { + if (frustum_count > dbg->max_frustums_in_sector_opt) + dbg->max_frustums_in_sector_opt = frustum_count; + } + else + { + if (frustum_count > dbg->max_frustums_in_sector_noopt) + dbg->max_frustums_in_sector_noopt = frustum_count; + } } - r_frustums.push_back(F); - r_scissors.push_back(R_scissor); + // If the map reallocates, SNODE becomes invalid, but the Index stays correct. + u32 snode_idx = DM.m_sector_frustums.get_index(SNODE); + + Fvector& cam_pos = Device.vCameraPosition_saved; + float test_sphere_r = VIEWPORT_NEAR + EPS_L; // Search visible portals and go through them - sPoly S, D; - for (u32 I = 0; I < m_portals.size(); I++) + for (CPortal* PORTAL : m_portals) { - if (m_portals[I]->marker == PortalTraverser.i_marker) continue; + if (dbg) + { + ++dbg->portals_checked; + if (opt_bucket) + ++dbg->portals_checked_opt; + else + ++dbg->portals_checked_noopt; + } - CPortal* PORTAL = m_portals[I]; - CSector* pSector; + // Refresh pointer before use (in case previous loop iteration realloc'd) + SNODE = DM.m_sector_frustums.get_node(snode_idx); - // Select sector (allow intersecting portals to be finely classified) - if (PORTAL->bDualRender) + if (SNODE->val.second.find(PORTAL)) { - pSector = PORTAL->getSector(this); + if (dbg) + ++dbg->portals_skipped_already_visited; + continue; } - else + // Early-out sphere + if (!F.testSphere_dirty(PORTAL->S.P, PORTAL->S.R)) { - pSector = PORTAL->getSectorBack(PortalTraverser.i_vBase); - if (pSector == this) continue; - if (pSector == PortalTraverser.i_start) continue; + if (dbg) + ++dbg->portals_rejected_sphere; + continue; } - // Early-out sphere - if (!F.testSphere_dirty(PORTAL->S.P, PORTAL->S.R)) continue; + CSector* pSector = nullptr; + + // Select sector (allow intersecting portals to be finely classified) + if (PORTAL->S.P.distance_to(cam_pos) < PORTAL->S.R && PORTAL->distance(cam_pos) <= test_sphere_r)//bDualRender + pSector = PORTAL->getSector(this); + else + pSector = PORTAL->getSectorBack(DM.i_vBase); - // SSA (if required) - if (PortalTraverser.i_options & CPortalTraverser::VQ_SSA) + if (pSector == nullptr || pSector == this || pSector == DM.i_start) { - Fvector dir2portal; - dir2portal.sub(PORTAL->S.P, PortalTraverser.i_vBase); - float R = PORTAL->S.R; - float distSQ = dir2portal.square_magnitude(); - float ssa = R * R / distSQ; - dir2portal.div(_sqrt(distSQ)); - ssa *= _abs(PORTAL->P.n.dotproduct(dir2portal)); - if (ssa < r_ssaDISCARD) continue; - - if (PortalTraverser.i_options & CPortalTraverser::VQ_FADE) + if (dbg) + ++dbg->portals_rejected_sector; + continue; + } + + if (DM.i_options & CDSGraphManager::VQ_FADE | CDSGraphManager::VQ_SSA && psDeviceFlags.test(rsDrawPortals)) + DM.fade_portal(PORTAL, 1.f); + else + { + // SSA (if required) + if (DM.i_options & CDSGraphManager::VQ_SSA) { - if (ssa < r_ssaLOD_A) PortalTraverser.fade_portal(PORTAL, ssa); - if (ssa < r_ssaLOD_B) continue ; + Fvector dir2portal; + dir2portal.sub(PORTAL->S.P, DM.i_vBase); + float R = PORTAL->S.R; + float distSQ = dir2portal.square_magnitude(); + float ssa = R * R / distSQ; + dir2portal.div(_sqrt(distSQ)); + ssa *= _abs(PORTAL->P.n.dotproduct(dir2portal)); + if (ssa < r_ssaDISCARD) + { + if (dbg) + ++dbg->portals_rejected_ssa; + continue; + } + + if (DM.i_options & CDSGraphManager::VQ_FADE) + { + if (ssa < r_ssaLOD_A) + DM.fade_portal(PORTAL, ssa); + + if (ssa < r_ssaLOD_B) + continue; + } } } // Clip by frustum svector& POLY = PORTAL->getPoly(); - S.assign(&*POLY.begin(), POLY.size()); - D.clear(); - sPoly* P = F.ClipPoly(S, D); - if (0 == P) continue; - - // Scissor and optimized HOM-testing - _scissor scissor; - if (PortalTraverser.i_options & CPortalTraverser::VQ_SCISSOR && (!PORTAL->bDualRender)) - { - // Build scissor rectangle in projection-space - Fbox2 bb; - bb.invalidate(); - float depth = flt_max; - sPoly& p = *P; - for (u32 vit = 0; vit < p.size(); vit++) - { - Fvector4 t; - Fmatrix& M = PortalTraverser.i_mXFORM_01; - Fvector& v = p[vit]; - - t.x = v.x * M._11 + v.y * M._21 + v.z * M._31 + M._41; - t.y = v.x * M._12 + v.y * M._22 + v.z * M._32 + M._42; - t.z = v.x * M._13 + v.y * M._23 + v.z * M._33 + M._43; - t.w = v.x * M._14 + v.y * M._24 + v.z * M._34 + M._44; - t.mul(1.f / t.w); - - if (t.x < bb.min.x) bb.min.x = t.x; - if (t.x > bb.max.x) bb.max.x = t.x; - if (t.y < bb.min.y) bb.min.y = t.y; - if (t.y > bb.max.y) bb.max.y = t.y; - if (t.z < depth) depth = t.z; - } - // Msg ("bb(%s): (%f,%f)-(%f,%f), d=%f", PORTAL->bDualRender?"true":"false",bb.min.x, bb.min.y, bb.max.x, bb.max.y,depth); - if (depth < EPS) - { - scissor = R_scissor; + DM.S.clear(); + DM.S.assign(&*POLY.begin(), POLY.size()); + DM.D.clear(); + sPoly* P = F.ClipPoly(DM.S, DM.D); - // Cull by HOM (slower algo) - if ( - (PortalTraverser.i_options & CPortalTraverser::VQ_HOM) && - (!RImplementation.HOM.visible(*P)) - ) - continue; - } - else - { - // perform intersection (this is just to be sure, it is probably clipped in 3D already) - if (bb.min.x > R_scissor.min.x) scissor.min.x = bb.min.x; - else scissor.min.x = R_scissor.min.x; - if (bb.min.y > R_scissor.min.y) scissor.min.y = bb.min.y; - else scissor.min.y = R_scissor.min.y; - if (bb.max.x < R_scissor.max.x) scissor.max.x = bb.max.x; - else scissor.max.x = R_scissor.max.x; - if (bb.max.y < R_scissor.max.y) scissor.max.y = bb.max.y; - else scissor.max.y = R_scissor.max.y; - scissor.depth = depth; - - // Msg ("scissor: (%f,%f)-(%f,%f)", scissor.min.x, scissor.min.y, scissor.max.x, scissor.max.y); - // Check if box is non-empty - if (scissor.min.x >= scissor.max.x) continue; - if (scissor.min.y >= scissor.max.y) continue; - - // Cull by HOM (faster algo) - if ( - (PortalTraverser.i_options & CPortalTraverser::VQ_HOM) && - (!RImplementation.HOM.visible(scissor, depth)) - ) - continue; - } + if (0 == P) + { + if (dbg) + ++dbg->portals_rejected_clip; + continue; } - else + + // Cull by HOM (slower algo) + if ((DM.i_options & CDSGraphManager::VQ_HOM) && !RImplementation.HOM.visible(*P)) { - scissor = R_scissor; - - // Cull by HOM (slower algo) - if ( - (PortalTraverser.i_options & CPortalTraverser::VQ_HOM) && - (!RImplementation.HOM.visible(*P)) - ) - continue; + if (dbg) + ++dbg->portals_rejected_hom; + continue; } - // Create _new_ frustum and recurse - CFrustum Clip; - Clip.CreateFromPortal(P, PORTAL->P.n, PortalTraverser.i_vBase, PortalTraverser.i_mXFORM); - PORTAL->marker = PortalTraverser.i_marker; - PORTAL->bDualRender = FALSE; - pSector->traverse(Clip, scissor); + if (pSector) + { + // Create _new_ frustum and recurse + SNODE->val.second.insert(PORTAL); + if (dbg) + { + ++dbg->portals_recursed; + if (opt_bucket) + ++dbg->portals_recursed_opt; + else + ++dbg->portals_recursed_noopt; + } + pSector->traverse(CreateFrustumFromPortal(P, DM.i_vBase, DM.i_mXFORM), DM); + } } } @@ -266,7 +263,7 @@ void CSector::load(IReader& fs) { // Assign portal polygons u32 size = fs.find_chunk(fsP_Portals); - R_ASSERT(0==(size&1)); + R_ASSERT(0 == (size & 1)); u32 count = size / 2; m_portals.reserve(count); while (count) @@ -282,7 +279,7 @@ void CSector::load(IReader& fs) { // Assign visual size = fs.find_chunk(fsP_Root); - R_ASSERT(size==4); + R_ASSERT(size == 4); m_root = (dxRender_Visual*)RImplementation.getVisual(fs.r_u32()); } } diff --git a/src/Layers/xrRender/r__sector.h b/src/Layers/xrRender/r__sector.h index 2b35de3253..249f517a86 100644 --- a/src/Layers/xrRender/r__sector.h +++ b/src/Layers/xrRender/r__sector.h @@ -6,19 +6,11 @@ #define _PORTAL_H_ #pragma once +#include "r__dsgraph_types.h" class CPortal; class CSector; - -struct _scissor : public Fbox2 -{ - float depth; -}; - // Connector class CPortal : public IRender_Portal -#ifdef DEBUG - , public pureRender -#endif { private: svector poly; @@ -26,8 +18,7 @@ class CPortal : public IRender_Portal public: Fplane P; Fsphere S; - u32 marker; - BOOL bDualRender; + Fbox BB; void Setup(Fvector* V, int vcnt, CSector* face, CSector* back); @@ -49,73 +40,25 @@ class CPortal : public IRender_Portal } float distance(const Fvector& V) { return _abs(P.classify(V)); } - - CPortal(); - virtual ~CPortal(); - -#ifdef DEBUG - virtual void OnRender (); -#endif + }; class dxRender_Visual; - +class CDSGraphManager; // Main 'Sector' class class CSector : public IRender_Sector { protected: dxRender_Visual* m_root; // whole geometry of that sector xr_vector m_portals; -public: - xr_vector r_frustums; - xr_vector<_scissor> r_scissors; - _scissor r_scissor_merged; - u32 r_marker; public: // Main interface dxRender_Visual* root() { return m_root; } - void traverse(CFrustum& F, _scissor& R); + void traverse(CFrustum&& F, CDSGraphManager& DM); void load(IReader& fs); CSector() { m_root = NULL; } virtual ~CSector(); }; -class CPortalTraverser -{ -public: - enum - { - VQ_HOM = (1 << 0), - VQ_SSA = (1 << 1), - VQ_SCISSOR = (1 << 2), - VQ_FADE = (1 << 3), - // requires SSA to work - }; - -public: - u32 i_marker; // input - u32 i_options; // input: culling options - Fvector i_vBase; // input: "view" point - Fmatrix i_mXFORM; // input: 4x4 xform - Fmatrix i_mXFORM_01; // - CSector* i_start; // input: starting point - xr_vector r_sectors; // result - xr_vector> f_portals; // - ref_shader f_shader; - ref_geom f_geom; -public: - CPortalTraverser(); - void initialize(); - void destroy(); - void traverse(IRender_Sector* start, CFrustum& F, Fvector& vBase, Fmatrix& mXFORM, u32 options); - void fade_portal(CPortal* _p, float ssa); - void fade_render(); -#ifdef DEBUG - void dbg_draw (); -#endif -}; - -extern CPortalTraverser PortalTraverser; - #endif // !defined(AFX_PORTAL_H__1FC2D371_4A19_49EA_BD1E_2D0F8DEBBF15__INCLUDED_) diff --git a/src/Layers/xrRender/r__sector_detect.cpp b/src/Layers/xrRender/r__sector_detect.cpp new file mode 100644 index 0000000000..e3436f055a --- /dev/null +++ b/src/Layers/xrRender/r__sector_detect.cpp @@ -0,0 +1,208 @@ +#include "stdafx.h" +#include "FHierrarhyVisual.h" +#include "r__sector.h" + +#if (RENDER==R_R4) +#include "r4.h" +#elif (RENDER==R_R3) +#include "r3.h" +#elif (RENDER==R_R2) +#include "r2.h" +#elif (RENDER==R_R1) +#include "FStaticRender.h" +#endif + +int CRender::translateSector(IRender_Sector* pSector) +{ + if (!pSector) + return -1; + + for (u32 i = 0; i < Sectors.size(); ++i) + { + if (Sectors[i] == pSector) + return i; + } + + FATAL("Sector was not found!"); + NODEFAULT; + +#ifdef DEBUG + return (-1); +#endif // #ifdef DEBUG +} + +IRender_Sector* CRender::detectSector(const Fvector& P) +{ + IRender_Sector* S = NULL; + Fvector dir; + + dir.set(0, -1, 0); + S = detectSector(P, dir); + if (NULL == S) + { + dir.set(0, 1, 0); + S = detectSector(P, dir); + } + return S; +} + +thread_local xrXRC sectors_detect_xrc; +IRender_Sector* CRender::detectLastSector(const Fvector& P) +{ + if (SectorsCount() == 1) + return pOutdoorSector; + + static auto detectSector = [](const Fvector& P, Fvector& dir) -> IRender_Sector* + { + sectors_detect_xrc.ray_options(CDB::OPT_ONLYNEAREST); + // Portals model + if (RImplementation.rmPortals) + { + sectors_detect_xrc.ray_query(RImplementation.rmPortals, P, dir, 1000.f); + if (sectors_detect_xrc.r_count()) { + CDB::RESULT* RP = sectors_detect_xrc.r_begin(); + CDB::TRI* pTri = RImplementation.rmPortals->get_tris() + RP->id; + CPortal* pPortal = (CPortal*)RImplementation.Portals[pTri->dummy]; + CSector* S = pPortal->getSectorFacing(P); + FHierrarhyVisual* pV = (FHierrarhyVisual*)S->root(); + if (pV) + { + if (pV->vis.box.contains(P)) + return S; + } + } + } + + // Geometry model + sectors_detect_xrc.ray_query(g_pGameLevel->ObjectSpace.GetStaticModel(), P, dir, 1000.f); + if (sectors_detect_xrc.r_count()) { + CDB::RESULT* RP = sectors_detect_xrc.r_begin(); + return RImplementation.getSector(RP->sector); + } + + return nullptr; + }; + + IRender_Sector* S = nullptr; + Fvector dir; + + dir.set(0, -1, 0); + S = detectSector(P, dir); + if (nullptr == S) + { + dir.set(0, 1, 0); + S = detectSector(P, dir); + } + return S; + +} + +IRender_Sector* CRender::detectSector(const Fvector& P, Fvector& dir) +{ + if (SectorsCount() == 1) + return pOutdoorSector; + + sectors_detect_xrc.ray_options(CDB::OPT_ONLYNEAREST); + // Portals model + int id1 = -1; + float range1 = 500.f; + if (rmPortals) + { + sectors_detect_xrc.ray_query(rmPortals, P, dir, range1); + if (sectors_detect_xrc.r_count()) + { + CDB::RESULT* RP1 = sectors_detect_xrc.r_begin(); + id1 = RP1->id; + range1 = RP1->range; + } + } + + // Geometry model + int id2 = -1; + float range2 = range1; + sectors_detect_xrc.ray_query(g_pGameLevel->ObjectSpace.GetStaticModel(), P, dir, range2); + if (sectors_detect_xrc.r_count()) + { + CDB::RESULT* RP2 = sectors_detect_xrc.r_begin(); + id2 = RP2->id; + range2 = RP2->range; + } + + // Select ID + int ID; + if (id1 >= 0) + { + if (id2 >= 0) ID = (range1 <= range2 + EPS) ? id1 : id2; // both was found + else ID = id1; // only id1 found + } + else if (id2 >= 0) ID = id2; // only id2 found + else return 0; + + if (ID == id1) + { + // Take sector, facing to our point from portal + CDB::TRI* pTri = rmPortals->get_tris() + ID; + CPortal* pPortal = (CPortal*)Portals[pTri->dummy]; + return pPortal->getSectorFacing(P); + } + else + { + // Take triangle at ID and use it's Sector + CDB::TRI* pTri = g_pGameLevel->ObjectSpace.GetStaticTris() + ID; + return getSector(pTri->sector); + } +} + +void CRender::detectSectors_sphere(CSector* sector, FixedSet& m_sectors, const Fvector& b_center, const Fvector& b_dim) +{ + m_sectors.clear(); + m_sectors.insert(sector); + if (rmPortals) + { + sectors_detect_xrc.box_options(CDB::OPT_FULL_TEST); + sectors_detect_xrc.box_query(rmPortals, b_center, b_dim); + for (int K = 0; K < sectors_detect_xrc.r_count(); K++) + { + CPortal* pPortal = (CPortal*)Portals[rmPortals->get_tris()[sectors_detect_xrc.r_begin()[K].id].dummy]; + + if (!pPortal) + continue; + + CSector* pFront = pPortal->Front(); + CSector* pBack = pPortal->Back(); + + if (pFront) + m_sectors.insert(pFront); + + if (pBack) + m_sectors.insert(pBack); + } + } +} + +void CRender::detectSectors_frustum(CSector* sector, FixedSet& m_sectors, CFrustum* _frustum) +{ + m_sectors.clear(); + m_sectors.insert(sector); + if (rmPortals) + { + sectors_detect_xrc.frustum_options(CDB::OPT_FULL_TEST); + sectors_detect_xrc.frustum_query(rmPortals, *_frustum); + for (int K = 0; K < sectors_detect_xrc.r_count(); K++) + { + CPortal* pPortal = (CPortal*)Portals[rmPortals->get_tris()[sectors_detect_xrc.r_begin()[K].id].dummy]; + + if (!pPortal) + continue; + + CSector* pFront = pPortal->Front(); + CSector* pBack = pPortal->Back(); + + if (pFront) + m_sectors.insert(pFront); + + if (pBack) + m_sectors.insert(pBack); + } + } +} diff --git a/src/Layers/xrRender/r__sector_traversal.cpp b/src/Layers/xrRender/r__sector_traversal.cpp deleted file mode 100644 index aa5c12d9db..0000000000 --- a/src/Layers/xrRender/r__sector_traversal.cpp +++ /dev/null @@ -1,169 +0,0 @@ -#include "stdafx.h" -#include "../../xrEngine/igame_persistent.h" -#include "../../xrEngine/environment.h" -#include "fvf.h" - -CPortalTraverser PortalTraverser; - -CPortalTraverser::CPortalTraverser() -{ - i_marker = 0xffffffff; -} - -#ifdef DEBUG -xr_vector dbg_sectors; -#endif - -void CPortalTraverser::traverse(IRender_Sector* start, CFrustum& F, Fvector& vBase, Fmatrix& mXFORM, u32 options) -{ - Fmatrix m_viewport_01 = { - 1.f / 2.f, 0.0f, 0.0f, 0.0f, - 0.0f, -1.f / 2.f, 0.0f, 0.0f, - 0.0f, 0.0f, 1.0f, 0.0f, - 1.f / 2.f + 0 + 0, 1.f / 2.f + 0 + 0, 0.0f, 1.0f - }; - - if (options & VQ_FADE) - { - f_portals.clear(); - f_portals.reserve(16); - } - - VERIFY(start); - i_marker ++; - i_options = options; - i_vBase = vBase; - i_mXFORM = mXFORM; - i_mXFORM_01.mul(m_viewport_01, mXFORM); - i_start = (CSector*)start; - r_sectors.clear(); - _scissor scissor; - scissor.set(0, 0, 1, 1); - scissor.depth = 0; - i_start->traverse(F, scissor); - - if (options & VQ_SCISSOR) - { - // dbg_sectors = r_sectors; - // merge scissor info - for (u32 s = 0; s < r_sectors.size(); s++) - { - CSector* S = (CSector*)r_sectors[s]; - S->r_scissor_merged.invalidate(); - S->r_scissor_merged.depth = flt_max; - for (u32 it = 0; it < S->r_scissors.size(); it++) - { - S->r_scissor_merged.merge(S->r_scissors[it]); - if (S->r_scissors[it].depth < S->r_scissor_merged.depth) - S->r_scissor_merged.depth = S->r_scissors[it].depth; - } - } - } -} - -void CPortalTraverser::fade_portal(CPortal* _p, float ssa) -{ - f_portals.push_back(mk_pair(_p, ssa)); -} - -void CPortalTraverser::initialize() -{ - f_shader.create("portal"); - f_geom.create(FVF::F_L, RCache.Vertex.Buffer(), 0); -} - -void CPortalTraverser::destroy() -{ - f_geom.destroy(); - f_shader.destroy(); -} - -ICF bool psort_pred(const std::pair& _1, const std::pair& _2) -{ - float d1 = PortalTraverser.i_vBase.distance_to_sqr(_1.first->S.P); - float d2 = PortalTraverser.i_vBase.distance_to_sqr(_2.first->S.P); - return d2 > d1; // descending, back to front -} - -extern float r_ssaDISCARD; -extern float r_ssaLOD_A, r_ssaLOD_B; - -void CPortalTraverser::fade_render() -{ - if (f_portals.empty()) return; - - // re-sort, back to front - std::sort(f_portals.begin(), f_portals.end(), psort_pred); - - // calc poly-count - u32 _pcount = 0; - for (u32 _it = 0; _it < f_portals.size(); _it++) _pcount += f_portals[_it].first->getPoly().size() - 2; - - // fill buffers - u32 _offset = 0; - FVF::L* _v = (FVF::L*)RCache.Vertex.Lock(_pcount * 3, f_geom.stride(), _offset); - float ssaRange = r_ssaLOD_A - r_ssaLOD_B; - Fvector _ambient_f = g_pGamePersistent->Environment().CurrentEnv->ambient; - u32 _ambient = color_rgba_f(_ambient_f.x, _ambient_f.y, _ambient_f.z, 0); - for (u32 _it = 0; _it < f_portals.size(); _it++) - { - std::pair& fp = f_portals[_it]; - CPortal* _P = fp.first; - float _ssa = fp.second; - float ssaDiff = _ssa - r_ssaLOD_B; - float ssaScale = ssaDiff / ssaRange; - int iA = iFloor((1 - ssaScale) * 255.5f); - clamp(iA, 0, 255); - u32 _clr = subst_alpha(_ambient, u32(iA)); - - // fill polys - u32 _polys = _P->getPoly().size() - 2; - for (u32 _pit = 0; _pit < _polys; _pit++) - { - _v->set(_P->getPoly()[0], _clr); - _v++; - _v->set(_P->getPoly()[_pit + 1], _clr); - _v++; - _v->set(_P->getPoly()[_pit + 2], _clr); - _v++; - } - } - RCache.Vertex.Unlock(_pcount * 3, f_geom.stride()); - - // render - RCache.set_xform_world(Fidentity); - RCache.set_Shader(f_shader); - RCache.set_Geometry(f_geom); - RCache.set_CullMode(CULL_NONE); - RCache.Render(D3DPT_TRIANGLELIST, _offset, _pcount); - RCache.set_CullMode(CULL_CCW); - - // cleanup - f_portals.clear(); -} - -#ifdef DEBUG -void CPortalTraverser::dbg_draw () -{ - RCache.OnFrameEnd (); - RCache.set_xform_world (Fidentity); - RCache.set_xform_view (Fidentity); - RCache.set_xform_project(Fidentity); - for (u32 s=0; sr_scissor_merged; - bb.min.x = bb.min.x * 2 - 1; - bb.max.x = bb.max.x * 2 - 1; - bb.min.y = (1-bb.min.y) * 2 - 1; - bb.max.y = (1-bb.max.y) * 2 - 1; - - verts[0].set(bb.min.x,bb.min.y,EPS,0xffffffff); - verts[1].set(bb.max.x,bb.min.y,EPS,0xffffffff); - verts[2].set(bb.max.x,bb.max.y,EPS,0xffffffff); - verts[3].set(bb.min.x,bb.max.y,EPS,0xffffffff); - verts[4].set(bb.min.x,bb.min.y,EPS,0xffffffff); - RCache.dbg_Draw (D3DPT_LINESTRIP,verts,4); - } -} -#endif diff --git a/src/Layers/xrRender/r_constants.cpp b/src/Layers/xrRender/r_constants.cpp index 6b7ba05643..6f1a611903 100644 --- a/src/Layers/xrRender/r_constants.cpp +++ b/src/Layers/xrRender/r_constants.cpp @@ -30,14 +30,25 @@ void R_constant_table::fatal(LPCSTR S) FATAL(S); } +void R_constant_table::_copy(const R_constant_table& Other) +{ + table = Other.table; +#if defined(USE_DX10) || defined(USE_DX11) + m_CBTable = Other.m_CBTable; +#endif +} + + // predicates -IC bool p_sort(const ref_constant& C1, const ref_constant& C2) noexcept +IC bool p_sort_constants(const ref_constant& C1, const ref_constant& C2) noexcept { return C1->name < C2->name; } R_constant* R_constant_table::get(LPCSTR S) { + PROF_EVENT("R_constant_table::get LPCSTR"); + // demonized: make shared_str and use override, str most likely already exists, faster shared_str s(S); return get(s); @@ -45,6 +56,7 @@ R_constant* R_constant_table::get(LPCSTR S) R_constant* R_constant_table::get(shared_str& S) { + PROF_EVENT("R_constant_table::get shared_str"); // demonized: use lower_bound for shared_str search, sorted by pointer static auto sortFunc = [](const ref_constant& C, const shared_str& S) noexcept { return C->name < S; }; auto it = std::lower_bound(table.begin(), table.end(), S, sortFunc); @@ -191,7 +203,7 @@ BOOL R_constant_table::parse(void* _desc, u32 destination) L.cls = r_type; } } - std::sort(table.begin(), table.end(), p_sort); + std::sort(table.begin(), table.end(), p_sort_constants); return TRUE; } #endif // USE_DX10 @@ -247,7 +259,7 @@ void R_constant_table::merge(R_constant_table* T) std::move(table_tmp.begin(), table_tmp.end(), std::back_inserter(table)); // Sort - std::sort(table.begin(), table.end(), p_sort); + std::sort(table.begin(), table.end(), p_sort_constants); } #if defined(USE_DX10) || defined(USE_DX11) diff --git a/src/Layers/xrRender/r_constants.h b/src/Layers/xrRender/r_constants.h index 626409e798..c9e9b93fe1 100644 --- a/src/Layers/xrRender/r_constants.h +++ b/src/Layers/xrRender/r_constants.h @@ -130,9 +130,8 @@ struct ECORE_API R_constant : public xr_resource R_constant_load samp; R_constant_setup* handler; - R_constant() : type(u16(-1)), destination(0), handler(NULL) - { - }; + R_constant() : type(u16(-1)), destination(0), handler(nullptr) {}; + //R_constant& operator=(const R_constant& Other) = delete; IC R_constant_load& get_load(u32 destination) { @@ -206,8 +205,12 @@ class ECORE_API R_constant_table : public xr_resource_flagged #endif // USE_DX10 public: + //R_constant_table() = default; ~R_constant_table(); + //R_constant_table& operator=(const R_constant& Other) = delete; + + void _copy(const R_constant_table& Other); void clear(); BOOL parse(void* desc, u32 destination); void merge(R_constant_table* C); @@ -217,7 +220,7 @@ class ECORE_API R_constant_table : public xr_resource_flagged BOOL equal(R_constant_table& C); BOOL equal(R_constant_table* C) { return equal(*C); } BOOL empty() { return 0 == table.size(); } -private: + }; typedef resptr_core> ref_ctable; diff --git a/src/Layers/xrRender/r_sun_cascades.h b/src/Layers/xrRender/r_sun_cascades.h index d6cd659126..4e5a8ef352 100644 --- a/src/Layers/xrRender/r_sun_cascades.h +++ b/src/Layers/xrRender/r_sun_cascades.h @@ -1,16 +1,16 @@ #pragma once +#include "r__dsgraph_types.h" +#include "r__sector.h" namespace sun { struct ray { - ray() - { - } - + ray() = default; ray(Fvector3 const& _P, Fvector3 const& _D): P(_P), D(_D) { } + ~ray() = default; Fvector3 D; Fvector3 P; @@ -18,7 +18,10 @@ namespace sun struct cascade { - cascade() : reset_chain(false) + cascade() : size(0.0f), bias(0.0f), reset_chain(false) + { + } + cascade(const cascade& other) { } @@ -27,5 +30,11 @@ namespace sun float size; float bias; bool reset_chain; + + CFrustum cull_frustum; + Fvector3 cull_COP; + Fmatrix cull_xform; + + CDSGraphManager GMCascade = CDSGraphManager(u32(0), u32(STYPE_RENDERABLE + STYPE_RENDERABLESHADOW), { true,false,false,false,true,false,false }); }; } //namespace sun diff --git a/src/Layers/xrRender/rendertarget_phase_blur.cpp b/src/Layers/xrRender/rendertarget_phase_blur.cpp index 6f2e68c139..5d39f3887d 100644 --- a/src/Layers/xrRender/rendertarget_phase_blur.cpp +++ b/src/Layers/xrRender/rendertarget_phase_blur.cpp @@ -334,6 +334,7 @@ void CRenderTarget::phase_ssfx_ssr() void CRenderTarget::phase_ssfx_volumetric_blur() { + PROF_EVENT("phase_ssfx_volumetric_blur"); // Be careful and clear the buffer ( rt_Generic_2 contain unspeakable stuff if no volumetric is written ) if (!m_bHasActiveVolumetric) @@ -361,8 +362,8 @@ void CRenderTarget::phase_ssfx_volumetric_blur() p0.set(0.0f, 0.0f); p1.set(1.0f, 1.0f); - // Volumetric always at 1/8 res - set_viewport_size(HW.pContext, w / 8, h / 8); + // Volumetric always at volsize res, default 1/8 + set_viewport_size(HW.pContext, w / RImplementation.o.volsize, h / RImplementation.o.volsize); ref_rt* rt_VolBlur[2] = { &rt_ssfx_volumetric_tmp, &rt_ssfx_volumetric }; int pixelsize[4] = { 0, 1, 1, 2 }; // half pixel + pixelsize @@ -385,7 +386,7 @@ void CRenderTarget::phase_ssfx_volumetric_blur() // Draw COLOR RCache.set_Element(s_ssfx_volumetric_blur->E[b % 2]); - RCache.set_c("blur_setup", w / 8, h / 8, pixelsize[b], pixelscale[b]); + RCache.set_c("blur_setup", w / RImplementation.o.volsize, h / RImplementation.o.volsize, pixelsize[b], pixelscale[b]); RCache.set_Geometry(g_combine); RCache.Render(D3DPT_TRIANGLELIST, Offset, 0, 4, 0, 2); } @@ -692,7 +693,8 @@ void CRenderTarget::phase_ssfx_sss_ext(light_Package& LP) for (int slot = 0; slot < 8; slot++) Lights_Array[slot].set(0, 0, 0, 0); - xr_vector LightsSort; + static xr_vector LightsSort; + LightsSort.clear(); bool CheckPackage = true; if (Device.dwFrame > sss_currentframe) @@ -700,12 +702,22 @@ void CRenderTarget::phase_ssfx_sss_ext(light_Package& LP) sss_currentframe = Device.dwFrame + 2; xr_vector& source = LP.v_shadowed; + + // demonized: use whatever omni light visible by checking its parent + // normally it should be omnipart_num 0, but with omnipart_vischeck its not guaranteed, hope its stable + static xr_unordered_flat_set omni_parents; + omni_parents.clear(); for (u32 it = 0; it < source.size(); it++) { light* L = source[it]; + light* parent = L->omipart_parent; - if (L->omnipart_num == 0 && L->range > 1.5f) + if ((L->omnipart_num == 0 || (parent && omni_parents.find(parent) == omni_parents.end())) && L->range > 1.5f) { + light* to_insert = L->omnipart_num == 0 ? L : parent; + if (to_insert) + omni_parents.insert(to_insert); + if (L->distance < 800 && L->flags.bActive) { L->distance_lpos = Device.vCameraPosition.distance_to(L->position); @@ -767,6 +779,7 @@ void CRenderTarget::phase_ssfx_sss_ext(light_Package& LP) LightSlot[FreeSlot] = L; L->sss_id = FreeSlot; + L->sss_remove_latency = 0; L->sss_on_light_destroy.bind(OnLightDestroy); if (L->flags.type == IRender_Light::OMNIPART) @@ -812,15 +825,22 @@ void CRenderTarget::phase_ssfx_sss_ext(light_Package& LP) // Remove Light if (!LightSlot[slot]->flags.bActive || Remove) { - if (LightSlot[slot]->flags.type == IRender_Light::OMNIPART) - LightSlot[slot]->sss_refresh = true; - - LightSlot[slot]->sss_id = -1; - LightSlot[slot]->sss_on_light_destroy.clear(); - LightSlot[slot] = NULL; + // demonized: keep the light pointer for some frames to eliminate flicker, but also check if its actually been disabled + LightSlot[slot]->sss_remove_latency++; + if (!LightSlot[slot]->flags.bActive || LightSlot[slot]->sss_remove_latency > 5) + { + if (LightSlot[slot]->flags.type == IRender_Light::OMNIPART) + LightSlot[slot]->sss_refresh = true; + + LightSlot[slot]->sss_id = -1; + LightSlot[slot]->sss_on_light_destroy.clear(); + LightSlot[slot] = NULL; + } } else { + LightSlot[slot]->sss_remove_latency = 0; + // Update Light Fvector L_pos; diff --git a/src/Layers/xrRender/xrRender_console.cpp b/src/Layers/xrRender/xrRender_console.cpp index aa8636e3d3..4702019d90 100644 --- a/src/Layers/xrRender/xrRender_console.cpp +++ b/src/Layers/xrRender/xrRender_console.cpp @@ -118,7 +118,9 @@ xr_token screenshot_mode_token [ ] = { extern int psSkeletonUpdate; extern float r__dtex_range; -Flags32 ps_r__common_flags = {/*RFLAG_NO_RAM_TEXTURES*/ }; // All renders +//RFLAG_NO_RAM_TEXTURES +//RFLAG_HOM_DYNAMIC +Flags32 ps_r__common_flags = {0}; // All renders //int ps_r__Supersample = 1 ; int ps_r__LightSleepFrames = 10; @@ -143,7 +145,9 @@ float ps_r__GLOD_ssa_start = 256.f; float ps_r__GLOD_ssa_end = 64.f; float ps_r__LOD = 0.75f; //. float ps_r__LOD_Power = 1.5f ; -float ps_r__ssaDISCARD = 3.5f; //RO +float ps_r__ssaDISCARD = 7.f; //RO +float ps_r__ssaDISCARD_exp = 0.5f; // demonized +float ps_r__ssaDISCARD_fade_k = 4.0f; // demonized float ps_r__ssaDONTSORT = 32.f; //RO float ps_r__ssaHZBvsTEX = 96.f; //RO @@ -166,6 +170,7 @@ int ps_r1_SoftwareSkinning = 0; // r1-only // R2 float ps_r2_ssaLOD_A = 64.f; float ps_r2_ssaLOD_B = 48.f; +BOOL ps_r2_particle_dt = FALSE; // R2-specific Flags32 ps_r2_ls_flags = { @@ -175,7 +180,7 @@ Flags32 ps_r2_ls_flags = { | R2FLAG_USE_NVSTENCIL | R2FLAG_EXP_SPLIT_SCENE | R2FLAG_EXP_MT_CALC | R3FLAG_DYN_WET_SURF | R3FLAG_VOLUMETRIC_SMOKE - //| R3FLAG_MSAA + //| R3FLAG_MSAA //| R3FLAG_MSAA_OPT | R2FLAG_DETAIL_BUMP @@ -227,7 +232,7 @@ float ps_r2_ls_depth_scale = 1.00001f; // 1.00001f float ps_r2_ls_depth_bias = -0.001f; // -0.0001f float ps_r2_ls_squality = 1.0f; // 1.00f float ps_r2_sun_tsm_projection = 0.3f; // 0.18f -float ps_r2_sun_tsm_bias = -0.01f; // +float ps_r2_sun_tsm_bias = -0.01f; // float ps_r2_sun_near = 20.f; // 12.0f extern float OLES_SUN_LIMIT_27_01_07; // actually sun_far @@ -241,18 +246,20 @@ float ps_r2_sun_lumscale = 1.0f; // 1.0f float ps_r2_sun_lumscale_hemi = 1.0f; // 1.0f float ps_r2_sun_lumscale_amb = 1.0f; Fvector3 ps_r2_sun_lumscale_color = { 1.f, 1.f, 1.f }; -float ps_r2_gmaterial = 2.2f; // +float ps_r2_gmaterial = 2.2f; // float ps_r2_zfill = 0.25f; // .1f float ps_r2_dhemi_sky_scale = 0.08f; // 1.5f float ps_r2_dhemi_light_scale = 0.2f; float ps_r2_dhemi_light_flow = 0.1f; int ps_r2_dhemi_count = 5; // 5 +int ps_r2_shadow_omnipart_vischeck = 1; int ps_r2_wait_sleep = 0; int ps_r2_qsync = 0; float ps_r2_lt_smooth = 1.f; // 1.f float ps_r2_slight_fade = 0.5f; // 1.f +float ps_r2_shadow_lod_min = 0.02f; ///////lvutner Fvector4 ps_r2_mask_control = {.0f, .0f, .0f, .0f}; // r2-only Fvector ps_r2_drops_control = {.0f, 1.15f, .0f}; // r2-only @@ -481,6 +488,11 @@ int ps_r3_dyn_wet_surf_sm_res = 256; // 256 Flags32 psDeviceFlags2 = { 0 }; Flags32 ps_actor_shadow_flags = {0}; //Swartz: actor shadow +int ps_r__tex_evict_enabled = 0; +int ps_r__tex_evict_age_frames = 1800; +int ps_r__tex_evict_batch_size = 200; +int ps_r__tex_evict_interval = 600; + //AVO: detail draw radius Flags32 ps_common_flags = {0}; // r1-only u32 ps_steep_parallax = 0; @@ -514,9 +526,19 @@ float ps_r2_gloss_factor = 4.0f; float ps_r2_gloss_min = 0.0f; //- Mad Max +// demonized +BOOL occq_debug = FALSE; +BOOL r_blood_decals_on_objects = FALSE; + int opt_static = 2; int opt_dynamic = 2; +int ps_pfx_volumetric_mode = 0; +int ps_r__portal_traverse_stats = 0; + +float r_rain_exp = 1.f; +float r_rain_k = 99.0f; + #ifndef _EDITOR #include "../../xrEngine/xr_ioconsole.h" #include "../../xrEngine/xr_ioc_cmd.h" @@ -1055,7 +1077,7 @@ class CCC_Fog_Reload : public IConsole_Command { public: CCC_Fog_Reload(LPCSTR N) : IConsole_Command(N) { bEmptyArgsHandled = TRUE; }; - virtual void Execute(LPCSTR args) + virtual void Execute(LPCSTR args) { FluidManager.UpdateProfiles(); } @@ -1069,9 +1091,7 @@ void xrRender_initconsole() CMD3(CCC_Preset, "_preset", &ps_Preset, qpreset_token); CMD4(CCC_Integer, "rs_skeleton_update", &psSkeletonUpdate, 2, 128); -#ifdef DEBUG CMD1(CCC_DumpResources, "dump_resources"); -#endif // DEBUG CMD4(CCC_Float, "r__dtex_range", &r__dtex_range, 5, 175); @@ -1089,8 +1109,8 @@ void xrRender_initconsole() CMD4(CCC_Float, "r__ssa_glod_end", &ps_r__GLOD_ssa_end, 16, 96 ); CMD4(CCC_Float, "r__wallmark_shift_pp", &ps_r__WallmarkSHIFT, 0.0f, 1.f ); CMD4(CCC_Float, "r__wallmark_shift_v", &ps_r__WallmarkSHIFT_V, 0.0f, 1.f ); - CMD1(CCC_ModelPoolStat,"stat_models" ); #endif // DEBUG + CMD1(CCC_ModelPoolStat,"stat_models" ); CMD4(CCC_Float, "r__wallmark_ttl", &ps_r__WallmarkTTL, 1.0f, 10.f*60.f); CMD4(CCC_Integer, "r__supersample", &ps_r__Supersample, 1, 8); @@ -1121,10 +1141,15 @@ void xrRender_initconsole() //no ram textures should be enabled by default on r3/r4 if (RENDER == R_R3 || RENDER == R_R4) ps_r__common_flags.set(RFLAG_NO_RAM_TEXTURES, TRUE); + CMD4(CCC_Integer, "r__occq_debug", &occq_debug, 0, 1); + CMD3(CCC_Mask, "r__no_ram_textures", &ps_r__common_flags, RFLAG_NO_RAM_TEXTURES); + CMD3(CCC_Mask, "r__hom_dynamic", &ps_r__common_flags, RFLAG_HOM_DYNAMIC); CMD2(CCC_tf_Aniso, "r__tf_aniso", &ps_r__tf_Anisotropic); // {1..16} CMD2(CCC_tf_MipBias, "r__tf_mipbias", &ps_r__tf_Mipbias); // {-3 +3} + CMD4(CCC_Integer, "r__blood_decals_on_objects", &r_blood_decals_on_objects, 0, 1); + // R1 CMD4(CCC_Float, "r1_ssa_lod_a", &ps_r1_ssaLOD_A, 16, 96); CMD4(CCC_Float, "r1_ssa_lod_b", &ps_r1_ssaLOD_B, 16, 64); @@ -1182,13 +1207,15 @@ void xrRender_initconsole() CMD3(CCC_Token, "r_screenshot_mode", &ps_r_screenshot_token, screenshot_mode_token); + CMD3(CCC_Mask, "r2_mt", &ps_r2_ls_flags, R2FLAG_EXP_MT_CALC); + #ifdef DEBUG CMD3(CCC_Mask, "r2_use_nvdbt", &ps_r2_ls_flags, R2FLAG_USE_NVDBT); - CMD3(CCC_Mask, "r2_mt", &ps_r2_ls_flags, R2FLAG_EXP_MT_CALC); #endif // DEBUG CMD3(CCC_Mask, "r2_sun", &ps_r2_ls_flags, R2FLAG_SUN); CMD3(CCC_Mask, "r2_sun_details", &ps_r2_ls_flags, R2FLAG_SUN_DETAILS); + CMD3(CCC_Mask, "r2_lights_details", &ps_r2_ls_flags, R2FLAG_LIGHTS_DETAILS); CMD3(CCC_Mask, "r2_sun_focus", &ps_r2_ls_flags, R2FLAG_SUN_FOCUS); // CMD3(CCC_Mask, "r2_sun_static", &ps_r2_ls_flags, R2FLAG_SUN_STATIC); // CMD3(CCC_Mask, "r2_exp_splitscene", &ps_r2_ls_flags, R2FLAG_EXP_SPLIT_SCENE); @@ -1304,7 +1331,7 @@ void xrRender_initconsole() CMD4(CCC_Integer, "r__heatvision", &ps_r2_heatvision, 0, 1); //--DSR-- HeatVision CMD3(CCC_Mask, "r2_terrain_z_prepass", &ps_r2_ls_flags, R2FLAG_TERRAIN_PREPASS); //Terrain Z Prepass @Zagolski - + //////////other CMD3(CCC_Mask, "r2_water_reflections", &ps_r2_anomaly_flags, R2_AN_FLAG_WATER_REFLECTIONS); CMD3(CCC_Mask, "r2_mblur_enabled", &ps_r2_anomaly_flags, R2_AN_FLAG_MBLUR); @@ -1315,7 +1342,7 @@ void xrRender_initconsole() CMD4(CCC_Integer, "r2_gi_depth", &ps_r2_GI_depth, 1, 5 ); CMD4(CCC_Integer, "r2_gi_photons", &ps_r2_GI_photons, 8, 256 ); CMD4(CCC_Float, "r2_gi_refl", &ps_r2_GI_refl, EPS_L, 0.99f ); - + //Shader param stuff Fvector4 tw2_min = { -100.f, -100.f, -100.f, -100.f }; Fvector4 tw2_max = { 100.f, 100.f, 100.f, 100.f }; @@ -1327,7 +1354,7 @@ void xrRender_initconsole() CMD4(CCC_Vector4, "shader_param_6", &ps_dev_param_6, tw2_min, tw2_max); CMD4(CCC_Vector4, "shader_param_7", &ps_dev_param_7, tw2_min, tw2_max); CMD4(CCC_Vector4, "shader_param_8", &ps_dev_param_8, tw2_min, tw2_max); - + // Mark Switch CMD4(CCC_Integer, "markswitch_current", &ps_markswitch_current, 0, 32); CMD4(CCC_Integer, "markswitch_count", &ps_markswitch_count, 0, 32); @@ -1340,7 +1367,7 @@ void xrRender_initconsole() CMD4(CCC_Vector4, "s3ds_param_4", &ps_s3ds_param_4, tw2_min, tw2_max); CMD4(CCC_Float, "hud_fov_aim_factor", &hud_fov_aim_factor, 0.0f, 1.0f); - + // Screen Space Shaders CMD4(CCC_Vector4, "ssfx_floravariation", &ps_ssfx_floravariation, Fvector4().set(0, 0, 0, 0), Fvector4().set(10, 1, 10, 1)); CMD4(CCC_Vector4, "ssfx_taa", &ps_ssfx_taa, Fvector4().set(0, 0, 0, 0), Fvector4().set(1, 1, 2, 1)); @@ -1380,7 +1407,7 @@ void xrRender_initconsole() CMD4(CCC_Integer, "ssfx_ssr_quality", &ps_ssfx_ssr_quality, 0, 5); CMD4(CCC_Vector4, "ssfx_ssr", &ps_ssfx_ssr, Fvector4().set(1, 0, 0, 0), Fvector4().set(2, 1, 1, 1)); CMD4(CCC_Vector4, "ssfx_ssr_2", &ps_ssfx_ssr_2, Fvector4().set(0, 0, 0, 0), Fvector4().set(2, 2, 2, 2)); - + CMD4(CCC_Vector4, "ssfx_terrain_quality", &ps_ssfx_terrain_quality, Fvector4().set(0, 0, 0, 0), Fvector4().set(40, 0, 0, 0)); CMD4(CCC_Vector4, "ssfx_terrain_offset", &ps_ssfx_terrain_offset, Fvector4().set(-1, -1, -1, -1), Fvector4().set(1, 1, 1, 1)); @@ -1419,11 +1446,11 @@ void xrRender_initconsole() CMD4(CCC_Vector4, "ssfx_grass_shadows", &ps_ssfx_grass_shadows, Fvector4().set(0, 0, 0, 0), Fvector4().set(3, 1, 100, 100)); CMD4(CCC_ssfx_cascades, "ssfx_shadow_cascades", &ps_ssfx_shadow_cascades, Fvector3().set(1.0f, 1.0f, 1.0f), Fvector3().set(300, 300, 300)); - + CMD4(CCC_Vector4, "ssfx_grass_interactive", &ps_ssfx_grass_interactive, Fvector4().set(0, 0, 0, 0), Fvector4().set(1, 15, 5000, 1)); CMD4(CCC_Vector4, "ssfx_int_grass_params_1", &ps_ssfx_int_grass_params_1, Fvector4().set(0, 0, 0, 0), Fvector4().set(5, 5, 5, 60)); CMD4(CCC_Vector4, "ssfx_int_grass_params_2", &ps_ssfx_int_grass_params_2, Fvector4().set(0, 0, 0, 0), Fvector4().set(5, 20, 1, 5)); - + CMD4(CCC_Vector4, "ssfx_wpn_dof_1", &ps_ssfx_wpn_dof_1, tw2_min, tw2_max); CMD4(CCC_Float, "ssfx_wpn_dof_2", &ps_ssfx_wpn_dof_2, 0, 1); @@ -1451,12 +1478,17 @@ void xrRender_initconsole() CMD4(CCC_Float, "particle_update_mod", &ps_particle_update_coeff, 0.04f, 10.f); + CMD4(CCC_Float, "r__rain_exp", &r_rain_exp, 0.1f, 5.f); + CMD4(CCC_Float, "r__rain_k", &r_rain_k, 10.f, 300.f); + // Geometry optimization CMD4(CCC_Integer, "r__optimize_static_geom", &opt_static, 0, 4); CMD4(CCC_Integer, "r__optimize_dynamic_geom", &opt_dynamic, 0, 4); + CMD4(CCC_Integer, "r__portal_traverse_stats", &ps_r__portal_traverse_stats, 0, 1); psDeviceFlags2.set(rsOptShadowGeom, TRUE); CMD3(CCC_Mask, "r__optimize_shadow_geom", &psDeviceFlags2, rsOptShadowGeom); + CMD4(CCC_Integer, "r2_shadow_omnipart_vischeck", &ps_r2_shadow_omnipart_vischeck, 0, 1); CMD4(CCC_Integer, "r2_wait_sleep", &ps_r2_wait_sleep, 0, 1); CMD4(CCC_Integer, "r2_qsync", &ps_r2_qsync, 0, 1); @@ -1472,7 +1504,7 @@ void xrRender_initconsole() #endif // DEBUG CMD3(CCC_Mask, "r2_shadow_cascede_old", &ps_r2_ls_flags_ext, R2FLAGEXT_SUN_OLD); - + CMD4(CCC_Float, "r2_ls_depth_scale", &ps_r2_ls_depth_scale, 0.5, 1.5); CMD4(CCC_Float, "r2_ls_depth_bias", &ps_r2_ls_depth_bias, -0.5, +0.5); @@ -1480,6 +1512,7 @@ void xrRender_initconsole() // CMD4(CCC_Float, "r2_parallax_range", &ps_r2_df_parallax_range, 5.0f, 175.0f ); CMD4(CCC_Float, "r2_slight_fade", &ps_r2_slight_fade, .2f, 1.f); + CMD4(CCC_Float, "r2_shadow_lod_min", &ps_r2_shadow_lod_min, 0.f, 1.f); tw_min.set(0, 0, 0); tw_max.set(1, 1, 1); @@ -1537,9 +1570,16 @@ void xrRender_initconsole() CMD3(CCC_Token, "r3_msaa_alphatest", &ps_r3_msaa_atest, qmsaa__atest_token); CMD3(CCC_Token, "r3_minmax_sm", &ps_r3_minmax_sm, qminmax_sm_token); + CMD3(CCC_Mask, "r__fast_details_update" ,&ps_r2_ls_flags, R2FLAG_FAST_DETAILS_UPDATE); + #ifdef DETAIL_RADIUS CMD4(CCC_detail_radius, "r__detail_radius", &ps_r__detail_radius, 0, 250); CMD3(CCC_Mask, "r__clear_models_on_unload", &psDeviceFlags2, rsClearModels); //Alundaio + CMD3(CCC_Mask, "r__clear_resources_on_unload", &psDeviceFlags2, rsClearAllResources); + CMD4(CCC_Integer, "r__tex_evict_enabled", &ps_r__tex_evict_enabled, 0, 1 ); + CMD4(CCC_Integer, "r__tex_evict_age_frames", &ps_r__tex_evict_age_frames, 300, 36000); + CMD4(CCC_Integer, "r__tex_evict_batch_size", &ps_r__tex_evict_batch_size, 10, 1000 ); + CMD4(CCC_Integer, "r__tex_evict_interval", &ps_r__tex_evict_interval, 60, 3600 ); CMD3(CCC_Mask, "r__use_precompiled_shaders", &psDeviceFlags2, rsPrecompiledShaders); //Alundaio CMD3(CCC_Mask, "r__enable_grass_shadow", &psDeviceFlags2, rsGrassShadow); //Alundaio CMD3(CCC_Mask, "r__no_scale_on_fade", &psDeviceFlags2, rsNoScale); //Alundaio @@ -1562,6 +1602,13 @@ void xrRender_initconsole() CMD4(CCC_Vector4, "vignette_control", &ps_vignette_control, Fvector4().set(0.0f, 0.0f, 0.0f, 0.0f), Fvector4().set(1.0f, 1.0f, 1.0f, 1.0f)); + CMD4(CCC_Integer, "pfx_volumetric_mode", &ps_pfx_volumetric_mode, 0, 1); + + CMD4(CCC_Float, "r__ssa_discard", &ps_r__ssaDISCARD, 0.f, 50.0f); + CMD4(CCC_Float, "r__ssa_discard_exp", &ps_r__ssaDISCARD_exp, 0.1f, 3.0f); + CMD4(CCC_Float, "r__ssa_discard_fade_k", &ps_r__ssaDISCARD_fade_k, 1.f, 4.0f); + // CMD3(CCC_Mask, "r2_sun_ignore_portals", &ps_r2_ls_flags, R2FLAG_SUN_IGNORE_PORTALS); + CMD4(CCC_Integer, "r_particles_real_dt", &ps_r2_particle_dt, 0, 1); } #endif diff --git a/src/Layers/xrRender/xrRender_console.h b/src/Layers/xrRender/xrRender_console.h index 749cc71d7c..2fd58bc6cd 100644 --- a/src/Layers/xrRender/xrRender_console.h +++ b/src/Layers/xrRender/xrRender_console.h @@ -99,6 +99,7 @@ extern ECORE_API float ps_r__tf_Mipbias; enum { RFLAG_NO_RAM_TEXTURES = (1 << 0), + RFLAG_HOM_DYNAMIC = (1 << 1), }; extern ECORE_API Flags32 ps_r__common_flags; @@ -126,6 +127,7 @@ enum // R2 extern ECORE_API float ps_r2_ssaLOD_A; extern ECORE_API float ps_r2_ssaLOD_B; +extern ECORE_API BOOL ps_r2_particle_dt; // R2-specific extern ECORE_API Flags32 ps_r2_ls_flags; // r2-only @@ -175,7 +177,9 @@ extern ECORE_API float ps_r2_dhemi_sky_scale; // 1.5f extern ECORE_API float ps_r2_dhemi_light_scale; // 1.f extern ECORE_API float ps_r2_dhemi_light_flow; // .1f extern ECORE_API int ps_r2_dhemi_count; // 5 +extern ECORE_API int ps_r2_shadow_omnipart_vischeck; extern ECORE_API float ps_r2_slight_fade; // 1.f +extern ECORE_API float ps_r2_shadow_lod_min; // 1.f extern ECORE_API int ps_r2_wait_sleep; extern ECORE_API int ps_r2_qsync; ////lvutner @@ -281,66 +285,70 @@ extern ECORE_API int ps_r3_dyn_wet_surf_sm_res; // 256 extern ECORE_API int opt_static; extern ECORE_API int opt_dynamic; +extern ECORE_API int ps_pfx_volumetric_mode; +extern ECORE_API int ps_r__portal_traverse_stats; -enum +enum : u64 { - R2FLAG_SUN = (1 << 0), - R2FLAG_SUN_FOCUS = (1 << 1), - R2FLAG_SUN_TSM = (1 << 2), - R2FLAG_SUN_DETAILS = (1 << 3), - R2FLAG_TONEMAP = (1 << 4), - R2FLAG_AA = (1 << 5), - R2FLAG_GI = (1 << 6), - R2FLAG_FASTBLOOM = (1 << 7), - R2FLAG_GLOBALMATERIAL = (1 << 8), - R2FLAG_ZFILL = (1 << 9), - R2FLAG_R1LIGHTS = (1 << 10), - R2FLAG_SUN_IGNORE_PORTALS = (1 << 11), - - R2FLAG_EXP_SPLIT_SCENE = (1 << 12), - R2FLAG_EXP_DONT_TEST_UNSHADOWED = (1 << 13), - R2FLAG_EXP_DONT_TEST_SHADOWED = (1 << 14), - - R2FLAG_USE_NVDBT = (1 << 15), - R2FLAG_USE_NVSTENCIL = (1 << 16), - - R2FLAG_EXP_MT_CALC = (1 << 17), - - R2FLAG_SOFT_WATER = (1 << 18), + R2FLAG_SUN = (1ull << 0), + R2FLAG_SUN_FOCUS = (1ull << 1), + R2FLAG_SUN_TSM = (1ull << 2), + R2FLAG_SUN_DETAILS = (1ull << 3), + R2FLAG_TONEMAP = (1ull << 4), + R2FLAG_AA = (1ull << 5), + R2FLAG_GI = (1ull << 6), + R2FLAG_FASTBLOOM = (1ull << 7), + R2FLAG_GLOBALMATERIAL = (1ull << 8), + R2FLAG_ZFILL = (1ull << 9), + R2FLAG_R1LIGHTS = (1ull << 10), + R2FLAG_SUN_IGNORE_PORTALS = (1ull << 11), + + R2FLAG_EXP_SPLIT_SCENE = (1ull << 12), + R2FLAG_EXP_DONT_TEST_UNSHADOWED = (1ull << 13), + R2FLAG_EXP_DONT_TEST_SHADOWED = (1ull << 14), + + R2FLAG_USE_NVDBT = (1ull << 15), + R2FLAG_USE_NVSTENCIL = (1ull << 16), + + R2FLAG_EXP_MT_CALC = (1ull << 17), + + R2FLAG_SOFT_WATER = (1ull << 18), // Igor: need restart - R2FLAG_SOFT_PARTICLES = (1 << 19), + R2FLAG_SOFT_PARTICLES = (1ull << 19), // Igor: need restart - R2FLAG_VOLUMETRIC_LIGHTS = (1 << 20), - R2FLAG_STEEP_PARALLAX = (1 << 21), - R2FLAG_DOF = (1 << 22), + R2FLAG_VOLUMETRIC_LIGHTS = (1ull << 20), + R2FLAG_STEEP_PARALLAX = (1ull << 21), + R2FLAG_DOF = (1ull << 22), - R1FLAG_DETAIL_TEXTURES = (1 << 23), + R1FLAG_DETAIL_TEXTURES = (1ull << 23), - R2FLAG_DETAIL_BUMP = (1 << 24), + R2FLAG_DETAIL_BUMP = (1ull << 24), - R3FLAG_DYN_WET_SURF = (1 << 25), - R3FLAG_VOLUMETRIC_SMOKE = (1 << 26), + R3FLAG_DYN_WET_SURF = (1ull << 25), + R3FLAG_VOLUMETRIC_SMOKE = (1ull << 26), - //R3FLAG_MSAA = (1<<28), - R3FLAG_MSAA_HYBRID = (1 << 27), - R3FLAG_MSAA_OPT = (1 << 28), - R2FLAG_TERRAIN_PREPASS = (1 << 29), - R3FLAG_USE_DX10_1 = (1 << 30), - //R3FLAG_MSAA_ALPHATEST = (1<<31), + //R3FLAG_MSAA = (1ull<<28), + R3FLAG_MSAA_HYBRID = (1ull << 27), + R3FLAG_MSAA_OPT = (1ull << 28), + R2FLAG_TERRAIN_PREPASS = (1ull << 29), + R3FLAG_USE_DX10_1 = (1ull << 30), + R2FLAG_LIGHTS_DETAILS = (1ull<<31), + R2FLAG_FAST_DETAILS_UPDATE = (1ull<<32) + //R3FLAG_MSAA_ALPHATEST = (1ull<<31), }; -enum +enum: u64 { - R2FLAGEXT_SSAO_BLUR = (1 << 0), - R2FLAGEXT_SSAO_OPT_DATA = (1 << 1), - R2FLAGEXT_SSAO_HALF_DATA = (1 << 2), - R2FLAGEXT_SSAO_HBAO = (1 << 3), - R2FLAGEXT_SSAO_HDAO = (1 << 4), - R2FLAGEXT_ENABLE_TESSELLATION = (1 << 5), - R2FLAGEXT_WIREFRAME = (1 << 6), - R_FLAGEXT_HOM_DEPTH_DRAW = (1 << 7), - R2FLAGEXT_SUN_ZCULLING = (1 << 8), - R2FLAGEXT_SUN_OLD = (1 << 9), + R2FLAGEXT_SSAO_BLUR = (1ull << 0), + R2FLAGEXT_SSAO_OPT_DATA = (1ull << 1), + R2FLAGEXT_SSAO_HALF_DATA = (1ull << 2), + R2FLAGEXT_SSAO_HBAO = (1ull << 3), + R2FLAGEXT_SSAO_HDAO = (1ull << 4), + R2FLAGEXT_ENABLE_TESSELLATION = (1ull << 5), + R2FLAGEXT_WIREFRAME = (1ull << 6), + R_FLAGEXT_HOM_DEPTH_DRAW = (1ull << 7), + R2FLAGEXT_SUN_ZCULLING = (1ull << 8), + R2FLAGEXT_SUN_OLD = (1ull << 9), }; enum @@ -370,6 +378,15 @@ enum //-Swartz +// demonized: +extern ECORE_API BOOL occq_debug; + +// Texture eviction system +extern ECORE_API int ps_r__tex_evict_enabled; +extern ECORE_API int ps_r__tex_evict_age_frames; +extern ECORE_API int ps_r__tex_evict_batch_size; +extern ECORE_API int ps_r__tex_evict_interval; + extern void xrRender_initconsole(); extern BOOL xrRender_test_hw(); diff --git a/src/Layers/xrRenderDX10/3DFluid/dx103DFluidGrid.cpp b/src/Layers/xrRenderDX10/3DFluid/dx103DFluidGrid.cpp index 3a084e4b99..7a73879797 100644 --- a/src/Layers/xrRenderDX10/3DFluid/dx103DFluidGrid.cpp +++ b/src/Layers/xrRenderDX10/3DFluid/dx103DFluidGrid.cpp @@ -33,16 +33,16 @@ namespace #define VERTICES_PER_LINE 2 #define LINES_PER_SLICE 4 -dx103DFluidGrid::dx103DFluidGrid() -{ -} +dx103DFluidGrid::dx103DFluidGrid() {} + +dx103DFluidGrid::~dx103DFluidGrid() { DestroyVertexBuffers(); } -dx103DFluidGrid::~dx103DFluidGrid() +void dx103DFluidGrid::DestroyVertexBuffers() { - _RELEASE(m_pRenderQuadBuffer); - _RELEASE(m_pSlicesBuffer); - _RELEASE(m_pBoundarySlicesBuffer); - _RELEASE(m_pBoundaryLinesBuffer); + _RELEASE(m_pRenderQuadBuffer); + _RELEASE(m_pSlicesBuffer); + _RELEASE(m_pBoundarySlicesBuffer); + _RELEASE(m_pBoundaryLinesBuffer); } void dx103DFluidGrid::Initialize(int gridWidth, int gridHeight, int gridDepth) diff --git a/src/Layers/xrRenderDX10/3DFluid/dx103DFluidGrid.h b/src/Layers/xrRenderDX10/3DFluid/dx103DFluidGrid.h index 5379b27d89..45035fa375 100644 --- a/src/Layers/xrRenderDX10/3DFluid/dx103DFluidGrid.h +++ b/src/Layers/xrRenderDX10/3DFluid/dx103DFluidGrid.h @@ -19,6 +19,7 @@ class dx103DFluidGrid private: void CreateVertexBuffers(); + void DestroyVertexBuffers(); void InitScreenSlice(VS_INPUT_FLUIDSIM_STRUCT** vertices, int z, int& index); void InitSlice(int z, VS_INPUT_FLUIDSIM_STRUCT** vertices, int& index); diff --git a/src/Layers/xrRenderDX10/3DFluid/dx103DFluidManager.cpp b/src/Layers/xrRenderDX10/3DFluid/dx103DFluidManager.cpp index 49f339581c..036f9d10b5 100644 --- a/src/Layers/xrRenderDX10/3DFluid/dx103DFluidManager.cpp +++ b/src/Layers/xrRenderDX10/3DFluid/dx103DFluidManager.cpp @@ -107,7 +107,6 @@ void dx103DFluidManager::Initialize(int width, int height, int depth) strHalfVolumeDim = "halfVolumeDim"; strGravityBuoyancy = "GravityBuoyancy"; - //if (strstr(Core.Params,"-no_volumetric_fog")) if (!RImplementation.o.volumetricfog) return; diff --git a/src/Layers/xrRenderDX10/3DFluid/dx103DFluidObstacles.cpp b/src/Layers/xrRenderDX10/3DFluid/dx103DFluidObstacles.cpp index 3f1b3abcfd..df8ba4fba3 100644 --- a/src/Layers/xrRenderDX10/3DFluid/dx103DFluidObstacles.cpp +++ b/src/Layers/xrRenderDX10/3DFluid/dx103DFluidObstacles.cpp @@ -206,7 +206,7 @@ void dx103DFluidObstacles::ProcessDynamicObstacles(const dx103DFluidData& FluidD // Determine visibility for dynamic part of scene for (u32 i = 0; i < m_lstRenderables.size(); ++i) { - ISpatial* spatial = m_lstRenderables[i]; + ISpatialShared spatial = m_lstRenderables[i]; // Can use to optimize invisible dynamic objects if necessary //CSector* sector = (CSector*)spatial->spatial.sector; //if (0==sector) continue; // disassociated from S/P structure diff --git a/src/Layers/xrRenderDX10/3DFluid/dx103DFluidObstacles.h b/src/Layers/xrRenderDX10/3DFluid/dx103DFluidObstacles.h index cf703e1bf3..f1aa4b971f 100644 --- a/src/Layers/xrRenderDX10/3DFluid/dx103DFluidObstacles.h +++ b/src/Layers/xrRenderDX10/3DFluid/dx103DFluidObstacles.h @@ -48,7 +48,7 @@ class dx103DFluidObstacles // Cache vectors to avoid memory reallocations // TODO: DX10: Reserve memory on object creation - xr_vector m_lstRenderables; + xr_vector m_lstRenderables; xr_vector m_lstShells; xr_vector m_lstElements; }; diff --git a/src/Layers/xrRenderDX10/3DFluid/dx103DFluidRenderer.cpp b/src/Layers/xrRenderDX10/3DFluid/dx103DFluidRenderer.cpp index baed6cc1ea..96be7660cc 100644 --- a/src/Layers/xrRenderDX10/3DFluid/dx103DFluidRenderer.cpp +++ b/src/Layers/xrRenderDX10/3DFluid/dx103DFluidRenderer.cpp @@ -457,7 +457,7 @@ void dx103DFluidRenderer::Draw(const dx103DFluidData& FluidData) else RCache.set_Element(m_RendererTechnique[RS_QuadRaycastFog]); - PrepareCBuffer(FluidData, m_iRenderTextureWidth, m_iRenderTextureHeight); + PrepareCBuffer(FluidData, m_iRenderTextureWidth, m_iRenderTextureHeight, false); DrawScreenQuad(); @@ -482,7 +482,7 @@ void dx103DFluidRenderer::Draw(const dx103DFluidData& FluidData) RImplementation.rmNormal(); - PrepareCBuffer(FluidData, Device.dwWidth, Device.dwHeight); + PrepareCBuffer(FluidData, Device.dwWidth, Device.dwHeight, true); RCache.set_c(strDiffuseLight, LightData.m_vLightIntencity.x, LightData.m_vLightIntencity.y, LightData.m_vLightIntencity.z, 1.0f); @@ -501,7 +501,7 @@ void dx103DFluidRenderer::ComputeRayData(const dx103DFluidData &FluidData) pTarget->u_setrt(RT[RRT_RayDataTex], nullptr, nullptr, nullptr); // LDR RT RCache.set_Element(m_RendererTechnique[RS_CompRayData_Back]); - PrepareCBuffer(FluidData, Device.dwWidth, Device.dwHeight); + PrepareCBuffer(FluidData, Device.dwWidth, Device.dwHeight, false); // Render volume back faces // We output xyz=(0,-1,0) and w=min(sceneDepth, boxDepth) @@ -516,7 +516,7 @@ void dx103DFluidRenderer::ComputeRayData(const dx103DFluidData &FluidData) RCache.set_Element(m_RendererTechnique[RS_CompRayData_Front]); - PrepareCBuffer(FluidData, Device.dwWidth, Device.dwHeight); + PrepareCBuffer(FluidData, Device.dwWidth, Device.dwHeight, true); DrawBox(); } @@ -529,7 +529,7 @@ void dx103DFluidRenderer::ComputeEdgeTexture(const dx103DFluidData &FluidData) // First setup viewport to match the size of the destination low-res texture - PrepareCBuffer(FluidData, m_iRenderTextureWidth, m_iRenderTextureHeight); + PrepareCBuffer(FluidData, m_iRenderTextureWidth, m_iRenderTextureHeight, false); // Downsample the rayDataTexture to a new small texture, simply using point sample (no filtering) @@ -539,7 +539,7 @@ void dx103DFluidRenderer::ComputeEdgeTexture(const dx103DFluidData &FluidData) pTarget->u_setrt(RT[RRT_EdgeTex], nullptr, nullptr, nullptr); // LDR RT RCache.set_Element(m_RendererTechnique[RS_QuadEdgeDetect]); - PrepareCBuffer(FluidData, m_iRenderTextureWidth, m_iRenderTextureHeight); + PrepareCBuffer(FluidData, m_iRenderTextureWidth, m_iRenderTextureHeight, true); DrawScreenQuad(); } @@ -596,7 +596,7 @@ void dx103DFluidRenderer::CalculateLighting(const dx103DFluidData& FluidData, Fo // Determine visibility for dynamic part of scene for (u32 i = 0; i < iNumRenderables; ++i) { - ISpatial* spatial = m_lstRenderables[i]; + ISpatialShared spatial = m_lstRenderables[i]; // Light light* pLight = (light*)spatial->dcast_Light(); @@ -631,8 +631,14 @@ void dx103DFluidRenderer::CalculateLighting(const dx103DFluidData& FluidData, Fo //LightData.m_vLightIntencity.set( 1.0f, 1.0f, 1.0f); } -void dx103DFluidRenderer::PrepareCBuffer(const dx103DFluidData &FluidData, u32 RTWidth, u32 RTHeight) +void dx103DFluidRenderer::PrepareCBuffer(const dx103DFluidData &FluidData, u32 RTWidth, u32 RTHeight, bool SizeOnly) { + RCache.set_c(strRTWidth, (float)RTWidth); + RCache.set_c(strRTHeight, (float)RTHeight); + + // if (SizeOnly) + // return; + const Fmatrix &transform = FluidData.GetTransform(); RCache.set_xform_world(transform); @@ -678,7 +684,4 @@ void dx103DFluidRenderer::PrepareCBuffer(const dx103DFluidData &FluidData, u32 R D3DXVECTOR3 Origin(0,0,0); D3DXVec3Transform((D3DXVECTOR4*)&EyeInGridSpace, (D3DXVECTOR3*)&Origin, (D3DXMATRIX*)&WorldViewInv); RCache.set_c(strEyeOnGrid, *(Fvector4*)&EyeInGridSpace); - - RCache.set_c(strRTWidth, (float)RTWidth); - RCache.set_c(strRTHeight, (float)RTHeight); } diff --git a/src/Layers/xrRenderDX10/3DFluid/dx103DFluidRenderer.h b/src/Layers/xrRenderDX10/3DFluid/dx103DFluidRenderer.h index bfba5457c6..839a24a0a6 100644 --- a/src/Layers/xrRenderDX10/3DFluid/dx103DFluidRenderer.h +++ b/src/Layers/xrRenderDX10/3DFluid/dx103DFluidRenderer.h @@ -67,7 +67,7 @@ class dx103DFluidRenderer void CalculateRenderTextureSize(int screenWidth, int screenHeight); void CreateRayDataResources(int width, int height); - void PrepareCBuffer(const dx103DFluidData &FluidData, u32 RTWidth, u32 RTHeight); + void PrepareCBuffer(const dx103DFluidData &FluidData, u32 RTWidth, u32 RTHeight, bool SizeOnly = false); void ComputeRayData(const dx103DFluidData &FluidData); void ComputeEdgeTexture(const dx103DFluidData &FluidData); @@ -110,7 +110,7 @@ class dx103DFluidRenderer // Cache vectors to avoid memory reallocations // TODO: DX10: Reserve memory on object creation - xr_vector m_lstRenderables; + xr_vector m_lstRenderables; }; #endif // dx103DFluidRenderer_included diff --git a/src/Layers/xrRenderDX10/StateManager/dx10SamplerStateCache.cpp b/src/Layers/xrRenderDX10/StateManager/dx10SamplerStateCache.cpp index e93569231d..2743b067a2 100644 --- a/src/Layers/xrRenderDX10/StateManager/dx10SamplerStateCache.cpp +++ b/src/Layers/xrRenderDX10/StateManager/dx10SamplerStateCache.cpp @@ -184,6 +184,9 @@ void dx10SamplerStateCache::SetMaxAnisotropy(u32 uiMaxAniso) StateRecord& rec = m_StateArray[i]; StateDecs desc; + if (!rec.m_pState) + continue; + rec.m_pState->GetDesc(&desc); // MaxAnisitropy is reset by ValidateState if not aplicable diff --git a/src/Layers/xrRenderDX10/dx10ConstantBuffer.cpp b/src/Layers/xrRenderDX10/dx10ConstantBuffer.cpp index f11fb140e6..551b400319 100644 --- a/src/Layers/xrRenderDX10/dx10ConstantBuffer.cpp +++ b/src/Layers/xrRenderDX10/dx10ConstantBuffer.cpp @@ -6,7 +6,8 @@ dx10ConstantBuffer::~dx10ConstantBuffer() { - DEV->_DeleteConstantBuffer(this); + if (Device.m_pRender && DEV) + DEV->_DeleteConstantBuffer(this); // Flush(); _RELEASE(m_pBuffer); xr_free(m_pBufferData); diff --git a/src/Layers/xrRenderDX10/dx10DetailManager_VS.cpp b/src/Layers/xrRenderDX10/dx10DetailManager_VS.cpp index 4abf7a8362..6be0bd9981 100644 --- a/src/Layers/xrRenderDX10/dx10DetailManager_VS.cpp +++ b/src/Layers/xrRenderDX10/dx10DetailManager_VS.cpp @@ -67,8 +67,9 @@ void CDetailManager::hw_Load_Shaders() hwc_s_array = T1.get("array"); } -void CDetailManager::hw_Render() +void CDetailManager::hw_Render(light* L) { + PROF_EVENT("CDetailManager::hw_Render"); // Render-prepare // Update timer // Can't use Device.fTimeDelta since it is smoothed! Don't know why, but smoothed value looks more choppy! @@ -90,12 +91,14 @@ void CDetailManager::hw_Render() dir2.set(_sin(tm_rot2), 0, _cos(tm_rot2), 0).normalize().mul(swing_current.amp2); // Setup geometry and DMA + RCache.set_CullMode(CULL_NONE); + RCache.set_xform_world(Fidentity); RCache.set_Geometry(hw_Geom); - - // Wave0 float scale = 1.f / float(quant); Fvector4 wave, prev_wave; Fvector4 consts; + + // Wave0 consts.set(scale, scale, ps_r__Detail_l_aniso, ps_r__Detail_l_ambient); //wave.set (1.f/5.f, 1.f/7.f, 1.f/3.f, Device.fTimeGlobal*swing_current.speed); wave.set(1.f / 5.f, 1.f / 7.f, 1.f / 3.f, m_time_pos); @@ -104,7 +107,7 @@ void CDetailManager::hw_Render() //RCache.set_c (&*hwc_wave, wave.div(PI_MUL_2)); // wave //RCache.set_c (&*hwc_wind, dir1); // wind-dir //hw_Render_dump (&*hwc_array, 1, 0, c_hdr ); - hw_Render_dump(consts, wave.div(PI_MUL_2), dir1, prev_wave.div(PI_MUL_2), prev_dir1, 1, 0); + hw_Render_dump(consts, wave.div(PI_MUL_2), dir1, prev_wave.div(PI_MUL_2), prev_dir1, 1, 0, L); // Wave1 //wave.set (1.f/3.f, 1.f/7.f, 1.f/5.f, Device.fTimeGlobal*swing_current.speed); @@ -113,14 +116,14 @@ void CDetailManager::hw_Render() //RCache.set_c (&*hwc_wave, wave.div(PI_MUL_2)); // wave //RCache.set_c (&*hwc_wind, dir2); // wind-dir //hw_Render_dump (&*hwc_array, 2, 0, c_hdr ); - hw_Render_dump(consts, wave.div(PI_MUL_2), dir2, prev_wave.div(PI_MUL_2), prev_dir2, 2, 0); + hw_Render_dump(consts, wave.div(PI_MUL_2), dir2, prev_wave.div(PI_MUL_2), prev_dir2, 2, 0, L); // Still consts.set(scale, scale, scale, 1.f); //RCache.set_c (&*hwc_s_consts,scale, scale, scale, 1.f); //RCache.set_c (&*hwc_s_xform, Device.mFullTransform); //hw_Render_dump (&*hwc_s_array, 0, 1, c_hdr ); - hw_Render_dump(consts, wave.div(PI_MUL_2), dir2, prev_wave.div(PI_MUL_2), prev_dir2, 0, 1); + hw_Render_dump(consts, wave.div(PI_MUL_2), dir2, prev_wave.div(PI_MUL_2), prev_dir2, 0, 1, L); if (prev_frame != Device.dwFrame) { @@ -133,11 +136,16 @@ void CDetailManager::hw_Render() prev_dir1.set(dir1); prev_dir2.set(dir2); } + + RCache.set_CullMode(CULL_CCW); } void CDetailManager::hw_Render_dump(const Fvector4& consts, const Fvector4& wave, const Fvector4& wind, - const Fvector4& prev_wave, const Fvector4& prev_wind, u32 var_id, u32 lod_id) + const Fvector4& prev_wave, const Fvector4& prev_wind, u32 var_id, u32 lod_id, light* L) { + if (RImplementation.phase == CRender::PHASE_SMAP && var_id == 0) + return; + static shared_str strConsts("consts"); static shared_str strWave("wave"); static shared_str strDir2D("dir2D"); @@ -283,11 +291,24 @@ void CDetailManager::hw_Render_dump(const Fvector4& consts, const Fvector4& wave for (; _iI != _iE; _iI++) { SlotItem& Instance = **_iI; + + if (!RImplementation.GMBase.is_sector_visible(RImplementation.pOutdoorSector)) + continue; + + if (RImplementation.phase == CRender::PHASE_SMAP && L) + { + if (!L->GMLight.is_sector_visible(RImplementation.pOutdoorSector)) + continue; + + if (L->position.distance_to_sqr(Instance.position) >= _sqr(L->range)) + continue; + } + u32 base = dwBatch * 4; Instance.alpha += GoToValue(Instance.alpha, Instance.alpha_target); - float scale = Instance.scale_calculated; + float scale = 1.f; // Sort of fade using the scale // fade_distance == -1 use light_position to define "fade", anything else uses fade_distance @@ -300,8 +321,7 @@ void CDetailManager::hw_Render_dump(const Fvector4& consts, const Fvector4& wave break; // Build matrix ( 3x4 matrix, last row - color ) - //float scale = Instance.scale_calculated; - Fmatrix& M = Instance.mRotY; + Fmatrix& M = Instance.mRotY_calculated; c_storage[base + 0].set(M._11 * scale, M._21 * scale, M._31 * scale, M._41); c_storage[base + 1].set(M._12 * scale, M._22 * scale, M._32 * scale, M._42); c_storage[base + 2].set(M._13 * scale, M._23 * scale, M._33 * scale, M._43); @@ -362,12 +382,7 @@ void CDetailManager::hw_Render_dump(const Fvector4& consts, const Fvector4& wave // KD: we must not clear vis on r2 since we want details shadows if (ps_ssfx_grass_shadows.x <= 0) { - if (!psDeviceFlags2.test(rsGrassShadow) || ((ps_r2_ls_flags.test(R2FLAG_SUN_DETAILS) && (RImplementation.PHASE_SMAP == - RImplementation.phase)) // phase smap with shadows - || (ps_r2_ls_flags.test(R2FLAG_SUN_DETAILS) && (RImplementation.PHASE_NORMAL == RImplementation.phase) - && (!RImplementation.is_sun())) // phase normal with shadows without sun - || (!ps_r2_ls_flags.test(R2FLAG_SUN_DETAILS) && (RImplementation.PHASE_NORMAL == RImplementation.phase)) - )) // phase normal without shadows + if (!psDeviceFlags2.test(rsGrassShadow) || RImplementation.PHASE_NORMAL == RImplementation.phase) // phase normal without shadows vis.clear_not_free(); } } diff --git a/src/Layers/xrRenderDX10/dx10HW.cpp b/src/Layers/xrRenderDX10/dx10HW.cpp index 4461f72311..bde69ad8ca 100644 --- a/src/Layers/xrRenderDX10/dx10HW.cpp +++ b/src/Layers/xrRenderDX10/dx10HW.cpp @@ -41,8 +41,6 @@ IDirect3DStateBlock9* dwDebugSB = 0; #endif */ -LPCSTR dxgiOld = "--dxgi-old"; - CHW::CHW() : // hD3D(NULL), //pD3D(NULL), @@ -436,7 +434,7 @@ void CHW::CreateDevice(HWND hwnd, bool move_window) if ((D3DFMT_UNKNOWN==fTarget) || (D3DFMT_UNKNOWN==fTarget)) { Msg ("Failed to initialize graphics hardware.\nPlease try to restart the game."); - FlushLog (); + xrLogger::FlushLog(); MessageBox (NULL,"Failed to initialize graphics hardware.\nPlease try to restart the game.","Error!",MB_OK|MB_ICONERROR); TerminateProcess (GetCurrentProcess(),0); } @@ -555,7 +553,7 @@ void CHW::CreateDevice(HWND hwnd, bool move_window) }; UINT create_device_flags = D3D11_CREATE_DEVICE_BGRA_SUPPORT; - if (strstr(Core.Params, "--dxgi-dbg")) { + if (Core.ParamsData.test(ECoreParams::dxgi_dbg)) { // enables d3d11 debug layer validation and output // viewable in VS debugger `Output > Debug` view or using a tool like Sysinternals DebugView create_device_flags |= D3D11_CREATE_DEVICE_DEBUG; @@ -649,7 +647,7 @@ void CHW::CreateDevice(HWND hwnd, bool move_window) "Please try to restart the game.\n" "CreateDevice returned 0x%08x", R ); - FlushLog(); + xrLogger::FlushLog(); MessageBox(NULL, "Failed to initialize graphics hardware.\nPlease try to restart the game.", "Error!", MB_OK | MB_ICONERROR); TerminateProcess(GetCurrentProcess(), 0); @@ -686,8 +684,8 @@ void CHW::CreateDevice(HWND hwnd, bool move_window) // probably the sequence ResizeTarget, ResizeBuffers, and UpdateViews is important // u32 memory = pDevice->GetAvailableTextureMem (); - if (strstr(Core.Params, dxgiOld)) { - Msg("* %s enabled", dxgiOld); + if (Core.ParamsData.test(ECoreParams::dxgi_old)) { + Msg("* %s enabled", "dxgi-old"); UpdateViews(); size_t memory = Desc.DedicatedVideoMemory; Msg("* Texture memory: %d M", memory / (1024 * 1024)); @@ -739,7 +737,7 @@ void CHW::DestroyDevice() if (!is_windowed) { m_pSwapChain->SetFullscreenState(FALSE, NULL); - if (strstr(Core.Params, dxgiOld)) { + if (Core.ParamsData.test(ECoreParams::dxgi_old)) { #ifdef USE_DX11 const auto& cd = m_ChainDesc; CHK_DX(m_pSwapChain->ResizeBuffers( @@ -1032,7 +1030,7 @@ DXGI_RATIONAL CHW::selectRefresh(u32 dwWidth, u32 dwHeight, DXGI_FORMAT fmt) float CurrentFreq = 60.0f; - if (psDeviceFlags.is(rsRefresh60hz) || strstr(Core.Params, "-60hz")) + if (psDeviceFlags.is(rsRefresh60hz) || Core.ParamsData.test(ECoreParams::_60hz)) { refresh_rate = 1.f / 60.f; return res; @@ -1094,7 +1092,7 @@ void CHW::OnAppActivate() m_pSwapChain->SetFullscreenState(TRUE, m_pOutput); #ifdef USE_DX11 - if (!strstr(Core.Params, dxgiOld)) { + if (!Core.ParamsData.test(ECoreParams::dxgi_old)) { _SHOW_REF("refCount:pBaseZB", pBaseZB); _RELEASE(pBaseZB); @@ -1140,7 +1138,7 @@ void CHW::OnAppDeactivate() m_pSwapChain->SetFullscreenState(FALSE, NULL); #ifdef USE_DX11 - if (!strstr(Core.Params, dxgiOld)) { + if (!Core.ParamsData.test(ECoreParams::dxgi_old)) { _SHOW_REF("refCount:pBaseZB", pBaseZB); _RELEASE(pBaseZB); @@ -1184,7 +1182,6 @@ BOOL CHW::support(D3DFORMAT fmt, DWORD type, DWORD usage) void CHW::updateWindowProps(HWND m_hWnd) { - // BOOL bWindowed = strstr(Core.Params,"-dedicated") ? TRUE : !psDeviceFlags.is (rsFullscreen); BOOL bWindowed = (g_screenmode != 2); // Set window properties depending on what mode were in. @@ -1200,7 +1197,7 @@ void CHW::updateWindowProps(HWND m_hWnd) else { dwWindowStyle |= WS_BORDER | WS_OVERLAPPEDWINDOW; - if (!strstr(Core.Params, "-no_dialog_header")) + if (!Core.ParamsData.test(ECoreParams::no_dialog_header)) dwWindowStyle |= WS_DLGFRAME | WS_SYSMENU | WS_MINIMIZEBOX; } diff --git a/src/Layers/xrRenderDX10/dx10R_Backend_Runtime.h b/src/Layers/xrRenderDX10/dx10R_Backend_Runtime.h index 2c293bf3cf..e83dfad2a3 100644 --- a/src/Layers/xrRenderDX10/dx10R_Backend_Runtime.h +++ b/src/Layers/xrRenderDX10/dx10R_Backend_Runtime.h @@ -5,6 +5,8 @@ #include "StateManager/dx10StateManager.h" #include "StateManager/dx10ShaderResourceStateCache.h" +#include "../../xrCore/profiler.h" + IC void CBackend::set_xform(u32 ID, const Fmatrix& M) { stat.xforms ++; @@ -280,6 +282,7 @@ IC void CBackend::Compute(UINT ThreadGroupCountX, UINT ThreadGroupCountY, UINT T IC void CBackend::Render(D3DPRIMITIVETYPE T, u32 baseV, u32 startV, u32 countV, u32 startI, u32 PC) { + PROF_EVENT("RCache.Render_ibvb"); //VERIFY(vs); //HW.pDevice->VSSetShader(vs); //HW.pDevice->GSSetShader(0); @@ -329,6 +332,7 @@ IC void CBackend::Render(D3DPRIMITIVETYPE T, u32 baseV, u32 startV, u32 countV, IC void CBackend::Render(D3DPRIMITIVETYPE T, u32 startV, u32 PC) { + PROF_EVENT("RCache.Render_vb"); // TODO: DX10: Remove triangle fan usage from the engine if (T == D3DPT_TRIANGLEFAN) return; @@ -455,6 +459,7 @@ ICF void CBackend::set_CullMode(u32 _mode) IC void CBackend::ApplyVertexLayout() { + PROF_EVENT("CBackend::ApplyVertexLayout"); VERIFY(vs); VERIFY(decl); VERIFY(m_pInputSignature); @@ -522,6 +527,7 @@ IC bool CBackend::CBuffersNeedUpdate(ref_cbuffer buf1[MaxCBuffers], ref_cbuffer IC void CBackend::set_Constants(R_constant_table* C) { + PROF_EVENT("CBackend::set_Constants"); // caching if (ctable == C) return; ctable = C; @@ -539,13 +545,13 @@ IC void CBackend::set_Constants(R_constant_table* C) // Setup constant tables { - ref_cbuffer aPixelConstants[MaxCBuffers]; - ref_cbuffer aVertexConstants[MaxCBuffers]; - ref_cbuffer aGeometryConstants[MaxCBuffers]; + static ref_cbuffer aPixelConstants[MaxCBuffers]; + static ref_cbuffer aVertexConstants[MaxCBuffers]; + static ref_cbuffer aGeometryConstants[MaxCBuffers]; #ifdef USE_DX11 - ref_cbuffer aHullConstants[MaxCBuffers]; - ref_cbuffer aDomainConstants[MaxCBuffers]; - ref_cbuffer aComputeConstants[MaxCBuffers]; + static ref_cbuffer aHullConstants[MaxCBuffers]; + static ref_cbuffer aDomainConstants[MaxCBuffers]; + static ref_cbuffer aComputeConstants[MaxCBuffers]; #endif for (int i = 0; i < MaxCBuffers; ++i) @@ -759,6 +765,7 @@ ICF void CBackend::ApplyRTandZB() IC void CBackend::get_ConstantDirect(shared_str& n, u32 DataSize, void** pVData, void** pGData, void** pPData) { + PROF_EVENT("CBackend::get_ConstantDirect"); R_constant* C = get_c(n); if (C) diff --git a/src/Layers/xrRenderDX10/dx10ResourceManager_Resources.cpp b/src/Layers/xrRenderDX10/dx10ResourceManager_Resources.cpp index 7c1e4ae7e7..dd2557b08a 100644 --- a/src/Layers/xrRenderDX10/dx10ResourceManager_Resources.cpp +++ b/src/Layers/xrRenderDX10/dx10ResourceManager_Resources.cpp @@ -73,6 +73,7 @@ BOOL reclaim(xr_vector& vec, const T* ptr) SState* CResourceManager::_CreateState(SimulatorStates& state_code) { xrCriticalSectionGuard guard(creationGuard); + // Search equal state-code for (u32 it = 0; it < v_states.size(); it++) { @@ -143,21 +144,22 @@ void CResourceManager::_DeletePass(const SPass* P) SVS* CResourceManager::_CreateVS(LPCSTR _name) { xrCriticalSectionGuard guard(creationGuard); - int skinning = -1; - string_path name; - xr_strcpy(name, _name); - if (0 == ::Render->m_skinning) { xr_strcat(name, "_0"); skinning = 0; } - if (1 == ::Render->m_skinning) { xr_strcat(name, "_1"); skinning = 1; } - if (2 == ::Render->m_skinning) { xr_strcat(name, "_2"); skinning = 2; } - if (3 == ::Render->m_skinning) { xr_strcat(name, "_3"); skinning = 3; } - if (4 == ::Render->m_skinning) { xr_strcat(name, "_4"); skinning = 4; } + xr_string res_name = _name; + + const int m_skinning = Engine.External.GetSkinningMode(); + if (m_skinning > 0) + { + res_name += "_" + xr_string::ToString(m_skinning); + } + + LPCSTR name = res_name.c_str(); LPSTR N = LPSTR(name); map_VS::iterator I = m_vs.find(N); if (I != m_vs.end()) return I->second; else { SVS* _vs = xr_new(); - _vs->skinning = skinning; + _vs->skinning = m_skinning; _vs->dwFlags |= xr_resource_flagged::RF_REGISTERED; m_vs.insert(mk_pair(_vs->set_name(name), _vs)); //_vs->vs = NULL; @@ -490,13 +492,20 @@ void CResourceManager::_DeleteDecl(const SDeclaration* dcl) //-------------------------------------------------------------------------------------------------------------- R_constant_table* CResourceManager::_CreateConstantTable(R_constant_table& C) { + if (C.empty()) return NULL; + xrCriticalSectionGuard guard(creationGuard); - if (C.empty()) return NULL; for (u32 it = 0; it < v_constant_tables.size(); it++) - if (v_constant_tables[it]->equal(C)) return v_constant_tables[it]; - v_constant_tables.push_back(xr_new(C)); - v_constant_tables.back()->dwFlags |= xr_resource_flagged::RF_REGISTERED; + if (v_constant_tables[it]->equal(C)) + return v_constant_tables[it]; + + auto NewElem = xr_new(C); + //NewElem->_copy(C); + NewElem->dwFlags |= xr_resource_flagged::RF_REGISTERED; + v_constant_tables.push_back(NewElem); + return NewElem; + return v_constant_tables.back(); } @@ -539,8 +548,8 @@ CRT* CResourceManager::_CreateRT(LPCSTR Name, u32 w, u32 h, D3DFORMAT f, u32 Sam void CResourceManager::_DeleteRT(const CRT* RT) { if (0 == (RT->dwFlags & xr_resource_flagged::RF_REGISTERED)) return; - xrCriticalSectionGuard guard(creationGuard); LPSTR N = LPSTR(*RT->cName); + xrCriticalSectionGuard guard(creationGuard); map_RT::iterator I = m_rtargets.find(N); if (I != m_rtargets.end()) { @@ -550,37 +559,6 @@ void CResourceManager::_DeleteRT(const CRT* RT) Msg("! ERROR: Failed to find render-target '%s'", *RT->cName); } -/* // DX10 cut -//-------------------------------------------------------------------------------------------------------------- -CRTC* CResourceManager::_CreateRTC (LPCSTR Name, u32 size, D3DFORMAT f) -{ - R_ASSERT(Name && Name[0] && size); - - // ***** first pass - search already created RTC - LPSTR N = LPSTR(Name); - map_RTC::iterator I = m_rtargets_c.find (N); - if (I!=m_rtargets_c.end()) return I->second; - else - { - CRTC *RT = xr_new(); - RT->dwFlags |= xr_resource_flagged::RF_REGISTERED; - m_rtargets_c.insert (mk_pair(RT->set_name(Name),RT)); - if (Device.b_is_Ready) RT->create (Name,size,f); - return RT; - } -} -void CResourceManager::_DeleteRTC (const CRTC* RT) -{ - if (0==(RT->dwFlags&xr_resource_flagged::RF_REGISTERED)) return; - LPSTR N = LPSTR (*RT->cName); - map_RTC::iterator I = m_rtargets_c.find (N); - if (I!=m_rtargets_c.end()) { - m_rtargets_c.erase(I); - return; - } - Msg ("! ERROR: Failed to find render-target '%s'",*RT->cName); -} -*/ //-------------------------------------------------------------------------------------------------------------- void CResourceManager::DBG_VerifyGeoms() { @@ -626,8 +604,8 @@ SGeometry* CResourceManager::CreateGeom(D3DVERTEXELEMENT9* decl, ID3DVertexBuffe SGeometry* CResourceManager::CreateGeom(u32 FVF, ID3DVertexBuffer* vb, ID3DIndexBuffer* ib) { - xrCriticalSectionGuard guard(creationGuard); D3DVERTEXELEMENT9 dcl [MAX_FVF_DECL_SIZE]; + xrCriticalSectionGuard guard(creationGuard); CHK_DX(D3DXDeclaratorFromFVF(FVF,dcl)); SGeometry* g = CreateGeom(dcl, vb, ib); return g; @@ -642,16 +620,18 @@ void CResourceManager::DeleteGeom(const SGeometry* Geom) } //-------------------------------------------------------------------------------------------------------------- +xr_task_group textures_load_tasks; CTexture* CResourceManager::_CreateTexture(LPCSTR _Name) { + PROF_EVENT("_CreateTexture"); // DBG_VerifyTextures (); if (0 == xr_strcmp(_Name, "null")) return 0; //Msg("texture %s", _Name); R_ASSERT(_Name && _Name[0]); string_path Name; xr_strcpy(Name, _Name); //. andy if (strext(Name)) *strext(Name)=0; - fix_texture_name(Name); xrCriticalSectionGuard guard(creationGuard); + fix_texture_name(Name); // ***** first pass - search already loaded texture LPSTR N = LPSTR(Name); map_TextureIt I = m_textures.find(N); @@ -662,7 +642,16 @@ CTexture* CResourceManager::_CreateTexture(LPCSTR _Name) T->dwFlags |= xr_resource_flagged::RF_REGISTERED; m_textures.insert(mk_pair(T->set_name(Name), T)); T->Preload(); - if (Device.b_is_Ready && !bDeferredLoad) T->Load(); + if (Device.b_is_Ready) + { + static DWORD this_thread_id = 0; + this_thread_id = GetCurrentThreadId(); + textures_load_tasks.run([=]() + { + if (this_thread_id != GetCurrentThreadId()) { PROF_THREAD("X-Ray PPL Thread") } + T->Load(); + }); + } return T; } } @@ -704,8 +693,8 @@ CMatrix* CResourceManager::_CreateMatrix(LPCSTR Name) R_ASSERT(Name && Name[0]); if (0 == stricmp(Name, "$null")) return NULL; - xrCriticalSectionGuard guard(creationGuard); LPSTR N = LPSTR(Name); + xrCriticalSectionGuard guard(creationGuard); map_Matrix::iterator I = m_matrices.find(N); if (I != m_matrices.end()) return I->second; else @@ -732,20 +721,14 @@ void CResourceManager::_DeleteMatrix(const CMatrix* M) Msg("! ERROR: Failed to find xform-def '%s'", *M->cName); } -void CResourceManager::ED_UpdateMatrix(LPCSTR Name, CMatrix* data) -{ - CMatrix* M = _CreateMatrix(Name); - *M = *data; -} - //-------------------------------------------------------------------------------------------------------------- CConstant* CResourceManager::_CreateConstant(LPCSTR Name) { R_ASSERT(Name && Name[0]); if (0 == stricmp(Name, "$null")) return NULL; - xrCriticalSectionGuard guard(creationGuard); LPSTR N = LPSTR(Name); + xrCriticalSectionGuard guard(creationGuard); map_Constant::iterator I = m_constants.find(N); if (I != m_constants.end()) return I->second; else @@ -772,12 +755,6 @@ void CResourceManager::_DeleteConstant(const CConstant* C) Msg("! ERROR: Failed to find R1-constant-def '%s'", *C->cName); } -void CResourceManager::ED_UpdateConstant(LPCSTR Name, CConstant* data) -{ - CConstant* C = _CreateConstant(Name); - *C = *data; -} - //-------------------------------------------------------------------------------------------------------------- bool cmp_tl(const std::pair& _1, const std::pair& _2) { @@ -794,7 +771,9 @@ STextureList* CResourceManager::_CreateTextureList(STextureList& L) if (L.equal(*base)) return base; } STextureList* lst = xr_new(L); + //lst->_copy(L); lst->dwFlags |= xr_resource_flagged::RF_REGISTERED; + lst_textures.push_back(lst); return lst; } @@ -820,12 +799,15 @@ SMatrixList* CResourceManager::_CreateMatrixList(SMatrixList& L) if (bEmpty) return NULL; xrCriticalSectionGuard guard(creationGuard); + for (u32 it = 0; it < lst_matrices.size(); it++) { SMatrixList* base = lst_matrices[it]; if (L.equal(*base)) return base; } SMatrixList* lst = xr_new(L); + //lst->_copy(L); + lst->dwFlags |= xr_resource_flagged::RF_REGISTERED; lst_matrices.push_back(lst); return lst; @@ -852,12 +834,15 @@ SConstantList* CResourceManager::_CreateConstantList(SConstantList& L) if (bEmpty) return NULL; xrCriticalSectionGuard guard(creationGuard); + for (u32 it = 0; it < lst_constants.size(); it++) { SConstantList* base = lst_constants[it]; if (L.equal(*base)) return base; } SConstantList* lst = xr_new(L); + //lst->_copy(L); + lst->dwFlags |= xr_resource_flagged::RF_REGISTERED; lst_constants.push_back(lst); return lst; diff --git a/src/Layers/xrRenderDX10/dx10ResourceManager_Scripting.cpp b/src/Layers/xrRenderDX10/dx10ResourceManager_Scripting.cpp index d480cb6df8..f81405e198 100644 --- a/src/Layers/xrRenderDX10/dx10ResourceManager_Scripting.cpp +++ b/src/Layers/xrRenderDX10/dx10ResourceManager_Scripting.cpp @@ -610,6 +610,7 @@ Shader* CResourceManager::_lua_Create(LPCSTR d_shader, LPCSTR s_textures) // Create _new_ entry Shader* N = xr_new(S); + //N->_copy(S); N->dwFlags |= xr_resource_flagged::RF_REGISTERED; v_shaders.push_back(N); return N; diff --git a/src/Layers/xrRenderDX10/dx10SH_RT.cpp b/src/Layers/xrRenderDX10/dx10SH_RT.cpp index 9635c5aa1a..4ee562b677 100644 --- a/src/Layers/xrRenderDX10/dx10SH_RT.cpp +++ b/src/Layers/xrRenderDX10/dx10SH_RT.cpp @@ -34,6 +34,7 @@ void CRT::create(LPCSTR Name, u32 w, u32 h, D3DFORMAT f, u32 SampleCount, bool u void CRT::create(LPCSTR Name, u32 w, u32 h, D3DFORMAT f, u32 SampleCount) #endif { + PROF_EVENT("CRT::create"); if (pSurface) return; R_ASSERT(HW.pDevice && Name && Name[0] && w && h); diff --git a/src/Layers/xrRenderDX10/dx10SH_Texture.cpp b/src/Layers/xrRenderDX10/dx10SH_Texture.cpp index 8d913f4b6b..a8b263e82f 100644 --- a/src/Layers/xrRenderDX10/dx10SH_Texture.cpp +++ b/src/Layers/xrRenderDX10/dx10SH_Texture.cpp @@ -19,8 +19,16 @@ #define PRIORITY_NORMAL 8 #define PRIORITY_LOW 4 +// Background PPL task group used to (re)load textures off the calling thread. +// Defined in dx10ResourceManager_Resources.cpp; CResourceManager::_CreateTexture +// dispatches brand-new textures' initial Load() through it whenever the device is +// ready. apply_load() below reuses the same queue for evicted textures instead of +// calling Load() inline. +extern xr_task_group textures_load_tasks; + void resptrcode_texture::create(LPCSTR _name) { + PROF_EVENT("resptrcode_texture::create"); _set(DEV->_CreateTexture(_name)); } @@ -39,11 +47,12 @@ CTexture::CTexture() seqMSPF = 0; flags.MemoryUsage = 0; flags.bLoaded = false; + flags.bLoading = false; flags.bUser = false; flags.seqCycles = FALSE; flags.bLoadedAsStaging = FALSE; m_material = 1.0f; - bind = fastdelegate::FastDelegate1(this, &CTexture::apply_load); + bind = xr_make_delegate(this, &CTexture::apply_load); } CTexture::~CTexture() @@ -56,6 +65,13 @@ CTexture::~CTexture() void CTexture::surface_set(ID3DBaseTexture* surf) { + while (flags.bLoading) + { + SwitchToThread(); + } + + if (cName.size() && strstr(cName.c_str(), "$user$")) + flags.bUser = true; if (surf) surf->AddRef(); _RELEASE(pSurface); _RELEASE(m_pSRView); @@ -120,6 +136,10 @@ void CTexture::surface_set(ID3DBaseTexture* surf) ID3DBaseTexture* CTexture::surface_get() { + while (flags.bLoading) + { + SwitchToThread(); + } if (flags.bLoadedAsStaging) ProcessStaging(); @@ -129,18 +149,57 @@ ID3DBaseTexture* CTexture::surface_get() void CTexture::PostLoad() { - if (pTheora) bind = fastdelegate::FastDelegate1(this, &CTexture::apply_theora); - else if (pAVI) bind = fastdelegate::FastDelegate1(this, &CTexture::apply_avi); - else if (!seqDATA.empty()) bind = fastdelegate::FastDelegate1(this, &CTexture::apply_seq); - else if (gifPlayer) bind = fastdelegate::FastDelegate1(this, &CTexture::apply_gif); - else bind = fastdelegate::FastDelegate1(this, &CTexture::apply_normal); + if (pTheora) bind = xr_make_delegate(this, &CTexture::apply_theora); + else if (pAVI) bind = xr_make_delegate(this, &CTexture::apply_avi); + else if (!seqDATA.empty()) bind = xr_make_delegate(this, &CTexture::apply_seq); + else if (gifPlayer) bind = xr_make_delegate(this, &CTexture::apply_gif); + else bind = xr_make_delegate(this, &CTexture::apply_normal); } void CTexture::apply_load(u32 dwStage) { - if (!flags.bLoaded) Load(); - else PostLoad(); - bind(dwStage); + if (!flags.bLoaded) + { + // Never loaded, or just dropped by EvictStalledTextures(). Load() ends up in + // D3DX11CreateTextureFromMemory, which races the resource thread if run inline + // here (this can run on the render thread mid-gameplay just as easily as on a + // loading-screen thread during level load - neither is safe in the MT build). + // Queue the (re)load the same way _CreateTexture() does for new textures instead; + // bLoading guards against re-queuing every call while that's in flight. + if (!flags.bLoading) + { +#ifdef DEBUG + Msg("* [TexReload] queued: %s", cName.c_str()); +#endif // DEBUG + CTexture* self = this; + static DWORD this_thread_id = 0; + this_thread_id = GetCurrentThreadId(); + textures_load_tasks.run([self]() + { + if (this_thread_id != GetCurrentThreadId()) { PROF_THREAD("X-Ray PPL Thread") } + self->Load(); + }); + } + // Bind nothing (or whatever is already there, e.g. mid-flight from an + // in-flight Load()) for this call. apply_normal() waits out any in-flight + // load, so this never touches D3D resources that are being created + // concurrently. Once the queued Load() completes, PostLoad() re-points + // `bind` at the real apply_* handler and subsequent calls stop landing here. + apply_normal(dwStage); + return; + } + + PostLoad(); + if (bind == xr_make_delegate(this, &CTexture::apply_load)) + { + // This should not happen - if bind is still apply_load, fall back to apply_normal + // which will just apply the (potentially unloaded) surface + apply_normal(dwStage); + } + else + { + bind(dwStage); + } }; void CTexture::ProcessStaging() @@ -228,6 +287,12 @@ void CTexture::ProcessStaging() void CTexture::Apply(u32 dwStage) { + while (flags.bLoading) + { + SwitchToThread(); + } + dwLastUsedFrame = RDEVICE.dwFrame; + if (flags.bLoadedAsStaging) ProcessStaging(); @@ -274,6 +339,10 @@ void CTexture::Apply(u32 dwStage) void CTexture::apply_theora(u32 dwStage) { + while (flags.bLoading) + { + SwitchToThread(); + } if (pTheora->Update(m_play_time != 0xFFFFFFFF ? m_play_time : Device.dwTimeContinual)) { D3D_RESOURCE_DIMENSION type; @@ -313,6 +382,10 @@ void CTexture::apply_theora(u32 dwStage) void CTexture::apply_avi(u32 dwStage) { + while (flags.bLoading) + { + SwitchToThread(); + } if (pAVI->NeedUpdate()) { D3D_RESOURCE_DIMENSION type; @@ -345,6 +418,10 @@ void CTexture::apply_avi(u32 dwStage) void CTexture::apply_seq(u32 dwStage) { + while (flags.bLoading) + { + SwitchToThread(); + } // SEQ u32 frame = Device.dwTimeContinual / seqMSPF; //Device.dwTimeGlobal u32 frame_data = seqDATA.size(); @@ -367,6 +444,10 @@ void CTexture::apply_seq(u32 dwStage) void CTexture::apply_gif(u32 dwStage) { + while (flags.bLoading) + { + SwitchToThread(); + } if (gifPlayer->UpdateFrame()) { const CGIFAnimationPlayer::Frame* const gifFrame = gifPlayer->GetActiveFrame(); @@ -380,13 +461,17 @@ void CTexture::apply_gif(u32 dwStage) void CTexture::apply_normal(u32 dwStage) { + while (flags.bLoading) + { + SwitchToThread(); + } //CHK_DX(HW.pDevice->SetTexture(dwStage,pSurface)); Apply(dwStage); }; void CTexture::Preload() { - if (!strstr(Core.Params, "-r4_dev")) + if (!Core.ParamsData.test(ECoreParams::r4_dev)) { m_bumpmap = DEV->m_textures_description.GetBumpName(cName); } @@ -395,16 +480,32 @@ void CTexture::Preload() void CTexture::Load() { - flags.bLoaded = true; + PROF_EVENT("CTexture::Load"); + + if (flags.bLoaded || flags.bLoading) return; + flags.bLoading = true; + flags.bLoaded = false; desc_cache = 0; - if (pSurface) return; + if (pSurface) + { + flags.bLoading = false; + flags.bLoaded = true; + return; + } flags.bUser = false; flags.MemoryUsage = 0; - if (0 == stricmp(*cName, "$null")) return; + if (0 == stricmp(*cName, "$null")) + { + flags.bLoading = false; + flags.bLoaded = true; + return; + } if (0 != strstr(*cName, "$user$")) { flags.bUser = true; + flags.bLoading = false; + flags.bLoaded = true; return; } @@ -597,10 +698,20 @@ void CTexture::Load() CHK_DX(HW.pDevice->CreateShaderResourceView(pSurface, NULL, &m_pSRView)); } PostLoad(); + flags.bLoading = false; + flags.bLoaded = true; } void CTexture::Unload() { + while (flags.bLoading) + { + SwitchToThread(); + } + + // Already unloaded or never loaded: nothing to do. + if (!flags.bLoaded) + return; #ifdef DEBUG string_path msg_buff; xr_sprintf (msg_buff,sizeof(msg_buff),"* Unloading texture [%s] pSurface RefCount=",cName.c_str()); @@ -639,11 +750,15 @@ void CTexture::Unload() xr_delete(pAVI); xr_delete(pTheora); - bind = fastdelegate::FastDelegate1(this, &CTexture::apply_load); + bind = xr_make_delegate(this, &CTexture::apply_load); } void CTexture::desc_update() { + while (flags.bLoading) + { + SwitchToThread(); + } desc_cache = pSurface; if (pSurface) { @@ -704,20 +819,36 @@ D3D_USAGE CTexture::GetUsage() void CTexture::video_Play(BOOL looped, u32 _time) { + while (flags.bLoading) + { + SwitchToThread(); + } if (pTheora) pTheora->Play(looped, (_time != 0xFFFFFFFF) ? (m_play_time = _time) : Device.dwTimeContinual); } void CTexture::video_Pause(BOOL state) { + while (flags.bLoading) + { + SwitchToThread(); + } if (pTheora) pTheora->Pause(state); } void CTexture::video_Stop() { + while (flags.bLoading) + { + SwitchToThread(); + } if (pTheora) pTheora->Stop(); } BOOL CTexture::video_IsPlaying() { + while (flags.bLoading) + { + SwitchToThread(); + } return (pTheora) ? pTheora->IsPlaying() : FALSE; } diff --git a/src/Layers/xrRenderDX10/dx10Texture.cpp b/src/Layers/xrRenderDX10/dx10Texture.cpp index 05708873d1..1a52e69b9e 100644 --- a/src/Layers/xrRenderDX10/dx10Texture.cpp +++ b/src/Layers/xrRenderDX10/dx10Texture.cpp @@ -343,7 +343,7 @@ ID3DBaseTexture* CRender::texture_load(LPCSTR fRName, u32& ret_msize, bool bStag { if (!FS.exist(fn, "$game_textures$", fname, ".dds")) goto _BUMP_from_base; - else if (strstr(Core.Params, "-no_bump_mode2")) + else if (Core.ParamsData.test(ECoreParams::no_bump_mode2)) { if (strstr(fname, "_bump#")) { @@ -362,7 +362,7 @@ ID3DBaseTexture* CRender::texture_load(LPCSTR fRName, u32& ret_msize, bool bStag img_size = S->length(); goto _DDS_2D; } - else if (strstr(Core.Params, "-no_bump_mode1") && strstr(fname, "_bump#")) + else if (Core.ParamsData.test(ECoreParams::no_bump_mode1) && strstr(fname, "_bump#")) { R_ASSERT2(FS.exist(fn,"$game_textures$", "ed\\ed_dummy_bump#", ".dds"), "ed_dummy_bump#"); S = FS.r_open(fn); diff --git a/src/Layers/xrRenderDX10/dx10r_constants_cache.cpp b/src/Layers/xrRenderDX10/dx10r_constants_cache.cpp index 6b0ae5265d..05f703c8dc 100644 --- a/src/Layers/xrRenderDX10/dx10r_constants_cache.cpp +++ b/src/Layers/xrRenderDX10/dx10r_constants_cache.cpp @@ -5,6 +5,7 @@ dx10ConstantBuffer& R_constants::GetCBuffer(R_constant* C, BufferType BType) { + PROF_EVENT("R_constants::GetCBuffer"); if (BType == BT_PixelBuffer) { // Decode index @@ -70,6 +71,7 @@ dx10ConstantBuffer& R_constants::GetCBuffer(R_constant* C, BufferType BType) void R_constants::flush_cache() { + PROF_EVENT("R_constants::flush_cache"); for (int i = 0; i < CBackend::MaxCBuffers; ++i) { if (RCache.m_aVertexConstants[i]) diff --git a/src/Layers/xrRender/Texture.cpp b/src/Layers/xrRenderDX9/dx9Texture.cpp similarity index 98% rename from src/Layers/xrRender/Texture.cpp rename to src/Layers/xrRenderDX9/dx9Texture.cpp index 3e7a410b4e..d0029384d2 100644 --- a/src/Layers/xrRender/Texture.cpp +++ b/src/Layers/xrRenderDX9/dx9Texture.cpp @@ -10,7 +10,7 @@ #pragma warning(default:4995) #ifndef _EDITOR -#include "dxRenderDeviceRender.h" +#include "../xrRender/dxRenderDeviceRender.h" #endif // #include "std_classes.h" @@ -130,7 +130,7 @@ void TW_Save(ID3DTexture2D* T, LPCSTR name, LPCSTR prefix, LPCSTR postfix) if ('\\' == fn[it]) fn[it] = '_'; string256 fn2; strconcat(sizeof(fn2), fn2, "debug\\", fn, ".dds"); - Log("* debug texture save: ", fn2); + Msg("* debug texture save: %s", fn2); R_CHK(D3DXSaveTextureToFile (fn2,D3DXIFF_DDS,T,0)); } @@ -339,7 +339,7 @@ ID3DBaseTexture* CRender::texture_load(LPCSTR fRName, u32& ret_msize) { if (!FS.exist(fn, "$game_textures$", fname, ".dds")) goto _BUMP_from_base; - else if (strstr(Core.Params, "-no_bump_mode2")) + else if (Core.ParamsData.test(ECoreParams::no_bump_mode2)) { if (strstr(fname, "_bump#")) { @@ -358,7 +358,7 @@ ID3DBaseTexture* CRender::texture_load(LPCSTR fRName, u32& ret_msize) img_size = S->length(); goto _DDS_2D; } - else if (strstr(Core.Params, "-no_bump_mode1") && strstr(fname, "_bump#")) + else if (Core.ParamsData.test(ECoreParams::no_bump_mode1) && strstr(fname, "_bump#")) { R_ASSERT2(FS.exist(fn,"$game_textures$", "ed\\ed_dummy_bump#", ".dds"), "ed_dummy_bump#"); S = FS.r_open(fn); diff --git a/src/Layers/xrRenderPC_R1/FStaticRender.cpp b/src/Layers/xrRenderPC_R1/FStaticRender.cpp index 617d8d4bc9..78770e5d3b 100644 --- a/src/Layers/xrRenderPC_R1/FStaticRender.cpp +++ b/src/Layers/xrRenderPC_R1/FStaticRender.cpp @@ -21,7 +21,7 @@ #include "../../xrCPU_Pipe/ttapi.h" #endif - +#include "../../xrParticles/ParticlesAsyncManager.h" using namespace R_dsgraph; CRender RImplementation; @@ -31,7 +31,7 @@ ShaderElement* CRender::rimp_select_sh_dynamic(dxRender_Visual* pVisual, float c { switch (phase) { - case PHASE_NORMAL: return (RImplementation.L_Projector->shadowing() +case PHASE_NORMAL: return (L_Projector->shadowing() ? pVisual->shader->E[SE_R1_NORMAL_HQ] : pVisual->shader->E[SE_R1_NORMAL_LQ])._get(); case PHASE_POINT: return pVisual->shader->E[SE_R1_LPOINT]._get(); @@ -77,26 +77,22 @@ void CRender::create() // distortion u32 v_dev = CAP_VERSION(HW.Caps.raster_major, HW.Caps.raster_minor); u32 v_need = CAP_VERSION(1, 4); - if (v_dev >= v_need) o.distortion = TRUE; - else o.distortion = FALSE; - if (strstr(Core.Params, "-nodistort")) o.distortion = FALSE; + o.distortion = v_dev >= v_need && !Core.ParamsData.test(ECoreParams::nodistort); Msg("* distortion: %s, dev(%d),need(%d)", o.distortion ? "used" : "unavailable", v_dev, v_need); // Color mapping - if (v_dev >= v_need) o.color_mapping = TRUE; - else o.color_mapping = FALSE; - if (strstr(Core.Params, "-nocolormap")) o.color_mapping = FALSE; + o.color_mapping = v_dev >= v_need && !Core.ParamsData.test(ECoreParams::nocolormap); Msg("* color_mapping: %s, dev(%d),need(%d)", o.color_mapping ? "used" : "unavailable", v_dev, v_need); - m_skinning = -1; + Engine.External.SetSkinningMode(); // disasm - o.disasm = (strstr(Core.Params, "-disasm")) ? TRUE : FALSE; - o.forceskinw = (strstr(Core.Params, "-skinw")) ? TRUE : FALSE; + o.disasm = Core.ParamsData.test(ECoreParams::disasm); + o.forceskinw = Core.ParamsData.test(ECoreParams::skinw); o.no_detail_textures = !ps_r2_ls_flags.test(R1FLAG_DETAIL_TEXTURES); c_ldynamic_props = "L_dynamic_props"; - o.no_ram_textures = (strstr(Core.Params, "-noramtex")) ? TRUE : ps_r__common_flags.test(RFLAG_NO_RAM_TEXTURES); + o.no_ram_textures = Core.ParamsData.test(ECoreParams::noramtex) ? TRUE : ps_r__common_flags.test(RFLAG_NO_RAM_TEXTURES); if (o.no_ram_textures) Msg("* Managed textures disabled"); else @@ -113,13 +109,14 @@ void CRender::create() PSLibrary.OnCreate(); //. HWOCC.occq_create (occq_size); - ::PortalTraverser.initialize(); + GMBase.initialize(); + Device.ModelDefferClear = xr_make_delegate(Models, &CModelPool::DeleteQueuedDeffer); } void CRender::destroy() { m_bMakeAsyncSS = false; - ::PortalTraverser.destroy(); + GMBase.destroy(); //. HWOCC.occq_destroy (); PSLibrary.OnDestroy(); @@ -130,7 +127,7 @@ void CRender::destroy() xr_delete(Target); Device.seqFrame.Remove(this); - r_dsgraph_destroy(); + Device.ModelDefferClear = nullptr; } void CRender::reset_begin() @@ -155,7 +152,7 @@ void CRender::reset_end() // let's reload details while changed details options on vid_restart if (b_loaded && (dm_current_size != dm_size || ps_r__Detail_density != ps_current_detail_density)) { - Details = new CDetailManager(); + Details = xr_new(); Details->Load(); } @@ -168,15 +165,11 @@ void CRender::OnFrame() { Models->DeleteQueue(); - if (ps_r2_ls_flags.test(R2FLAG_EXP_MT_CALC)) - { - // MT-details (@front) - Device.seqParallel.insert( - Device.seqParallel.begin(), fastdelegate::FastDelegate0<>(Details, &CDetailManager::MT_CALC)); + //Lights Delete queue + for (light* L : v_all_lights_dque) + xr_delete(L); - // MT-HOM (@front) - Device.seqParallel.insert(Device.seqParallel.begin(), fastdelegate::FastDelegate0<>(&HOM, &CHOM::MT_RENDER)); - } + v_all_lights_dque.clear(); } // Implementation @@ -189,7 +182,15 @@ IRenderVisual* CRender::model_Duplicate(IRenderVisual* V) { return Models->Insta void CRender::model_Delete(IRenderVisual* & V, BOOL bDiscard) { dxRender_Visual* pVisual = (dxRender_Visual*)V; - Models->Delete(pVisual, bDiscard); + if (Models) + Models->Delete(pVisual, bDiscard); + V = 0; +} + +void CRender::model_Delete_Deffered(IRenderVisual* & V) +{ + dxRender_Visual* pVisual = (dxRender_Visual*)V; + Models->DeleteDeffered(pVisual); V = 0; } @@ -291,20 +292,11 @@ IRender_Light* CRender::light_create() { return L_DB->Create(); } IRender_Glow* CRender::glow_create() { return xr_new(); } -void CRender::flush() { r_dsgraph_render_graph(0); } +void CRender::flush() { RImplementation.GMBase.r_dsgraph_render_graph(0); } BOOL CRender::occ_visible(vis_data& P) { return HOM.visible(P); } BOOL CRender::occ_visible(sPoly& P) { return HOM.visible(P); } BOOL CRender::occ_visible(Fbox& P) { return HOM.visible(P); } -ENGINE_API extern BOOL g_bRendering; - -void CRender::add_Visual(IRenderVisual* V) -{ - VERIFY(g_bRendering); - add_leafs_Dynamic((dxRender_Visual*)V); -} - -void CRender::add_Geometry(IRenderVisual* V) { add_Static((dxRender_Visual*)V, View->getMask()); } // demonized: add user defined rotation to wallmark void CRender::add_StaticWallmark(ref_shader& S, const Fvector& P, float s, CDB::TRI* T, Fvector* verts, float ttl, bool ignore_opt, bool random_rotation) @@ -345,7 +337,7 @@ void CRender::clear_static_wallmarks() void CRender::add_SkeletonWallmark(intrusive_ptr wm) { - Wallmarks->AddSkeletonWallmark(wm); + Wallmarks->AddSkeletonWallmark(std::move(wm)); } void CRender::add_SkeletonWallmark(const Fmatrix* xf, CKinematics* obj, ref_shader& sh, const Fvector& start, @@ -362,6 +354,16 @@ void CRender::add_SkeletonWallmark(const Fmatrix* xf, IKinematics* obj, IWallMar if (pShader) add_SkeletonWallmark(xf, (CKinematics*)obj, *pShader, start, dir, size, ttl, ignore_opt); } +void CRender::remove_SkeletonWallmarksFromObject(IKinematics* obj) +{ + Wallmarks->RemoveSkeletonWallmarksFromObject(static_cast(obj)); +} + +void CRender::update_Wallmarks() +{ + Wallmarks->UpdateWallmarks(); +} + void CRender::add_Occluder(Fbox2& bb_screenspace) { VERIFY(_valid(bb_screenspace)); @@ -370,47 +372,18 @@ void CRender::add_Occluder(Fbox2& bb_screenspace) #include "../../xrEngine/PS_instance.h" -void CRender::set_Object(IRenderable* O) -{ - VERIFY(g_bRendering); - val_pObject = O; // NULL is OK, trust me :) - if (val_pObject) - { - VERIFY(fast_dynamic_cast(O) || fast_dynamic_cast(O)); - if (O->renderable.pROS) { VERIFY(fast_dynamic_cast(O->renderable.pROS)); } - } - if (PHASE_NORMAL == phase) - { - if (L_Shadows) - L_Shadows->set_object(O); - - if (L_Projector) - L_Projector->set_object(O); - } - else - { - if (L_Shadows) - L_Shadows->set_object(0); - - if (L_Projector) - L_Projector->set_object(0); - } -} - void CRender::apply_object(IRenderable* O) { if (0 == O) return; if (O->renderable_ROS()) { CROS_impl& LT = *((CROS_impl*)O->renderable.pROS); - VERIFY(fast_dynamic_cast(O) || fast_dynamic_cast(O)); - VERIFY(fast_dynamic_cast(O->renderable.pROS)); float o_hemi = 0.5f * LT.get_hemi(); float o_sun = 0.5f * LT.get_sun(); RCache.set_c(c_ldynamic_props, o_sun, o_sun, o_sun, o_hemi); // shadowing if ((LT.shadow_recv_frame == Device.dwFrame) && O->renderable_ShadowReceive()) - RImplementation.L_Projector->setup(LT.shadow_recv_slot); + L_Projector->setup(LT.shadow_recv_slot); } } @@ -438,6 +411,12 @@ CRender::CRender() CRender::~CRender() { + for (auto& it : SWIs) { + xr_free(it.sw); + it.sw = nullptr; + it.count = 0; + } + SWIs.clear(); } extern float r_ssaDISCARD; @@ -446,13 +425,6 @@ extern float r_ssaLOD_A, r_ssaLOD_B; extern float r_ssaGLOD_start, r_ssaGLOD_end; extern float r_ssaHZBvsTEX; -ICF bool pred_sp_sort(ISpatial* _1, ISpatial* _2) -{ - float d1 = _1->spatial.sphere.P.distance_to_sqr(Device.vCameraPosition); - float d2 = _2->spatial.sphere.P.distance_to_sqr(Device.vCameraPosition); - return d1 < d2; -} - void CRender::Calculate() { #ifdef _GPA_ENABLED @@ -475,12 +447,7 @@ void CRender::Calculate() // Frustum & HOM rendering ViewBase.CreateFromMatrix(Device.mFullTransform, FRUSTUM_P_LRTB | FRUSTUM_P_FAR); - View = 0; - if (!ps_r2_ls_flags.test(R2FLAG_EXP_MT_CALC)) - { - HOM.Enable(); - HOM.Render(ViewBase); - } + HOM.MT_RENDER(); gm_SetNearer(FALSE); phase = PHASE_NORMAL; @@ -496,174 +463,17 @@ void CRender::Calculate() vLastCameraPos.set(Device.vCameraPosition); } - // Check if camera is too near to some portal - if so force DualRender - if (rmPortals) - { - Fvector box_radius; - box_radius.set(EPS_L * 2, EPS_L * 2, EPS_L * 2); - Sectors_xrc.box_options(CDB::OPT_FULL_TEST); - Sectors_xrc.box_query(rmPortals, Device.vCameraPosition, box_radius); - for (int K = 0; K < Sectors_xrc.r_count(); K++) - { - CPortal* pPortal = (CPortal*)Portals[rmPortals->get_tris()[Sectors_xrc.r_begin()[K].id].dummy]; - pPortal->bDualRender = TRUE; - } - } // if (L_DB) L_DB->Update(); // Main process - marker++; - if (pLastSector) - { - // Traverse sector/portal structure - PortalTraverser.traverse - ( - pLastSector, - ViewBase, - Device.vCameraPosition, - Device.mFullTransform, - CPortalTraverser::VQ_HOM + CPortalTraverser::VQ_SSA + CPortalTraverser::VQ_FADE - ); - - // Determine visibility for static geometry hierrarhy - if (psDeviceFlags.test(rsDrawStatic)) - { - for (u32 s_it = 0; s_it < PortalTraverser.r_sectors.size(); s_it++) - { - CSector* sector = (CSector*)PortalTraverser.r_sectors[s_it]; - dxRender_Visual* root = sector->root(); - for (u32 v_it = 0; v_it < sector->r_frustums.size(); v_it++) - { - set_Frustum(&(sector->r_frustums[v_it])); - add_Geometry(root); - } - } - } - - // Traverse object database - if (psDeviceFlags.test(rsDrawDynamic)) - { - g_SpatialSpace->q_frustum - ( - lstRenderables, - ISpatial_DB::O_ORDERED, - STYPE_RENDERABLE + STYPE_LIGHTSOURCE, - ViewBase - ); - - // Exact sorting order (front-to-back) - std::sort(lstRenderables.begin(), lstRenderables.end(), pred_sp_sort); - - // Determine visibility for dynamic part of scene - set_Object(0); - g_hud->Render_First(); // R1 shadows - g_hud->Render_Last(); - u32 uID_LTRACK = 0xffffffff; - if (phase == PHASE_NORMAL) - { - uLastLTRACK++; - if (lstRenderables.size()) uID_LTRACK = uLastLTRACK % lstRenderables.size(); - - // update light-vis for current entity / actor - CObject* O = g_pGameLevel->CurrentViewEntity(); - if (O) - { - CROS_impl* R = (CROS_impl*)O->ROS(); - if (R) R->update(O); - } - } - for (u32 o_it = 0; o_it < lstRenderables.size(); o_it++) - { - ISpatial* spatial = lstRenderables[o_it]; - spatial->spatial_updatesector(); - CSector* sector = (CSector*)spatial->spatial.sector; - if (0 == sector) - continue; // disassociated from S/P structure + GMBase.traverse(pLastSector, ViewBase, Device.vCameraPosition, Device.mFullTransform); + GMBase.r_dsgraph_capture(true, true); - // Filter only not light spatial - if (PortalTraverser.i_marker != sector->r_marker && (spatial->spatial.type & STYPE_RENDERABLE)) continue - ; // inactive (untouched) sector - - if (spatial->spatial.type & STYPE_RENDERABLE) - { - for (u32 v_it = 0; v_it < sector->r_frustums.size(); v_it++) - { - set_Frustum(&(sector->r_frustums[v_it])); - - if (!View->testSphere_dirty(spatial->spatial.sphere.P, spatial->spatial.sphere.R) - /*&& (spatial->spatial.type & STYPE_RENDERABLE)*/) continue; - // renderable - IRenderable* renderable = spatial->dcast_Renderable(); - if (0 == renderable) - { - // It may be an glow - CGlow* glow = fast_dynamic_cast(spatial); - VERIFY(glow); - L_Glows->add(glow); - } - else - { - // Occlusiond - vis_data& v_orig = renderable->renderable.visual->getVisData(); - vis_data v_copy = v_orig; - v_copy.box.xform(renderable->renderable.xform); - BOOL bVisible = HOM.visible(v_copy); - v_orig.accept_frame = v_copy.accept_frame; - v_orig.marker = v_copy.marker; - v_orig.hom_frame = v_copy.hom_frame; - v_orig.hom_tested = v_copy.hom_tested; - if (!bVisible) break; // exit loop on frustums - - // rendering - if (o_it == uID_LTRACK && renderable->renderable_ROS()) - { - // track lighting environment - CROS_impl* T = (CROS_impl*)renderable->renderable_ROS(); - T->update(renderable); - } - set_Object(renderable); - renderable->renderable_Render(); - set_Object(0); //? is it needed at all - } - break; // exit loop on frustums - } - } - else - { - if (ViewBase.testSphere_dirty(spatial->spatial.sphere.P, spatial->spatial.sphere.R)) - { - VERIFY(spatial->spatial.type & STYPE_LIGHTSOURCE); - // lightsource - light* L = (light*)spatial->dcast_Light(); - VERIFY(L); - if (L->spatial.sector) - { - vis_data& vis = L->get_homdata(); - if (HOM.visible(vis)) L_DB->add_light(L); - } - } - } - } - } - - // Calculate miscelaneous stuff - L_Shadows->calculate(); - L_Projector->calculate(); - } - else - { - set_Object(0); - /* - g_pGameLevel->pHUD->Render_First (); - g_pGameLevel->pHUD->Render_Last (); - - // Calculate miscelaneous stuff - L_Shadows->calculate (); - L_Projector->calculate (); - */ - } + // Calculate miscelaneous stuff + L_Shadows->calculate(); + L_Projector->calculate(); // End calc Device.Statistic->RenderCALC.End(); @@ -703,24 +513,19 @@ void CRender::Render() return; } - Device.Statistic->RenderDUMP.Begin(); // Begin Target->Begin(); - o.vis_intersect = FALSE; phase = PHASE_NORMAL; - r_dsgraph_render_hud(); // hud - r_dsgraph_render_graph(0); // normal level + GMBase.r_dsgraph_render_hud(); // hud + GMBase.r_dsgraph_render_graph(0); // normal level if (Details)Details->Render(); // grass / details - r_dsgraph_render_lods(true, false); // lods - FB + GMBase.r_dsgraph_render_lods(true, false); // lods - FB CEnvironment* Env = &g_pGamePersistent->Environment(); Env->RenderSky(); // sky / sun Env->RenderClouds(); // clouds - r_pmask(true, false); // disable priority "1" - o.vis_intersect = TRUE; - HOM.Disable(); L_Dynamic->render(0); // addititional light sources if (Wallmarks)Wallmarks->Render(); // wallmarks has priority as normal geometry @@ -729,21 +534,20 @@ void CRender::Render() g_hud->Render_R1_Attachment_UI(); if (g_hud->RenderActiveItemUIQuery()) - r_dsgraph_render_hud_ui(); + GMBase.r_dsgraph_render_hud_ui(); if (g_hud->RenderCamAttachedUIQuery()) - r_dsgraph_render_cam_ui(); + GMBase.r_dsgraph_render_cam_ui(); } - HOM.Enable(); - o.vis_intersect = FALSE; phase = PHASE_NORMAL; - r_pmask(true, true); // enable priority "0" and "1" if (L_Shadows)L_Shadows->render(); // ... and shadows - r_dsgraph_render_lods(false, true); // lods - FB - r_dsgraph_render_graph(1); // normal level, secondary priority + GMBase.r_dsgraph_render_lods(false, true); // lods - FB + GMBase.r_dsgraph_render_static(1); // normal level, secondary priority + CParticlesAsync::Wait(); + GMBase.r_dsgraph_render_dynamic(1, true); // normal level, secondary priority L_Dynamic->render(1); // addititional light sources, secondary priority - PortalTraverser.fade_render(); // faded-portals - r_dsgraph_render_sorted(); // strict-sorted geoms + GMBase.fade_render(); // faded-portals + GMBase.r_dsgraph_render_sorted(); // strict-sorted geoms if (L_Glows)L_Glows->Render(); // glows if (ps_r2_anomaly_flags.test(R2_AN_FLAG_FLARES))Env->RenderFlares(); // lens-flares Env->RenderLast(); // rain/thunder-bolts @@ -753,8 +557,8 @@ void CRender::Render() { for ( u32 iPass = 0; iPass Portals; @@ -77,6 +73,15 @@ class CRender : public R_dsgraph_structure CDetailManager* Details; CModelPool* Models; + //CFrustum rainwet_cull_frustum; + //Fvector3 rainwet_cull_COP; + //Fmatrix rainwet_cull_xform; + // + //CDSGraphManager GMRainWet = CDSGraphManager(u32(0), u32(STYPE_RENDERABLE), { true,false,false,false,true,false,false }); + CDSGraphManager GMBase = CDSGraphManager(u32(CDSGraphManager::VQ_HOM + CDSGraphManager::VQ_SSA + CDSGraphManager::VQ_FADE), + u32(STYPE_RENDERABLE + STYPE_PARTICLE + STYPE_LIGHTSOURCE), + { true,true,true,true,false,false,false }); + CRenderTarget* Target; // Render-target // R1-specific global constants @@ -89,6 +94,7 @@ class CRender : public R_dsgraph_structure shared_str c_ldynamic_props; bool m_bMakeAsyncSS; bool m_bFirstFrameAfterReset; // Determines weather the frame is the first after resetting device. + xr_list v_all_lights_dque; private: // Loading / Unloading @@ -98,11 +104,6 @@ class CRender : public R_dsgraph_structure void LoadSectors(IReader* fs); void LoadSWIs(CStreamReader* fs); - BOOL add_Dynamic(dxRender_Visual* pVisual, u32 planes); // normal processing - void add_Static(dxRender_Visual* pVisual, u32 planes); - void add_leafs_Dynamic(dxRender_Visual* pVisual); // if detected node's full visibility - void add_leafs_Static(dxRender_Visual* pVisual); // if detected node's full visibility - public: ShaderElement* rimp_select_sh_static(dxRender_Visual* pVisual, float cdist_sq); ShaderElement* rimp_select_sh_dynamic(dxRender_Visual* pVisual, float cdist_sq); @@ -152,15 +153,16 @@ class CRender : public R_dsgraph_structure virtual IRender_Sector* getSector(int id); virtual IRenderVisual* getVisual(int id); virtual IRender_Sector* detectSector(const Fvector& P); + IRender_Sector* detectLastSector(const Fvector& P); + IRender_Sector* detectSector(const Fvector& P, Fvector& D); + void detectSectors_sphere(CSector* sector, FixedSet& m_sectors, const Fvector& b_center, const Fvector& b_dim); + void detectSectors_frustum(CSector* sector, FixedSet& m_sectors, CFrustum* _frustum); int translateSector(IRender_Sector* pSector); virtual IRender_Target* getTarget(); // Main virtual void flush(); - virtual void set_Object(IRenderable* O); virtual void add_Occluder(Fbox2& bb_screenspace); // mask screen region as oclluded - virtual void add_Visual(IRenderVisual* V); // add visual leaf (no culling performed at all) - virtual void add_Geometry(IRenderVisual* V); // add visual(s) (all culling performed) // wallmarks // demonized: add user defined rotation to wallmark @@ -177,6 +179,9 @@ class CRender : public R_dsgraph_structure virtual void add_SkeletonWallmark(const Fmatrix* xf, IKinematics* obj, IWallMarkArray* pArray, const Fvector& start, const Fvector& dir, float size, float ttl = 0.f, bool ignore_opt = false); + virtual void remove_SkeletonWallmarksFromObject(IKinematics* obj); + virtual void update_Wallmarks(); + // virtual IBlender* blender_create(CLASS_ID cls); virtual void blender_destroy(IBlender* &); @@ -199,6 +204,7 @@ class CRender : public R_dsgraph_structure virtual IRenderVisual* model_CreateChild(LPCSTR name, IReader* data); virtual IRenderVisual* model_Duplicate(IRenderVisual* V); virtual void model_Delete(IRenderVisual* & V, BOOL bDiscard); + virtual void model_Delete_Deffered(IRenderVisual* & V); virtual void model_Delete(IRender_DetailModel* & F); virtual void model_Logging(BOOL bEnable) { Models->Logging(bEnable); } virtual void models_Prefetch(); @@ -269,6 +275,8 @@ class CRender : public R_dsgraph_structure // Constructor/destructor/loader CRender(); virtual ~CRender(); + + virtual size_t SectorsCount() { return Sectors.size(); } protected: virtual void ScreenshotImpl(ScreenshotMode mode, LPCSTR name, CMemoryWriter* memory_writer); diff --git a/src/Layers/xrRenderPC_R1/FStaticRender_DetectSector.cpp b/src/Layers/xrRenderPC_R1/FStaticRender_DetectSector.cpp deleted file mode 100644 index d92f70e1ad..0000000000 --- a/src/Layers/xrRenderPC_R1/FStaticRender_DetectSector.cpp +++ /dev/null @@ -1,76 +0,0 @@ -#include "stdafx.h" - -int CRender::translateSector(IRender_Sector* pSector) -{ - if (!pSector) - return -1; - - for (u32 i = 0; i < Sectors.size(); ++i) - { - if (Sectors[i] == pSector) - return i; - } - - FATAL("Sector was not found!"); - NODEFAULT; - -#ifdef DEBUG - return (-1); -#endif // #ifdef DEBUG -} - -IRender_Sector* CRender::detectSector(const Fvector& P) -{ - Sectors_xrc.ray_options(CDB::OPT_ONLYNEAREST); - Fvector dir; - dir.set(0, -1, 0); - - // Portals model - int id1 = -1; - float range1 = 500.f; - if (rmPortals) - { - Sectors_xrc.ray_query(rmPortals, P, dir, range1); - if (Sectors_xrc.r_count()) - { - CDB::RESULT* RP1 = Sectors_xrc.r_begin(); - id1 = RP1->id; - range1 = RP1->range; - } - } - - // Geometry model - int id2 = -1; - float range2 = range1; - Sectors_xrc.ray_query(g_pGameLevel->ObjectSpace.GetStaticModel(), P, dir, range2); - if (Sectors_xrc.r_count()) - { - CDB::RESULT* RP2 = Sectors_xrc.r_begin(); - id2 = RP2->id; - range2 = RP2->range; - } - - // Select ID - int ID; - if (id1 >= 0) - { - if (id2 >= 0) ID = (range1 <= range2 + EPS) ? id1 : id2; // both was found - else ID = id1; // only id1 found - } - else if (id2 >= 0) ID = id2; // only id2 found - else return 0; - - if (ID == id1) - { - // Take sector, facing to our point from portal - CDB::TRI* pTri = rmPortals->get_tris() + ID; - CPortal* pPortal = (CPortal*)Portals[pTri->dummy]; - return pPortal->getSectorFacing(P); - } - else - { - // Take triangle at ID and use it's Sector - CDB::TRI* pTri = g_pGameLevel->ObjectSpace.GetStaticTris() + ID; - return getSector(pTri->sector); - } -} diff --git a/src/Layers/xrRenderPC_R1/FStaticRender_Loader.cpp b/src/Layers/xrRenderPC_R1/FStaticRender_Loader.cpp index 0884e92b50..3146eccfcf 100644 --- a/src/Layers/xrRenderPC_R1/FStaticRender_Loader.cpp +++ b/src/Layers/xrRenderPC_R1/FStaticRender_Loader.cpp @@ -63,8 +63,6 @@ void CRender::level_Load(IReader* fs) rmFar(); rmNormal(); - marker = 0; - if (!g_dedicated_server) { // VB,IB,SWI @@ -110,6 +108,8 @@ void CRender::level_Unload() if (0 == g_pGameLevel) return; if (!b_loaded) return; + GMBase.clear(); + u32 I; // HOM @@ -122,6 +122,7 @@ void CRender::level_Unload() // 1. xr_delete(rmPortals); pLastSector = 0; + pOutdoorSector = 0; vLastCameraPos.set(flt_max,flt_max,flt_max); uLastLTRACK = 0; @@ -282,7 +283,8 @@ void CRender::LoadLights(IReader* fs) // glows IReader* chunk = fs->open_chunk(fsL_GLOWS); - R_ASSERT(chunk && "Can't find glows"); + if (!chunk) + return; L_Glows->Load(chunk); chunk->close(); } @@ -359,6 +361,23 @@ void CRender::LoadSectors(IReader* fs) // Sectors[d]->DebugDump (); pLastSector = 0; + + // Search for default sector - assume "default" or "outdoor" sector is the largest one + //. hack: need to know real outdoor sector + CSector* largest_sector = 0; + float largest_sector_vol = 0; + for (u32 s = 0; s < Sectors.size(); s++) + { + CSector* S = (CSector*)Sectors[s]; + dxRender_Visual* V = S->root(); + float vol = V->vis.box.getvolume(); + if (vol > largest_sector_vol) + { + largest_sector_vol = vol; + largest_sector = S; + } + } + pOutdoorSector = largest_sector; } void CRender::LoadSWIs(CStreamReader* base_fs) diff --git a/src/Layers/xrRenderPC_R1/FStaticRender_RenderTarget.cpp b/src/Layers/xrRenderPC_R1/FStaticRender_RenderTarget.cpp index 6064746943..8438bc7257 100644 --- a/src/Layers/xrRenderPC_R1/FStaticRender_RenderTarget.cpp +++ b/src/Layers/xrRenderPC_R1/FStaticRender_RenderTarget.cpp @@ -317,12 +317,7 @@ void CRenderTarget::End() BOOL bDistort = RImplementation.o.distortion; BOOL bCMap = NeedColorMapping(); bool _menu_pp = g_pGamePersistent ? g_pGamePersistent->OnRenderPPUI_query() : false; - u32 count = RImplementation.mapDistort.size() + RImplementation.mapHUDDistort.size(); - - if ((0 == count) && !_menu_pp) - { - bDistort = FALSE; - } + if ((0==RImplementation.GMBase.RGraph.mapStaticSorted.Distort.size() && 0 == RImplementation.GMBase.RGraph.mapDynamicSorted.Distort.size() && 0 == RImplementation.GMBase.RGraph.mapHUDSorted.Distort.size()) && !_menu_pp) bDistort = FALSE; if (bDistort) { phase_distortion(); @@ -412,12 +407,13 @@ void CRenderTarget::phase_distortion() if (g_pGameLevel && g_pGamePersistent && !g_pGamePersistent->OnRenderPPUI_query()) { - RImplementation.r_dsgraph_render_distort(); + RImplementation.GMBase.r_dsgraph_render_distort(); } else { - RImplementation.mapDistort.clear(); - RImplementation.mapHUDDistort.clear(); + RImplementation.GMBase.RGraph.mapStaticSorted.Distort.clear(); + RImplementation.GMBase.RGraph.mapDynamicSorted.Distort.clear(); + RImplementation.GMBase.RGraph.mapHUDSorted.Distort.clear(); } if (g_pGamePersistent) g_pGamePersistent->OnRenderPPUI_PP(); // PP-UI diff --git a/src/Layers/xrRenderPC_R1/GlowManager.cpp b/src/Layers/xrRenderPC_R1/GlowManager.cpp index 87c0cdcd5c..e91a696e03 100644 --- a/src/Layers/xrRenderPC_R1/GlowManager.cpp +++ b/src/Layers/xrRenderPC_R1/GlowManager.cpp @@ -17,8 +17,9 @@ ////////////////////////////////////////////////////////////////////// -CGlow::CGlow() : ISpatial(g_SpatialSpace) +CGlow::CGlow()// : ISpatial(g_SpatialSpace) { + ISpatialOwner::spatial_create(g_SpatialSpace, this, STYPE_GLOW); flags.bActive = false; position.set(0, 0, 0); direction.set(0, 0, 0); @@ -27,7 +28,6 @@ CGlow::CGlow() : ISpatial(g_SpatialSpace) bTestResult = FALSE; fade = 1.f; dwFrame = 0; - spatial.type = STYPE_RENDERABLE; } CGlow::~CGlow() @@ -42,13 +42,13 @@ void CGlow::set_active(bool a) { if (flags.bActive) return; flags.bActive = true; - spatial_register(); + ISpatialOwner::spatial_register(); } else { if (!flags.bActive) return; flags.bActive = false; - spatial_unregister(); + ISpatialOwner::spatial_unregister(); } } @@ -90,8 +90,8 @@ void CGlow::set_color(float r, float g, float b) void CGlow::spatial_move() { - spatial.sphere.set(position, radius); - ISpatial::spatial_move(); + SpatialComponent->spatial.sphere.set(position, radius); + ISpatialOwner::spatial_move(); } ////////////////////////////////////////////////////////////////////// @@ -121,7 +121,7 @@ void CGlowManager::Load(IReader* fs) CGlow* G = xr_new(); fs->r(&G->position, 3 * sizeof(float)); fs->r(&G->radius, 1 * sizeof(float)); - G->spatial.sphere.set(G->position, G->radius); + G->SpatialComponent->spatial.sphere.set(G->position, G->radius); G->direction.set(0, 0, 0); u16 S = fs->r_u16(); @@ -131,7 +131,7 @@ void CGlowManager::Load(IReader* fs) G->dwFrame = 0x0; G->bTestResult = TRUE; - G->spatial.type = STYPE_RENDERABLE; + G->SpatialComponent->spatial.type = STYPE_RENDERABLE; G->set_active(true); @@ -169,7 +169,7 @@ void CGlowManager::add(ref_glow G_) float dt = Device.fTimeDelta; float dlim2 = MAX_GlowsDist2; - float range = Device.vCameraPosition.distance_to_sqr(G->spatial.sphere.P); + float range = Device.vCameraPosition.distance_to_sqr(G->position); if (range < dlim2) { // 2. Use result of test @@ -241,7 +241,7 @@ void CGlowManager::render_sw() if (G.dwFrame == 'test') break; G.dwFrame = 'test'; Fvector dir; - dir.sub(G.spatial.sphere.P, start); + dir.sub(G.position, start); float range = dir.magnitude(); if (range > EPS_S) { diff --git a/src/Layers/xrRenderPC_R1/GlowManager.h b/src/Layers/xrRenderPC_R1/GlowManager.h index 6783418e6d..e4fbe6920b 100644 --- a/src/Layers/xrRenderPC_R1/GlowManager.h +++ b/src/Layers/xrRenderPC_R1/GlowManager.h @@ -9,7 +9,9 @@ #include "../../xrcdb/ispatial.h" #include "../../xrcdb/xr_collide_defs.h" -class CGlow : public IRender_Glow, public ISpatial +class CGlow: + public IRender_Glow, + public ISpatialOwner { public: struct @@ -43,7 +45,9 @@ class CGlow : public IRender_Glow, public ISpatial virtual void set_texture(LPCSTR name); virtual void set_color(const Fcolor& C); virtual void set_color(float r, float g, float b); - virtual void spatial_move(); + virtual void spatial_move() override; + + virtual CGlow* dcast_CGlow() override { return this; }; }; #define MAX_GlowsPerFrame 64 diff --git a/src/Layers/xrRenderPC_R1/LightPPA.cpp b/src/Layers/xrRenderPC_R1/LightPPA.cpp index d1279436c8..bed71119bb 100644 --- a/src/Layers/xrRenderPC_R1/LightPPA.cpp +++ b/src/Layers/xrRenderPC_R1/LightPPA.cpp @@ -154,10 +154,10 @@ void CLightR_Manager::render_point(u32 _priority) for (xr_vector::iterator it = selected_point.begin(); it != selected_point.end(); it++) { light* L = *it; - VERIFY(L->spatial.sector && _valid(L->range)); + VERIFY(L->SpatialComponent->spatial.sector && _valid(L->range)); // 0. Dimm & Clip - float lc_dist = lc_COP.distance_to(L->spatial.sphere.P) - L->spatial.sphere.R; + float lc_dist = lc_COP.distance_to(L->SpatialComponent->spatial.sphere.P) - L->SpatialComponent->spatial.sphere.R; float lc_scale = 1 - lc_dist / lc_limit; if (lc_scale < EPS) continue; if (L->range < 0.01f) continue; @@ -198,32 +198,32 @@ void CLightR_Manager::render_point(u32 _priority) RImplementation.r1_dlight_tcgen = L_texgen; // 3. Calculate visibility for light + build soring tree - VERIFY(L->spatial.sector); - if (_priority == 1) - RImplementation.r_pmask(false, true); + VERIFY(L->SpatialComponent->spatial.sector); + //if( _priority == 1) + // RImplementation.r_pmask (false,true); - RImplementation.r_dsgraph_render_subspace( - L->spatial.sector, - L_combine, - L_pos, - true, - true - ); + CFrustum F; + F.CreateFromMatrix(L_combine, FRUSTUM_P_LRTB | FRUSTUM_P_FAR); - if (_priority == 1) - RImplementation.r_pmask(true, true); + L->GMLight.traverse((CSector*)L->SpatialComponent->spatial.sector, F, L_pos, L_combine); + L->GMLight.r_dsgraph_capture(false,true); + //if( _priority == 1) + // RImplementation.r_pmask (true,true); + F.CreateFromMatrix(L_combine, FRUSTUM_P_ALL); // 4. Analyze if HUD intersects light volume - BOOL bHUD = FALSE; - CFrustum F; - F.CreateFromMatrix(L_combine,FRUSTUM_P_ALL); - bHUD = F.testSphere_dirty(Device.vCameraPosition, 2.f); + BOOL bHUD = FALSE; + bHUD = F.testSphere_dirty(Device.vCameraPosition,2.f); // 5. Dump sorting tree RCache.set_Constants((R_constant_table*)0); - if (bHUD && _priority == 0) g_hud->Render_Last(); - RImplementation.r_dsgraph_render_graph(_priority); - if (bHUD && _priority == 0) RImplementation.r_dsgraph_render_hud(); + if (bHUD&&_priority == 0) + g_hud->Render_Last(&L->GMLight); + + L->GMLight.r_dsgraph_render_graph(_priority); + + if (bHUD&&_priority == 0) + L->GMLight.r_dsgraph_render_hud(); } // ??? grass ??? } @@ -240,7 +240,7 @@ void CLightR_Manager::render_spot(u32 _priority) light* L = *it; // 0. Dimm & Clip - float lc_dist = lc_COP.distance_to(L->spatial.sphere.P) - L->spatial.sphere.R; + float lc_dist = lc_COP.distance_to(L->SpatialComponent->spatial.sphere.P) - L->SpatialComponent->spatial.sphere.R; float lc_scale = 1 - lc_dist / lc_limit; if (lc_scale < EPS) continue; @@ -280,35 +280,35 @@ void CLightR_Manager::render_spot(u32 _priority) RImplementation.r1_dlight_tcgen = L_texgen; // 3. Calculate visibility for light + build soring tree - VERIFY(L->spatial.sector); + VERIFY(L->SpatialComponent->spatial.sector); // RImplementation.marker ++; - if (_priority == 1) - RImplementation.r_pmask(false, true); + //if( _priority == 1) + // RImplementation.r_pmask (false,true); - RImplementation.r_dsgraph_render_subspace( - L->spatial.sector, - L_combine, - L_pos, - TRUE, - TRUE // precise portals - ); - - if (_priority == 1) - RImplementation.r_pmask(true, true); + CFrustum F; + F.CreateFromMatrix(L_combine, FRUSTUM_P_LRTB | FRUSTUM_P_FAR); + L->GMLight.traverse((CSector*)L->SpatialComponent->spatial.sector, F, L_pos, L_combine); + L->GMLight.r_dsgraph_capture(false, true); + //if( _priority == 1) + // RImplementation.r_pmask (true,true); + F.CreateFromMatrix(L_combine, FRUSTUM_P_ALL); // 4. Analyze if HUD intersects light volume - BOOL bHUD = FALSE; - CFrustum F; - F.CreateFromMatrix(L_combine,FRUSTUM_P_ALL); - bHUD = F.testSphere_dirty(Device.vCameraPosition, 2.f); + BOOL bHUD = FALSE; + bHUD = F.testSphere_dirty(Device.vCameraPosition,2.f); // if (bHUD) Msg ("HUD"); // 4. Dump sorting tree // RCache.set_ClipPlanes (true, &L_combine); RCache.set_Constants((R_constant_table*)0); - if (bHUD && _priority == 0) g_hud->Render_Last(); - RImplementation.r_dsgraph_render_graph(_priority); - if (bHUD && _priority == 0) RImplementation.r_dsgraph_render_hud(); + + if (bHUD&&_priority == 0) + g_hud->Render_Last(&L->GMLight); + + L->GMLight.r_dsgraph_render_graph(_priority); + + if (bHUD&&_priority == 0) + L->GMLight.r_dsgraph_render_hud(); // RCache.set_ClipPlanes (false, &L_combine); } // ??? grass ???l @@ -369,7 +369,7 @@ void CLightR_Manager::render(u32 _priority) void CLightR_Manager::add(light* L) { if (L->range < 0.1f) return; - if (0 == L->spatial.sector) return; + if (0 == L->SpatialComponent->spatial.sector) return; if (IRender_Light::POINT == L->flags.type) { // PPA @@ -380,7 +380,7 @@ void CLightR_Manager::add(light* L) // spot/flash selected_spot.push_back(L); } - VERIFY(L->spatial.sector); + VERIFY(L->SpatialComponent->spatial.sector); } CLightR_Manager::CLightR_Manager() diff --git a/src/Layers/xrRenderPC_R1/LightProjector.cpp b/src/Layers/xrRenderPC_R1/LightProjector.cpp index a0ba0cff09..32844ab312 100644 --- a/src/Layers/xrRenderPC_R1/LightProjector.cpp +++ b/src/Layers/xrRenderPC_R1/LightProjector.cpp @@ -7,6 +7,7 @@ #include "../../include/xrRender/RenderVisual.h" #include "../../xrEngine/xr_object.h" #include "../xrRender/lighttrack.h" +#include "../xrServerEntities/smart_cast.h" #ifndef _EDITOR #include "../../xrCPU_Pipe/ttapi.h" @@ -55,13 +56,13 @@ CLightProjector::~CLightProjector() RT.destroy(); } -void CLightProjector::set_object(IRenderable* O) +void CLightProjector::set_object(IRenderable* O, IDSGraphManager& DM) { + xrCriticalSectionGuard guard(&cs); if ((0 == O) || (receivers.size() >= P_o_count)) current = 0; else { - if (!O->renderable_ShadowReceive() || RImplementation.val_bInvisible || ((CROS_impl*)O->renderable_ROS())-> - shadow_recv_frame == Device.dwFrame) + if (!O->renderable_ShadowReceive() || DM.i_mask[IDSGraphManager::fl_invisible] || ((CROS_impl*)O->renderable_ROS())->shadow_recv_frame == Device.dwFrame) { current = 0; return; @@ -78,14 +79,14 @@ void CLightProjector::set_object(IRenderable* O) if (current) { - ISpatial* spatial = fast_dynamic_cast(O); + ISpatialShared spatial = O->SpatialComponent; if (0 == spatial) current = 0; else { spatial->spatial_updatesector(); if (0 == spatial->spatial.sector) { - CObject* obj = fast_dynamic_cast(O); + CObject* obj = smart_cast(O); if (obj) Msg("! Invalid object '%s' position. Outside of sector structure.", obj->cName().c_str()); current = 0; } @@ -132,13 +133,87 @@ void CLightProjector::OnAppActivate() // #include "../xrRender/SkeletonCustom.h" +#include "../xrRender/FHierrarhyVisual.h" +#include "../xrRender/SkeletonCustom.h" +#include "../../xrEngine/Fmesh.h" +#include "../xrRender/FLOD.h" + +void r_dsgraph_render_R1_box(xr_vector& lstVisuals, CSector* _S, Fbox& BB, int sh) +{ + CSector* S = _S; + lstVisuals.clear(); + lstVisuals.push_back(S->root()); + + for (u32 i = 0; i < lstVisuals.size(); ++i) + { + auto V = lstVisuals[i]; + // Visual is 100% visible - simply add it + switch (V->Type) + { + case MT_HIERRARHY: + { + // Add all children + FHierrarhyVisual* pV = (FHierrarhyVisual*)V; + auto I = pV->children.begin(); + auto E = pV->children.end(); + for (; I != E; ++I) + { + dxRender_Visual* T = (dxRender_Visual*)*I; + if (BB.intersect(T->vis.box)) lstVisuals.push_back(T); + } + } + break; + case MT_SKELETON_ANIM: + case MT_SKELETON_RIGID: + { + // Add all children (s) + CKinematics* pV = (CKinematics*)V; + pV->CalculateBones(TRUE); + auto I = pV->children.begin(); + auto E = pV->children.end(); + for (; I != E; ++I) + { + dxRender_Visual* T = (dxRender_Visual*)*I; + if (BB.intersect(T->vis.box)) lstVisuals.push_back(T); + } + } + break; + case MT_LOD: + { + FLOD* pV = (FLOD*)V; + auto I = pV->children.begin(); + auto E = pV->children.end(); + for (; I != E; ++I) + { + dxRender_Visual* T = (dxRender_Visual*)*I; + if (BB.intersect(T->vis.box)) lstVisuals.push_back(T); + } + } + break; + default: + { + // Renderable visual + ShaderElement* E_ = V->shader->E[sh]._get(); + if (E_ && !(E_->flags.bDistort)) + { + for (u32 pass = 0; pass < E_->passes.size(); pass++) + { + RCache.set_Element(E_, pass); + V->Render(-1.f); + } + } + } + break; + } + } +} void CLightProjector::calculate() { #ifdef _GPA_ENABLED TAL_SCOPED_TASK_NAMED("CLightProjector::calculate()"); #endif // _GPA_ENABLED - + xrCriticalSectionGuard guard(&cs); if (receivers.empty()) return; // perform validate / markup @@ -238,7 +313,7 @@ void CLightProjector::calculate() v.sub(v_Cs, v_C);; #ifdef DEBUG if ((v.x * v.x + v.y * v.y + v.z * v.z) <= flt_zero) { - CObject* OO = fast_dynamic_cast(R.O); + CObject* OO = smart_cast(R.O); Msg("Object[%s] Visual[%s] has invalid position. ", *OO->cName(), *OO->cNameVisual()); Fvector cc; OO->Center(cc); @@ -253,7 +328,7 @@ void CLightProjector::calculate() Log("v_Cs", v_Cs); Log("all bones transform:--------"); - CKinematics* K = fast_dynamic_cast(OO->Visual()); + CKinematics* K = smart_cast(OO->Visual()); for (u16 ii = 0; ii < K->LL_BoneCount(); ++ii) { Fmatrix tr; @@ -318,12 +393,12 @@ void CLightProjector::calculate() BB.set(min, max); R.UVclamp_min.set(min).add(.05f); // shrink a little R.UVclamp_max.set(max).sub(.05f); // shrink a little - ISpatial* spatial = fast_dynamic_cast(O); + ISpatialShared spatial = O->SpatialComponent; if (spatial) { spatial->spatial_updatesector(); - if (spatial->spatial.sector) RImplementation.r_dsgraph_render_R1_box( - spatial->spatial.sector, BB, SE_R1_LMODELS); + if (spatial->spatial.sector) + r_dsgraph_render_R1_box(lstVisuals, (CSector*)spatial->spatial.sector, BB, SE_R1_LMODELS); } //if (spatial) RImplementation.r_dsgraph_render_subspace (spatial->spatial.sector,mCombine,v_C,FALSE); } diff --git a/src/Layers/xrRenderPC_R1/LightProjector.h b/src/Layers/xrRenderPC_R1/LightProjector.h index b8702712ac..dafc0e79bd 100644 --- a/src/Layers/xrRenderPC_R1/LightProjector.h +++ b/src/Layers/xrRenderPC_R1/LightProjector.h @@ -17,7 +17,7 @@ class CLightProjector : public pureAppActivate static const int P_o_count = P_o_line * P_o_line; // - typedef R_dsgraph::_MatrixItem NODE; + typedef R_dsgraph::DSGraphItem NODE; struct recv { @@ -36,13 +36,15 @@ class CLightProjector : public pureAppActivate xr_vector cache; // same as number of slots xr_vector receivers; xr_vector taskid; + xr_vector lstVisuals; ref_rt RT; shared_str c_xform; shared_str c_clamp; shared_str c_factor; + xrCriticalSection cs; public: - void set_object(IRenderable* O); + void set_object(IRenderable* O, IDSGraphManager& DM); BOOL shadowing() { return current != 0; } void calculate(); void setup(int slot); diff --git a/src/Layers/xrRenderPC_R1/LightShadows.cpp b/src/Layers/xrRenderPC_R1/LightShadows.cpp index 132e3a6913..5d8143b244 100644 --- a/src/Layers/xrRenderPC_R1/LightShadows.cpp +++ b/src/Layers/xrRenderPC_R1/LightShadows.cpp @@ -87,13 +87,13 @@ CLightShadows::~CLightShadows() cache.clear(); } -void CLightShadows::set_object(IRenderable* O) +void CLightShadows::set_object(IRenderable* O, IDSGraphManager& DM) { + xrCriticalSectionGuard guard(&cs); if (0 == O) current = 0; else { - if (!O->renderable_ShadowGenerate() || RImplementation.val_bHUD || ((CROS_impl*)O->renderable_ROS())-> - shadow_gen_frame == Device.dwFrame) + if (!O->renderable_ShadowGenerate() || DM.i_mask[IDSGraphManager::fl_hud] || ((CROS_impl*)O->renderable_ROS())->shadow_gen_frame == Device.dwFrame) { current = 0; return; @@ -135,15 +135,17 @@ void CLightShadows::set_object(IRenderable* O) void CLightShadows::add_element(NODE& N) { + xrCriticalSectionGuard guard(&cs); if (0 == current) return; VERIFY2(casters.back()->nodes.size()<24, "Object exceeds limit of 24 renderable parts/materials"); - if (0 == N.pVisual->shader->E[SE_R1_LMODELS]._get()) return; + if (0 == N.val.pVisual->shader->E[SE_R1_LMODELS]._get()) return; casters.back()->nodes.push_back(N); } // void CLightShadows::calculate() { + xrCriticalSectionGuard guard(&cs); #ifdef _GPA_ENABLED TAL_SCOPED_TASK_NAMED( "CLightShadows::calculate()" ); #endif // _GPA_ENABLED @@ -275,9 +277,9 @@ void CLightShadows::calculate() for (u32 n_it = 0; n_it < C.nodes.size(); n_it++) { NODE& N = C.nodes[n_it]; - dxRender_Visual* V = N.pVisual; + dxRender_Visual* V = N.val.pVisual; RCache.set_Element(V->shader->E[SE_R1_LMODELS]); - RCache.set_xform_world(N.Matrix); + RCache.set_xform_world(*N.val.pMatrix); V->Render(-1.0f); } @@ -378,6 +380,7 @@ IC int PLC_calc(Fvector& P, Fvector& N, light* L, float energy, Fvector& O) void CLightShadows::render() { + xrCriticalSectionGuard guard(&cs); // Gain access to collision-DB CDB::MODEL* DB = g_pGameLevel->ObjectSpace.GetStaticModel(); CDB::TRI* TRIS = DB->get_tris(); diff --git a/src/Layers/xrRenderPC_R1/LightShadows.h b/src/Layers/xrRenderPC_R1/LightShadows.h index ab5d163695..669e359989 100644 --- a/src/Layers/xrRenderPC_R1/LightShadows.h +++ b/src/Layers/xrRenderPC_R1/LightShadows.h @@ -13,7 +13,7 @@ class CLightShadows { private: // - typedef R_dsgraph::_MatrixItem NODE; + typedef R_dsgraph::mapDSGraphItemsMap::TNode NODE; struct caster { @@ -79,9 +79,10 @@ class CLightShadows ref_geom geom_World; ref_shader sh_Screen; ref_geom geom_Screen; + xrCriticalSection cs; private: public: - void set_object(IRenderable* O); + void set_object(IRenderable* O, IDSGraphManager& DM); void add_element(NODE& N); void calculate(); void render(); diff --git a/src/Layers/xrRenderPC_R1/stdafx.h b/src/Layers/xrRenderPC_R1/stdafx.h index 328bc0b73c..04d88e2a58 100644 --- a/src/Layers/xrRenderPC_R1/stdafx.h +++ b/src/Layers/xrRenderPC_R1/stdafx.h @@ -32,6 +32,8 @@ #include "../../xrEngine/render.h" #include "../../xrEngine/_d3d_extensions.h" +#include "../../xrCore/profiler.h" + #ifndef _EDITOR #include "../../xrEngine/igame_level.h" diff --git a/src/Layers/xrRenderPC_R1/xrRender_R1.vcxproj b/src/Layers/xrRenderPC_R1/xrRender_R1.vcxproj index 53ba76e9c2..d40c1c2f58 100644 --- a/src/Layers/xrRenderPC_R1/xrRender_R1.vcxproj +++ b/src/Layers/xrRenderPC_R1/xrRender_R1.vcxproj @@ -13,6 +13,10 @@ Release x64 + + VerifiedDX11ASAN + x64 + VerifiedDX11 x64 @@ -57,6 +61,14 @@ false x64 + + StaticLibrary + v143 + MultiByte + false + x64 + true + StaticLibrary v143 @@ -87,6 +99,11 @@ + + + + + @@ -116,6 +133,11 @@ $(xrGameDir)bin_dbg\$(Platform)\$(Configuration)\ $(xrIntDir)$(ProjectName)\ + + false + $(xrGameDir)bin_dbg\$(Platform)\$(Configuration)\ + $(xrIntDir)$(ProjectName)\ + false $(xrGameDir)bin_dbg\$(Platform)\$(Configuration)\ @@ -199,7 +221,7 @@ false false .;$(SolutionDir)3rd party\imgui\;$(SolutionDir)3rd party\luajit-2\src\;$(SolutionDir)3rd party\luabind\;$(SolutionDir)xrCore;$(xrSdkDir)include;$(XRAY_16X_LIBS)OpenAutomate\inc;$(XRAY_16X_LIBS)nvapi;%(AdditionalIncludeDirectories) - USE_VERIFY_IN_RELEASE;WIN32;NDEBUG;_WINDOWS;_USRDLL;XRRENDER_R1_EXPORTS;_SECURE_SCL=0;%(PreprocessorDefinitions) + XRCORE_PROFILER;USE_VERIFY_IN_RELEASE;WIN32;NDEBUG;_WINDOWS;_USRDLL;XRRENDER_R1_EXPORTS;_SECURE_SCL=0;%(PreprocessorDefinitions) NotSet Use EditAndContinue @@ -237,7 +259,7 @@ false false .;$(SolutionDir)3rd party\imgui\;$(SolutionDir)3rd party\luajit-2\src\;$(SolutionDir)3rd party\luabind\;$(SolutionDir)xrCore;$(xrSdkDir)include;$(XRAY_16X_LIBS)OpenAutomate\inc;$(XRAY_16X_LIBS)nvapi;%(AdditionalIncludeDirectories) - USE_VERIFY_IN_RELEASE;WIN32;NDEBUG;_WINDOWS;_USRDLL;XRRENDER_R1_EXPORTS;_SECURE_SCL=0;%(PreprocessorDefinitions) + XRCORE_PROFILER;USE_VERIFY_IN_RELEASE;WIN32;NDEBUG;_WINDOWS;_USRDLL;XRRENDER_R1_EXPORTS;_SECURE_SCL=0;%(PreprocessorDefinitions) NotSet Use EditAndContinue @@ -265,6 +287,44 @@ true + + + Disabled + Disabled + false + Neither + false + false + false + .;$(SolutionDir)3rd party\imgui\;$(SolutionDir)3rd party\luajit-2\src\;$(SolutionDir)3rd party\luabind\;$(SolutionDir)xrCore;$(xrSdkDir)include;$(XRAY_16X_LIBS)OpenAutomate\inc;$(XRAY_16X_LIBS)nvapi;%(AdditionalIncludeDirectories) + XRCORE_PROFILER;USE_VERIFY_IN_RELEASE;_DISABLE_VECTOR_ANNOTATION;_DISABLE_STRING_ANNOTATION;WIN32;NDEBUG;_WINDOWS;_USRDLL;XRRENDER_R1_EXPORTS;_SECURE_SCL=0;%(PreprocessorDefinitions) + NotSet + Use + ProgramDatabase + USE_LUAJIT_ONE + true + Level4 + false + MultiThreadedDLL + false + stdcpp17 + true + + + d3dx9.lib;nvapi.lib;%(AdditionalDependencies) + $(SolutionDir)3rd party\luajit-2\src\;$(xrSdkDir)libraries\x64;$(xrLibDir);$(SolutionDir)x64\Release;%(AdditionalLibraryDirectories) + NotSet + true + true + true + Default + false + false + $(xrLibDir)$(TargetName).lib + LIBCMT + true + + .;$(SolutionDir)3rd party\imgui\;$(SolutionDir)3rd party\luajit-2\src\;$(SolutionDir)3rd party\luabind\;$(SolutionDir)xrCore;$(xrSdkDir)include;$(XRAY_16X_LIBS)OpenAutomate\inc;$(XRAY_16X_LIBS)nvapi;%(AdditionalIncludeDirectories) @@ -348,6 +408,7 @@ + @@ -416,7 +477,7 @@ - + @@ -476,6 +537,7 @@ + @@ -549,11 +611,12 @@ + - + @@ -565,7 +628,6 @@ - @@ -585,7 +647,6 @@ - @@ -597,8 +658,10 @@ Create Create Create + Create Create + diff --git a/src/Layers/xrRenderPC_R1/xrRender_R1.vcxproj.filters b/src/Layers/xrRenderPC_R1/xrRender_R1.vcxproj.filters index fc88565500..3202175f36 100644 --- a/src/Layers/xrRenderPC_R1/xrRender_R1.vcxproj.filters +++ b/src/Layers/xrRenderPC_R1/xrRender_R1.vcxproj.filters @@ -180,9 +180,6 @@ Core - - Core - Core @@ -624,6 +621,10 @@ Core + + Core + + @@ -641,9 +642,6 @@ Core - - Core - Core @@ -665,9 +663,6 @@ Core - - Core - Core @@ -767,9 +762,6 @@ Visibility\Sector/Portal - - Visibility\Sector/Portal - Visibility\HOM Occlusion @@ -1034,5 +1026,13 @@ Core + + + Core + + + Visibility\Sector/Portal + + - \ No newline at end of file + diff --git a/src/Layers/xrRenderPC_R2/Light_Render_Direct.cpp b/src/Layers/xrRenderPC_R2/Light_Render_Direct.cpp deleted file mode 100644 index 5f6f1f7b2c..0000000000 --- a/src/Layers/xrRenderPC_R2/Light_Render_Direct.cpp +++ /dev/null @@ -1,2 +0,0 @@ -#include "StdAfx.h" -#include "light_render_direct.h" diff --git a/src/Layers/xrRenderPC_R2/Light_Render_Direct.h b/src/Layers/xrRenderPC_R2/Light_Render_Direct.h deleted file mode 100644 index 15b4214acb..0000000000 --- a/src/Layers/xrRenderPC_R2/Light_Render_Direct.h +++ /dev/null @@ -1,7 +0,0 @@ -#pragma once - -class CLight_Compute_XFORM_and_VIS -{ -public: - void compute_xf_spot(light* L); // -}; diff --git a/src/Layers/xrRenderPC_R2/Light_Render_Direct_ComputeXFS.cpp b/src/Layers/xrRenderPC_R2/Light_Render_Direct_ComputeXFS.cpp deleted file mode 100644 index 108ae4099f..0000000000 --- a/src/Layers/xrRenderPC_R2/Light_Render_Direct_ComputeXFS.cpp +++ /dev/null @@ -1,95 +0,0 @@ -#include "stdafx.h" -#include "light_render_direct.h" - -void CLight_Compute_XFORM_and_VIS::compute_xf_spot(light* L) -{ - // Build EYE-space xform - Fvector L_dir, L_up, L_right, L_pos; - L_dir.set(L->direction); - L_dir.normalize(); - - if (L->right.square_magnitude() > EPS) - { - // use specified 'up' and 'right', just enshure ortho-normalization - L_right.set(L->right); - L_right.normalize(); - L_up.crossproduct(L_dir, L_right); - L_up.normalize(); - L_right.crossproduct(L_up, L_dir); - L_right.normalize(); - } - else - { - // auto find 'up' and 'right' vectors - L_up.set(0, 1, 0); - if (_abs(L_up.dotproduct(L_dir)) > .99f) L_up.set(0, 0, 1); - L_right.crossproduct(L_up, L_dir); - L_right.normalize(); - L_up.crossproduct(L_dir, L_right); - L_up.normalize(); - } - L_pos.set(L->position); - - // - int _cached_size = L->X.S.size; - L->X.S.posX = L->X.S.posY = 0; - L->X.S.size = SMAP_adapt_max; - L->X.S.transluent = FALSE; - - // Compute approximate screen area (treating it as an point light) - R*R/dist_sq - // Note: we clamp screen space area to ONE, although it is not correct at all - float dist = Device.vCameraPosition.distance_to(L->spatial.sphere.P) - L->spatial.sphere.R; - if (dist < 0) dist = 0; - float ssa = clampr(L->range * L->range / (1.f + dist * dist), 0.f, 1.f); - - // compute intensity - float intensity0 = (L->color.r + L->color.g + L->color.b) / 3.f; - float intensity1 = (L->color.r * 0.2125f + L->color.g * 0.7154f + L->color.b * 0.0721f); - float intensity = (intensity0 + intensity1) / 2.f; // intensity1 tends to underestimate... - - // compute how much duelling frusta occurs [-1..1]-> 1 + [-0.5 .. +0.5] - float duel_dot = 1.f - 0.5f * Device.vCameraDirection.dotproduct(L_dir); - - // compute how large the light is - give more texels to larger lights, assume 8m as being optimal radius - float sizefactor = L->range / 8.f; // 4m = .5, 8m=1.f, 16m=2.f, 32m=4.f - - // compute how wide the light frustum is - assume 90deg as being optimal - float widefactor = L->cone / deg2rad(90.f); // - - // factors - float factor0 = powf(ssa, 1.f / 2.f); // ssa is quadratic - float factor1 = powf(intensity, 1.f / 16.f); // less perceptually important? - float factor2 = powf(duel_dot, 1.f / 4.f); // difficult to fast-change this -> visible - float factor3 = powf(sizefactor, 1.f / 4.f); // this shouldn't make much difference - float factor4 = powf(widefactor, 1.f / 2.f); // make it linear ??? - float factor = ps_r2_ls_squality * factor0 * factor1 * factor2 * factor3 * factor4; - - // final size calc - u32 _size = iFloor(factor * SMAP_adapt_optimal); - if (_size < SMAP_adapt_min) _size = SMAP_adapt_min; - if (_size > SMAP_adapt_max) _size = SMAP_adapt_max; - int _epsilon = iCeil(float(_size) * 0.01f); - int _diff = _abs(int(_size) - int(_cached_size)); - L->X.S.size = (_diff >= _epsilon) ? _size : _cached_size; - - // make N pixel border - L->X.S.view.build_camera_dir(L_pos, L_dir, L_up); - //float n = 2.f ; - //float x = float(L->X.S.size) ; - //float alpha = L->cone/2 ; - //float tan_beta = (x+2*n)*tanf(alpha) / x ; - //float g_alpha = 2*rad2deg (alpha); - //float g_beta = 2*rad2deg (atanf(tan_beta)); - //Msg ("x(%f) : a(%f), b(%f)",x,g_alpha,g_beta); - - /* Ray Twitty */ - float tan_shift; - if (L->flags.type == IRender_Light::POINT) - tan_shift = deg2rad(11.5f); - else - tan_shift = deg2rad(3.5f); - - /* Ray Twitty end */ - L->X.S.project.build_projection(L->cone + tan_shift, 1.f, L->virtual_size, L->range + EPS_S); - L->X.S.combine.mul(L->X.S.project, L->X.S.view); -} diff --git a/src/Layers/xrRenderPC_R2/light_GI.cpp b/src/Layers/xrRenderPC_R2/light_GI.cpp index 0e0084c8cb..c04f4ab24e 100644 --- a/src/Layers/xrRenderPC_R2/light_GI.cpp +++ b/src/Layers/xrRenderPC_R2/light_GI.cpp @@ -47,7 +47,7 @@ void light::gi_generate() LI.D.reflect(dir, TN); LI.E = dot * (1 - R->range / range); if (LI.E < ps_r2_GI_clip) continue; - LI.S = spatial.sector; //. BUG + LI.S = SpatialComponent->spatial.sector; //. BUG indirect.push_back(LI); } diff --git a/src/Layers/xrRenderPC_R2/light_smapvis.cpp b/src/Layers/xrRenderPC_R2/light_smapvis.cpp deleted file mode 100644 index 5a25a987d2..0000000000 --- a/src/Layers/xrRenderPC_R2/light_smapvis.cpp +++ /dev/null @@ -1,131 +0,0 @@ -#include "StdAfx.h" -#include "../xrRender/light.h" -#include "../xrRender/FBasicVisual.h" - -smapvis::smapvis() -{ - invalidate(); - frame_sleep = 0; -} - -smapvis::~smapvis() -{ - flushoccq(); - invalidate(); -} - -void smapvis::invalidate() -{ - state = state_counting; - testQ_V = 0; - frame_sleep = Device.dwFrame + ps_r__LightSleepFrames; - invisible.clear(); -} - -void smapvis::begin() -{ - RImplementation.clear_Counters(); - switch (state) - { - case state_counting: - // do nothing -> we just prepare for testing process - break; - case state_working: - // mark already known to be invisible visuals, set breakpoint - testQ_V = 0; - testQ_id = 0; - mark(); - RImplementation.set_Feedback(this, test_current); - break; - case state_usingTC: - // just mark - mark(); - break; - } -} - -void smapvis::end() -{ - // Gather stats - u32 ts, td; - RImplementation.get_Counters(ts, td); - RImplementation.stats.ic_total += ts; - RImplementation.set_Feedback(0, 0); - - switch (state) - { - case state_counting: - // switch to 'working' - if (sleep()) - { - test_count = ts; - test_current = 0; - state = state_working; - } - break; - case state_working: - // feedback should be called at this time -> clear feedback - // issue query - if (testQ_V) - { - RImplementation.occq_begin(testQ_id); - RImplementation.marker += 1; - RImplementation.r_dsgraph_insert_static(testQ_V); - RImplementation.r_dsgraph_render_graph(0); - RImplementation.occq_end(testQ_id); - testQ_frame = Device.dwFrame + 1; // get result on next frame - } - break; - case state_usingTC: - // nothing to do - break; - } -} - -void smapvis::flushoccq() -{ - // the tough part - if (testQ_frame != Device.dwFrame) return; - if ((state != state_working) || (!testQ_V)) return; - u64 fragments = RImplementation.occq_get(testQ_id); - if (0 == fragments) - { - // this is invisible shadow-caster, register it - // next time we will not get this caster, so 'test_current' remains the same - invisible.push_back(testQ_V); - test_count --; - } - else - { - // this is visible shadow-caster, advance testing - test_current ++; - } - - testQ_V = 0; - - if (test_current == test_count) - { - // we are at the end of list - if (state == state_working) state = state_usingTC; - } -} - -void smapvis::resetoccq() -{ - if (testQ_frame == (Device.dwFrame + 1)) testQ_frame--; - flushoccq(); -} - -void smapvis::mark() -{ - RImplementation.stats.ic_culled += invisible.size(); - u32 marker = RImplementation.marker + 1; // we are called befor marker increment - for (u32 it = 0; it < invisible.size(); it++) - invisible[it]->vis.marker = marker; // this effectively disables processing -} - -void smapvis::rfeedback_static(dxRender_Visual* V) -{ - testQ_V = V; - RImplementation.set_Feedback(0, 0); -} diff --git a/src/Layers/xrRenderPC_R2/light_smapvis.h b/src/Layers/xrRenderPC_R2/light_smapvis.h deleted file mode 100644 index 29bca1ce7b..0000000000 --- a/src/Layers/xrRenderPC_R2/light_smapvis.h +++ /dev/null @@ -1,36 +0,0 @@ -#pragma once - -class smapvis : public R_feedback -{ -public: - enum - { - state_counting = 0, - state_working = 1, - state_usingTC = 3, - } state; - - xr_vector invisible; - - u32 frame_sleep; - u32 test_count; - u32 test_current; - dxRender_Visual* testQ_V; - u32 testQ_id; - u32 testQ_frame; -public: - smapvis(); - ~smapvis(); - - void invalidate(); - void begin(); // should be called before 'marker++' and before graph-build - void end(); - void mark(); - void flushoccq(); // should be called when no rendering of light is supposed - - void resetoccq(); - - IC bool sleep() { return Device.dwFrame > frame_sleep; } - - virtual void rfeedback_static(dxRender_Visual* V); -}; diff --git a/src/Layers/xrRenderPC_R2/light_vis.cpp b/src/Layers/xrRenderPC_R2/light_vis.cpp deleted file mode 100644 index 6c570d4a14..0000000000 --- a/src/Layers/xrRenderPC_R2/light_vis.cpp +++ /dev/null @@ -1,87 +0,0 @@ -#include "StdAfx.h" -#include "../xrRender/light.h" -#include "../../xrEngine/cl_intersect.h" - -const u32 delay_small_min = 1; -const u32 delay_small_max = 3; -const u32 delay_large_min = 10; -const u32 delay_large_max = 20; -const u32 cullfragments = 4; - -void light::vis_prepare() -{ - if (int(indirect_photons) != ps_r2_GI_photons) gi_generate(); - - // . test is sheduled for future = keep old result - // . test time comes :) - // . camera inside light volume = visible, shedule for 'small' interval - // . perform testing = ???, pending - - u32 frame = Device.dwFrame; - if (frame < vis.frame2test) return; - - float safe_area = VIEWPORT_NEAR; - { - float a0 = deg2rad(Device.fFOV * Device.fASPECT / 2.f); - float a1 = deg2rad(Device.fFOV / 2.f); - float x0 = VIEWPORT_NEAR / _cos(a0); - float x1 = VIEWPORT_NEAR / _cos(a1); - float c = _sqrt(x0 * x0 + x1 * x1); - safe_area = _max(_max(VIEWPORT_NEAR, _max(x0, x1)), c); - } - - //Msg ("sc[%f,%f,%f]/c[%f,%f,%f] - sr[%f]/r[%f]",VPUSH(spatial.center),VPUSH(position),spatial.radius,range); - //Msg ("dist:%f, sa:%f",Device.vCameraPosition.distance_to(spatial.center),safe_area); - bool skiptest = false; - if (ps_r2_ls_flags.test(R2FLAG_EXP_DONT_TEST_UNSHADOWED) && !flags.bShadow) skiptest = true; - if (ps_r2_ls_flags.test(R2FLAG_EXP_DONT_TEST_SHADOWED) && flags.bShadow) skiptest = true; - - if (skiptest || Device.vCameraPosition.distance_to(spatial.sphere.P) <= (spatial.sphere.R * 1.01f + safe_area)) - { - // small error - vis.visible = true; - vis.pending = false; - vis.frame2test = frame + ::Random.randI(delay_small_min, delay_small_max); - return; - } - - // testing - vis.pending = true; - xform_calc(); - RCache.set_xform_world(m_xform); - vis.query_order = RImplementation.occq_begin(vis.query_id); - // Hack: Igor. Light is visible if it's frutum is visible. (Only for volumetric) - // Hope it won't slow down too much since there's not too much volumetric lights - // TODO: sort for performance improvement if this technique hurts - if ((flags.type == IRender_Light::SPOT) && flags.bShadow && flags.bVolumetric) - RCache.set_Stencil(FALSE); - else - RCache.set_Stencil(TRUE, D3DCMP_LESSEQUAL, 0x01, 0xff, 0x00); - RImplementation.Target->draw_volume(this); - RImplementation.occq_end(vis.query_id); -} - -void light::vis_update() -{ - // . not pending ->>> return (early out) - // . test-result: visible: - // . shedule for 'large' interval - // . test-result: invisible: - // . shedule for 'next-frame' interval - - if (!vis.pending) return; - - u32 frame = Device.dwFrame; - u32 fragments = RImplementation.occq_get(vis.query_id); - - vis.visible = (fragments > cullfragments); - vis.pending = false; - if (vis.visible) - { - vis.frame2test = frame + ::Random.randI(delay_large_min, delay_large_max); - } - else - { - vis.frame2test = frame + 1; - } -} diff --git a/src/Layers/xrRenderPC_R2/r2.cpp b/src/Layers/xrRenderPC_R2/r2.cpp index 0fb6640b38..d35ffe864e 100644 --- a/src/Layers/xrRenderPC_R2/r2.cpp +++ b/src/Layers/xrRenderPC_R2/r2.cpp @@ -158,7 +158,7 @@ void CRender::create() { Device.seqFrame.Add(this,REG_PRIORITY_HIGH + 0x12345678); - m_skinning = -1; + Engine.External.SetSkinningMode(); // hardware o.smapsize = 2048; @@ -243,7 +243,7 @@ void CRender::create() o.fp16_blend = HW.support(D3DFMT_A16B16G16R16F, D3DRTYPE_TEXTURE,D3DUSAGE_QUERY_POSTPIXELSHADER_BLENDING); // search for ATI formats - if (!o.HW_smap && (0 == strstr(Core.Params, "-nodf24"))) + if (!o.HW_smap && !Core.ParamsData.test(ECoreParams::nodf24)) { o.HW_smap = HW.support((D3DFORMAT)(MAKEFOURCC('D', 'F', '2', '4')), D3DRTYPE_TEXTURE,D3DUSAGE_DEPTHSTENCIL); if (o.HW_smap) @@ -256,7 +256,7 @@ void CRender::create() } // emulate ATI-R4xx series - if (strstr(Core.Params, "-r4xx")) + if (Core.ParamsData.test(ECoreParams::r4xx)) { o.mrtmixdepth = FALSE; o.HW_smap = FALSE; @@ -284,47 +284,47 @@ void CRender::create() (D3DFORMAT MAKEFOURCC('R', 'A', 'W', 'Z')))); } - if (strstr(Core.Params, "-nonvs")) o.nvstencil = FALSE; + if (Core.ParamsData.test(ECoreParams::nonvs)) + o.nvstencil = FALSE; // nv-dbt o.nvdbt = HW.support((D3DFORMAT)MAKEFOURCC('N', 'V', 'D', 'B'), D3DRTYPE_SURFACE, 0); if (o.nvdbt) Msg("* NV-DBT supported and used"); - o.no_ram_textures = (strstr(Core.Params, "-noramtex")) ? TRUE : ps_r__common_flags.test(RFLAG_NO_RAM_TEXTURES); + o.no_ram_textures = Core.ParamsData.test(ECoreParams::noramtex) ? TRUE : ps_r__common_flags.test(RFLAG_NO_RAM_TEXTURES); if (o.no_ram_textures) Msg("* Managed textures disabled"); else Msg("* Managed textures enabled"); // options (smap-pool-size) - if (strstr(Core.Params, "-smap1536")) o.smapsize = 1536; - if (strstr(Core.Params, "-smap2048")) o.smapsize = 2048; - if (strstr(Core.Params, "-smap2560")) o.smapsize = 2560; - if (strstr(Core.Params, "-smap3072")) o.smapsize = 3072; - if (strstr(Core.Params, "-smap4096")) o.smapsize = 4096; + if (Core.ParamsData.test(ECoreParams::smap1536)) o.smapsize = 1536; + if (Core.ParamsData.test(ECoreParams::smap2048)) o.smapsize = 2048; + if (Core.ParamsData.test(ECoreParams::smap2560)) o.smapsize = 2560; + if (Core.ParamsData.test(ECoreParams::smap3072)) o.smapsize = 3072; + if (Core.ParamsData.test(ECoreParams::smap4096)) o.smapsize = 4096; // gloss char* g = strstr(Core.Params, "-gloss "); - o.forcegloss = g ? TRUE : FALSE; + o.forcegloss = Core.ParamsData.test(ECoreParams::gloss); if (g) { o.forcegloss_v = float(atoi(g + xr_strlen("-gloss "))) / 255.f; } // options - o.bug = (strstr(Core.Params, "-bug")) ? TRUE : FALSE; - o.sunfilter = (strstr(Core.Params, "-sunfilter")) ? TRUE : FALSE; - //. o.sunstatic = (strstr(Core.Params,"-sunstatic"))? TRUE :FALSE ; + o.bug = Core.ParamsData.test(ECoreParams::bug); + o.sunfilter = Core.ParamsData.test(ECoreParams::sunfilter); o.sunstatic = r2_sun_static; o.advancedpp = r2_advanced_pp; - o.sjitter = (strstr(Core.Params, "-sjitter")) ? TRUE : FALSE; - o.depth16 = (strstr(Core.Params, "-depth16")) ? TRUE : FALSE; - o.noshadows = (strstr(Core.Params, "-noshadows")) ? TRUE : FALSE; - o.Tshadows = (strstr(Core.Params, "-tsh")) ? TRUE : FALSE; - o.distortion_enabled = (strstr(Core.Params, "-nodistort")) ? FALSE : TRUE; + o.sjitter = Core.ParamsData.test(ECoreParams::sjitter); + o.depth16 = Core.ParamsData.test(ECoreParams::depth16); + o.noshadows = Core.ParamsData.test(ECoreParams::noshadows); + o.Tshadows = Core.ParamsData.test(ECoreParams::tsh); + o.distortion_enabled = !Core.ParamsData.test(ECoreParams::nodistort); o.distortion = o.distortion_enabled; - o.disasm = (strstr(Core.Params, "-disasm")) ? TRUE : FALSE; - o.forceskinw = (strstr(Core.Params, "-skinw")) ? TRUE : FALSE; + o.disasm = Core.ParamsData.test(ECoreParams::disasm); + o.forceskinw = Core.ParamsData.test(ECoreParams::skinw); o.ssao_blur_on = ps_r2_ls_flags_ext.test(R2FLAGEXT_SSAO_BLUR) && ps_r_ssao != 0; o.ssao_opt_data = ps_r2_ls_flags_ext.test(R2FLAGEXT_SSAO_OPT_DATA) && (ps_r_ssao != 0); @@ -357,54 +357,27 @@ void CRender::create() HWOCC.occq_create(occq_size); //rmNormal (); - marker = 0; - //R_CHK (HW.pDevice->CreateQuery(D3DQUERYTYPE_EVENT,&q_sync_point[0])); - //R_CHK (HW.pDevice->CreateQuery(D3DQUERYTYPE_EVENT,&q_sync_point[1])); - ZeroMemory(q_sync_point, sizeof(q_sync_point)); - for (u32 i = 0; i < HW.Caps.iGPUNum; ++i) - R_CHK(HW.pDevice->CreateQuery(D3DQUERYTYPE_EVENT,&q_sync_point[i])); + GMBase.initialize(); - ::PortalTraverser.initialize(); + Device.ModelDefferClear = xr_make_delegate(Models, &CModelPool::DeleteQueuedDeffer); } void CRender::destroy() { m_bMakeAsyncSS = false; - ::PortalTraverser.destroy(); - //_RELEASE (q_sync_point[1]); - //_RELEASE (q_sync_point[0]); - for (u32 i = 0; i < HW.Caps.iGPUNum; ++i) - _RELEASE(q_sync_point[i]); + GMBase.destroy(); + HWOCC.occq_destroy(); xr_delete(Models); xr_delete(Target); PSLibrary.OnDestroy(); Device.seqFrame.Remove(this); - r_dsgraph_destroy(); + Device.ModelDefferClear = nullptr; } void CRender::reset_begin() { - // Update incremental shadowmap-visibility solver - // BUG-ID: 10646 - { - u32 it = 0; - for (it = 0; it < Lights_LastFrame.size(); it++) - { - if (0 == Lights_LastFrame[it]) continue ; - try - { - Lights_LastFrame[it]->svis.resetoccq(); - } - catch (...) - { - Msg("! Failed to flush-OCCq on light [%d] %X", it, *(u32*)(&Lights_LastFrame[it])); - } - } - Lights_LastFrame.clear(); - } - //AVO: let's reload details while changed details options on vid_restart if (b_loaded && ((dm_current_size != dm_size) || (ps_r__Detail_density != ps_current_detail_density) || ( ps_r__Detail_height != ps_current_detail_height))) @@ -416,18 +389,10 @@ void CRender::reset_begin() xr_delete(Target); HWOCC.occq_destroy(); - //_RELEASE (q_sync_point[1]); - //_RELEASE (q_sync_point[0]); - for (u32 i = 0; i < HW.Caps.iGPUNum; ++i) - _RELEASE(q_sync_point[i]); } void CRender::reset_end() { - //R_CHK (HW.pDevice->CreateQuery(D3DQUERYTYPE_EVENT,&q_sync_point[0])); - //R_CHK (HW.pDevice->CreateQuery(D3DQUERYTYPE_EVENT,&q_sync_point[1])); - for (u32 i = 0; i < HW.Caps.iGPUNum; ++i) - R_CHK(HW.pDevice->CreateQuery(D3DQUERYTYPE_EVENT,&q_sync_point[i])); HWOCC.occq_create(occq_size); Target = xr_new(); @@ -447,32 +412,19 @@ void CRender::reset_end() m_bFirstFrameAfterReset = true; } -/* -void CRender::OnFrame() -{ - Models->DeleteQueue (); - if (ps_r2_ls_flags.test(R2FLAG_EXP_MT_CALC)) { - Device.seqParallel.insert (Device.seqParallel.begin(), - fastdelegate::FastDelegate0<>(&HOM,&CHOM::MT_RENDER)); - } -}*/ void CRender::OnFrame() { Models->DeleteQueue(); - if (ps_r2_ls_flags.test(R2FLAG_EXP_MT_CALC)) + { - // MT-details (@front) - if (Details) - Device.seqParallel.insert(Device.seqParallel.begin(), - fastdelegate::FastDelegate0<>(Details, &CDetailManager::MT_CALC)); + //Lights Delete queue + for (light*L:v_all_lights_dque) + xr_delete(L); - // MT-HOM (@front) - Device.seqParallel.insert(Device.seqParallel.begin(), - fastdelegate::FastDelegate0<>(&HOM, &CHOM::MT_RENDER)); + v_all_lights_dque.clear(); } } - // Implementation IRender_ObjectSpecific* CRender::ros_create(IRenderable* parent) { return xr_new(); } void CRender::ros_destroy(IRender_ObjectSpecific* & p) { xr_delete(p); } @@ -483,7 +435,15 @@ IRenderVisual* CRender::model_Duplicate(IRenderVisual* V) { return Models->Insta void CRender::model_Delete(IRenderVisual* & V, BOOL bDiscard) { dxRender_Visual* pVisual = (dxRender_Visual*)V; - Models->Delete(pVisual, bDiscard); + if (Models) + Models->Delete(pVisual, bDiscard); + V = 0; +} + +void CRender::model_Delete_Deffered(IRenderVisual* & V) +{ + dxRender_Visual* pVisual = (dxRender_Visual*)V; + Models->DeleteDeffered(pVisual); V = 0; } @@ -608,14 +568,12 @@ IRender_Target* CRender::getTarget() { return Target; } IRender_Light* CRender::light_create() { return Lights.Create(); } IRender_Glow* CRender::glow_create() { return xr_new(); } -void CRender::flush() { r_dsgraph_render_graph(0); } +void CRender::flush() { RImplementation.GMBase.r_dsgraph_render_graph(0); } BOOL CRender::occ_visible(vis_data& P) { return HOM.visible(P); } BOOL CRender::occ_visible(sPoly& P) { return HOM.visible(P); } BOOL CRender::occ_visible(Fbox& P) { return HOM.visible(P); } -void CRender::add_Visual(IRenderVisual* V) { add_leafs_Dynamic((dxRender_Visual*)V); } -void CRender::add_Geometry(IRenderVisual* V) { add_Static((dxRender_Visual*)V, View->getMask()); } // demonized: add user defined rotation to wallmark void CRender::add_StaticWallmark(ref_shader& S, const Fvector& P, float s, CDB::TRI* T, Fvector* verts, float ttl, bool ignore_opt, bool random_rotation) @@ -655,7 +613,7 @@ void CRender::clear_static_wallmarks() void CRender::add_SkeletonWallmark(intrusive_ptr wm) { - Wallmarks->AddSkeletonWallmark(wm); + Wallmarks->AddSkeletonWallmark(std::move(wm)); } void CRender::add_SkeletonWallmark(const Fmatrix* xf, CKinematics* obj, ref_shader& sh, const Fvector& start, @@ -672,16 +630,23 @@ void CRender::add_SkeletonWallmark(const Fmatrix* xf, IKinematics* obj, IWallMar if (pShader) add_SkeletonWallmark(xf, (CKinematics*)obj, *pShader, start, dir, size, ttl, ignore_opt); } -void CRender::add_Occluder(Fbox2& bb_screenspace) +void CRender::remove_SkeletonWallmarksFromObject(IKinematics* obj) { - HOM.occlude(bb_screenspace); + Wallmarks->RemoveSkeletonWallmarksFromObject(static_cast(obj)); } -void CRender::set_Object(IRenderable* O) +void CRender::update_Wallmarks() { - val_pObject = O; + Wallmarks->UpdateWallmarks(); } +void CRender::add_Occluder(Fbox2& bb_screenspace) +{ + HOM.occlude(bb_screenspace); +} + + + void CRender::rmNear() { IRender_Target* T = getTarget(); @@ -714,8 +679,7 @@ CRender::CRender() CRender::~CRender() { - for (FSlideWindowItem it : SWIs) - { + for (auto& it : SWIs) { xr_free(it.sw); it.sw = nullptr; it.count = 0; @@ -731,6 +695,22 @@ void CRender::Statistics(CGameFont* _F) F.OutNext(" **** LT:%2d,LV:%2d **** ", stats.l_total, stats.l_visible); stats.l_visible = 0; F.OutNext(" S(%2d) | (%2d)NS ", stats.l_shadowed, stats.l_unshadowed); + F.OutNext("LP sh(in:%u,vis:%u,r:%u) pk(%u/%u)", stats.ls_shadowed_in, stats.ls_shadowed_after_vis, + stats.ls_shadowed_rendered, stats.ls_shadowed_peak_in, stats.ls_shadowed_peak_after_vis); + F.OutNext("LP uns p(in:%u,r:%u) s(in:%u,r:%u)", stats.ls_unshadowed_point_in, stats.ls_unshadowed_point_rendered, + stats.ls_unshadowed_spot_in, stats.ls_unshadowed_spot_rendered); + F.OutNext("LP sh skip: pend[%u] inv[%u]", stats.ls_shadowed_pending_skipped, stats.ls_shadowed_invisible_skipped); + stats.ls_shadowed_in = 0; + stats.ls_shadowed_after_vis = 0; + stats.ls_shadowed_rendered = 0; + stats.ls_shadowed_pending_skipped = 0; + stats.ls_shadowed_invisible_skipped = 0; + stats.ls_shadowed_peak_in = 0; + stats.ls_shadowed_peak_after_vis = 0; + stats.ls_unshadowed_point_in = 0; + stats.ls_unshadowed_spot_in = 0; + stats.ls_unshadowed_point_rendered = 0; + stats.ls_unshadowed_spot_rendered = 0; F.OutNext("smap use[%2d], merge[%2d], finalclip[%2d]", stats.s_used, stats.s_merged - stats.s_used, stats.s_finalclip); stats.s_used = 0; @@ -897,6 +877,7 @@ HRESULT CRender::shader_compile( u32 len = 0; // options + const int m_skinning = Engine.External.GetSkinningMode(); { xr_sprintf(c_smapsize, "%04d", u32(o.smapsize)); defines[def_it].Name = "SMAP_size"; diff --git a/src/Layers/xrRenderPC_R2/r2.h b/src/Layers/xrRenderPC_R2/r2.h index ec272760b7..0df787ea62 100644 --- a/src/Layers/xrRenderPC_R2/r2.h +++ b/src/Layers/xrRenderPC_R2/r2.h @@ -1,6 +1,7 @@ -#pragma once +#pragma once -#include "../xrRender/r__dsgraph_structure.h" +#include "../xrRender/r__dsgraph_manager.h" +#include "../xrRender/r__sector.h" #include "../xrRender/r__occlusion.h" #include "../xrRender/PSLibrary.h" @@ -15,7 +16,6 @@ #include "smap_allocator.h" #include "../xrRender/light_db.h" -#include "light_render_direct.h" #include "../xrRender/LightTrack.h" #include "../xrRender/r_sun_cascades.h" @@ -26,17 +26,8 @@ class dxRender_Visual; // definition -class CRender : public R_dsgraph_structure +class CRender : public IRender_interface, public pureFrame { -public: - enum - { - PHASE_NORMAL = 0, - // E[0] - PHASE_SMAP = 1, - // E[1] - }; - public: struct _options { @@ -89,12 +80,24 @@ class CRender : public R_dsgraph_structure s32 s_used, s_merged, s_finalclip; u32 o_queries, o_culled; u32 ic_total, ic_culled; + u32 ls_shadowed_in; + u32 ls_shadowed_after_vis; + u32 ls_shadowed_rendered; + u32 ls_shadowed_pending_skipped; + u32 ls_shadowed_invisible_skipped; + u32 ls_shadowed_peak_in; + u32 ls_shadowed_peak_after_vis; + u32 ls_unshadowed_point_in; + u32 ls_unshadowed_spot_in; + u32 ls_unshadowed_point_rendered; + u32 ls_unshadowed_spot_rendered; } stats; public: bool is_sun(); // Sector detection and visibility CSector* pLastSector; + CSector* pOutdoorSector; Fvector vLastCameraPos; u32 uLastLTRACK; xr_vector Portals; @@ -121,27 +124,33 @@ class CRender : public R_dsgraph_structure CRenderTarget* Target; // Render-target CLight_DB Lights; - CLight_Compute_XFORM_and_VIS LR; - xr_vector Lights_LastFrame; SMAP_Allocator LP_smap_pool; light_Package LP_normal; light_Package LP_pending; - xr_vector> main_coarse_structure; + CFrustum rainwet_cull_frustum; + Fvector3 rainwet_cull_COP; + Fmatrix rainwet_cull_xform; + + //CDSGraphManager GMRainWet = CDSGraphManager(u32(0), u32(STYPE_RENDERABLE), { true,false,false,false,true,false,false }); + CDSGraphManager GMBase = CDSGraphManager(u32(CDSGraphManager::VQ_HOM + CDSGraphManager::VQ_SSA + CDSGraphManager::VQ_FADE), + u32(STYPE_RENDERABLE + STYPE_PARTICLE + STYPE_LIGHTSOURCE), + { true,true,true,true,false,false,false }); shared_str c_sbase; shared_str c_lmaterial; float o_hemi; float o_hemi_cube[CROS_impl::NUM_FACES]; float o_sun; - IDirect3DQuery9* q_sync_point[CHWCaps::MAX_GPUS]; - u32 q_sync_count; bool m_bMakeAsyncSS; bool m_bFirstFrameAfterReset; // Determines weather the frame is the first after resetting device. xr_vector m_sun_cascades; + xr_set v_all_lights; + xr_list v_all_lights_dque; + private: // Loading / Unloading void LoadBuffers(CStreamReader* fs, BOOL _alternative); @@ -151,21 +160,12 @@ class CRender : public R_dsgraph_structure void LoadSectors(IReader* fs); void LoadSWIs(CStreamReader* fs); - BOOL add_Dynamic(dxRender_Visual* pVisual, u32 planes); // normal processing - void add_Static(dxRender_Visual* pVisual, u32 planes); - void add_leafs_Dynamic(dxRender_Visual* pVisual); // if detected node's full visibility - void add_leafs_Static(dxRender_Visual* pVisual); // if detected node's full visibility - public: IRender_Sector* rimp_detectSector(Fvector& P, Fvector& D); - void render_main(Fmatrix& mCombined, bool _fportals); void render_forward(); void render_smap_direct(Fmatrix& mCombined); void render_indirect(light* L); void render_lights(light_Package& LP); - void render_sun(); - void render_sun_near(); - void render_sun_filtered(); void render_menu(); void render_sun_cascade(u32 cascade_ind); void init_cacades(); @@ -182,6 +182,9 @@ class CRender : public R_dsgraph_structure IRender_Sector* getSectorActive(); IRenderVisual* model_CreatePE(LPCSTR name); IRender_Sector* detectSector(const Fvector& P, Fvector& D); + IRender_Sector* detectLastSector(const Fvector& P); + void detectSectors_sphere(CSector* sector, FixedSet& m_sectors, const Fvector& b_center, const Fvector& b_dim); + void detectSectors_frustum(CSector* sector, FixedSet& m_sectors, CFrustum* _frustum); int translateSector(IRender_Sector* pSector); // HW-occlusion culling @@ -256,12 +259,9 @@ class CRender : public R_dsgraph_structure virtual IRender_Sector* detectSector(const Fvector& P); virtual IRender_Target* getTarget(); - // Main + // Main virtual void flush(); - virtual void set_Object(IRenderable* O); virtual void add_Occluder(Fbox2& bb_screenspace); // mask screen region as oclluded - virtual void add_Visual(IRenderVisual* V); // add visual leaf (no culling performed at all) - virtual void add_Geometry(IRenderVisual* V); // add visual(s) (all culling performed) // wallmarks // demonized: add user defined rotation to wallmark @@ -278,6 +278,9 @@ class CRender : public R_dsgraph_structure virtual void add_SkeletonWallmark(const Fmatrix* xf, IKinematics* obj, IWallMarkArray* pArray, const Fvector& start, const Fvector& dir, float size, float ttl = 0.f, bool ignore_opt = false); + virtual void remove_SkeletonWallmarksFromObject(IKinematics* obj); + virtual void update_Wallmarks(); + // virtual IBlender* blender_create(CLASS_ID cls); virtual void blender_destroy(IBlender* &); @@ -298,6 +301,7 @@ class CRender : public R_dsgraph_structure virtual IRenderVisual* model_Duplicate(IRenderVisual* V); virtual void model_Delete(IRenderVisual* & V, BOOL bDiscard); virtual void model_Delete(IRender_DetailModel* & F); + virtual void model_Delete_Deffered(IRenderVisual* & V); virtual void model_Logging(BOOL bEnable) { Models->Logging(bEnable); } virtual void models_Prefetch(); virtual void models_PrefetchOne(LPCSTR name, bool assert = true); @@ -361,6 +365,8 @@ class CRender : public R_dsgraph_structure // Constructor/destructor/loader CRender(); virtual ~CRender(); + + virtual size_t SectorsCount() { return Sectors.size(); } protected: virtual void ScreenshotImpl(ScreenshotMode mode, LPCSTR name, CMemoryWriter* memory_writer); diff --git a/src/Layers/xrRenderPC_R2/r2_R_calculate.cpp b/src/Layers/xrRenderPC_R2/r2_R_calculate.cpp deleted file mode 100644 index 10bc156d00..0000000000 --- a/src/Layers/xrRenderPC_R2/r2_R_calculate.cpp +++ /dev/null @@ -1,75 +0,0 @@ -#include "stdafx.h" -#include "../../xrEngine/customhud.h" - -float g_fSCREEN; - -extern float r_dtex_range; -extern float r_ssaDISCARD; -extern float r_ssaDONTSORT; -extern float r_ssaLOD_A; -extern float r_ssaLOD_B; -extern float r_ssaHZBvsTEX; -extern float r_ssaGLOD_start, r_ssaGLOD_end; - -void CRender::Calculate() -{ - // Transfer to global space to avoid deep pointer access - IRender_Target* T = getTarget(); - float fov_factor = _sqr(90.f / Device.fFOV); - g_fSCREEN = float(T->get_width() * T->get_height()) * fov_factor * (EPS_S + ps_r__LOD); - r_ssaDISCARD = _sqr(ps_r__ssaDISCARD) / g_fSCREEN; - r_ssaDONTSORT = _sqr(ps_r__ssaDONTSORT / 3) / g_fSCREEN; - r_ssaLOD_A = _sqr(ps_r2_ssaLOD_A / 3) / g_fSCREEN; - r_ssaLOD_B = _sqr(ps_r2_ssaLOD_B / 3) / g_fSCREEN; - r_ssaGLOD_start = _sqr(ps_r__GLOD_ssa_start / 3) / g_fSCREEN; - r_ssaGLOD_end = _sqr(ps_r__GLOD_ssa_end / 3) / g_fSCREEN; - r_ssaHZBvsTEX = _sqr(ps_r__ssaHZBvsTEX / 3) / g_fSCREEN; - r_dtex_range = ps_r2_df_parallax_range * g_fSCREEN / (1024.f * 768.f); - - // Detect camera-sector - if (!vLastCameraPos.similar(Device.vCameraPosition, EPS_S)) - { - CSector* pSector = (CSector*)detectSector(Device.vCameraPosition); - if (pSector && (pSector != pLastSector)) - g_pGamePersistent->OnSectorChanged(translateSector(pSector)); - - if (0 == pSector) pSector = pLastSector; - pLastSector = pSector; - vLastCameraPos.set(Device.vCameraPosition); - } - - // Check if camera is too near to some portal - if so force DualRender - if (rmPortals) - { - float eps = VIEWPORT_NEAR + EPS_L; - Fvector box_radius; - box_radius.set(eps, eps, eps); - Sectors_xrc.box_options(CDB::OPT_FULL_TEST); - Sectors_xrc.box_query(rmPortals, Device.vCameraPosition, box_radius); - for (int K = 0; K < Sectors_xrc.r_count(); K++) - { - CPortal* pPortal = (CPortal*)Portals[rmPortals->get_tris()[Sectors_xrc.r_begin()[K].id].dummy]; - pPortal->bDualRender = TRUE; - } - } - - // - Lights.Update(); - - // Check if we touch some light even trough portal - lstRenderables.clear(); - g_SpatialSpace->q_sphere(lstRenderables, 0, STYPE_LIGHTSOURCE, Device.vCameraPosition, EPS_L); - for (u32 _it = 0; _it < lstRenderables.size(); _it++) - { - ISpatial* spatial = lstRenderables[_it]; - spatial->spatial_updatesector(); - CSector* sector = (CSector*)spatial->spatial.sector; - if (0 == sector) continue; // disassociated from S/P structure - - VERIFY(spatial->spatial.type & STYPE_LIGHTSOURCE); - // lightsource - light* L = (light*)(spatial->dcast_Light()); - VERIFY(L); - Lights.add_light(L); - } -} diff --git a/src/Layers/xrRenderPC_R2/r2_R_lights.cpp b/src/Layers/xrRenderPC_R2/r2_R_lights.cpp deleted file mode 100644 index c948c139e2..0000000000 --- a/src/Layers/xrRenderPC_R2/r2_R_lights.cpp +++ /dev/null @@ -1,294 +0,0 @@ -#include "stdafx.h" - -IC bool pred_area(light* _1, light* _2) -{ - u32 a0 = _1->X.S.size; - u32 a1 = _2->X.S.size; - return a0 > a1; // reverse -> descending -} - -IC void hud_light_apply(xr_map>& saved_pos, xr_vector& source) -{ - for (u32 it = 0; it < source.size(); it++) - { - light* L = source[it]; - if (!L->get_hud_mode()) continue; - - saved_pos.emplace(L, mk_pair(L->position, L->direction)); - - Device.hud_to_world(L->position); - Device.hud_to_world_dir(L->direction); - } -} - -IC void hud_light_restore(xr_map>& saved_pos, xr_vector& source) -{ - for (const auto& saved : saved_pos) - { - light* L = saved.first; - if (!L->get_hud_mode()) continue; - - L->position = saved.second.first; - L->direction = saved.second.second; - } -} - -void CRender::render_lights(light_Package& LP) -{ - xr_map> saved_pos; - ////////////////////////////////////////////////////////////////////////// - // 0. apply hud_mode projection if necessary - hud_light_apply(saved_pos, LP.v_shadowed); - hud_light_apply(saved_pos, LP.v_point); - hud_light_apply(saved_pos, LP.v_spot); - // Refactor order based on ability to pack shadow-maps - // 1. calculate area + sort in descending order - // const u16 smap_unassigned = u16(-1); - { - xr_vector& source = LP.v_shadowed; - for (u32 it = 0; it < source.size(); it++) - { - light* L = source[it]; - L->vis_update(); - if (!L->vis.visible) - { - source.erase(source.begin() + it); - it--; - } - else - { - LR.compute_xf_spot(L); - } - } - } - - // 2. refactor - infact we could go from the backside and sort in ascending order - { - xr_vector& source = LP.v_shadowed; - xr_vector refactored; - refactored.reserve(source.size()); - u32 total = source.size(); - - for (u16 smap_ID = 0; refactored.size() != total; smap_ID++) - { - LP_smap_pool.initialize(RImplementation.o.smapsize); - std::sort(source.begin(), source.end(), pred_area); - for (u32 test = 0; test < source.size(); test++) - { - light* L = source[test]; - SMAP_Rect R; - if (LP_smap_pool.push(R, L->X.S.size)) - { - // OK - L->X.S.posX = R.min.x; - L->X.S.posY = R.min.y; - L->vis.smap_ID = smap_ID; - refactored.push_back(L); - source.erase(source.begin() + test); - test --; - } - } - } - - // save (lights are popped from back) - std::reverse(refactored.begin(), refactored.end()); - LP.v_shadowed = refactored; - } - - ////////////////////////////////////////////////////////////////////////// - // sort lights by importance??? - // while (has_any_lights_that_cast_shadows) { - // if (has_point_shadowed) -> generate point shadowmap - // if (has_spot_shadowed) -> generate spot shadowmap - // switch-to-accumulator - // if (has_point_unshadowed) -> accum point unshadowed - // if (has_spot_unshadowed) -> accum spot unshadowed - // if (was_point_shadowed) -> accum point shadowed - // if (was_spot_shadowed) -> accum spot shadowed - // } - // if (left_some_lights_that_doesn't cast shadows) - // accumulate them - HOM.Disable(); - while (LP.v_shadowed.size()) - { - // if (has_spot_shadowed) - xr_vector L_spot_s; - stats.s_used ++; - - // generate spot shadowmap - Target->phase_smap_spot_clear(); - xr_vector& source = LP.v_shadowed; - light* L = source.back(); - u16 sid = L->vis.smap_ID; - while (true) - { - if (source.empty()) break; - L = source.back(); - if (L->vis.smap_ID != sid) break; - source.pop_back(); - Lights_LastFrame.push_back(L); - - // render - phase = PHASE_SMAP; - if (RImplementation.o.Tshadows) r_pmask(true, true); - else r_pmask(true, false); - L->svis.begin(); - r_dsgraph_render_subspace(L->spatial.sector, L->X.S.combine, L->position, TRUE); - bool bNormal = mapNormalPasses[0][0].size() || mapMatrixPasses[0][0].size(); - bool bSpecial = mapNormalPasses[1][0].size() || mapMatrixPasses[1][0].size() || mapSorted.size(); - if (bNormal || bSpecial) - { - stats.s_merged ++; - L_spot_s.push_back(L); - Target->phase_smap_spot(L); - RCache.set_xform_world(Fidentity); - RCache.set_xform_view(L->X.S.view); - RCache.set_xform_project(L->X.S.project); - r_dsgraph_render_graph(0); - L->X.S.transluent = FALSE; - if (bSpecial) - { - L->X.S.transluent = TRUE; - Target->phase_smap_spot_tsh(L); - r_dsgraph_render_graph(1); // normal level, secondary priority - r_dsgraph_render_sorted(); // strict-sorted geoms - } - } - else - { - stats.s_finalclip ++; - } - L->svis.end(); - r_pmask(true, false); - } - - // switch-to-accumulator - Target->phase_accumulator(); - HOM.Disable(); - - // if (has_point_unshadowed) -> accum point unshadowed - if (!LP.v_point.empty()) - { - light* L = LP.v_point.back(); - LP.v_point.pop_back(); - L->vis_update(); - if (L->vis.visible) - { - Target->accum_point(L); - render_indirect(L); - } - } - - // if (has_spot_unshadowed) -> accum spot unshadowed - if (!LP.v_spot.empty()) - { - light* L = LP.v_spot.back(); - LP.v_spot.pop_back(); - L->vis_update(); - if (L->vis.visible) - { - LR.compute_xf_spot(L); - Target->accum_spot(L); - render_indirect(L); - } - } - - // if (was_spot_shadowed) -> accum spot shadowed - if (!L_spot_s.empty()) - { - for (u32 it = 0; it < L_spot_s.size(); it++) - { - Target->accum_spot(L_spot_s[it]); - render_indirect(L_spot_s[it]); - - if (RImplementation.o.advancedpp && ps_r2_ls_flags.is(R2FLAG_VOLUMETRIC_LIGHTS)) - Target->accum_volumetric(L_spot_s[it]); - } - - L_spot_s.clear(); - } - } - - // Point lighting (unshadowed, if left) - if (!LP.v_point.empty()) - { - xr_vector& Lvec = LP.v_point; - for (u32 pid = 0; pid < Lvec.size(); pid++) - { - Lvec[pid]->vis_update(); - if (Lvec[pid]->vis.visible) - { - render_indirect(Lvec[pid]); - Target->accum_point(Lvec[pid]); - } - } - Lvec.clear(); - } - - // Spot lighting (unshadowed, if left) - if (!LP.v_spot.empty()) - { - xr_vector& Lvec = LP.v_spot; - for (u32 pid = 0; pid < Lvec.size(); pid++) - { - Lvec[pid]->vis_update(); - if (Lvec[pid]->vis.visible) - { - LR.compute_xf_spot(Lvec[pid]); - render_indirect(Lvec[pid]); - Target->accum_spot(Lvec[pid]); - } - } - Lvec.clear(); - } - - // restore world projection if necessary - hud_light_restore(saved_pos, LP.v_shadowed); - hud_light_restore(saved_pos, LP.v_point); - hud_light_restore(saved_pos, LP.v_spot); -} - -void CRender::render_indirect(light* L) -{ - if (!ps_r2_ls_flags.test(R2FLAG_GI)) return; - - light LIGEN; - LIGEN.set_type(IRender_Light::REFLECTED); - LIGEN.set_shadow(false); - LIGEN.set_cone(PI_DIV_2 * 2.f); - - xr_vector& Lvec = L->indirect; - if (Lvec.empty()) return; - float LE = L->color.intensity(); - for (u32 it = 0; it < Lvec.size(); it++) - { - light_indirect& LI = Lvec[it]; - - // energy and color - float LIE = LE * LI.E; - if (LIE < ps_r2_GI_clip) continue; - Fvector T; - T.set(L->color.r, L->color.g, L->color.b).mul(LI.E); - LIGEN.set_color(T.x, T.y, T.z); - - // geometric - Fvector L_up, L_right; - L_up.set(0, 1, 0); - if (_abs(L_up.dotproduct(LI.D)) > .99f) L_up.set(0, 0, 1); - L_right.crossproduct(L_up, LI.D).normalize(); - LIGEN.spatial.sector = LI.S; - LIGEN.set_position(LI.P); - LIGEN.set_rotation(LI.D, L_right); - - // range - // dist^2 / range^2 = A - has infinity number of solutions - // approximate energy by linear fallof Emax / (1 + x) = Emin - float Emax = LIE; - float Emin = 1.f / 255.f; - float x = (Emax - Emin) / Emin; - if (x < 0.1f) continue; - LIGEN.set_range(x); - - Target->accum_reflected(&LIGEN); - } -} diff --git a/src/Layers/xrRenderPC_R2/r2_R_render.cpp b/src/Layers/xrRenderPC_R2/r2_R_render.cpp index c8cf41cb7c..ce60dc2988 100644 --- a/src/Layers/xrRenderPC_R2/r2_R_render.cpp +++ b/src/Layers/xrRenderPC_R2/r2_R_render.cpp @@ -3,167 +3,8 @@ #include "../xrRender/FBasicVisual.h" #include "../../xrEngine/customhud.h" #include "../../xrEngine/xr_object.h" - -IC bool pred_sp_sort(ISpatial* _1, ISpatial* _2) -{ - float d1 = _1->spatial.sphere.P.distance_to_sqr(Device.vCameraPosition); - float d2 = _2->spatial.sphere.P.distance_to_sqr(Device.vCameraPosition); - return d1 < d2; -} - -void CRender::render_main(Fmatrix& m_ViewProjection, bool _fportals) -{ - // Msg ("---begin"); - marker ++; - - // Calculate sector(s) and their objects - if (pLastSector) - { - //!!! - //!!! BECAUSE OF PARALLEL HOM RENDERING TRY TO DELAY ACCESS TO HOM AS MUCH AS POSSIBLE - //!!! - { - // Traverse object database - g_SpatialSpace->q_frustum - ( - lstRenderables, - ISpatial_DB::O_ORDERED, - STYPE_RENDERABLE + STYPE_LIGHTSOURCE, - ViewBase - ); - - // (almost) Exact sorting order (front-to-back) - std::sort(lstRenderables.begin(), lstRenderables.end(), pred_sp_sort); - - // Determine visibility for dynamic part of scene - set_Object(0); - u32 uID_LTRACK = 0xffffffff; - if (phase == PHASE_NORMAL) - { - uLastLTRACK ++; - if (lstRenderables.size()) uID_LTRACK = uLastLTRACK % lstRenderables.size(); - - // update light-vis for current entity / actor - CObject* O = g_pGameLevel->CurrentViewEntity(); - if (O) - { - CROS_impl* R = (CROS_impl*)O->ROS(); - if (R) R->update(O); - } - - // update light-vis for selected entity - // track lighting environment - if (lstRenderables.size()) - { - IRenderable* renderable = lstRenderables[uID_LTRACK]->dcast_Renderable(); - if (renderable) - { - CROS_impl* T = (CROS_impl*)renderable->renderable_ROS(); - if (T) T->update(renderable); - } - } - } - } - - // Traverse sector/portal structure - PortalTraverser.traverse - ( - pLastSector, - ViewBase, - Device.vCameraPosition, - m_ViewProjection, - CPortalTraverser::VQ_HOM + CPortalTraverser::VQ_SSA + CPortalTraverser::VQ_FADE - //. disabled scissoring (HW.Caps.bScissor?CPortalTraverser::VQ_SCISSOR:0) // generate scissoring info - ); - - // Determine visibility for static geometry hierrarhy - for (u32 s_it = 0; s_it < PortalTraverser.r_sectors.size(); s_it++) - { - CSector* sector = (CSector*)PortalTraverser.r_sectors[s_it]; - dxRender_Visual* root = sector->root(); - for (u32 v_it = 0; v_it < sector->r_frustums.size(); v_it++) - { - set_Frustum(&(sector->r_frustums[v_it])); - add_Geometry(root); - } - } - - // Traverse frustums - for (u32 o_it = 0; o_it < lstRenderables.size(); o_it++) - { - ISpatial* spatial = lstRenderables[o_it]; - spatial->spatial_updatesector(); - CSector* sector = (CSector*)spatial->spatial.sector; - if (0 == sector) continue; // disassociated from S/P structure - - if (spatial->spatial.type & STYPE_LIGHTSOURCE) - { - // lightsource - light* L = (light*)(spatial->dcast_Light()); - VERIFY(L); - float lod = L->get_LOD(); - if (lod > EPS_L) - { - vis_data& vis = L->get_homdata(); - if (HOM.visible(vis)) Lights.add_light(L); - } - continue ; - } - - if (PortalTraverser.i_marker != sector->r_marker) continue; // inactive (untouched) sector - for (u32 v_it = 0; v_it < sector->r_frustums.size(); v_it++) - { - CFrustum& view = sector->r_frustums[v_it]; - if (!view.testSphere_dirty(spatial->spatial.sphere.P, spatial->spatial.sphere.R)) continue; - - if (spatial->spatial.type & STYPE_RENDERABLE) - { - // renderable - IRenderable* renderable = spatial->dcast_Renderable(); - VERIFY(renderable); - - // Occlusion - // casting is faster then using getVis method - vis_data& v_orig = ((dxRender_Visual*)renderable->renderable.visual)->vis; - vis_data v_copy = v_orig; - v_copy.box.xform(renderable->renderable.xform); - BOOL bVisible = HOM.visible(v_copy); - v_orig.marker = v_copy.marker; - v_orig.accept_frame = v_copy.accept_frame; - v_orig.hom_frame = v_copy.hom_frame; - v_orig.hom_tested = v_copy.hom_tested; - if (!bVisible) break; // exit loop on frustums - - // Rendering - set_Object(renderable); - renderable->renderable_Render(); - set_Object(0); - } - break; // exit loop on frustums - } - } - if (g_pGameLevel && (phase == PHASE_NORMAL)) - { - g_hud->Render_Last(); // HUD - if (g_hud->RenderActiveItemUIQuery()) - r_dsgraph_render_hud_ui(); - if (g_hud->RenderCamAttachedUIQuery()) - r_dsgraph_render_cam_ui(); - } - } - else - { - set_Object(0); - if (g_pGameLevel && (phase == PHASE_NORMAL)) - { - g_hud->Render_Last(); // HUD - if (g_hud->RenderActiveItemUIQuery()) - r_dsgraph_render_hud_ui(); - if (g_hud->RenderCamAttachedUIQuery()) - r_dsgraph_render_cam_ui(); - } - } -} +#include "../xrRender/SkeletonCustom.h" +#include "../../xrParticles/ParticlesAsyncManager.h" void CRender::render_menu() { @@ -216,8 +57,6 @@ extern u32 g_r; void CRender::Render() { - VERIFY(0==mapDistort.size()); - bool _menu_pp = g_pGamePersistent ? g_pGamePersistent->OnRenderPPUI_query() : false; if (_menu_pp) { @@ -232,6 +71,9 @@ void CRender::Render() if (m_bFirstFrameAfterReset) { + for (light* L : v_all_lights)//critical!!! + L->m_moving_frames = 0; + m_bFirstFrameAfterReset = false; return; } @@ -247,175 +89,47 @@ void CRender::Render() // HOM ViewBase.CreateFromMatrix(Device.mFullTransform, FRUSTUM_P_LRTB + FRUSTUM_P_FAR); - View = 0; - if (!ps_r2_ls_flags.test(R2FLAG_EXP_MT_CALC)) - { - HOM.Enable(); - HOM.Render(ViewBase); - } - - //******* Z-prefill calc - DEFERRER RENDERER - if (ps_r2_ls_flags.test(R2FLAG_ZFILL)) - { - Device.Statistic->RenderCALC.Begin(); - float z_distance = ps_r2_zfill; - Fmatrix m_zfill, m_project; - m_project.build_projection( - deg2rad(Device.fFOV/* *Device.fASPECT*/), - Device.fASPECT, VIEWPORT_NEAR, - z_distance * g_pGamePersistent->Environment().CurrentEnv->far_plane); - m_zfill.mul(m_project, Device.mView); - r_pmask(true, false); // enable priority "0" - set_Recorder(NULL); - phase = PHASE_SMAP; - render_main(m_zfill, false); - r_pmask(true, false); // disable priority "1" - Device.Statistic->RenderCALC.End(); - - // flush - Target->phase_scene_prepare(); - RCache.set_ColorWriteEnable(FALSE); - r_dsgraph_render_graph(0); - RCache.set_ColorWriteEnable(); - } - else - { - Target->phase_scene_prepare(); - } + HOM.MT_RENDER(); - //******* - // Sync point - Device.Statistic->RenderDUMP_Wait_S.Begin(); - if (ps_r2_qsync) - { - CTimer T; - T.Start(); - BOOL result = FALSE; - HRESULT hr = S_FALSE; - while ((hr = q_sync_point[q_sync_count]->GetData(&result, sizeof(result),D3DGETDATA_FLUSH)) == S_FALSE) - { - if (!SwitchToThread()) Sleep(ps_r2_wait_sleep); - if (T.GetElapsed_ms() > 500) - { - result = FALSE; - break; - } - } - } - Device.Statistic->RenderDUMP_Wait_S.End(); - q_sync_count = (q_sync_count + 1) % HW.Caps.iGPUNum; - CHK_DX(q_sync_point[q_sync_count]->Issue(D3DISSUE_END)); + Target->phase_scene_prepare(); //******* Main calc - DEFERRER RENDERER // Main calc Device.Statistic->RenderCALC.Begin(); - r_pmask(true, false, true); // enable priority "0",+ capture wmarks - if (bSUN) set_Recorder(&main_coarse_structure); - else set_Recorder(NULL); phase = PHASE_NORMAL; - render_main(Device.mFullTransform, true); - set_Recorder(NULL); - r_pmask(true, false); // disable priority "1" + GMBase.traverse(pLastSector, ViewBase, Device.vCameraPosition, Device.mFullTransform); + GMBase.r_dsgraph_capture(false, true); + GMBase.r_dsgraph_capture_hud(); Device.Statistic->RenderCALC.End(); if (ps_r2_ls_flags.test(R2FLAG_TERRAIN_PREPASS)) { Target->u_setrt(Device.dwWidth, Device.dwHeight, NULL, NULL, NULL, HW.pBaseZB); - r_dsgraph_render_landscape(0, false); } - BOOL split_the_scene_to_minimize_wait = FALSE; - if (ps_r2_ls_flags.test(R2FLAG_EXP_SPLIT_SCENE)) split_the_scene_to_minimize_wait = TRUE; - //******* Main render :: PART-0 -- first - if (!split_the_scene_to_minimize_wait) - { - // level, DO NOT SPLIT - Target->phase_scene_begin(); - r_dsgraph_render_hud(); - r_dsgraph_render_graph(0); - r_dsgraph_render_lods(true, true); - if (Details) Details->Render(); - if (ps_r2_ls_flags.test(R2FLAG_TERRAIN_PREPASS)) r_dsgraph_render_landscape(1, true); - Target->phase_scene_end(); - } - else { // level, SPLIT Target->phase_scene_begin(); - r_dsgraph_render_graph(0); + GMBase.r_dsgraph_render_graph(0); Target->disable_aniso(); } //******* Occlusion testing of volume-limited light-sources - Target->phase_occq(); - LP_normal.clear(); - LP_pending.clear(); { - // perform tests - u32 count = 0; - light_Package& LP = Lights.package; - - // stats - stats.l_shadowed = LP.v_shadowed.size(); - stats.l_unshadowed = LP.v_point.size() + LP.v_spot.size(); - stats.l_total = stats.l_shadowed + stats.l_unshadowed; - - // perform tests - count = _max(count, LP.v_point.size()); - count = _max(count, LP.v_spot.size()); - count = _max(count, LP.v_shadowed.size()); - for (u32 it = 0; it < count; it++) - { - if (it < LP.v_point.size()) - { - light* L = LP.v_point[it]; - L->vis_prepare(); - if (L->vis.pending) LP_pending.v_point.push_back(L); - else LP_normal.v_point.push_back(L); - } - if (it < LP.v_spot.size()) - { - light* L = LP.v_spot[it]; - L->vis_prepare(); - if (L->vis.pending) LP_pending.v_spot.push_back(L); - else LP_normal.v_spot.push_back(L); - } - if (it < LP.v_shadowed.size()) - { - light* L = LP.v_shadowed[it]; - L->vis_prepare(); - if (L->vis.pending) LP_pending.v_shadowed.push_back(L); - else LP_normal.v_shadowed.push_back(L); - } - } + Target->phase_occq(); + LP_normal.clear(); + LP_pending.clear(); + GMBase.r_dsgraph_capture_lights(); } - LP_normal.sort(); - LP_pending.sort(); //******* Main render :: PART-1 (second) - if (split_the_scene_to_minimize_wait) { - // skybox can be drawn here - if (0) - { - Target->u_setrt(Target->rt_Generic_0, Target->rt_Generic_1, 0, HW.pBaseZB); - RCache.set_CullMode(CULL_NONE); - RCache.set_Stencil(FALSE); - - // draw skybox - RCache.set_ColorWriteEnable(); - CHK_DX(HW.pDevice->SetRenderState ( D3DRS_ZENABLE, FALSE )); - g_pGamePersistent->Environment().RenderSky(); - CHK_DX(HW.pDevice->SetRenderState ( D3DRS_ZENABLE, TRUE )); - } - - // level + // level, SPLIT2 Target->phase_scene_begin(); - r_dsgraph_render_hud(); - r_dsgraph_render_lods(true, true); + GMBase.r_dsgraph_render_hud(); + GMBase.r_dsgraph_render_lods(true, true); if (Details) Details->Render(); - if (ps_r2_ls_flags.test(R2FLAG_TERRAIN_PREPASS)) r_dsgraph_render_landscape(1, true); Target->phase_scene_end(); } @@ -427,37 +141,12 @@ void CRender::Render() Wallmarks->Render(); // wallmarks has priority as normal geometry } - // Update incremental shadowmap-visibility solver - { - u32 it = 0; - for (it = 0; it < Lights_LastFrame.size(); it++) - { - if (0 == Lights_LastFrame[it]) continue ; - try - { - Lights_LastFrame[it]->svis.flushoccq(); - } - catch (...) - { - Msg("! Failed to flush-OCCq on light [%d] %X", it, *(u32*)(&Lights_LastFrame[it])); - } - } - Lights_LastFrame.clear(); - } - // Directional light - fucking sun if (bSUN) { RImplementation.stats.l_visible ++; - if (!ps_r2_ls_flags_ext.is(R2FLAGEXT_SUN_OLD)) - render_sun_cascades(); - else - { - render_sun_near(); - render_sun(); - render_sun_filtered(); - } - + render_sun_cascades(); + Target->increment_light_marker(); Target->accum_direct_blend(); } @@ -472,7 +161,7 @@ void CRender::Render() //RCache.set_Stencil (TRUE,D3DCMP_ALWAYS,0x00,0xff,0xff,D3DSTENCILOP_KEEP,D3DSTENCILOP_REPLACE,D3DSTENCILOP_KEEP); RCache.set_CullMode(CULL_CCW); RCache.set_ColorWriteEnable(); - RImplementation.r_dsgraph_render_emissive(); + GMBase.r_dsgraph_render_emissive(); // Stencil - draw only where stencil >= 0x1 RCache.set_Stencil(TRUE, D3DCMP_LESSEQUAL, 0x01, 0xff, 0x00); @@ -482,7 +171,6 @@ void CRender::Render() // Lighting, non dependant on OCCQ Target->phase_accumulator(); - HOM.Disable(); render_lights(LP_normal); // Lighting, dependant on OCCQ @@ -490,26 +178,35 @@ void CRender::Render() // Postprocess Target->phase_combine(); - VERIFY(0 == mapDistort.size() + mapHUDDistort.size()); + + /*if (Details) + Details->details_clear();*/ + + if (g_hud) + { + if (g_hud->RenderActiveItemUIQuery()) + GMBase.r_dsgraph_render_hud_ui(); + if (g_hud->RenderCamAttachedUIQuery()) + GMBase.r_dsgraph_render_cam_ui(); + } } void CRender::render_forward() { - VERIFY(0 == mapDistort.size() + mapHUDDistort.size()); RImplementation.o.distortion = RImplementation.o.distortion_enabled; // enable distorion //******* Main render - second order geometry (the one, that doesn't support deffering) //.todo: should be done inside "combine" with estimation of of luminance, tone-mapping, etc. { + HOM.Enable(); // level - r_pmask(false, true); // enable priority "1" phase = PHASE_NORMAL; - render_main(Device.mFullTransform, false); // // Igor: we don't want to render old lods on next frame. - mapLOD.clear(); - r_dsgraph_render_graph(1); // normal level, secondary priority - PortalTraverser.fade_render(); // faded-portals - r_dsgraph_render_sorted(); // strict-sorted geoms + GMBase.r_dsgraph_render_static(1); // normal level, secondary priority + CParticlesAsync::Wait(); + GMBase.r_dsgraph_render_dynamic(1); + GMBase.fade_render(); // faded-portals + GMBase.r_dsgraph_render_sorted(); // strict-sorted geoms g_pGamePersistent->Environment().RenderLast(); // rain/thunder-bolts } @@ -537,4 +234,4 @@ void CRender::RenderToTarget(RRT target) HW.pDevice->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &pBackBuffer); D3DXLoadSurfaceFromSurface((*RT)->pRT, 0, 0, pBackBuffer, 0, 0, D3DX_DEFAULT, 0); pBackBuffer->Release(); -} \ No newline at end of file +} diff --git a/src/Layers/xrRenderPC_R2/r2_R_sun.cpp b/src/Layers/xrRenderPC_R2/r2_R_sun.cpp deleted file mode 100644 index ae1e8fe8cf..0000000000 --- a/src/Layers/xrRenderPC_R2/r2_R_sun.cpp +++ /dev/null @@ -1,1831 +0,0 @@ -#include "stdafx.h" -#include "../../xrEngine/igame_persistent.h" -#include "../../xrEngine/irenderable.h" -#include "../xrRender/FBasicVisual.h" - -const float tweak_COP_initial_offs = 1200.f; -const float tweak_ortho_xform_initial_offs = 1000.f; //. ? -const float tweak_guaranteed_range = 20.f; //. ? - -//float OLES_SUN_LIMIT_27_01_07 = 180.f ; -float OLES_SUN_LIMIT_27_01_07 = 100.f; - -const float MAP_SIZE_START = 6.f; -const float MAP_GROW_FACTOR = 4.f; - -////////////////////////////////////////////////////////////////////////// -// tables to calculate view-frustum bounds in world space -// note: D3D uses [0..1] range for Z -static Fvector3 corners [8] = { - {-1, -1, 0}, {-1, -1, +1}, - {-1, +1, +1}, {-1, +1, 0}, - {+1, +1, +1}, {+1, +1, 0}, - {+1, -1, +1}, {+1, -1, 0} -}; -static int facetable[6][4] = { - {6, 7, 5, 4}, {1, 0, 7, 6}, - {1, 2, 3, 0}, {3, 2, 4, 5}, - // near and far planes - {0, 3, 5, 7}, {1, 6, 4, 2}, -}; -////////////////////////////////////////////////////////////////////////// -#define DW_AS_FLT(DW) (*(FLOAT*)&(DW)) -#define FLT_AS_DW(F) (*(DWORD*)&(F)) -#define FLT_SIGN(F) ((FLT_AS_DW(F) & 0x80000000L)) -#define ALMOST_ZERO(F) ((FLT_AS_DW(F) & 0x7f800000L)==0) -#define IS_SPECIAL(F) ((FLT_AS_DW(F) & 0x7f800000L)==0x7f800000L) - -////////////////////////////////////////////////////////////////////////// -struct Frustum -{ - Frustum(); - Frustum(const D3DXMATRIX* matrix); - - D3DXPLANE camPlanes [6]; - int nVertexLUT [6]; - D3DXVECTOR3 pntList [8]; -}; - -struct BoundingBox -{ - D3DXVECTOR3 minPt; - D3DXVECTOR3 maxPt; - - BoundingBox(): minPt(1e33f, 1e33f, 1e33f), maxPt(-1e33f, -1e33f, -1e33f) - { - } - - BoundingBox(const BoundingBox& other): minPt(other.minPt), maxPt(other.maxPt) - { - } - - explicit BoundingBox(const D3DXVECTOR3* points, UINT n): minPt(1e33f, 1e33f, 1e33f), maxPt(-1e33f, -1e33f, -1e33f) - { - for (unsigned int i = 0; i < n; i++) - Merge(&points[i]); - } - - explicit BoundingBox(const std::vector* points): minPt(1e33f, 1e33f, 1e33f), - maxPt(-1e33f, -1e33f, -1e33f) - { - for (unsigned int i = 0; i < points->size(); i++) - Merge(&(*points)[i]); - } - - explicit BoundingBox(const std::vector* boxes): minPt(1e33f, 1e33f, 1e33f), - maxPt(-1e33f, -1e33f, -1e33f) - { - for (unsigned int i = 0; i < boxes->size(); i++) - { - Merge(&(*boxes)[i].maxPt); - Merge(&(*boxes)[i].minPt); - } - } - - void Centroid(D3DXVECTOR3* vec) const { *vec = 0.5f * (minPt + maxPt); } - - void Merge(const D3DXVECTOR3* vec) - { - minPt.x = _min(minPt.x, vec->x); - minPt.y = _min(minPt.y, vec->y); - minPt.z = _min(minPt.z, vec->z); - maxPt.x = _max(maxPt.x, vec->x); - maxPt.y = _max(maxPt.y, vec->y); - maxPt.z = _max(maxPt.z, vec->z); - } - - D3DXVECTOR3 Point(int i) const - { - return D3DXVECTOR3((i & 1) ? minPt.x : maxPt.x, (i & 2) ? minPt.y : maxPt.y, (i & 4) ? minPt.z : maxPt.z); - } -}; - -/////////////////////////////////////////////////////////////////////////// -BOOL LineIntersection2D(D3DXVECTOR2* result, const D3DXVECTOR2* lineA, const D3DXVECTOR2* lineB) -{ - // if the lines are parallel, the lines will not intersect in a point - // NOTE: assumes the rays are already normalized!!!! - VERIFY(_abs(D3DXVec2Dot(&lineA[1], &lineB[1]))<1.f); - - float x[2] = {lineA[0].x, lineB[0].x}; - float y[2] = {lineA[0].y, lineB[0].y}; - float dx[2] = {lineA[1].x, lineB[1].x}; - float dy[2] = {lineA[1].y, lineB[1].y}; - - float x_diff = x[0] - x[1]; - float y_diff = y[0] - y[1]; - - float s = (x_diff - (dx[1] / dy[1]) * y_diff) / ((dx[1] * dy[0] / dy[1]) - dx[0]); - // float t = (x_diff + s*dx[0]) / dx[1]; - - *result = lineA[0] + s * lineA[1]; - return TRUE; -} - -/////////////////////////////////////////////////////////////////////////// -// PlaneIntersection -// computes the point where three planes intersect -// returns whether or not the point exists. -static inline BOOL PlaneIntersection(D3DXVECTOR3* intersectPt, const D3DXPLANE* p0, const D3DXPLANE* p1, - const D3DXPLANE* p2) -{ - D3DXVECTOR3 n0(p0->a, p0->b, p0->c); - D3DXVECTOR3 n1(p1->a, p1->b, p1->c); - D3DXVECTOR3 n2(p2->a, p2->b, p2->c); - - D3DXVECTOR3 n1_n2, n2_n0, n0_n1; - - D3DXVec3Cross(&n1_n2, &n1, &n2); - D3DXVec3Cross(&n2_n0, &n2, &n0); - D3DXVec3Cross(&n0_n1, &n0, &n1); - - float cosTheta = D3DXVec3Dot(&n0, &n1_n2); - - if (ALMOST_ZERO(cosTheta) || IS_SPECIAL(cosTheta)) - return FALSE; - - float secTheta = 1.f / cosTheta; - - n1_n2 = n1_n2 * p0->d; - n2_n0 = n2_n0 * p1->d; - n0_n1 = n0_n1 * p2->d; - - *intersectPt = -(n1_n2 + n2_n0 + n0_n1) * secTheta; - return TRUE; -} - -Frustum::Frustum() -{ - for (int i = 0; i < 6; i++) - camPlanes[i] = D3DXPLANE(0.f, 0.f, 0.f, 0.f); -} - -// build a frustum from a camera (projection, or viewProjection) matrix -Frustum::Frustum(const D3DXMATRIX* matrix) -{ - // build a view frustum based on the current view & projection matrices... - D3DXVECTOR4 column4(matrix->_14, matrix->_24, matrix->_34, matrix->_44); - D3DXVECTOR4 column1(matrix->_11, matrix->_21, matrix->_31, matrix->_41); - D3DXVECTOR4 column2(matrix->_12, matrix->_22, matrix->_32, matrix->_42); - D3DXVECTOR4 column3(matrix->_13, matrix->_23, matrix->_33, matrix->_43); - - D3DXVECTOR4 planes[6]; - planes[0] = column4 - column1; // left - planes[1] = column4 + column1; // right - planes[2] = column4 - column2; // bottom - planes[3] = column4 + column2; // top - planes[4] = column4 - column3; // near - planes[5] = column4 + column3; // far - // ignore near & far plane - - int p; - - for (p = 0; p < 6; p++) // normalize the planes - { - float dot = planes[p].x * planes[p].x + planes[p].y * planes[p].y + planes[p].z * planes[p].z; - dot = 1.f / _sqrt(dot); - planes[p] = planes[p] * dot; - } - - for (p = 0; p < 6; p++) - camPlanes[p] = D3DXPLANE(planes[p].x, planes[p].y, planes[p].z, planes[p].w); - - // build a bit-field that will tell us the indices for the nearest and farthest vertices from each plane... - for (int i = 0; i < 6; i++) - nVertexLUT[i] = ((planes[i].x < 0.f) ? 1 : 0) | ((planes[i].y < 0.f) ? 2 : 0) | ((planes[i].z < 0.f) ? 4 : 0); - - for (int i = 0; i < 8; i++) // compute extrema - { - const D3DXPLANE& p0 = (i & 1) ? camPlanes[4] : camPlanes[5]; - const D3DXPLANE& p1 = (i & 2) ? camPlanes[3] : camPlanes[2]; - const D3DXPLANE& p2 = (i & 4) ? camPlanes[0] : camPlanes[1]; - PlaneIntersection(&pntList[i], &p0, &p1, &p2); - } -} - - -////////////////////////////////////////////////////////////////////////// -// OLES: naive builder of infinite volume expanded from base frustum towards -// light source. really slow, but it works for our simple usage :) -// note: normals points to 'outside' -////////////////////////////////////////////////////////////////////////// - -const u32 LIGHT_CUBOIDSIDEPOLYS_COUNT = 4; -const u32 LIGHT_CUBOIDVERTICES_COUNT = 2 * LIGHT_CUBOIDSIDEPOLYS_COUNT; - -template -class FixedConvexVolume -{ -public: - - struct _poly - { - int points[4]; - Fplane plane; - }; - - xr_vector view_frustum_rays; - sun::ray view_ray; - sun::ray light_ray; - Fvector3 light_cuboid_points [LIGHT_CUBOIDVERTICES_COUNT]; - _poly light_cuboid_polys [LIGHT_CUBOIDSIDEPOLYS_COUNT]; - -public: - - void compute_planes() - { - for (u32 it = 0; it < LIGHT_CUBOIDSIDEPOLYS_COUNT; it++) - { - _poly& P = light_cuboid_polys[it]; - - P.plane.build(light_cuboid_points[P.points[0]], light_cuboid_points[P.points[2]], - light_cuboid_points[P.points[1]]); - - // verify - if (_debug) - { - Fvector& p0 = light_cuboid_points[P.points[0]]; - Fvector& p1 = light_cuboid_points[P.points[1]]; - Fvector& p2 = light_cuboid_points[P.points[2]]; - Fvector& p3 = light_cuboid_points[P.points[3]]; - Fplane p012; - p012.build(p0, p1, p2); - Fplane p123; - p123.build(p1, p2, p3); - Fplane p230; - p230.build(p2, p3, p0); - Fplane p301; - p301.build(p3, p0, p1); - VERIFY(p012.n.similar(p123.n) && p012.n.similar(p230.n) && p012.n.similar(p301.n)); - } - } - } - - void compute_caster_model_fixed(xr_vector& dest, Fvector3& translation, float map_size, - bool clip_by_view_near) - { - translation.set(0.f, 0.f, 0.f); - - if (fis_zero(1 - abs(view_ray.D.dotproduct(light_ray.D)), EPS_S)) - return; - - // compute planes for each polygon. - compute_planes(); - - for (u32 i = 0; i < LIGHT_CUBOIDSIDEPOLYS_COUNT; i++) - VERIFY(light_cuboid_polys[i].plane.classify(light_ray.P) > 0); - - int align_planes[2]; - int align_planes_count = 0; - - // find one or two planes that align to view frustum from behind. - for (u32 i = 0; i < LIGHT_CUBOIDSIDEPOLYS_COUNT; i++) - { - float tmp_dot = view_ray.D.dotproduct(light_cuboid_polys[i].plane.n); - if (tmp_dot <= EPS_L) - continue; - - align_planes[align_planes_count] = i; - ++align_planes_count; - - if (align_planes_count == 2) - break; - } - - - Fvector align_vector; - align_vector.set(0.f, 0.f, 0.f); - - // Align ray points to the align planes. - for (int p = 0; p < align_planes_count; ++p) - { - // Hack ! - float min_dist = 10000; - for (u32 i = 0; i < view_frustum_rays.size(); ++i) - { - float tmp_dist = 0; - Fvector tmp_point = view_frustum_rays[i].P; - - tmp_dist = light_cuboid_polys[align_planes[p]].plane.classify(tmp_point); - min_dist = _min(tmp_dist, min_dist); - } - - Fvector shift = light_cuboid_polys[align_planes[p]].plane.n; - shift.mul(min_dist); - align_vector.add(shift); - } - - translation.add(align_vector); - - // Move light ray by the alignment shift. - light_ray.P.add(align_vector); - - // Here we can skip this stage us in the next pass we need only normals of planes. - // in the next translate_light_model call will contain this shift as well. - // translate_light_model ( align_vector ); - - // Reset to reuse. - align_vector.set(0.f, 0.f, 0.f); - - // Check if view edges intersect, and push planes................ - for (int p = 0; p < align_planes_count; ++p) - { - float max_mag = 0; - for (u32 i = 0; i < view_frustum_rays.size(); ++i) - { - float plane_dot_ray = view_frustum_rays[i].D.dotproduct(light_cuboid_polys[align_planes[p]].plane.n); - if (plane_dot_ray < 0) - { - Fvector per_plane_view; - per_plane_view.crossproduct(light_cuboid_polys[align_planes[p]].plane.n, view_ray.D); - Fvector per_view_to_plane; - per_view_to_plane.crossproduct(per_plane_view, view_ray.D); - - float tmp_mag = -plane_dot_ray / view_frustum_rays[i].D.dotproduct(per_view_to_plane); - - max_mag = (max_mag < tmp_mag) ? tmp_mag : max_mag; - } - } - - if (fis_zero(max_mag)) - continue; - - VERIFY(max_mag <= 1.f); - - float dist = -light_cuboid_polys[align_planes[p]].plane.n.dotproduct(translation); - align_vector.mad(light_cuboid_polys[align_planes[p]].plane.n, dist * max_mag); - } - - translation.add(align_vector); - light_ray.P.add(align_vector); - translate_light_model(translation); - - - // compute culling planes by rays as edges - for (u32 i = 0; i < view_frustum_rays.size(); ++i) - { - Fvector tmp_vector; - tmp_vector.crossproduct(view_frustum_rays[i].D, light_ray.D); - - // check if the vectors are parallel - if (fis_zero(tmp_vector.square_magnitude(), EPS)) - continue; - - Fplane tmp_plane; - tmp_plane.build(view_frustum_rays[i].P, tmp_vector); - - float sign = 0; - if (check_cull_plane_valid(tmp_plane, sign, 5)) - { - tmp_plane.n.mul(-sign); - tmp_plane.d *= -sign; - dest.push_back(tmp_plane); - } - } - - // compute culling planes by ray points pairs as edges - if (clip_by_view_near && abs(view_ray.D.dotproduct(light_ray.D)) < 0.8) - { - Fvector perp_light_view, perp_light_to_view; - perp_light_view.crossproduct(view_ray.D, light_ray.D); - perp_light_to_view.crossproduct(perp_light_view, light_ray.D); - - Fplane plane; - plane.build(view_ray.P, perp_light_to_view); - - float max_dist = -1000; - for (u32 i = 0; i < view_frustum_rays.size(); ++i) - max_dist = _max(plane.classify(view_frustum_rays[i].P), max_dist); - - for (u32 i = 0; i < view_frustum_rays.size(); ++i) - { - Fvector P = view_frustum_rays[i].P; - P.mad(view_frustum_rays[i].D, 5); - - if (plane.classify(P) > max_dist) - { - max_dist = 0.f; - break; - } - } - - if (max_dist > -1000) - { - plane.d += max_dist; - dest.push_back(plane); - } - } - - for (u32 i = 0; i < LIGHT_CUBOIDSIDEPOLYS_COUNT; i++) - { - dest.push_back(light_cuboid_polys[i].plane); - dest.back().n.mul(-1); - dest.back().d *= -1; - VERIFY(light_cuboid_polys[i].plane.classify(light_ray.P) > 0); - } - - // Compute ray intersection with light model, this is needed to next cascade to start it's placement. - for (u32 i = 0; i < view_frustum_rays.size(); ++i) - { - float min_dist = 2 * map_size; - for (int p = 0; p < 4; ++p) - { - float dist; - if ((light_cuboid_polys[p].plane.n.dotproduct(view_frustum_rays[i].D)) > -0.1) - dist = map_size; - else - light_cuboid_polys[p].plane.intersectRayDist(view_frustum_rays[i].P, view_frustum_rays[i].D, dist); - - if (dist > EPS_L && dist < min_dist) - min_dist = dist; - } - - view_frustum_rays[i].P.mad(view_frustum_rays[i].D, min_dist); - } - } - - bool check_cull_plane_valid(Fplane const& plane, float& sign, float mad_factor = 0.f) - { - bool valid = false; - bool oriented = false; - float orient = 0; - for (u32 j = 0; j < view_frustum_rays.size(); ++j) - { - float tmp_dist = 0.f; - Fvector tmp_pt = view_frustum_rays[j].P; - tmp_pt.mad(view_frustum_rays[j].D, mad_factor); - tmp_dist = plane.classify(tmp_pt); - - if (fis_zero(tmp_dist, EPS_L)) - continue; - - if (!oriented) - { - orient = tmp_dist > 0.f ? 1.f : -1.f; - valid = true; - oriented = true; - continue; - } - - if (tmp_dist < 0 && orient < 0 || tmp_dist > 0 && orient > 0) - continue; - - valid = false; - break; - } - sign = orient; - return valid; - } - - void translate_light_model(Fvector translate) - { - Fmatrix trans_mat; - trans_mat.translate(translate); - for (int i = 0; i < LIGHT_CUBOIDSIDEPOLYS_COUNT; ++i) - light_cuboid_polys[i].plane.d -= translate.dotproduct(light_cuboid_polys[i].plane.n); - } -}; - -////////////////////////////////////////////////////////////////////////// -// OLES: naive builder of infinite volume expanded from base frustum towards -// light source. really slow, but it works for our simple usage :) -// note: normals points to 'outside' -////////////////////////////////////////////////////////////////////////// -template -class DumbConvexVolume -{ -public: - struct _poly - { - xr_vector points; - Fvector3 planeN; - float planeD; - float classify(Fvector3& p) { return planeN.dotproduct(p) + planeD; } - }; - - struct _edge - { - int p0, p1; - int counter; - _edge(int _p0, int _p1, int m) : p0(_p0), p1(_p1), counter(m) { if (p0 > p1) swap(p0, p1); } - bool equal(_edge& E) { return p0 == E.p0 && p1 == E.p1; } - }; - -public: - xr_vector points; - xr_vector<_poly> polys; - xr_vector<_edge> edges; -public: - void compute_planes() - { - for (int it = 0; it < int(polys.size()); it++) - { - _poly& P = polys[it]; - Fvector3 t1, t2; - t1.sub(points[P.points[0]], points[P.points[1]]); - t2.sub(points[P.points[0]], points[P.points[2]]); - P.planeN.crossproduct(t1, t2).normalize(); - P.planeD = - P.planeN.dotproduct(points[P.points[0]]); - - // verify - if (_debug) - { - Fvector& p0 = points[P.points[0]]; - Fvector& p1 = points[P.points[1]]; - Fvector& p2 = points[P.points[2]]; - Fvector& p3 = points[P.points[3]]; - Fplane p012; - p012.build(p0, p1, p2); - Fplane p123; - p123.build(p1, p2, p3); - Fplane p230; - p230.build(p2, p3, p0); - Fplane p301; - p301.build(p3, p0, p1); - VERIFY(p012.n.similar(p123.n) && p012.n.similar(p230.n) && p012.n.similar(p301.n)); - } - } - } - - - void compute_caster_model(xr_vector& dest, Fvector3 direction) - { - CRenderTarget& T = *RImplementation.Target; - - // COG - Fvector3 cog = {0, 0, 0}; - for (int it = 0; it < int(points.size()); it++) cog.add(points[it]); - cog.div(float(points.size())); - - // planes - compute_planes(); - for (int it = 0; it < int(polys.size()); it++) - { - _poly& base = polys[it]; - if (base.classify(cog) > 0) std::reverse(base.points.begin(), base.points.end()); - } - - // remove faceforward polys, build list of edges -> find open ones - compute_planes(); - for (int it = 0; it < int(polys.size()); it++) - { - _poly& base = polys[it]; - VERIFY(base.classify(cog)<0); // debug - - int marker = (base.planeN.dotproduct(direction) <= 0) ? -1 : 1; - - // register edges - xr_vector& plist = polys[it].points; - for (int p = 0; p < int(plist.size()); p++) - { - _edge E(plist[p], plist[(p + 1) % plist.size()], marker); - bool found = false; - for (int e = 0; e < int(edges.size()); e++) - if (edges[e].equal(E)) - { - edges[e].counter += marker; - found = true; - break; - } - if (!found) - { - edges.push_back(E); - if (_debug) T.dbg_addline(points[E.p0], points[E.p1], color_rgba(255, 0, 0, 255)); - } - } - - // remove if unused - if (marker < 0) - { - polys.erase(polys.begin() + it); - it--; - } - } - - // Extend model to infinity, the volume is not capped, so this is indeed up to infinity - for (int e = 0; e < int(edges.size()); e++) - { - if (edges[e].counter != 0) continue; - _edge& E = edges[e]; - if (_debug) T.dbg_addline(points[E.p0], points[E.p1], color_rgba(255, 255, 255, 255)); - Fvector3 point; - points.push_back(point.sub(points[E.p0], direction)); - points.push_back(point.sub(points[E.p1], direction)); - polys.push_back(_poly()); - _poly& P = polys.back(); - int pend = int(points.size()); - P.points.push_back(E.p0); - P.points.push_back(E.p1); - P.points.push_back(pend - 1); //p1 mod - P.points.push_back(pend - 2); //p0 mod - if (_debug) T.dbg_addline(points[E.p0], point.mad(points[E.p0], direction, -1000), - color_rgba(0, 255, 0, 255)); - if (_debug) T.dbg_addline(points[E.p1], point.mad(points[E.p1], direction, -1000), - color_rgba(0, 255, 0, 255)); - } - - // Reorient planes (try to write more inefficient code :) - compute_planes(); - for (int it = 0; it < int(polys.size()); it++) - { - _poly& base = polys[it]; - if (base.classify(cog) > 0) std::reverse(base.points.begin(), base.points.end()); - } - - // Export - compute_planes(); - for (int it = 0; it < int(polys.size()); it++) - { - _poly& P = polys[it]; - Fplane pp = {P.planeN, P.planeD}; - dest.push_back(pp); - } - } -}; - -////////////////////////////////////////////////////////////////////////// -Fvector3 wform(Fmatrix& m, Fvector3 const& v) -{ - Fvector4 r; - r.x = v.x * m._11 + v.y * m._21 + v.z * m._31 + m._41; - r.y = v.x * m._12 + v.y * m._22 + v.z * m._32 + m._42; - r.z = v.x * m._13 + v.y * m._23 + v.z * m._33 + m._43; - r.w = v.x * m._14 + v.y * m._24 + v.z * m._34 + m._44; - // VERIFY (r.w>0.f); - float invW = 1.0f / r.w; - Fvector3 r3 = {r.x * invW, r.y * invW, r.z * invW}; - return r3; -} - -////////////////////////////////////////////////////////////////////////// -// OLES: naive 3D clipper - roubustness around 0, but works for this sample -// note: normals points to 'outside' -////////////////////////////////////////////////////////////////////////// -const float _eps = 0.000001f; - -struct DumbClipper -{ - CFrustum frustum; - xr_vector planes; - - BOOL clip(D3DXVECTOR3& p0, D3DXVECTOR3& p1) // returns TRUE if result meaningfull - { - float denum; - D3DXVECTOR3 D; - for (int it = 0; it < int(planes.size()); it++) - { - D3DXPLANE& P = planes[it]; - float cls0 = D3DXPlaneDotCoord(&P, &p0); - float cls1 = D3DXPlaneDotCoord(&P, &p1); - if (cls0 > 0 && cls1 > 0) return false; // fully outside - - if (cls0 > 0) - { - // clip p0 - D = p1 - p0; - denum = D3DXPlaneDotNormal(&P, &D); - if (denum != 0) p0 += - D * cls0 / denum; - } - if (cls1 > 0) - { - // clip p1 - D = p0 - p1; - denum = D3DXPlaneDotNormal(&P, &D); - if (denum != 0) p1 += - D * cls1 / denum; - } - } - return true; - } - - D3DXVECTOR3 point(Fbox& bb, int i) const - { - return D3DXVECTOR3((i & 1) ? bb.min.x : bb.max.x, (i & 2) ? bb.min.y : bb.max.y, (i & 4) ? bb.min.z : bb.max.z); - } - - Fbox clipped_AABB(xr_vector>& src, Fmatrix& xf) - { - Fbox3 result; - result.invalidate(); - for (int it = 0; it < int(src.size()); it++) - { - Fbox& bb = src[it]; - u32 mask = frustum.getMask(); - EFC_Visible res = frustum.testAABB(&bb.min.x, mask); - switch (res) - { - case fcvNone: continue; - case fcvFully: - for (int c = 0; c < 8; c++) - { - D3DXVECTOR3 p0 = point(bb, c); - Fvector x0 = wform(xf, *((Fvector*)(&p0))); - result.modify(x0); - } - break; - case fcvPartial: - for (int c0 = 0; c0 < 8; c0++) - { - for (int c1 = 0; c1 < 8; c1++) - { - if (c0 == c1) continue; - D3DXVECTOR3 p0 = point(bb, c0); - D3DXVECTOR3 p1 = point(bb, c1); - if (!clip(p0, p1)) continue; - Fvector x0 = wform(xf, *((Fvector*)(&p0))); - Fvector x1 = wform(xf, *((Fvector*)(&p1))); - result.modify(x0); - result.modify(x1); - } - } - break; - }; - } - return result; - } -}; - -template -inline const _Tp& min(const _Tp& __a, const _Tp& __b) -{ - return __b < __a ? __b : __a; -} - -template -inline const _Tp& max(const _Tp& __a, const _Tp& __b) -{ - return __a < __b ? __b : __a; -} - -xr_vector> s_casters; - -D3DXVECTOR2 BuildTSMProjectionMatrix_caster_depth_bounds(D3DXMATRIX& lightSpaceBasis) -{ - float min_z = 1e32f, max_z = -1e32f; - D3DXMATRIX minmax_xf; - D3DXMatrixMultiply(&minmax_xf, (D3DXMATRIX*)&Device.mView, &lightSpaceBasis); - Fmatrix& minmax_xform = *((Fmatrix*)&minmax_xf); - for (u32 c = 0; c < s_casters.size(); c++) - { - Fvector3 pt; - for (int e = 0; e < 8; e++) - { - s_casters[c].getpoint(e, pt); - pt = wform(minmax_xform, pt); - min_z = _min(min_z, pt.z); - max_z = _max(max_z, pt.z); - } - } - return D3DXVECTOR2(min_z, max_z); -} - -void CRender::render_sun() -{ - light* fuckingsun = (light*)Lights.sun_adapted._get(); - D3DXMATRIX m_LightViewProj; - - // calculate view-frustum bounds in world space - Fmatrix ex_project, ex_full, ex_full_inverse; - { - float _far_ = min(OLES_SUN_LIMIT_27_01_07, g_pGamePersistent->Environment().CurrentEnv->far_plane); - //ex_project.build_projection (deg2rad(Device.fFOV/* *Device.fASPECT*/),Device.fASPECT,ps_r2_sun_near,_far_); - ex_project.build_projection(deg2rad(Device.fFOV/* *Device.fASPECT*/), Device.fASPECT,VIEWPORT_NEAR, _far_); - ex_full.mul(ex_project, Device.mView); - D3DXMatrixInverse((D3DXMATRIX*)&ex_full_inverse, 0, (D3DXMATRIX*)&ex_full); - } - - // Compute volume(s) - something like a frustum for infinite directional light - // Also compute virtual light position and sector it is inside - CFrustum cull_frustum; - xr_vector cull_planes; - Fvector3 cull_COP; - CSector* cull_sector; - Fmatrix cull_xform; - { - FPU::m64r(); - // Lets begin from base frustum - Fmatrix fullxform_inv = ex_full_inverse; - DumbConvexVolume hull; - { - hull.points.reserve(8); - for (int p = 0; p < 8; p++) - { - Fvector3 xf = wform(fullxform_inv, corners[p]); - hull.points.push_back(xf); - } - for (int plane = 0; plane < 6; plane++) - { - hull.polys.push_back(DumbConvexVolume::_poly()); - for (int pt = 0; pt < 4; pt++) - hull.polys.back().points.push_back(facetable[plane][pt]); - } - } - hull.compute_caster_model(cull_planes, fuckingsun->direction); - - // Search for default sector - assume "default" or "outdoor" sector is the largest one - //. hack: need to know real outdoor sector - CSector* largest_sector = 0; - float largest_sector_vol = 0; - for (u32 s = 0; s < Sectors.size(); s++) - { - CSector* S = (CSector*)Sectors[s]; - dxRender_Visual* V = S->root(); - float vol = V->vis.box.getvolume(); - if (vol > largest_sector_vol) - { - largest_sector_vol = vol; - largest_sector = S; - } - } - cull_sector = largest_sector; - - // COP - 100 km away - cull_COP.mad(Device.vCameraPosition, fuckingsun->direction, -tweak_COP_initial_offs); - - // Create frustum for query - cull_frustum._clear(); - for (u32 p = 0; p < cull_planes.size(); p++) - cull_frustum._add(cull_planes[p]); - - // Create approximate ortho-xform - // view: auto find 'up' and 'right' vectors - Fmatrix mdir_View, mdir_Project; - Fvector L_dir, L_up, L_right, L_pos; - L_pos.set(fuckingsun->position); - L_dir.set(fuckingsun->direction).normalize(); - L_up.set(0, 1, 0); - if (_abs(L_up.dotproduct(L_dir)) > .99f) L_up.set(0, 0, 1); - L_right.crossproduct(L_up, L_dir).normalize(); - L_up.crossproduct(L_dir, L_right).normalize(); - mdir_View.build_camera_dir(L_pos, L_dir, L_up); - - // projection: box - Fbox frustum_bb; - frustum_bb.invalidate(); - for (int it = 0; it < 8; it++) - { - Fvector xf = wform(mdir_View, hull.points[it]); - frustum_bb.modify(xf); - } - Fbox& bb = frustum_bb; - bb.grow(EPS); - D3DXMatrixOrthoOffCenterLH((D3DXMATRIX*)&mdir_Project, bb.min.x, bb.max.x, bb.min.y, bb.max.y, - bb.min.z - tweak_ortho_xform_initial_offs, bb.max.z); - - // full-xform - cull_xform.mul(mdir_Project, mdir_View); - FPU::m24r(); - } - - // Begin SMAP-render - { - HOM.Disable(); - phase = PHASE_SMAP; - if (RImplementation.o.Tshadows) r_pmask(true, true); - else r_pmask(true, false); - // fuckingsun->svis.begin (); - } - - // Fill the database - xr_vector>& s_receivers = main_coarse_structure; - s_casters.reserve(s_receivers.size()); - set_Recorder(&s_casters); - r_dsgraph_render_subspace(cull_sector, &cull_frustum, cull_xform, cull_COP, TRUE); - - // IGNORE PORTALS - if (ps_r2_ls_flags.test(R2FLAG_SUN_IGNORE_PORTALS)) - { - for (u32 s = 0; s < Sectors.size(); s++) - { - CSector* S = (CSector*)Sectors[s]; - dxRender_Visual* root = S->root(); - - set_Frustum(&cull_frustum); - add_Geometry(root); - } - } - set_Recorder(NULL); - - // Prepare to interact with D3DX code - const D3DXMATRIX& m_View = *((D3DXMATRIX*)(&Device.mView)); - const D3DXMATRIX& m_Projection = *((D3DXMATRIX*)(&ex_project)); - const D3DXVECTOR3 m_lightDir = -D3DXVECTOR3(fuckingsun->direction.x, fuckingsun->direction.y, - fuckingsun->direction.z); - - // these are the limits specified by the physical camera - // gamma is the "tilt angle" between the light and the view direction. - float m_fCosGamma = m_lightDir.x * m_View._13 + - m_lightDir.y * m_View._23 + - m_lightDir.z * m_View._33; - float m_fTSM_Delta = ps_r2_sun_tsm_projection; - - // Compute REAL sheared xform based on receivers/casters information - FPU::m64r(); - if (_abs(m_fCosGamma) < 0.99f && ps_r2_ls_flags.test(R2FLAG_SUN_TSM)) - { - // get the near and the far plane (points) in eye space. - D3DXVECTOR3 frustumPnts[8]; - - Frustum eyeFrustum(&m_Projection); // autocomputes all the extrema points - - for (int i = 0; i < 4; i++) - { - frustumPnts[i] = eyeFrustum.pntList[(i << 1)]; // far plane - frustumPnts[i + 4] = eyeFrustum.pntList[(i << 1) | 0x1]; // near plane - } - - // we need to transform the eye into the light's post-projective space. - // however, the sun is a directional light, so we first need to find an appropriate - // rotate/translate matrix, before constructing an ortho projection. - // this matrix is a variant of "light space" from LSPSMs, with the Y and Z axes permuted - - D3DXVECTOR3 leftVector, upVector, viewVector; - const D3DXVECTOR3 eyeVector(0.f, 0.f, -1.f); // eye is always -Z in eye space - - // code copied straight from BuildLSPSMProjectionMatrix - D3DXVec3TransformNormal(&upVector, &m_lightDir, &m_View); // lightDir is defined in eye space, so xform it - D3DXVec3Cross(&leftVector, &upVector, &eyeVector); - D3DXVec3Normalize(&leftVector, &leftVector); - D3DXVec3Cross(&viewVector, &upVector, &leftVector); - - D3DXMATRIX lightSpaceBasis; - lightSpaceBasis._11 = leftVector.x; - lightSpaceBasis._12 = viewVector.x; - lightSpaceBasis._13 = -upVector.x; - lightSpaceBasis._14 = 0.f; - lightSpaceBasis._21 = leftVector.y; - lightSpaceBasis._22 = viewVector.y; - lightSpaceBasis._23 = -upVector.y; - lightSpaceBasis._24 = 0.f; - lightSpaceBasis._31 = leftVector.z; - lightSpaceBasis._32 = viewVector.z; - lightSpaceBasis._33 = -upVector.z; - lightSpaceBasis._34 = 0.f; - lightSpaceBasis._41 = 0.f; - lightSpaceBasis._42 = 0.f; - lightSpaceBasis._43 = 0.f; - lightSpaceBasis._44 = 1.f; - - // rotate the view frustum into light space - D3DXVec3TransformCoordArray(frustumPnts, sizeof(D3DXVECTOR3), frustumPnts, sizeof(D3DXVECTOR3), - &lightSpaceBasis, sizeof(frustumPnts) / sizeof(D3DXVECTOR3)); - - // build an off-center ortho projection that translates and scales the eye frustum's 3D AABB to the unit cube - BoundingBox frustumBox(frustumPnts, sizeof(frustumPnts) / sizeof(D3DXVECTOR3)); - - // also - transform the shadow caster bounding boxes into light projective space. we want to translate along the Z axis so that - // all shadow casters are in front of the near plane. - D3DXVECTOR2 depthbounds = BuildTSMProjectionMatrix_caster_depth_bounds(lightSpaceBasis); - - float min_z = min(depthbounds.x, frustumBox.minPt.z); - float max_z = max(depthbounds.y, frustumBox.maxPt.z); - - if (min_z <= 1.f) //? - { - D3DXMATRIX lightSpaceTranslate; - D3DXMatrixTranslation(&lightSpaceTranslate, 0.f, 0.f, -min_z + 1.f); - max_z = -min_z + max_z + 1.f; - min_z = 1.f; - D3DXMatrixMultiply(&lightSpaceBasis, &lightSpaceBasis, &lightSpaceTranslate); - D3DXVec3TransformCoordArray(frustumPnts, sizeof(D3DXVECTOR3), frustumPnts, sizeof(D3DXVECTOR3), - &lightSpaceTranslate, sizeof(frustumPnts) / sizeof(D3DXVECTOR3)); - frustumBox = BoundingBox(frustumPnts, sizeof(frustumPnts) / sizeof(D3DXVECTOR3)); - } - - D3DXMATRIX lightSpaceOrtho; - D3DXMatrixOrthoOffCenterLH(&lightSpaceOrtho, frustumBox.minPt.x, frustumBox.maxPt.x, frustumBox.minPt.y, - frustumBox.maxPt.y, min_z, max_z); - - // transform the view frustum by the new matrix - D3DXVec3TransformCoordArray(frustumPnts, sizeof(D3DXVECTOR3), frustumPnts, sizeof(D3DXVECTOR3), - &lightSpaceOrtho, sizeof(frustumPnts) / sizeof(D3DXVECTOR3)); - - D3DXVECTOR2 centerPts [2]; - // near plane - centerPts[0].x = 0.25f * (frustumPnts[4].x + frustumPnts[5].x + frustumPnts[6].x + frustumPnts[7].x); - centerPts[0].y = 0.25f * (frustumPnts[4].y + frustumPnts[5].y + frustumPnts[6].y + frustumPnts[7].y); - // far plane - centerPts[1].x = 0.25f * (frustumPnts[0].x + frustumPnts[1].x + frustumPnts[2].x + frustumPnts[3].x); - centerPts[1].y = 0.25f * (frustumPnts[0].y + frustumPnts[1].y + frustumPnts[2].y + frustumPnts[3].y); - - D3DXVECTOR2 centerOrig = (centerPts[0] + centerPts[1]) * 0.5f; - - D3DXMATRIX trapezoid_space; - - D3DXMATRIX xlate_center(1.f, 0.f, 0.f, 0.f, - 0.f, 1.f, 0.f, 0.f, - 0.f, 0.f, 1.f, 0.f, - -centerOrig.x, -centerOrig.y, 0.f, 1.f); - - D3DXVECTOR2 center_dirl = D3DXVECTOR2(centerPts[1] - centerOrig); - float half_center_len = D3DXVec2Length(¢er_dirl); - float x_len = centerPts[1].x - centerOrig.x; - float y_len = centerPts[1].y - centerOrig.y; - - float cos_theta = x_len / half_center_len; - float sin_theta = y_len / half_center_len; - - D3DXMATRIX rot_center(cos_theta, -sin_theta, 0.f, 0.f, - sin_theta, cos_theta, 0.f, 0.f, - 0.f, 0.f, 1.f, 0.f, - 0.f, 0.f, 0.f, 1.f); - - // this matrix transforms the center line to y=0. - // since Top and Base are orthogonal to Center, we can skip computing the convex hull, and instead - // just find the view frustum X-axis extrema. The most negative is Top, the most positive is Base - // Point Q (trapezoid projection point) will be a point on the y=0 line. - D3DXMatrixMultiply(&trapezoid_space, &xlate_center, &rot_center); - D3DXVec3TransformCoordArray(frustumPnts, sizeof(D3DXVECTOR3), frustumPnts, sizeof(D3DXVECTOR3), - &trapezoid_space, sizeof(frustumPnts) / sizeof(D3DXVECTOR3)); - - BoundingBox frustumAABB2D(frustumPnts, sizeof(frustumPnts) / sizeof(D3DXVECTOR3)); - - float x_scale = max(_abs(frustumAABB2D.maxPt.x), _abs(frustumAABB2D.minPt.x)); - float y_scale = max(_abs(frustumAABB2D.maxPt.y), _abs(frustumAABB2D.minPt.y)); - x_scale = 1.f / x_scale; - y_scale = 1.f / y_scale; - - // maximize the area occupied by the bounding box - D3DXMATRIX scale_center(x_scale, 0.f, 0.f, 0.f, - 0.f, y_scale, 0.f, 0.f, - 0.f, 0.f, 1.f, 0.f, - 0.f, 0.f, 0.f, 1.f); - - D3DXMatrixMultiply(&trapezoid_space, &trapezoid_space, &scale_center); - - // scale the frustum AABB up by these amounts (keep all values in the same space) - frustumAABB2D.minPt.x *= x_scale; - frustumAABB2D.maxPt.x *= x_scale; - frustumAABB2D.minPt.y *= y_scale; - frustumAABB2D.maxPt.y *= y_scale; - - // compute eta. - float lambda = frustumAABB2D.maxPt.x - frustumAABB2D.minPt.x; - float delta_proj = m_fTSM_Delta * lambda; //focusPt.x - frustumAABB2D.minPt.x; - const float xi = -0.6f; // - 0.6f; // 80% line - float eta = (lambda * delta_proj * (1.f + xi)) / (lambda * (1.f - xi) - 2.f * delta_proj); - - // compute the projection point a distance eta from the top line. this point is on the center line, y=0 - D3DXVECTOR2 projectionPtQ(frustumAABB2D.maxPt.x + eta, 0.f); - - // find the maximum slope from the projection point to any point in the frustum. this will be the - // projection field-of-view - float max_slope = -1e32f; - float min_slope = 1e32f; - - for (int i = 0; i < sizeof(frustumPnts) / sizeof(D3DXVECTOR3); i++) - { - D3DXVECTOR2 tmp(frustumPnts[i].x * x_scale, frustumPnts[i].y * y_scale); - float x_dist = tmp.x - projectionPtQ.x; - if (!(ALMOST_ZERO(tmp.y) || ALMOST_ZERO(x_dist))) - { - max_slope = max(max_slope, tmp.y / x_dist); - min_slope = min(min_slope, tmp.y / x_dist); - } - } - - float xn = eta; - float xf = lambda + eta; - - D3DXMATRIX ptQ_xlate(-1.f, 0.f, 0.f, 0.f, - 0.f, 1.f, 0.f, 0.f, - 0.f, 0.f, 1.f, 0.f, - projectionPtQ.x, 0.f, 0.f, 1.f); - D3DXMatrixMultiply(&trapezoid_space, &trapezoid_space, &ptQ_xlate); - - // this shear balances the "trapezoid" around the y=0 axis (no change to the projection pt position) - // since we are redistributing the trapezoid, this affects the projection field of view (shear_amt) - float shear_amt = (max_slope + _abs(min_slope)) * 0.5f - max_slope; - max_slope = max_slope + shear_amt; - - D3DXMATRIX trapezoid_shear(1.f, shear_amt, 0.f, 0.f, - 0.f, 1.f, 0.f, 0.f, - 0.f, 0.f, 1.f, 0.f, - 0.f, 0.f, 0.f, 1.f); - - D3DXMatrixMultiply(&trapezoid_space, &trapezoid_space, &trapezoid_shear); - - - float z_aspect = (frustumBox.maxPt.z - frustumBox.minPt.z) / (frustumAABB2D.maxPt.y - frustumAABB2D.minPt.y); - - // perform a 2DH projection to 'unsqueeze' the top line. - D3DXMATRIX trapezoid_projection(xf / (xf - xn), 0.f, 0.f, 1.f, - 0.f, 1.f / max_slope, 0.f, 0.f, - 0.f, 0.f, 1.f / (z_aspect * max_slope), 0.f, - -xn * xf / (xf - xn), 0.f, 0.f, 0.f); - - D3DXMatrixMultiply(&trapezoid_space, &trapezoid_space, &trapezoid_projection); - - // the x axis is compressed to [0..1] as a result of the projection, so expand it to [-1,1] - D3DXMATRIX biasedScaleX(2.f, 0.f, 0.f, 0.f, - 0.f, 1.f, 0.f, 0.f, - 0.f, 0.f, 1.f, 0.f, - -1.f, 0.f, 0.f, 1.f); - D3DXMatrixMultiply(&trapezoid_space, &trapezoid_space, &biasedScaleX); - - D3DXMatrixMultiply(&m_LightViewProj, &m_View, &lightSpaceBasis); - D3DXMatrixMultiply(&m_LightViewProj, &m_LightViewProj, &lightSpaceOrtho); - D3DXMatrixMultiply(&m_LightViewProj, &m_LightViewProj, &trapezoid_space); - } - else - { - m_LightViewProj = *((D3DXMATRIX*)(&cull_xform)); - } - FPU::m24r(); - - // perform "refit" or "focusing" on relevant - if (ps_r2_ls_flags.test(R2FLAG_SUN_FOCUS)) - { - FPU::m64r(); - - // create clipper - DumbClipper view_clipper; - Fmatrix& xform = *((Fmatrix*)&m_LightViewProj); - view_clipper.frustum.CreateFromMatrix(ex_full,FRUSTUM_P_ALL); - for (int p = 0; p < view_clipper.frustum.p_count; p++) - { - Fplane& P = view_clipper.frustum.planes[p]; - view_clipper.planes.push_back(D3DXPLANE(P.n.x, P.n.y, P.n.z, P.d)); - } - - // - Fbox3 b_casters, b_receivers; - Fvector3 pt; - - // casters - b_casters.invalidate(); - for (u32 c = 0; c < s_casters.size(); c++) - { - for (int e = 0; e < 8; e++) - { - s_casters[c].getpoint(e, pt); - pt = wform(xform, pt); - b_casters.modify(pt); - } - } - - // receivers - b_receivers.invalidate(); - b_receivers = view_clipper.clipped_AABB(s_receivers, xform); - Fmatrix x_project, x_full, x_full_inverse; - { - x_project.build_projection(deg2rad(Device.fFOV/* *Device.fASPECT*/), Device.fASPECT, ps_r2_sun_near, - ps_r2_sun_near + tweak_guaranteed_range); - x_project.build_projection(deg2rad(Device.fFOV/* *Device.fASPECT*/), Device.fASPECT,VIEWPORT_NEAR, - ps_r2_sun_near + tweak_guaranteed_range); - x_full.mul(x_project, Device.mView); - D3DXMatrixInverse((D3DXMATRIX*)&x_full_inverse, 0, (D3DXMATRIX*)&x_full); - } - for (int e = 0; e < 8; e++) - { - pt = wform(x_full_inverse, corners[e]); // world space - pt = wform(xform, pt); // trapezoid space - b_receivers.modify(pt); - } - - // some tweaking - b_casters.grow(EPS); - b_receivers.grow(EPS); - - // because caster points are from coarse representation only allow to "shrink" box, not grow - // that is the same as if we first clip casters by frustum - if (b_receivers.min.x < -1) b_receivers.min.x = -1; - if (b_receivers.min.y < -1) b_receivers.min.y = -1; - if (b_casters.min.z < 0) b_casters.min.z = 0; - if (b_receivers.max.x > +1) b_receivers.max.x = +1; - if (b_receivers.max.y > +1) b_receivers.max.y = +1; - if (b_casters.max.z > +1) b_casters.max.z = +1; - - // refit? - /* - const float EPS = 0.001f; - D3DXMATRIX refit; - D3DXMatrixOrthoOffCenterLH ( &refit, b_receivers.min.x, b_receivers.max.x, b_receivers.min.y, b_receivers.max.y, b_casters.min.z-EPS, b_casters.max.z+EPS ); - D3DXMatrixMultiply ( &m_LightViewProj, &m_LightViewProj, &refit); - */ - - float boxWidth = b_receivers.max.x - b_receivers.min.x; - float boxHeight = b_receivers.max.y - b_receivers.min.y; - // the divide by two's cancel out in the translation, but included for clarity - float boxX = (b_receivers.max.x + b_receivers.min.x) / 2.f; - float boxY = (b_receivers.max.y + b_receivers.min.y) / 2.f; - D3DXMATRIX trapezoidUnitCube(2.f / boxWidth, 0.f, 0.f, 0.f, - 0.f, 2.f / boxHeight, 0.f, 0.f, - 0.f, 0.f, 1.f, 0.f, - -2.f * boxX / boxWidth, -2.f * boxY / boxHeight, 0.f, 1.f); - D3DXMatrixMultiply(&m_LightViewProj, &m_LightViewProj, &trapezoidUnitCube); - //D3DXMatrixMultiply( &trapezoid_space, &trapezoid_space, &trapezoidUnitCube ); - FPU::m24r(); - } - - // Finalize & Cleanup - fuckingsun->X.D.combine = *((Fmatrix*)&m_LightViewProj); - s_receivers.clear(); - s_casters.clear(); - - // Render shadow-map - //. !!! We should clip based on shrinked frustum (again) - { - bool bNormal = mapNormalPasses[0][0].size() || mapMatrixPasses[0][0].size(); - bool bSpecial = mapNormalPasses[1][0].size() || mapMatrixPasses[1][0].size() || mapSorted.size(); - if (bNormal || bSpecial) - { - Target->phase_smap_direct(fuckingsun, SE_SUN_FAR); - RCache.set_xform_world(Fidentity); - RCache.set_xform_view(Fidentity); - RCache.set_xform_project(fuckingsun->X.D.combine); - r_dsgraph_render_graph(0); - fuckingsun->X.D.transluent = FALSE; - if (bSpecial) - { - fuckingsun->X.D.transluent = TRUE; - Target->phase_smap_direct_tsh(fuckingsun, SE_SUN_FAR); - r_dsgraph_render_graph(1); // normal level, secondary priority - r_dsgraph_render_sorted(); // strict-sorted geoms - } - } - } - - // End SMAP-render - { - // fuckingsun->svis.end (); - r_pmask(true, false); - } - - // Accumulate - Target->phase_accumulator(); - Target->accum_direct(SE_SUN_FAR); - - // Restore XForms - RCache.set_xform_world(Fidentity); - RCache.set_xform_view(Device.mView); - RCache.set_xform_project(Device.mProject); -} - -void CRender::render_sun_near() -{ - light* fuckingsun = (light*)Lights.sun_adapted._get(); - D3DXMATRIX m_LightViewProj; - - // calculate view-frustum bounds in world space - Fmatrix ex_project, ex_full, ex_full_inverse; - { - ex_project.build_projection(deg2rad(Device.fFOV/* *Device.fASPECT*/), Device.fASPECT,VIEWPORT_NEAR, - ps_r2_sun_near); - ex_full.mul(ex_project, Device.mView); - D3DXMatrixInverse((D3DXMATRIX*)&ex_full_inverse, 0, (D3DXMATRIX*)&ex_full); - } - - // Compute volume(s) - something like a frustum for infinite directional light - // Also compute virtual light position and sector it is inside - CFrustum cull_frustum; - xr_vector cull_planes; - Fvector3 cull_COP; - CSector* cull_sector; - Fmatrix cull_xform; - { - FPU::m64r(); - // Lets begin from base frustum - Fmatrix fullxform_inv = ex_full_inverse; -#ifdef _DEBUG - typedef DumbConvexVolume t_volume; -#else - typedef DumbConvexVolume t_volume; -#endif - t_volume hull; - { - hull.points.reserve(9); - for (int p = 0; p < 8; p++) - { - Fvector3 xf = wform(fullxform_inv, corners[p]); - hull.points.push_back(xf); - } - for (int plane = 0; plane < 6; plane++) - { - hull.polys.push_back(t_volume::_poly()); - for (int pt = 0; pt < 4; pt++) - hull.polys.back().points.push_back(facetable[plane][pt]); - } - } - hull.compute_caster_model(cull_planes, fuckingsun->direction); -#ifdef _DEBUG - for (u32 it=0; itdbg_addplane(cull_planes[it],0xffffffff); -#endif - - // Search for default sector - assume "default" or "outdoor" sector is the largest one - //. hack: need to know real outdoor sector - CSector* largest_sector = 0; - float largest_sector_vol = 0; - for (u32 s = 0; s < Sectors.size(); s++) - { - CSector* S = (CSector*)Sectors[s]; - dxRender_Visual* V = S->root(); - float vol = V->vis.box.getvolume(); - if (vol > largest_sector_vol) - { - largest_sector_vol = vol; - largest_sector = S; - } - } - cull_sector = largest_sector; - - // COP - 100 km away - cull_COP.mad(Device.vCameraPosition, fuckingsun->direction, -tweak_COP_initial_offs); - - // Create frustum for query - cull_frustum._clear(); - for (u32 p = 0; p < cull_planes.size(); p++) - cull_frustum._add(cull_planes[p]); - - // Create approximate ortho-xform - // view: auto find 'up' and 'right' vectors - Fmatrix mdir_View, mdir_Project; - Fvector L_dir, L_up, L_right, L_pos; - L_pos.set(fuckingsun->position); - L_dir.set(fuckingsun->direction).normalize(); - L_right.set(1, 0, 0); - if (_abs(L_right.dotproduct(L_dir)) > .99f) L_right.set(0, 0, 1); - L_up.crossproduct(L_dir, L_right).normalize(); - L_right.crossproduct(L_up, L_dir).normalize(); - mdir_View.build_camera_dir(L_pos, L_dir, L_up); - - // projection: box - /* - // Original - float _D = ps_r2_sun_near; - float a0 = deg2rad(Device.fFOV*Device.fASPECT)/2.f; - float a1 = deg2rad(Device.fFOV)/2.f; - float c0 = _D/_cos(a0); - float c1 = _D/_cos(a1); - float k0 = 2.f*c0*_sin(a0); - float k1 = 2.f*c1*_sin(a1); - float borderalpha = (Device.fFOV-10) / (90-10); - - float nearborder = 1*borderalpha + 1.136363636364f*(1-borderalpha); - float spherical_range = ps_r2_sun_near_border * nearborder * _max(_max(c0,c1), _max(k0,k1)*1.414213562373f ); - Fbox frustum_bb; frustum_bb.invalidate (); - hull.points.push_back (Device.vCameraPosition); - for (int it=0; it<9; it++) { - Fvector xf = wform (mdir_View,hull.points[it]); - frustum_bb.modify (xf); - } - float size_x = frustum_bb.max.x - frustum_bb.min.x; - float size_y = frustum_bb.max.y - frustum_bb.min.y; - float diff_x = (spherical_range - size_x)/2.f; //VERIFY(diff_x>=0); - float diff_y = (spherical_range - size_y)/2.f; //VERIFY(diff_y>=0); - frustum_bb.min.x -= diff_x; frustum_bb.max.x += diff_x; - frustum_bb.min.y -= diff_y; frustum_bb.max.y += diff_y; - Fbox& bb = frustum_bb; - D3DXMatrixOrthoOffCenterLH ((D3DXMATRIX*)&mdir_Project,bb.min.x,bb.max.x, bb.min.y,bb.max.y, bb.min.z-tweak_ortho_xform_initial_offs,bb.max.z); - /**/ - - // Simple - Fbox frustum_bb; - frustum_bb.invalidate(); - for (int it = 0; it < 8; it++) - { - //for (int it=0; it<9; it++) { - Fvector xf = wform(mdir_View, hull.points[it]); - frustum_bb.modify(xf); - } - Fbox& bb = frustum_bb; - bb.grow(EPS); - D3DXMatrixOrthoOffCenterLH((D3DXMATRIX*)&mdir_Project, bb.min.x, bb.max.x, bb.min.y, bb.max.y, - bb.min.z - tweak_ortho_xform_initial_offs, bb.max.z); - /**/ - - // build viewport xform - float view_dim = float(RImplementation.o.smapsize); - Fmatrix m_viewport = { - view_dim / 2.f, 0.0f, 0.0f, 0.0f, - 0.0f, -view_dim / 2.f, 0.0f, 0.0f, - 0.0f, 0.0f, 1.0f, 0.0f, - view_dim / 2.f, view_dim / 2.f, 0.0f, 1.0f - }; - Fmatrix m_viewport_inv; - D3DXMatrixInverse((D3DXMATRIX*)&m_viewport_inv, 0, (D3DXMATRIX*)&m_viewport); - - // snap view-position to pixel - cull_xform.mul(mdir_Project, mdir_View); - Fvector cam_proj = wform(cull_xform, Device.vCameraPosition); - Fvector cam_pixel = wform(m_viewport, cam_proj); - cam_pixel.x = floorf(cam_pixel.x); - cam_pixel.y = floorf(cam_pixel.y); - Fvector cam_snapped = wform(m_viewport_inv, cam_pixel); - Fvector diff; - diff.sub(cam_snapped, cam_proj); - Fmatrix adjust; - adjust.translate(diff); - cull_xform.mulA_44(adjust); - - // calculate scissor - Fbox scissor; - scissor.invalidate(); - Fmatrix scissor_xf; - scissor_xf.mul(m_viewport, cull_xform); - for (int it = 0; it < 9; it++) - { - Fvector xf = wform(scissor_xf, hull.points[it]); - scissor.modify(xf); - } - s32 limit = RImplementation.o.smapsize - 1; - fuckingsun->X.D.minX = clampr(iFloor(scissor.min.x), 0, limit); - fuckingsun->X.D.maxX = clampr(iCeil(scissor.max.x), 0, limit); - fuckingsun->X.D.minY = clampr(iFloor(scissor.min.y), 0, limit); - fuckingsun->X.D.maxY = clampr(iCeil(scissor.max.y), 0, limit); - - // full-xform - FPU::m24r(); - } - - // Begin SMAP-render - { - bool bSpecialFull = mapNormalPasses[1][0].size() || mapMatrixPasses[1][0].size() || mapSorted.size(); - VERIFY(!bSpecialFull); - HOM.Disable(); - phase = PHASE_SMAP; - if (RImplementation.o.Tshadows) r_pmask(true, true); - else r_pmask(true, false); - // fuckingsun->svis.begin (); - } - - // Fill the database - r_dsgraph_render_subspace(cull_sector, &cull_frustum, cull_xform, cull_COP, TRUE); - - // Finalize & Cleanup - fuckingsun->X.D.combine = cull_xform; //*((Fmatrix*)&m_LightViewProj); - - // Render shadow-map - //. !!! We should clip based on shrinked frustum (again) - { - bool bNormal = mapNormalPasses[0][0].size() || mapMatrixPasses[0][0].size(); - bool bSpecial = mapNormalPasses[1][0].size() || mapMatrixPasses[1][0].size() || mapSorted.size(); - if (bNormal || bSpecial) - { - Target->phase_smap_direct(fuckingsun, SE_SUN_NEAR); - RCache.set_xform_world(Fidentity); - RCache.set_xform_view(Fidentity); - RCache.set_xform_project(fuckingsun->X.D.combine); - r_dsgraph_render_graph(0); - if (ps_r2_ls_flags.test(R2FLAG_SUN_DETAILS)) - Details->Render(); - fuckingsun->X.D.transluent = FALSE; - if (bSpecial) - { - fuckingsun->X.D.transluent = TRUE; - Target->phase_smap_direct_tsh(fuckingsun, SE_SUN_NEAR); - r_dsgraph_render_graph(1); // normal level, secondary priority - r_dsgraph_render_sorted(); // strict-sorted geoms - } - } - } - - // End SMAP-render - { - // fuckingsun->svis.end (); - r_pmask(true, false); - } - - // Accumulate - Target->phase_accumulator(); - Target->accum_direct(SE_SUN_NEAR); - - // Restore XForms - RCache.set_xform_world(Fidentity); - RCache.set_xform_view(Device.mView); - RCache.set_xform_project(Device.mProject); -} - -void CRender::render_sun_filtered() -{ - if (!RImplementation.o.sunfilter) return; - Target->phase_accumulator(); - Target->accum_direct(SE_SUN_LUMINANCE); -} - -void CRender::init_cacades() -{ - u32 cascade_count = 3; - m_sun_cascades.resize(cascade_count); - - float fBias = -0.0000025f; - // float size = MAP_SIZE_START; - m_sun_cascades[0].reset_chain = true; - m_sun_cascades[0].size = 20; - m_sun_cascades[0].bias = m_sun_cascades[0].size * fBias; - - m_sun_cascades[1].size = 40; - m_sun_cascades[1].bias = m_sun_cascades[1].size * fBias; - - m_sun_cascades[2].size = 160; - m_sun_cascades[2].bias = m_sun_cascades[2].size * fBias; - - // for( u32 i = 0; i < cascade_count; ++i ) - // { - // m_sun_cascades[i].size = size; - // size *= MAP_GROW_FACTOR; - // } - /// m_sun_cascades[m_sun_cascades.size()-1].size = 80; -} - -void CRender::render_sun_cascades() -{ - bool b_need_to_render_sunshafts = RImplementation.Target->need_to_render_sunshafts(); - bool last_cascade_chain_mode = m_sun_cascades.back().reset_chain; - if (b_need_to_render_sunshafts) - m_sun_cascades[m_sun_cascades.size() - 1].reset_chain = true; - - for (u32 i = 0; i < m_sun_cascades.size(); ++i) - render_sun_cascade(i); - - if (b_need_to_render_sunshafts) - m_sun_cascades[m_sun_cascades.size() - 1].reset_chain = last_cascade_chain_mode; -} - -void CRender::render_sun_cascade(u32 cascade_ind) -{ - light* fuckingsun = (light*)Lights.sun_adapted._get(); - - // calculate view-frustum bounds in world space - Fmatrix ex_project, ex_full, ex_full_inverse; - { - ex_project = Device.mProject; - ex_full.mul(ex_project, Device.mView); - D3DXMatrixInverse((D3DXMATRIX*)&ex_full_inverse, 0, (D3DXMATRIX*)&ex_full); - } - - // Compute volume(s) - something like a frustum for infinite directional light - // Also compute virtual light position and sector it is inside - CFrustum cull_frustum; - xr_vector cull_planes; - Fvector3 cull_COP; - CSector* cull_sector; - Fmatrix cull_xform; - { - FPU::m64r(); - // Lets begin from base frustum - Fmatrix fullxform_inv = ex_full_inverse; -#ifdef _DEBUG - typedef DumbConvexVolume t_volume; -#else - typedef DumbConvexVolume t_volume; -#endif - - //******************************* Need to be placed after cuboid built ************************** - // Search for default sector - assume "default" or "outdoor" sector is the largest one - //. hack: need to know real outdoor sector - CSector* largest_sector = 0; - float largest_sector_vol = 0; - for (u32 s = 0; s < Sectors.size(); s++) - { - CSector* S = (CSector*)Sectors[s]; - dxRender_Visual* V = S->root(); - float vol = V->vis.box.getvolume(); - if (vol > largest_sector_vol) - { - largest_sector_vol = vol; - largest_sector = S; - } - } - cull_sector = largest_sector; - - // COP - 100 km away - cull_COP.mad(Device.vCameraPosition, fuckingsun->direction, -tweak_COP_initial_offs); - - // Create approximate ortho-xform - // view: auto find 'up' and 'right' vectors - Fmatrix mdir_View, mdir_Project; - Fvector L_dir, L_up, L_right, L_pos; - L_pos.set(fuckingsun->position); - L_dir.set(fuckingsun->direction).normalize(); - L_right.set(1, 0, 0); - if (_abs(L_right.dotproduct(L_dir)) > .99f) L_right.set(0, 0, 1); - L_up.crossproduct(L_dir, L_right).normalize(); - L_right.crossproduct(L_up, L_dir).normalize(); - mdir_View.build_camera_dir(L_pos, L_dir, L_up); - - - ////////////////////////////////////////////////////////////////////////// -#ifdef _DEBUG - typedef FixedConvexVolume t_cuboid; -#else - typedef FixedConvexVolume t_cuboid; -#endif - - t_cuboid light_cuboid; - { - // Initialize the first cascade rays, then each cascade will initialize rays for next one. - if (cascade_ind == 0 || m_sun_cascades[cascade_ind].reset_chain) - { - Fvector3 near_p, edge_vec; - for (int p = 0; p < 4; p++) - { - near_p = wform(fullxform_inv, corners[facetable[4][p]]); - edge_vec = wform(fullxform_inv, corners[facetable[5][p]]); - edge_vec.sub(near_p); - edge_vec.normalize(); - - light_cuboid.view_frustum_rays.push_back(sun::ray(near_p, edge_vec)); - } - } - else - light_cuboid.view_frustum_rays = m_sun_cascades[cascade_ind].rays; - - light_cuboid.view_ray.P = Device.vCameraPosition; - light_cuboid.view_ray.D = Device.vCameraDirection; - light_cuboid.light_ray.P = L_pos; - light_cuboid.light_ray.D = L_dir; - } - - // THIS NEED TO BE A CONSTATNT - Fplane light_top_plane; - light_top_plane.build_unit_normal(L_pos, L_dir); - float dist = light_top_plane.classify(Device.vCameraPosition); - - float map_size = m_sun_cascades[cascade_ind].size; - D3DXMatrixOrthoOffCenterLH((D3DXMATRIX*)&mdir_Project, -map_size * 0.5f, map_size * 0.5f, -map_size * 0.5f, - map_size * 0.5f, 0.1, dist + map_size); - - // build viewport xform - float view_dim = float(RImplementation.o.smapsize); - Fmatrix m_viewport = { - view_dim / 2.f, 0.0f, 0.0f, 0.0f, - 0.0f, -view_dim / 2.f, 0.0f, 0.0f, - 0.0f, 0.0f, 1.0f, 0.0f, - view_dim / 2.f, view_dim / 2.f, 0.0f, 1.0f - }; - Fmatrix m_viewport_inv; - D3DXMatrixInverse((D3DXMATRIX*)&m_viewport_inv, 0, (D3DXMATRIX*)&m_viewport); - - cull_xform.mul(mdir_Project, mdir_View); - Fmatrix cull_xform_inv; - cull_xform_inv.invert(cull_xform); - - - // light_cuboid.light_cuboid_points.reserve (9); - for (int p = 0; p < 8; p++) - { - Fvector3 xf = wform(cull_xform_inv, corners[p]); - light_cuboid.light_cuboid_points[p] = xf; - } - - // only side planes - for (int plane = 0; plane < 4; plane++) - for (int pt = 0; pt < 4; pt++) - { - int asd = facetable[plane][pt]; - light_cuboid.light_cuboid_polys[plane].points[pt] = asd; - } - - - Fvector lightXZshift; - light_cuboid.compute_caster_model_fixed(cull_planes, lightXZshift, m_sun_cascades[cascade_ind].size, - m_sun_cascades[cascade_ind].reset_chain); - Fvector proj_view = Device.vCameraDirection; - proj_view.y = 0; - proj_view.normalize(); - // lightXZshift.mad(proj_view, 20); - - // Initialize rays for the next cascade - if (cascade_ind < m_sun_cascades.size() - 1) - m_sun_cascades[cascade_ind + 1].rays = light_cuboid.view_frustum_rays; - -#ifdef _DEBUG - - static bool draw_debug = false; - if( draw_debug && cascade_ind == 0 ) - for (u32 it=0; itdbg_addplane(cull_planes[it],it*0xFFF); -#endif - - Fvector cam_shifted = L_pos; - cam_shifted.add(lightXZshift); - - // rebuild the view transform with the shift. - mdir_View.identity(); - mdir_View.build_camera_dir(cam_shifted, L_dir, L_up); - cull_xform.identity(); - cull_xform.mul(mdir_Project, mdir_View); - cull_xform_inv.invert(cull_xform); - - - // Create frustum for query - cull_frustum._clear(); - for (u32 p = 0; p < cull_planes.size(); p++) - cull_frustum._add(cull_planes[p]); - - { - Fvector cam_proj = Device.vCameraPosition; - const float align_aim_step_coef = 4.f; - cam_proj.set(floorf(cam_proj.x / align_aim_step_coef) + align_aim_step_coef / 2, - floorf(cam_proj.y / align_aim_step_coef) + align_aim_step_coef / 2, - floorf(cam_proj.z / align_aim_step_coef) + align_aim_step_coef / 2); - cam_proj.mul(align_aim_step_coef); - Fvector cam_pixel = wform(cull_xform, cam_proj); - cam_pixel = wform(m_viewport, cam_pixel); - Fvector shift_proj = lightXZshift; - cull_xform.transform_dir(shift_proj); - m_viewport.transform_dir(shift_proj); - - const float align_granularity = 4.f; - shift_proj.x = shift_proj.x > 0 ? align_granularity : -align_granularity; - shift_proj.y = shift_proj.y > 0 ? align_granularity : -align_granularity; - shift_proj.z = 0; - - cam_pixel.x = cam_pixel.x / align_granularity - floorf(cam_pixel.x / align_granularity); - cam_pixel.y = cam_pixel.y / align_granularity - floorf(cam_pixel.y / align_granularity); - cam_pixel.x *= align_granularity; - cam_pixel.y *= align_granularity; - cam_pixel.z = 0; - - cam_pixel.sub(shift_proj); - - m_viewport_inv.transform_dir(cam_pixel); - cull_xform_inv.transform_dir(cam_pixel); - Fvector diff = cam_pixel; - static float sign_test = -1.f; - diff.mul(sign_test); - Fmatrix adjust; - adjust.translate(diff); - cull_xform.mulB_44(adjust); - } - - m_sun_cascades[cascade_ind].xform = cull_xform; - - s32 limit = RImplementation.o.smapsize - 1; - fuckingsun->X.D.minX = 0; - fuckingsun->X.D.maxX = limit; - fuckingsun->X.D.minY = 0; - fuckingsun->X.D.maxY = limit; - - // full-xform - FPU::m24r(); - } - - // Begin SMAP-render - { - bool bSpecialFull = mapNormalPasses[1][0].size() || mapMatrixPasses[1][0].size() || mapSorted.size(); - VERIFY(!bSpecialFull); - HOM.Disable(); - phase = PHASE_SMAP; - if (RImplementation.o.Tshadows) r_pmask(true, true); - else r_pmask(true, false); - // fuckingsun->svis.begin (); - } - - // Fill the database - r_dsgraph_render_subspace(cull_sector, &cull_frustum, cull_xform, cull_COP, TRUE); - - // Finalize & Cleanup - fuckingsun->X.D.combine = cull_xform; - - // Render shadow-map - //. !!! We should clip based on shrinked frustum (again) - { - bool bNormal = mapNormalPasses[0][0].size() || mapMatrixPasses[0][0].size(); - bool bSpecial = mapNormalPasses[1][0].size() || mapMatrixPasses[1][0].size() || mapSorted.size(); - if (bNormal || bSpecial) - { - Target->phase_smap_direct(fuckingsun, SE_SUN_FAR); - RCache.set_xform_world(Fidentity); - RCache.set_xform_view(Fidentity); - RCache.set_xform_project(fuckingsun->X.D.combine); - r_dsgraph_render_graph(0); - if (ps_r2_ls_flags.test(R2FLAG_SUN_DETAILS)) - Details->Render(); - fuckingsun->X.D.transluent = FALSE; - if (bSpecial) - { - fuckingsun->X.D.transluent = TRUE; - Target->phase_smap_direct_tsh(fuckingsun, SE_SUN_FAR); - r_dsgraph_render_graph(1); // normal level, secondary priority - r_dsgraph_render_sorted(); // strict-sorted geoms - } - } - } - - // End SMAP-render - { - // fuckingsun->svis.end (); - r_pmask(true, false); - } - - // Accumulate - Target->phase_accumulator(); - - if (cascade_ind == 0) - Target->accum_direct_cascade(SE_SUN_NEAR, m_sun_cascades[cascade_ind].xform, m_sun_cascades[cascade_ind].xform, - m_sun_cascades[cascade_ind].bias); - else if (cascade_ind < m_sun_cascades.size() - 1) - Target->accum_direct_cascade(SE_SUN_MIDDLE, m_sun_cascades[cascade_ind].xform, - m_sun_cascades[cascade_ind - 1].xform, m_sun_cascades[cascade_ind].bias); - else - Target->accum_direct_cascade(SE_SUN_FAR, m_sun_cascades[cascade_ind].xform, - m_sun_cascades[cascade_ind - 1].xform, m_sun_cascades[cascade_ind].bias); - - - // Restore XForms - RCache.set_xform_world(Fidentity); - RCache.set_xform_view(Device.mView); - RCache.set_xform_project(Device.mProject); -} diff --git a/src/Layers/xrRenderPC_R2/r2_loader.cpp b/src/Layers/xrRenderPC_R2/r2_loader.cpp index a1c8be8cc3..19bd7e7787 100644 --- a/src/Layers/xrRenderPC_R2/r2_loader.cpp +++ b/src/Layers/xrRenderPC_R2/r2_loader.cpp @@ -101,11 +101,6 @@ void CRender::level_Load(IReader* fs) // End pApp->LoadEnd(); - // sanity-clear - lstLODs.clear(); - lstLODgroups.clear(); - mapLOD.clear(); - // signal loaded b_loaded = TRUE; } @@ -115,6 +110,10 @@ void CRender::level_Unload() if (0 == g_pGameLevel) return; if (!b_loaded) return; + GMBase.clear(); + for (sun::cascade& cascade : m_sun_cascades) + cascade.GMCascade.clear(); + u32 I; // HOM @@ -127,7 +126,8 @@ void CRender::level_Unload() // 1. xr_delete(rmPortals); pLastSector = 0; - vLastCameraPos.set(0, 0, 0); + pOutdoorSector = 0; + vLastCameraPos.set(0,0,0); // 2. for (I = 0; I < Sectors.size(); I++) xr_delete(Sectors[I]); Sectors.clear(); @@ -190,10 +190,17 @@ void CRender::level_Unload() //*** Shaders Shaders.clear_and_free(); - if (psDeviceFlags2.test(rsClearModels)) + const bool clearResources = psDeviceFlags2.test(rsClearAllResources); + if (psDeviceFlags2.test(rsClearModels) || clearResources) { Models->ClearPool(true); Visuals.clear_and_free(); + if (clearResources) + { + dxRenderDeviceRender::Instance().Resources->UnloadAllTexturesOnLevelUnload(); + dxRenderDeviceRender::Instance().ResourcesDestroyNecessaryTextures(); + dxRenderDeviceRender::Instance().Resources->Evict(); + } dxRenderDeviceRender::Instance().Resources->Dump(false); //static int unload_counter = 0; //Msg("The Level Unloaded.======================== %d", ++unload_counter); @@ -377,6 +384,23 @@ void CRender::LoadSectors(IReader* fs) // Sectors[d]->DebugDump (); pLastSector = 0; + + // Search for default sector - assume "default" or "outdoor" sector is the largest one + //. hack: need to know real outdoor sector + CSector* largest_sector = 0; + float largest_sector_vol = 0; + for (u32 s = 0; s < Sectors.size(); s++) + { + CSector* S = (CSector*)Sectors[s]; + dxRender_Visual* V = S->root(); + float vol = V->vis.box.getvolume(); + if (vol > largest_sector_vol) + { + largest_sector_vol = vol; + largest_sector = S; + } + } + pOutdoorSector = largest_sector; } void CRender::LoadSWIs(CStreamReader* base_fs) diff --git a/src/Layers/xrRenderPC_R2/r2_rendertarget.cpp b/src/Layers/xrRenderPC_R2/r2_rendertarget.cpp index 99d23ea55e..3abf14a0fd 100644 --- a/src/Layers/xrRenderPC_R2/r2_rendertarget.cpp +++ b/src/Layers/xrRenderPC_R2/r2_rendertarget.cpp @@ -476,15 +476,14 @@ CRenderTarget::CRenderTarget() t_LUM_dest.create(r2_RT_luminance_cur); // create pool - for (u32 it = 0; it < HW.Caps.iGPUNum * 2; it++) + for (u32 it = 0; it < 2; it++) { - string256 name; - xr_sprintf(name, "%s_%d", r2_RT_luminance_pool, it); - rt_LUM_pool[it].create(name, 1, 1, D3DFMT_R32F); + shared_str name; name.printf("%s_%d", r2_RT_luminance_pool, it); + rt_LUM_pool[it].create(name.c_str(), 1, 1, D3DFMT_R32F); u_setrt(rt_LUM_pool[it], 0, 0, 0); - CHK_DX(HW.pDevice->Clear( 0L, NULL, D3DCLEAR_TARGET, 0x7f7f7f7f, 1.0f, 0L)); + CHK_DX(HW.pDevice->Clear(0L, nullptr, D3DCLEAR_TARGET, 0x7f7f7f7f, 1.0f, 0L)); } - u_setrt(Device.dwWidth, Device.dwHeight, HW.pBaseRT,NULL,NULL, HW.pBaseZB); + u_setrt(Device.dwWidth, Device.dwHeight, HW.pBaseRT, nullptr, nullptr, HW.pBaseZB); } // COMBINE diff --git a/src/Layers/xrRenderPC_R2/r2_rendertarget.h b/src/Layers/xrRenderPC_R2/r2_rendertarget.h index 1576e9ad4b..53663db07f 100644 --- a/src/Layers/xrRenderPC_R2/r2_rendertarget.h +++ b/src/Layers/xrRenderPC_R2/r2_rendertarget.h @@ -103,7 +103,7 @@ class CRenderTarget : public IRender_Target // Igor: for async screenshots IDirect3DSurface9* pFB; //32bit (r,g,b,a) is situated in the system memory - ref_rt rt_LUM_pool [CHWCaps::MAX_GPUS * 2]; // 1xfp32,1x1, exp-result -> scaler + ref_rt rt_LUM_pool [2]; // 1xfp32,1x1, exp-result -> scaler ref_texture t_LUM_src; // source ref_texture t_LUM_dest; // destination & usage for current frame @@ -305,6 +305,7 @@ class CRenderTarget : public IRender_Target void accum_reflected(light* L); // Igor: for volumetric lights void accum_volumetric(light* L); + void accum_volumetric_lv(light* L); void phase_bloom(); void phase_luminance(); void phase_combine(); diff --git a/src/Layers/xrRenderPC_R2/r2_rendertarget_accum_direct.cpp b/src/Layers/xrRenderPC_R2/r2_rendertarget_accum_direct.cpp index e0e53dba54..f1c4d9520a 100644 --- a/src/Layers/xrRenderPC_R2/r2_rendertarget_accum_direct.cpp +++ b/src/Layers/xrRenderPC_R2/r2_rendertarget_accum_direct.cpp @@ -875,9 +875,6 @@ void CRenderTarget::accum_direct_volumetric(u32 sub_phase, const u32 Offset, con STextureList* _T = &*s_accum_direct_volumetric_cascade->E[0]->passes[0]->T; - if (ps_r2_ls_flags_ext.is(R2FLAGEXT_SUN_OLD)) - _T = &*s_accum_direct_volumetric->E[0]->passes[0]->T; - STextureList::iterator _it = _T->begin(); STextureList::iterator _end = _T->end(); for (; _it != _end; _it++) @@ -908,13 +905,8 @@ void CRenderTarget::accum_direct_volumetric(u32 sub_phase, const u32 Offset, con // setup - if (ps_r2_ls_flags_ext.is(R2FLAGEXT_SUN_OLD)) - RCache.set_Element(s_accum_direct_volumetric->E[0]); - else - { - RCache.set_Element(s_accum_direct_volumetric_cascade->E[0]); - RCache.set_CullMode(CULL_CCW); - } + RCache.set_Element(s_accum_direct_volumetric_cascade->E[0]); + RCache.set_CullMode(CULL_CCW); // RCache.set_c ("Ldynamic_dir", L_dir.x,L_dir.y,L_dir.z,0 ); RCache.set_c("Ldynamic_color", L_clr.x, L_clr.y, L_clr.z, 0); @@ -939,11 +931,7 @@ void CRenderTarget::accum_direct_volumetric(u32 sub_phase, const u32 Offset, con else { extern float OLES_SUN_LIMIT_27_01_07; - if (ps_r2_ls_flags_ext.is(R2FLAGEXT_SUN_OLD)) - zMin = ps_r2_sun_near; - else - zMin = 0; /////***************************************************************************************** - + zMin = 0; /////***************************************************************************************** zMax = OLES_SUN_LIMIT_27_01_07; } @@ -984,11 +972,8 @@ void CRenderTarget::accum_direct_volumetric(u32 sub_phase, const u32 Offset, con // setup stencil: we have to draw to both lit and unlit pixels //RCache.set_Stencil (TRUE,D3DCMP_LESSEQUAL,dwLightMarkerID,0xff,0x00); - if (ps_r2_ls_flags_ext.is(R2FLAGEXT_SUN_OLD)) - RCache.Render(D3DPT_TRIANGLELIST, Offset, 0, 4, 0, 2); - else - RCache.Render(D3DPT_TRIANGLELIST, Offset, 0, 8, 0, 16); - + RCache.Render(D3DPT_TRIANGLELIST, Offset, 0, 8, 0, 16); + // Fetch4 : disable if (RImplementation.o.HW_smap_FETCH4) { diff --git a/src/Layers/xrRenderPC_R2/r2_rendertarget_accum_point.cpp b/src/Layers/xrRenderPC_R2/r2_rendertarget_accum_point.cpp index 5f713da82f..e0ff711c8f 100644 --- a/src/Layers/xrRenderPC_R2/r2_rendertarget_accum_point.cpp +++ b/src/Layers/xrRenderPC_R2/r2_rendertarget_accum_point.cpp @@ -19,7 +19,6 @@ void CRenderTarget::accum_point(light* L) Device.mView.transform_tiny(L_pos, L->position); // Xforms - L->xform_calc(); RCache.set_xform_world(L->m_xform); RCache.set_xform_view(Device.mView); RCache.set_xform_project(Device.mProject); diff --git a/src/Layers/xrRenderPC_R2/r2_rendertarget_accum_reflected.cpp b/src/Layers/xrRenderPC_R2/r2_rendertarget_accum_reflected.cpp index ce482a3bf3..fca2a34fb8 100644 --- a/src/Layers/xrRenderPC_R2/r2_rendertarget_accum_reflected.cpp +++ b/src/Layers/xrRenderPC_R2/r2_rendertarget_accum_reflected.cpp @@ -10,7 +10,6 @@ void CRenderTarget::accum_reflected(light* L) ref_shader shader = s_accum_reflected; BOOL bIntersect = FALSE; //enable_scissor(L); - L->xform_calc(); RCache.set_xform_world(L->m_xform); RCache.set_xform_view(Device.mView); RCache.set_xform_project(Device.mProject); diff --git a/src/Layers/xrRenderPC_R2/r2_rendertarget_accum_spot.cpp b/src/Layers/xrRenderPC_R2/r2_rendertarget_accum_spot.cpp index 04f8b7af0f..4dcf0fa59f 100644 --- a/src/Layers/xrRenderPC_R2/r2_rendertarget_accum_spot.cpp +++ b/src/Layers/xrRenderPC_R2/r2_rendertarget_accum_spot.cpp @@ -1,5 +1,6 @@ #include "stdafx.h" #include "../xrRender/du_cone.h" +#include "..\xrRender\CHudInitializer.h" //extern Fvector du_cone_vertices[DU_CONE_NUMVERTEX]; @@ -25,7 +26,6 @@ void CRenderTarget::accum_spot(light* L) BOOL bIntersect = FALSE; //enable_scissor(L); { // setup xform - L->xform_calc(); RCache.set_xform_world(L->m_xform); RCache.set_xform_view(Device.mView); RCache.set_xform_project(Device.mProject); @@ -181,6 +181,12 @@ void CRenderTarget::accum_spot(light* L) u_DBT_disable(); } +// Stub to use vanilla +void CRenderTarget::accum_volumetric_lv(light* L) +{ + accum_volumetric(L); +} + void CRenderTarget::accum_volumetric(light* L) { //if (L->flags.type != IRender_Light::SPOT) return; @@ -198,7 +204,6 @@ void CRenderTarget::accum_volumetric(light* L) BOOL bIntersect = FALSE; //enable_scissor(L); { // setup xform - L->xform_calc(); RCache.set_xform_world(L->m_xform); RCache.set_xform_view(Device.mView); RCache.set_xform_project(Device.mProject); @@ -290,9 +295,9 @@ void CRenderTarget::accum_volumetric(light* L) Fbox aabb; //float scaledRadius = L->spatial.sphere.R * (1+L->m_volumetric_distance)*0.5f; - float scaledRadius = L->spatial.sphere.R * L->m_volumetric_distance; + float scaledRadius = L->SpatialComponent->spatial.sphere.R * L->m_volumetric_distance; Fvector rr = Fvector().set(scaledRadius, scaledRadius, scaledRadius); - Fvector pt = L->spatial.sphere.P; + Fvector pt = L->SpatialComponent->spatial.sphere.P; pt.sub(L->position); pt.mul(L->m_volumetric_distance); pt.add(L->position); diff --git a/src/Layers/xrRenderPC_R2/r2_rendertarget_enable_scissor.cpp b/src/Layers/xrRenderPC_R2/r2_rendertarget_enable_scissor.cpp index 8c34e36349..e10fbd4aa9 100644 --- a/src/Layers/xrRenderPC_R2/r2_rendertarget_enable_scissor.cpp +++ b/src/Layers/xrRenderPC_R2/r2_rendertarget_enable_scissor.cpp @@ -16,14 +16,14 @@ void CRenderTarget::enable_dbt_bounds(light* L) if (!ps_r2_ls_flags.test(R2FLAG_USE_NVDBT)) return; u32 mask = 0xffffffff; - EFC_Visible vis = RImplementation.ViewBase.testSphere(L->spatial.sphere.P, L->spatial.sphere.R * 1.01f, mask); + EFC_Visible vis = RImplementation.ViewBase.testSphere(L->SpatialComponent->spatial.sphere.P, L->SpatialComponent->spatial.sphere.R * 1.01f, mask); if (vis != fcvFully) return; // xform BB Fbox BB; Fvector rr; - rr.set(L->spatial.sphere.R, L->spatial.sphere.R, L->spatial.sphere.R); - BB.setb(L->spatial.sphere.P, rr); + rr.set(L->SpatialComponent->spatial.sphere.R, L->SpatialComponent->spatial.sphere.R, L->SpatialComponent->spatial.sphere.R); + BB.setb(L->SpatialComponent->spatial.sphere.P, rr); Fbox bbp; bbp.invalidate(); @@ -75,13 +75,13 @@ BOOL CRenderTarget::enable_scissor(light* L) // true if intersects near plane Fplane P; P.n.set(plane.x, plane.y, plane.z); P.d = plane.w; - float p_dist = P.classify(L->spatial.sphere.P) - L->spatial.sphere.R; + float p_dist = P.classify(L->SpatialComponent->spatial.sphere.P) - L->SpatialComponent->spatial.sphere.R; near_intersect = (p_dist <= 0); } #ifdef DEBUG if (1) { - Fsphere S; S.set (L->spatial.sphere.P,L->spatial.sphere.R); + Fsphere S; S.set (L->SpatialComponent->spatial.sphere.P,L->SpatialComponent->spatial.sphere.R); dbg_spheres.push_back (mk_pair(S,L->color)); } #endif diff --git a/src/Layers/xrRenderPC_R2/r2_rendertarget_phase_combine.cpp b/src/Layers/xrRenderPC_R2/r2_rendertarget_phase_combine.cpp index b85dd4f020..9e6854ee17 100644 --- a/src/Layers/xrRenderPC_R2/r2_rendertarget_phase_combine.cpp +++ b/src/Layers/xrRenderPC_R2/r2_rendertarget_phase_combine.cpp @@ -39,21 +39,19 @@ void CRenderTarget::phase_combine() Fvector2 p0, p1; //*** exposure-pipeline - u32 gpu_id = Device.dwFrame%HW.Caps.iGPUNum; if (Device.m_SecondViewport.IsSVPActive()) //--#SM+#-- +SecondVP+ Fix for screen flickering { - // clang-format off - gpu_id = (Device.dwFrame - 1) % HW.Caps.iGPUNum; // Фeen "ia?цaнey" tonemapping (HDR) iоnлa вueл?чaнey двойноaо ?aндa?a. - // Iобочнuй эффaeo - i?e ?aбоoa двойноaо ?aндa?a neо?оnoь eзiaнaнey tonemapping (HDR) iaдaao в двa ?aзa - // Ia?цaнea nвyзaно n oai, чoо HDR длy nвоaй ?aбоou o?aнeo уiaньoaннea eоiee "i?оoлuo eaд?ов" - // Эoe eaд?u оoноneoaльно iоoоae д?уa нa д?уaa, однaeо i?e вeл?чaнноi двойноi ?aндa?a - // в iоловeнa eaд?ов оeaзuвaaony ea?oeнea eз вoо?оaо ?aндa?a, e iоneольeу онa чanoо iоaao оoлeчaony iо цвaoу\y?eоnoe - // oо i?e iоiuoea nоздaнey "iлaвноaо" ia?aoодa iaaду нeie iолучaaony эффaeo ia?цaнey - + if (t_LUM_src != rt_LUM_pool[0]->pTexture) + t_LUM_src->surface_set(rt_LUM_pool[0]->pSurface); + if (t_LUM_dest != rt_LUM_pool[1]->pTexture) + t_LUM_dest->surface_set(rt_LUM_pool[1]->pSurface); } + else { - t_LUM_src->surface_set (rt_LUM_pool[gpu_id*2+0]->pSurface); - t_LUM_dest->surface_set (rt_LUM_pool[gpu_id*2+1]->pSurface); + if (t_LUM_src != rt_LUM_pool[0]->pTexture) + t_LUM_src->surface_set(rt_LUM_pool[0]->pSurface); + if (t_LUM_dest != rt_LUM_pool[1]->pTexture) + t_LUM_dest->surface_set(rt_LUM_pool[1]->pSurface); } RCache.set_CullMode(CULL_NONE); @@ -235,11 +233,13 @@ void CRenderTarget::phase_combine() // Distortion filter BOOL bDistort = RImplementation.o.distortion_enabled; // This can be modified { - u32 count = RImplementation.mapDistort.size() + RImplementation.mapHUDDistort.size(); - if ((0 == count) && !_menu_pp) - { - bDistort = FALSE; - } + if (( + 0 == RImplementation.GMBase.RGraph.mapStaticSorted.Distort.size() && + 0 == RImplementation.GMBase.RGraph.mapDynamicSorted.Distort.size() && + 0 == RImplementation.GMBase.RGraph.mapHUDSorted.Distort.size() + ) && !_menu_pp + ) + bDistort = FALSE; if (bDistort) { u_setrt(rt_Generic_1, 0, 0, HW.pBaseZB); // Now RT is a distortion mask @@ -247,7 +247,7 @@ void CRenderTarget::phase_combine() RCache.set_Stencil(FALSE); RCache.set_ColorWriteEnable(); CHK_DX(HW.pDevice->Clear ( 0L, NULL, D3DCLEAR_TARGET, color_rgba(127,127,0,127), 1.0f, 0L)); - RImplementation.r_dsgraph_render_distort(); + RImplementation.GMBase.r_dsgraph_render_distort(); if (g_pGamePersistent) g_pGamePersistent->OnRenderPPUI_PP(); // PP-UI } } @@ -419,9 +419,9 @@ void CRenderTarget::phase_combine() //*** exposure-pipeline-clear { - std::swap(rt_LUM_pool[gpu_id * 2 + 0], rt_LUM_pool[gpu_id * 2 + 1]); - t_LUM_src->surface_set(NULL); - t_LUM_dest->surface_set(NULL); + std::swap(rt_LUM_pool[0], rt_LUM_pool[1]); + t_LUM_src->surface_set(nullptr); + t_LUM_dest->surface_set(nullptr); } #ifdef DEBUG diff --git a/src/Layers/xrRenderPC_R2/r2_rendertarget_phase_luminance.cpp b/src/Layers/xrRenderPC_R2/r2_rendertarget_phase_luminance.cpp index cee0c6b835..5ce091a883 100644 --- a/src/Layers/xrRenderPC_R2/r2_rendertarget_phase_luminance.cpp +++ b/src/Layers/xrRenderPC_R2/r2_rendertarget_phase_luminance.cpp @@ -113,8 +113,7 @@ void CRenderTarget::phase_luminance() } // 222: Perform LUM-SAT, pass 2, 8x8 => 1x1 - u32 gpu_id = Device.dwFrame % HW.Caps.iGPUNum; - u_setrt(rt_LUM_pool[gpu_id * 2 + 1],NULL,NULL,NULL); + u_setrt(rt_LUM_pool[1],NULL,NULL,NULL); { // Build filter-kernel float _ts = 1; diff --git a/src/Layers/xrRenderPC_R2/r2_sector_detect.cpp b/src/Layers/xrRenderPC_R2/r2_sector_detect.cpp deleted file mode 100644 index 28c8331907..0000000000 --- a/src/Layers/xrRenderPC_R2/r2_sector_detect.cpp +++ /dev/null @@ -1,89 +0,0 @@ -#include "stdafx.h" -#include "r2.h" - -int CRender::translateSector(IRender_Sector* pSector) -{ - if (!pSector) - return -1; - - for (u32 i = 0; i < Sectors.size(); ++i) - { - if (Sectors[i] == pSector) - return i; - } - - FATAL("Sector was not found!"); - NODEFAULT; - -#ifdef DEBUG - return (-1); -#endif // #ifdef DEBUG -} - -IRender_Sector* CRender::detectSector(const Fvector& P) -{ - IRender_Sector* S = NULL; - Fvector dir; - Sectors_xrc.ray_options(CDB::OPT_ONLYNEAREST); - - dir.set(0, -1, 0); - S = detectSector(P, dir); - if (NULL == S) - { - dir.set(0, 1, 0); - S = detectSector(P, dir); - } - return S; -} - -IRender_Sector* CRender::detectSector(const Fvector& P, Fvector& dir) -{ - // Portals model - int id1 = -1; - float range1 = 500.f; - if (rmPortals) - { - Sectors_xrc.ray_query(rmPortals, P, dir, range1); - if (Sectors_xrc.r_count()) - { - CDB::RESULT* RP1 = Sectors_xrc.r_begin(); - id1 = RP1->id; - range1 = RP1->range; - } - } - - // Geometry model - int id2 = -1; - float range2 = range1; - Sectors_xrc.ray_query(g_pGameLevel->ObjectSpace.GetStaticModel(), P, dir, range2); - if (Sectors_xrc.r_count()) - { - CDB::RESULT* RP2 = Sectors_xrc.r_begin(); - id2 = RP2->id; - range2 = RP2->range; - } - - // Select ID - int ID; - if (id1 >= 0) - { - if (id2 >= 0) ID = (range1 <= range2 + EPS) ? id1 : id2; // both was found - else ID = id1; // only id1 found - } - else if (id2 >= 0) ID = id2; // only id2 found - else return 0; - - if (ID == id1) - { - // Take sector, facing to our point from portal - CDB::TRI* pTri = rmPortals->get_tris() + ID; - CPortal* pPortal = (CPortal*)Portals[pTri->dummy]; - return pPortal->getSectorFacing(P); - } - else - { - // Take triangle at ID and use it's Sector - CDB::TRI* pTri = g_pGameLevel->ObjectSpace.GetStaticTris() + ID; - return getSector(pTri->sector); - } -} diff --git a/src/Layers/xrRenderPC_R2/stdafx.h b/src/Layers/xrRenderPC_R2/stdafx.h index 0e48189d8b..9840815764 100644 --- a/src/Layers/xrRenderPC_R2/stdafx.h +++ b/src/Layers/xrRenderPC_R2/stdafx.h @@ -39,6 +39,8 @@ #include "../xrRender/xrRender_console.h" #include "r2.h" +#include "../../xrCore/profiler.h" + IC void jitter(CBlender_Compile& C) { C.r_Sampler("jitter0", JITTER(0), true, D3DTADDRESS_WRAP, D3DTEXF_POINT, D3DTEXF_NONE, D3DTEXF_POINT); diff --git a/src/Layers/xrRenderPC_R2/xrRender_R2.vcxproj b/src/Layers/xrRenderPC_R2/xrRender_R2.vcxproj index aa199ea72b..c6e5e27ca1 100644 --- a/src/Layers/xrRenderPC_R2/xrRender_R2.vcxproj +++ b/src/Layers/xrRenderPC_R2/xrRender_R2.vcxproj @@ -13,6 +13,10 @@ Release x64 + + VerifiedDX11ASAN + x64 + VerifiedDX11 x64 @@ -57,6 +61,14 @@ false x64 + + StaticLibrary + v143 + MultiByte + false + x64 + true + StaticLibrary v143 @@ -87,6 +99,11 @@ + + + + + @@ -116,6 +133,11 @@ $(xrGameDir)bin_dbg\$(Platform)\$(Configuration)\ $(xrIntDir)$(ProjectName)\ + + false + $(xrGameDir)bin_dbg\$(Platform)\$(Configuration)\ + $(xrIntDir)$(ProjectName)\ + false $(xrGameDir)bin_dbg\$(Platform)\$(Configuration)\ @@ -197,7 +219,7 @@ false false .;$(SolutionDir)3rd party\imgui\;$(SolutionDir)3rd party\luajit-2\src\;$(SolutionDir)3rd party\luabind\;$(SolutionDir)xrCore;$(xrSdkDir)include;$(XRAY_16X_LIBS)OpenAutomate\inc;$(XRAY_16X_LIBS)nvapi;%(AdditionalIncludeDirectories) - USE_VERIFY_IN_RELEASE;WIN32;NDEBUG;_WINDOWS;_USRDLL;XRRENDER_R2_EXPORTS;_SECURE_SCL=0;%(PreprocessorDefinitions) + XRCORE_PROFILER;USE_VERIFY_IN_RELEASE;WIN32;NDEBUG;_WINDOWS;_USRDLL;XRRENDER_R2_EXPORTS;_SECURE_SCL=0;%(PreprocessorDefinitions) NotSet Use EditAndContinue @@ -234,7 +256,7 @@ false false .;$(SolutionDir)3rd party\imgui\;$(SolutionDir)3rd party\luajit-2\src\;$(SolutionDir)3rd party\luabind\;$(SolutionDir)xrCore;$(xrSdkDir)include;$(XRAY_16X_LIBS)OpenAutomate\inc;$(XRAY_16X_LIBS)nvapi;%(AdditionalIncludeDirectories) - USE_VERIFY_IN_RELEASE;WIN32;NDEBUG;_WINDOWS;_USRDLL;XRRENDER_R2_EXPORTS;_SECURE_SCL=0;%(PreprocessorDefinitions) + XRCORE_PROFILER;USE_VERIFY_IN_RELEASE;WIN32;NDEBUG;_WINDOWS;_USRDLL;XRRENDER_R2_EXPORTS;_SECURE_SCL=0;%(PreprocessorDefinitions) NotSet Use EditAndContinue @@ -261,6 +283,43 @@ true + + + Disabled + Disabled + false + Neither + false + false + false + .;$(SolutionDir)3rd party\imgui\;$(SolutionDir)3rd party\luajit-2\src\;$(SolutionDir)3rd party\luabind\;$(SolutionDir)xrCore;$(xrSdkDir)include;$(XRAY_16X_LIBS)OpenAutomate\inc;$(XRAY_16X_LIBS)nvapi;%(AdditionalIncludeDirectories) + XRCORE_PROFILER;USE_VERIFY_IN_RELEASE;_DISABLE_VECTOR_ANNOTATION;_DISABLE_STRING_ANNOTATION;WIN32;NDEBUG;_WINDOWS;_USRDLL;XRRENDER_R2_EXPORTS;_SECURE_SCL=0;%(PreprocessorDefinitions) + NotSet + Use + ProgramDatabase + USE_LUAJIT_ONE + true + Level4 + false + MultiThreadedDLL + false + stdcpp17 + true + + + nvapi.lib;%(AdditionalDependencies) + $(SolutionDir)3rd party\luajit-2\src\;$(xrSdkDir)libraries\x64;$(xrLibDir);$(XRAY_16X_LIBS)OpenAutomate\libraries;$(SolutionDir)x64\Release;%(AdditionalLibraryDirectories) + NotSet + true + true + true + Default + false + $(xrLibDir)$(TargetName).lib + LIBCMT + true + + .;$(SolutionDir)3rd party\imgui\;$(SolutionDir)3rd party\luajit-2\src\;$(SolutionDir)3rd party\luabind\;$(SolutionDir)xrCore;$(xrSdkDir)include;$(XRAY_16X_LIBS)OpenAutomate\inc;$(XRAY_16X_LIBS)nvapi;%(AdditionalIncludeDirectories) @@ -342,6 +401,7 @@ + @@ -408,7 +468,8 @@ - + + @@ -461,8 +522,6 @@ - - @@ -489,6 +548,7 @@ + @@ -535,9 +595,11 @@ + + @@ -548,6 +610,7 @@ + @@ -568,16 +631,20 @@ + + + + - + @@ -589,7 +656,6 @@ - @@ -623,12 +689,7 @@ - - - - - @@ -650,20 +711,18 @@ - - - - Create Create Create Create + Create Create + diff --git a/src/Layers/xrRenderPC_R2/xrRender_R2.vcxproj.filters b/src/Layers/xrRenderPC_R2/xrRender_R2.vcxproj.filters index b67ef26566..56e398d04e 100644 --- a/src/Layers/xrRenderPC_R2/xrRender_R2.vcxproj.filters +++ b/src/Layers/xrRenderPC_R2/xrRender_R2.vcxproj.filters @@ -183,9 +183,6 @@ Core - - Core - Core @@ -225,12 +222,6 @@ Lights - - Lights - - - Lights - Lights @@ -684,6 +675,13 @@ Core + + Core + + + + Core + @@ -701,27 +699,12 @@ Core - - Core - Core - - Core - - - Core - Core - - Core - - - Core - Core @@ -743,9 +726,6 @@ Core - - Core - Core @@ -791,18 +771,6 @@ Lights - - Lights - - - Lights - - - Lights - - - Lights - Lights @@ -911,9 +879,6 @@ Visibility\Sector/Portal - - Visibility\Sector/Portal - Visibility\HOM Occlusion @@ -1247,5 +1212,31 @@ Core + + + Core + + + Visibility\Sector/Portal + + + Core + + + + Core + + + Core + + + Core + + + Core + + + Lights + - \ No newline at end of file + diff --git a/src/Layers/xrRenderPC_R3/Light_Render_Direct.cpp b/src/Layers/xrRenderPC_R3/Light_Render_Direct.cpp deleted file mode 100644 index 5f6f1f7b2c..0000000000 --- a/src/Layers/xrRenderPC_R3/Light_Render_Direct.cpp +++ /dev/null @@ -1,2 +0,0 @@ -#include "StdAfx.h" -#include "light_render_direct.h" diff --git a/src/Layers/xrRenderPC_R3/Light_Render_Direct.h b/src/Layers/xrRenderPC_R3/Light_Render_Direct.h deleted file mode 100644 index 15b4214acb..0000000000 --- a/src/Layers/xrRenderPC_R3/Light_Render_Direct.h +++ /dev/null @@ -1,7 +0,0 @@ -#pragma once - -class CLight_Compute_XFORM_and_VIS -{ -public: - void compute_xf_spot(light* L); // -}; diff --git a/src/Layers/xrRenderPC_R3/Light_Render_Direct_ComputeXFS.cpp b/src/Layers/xrRenderPC_R3/Light_Render_Direct_ComputeXFS.cpp deleted file mode 100644 index 108ae4099f..0000000000 --- a/src/Layers/xrRenderPC_R3/Light_Render_Direct_ComputeXFS.cpp +++ /dev/null @@ -1,95 +0,0 @@ -#include "stdafx.h" -#include "light_render_direct.h" - -void CLight_Compute_XFORM_and_VIS::compute_xf_spot(light* L) -{ - // Build EYE-space xform - Fvector L_dir, L_up, L_right, L_pos; - L_dir.set(L->direction); - L_dir.normalize(); - - if (L->right.square_magnitude() > EPS) - { - // use specified 'up' and 'right', just enshure ortho-normalization - L_right.set(L->right); - L_right.normalize(); - L_up.crossproduct(L_dir, L_right); - L_up.normalize(); - L_right.crossproduct(L_up, L_dir); - L_right.normalize(); - } - else - { - // auto find 'up' and 'right' vectors - L_up.set(0, 1, 0); - if (_abs(L_up.dotproduct(L_dir)) > .99f) L_up.set(0, 0, 1); - L_right.crossproduct(L_up, L_dir); - L_right.normalize(); - L_up.crossproduct(L_dir, L_right); - L_up.normalize(); - } - L_pos.set(L->position); - - // - int _cached_size = L->X.S.size; - L->X.S.posX = L->X.S.posY = 0; - L->X.S.size = SMAP_adapt_max; - L->X.S.transluent = FALSE; - - // Compute approximate screen area (treating it as an point light) - R*R/dist_sq - // Note: we clamp screen space area to ONE, although it is not correct at all - float dist = Device.vCameraPosition.distance_to(L->spatial.sphere.P) - L->spatial.sphere.R; - if (dist < 0) dist = 0; - float ssa = clampr(L->range * L->range / (1.f + dist * dist), 0.f, 1.f); - - // compute intensity - float intensity0 = (L->color.r + L->color.g + L->color.b) / 3.f; - float intensity1 = (L->color.r * 0.2125f + L->color.g * 0.7154f + L->color.b * 0.0721f); - float intensity = (intensity0 + intensity1) / 2.f; // intensity1 tends to underestimate... - - // compute how much duelling frusta occurs [-1..1]-> 1 + [-0.5 .. +0.5] - float duel_dot = 1.f - 0.5f * Device.vCameraDirection.dotproduct(L_dir); - - // compute how large the light is - give more texels to larger lights, assume 8m as being optimal radius - float sizefactor = L->range / 8.f; // 4m = .5, 8m=1.f, 16m=2.f, 32m=4.f - - // compute how wide the light frustum is - assume 90deg as being optimal - float widefactor = L->cone / deg2rad(90.f); // - - // factors - float factor0 = powf(ssa, 1.f / 2.f); // ssa is quadratic - float factor1 = powf(intensity, 1.f / 16.f); // less perceptually important? - float factor2 = powf(duel_dot, 1.f / 4.f); // difficult to fast-change this -> visible - float factor3 = powf(sizefactor, 1.f / 4.f); // this shouldn't make much difference - float factor4 = powf(widefactor, 1.f / 2.f); // make it linear ??? - float factor = ps_r2_ls_squality * factor0 * factor1 * factor2 * factor3 * factor4; - - // final size calc - u32 _size = iFloor(factor * SMAP_adapt_optimal); - if (_size < SMAP_adapt_min) _size = SMAP_adapt_min; - if (_size > SMAP_adapt_max) _size = SMAP_adapt_max; - int _epsilon = iCeil(float(_size) * 0.01f); - int _diff = _abs(int(_size) - int(_cached_size)); - L->X.S.size = (_diff >= _epsilon) ? _size : _cached_size; - - // make N pixel border - L->X.S.view.build_camera_dir(L_pos, L_dir, L_up); - //float n = 2.f ; - //float x = float(L->X.S.size) ; - //float alpha = L->cone/2 ; - //float tan_beta = (x+2*n)*tanf(alpha) / x ; - //float g_alpha = 2*rad2deg (alpha); - //float g_beta = 2*rad2deg (atanf(tan_beta)); - //Msg ("x(%f) : a(%f), b(%f)",x,g_alpha,g_beta); - - /* Ray Twitty */ - float tan_shift; - if (L->flags.type == IRender_Light::POINT) - tan_shift = deg2rad(11.5f); - else - tan_shift = deg2rad(3.5f); - - /* Ray Twitty end */ - L->X.S.project.build_projection(L->cone + tan_shift, 1.f, L->virtual_size, L->range + EPS_S); - L->X.S.combine.mul(L->X.S.project, L->X.S.view); -} diff --git a/src/Layers/xrRenderPC_R3/light_GI.cpp b/src/Layers/xrRenderPC_R3/light_GI.cpp index 0e0084c8cb..c04f4ab24e 100644 --- a/src/Layers/xrRenderPC_R3/light_GI.cpp +++ b/src/Layers/xrRenderPC_R3/light_GI.cpp @@ -47,7 +47,7 @@ void light::gi_generate() LI.D.reflect(dir, TN); LI.E = dot * (1 - R->range / range); if (LI.E < ps_r2_GI_clip) continue; - LI.S = spatial.sector; //. BUG + LI.S = SpatialComponent->spatial.sector; //. BUG indirect.push_back(LI); } diff --git a/src/Layers/xrRenderPC_R3/light_smapvis.cpp b/src/Layers/xrRenderPC_R3/light_smapvis.cpp deleted file mode 100644 index 5a25a987d2..0000000000 --- a/src/Layers/xrRenderPC_R3/light_smapvis.cpp +++ /dev/null @@ -1,131 +0,0 @@ -#include "StdAfx.h" -#include "../xrRender/light.h" -#include "../xrRender/FBasicVisual.h" - -smapvis::smapvis() -{ - invalidate(); - frame_sleep = 0; -} - -smapvis::~smapvis() -{ - flushoccq(); - invalidate(); -} - -void smapvis::invalidate() -{ - state = state_counting; - testQ_V = 0; - frame_sleep = Device.dwFrame + ps_r__LightSleepFrames; - invisible.clear(); -} - -void smapvis::begin() -{ - RImplementation.clear_Counters(); - switch (state) - { - case state_counting: - // do nothing -> we just prepare for testing process - break; - case state_working: - // mark already known to be invisible visuals, set breakpoint - testQ_V = 0; - testQ_id = 0; - mark(); - RImplementation.set_Feedback(this, test_current); - break; - case state_usingTC: - // just mark - mark(); - break; - } -} - -void smapvis::end() -{ - // Gather stats - u32 ts, td; - RImplementation.get_Counters(ts, td); - RImplementation.stats.ic_total += ts; - RImplementation.set_Feedback(0, 0); - - switch (state) - { - case state_counting: - // switch to 'working' - if (sleep()) - { - test_count = ts; - test_current = 0; - state = state_working; - } - break; - case state_working: - // feedback should be called at this time -> clear feedback - // issue query - if (testQ_V) - { - RImplementation.occq_begin(testQ_id); - RImplementation.marker += 1; - RImplementation.r_dsgraph_insert_static(testQ_V); - RImplementation.r_dsgraph_render_graph(0); - RImplementation.occq_end(testQ_id); - testQ_frame = Device.dwFrame + 1; // get result on next frame - } - break; - case state_usingTC: - // nothing to do - break; - } -} - -void smapvis::flushoccq() -{ - // the tough part - if (testQ_frame != Device.dwFrame) return; - if ((state != state_working) || (!testQ_V)) return; - u64 fragments = RImplementation.occq_get(testQ_id); - if (0 == fragments) - { - // this is invisible shadow-caster, register it - // next time we will not get this caster, so 'test_current' remains the same - invisible.push_back(testQ_V); - test_count --; - } - else - { - // this is visible shadow-caster, advance testing - test_current ++; - } - - testQ_V = 0; - - if (test_current == test_count) - { - // we are at the end of list - if (state == state_working) state = state_usingTC; - } -} - -void smapvis::resetoccq() -{ - if (testQ_frame == (Device.dwFrame + 1)) testQ_frame--; - flushoccq(); -} - -void smapvis::mark() -{ - RImplementation.stats.ic_culled += invisible.size(); - u32 marker = RImplementation.marker + 1; // we are called befor marker increment - for (u32 it = 0; it < invisible.size(); it++) - invisible[it]->vis.marker = marker; // this effectively disables processing -} - -void smapvis::rfeedback_static(dxRender_Visual* V) -{ - testQ_V = V; - RImplementation.set_Feedback(0, 0); -} diff --git a/src/Layers/xrRenderPC_R3/light_smapvis.h b/src/Layers/xrRenderPC_R3/light_smapvis.h deleted file mode 100644 index 29bca1ce7b..0000000000 --- a/src/Layers/xrRenderPC_R3/light_smapvis.h +++ /dev/null @@ -1,36 +0,0 @@ -#pragma once - -class smapvis : public R_feedback -{ -public: - enum - { - state_counting = 0, - state_working = 1, - state_usingTC = 3, - } state; - - xr_vector invisible; - - u32 frame_sleep; - u32 test_count; - u32 test_current; - dxRender_Visual* testQ_V; - u32 testQ_id; - u32 testQ_frame; -public: - smapvis(); - ~smapvis(); - - void invalidate(); - void begin(); // should be called before 'marker++' and before graph-build - void end(); - void mark(); - void flushoccq(); // should be called when no rendering of light is supposed - - void resetoccq(); - - IC bool sleep() { return Device.dwFrame > frame_sleep; } - - virtual void rfeedback_static(dxRender_Visual* V); -}; diff --git a/src/Layers/xrRenderPC_R3/light_vis.cpp b/src/Layers/xrRenderPC_R3/light_vis.cpp deleted file mode 100644 index f4334ea16c..0000000000 --- a/src/Layers/xrRenderPC_R3/light_vis.cpp +++ /dev/null @@ -1,87 +0,0 @@ -#include "StdAfx.h" -#include "../xrRender/light.h" -#include "../../xrEngine/cl_intersect.h" - -const u32 delay_small_min = 1; -const u32 delay_small_max = 3; -const u32 delay_large_min = 10; -const u32 delay_large_max = 20; -const u32 cullfragments = 4; - -void light::vis_prepare() -{ - if (int(indirect_photons) != ps_r2_GI_photons) gi_generate(); - - // . test is sheduled for future = keep old result - // . test time comes :) - // . camera inside light volume = visible, shedule for 'small' interval - // . perform testing = ???, pending - - u32 frame = Device.dwFrame; - if (frame < vis.frame2test) return; - - float safe_area = VIEWPORT_NEAR; - { - float a0 = deg2rad(Device.fFOV * Device.fASPECT / 2.f); - float a1 = deg2rad(Device.fFOV / 2.f); - float x0 = VIEWPORT_NEAR / _cos(a0); - float x1 = VIEWPORT_NEAR / _cos(a1); - float c = _sqrt(x0 * x0 + x1 * x1); - safe_area = _max(_max(VIEWPORT_NEAR, _max(x0, x1)), c); - } - - //Msg ("sc[%f,%f,%f]/c[%f,%f,%f] - sr[%f]/r[%f]",VPUSH(spatial.center),VPUSH(position),spatial.radius,range); - //Msg ("dist:%f, sa:%f",Device.vCameraPosition.distance_to(spatial.center),safe_area); - bool skiptest = false; - if (ps_r2_ls_flags.test(R2FLAG_EXP_DONT_TEST_UNSHADOWED) && !flags.bShadow) skiptest = true; - if (ps_r2_ls_flags.test(R2FLAG_EXP_DONT_TEST_SHADOWED) && flags.bShadow) skiptest = true; - - if (skiptest || Device.vCameraPosition.distance_to(spatial.sphere.P) <= (spatial.sphere.R * 1.01f + safe_area)) - { - // small error - vis.visible = true; - vis.pending = false; - vis.frame2test = frame + ::Random.randI(delay_small_min, delay_small_max); - return; - } - - // testing - vis.pending = true; - xform_calc(); - RCache.set_xform_world(m_xform); - vis.query_order = RImplementation.occq_begin(vis.query_id); - // Hack: Igor. Light is visible if it's frutum is visible. (Only for volumetric) - // Hope it won't slow down too much since there's not too much volumetric lights - // TODO: sort for performance improvement if this technique hurts - if ((flags.type == IRender_Light::SPOT) && flags.bShadow && flags.bVolumetric) - RCache.set_Stencil(FALSE); - else - RCache.set_Stencil(TRUE, D3DCMP_LESSEQUAL, 0x01, 0xff, 0x00); - RImplementation.Target->draw_volume(this); - RImplementation.occq_end(vis.query_id); -} - -void light::vis_update() -{ - // . not pending ->>> return (early out) - // . test-result: visible: - // . shedule for 'large' interval - // . test-result: invisible: - // . shedule for 'next-frame' interval - - if (!vis.pending) return; - - u32 frame = Device.dwFrame; - u64 fragments = RImplementation.occq_get(vis.query_id); - - vis.visible = (fragments > cullfragments); - vis.pending = false; - if (vis.visible) - { - vis.frame2test = frame + ::Random.randI(delay_large_min, delay_large_max); - } - else - { - vis.frame2test = frame + 1; - } -} diff --git a/src/Layers/xrRenderPC_R3/r2_R_lights.cpp b/src/Layers/xrRenderPC_R3/r2_R_lights.cpp deleted file mode 100644 index a0a096dd9c..0000000000 --- a/src/Layers/xrRenderPC_R3/r2_R_lights.cpp +++ /dev/null @@ -1,311 +0,0 @@ -#include "stdafx.h" - -IC bool pred_area(light* _1, light* _2) -{ - u32 a0 = _1->X.S.size; - u32 a1 = _2->X.S.size; - return a0 > a1; // reverse -> descending -} - -IC void hud_light_apply(xr_map>& saved_pos, xr_vector& source) -{ - for (u32 it = 0; it < source.size(); it++) - { - light* L = source[it]; - if (!L->get_hud_mode()) continue; - - saved_pos.emplace(L, mk_pair(L->position, L->direction)); - - Device.hud_to_world(L->position); - Device.hud_to_world_dir(L->direction); - } -} - -IC void hud_light_restore(xr_map>& saved_pos, xr_vector& source) -{ - for (const auto& saved : saved_pos) - { - light* L = saved.first; - if (!L->get_hud_mode()) continue; - - L->position = saved.second.first; - L->direction = saved.second.second; - } -} - -void CRender::render_lights(light_Package& LP) -{ - xr_map> saved_pos; - ////////////////////////////////////////////////////////////////////////// - // 0. apply hud_mode projection if necessary - hud_light_apply(saved_pos, LP.v_shadowed); - hud_light_apply(saved_pos, LP.v_point); - hud_light_apply(saved_pos, LP.v_spot); - // Refactor order based on ability to pack shadow-maps - // 1. calculate area + sort in descending order - // const u16 smap_unassigned = u16(-1); - { - xr_vector& source = LP.v_shadowed; - for (u32 it = 0; it < source.size(); it++) - { - light* L = source[it]; - L->vis_update(); - if (!L->vis.visible) - { - source.erase(source.begin() + it); - it--; - } - else - { - LR.compute_xf_spot(L); - } - } - } - - // 2. refactor - infact we could go from the backside and sort in ascending order - { - xr_vector& source = LP.v_shadowed; - xr_vector refactored; - refactored.reserve(source.size()); - u32 total = source.size(); - - for (u16 smap_ID = 0; refactored.size() != total; smap_ID++) - { - LP_smap_pool.initialize(RImplementation.o.smapsize); - std::sort(source.begin(), source.end(), pred_area); - for (u32 test = 0; test < source.size(); test++) - { - light* L = source[test]; - SMAP_Rect R; - if (LP_smap_pool.push(R, L->X.S.size)) - { - // OK - L->X.S.posX = R.min.x; - L->X.S.posY = R.min.y; - L->vis.smap_ID = smap_ID; - refactored.push_back(L); - source.erase(source.begin() + test); - test --; - } - } - } - - // save (lights are popped from back) - std::reverse(refactored.begin(), refactored.end()); - LP.v_shadowed = refactored; - } - - PIX_EVENT(SHADOWED_LIGHTS); - - ////////////////////////////////////////////////////////////////////////// - // sort lights by importance??? - // while (has_any_lights_that_cast_shadows) { - // if (has_point_shadowed) -> generate point shadowmap - // if (has_spot_shadowed) -> generate spot shadowmap - // switch-to-accumulator - // if (has_point_unshadowed) -> accum point unshadowed - // if (has_spot_unshadowed) -> accum spot unshadowed - // if (was_point_shadowed) -> accum point shadowed - // if (was_spot_shadowed) -> accum spot shadowed - // } - // if (left_some_lights_that_doesn't cast shadows) - // accumulate them - HOM.Disable(); - while (LP.v_shadowed.size()) - { - // if (has_spot_shadowed) - xr_vector L_spot_s; - stats.s_used ++; - - // generate spot shadowmap - Target->phase_smap_spot_clear(); - xr_vector& source = LP.v_shadowed; - light* L = source.back(); - u16 sid = L->vis.smap_ID; - while (true) - { - if (source.empty()) break; - L = source.back(); - if (L->vis.smap_ID != sid) break; - source.pop_back(); - Lights_LastFrame.push_back(L); - - // render - phase = PHASE_SMAP; - if (RImplementation.o.Tshadows) r_pmask(true, true); - else r_pmask(true, false); - L->svis.begin(); - PIX_EVENT(SHADOWED_LIGHTS_RENDER_SUBSPACE); - r_dsgraph_render_subspace(L->spatial.sector, L->X.S.combine, L->position, TRUE); - bool bNormal = mapNormalPasses[0][0].size() || mapMatrixPasses[0][0].size(); - bool bSpecial = mapNormalPasses[1][0].size() || mapMatrixPasses[1][0].size() || mapSorted.size(); - if (bNormal || bSpecial) - { - stats.s_merged ++; - L_spot_s.push_back(L); - Target->phase_smap_spot(L); - RCache.set_xform_world(Fidentity); - RCache.set_xform_view(L->X.S.view); - RCache.set_xform_project(L->X.S.project); - r_dsgraph_render_graph(0); - L->X.S.transluent = FALSE; - if (bSpecial) - { - L->X.S.transluent = TRUE; - Target->phase_smap_spot_tsh(L); - PIX_EVENT(SHADOWED_LIGHTS_RENDER_GRAPH); - r_dsgraph_render_graph(1); // normal level, secondary priority - PIX_EVENT(SHADOWED_LIGHTS_RENDER_SORTED); - r_dsgraph_render_sorted(); // strict-sorted geoms - } - } - else - { - stats.s_finalclip ++; - } - L->svis.end(); - r_pmask(true, false); - } - - PIX_EVENT(UNSHADOWED_LIGHTS); - - // switch-to-accumulator - Target->phase_accumulator(); - HOM.Disable(); - - PIX_EVENT(POINT_LIGHTS); - - // if (has_point_unshadowed) -> accum point unshadowed - if (!LP.v_point.empty()) - { - light* L = LP.v_point.back(); - LP.v_point.pop_back(); - L->vis_update(); - if (L->vis.visible) - { - Target->accum_point(L); - render_indirect(L); - } - } - - PIX_EVENT(SPOT_LIGHTS); - - // if (has_spot_unshadowed) -> accum spot unshadowed - if (!LP.v_spot.empty()) - { - light* L = LP.v_spot.back(); - LP.v_spot.pop_back(); - L->vis_update(); - if (L->vis.visible) - { - LR.compute_xf_spot(L); - Target->accum_spot(L); - render_indirect(L); - } - } - - PIX_EVENT(SPOT_LIGHTS_ACCUM_VOLUMETRIC); - - // if (was_spot_shadowed) -> accum spot shadowed - if (!L_spot_s.empty()) - { - PIX_EVENT(ACCUM_SPOT); - PIX_EVENT(ACCUM_VOLUMETRIC); - for (u32 it = 0; it < L_spot_s.size(); it++) - { - Target->accum_spot(L_spot_s[it]); - render_indirect(L_spot_s[it]); - - if (RImplementation.o.advancedpp && ps_r2_ls_flags.is(R2FLAG_VOLUMETRIC_LIGHTS)) - Target->accum_volumetric(L_spot_s[it]); - } - - L_spot_s.clear(); - } - } - - PIX_EVENT(POINT_LIGHTS_ACCUM); - // Point lighting (unshadowed, if left) - if (!LP.v_point.empty()) - { - xr_vector& Lvec = LP.v_point; - for (u32 pid = 0; pid < Lvec.size(); pid++) - { - Lvec[pid]->vis_update(); - if (Lvec[pid]->vis.visible) - { - render_indirect(Lvec[pid]); - Target->accum_point(Lvec[pid]); - } - } - Lvec.clear(); - } - - PIX_EVENT(SPOT_LIGHTS_ACCUM); - // Spot lighting (unshadowed, if left) - if (!LP.v_spot.empty()) - { - xr_vector& Lvec = LP.v_spot; - for (u32 pid = 0; pid < Lvec.size(); pid++) - { - Lvec[pid]->vis_update(); - if (Lvec[pid]->vis.visible) - { - LR.compute_xf_spot(Lvec[pid]); - render_indirect(Lvec[pid]); - Target->accum_spot(Lvec[pid]); - } - } - Lvec.clear(); - } - - // restore world projection if necessary - hud_light_restore(saved_pos, LP.v_shadowed); - hud_light_restore(saved_pos, LP.v_point); - hud_light_restore(saved_pos, LP.v_spot); -} - -void CRender::render_indirect(light* L) -{ - if (!ps_r2_ls_flags.test(R2FLAG_GI)) return; - - light LIGEN; - LIGEN.set_type(IRender_Light::REFLECTED); - LIGEN.set_shadow(false); - LIGEN.set_cone(PI_DIV_2 * 2.f); - - xr_vector& Lvec = L->indirect; - if (Lvec.empty()) return; - float LE = L->color.intensity(); - for (u32 it = 0; it < Lvec.size(); it++) - { - light_indirect& LI = Lvec[it]; - - // energy and color - float LIE = LE * LI.E; - if (LIE < ps_r2_GI_clip) continue; - Fvector T; - T.set(L->color.r, L->color.g, L->color.b).mul(LI.E); - LIGEN.set_color(T.x, T.y, T.z); - - // geometric - Fvector L_up, L_right; - L_up.set(0, 1, 0); - if (_abs(L_up.dotproduct(LI.D)) > .99f) L_up.set(0, 0, 1); - L_right.crossproduct(L_up, LI.D).normalize(); - LIGEN.spatial.sector = LI.S; - LIGEN.set_position(LI.P); - LIGEN.set_rotation(LI.D, L_right); - - // range - // dist^2 / range^2 = A - has infinity number of solutions - // approximate energy by linear fallof Emax / (1 + x) = Emin - float Emax = LIE; - float Emin = 1.f / 255.f; - float x = (Emax - Emin) / Emin; - if (x < 0.1f) continue; - LIGEN.set_range(x); - - Target->accum_reflected(&LIGEN); - } -} diff --git a/src/Layers/xrRenderPC_R3/r2_R_sun.cpp b/src/Layers/xrRenderPC_R3/r2_R_sun.cpp deleted file mode 100644 index 974643e838..0000000000 --- a/src/Layers/xrRenderPC_R3/r2_R_sun.cpp +++ /dev/null @@ -1,1431 +0,0 @@ -#include "stdafx.h" -#include "../../xrEngine/igame_persistent.h" -#include "../../xrEngine/irenderable.h" -#include "../xrRender/FBasicVisual.h" - -#include "r3_R_sun_support.h" - -const float tweak_COP_initial_offs = 1200.f; -const float tweak_ortho_xform_initial_offs = 1000.f; //. ? -const float tweak_guaranteed_range = 20.f; //. ? - -//float OLES_SUN_LIMIT_27_01_07 = 180.f ; -float OLES_SUN_LIMIT_27_01_07 = 100.f; - -const float MAP_SIZE_START = 6.f; -const float MAP_GROW_FACTOR = 4.f; - -////////////////////////////////////////////////////////////////////////// -// tables to calculate view-frustum bounds in world space -// note: D3D uses [0..1] range for Z -static Fvector3 corners [8] = { - {-1, -1, 0}, {-1, -1, +1}, - {-1, +1, +1}, {-1, +1, 0}, - {+1, +1, +1}, {+1, +1, 0}, - {+1, -1, +1}, {+1, -1, 0} -}; -static int facetable[6][4] = { - {6, 7, 5, 4}, {1, 0, 7, 6}, - {1, 2, 3, 0}, {3, 2, 4, 5}, - // near and far planes - {0, 3, 5, 7}, {1, 6, 4, 2}, -}; -////////////////////////////////////////////////////////////////////////// -#define DW_AS_FLT(DW) (*(FLOAT*)&(DW)) -#define FLT_AS_DW(F) (*(DWORD*)&(F)) -#define FLT_SIGN(F) ((FLT_AS_DW(F) & 0x80000000L)) -#define ALMOST_ZERO(F) ((FLT_AS_DW(F) & 0x7f800000L)==0) -#define IS_SPECIAL(F) ((FLT_AS_DW(F) & 0x7f800000L)==0x7f800000L) - -////////////////////////////////////////////////////////////////////////// -struct Frustum -{ - Frustum(); - Frustum(const D3DXMATRIX* matrix); - - D3DXPLANE camPlanes [6]; - int nVertexLUT [6]; - D3DXVECTOR3 pntList [8]; -}; - -struct BoundingBox -{ - D3DXVECTOR3 minPt; - D3DXVECTOR3 maxPt; - - BoundingBox(): minPt(1e33f, 1e33f, 1e33f), maxPt(-1e33f, -1e33f, -1e33f) - { - } - - BoundingBox(const BoundingBox& other): minPt(other.minPt), maxPt(other.maxPt) - { - } - - explicit BoundingBox(const D3DXVECTOR3* points, UINT n): minPt(1e33f, 1e33f, 1e33f), maxPt(-1e33f, -1e33f, -1e33f) - { - for (unsigned int i = 0; i < n; i++) - Merge(&points[i]); - } - - explicit BoundingBox(const std::vector* points): minPt(1e33f, 1e33f, 1e33f), - maxPt(-1e33f, -1e33f, -1e33f) - { - for (unsigned int i = 0; i < points->size(); i++) - Merge(&(*points)[i]); - } - - explicit BoundingBox(const std::vector* boxes): minPt(1e33f, 1e33f, 1e33f), - maxPt(-1e33f, -1e33f, -1e33f) - { - for (unsigned int i = 0; i < boxes->size(); i++) - { - Merge(&(*boxes)[i].maxPt); - Merge(&(*boxes)[i].minPt); - } - } - - void Centroid(D3DXVECTOR3* vec) const { *vec = 0.5f * (minPt + maxPt); } - - void Merge(const D3DXVECTOR3* vec) - { - minPt.x = _min(minPt.x, vec->x); - minPt.y = _min(minPt.y, vec->y); - minPt.z = _min(minPt.z, vec->z); - maxPt.x = _max(maxPt.x, vec->x); - maxPt.y = _max(maxPt.y, vec->y); - maxPt.z = _max(maxPt.z, vec->z); - } - - D3DXVECTOR3 Point(int i) const - { - return D3DXVECTOR3((i & 1) ? minPt.x : maxPt.x, (i & 2) ? minPt.y : maxPt.y, (i & 4) ? minPt.z : maxPt.z); - } -}; - -/////////////////////////////////////////////////////////////////////////// -BOOL LineIntersection2D(D3DXVECTOR2* result, const D3DXVECTOR2* lineA, const D3DXVECTOR2* lineB) -{ - // if the lines are parallel, the lines will not intersect in a point - // NOTE: assumes the rays are already normalized!!!! - VERIFY(_abs(D3DXVec2Dot(&lineA[1], &lineB[1]))<1.f); - - float x[2] = {lineA[0].x, lineB[0].x}; - float y[2] = {lineA[0].y, lineB[0].y}; - float dx[2] = {lineA[1].x, lineB[1].x}; - float dy[2] = {lineA[1].y, lineB[1].y}; - - float x_diff = x[0] - x[1]; - float y_diff = y[0] - y[1]; - - float s = (x_diff - (dx[1] / dy[1]) * y_diff) / ((dx[1] * dy[0] / dy[1]) - dx[0]); - // float t = (x_diff + s*dx[0]) / dx[1]; - - *result = lineA[0] + s * lineA[1]; - return TRUE; -} - -/////////////////////////////////////////////////////////////////////////// -// PlaneIntersection -// computes the point where three planes intersect -// returns whether or not the point exists. -static inline BOOL PlaneIntersection(D3DXVECTOR3* intersectPt, const D3DXPLANE* p0, const D3DXPLANE* p1, - const D3DXPLANE* p2) -{ - D3DXVECTOR3 n0(p0->a, p0->b, p0->c); - D3DXVECTOR3 n1(p1->a, p1->b, p1->c); - D3DXVECTOR3 n2(p2->a, p2->b, p2->c); - - D3DXVECTOR3 n1_n2, n2_n0, n0_n1; - - D3DXVec3Cross(&n1_n2, &n1, &n2); - D3DXVec3Cross(&n2_n0, &n2, &n0); - D3DXVec3Cross(&n0_n1, &n0, &n1); - - float cosTheta = D3DXVec3Dot(&n0, &n1_n2); - - if (ALMOST_ZERO(cosTheta) || IS_SPECIAL(cosTheta)) - return FALSE; - - float secTheta = 1.f / cosTheta; - - n1_n2 = n1_n2 * p0->d; - n2_n0 = n2_n0 * p1->d; - n0_n1 = n0_n1 * p2->d; - - *intersectPt = -(n1_n2 + n2_n0 + n0_n1) * secTheta; - return TRUE; -} - -Frustum::Frustum() -{ - for (int i = 0; i < 6; i++) - camPlanes[i] = D3DXPLANE(0.f, 0.f, 0.f, 0.f); -} - -// build a frustum from a camera (projection, or viewProjection) matrix -Frustum::Frustum(const D3DXMATRIX* matrix) -{ - // build a view frustum based on the current view & projection matrices... - D3DXVECTOR4 column4(matrix->_14, matrix->_24, matrix->_34, matrix->_44); - D3DXVECTOR4 column1(matrix->_11, matrix->_21, matrix->_31, matrix->_41); - D3DXVECTOR4 column2(matrix->_12, matrix->_22, matrix->_32, matrix->_42); - D3DXVECTOR4 column3(matrix->_13, matrix->_23, matrix->_33, matrix->_43); - - D3DXVECTOR4 planes[6]; - planes[0] = column4 - column1; // left - planes[1] = column4 + column1; // right - planes[2] = column4 - column2; // bottom - planes[3] = column4 + column2; // top - planes[4] = column4 - column3; // near - planes[5] = column4 + column3; // far - // ignore near & far plane - - int p; - - for (p = 0; p < 6; p++) // normalize the planes - { - float dot = planes[p].x * planes[p].x + planes[p].y * planes[p].y + planes[p].z * planes[p].z; - dot = 1.f / _sqrt(dot); - planes[p] = planes[p] * dot; - } - - for (p = 0; p < 6; p++) - camPlanes[p] = D3DXPLANE(planes[p].x, planes[p].y, planes[p].z, planes[p].w); - - // build a bit-field that will tell us the indices for the nearest and farthest vertices from each plane... - for (int i = 0; i < 6; i++) - nVertexLUT[i] = ((planes[i].x < 0.f) ? 1 : 0) | ((planes[i].y < 0.f) ? 2 : 0) | ((planes[i].z < 0.f) ? 4 : 0); - - for (int i = 0; i < 8; i++) // compute extrema - { - const D3DXPLANE& p0 = (i & 1) ? camPlanes[4] : camPlanes[5]; - const D3DXPLANE& p1 = (i & 2) ? camPlanes[3] : camPlanes[2]; - const D3DXPLANE& p2 = (i & 4) ? camPlanes[0] : camPlanes[1]; - PlaneIntersection(&pntList[i], &p0, &p1, &p2); - } -} - -////////////////////////////////////////////////////////////////////////// -Fvector3 wform(Fmatrix& m, Fvector3 const& v) -{ - Fvector4 r; - r.x = v.x * m._11 + v.y * m._21 + v.z * m._31 + m._41; - r.y = v.x * m._12 + v.y * m._22 + v.z * m._32 + m._42; - r.z = v.x * m._13 + v.y * m._23 + v.z * m._33 + m._43; - r.w = v.x * m._14 + v.y * m._24 + v.z * m._34 + m._44; - // VERIFY (r.w>0.f); - float invW = 1.0f / r.w; - Fvector3 r3 = {r.x * invW, r.y * invW, r.z * invW}; - return r3; -} - -////////////////////////////////////////////////////////////////////////// -// OLES: naive 3D clipper - roubustness around 0, but works for this sample -// note: normals points to 'outside' -////////////////////////////////////////////////////////////////////////// -const float _eps = 0.000001f; - -struct DumbClipper -{ - CFrustum frustum; - xr_vector planes; - - BOOL clip(D3DXVECTOR3& p0, D3DXVECTOR3& p1) // returns TRUE if result meaningfull - { - float denum; - D3DXVECTOR3 D; - for (int it = 0; it < int(planes.size()); it++) - { - D3DXPLANE& P = planes[it]; - float cls0 = D3DXPlaneDotCoord(&P, &p0); - float cls1 = D3DXPlaneDotCoord(&P, &p1); - if (cls0 > 0 && cls1 > 0) return false; // fully outside - - if (cls0 > 0) - { - // clip p0 - D = p1 - p0; - denum = D3DXPlaneDotNormal(&P, &D); - if (denum != 0) p0 += - D * cls0 / denum; - } - if (cls1 > 0) - { - // clip p1 - D = p0 - p1; - denum = D3DXPlaneDotNormal(&P, &D); - if (denum != 0) p1 += - D * cls1 / denum; - } - } - return true; - } - - D3DXVECTOR3 point(Fbox& bb, int i) const - { - return D3DXVECTOR3((i & 1) ? bb.min.x : bb.max.x, (i & 2) ? bb.min.y : bb.max.y, (i & 4) ? bb.min.z : bb.max.z); - } - - Fbox clipped_AABB(xr_vector>& src, Fmatrix& xf) - { - Fbox3 result; - result.invalidate(); - for (int it = 0; it < int(src.size()); it++) - { - Fbox& bb = src[it]; - u32 mask = frustum.getMask(); - EFC_Visible res = frustum.testAABB(&bb.min.x, mask); - switch (res) - { - case fcvNone: continue; - case fcvFully: - for (int c = 0; c < 8; c++) - { - D3DXVECTOR3 p0 = point(bb, c); - Fvector x0 = wform(xf, *((Fvector*)(&p0))); - result.modify(x0); - } - break; - case fcvPartial: - for (int c0 = 0; c0 < 8; c0++) - { - for (int c1 = 0; c1 < 8; c1++) - { - if (c0 == c1) continue; - D3DXVECTOR3 p0 = point(bb, c0); - D3DXVECTOR3 p1 = point(bb, c1); - if (!clip(p0, p1)) continue; - Fvector x0 = wform(xf, *((Fvector*)(&p0))); - Fvector x1 = wform(xf, *((Fvector*)(&p1))); - result.modify(x0); - result.modify(x1); - } - } - break; - }; - } - return result; - } -}; - -template -inline const _Tp& min(const _Tp& __a, const _Tp& __b) -{ - return __b < __a ? __b : __a; -} - -template -inline const _Tp& max(const _Tp& __a, const _Tp& __b) -{ - return __a < __b ? __b : __a; -} - -xr_vector> s_casters; - -D3DXVECTOR2 BuildTSMProjectionMatrix_caster_depth_bounds(D3DXMATRIX& lightSpaceBasis) -{ - float min_z = 1e32f, max_z = -1e32f; - D3DXMATRIX minmax_xf; - D3DXMatrixMultiply(&minmax_xf, (D3DXMATRIX*)&Device.mView, &lightSpaceBasis); - Fmatrix& minmax_xform = *((Fmatrix*)&minmax_xf); - for (u32 c = 0; c < s_casters.size(); c++) - { - Fvector3 pt; - for (int e = 0; e < 8; e++) - { - s_casters[c].getpoint(e, pt); - pt = wform(minmax_xform, pt); - min_z = _min(min_z, pt.z); - max_z = _max(max_z, pt.z); - } - } - return D3DXVECTOR2(min_z, max_z); -} - -void CRender::render_sun() -{ - PIX_EVENT(render_sun); - light* fuckingsun = (light*)Lights.sun_adapted._get(); - D3DXMATRIX m_LightViewProj; - - // calculate view-frustum bounds in world space - Fmatrix ex_project, ex_full, ex_full_inverse; - { - float _far_ = min(OLES_SUN_LIMIT_27_01_07, g_pGamePersistent->Environment().CurrentEnv->far_plane); - //ex_project.build_projection (deg2rad(Device.fFOV/* *Device.fASPECT*/),Device.fASPECT,ps_r2_sun_near,_far_); - ex_project.build_projection(deg2rad(Device.fFOV/* *Device.fASPECT*/), Device.fASPECT,VIEWPORT_NEAR, _far_); - //VIEWPORT_NEAR - ex_full.mul(ex_project, Device.mView); - D3DXMatrixInverse((D3DXMATRIX*)&ex_full_inverse, 0, (D3DXMATRIX*)&ex_full); - } - - // Compute volume(s) - something like a frustum for infinite directional light - // Also compute virtual light position and sector it is inside - CFrustum cull_frustum; - xr_vector cull_planes; - Fvector3 cull_COP; - CSector* cull_sector; - Fmatrix cull_xform; - { - FPU::m64r(); - // Lets begin from base frustum - Fmatrix fullxform_inv = ex_full_inverse; - DumbConvexVolume hull; - { - hull.points.reserve(8); - for (int p = 0; p < 8; p++) - { - Fvector3 xf = wform(fullxform_inv, corners[p]); - hull.points.push_back(xf); - } - for (int plane = 0; plane < 6; plane++) - { - hull.polys.push_back(DumbConvexVolume::_poly()); - for (int pt = 0; pt < 4; pt++) - hull.polys.back().points.push_back(facetable[plane][pt]); - } - } - hull.compute_caster_model(cull_planes, fuckingsun->direction); - - // Search for default sector - assume "default" or "outdoor" sector is the largest one - //. hack: need to know real outdoor sector - CSector* largest_sector = 0; - float largest_sector_vol = 0; - for (u32 s = 0; s < Sectors.size(); s++) - { - CSector* S = (CSector*)Sectors[s]; - dxRender_Visual* V = S->root(); - float vol = V->vis.box.getvolume(); - if (vol > largest_sector_vol) - { - largest_sector_vol = vol; - largest_sector = S; - } - } - cull_sector = largest_sector; - - // COP - 100 km away - cull_COP.mad(Device.vCameraPosition, fuckingsun->direction, -tweak_COP_initial_offs); - - // Create frustum for query - cull_frustum._clear(); - for (u32 p = 0; p < cull_planes.size(); p++) - cull_frustum._add(cull_planes[p]); - - // Create approximate ortho-xform - // view: auto find 'up' and 'right' vectors - Fmatrix mdir_View, mdir_Project; - Fvector L_dir, L_up, L_right, L_pos; - L_pos.set(fuckingsun->position); - L_dir.set(fuckingsun->direction).normalize(); - L_up.set(0, 1, 0); - if (_abs(L_up.dotproduct(L_dir)) > .99f) L_up.set(0, 0, 1); - L_right.crossproduct(L_up, L_dir).normalize(); - L_up.crossproduct(L_dir, L_right).normalize(); - mdir_View.build_camera_dir(L_pos, L_dir, L_up); - - // projection: box - Fbox frustum_bb; - frustum_bb.invalidate(); - for (int it = 0; it < 8; it++) - { - Fvector xf = wform(mdir_View, hull.points[it]); - frustum_bb.modify(xf); - } - Fbox& bb = frustum_bb; - bb.grow(EPS); - D3DXMatrixOrthoOffCenterLH((D3DXMATRIX*)&mdir_Project, bb.min.x, bb.max.x, bb.min.y, bb.max.y, - bb.min.z - tweak_ortho_xform_initial_offs, bb.max.z); - - // full-xform - cull_xform.mul(mdir_Project, mdir_View); - FPU::m24r(); - } - - // Begin SMAP-render - { - HOM.Disable(); - phase = PHASE_SMAP; - if (RImplementation.o.Tshadows) r_pmask(true, true); - else r_pmask(true, false); - // fuckingsun->svis.begin (); - } - - // Fill the database - xr_vector>& s_receivers = main_coarse_structure; - s_casters.reserve(s_receivers.size()); - set_Recorder(&s_casters); - r_dsgraph_render_subspace(cull_sector, &cull_frustum, cull_xform, cull_COP, TRUE); - - // IGNORE PORTALS - if (ps_r2_ls_flags.test(R2FLAG_SUN_IGNORE_PORTALS)) - { - for (u32 s = 0; s < Sectors.size(); s++) - { - CSector* S = (CSector*)Sectors[s]; - dxRender_Visual* root = S->root(); - - set_Frustum(&cull_frustum); - add_Geometry(root); - } - } - set_Recorder(NULL); - - // Prepare to interact with D3DX code - const D3DXMATRIX& m_View = *((D3DXMATRIX*)(&Device.mView)); - const D3DXMATRIX& m_Projection = *((D3DXMATRIX*)(&ex_project)); - const D3DXVECTOR3 m_lightDir = -D3DXVECTOR3(fuckingsun->direction.x, fuckingsun->direction.y, - fuckingsun->direction.z); - - // these are the limits specified by the physical camera - // gamma is the "tilt angle" between the light and the view direction. - float m_fCosGamma = m_lightDir.x * m_View._13 + - m_lightDir.y * m_View._23 + - m_lightDir.z * m_View._33; - float m_fTSM_Delta = ps_r2_sun_tsm_projection; - - // Compute REAL sheared xform based on receivers/casters information - FPU::m64r(); - if (_abs(m_fCosGamma) < 0.99f && ps_r2_ls_flags.test(R2FLAG_SUN_TSM)) - { - // get the near and the far plane (points) in eye space. - D3DXVECTOR3 frustumPnts[8]; - - Frustum eyeFrustum(&m_Projection); // autocomputes all the extrema points - - for (int i = 0; i < 4; i++) - { - frustumPnts[i] = eyeFrustum.pntList[(i << 1)]; // far plane - frustumPnts[i + 4] = eyeFrustum.pntList[(i << 1) | 0x1]; // near plane - } - - // we need to transform the eye into the light's post-projective space. - // however, the sun is a directional light, so we first need to find an appropriate - // rotate/translate matrix, before constructing an ortho projection. - // this matrix is a variant of "light space" from LSPSMs, with the Y and Z axes permuted - - D3DXVECTOR3 leftVector, upVector, viewVector; - const D3DXVECTOR3 eyeVector(0.f, 0.f, -1.f); // eye is always -Z in eye space - - // code copied straight from BuildLSPSMProjectionMatrix - D3DXVec3TransformNormal(&upVector, &m_lightDir, &m_View); // lightDir is defined in eye space, so xform it - D3DXVec3Cross(&leftVector, &upVector, &eyeVector); - D3DXVec3Normalize(&leftVector, &leftVector); - D3DXVec3Cross(&viewVector, &upVector, &leftVector); - - D3DXMATRIX lightSpaceBasis; - lightSpaceBasis._11 = leftVector.x; - lightSpaceBasis._12 = viewVector.x; - lightSpaceBasis._13 = -upVector.x; - lightSpaceBasis._14 = 0.f; - lightSpaceBasis._21 = leftVector.y; - lightSpaceBasis._22 = viewVector.y; - lightSpaceBasis._23 = -upVector.y; - lightSpaceBasis._24 = 0.f; - lightSpaceBasis._31 = leftVector.z; - lightSpaceBasis._32 = viewVector.z; - lightSpaceBasis._33 = -upVector.z; - lightSpaceBasis._34 = 0.f; - lightSpaceBasis._41 = 0.f; - lightSpaceBasis._42 = 0.f; - lightSpaceBasis._43 = 0.f; - lightSpaceBasis._44 = 1.f; - - // rotate the view frustum into light space - D3DXVec3TransformCoordArray(frustumPnts, sizeof(D3DXVECTOR3), frustumPnts, sizeof(D3DXVECTOR3), - &lightSpaceBasis, sizeof(frustumPnts) / sizeof(D3DXVECTOR3)); - - // build an off-center ortho projection that translates and scales the eye frustum's 3D AABB to the unit cube - BoundingBox frustumBox(frustumPnts, sizeof(frustumPnts) / sizeof(D3DXVECTOR3)); - - // also - transform the shadow caster bounding boxes into light projective space. we want to translate along the Z axis so that - // all shadow casters are in front of the near plane. - D3DXVECTOR2 depthbounds = BuildTSMProjectionMatrix_caster_depth_bounds(lightSpaceBasis); - - float min_z = min(depthbounds.x, frustumBox.minPt.z); - float max_z = max(depthbounds.y, frustumBox.maxPt.z); - - if (min_z <= 1.f) //? - { - D3DXMATRIX lightSpaceTranslate; - D3DXMatrixTranslation(&lightSpaceTranslate, 0.f, 0.f, -min_z + 1.f); - max_z = -min_z + max_z + 1.f; - min_z = 1.f; - D3DXMatrixMultiply(&lightSpaceBasis, &lightSpaceBasis, &lightSpaceTranslate); - D3DXVec3TransformCoordArray(frustumPnts, sizeof(D3DXVECTOR3), frustumPnts, sizeof(D3DXVECTOR3), - &lightSpaceTranslate, sizeof(frustumPnts) / sizeof(D3DXVECTOR3)); - frustumBox = BoundingBox(frustumPnts, sizeof(frustumPnts) / sizeof(D3DXVECTOR3)); - } - - D3DXMATRIX lightSpaceOrtho; - D3DXMatrixOrthoOffCenterLH(&lightSpaceOrtho, frustumBox.minPt.x, frustumBox.maxPt.x, frustumBox.minPt.y, - frustumBox.maxPt.y, min_z, max_z); - - // transform the view frustum by the new matrix - D3DXVec3TransformCoordArray(frustumPnts, sizeof(D3DXVECTOR3), frustumPnts, sizeof(D3DXVECTOR3), - &lightSpaceOrtho, sizeof(frustumPnts) / sizeof(D3DXVECTOR3)); - - D3DXVECTOR2 centerPts [2]; - // near plane - centerPts[0].x = 0.25f * (frustumPnts[4].x + frustumPnts[5].x + frustumPnts[6].x + frustumPnts[7].x); - centerPts[0].y = 0.25f * (frustumPnts[4].y + frustumPnts[5].y + frustumPnts[6].y + frustumPnts[7].y); - // far plane - centerPts[1].x = 0.25f * (frustumPnts[0].x + frustumPnts[1].x + frustumPnts[2].x + frustumPnts[3].x); - centerPts[1].y = 0.25f * (frustumPnts[0].y + frustumPnts[1].y + frustumPnts[2].y + frustumPnts[3].y); - - D3DXVECTOR2 centerOrig = (centerPts[0] + centerPts[1]) * 0.5f; - - D3DXMATRIX trapezoid_space; - - D3DXMATRIX xlate_center(1.f, 0.f, 0.f, 0.f, - 0.f, 1.f, 0.f, 0.f, - 0.f, 0.f, 1.f, 0.f, - -centerOrig.x, -centerOrig.y, 0.f, 1.f); - - D3DXVECTOR2 center_dirl = D3DXVECTOR2(centerPts[1] - centerOrig); - float half_center_len = D3DXVec2Length(¢er_dirl); - float x_len = centerPts[1].x - centerOrig.x; - float y_len = centerPts[1].y - centerOrig.y; - - float cos_theta = x_len / half_center_len; - float sin_theta = y_len / half_center_len; - - D3DXMATRIX rot_center(cos_theta, -sin_theta, 0.f, 0.f, - sin_theta, cos_theta, 0.f, 0.f, - 0.f, 0.f, 1.f, 0.f, - 0.f, 0.f, 0.f, 1.f); - - // this matrix transforms the center line to y=0. - // since Top and Base are orthogonal to Center, we can skip computing the convex hull, and instead - // just find the view frustum X-axis extrema. The most negative is Top, the most positive is Base - // Point Q (trapezoid projection point) will be a point on the y=0 line. - D3DXMatrixMultiply(&trapezoid_space, &xlate_center, &rot_center); - D3DXVec3TransformCoordArray(frustumPnts, sizeof(D3DXVECTOR3), frustumPnts, sizeof(D3DXVECTOR3), - &trapezoid_space, sizeof(frustumPnts) / sizeof(D3DXVECTOR3)); - - BoundingBox frustumAABB2D(frustumPnts, sizeof(frustumPnts) / sizeof(D3DXVECTOR3)); - - float x_scale = max(_abs(frustumAABB2D.maxPt.x), _abs(frustumAABB2D.minPt.x)); - float y_scale = max(_abs(frustumAABB2D.maxPt.y), _abs(frustumAABB2D.minPt.y)); - x_scale = 1.f / x_scale; - y_scale = 1.f / y_scale; - - // maximize the area occupied by the bounding box - D3DXMATRIX scale_center(x_scale, 0.f, 0.f, 0.f, - 0.f, y_scale, 0.f, 0.f, - 0.f, 0.f, 1.f, 0.f, - 0.f, 0.f, 0.f, 1.f); - - D3DXMatrixMultiply(&trapezoid_space, &trapezoid_space, &scale_center); - - // scale the frustum AABB up by these amounts (keep all values in the same space) - frustumAABB2D.minPt.x *= x_scale; - frustumAABB2D.maxPt.x *= x_scale; - frustumAABB2D.minPt.y *= y_scale; - frustumAABB2D.maxPt.y *= y_scale; - - // compute eta. - float lambda = frustumAABB2D.maxPt.x - frustumAABB2D.minPt.x; - float delta_proj = m_fTSM_Delta * lambda; //focusPt.x - frustumAABB2D.minPt.x; - const float xi = -0.6f; // - 0.6f; // 80% line - float eta = (lambda * delta_proj * (1.f + xi)) / (lambda * (1.f - xi) - 2.f * delta_proj); - - // compute the projection point a distance eta from the top line. this point is on the center line, y=0 - D3DXVECTOR2 projectionPtQ(frustumAABB2D.maxPt.x + eta, 0.f); - - // find the maximum slope from the projection point to any point in the frustum. this will be the - // projection field-of-view - float max_slope = -1e32f; - float min_slope = 1e32f; - - for (int i = 0; i < sizeof(frustumPnts) / sizeof(D3DXVECTOR3); i++) - { - D3DXVECTOR2 tmp(frustumPnts[i].x * x_scale, frustumPnts[i].y * y_scale); - float x_dist = tmp.x - projectionPtQ.x; - if (!(ALMOST_ZERO(tmp.y) || ALMOST_ZERO(x_dist))) - { - max_slope = max(max_slope, tmp.y / x_dist); - min_slope = min(min_slope, tmp.y / x_dist); - } - } - - float xn = eta; - float xf = lambda + eta; - - D3DXMATRIX ptQ_xlate(-1.f, 0.f, 0.f, 0.f, - 0.f, 1.f, 0.f, 0.f, - 0.f, 0.f, 1.f, 0.f, - projectionPtQ.x, 0.f, 0.f, 1.f); - D3DXMatrixMultiply(&trapezoid_space, &trapezoid_space, &ptQ_xlate); - - // this shear balances the "trapezoid" around the y=0 axis (no change to the projection pt position) - // since we are redistributing the trapezoid, this affects the projection field of view (shear_amt) - float shear_amt = (max_slope + _abs(min_slope)) * 0.5f - max_slope; - max_slope = max_slope + shear_amt; - - D3DXMATRIX trapezoid_shear(1.f, shear_amt, 0.f, 0.f, - 0.f, 1.f, 0.f, 0.f, - 0.f, 0.f, 1.f, 0.f, - 0.f, 0.f, 0.f, 1.f); - - D3DXMatrixMultiply(&trapezoid_space, &trapezoid_space, &trapezoid_shear); - - - float z_aspect = (frustumBox.maxPt.z - frustumBox.minPt.z) / (frustumAABB2D.maxPt.y - frustumAABB2D.minPt.y); - - // perform a 2DH projection to 'unsqueeze' the top line. - D3DXMATRIX trapezoid_projection(xf / (xf - xn), 0.f, 0.f, 1.f, - 0.f, 1.f / max_slope, 0.f, 0.f, - 0.f, 0.f, 1.f / (z_aspect * max_slope), 0.f, - -xn * xf / (xf - xn), 0.f, 0.f, 0.f); - - D3DXMatrixMultiply(&trapezoid_space, &trapezoid_space, &trapezoid_projection); - - // the x axis is compressed to [0..1] as a result of the projection, so expand it to [-1,1] - D3DXMATRIX biasedScaleX(2.f, 0.f, 0.f, 0.f, - 0.f, 1.f, 0.f, 0.f, - 0.f, 0.f, 1.f, 0.f, - -1.f, 0.f, 0.f, 1.f); - D3DXMatrixMultiply(&trapezoid_space, &trapezoid_space, &biasedScaleX); - - D3DXMatrixMultiply(&m_LightViewProj, &m_View, &lightSpaceBasis); - D3DXMatrixMultiply(&m_LightViewProj, &m_LightViewProj, &lightSpaceOrtho); - D3DXMatrixMultiply(&m_LightViewProj, &m_LightViewProj, &trapezoid_space); - } - else - { - m_LightViewProj = *((D3DXMATRIX*)(&cull_xform)); - } - FPU::m24r(); - - // perform "refit" or "focusing" on relevant - if (ps_r2_ls_flags.test(R2FLAG_SUN_FOCUS)) - { - FPU::m64r(); - - // create clipper - DumbClipper view_clipper; - Fmatrix& xform = *((Fmatrix*)&m_LightViewProj); - view_clipper.frustum.CreateFromMatrix(ex_full,FRUSTUM_P_ALL); - for (int p = 0; p < view_clipper.frustum.p_count; p++) - { - Fplane& P = view_clipper.frustum.planes[p]; - view_clipper.planes.push_back(D3DXPLANE(P.n.x, P.n.y, P.n.z, P.d)); - } - - // - Fbox3 b_casters, b_receivers; - Fvector3 pt; - - // casters - b_casters.invalidate(); - for (u32 c = 0; c < s_casters.size(); c++) - { - for (int e = 0; e < 8; e++) - { - s_casters[c].getpoint(e, pt); - pt = wform(xform, pt); - b_casters.modify(pt); - } - } - - // receivers - b_receivers.invalidate(); - b_receivers = view_clipper.clipped_AABB(s_receivers, xform); - Fmatrix x_project, x_full, x_full_inverse; - { - x_project.build_projection(deg2rad(Device.fFOV/* *Device.fASPECT*/), Device.fASPECT, ps_r2_sun_near, - ps_r2_sun_near + tweak_guaranteed_range); - x_project.build_projection(deg2rad(Device.fFOV/* *Device.fASPECT*/), Device.fASPECT,VIEWPORT_NEAR, - ps_r2_sun_near + tweak_guaranteed_range); - x_full.mul(x_project, Device.mView); - D3DXMatrixInverse((D3DXMATRIX*)&x_full_inverse, 0, (D3DXMATRIX*)&x_full); - } - for (int e = 0; e < 8; e++) - { - pt = wform(x_full_inverse, corners[e]); // world space - pt = wform(xform, pt); // trapezoid space - b_receivers.modify(pt); - } - - // some tweaking - b_casters.grow(EPS); - b_receivers.grow(EPS); - - // because caster points are from coarse representation only allow to "shrink" box, not grow - // that is the same as if we first clip casters by frustum - if (b_receivers.min.x < -1) b_receivers.min.x = -1; - if (b_receivers.min.y < -1) b_receivers.min.y = -1; - if (b_casters.min.z < 0) b_casters.min.z = 0; - if (b_receivers.max.x > +1) b_receivers.max.x = +1; - if (b_receivers.max.y > +1) b_receivers.max.y = +1; - if (b_casters.max.z > +1) b_casters.max.z = +1; - - // refit? - /* - const float EPS = 0.001f; - D3DXMATRIX refit; - D3DXMatrixOrthoOffCenterLH ( &refit, b_receivers.min.x, b_receivers.max.x, b_receivers.min.y, b_receivers.max.y, b_casters.min.z-EPS, b_casters.max.z+EPS ); - D3DXMatrixMultiply ( &m_LightViewProj, &m_LightViewProj, &refit); - */ - - float boxWidth = b_receivers.max.x - b_receivers.min.x; - float boxHeight = b_receivers.max.y - b_receivers.min.y; - // the divide by two's cancel out in the translation, but included for clarity - float boxX = (b_receivers.max.x + b_receivers.min.x) / 2.f; - float boxY = (b_receivers.max.y + b_receivers.min.y) / 2.f; - D3DXMATRIX trapezoidUnitCube(2.f / boxWidth, 0.f, 0.f, 0.f, - 0.f, 2.f / boxHeight, 0.f, 0.f, - 0.f, 0.f, 1.f, 0.f, - -2.f * boxX / boxWidth, -2.f * boxY / boxHeight, 0.f, 1.f); - D3DXMatrixMultiply(&m_LightViewProj, &m_LightViewProj, &trapezoidUnitCube); - //D3DXMatrixMultiply( &trapezoid_space, &trapezoid_space, &trapezoidUnitCube ); - FPU::m24r(); - } - - // Finalize & Cleanup - fuckingsun->X.D.combine = *((Fmatrix*)&m_LightViewProj); - s_receivers.clear(); - s_casters.clear(); - - // Render shadow-map - //. !!! We should clip based on shrinked frustum (again) - { - bool bNormal = mapNormalPasses[0][0].size() || mapMatrixPasses[0][0].size(); - bool bSpecial = mapNormalPasses[1][0].size() || mapMatrixPasses[1][0].size() || mapSorted.size(); - if (bNormal || bSpecial) - { - Target->phase_smap_direct(fuckingsun, SE_SUN_FAR); - RCache.set_xform_world(Fidentity); - RCache.set_xform_view(Fidentity); - RCache.set_xform_project(fuckingsun->X.D.combine); - r_dsgraph_render_graph(0); - fuckingsun->X.D.transluent = FALSE; - if (bSpecial) - { - fuckingsun->X.D.transluent = TRUE; - Target->phase_smap_direct_tsh(fuckingsun, SE_SUN_FAR); - r_dsgraph_render_graph(1); // normal level, secondary priority - r_dsgraph_render_sorted(); // strict-sorted geoms - } - } - } - - // End SMAP-render - { - // fuckingsun->svis.end (); - r_pmask(true, false); - } - - // Accumulate - Target->phase_accumulator(); - - if (Target->use_minmax_sm_this_frame()) - { - PIX_EVENT(SE_SUN_FAR_MINMAX_GENERATE); - Target->create_minmax_SM(); - } - - PIX_EVENT(SE_SUN_FAR); - Target->accum_direct(SE_SUN_FAR); - - // Restore XForms - RCache.set_xform_world(Fidentity); - RCache.set_xform_view(Device.mView); - RCache.set_xform_project(Device.mProject); -} - -void CRender::render_sun_near() -{ - light* fuckingsun = (light*)Lights.sun_adapted._get(); - D3DXMATRIX m_LightViewProj; - - // calculate view-frustum bounds in world space - Fmatrix ex_project, ex_full, ex_full_inverse; - { - ex_project.build_projection(deg2rad(Device.fFOV/* *Device.fASPECT*/), Device.fASPECT,VIEWPORT_NEAR, - ps_r2_sun_near); - ex_full.mul(ex_project, Device.mView); - D3DXMatrixInverse((D3DXMATRIX*)&ex_full_inverse, 0, (D3DXMATRIX*)&ex_full); - } - - // Compute volume(s) - something like a frustum for infinite directional light - // Also compute virtual light position and sector it is inside - CFrustum cull_frustum; - xr_vector cull_planes; - Fvector3 cull_COP; - CSector* cull_sector; - Fmatrix cull_xform; - { - FPU::m64r(); - // Lets begin from base frustum - Fmatrix fullxform_inv = ex_full_inverse; -#ifdef _DEBUG - typedef DumbConvexVolume t_volume; -#else - typedef DumbConvexVolume t_volume; -#endif - t_volume hull; - { - hull.points.reserve(9); - for (int p = 0; p < 8; p++) - { - Fvector3 xf = wform(fullxform_inv, corners[p]); - hull.points.push_back(xf); - } - for (int plane = 0; plane < 6; plane++) - { - hull.polys.push_back(t_volume::_poly()); - for (int pt = 0; pt < 4; pt++) - hull.polys.back().points.push_back(facetable[plane][pt]); - } - } - hull.compute_caster_model(cull_planes, fuckingsun->direction); -#ifdef _DEBUG - for (u32 it=0; itdbg_addplane(cull_planes[it],0xffffffff); -#endif - - // Search for default sector - assume "default" or "outdoor" sector is the largest one - //. hack: need to know real outdoor sector - CSector* largest_sector = 0; - float largest_sector_vol = 0; - for (u32 s = 0; s < Sectors.size(); s++) - { - CSector* S = (CSector*)Sectors[s]; - dxRender_Visual* V = S->root(); - float vol = V->vis.box.getvolume(); - if (vol > largest_sector_vol) - { - largest_sector_vol = vol; - largest_sector = S; - } - } - cull_sector = largest_sector; - - // COP - 100 km away - cull_COP.mad(Device.vCameraPosition, fuckingsun->direction, -tweak_COP_initial_offs); - - // Create frustum for query - cull_frustum._clear(); - for (u32 p = 0; p < cull_planes.size(); p++) - cull_frustum._add(cull_planes[p]); - - // Create approximate ortho-xform - // view: auto find 'up' and 'right' vectors - Fmatrix mdir_View, mdir_Project; - Fvector L_dir, L_up, L_right, L_pos; - L_pos.set(fuckingsun->position); - L_dir.set(fuckingsun->direction).normalize(); - L_right.set(1, 0, 0); - if (_abs(L_right.dotproduct(L_dir)) > .99f) L_right.set(0, 0, 1); - L_up.crossproduct(L_dir, L_right).normalize(); - L_right.crossproduct(L_up, L_dir).normalize(); - mdir_View.build_camera_dir(L_pos, L_dir, L_up); - - // projection: box - /* - // Original - float _D = ps_r2_sun_near; - float a0 = deg2rad(Device.fFOV*Device.fASPECT)/2.f; - float a1 = deg2rad(Device.fFOV)/2.f; - float c0 = _D/_cos(a0); - float c1 = _D/_cos(a1); - float k0 = 2.f*c0*_sin(a0); - float k1 = 2.f*c1*_sin(a1); - float borderalpha = (Device.fFOV-10) / (90-10); - - float nearborder = 1*borderalpha + 1.136363636364f*(1-borderalpha); - float spherical_range = ps_r2_sun_near_border * nearborder * _max(_max(c0,c1), _max(k0,k1)*1.414213562373f ); - Fbox frustum_bb; frustum_bb.invalidate (); - hull.points.push_back (Device.vCameraPosition); - for (int it=0; it<9; it++) { - Fvector xf = wform (mdir_View,hull.points[it]); - frustum_bb.modify (xf); - } - float size_x = frustum_bb.max.x - frustum_bb.min.x; - float size_y = frustum_bb.max.y - frustum_bb.min.y; - float diff_x = (spherical_range - size_x)/2.f; //VERIFY(diff_x>=0); - float diff_y = (spherical_range - size_y)/2.f; //VERIFY(diff_y>=0); - frustum_bb.min.x -= diff_x; frustum_bb.max.x += diff_x; - frustum_bb.min.y -= diff_y; frustum_bb.max.y += diff_y; - Fbox& bb = frustum_bb; - D3DXMatrixOrthoOffCenterLH ((D3DXMATRIX*)&mdir_Project,bb.min.x,bb.max.x, bb.min.y,bb.max.y, bb.min.z-tweak_ortho_xform_initial_offs,bb.max.z); - /**/ - - // Simple - Fbox frustum_bb; - frustum_bb.invalidate(); - for (int it = 0; it < 8; it++) - { - //for (int it=0; it<9; it++) { - Fvector xf = wform(mdir_View, hull.points[it]); - frustum_bb.modify(xf); - } - Fbox& bb = frustum_bb; - bb.grow(EPS); - D3DXMatrixOrthoOffCenterLH((D3DXMATRIX*)&mdir_Project, bb.min.x, bb.max.x, bb.min.y, bb.max.y, - bb.min.z - tweak_ortho_xform_initial_offs, bb.max.z); - /**/ - - - // build viewport xform - float view_dim = float(RImplementation.o.smapsize); - Fmatrix m_viewport = { - view_dim / 2.f, 0.0f, 0.0f, 0.0f, - 0.0f, -view_dim / 2.f, 0.0f, 0.0f, - 0.0f, 0.0f, 1.0f, 0.0f, - view_dim / 2.f, view_dim / 2.f, 0.0f, 1.0f - }; - Fmatrix m_viewport_inv; - D3DXMatrixInverse((D3DXMATRIX*)&m_viewport_inv, 0, (D3DXMATRIX*)&m_viewport); - - // snap view-position to pixel - cull_xform.mul(mdir_Project, mdir_View); - Fvector cam_proj = wform(cull_xform, Device.vCameraPosition); - Fvector cam_pixel = wform(m_viewport, cam_proj); - cam_pixel.x = floorf(cam_pixel.x); - cam_pixel.y = floorf(cam_pixel.y); - Fvector cam_snapped = wform(m_viewport_inv, cam_pixel); - Fvector diff; - diff.sub(cam_snapped, cam_proj); - Fmatrix adjust; - adjust.translate(diff); - cull_xform.mulA_44(adjust); - - // calculate scissor - Fbox scissor; - scissor.invalidate(); - Fmatrix scissor_xf; - scissor_xf.mul(m_viewport, cull_xform); - for (int it = 0; it < 9; it++) - { - Fvector xf = wform(scissor_xf, hull.points[it]); - scissor.modify(xf); - } - s32 limit = RImplementation.o.smapsize - 1; - fuckingsun->X.D.minX = clampr(iFloor(scissor.min.x), 0, limit); - fuckingsun->X.D.maxX = clampr(iCeil(scissor.max.x), 0, limit); - fuckingsun->X.D.minY = clampr(iFloor(scissor.min.y), 0, limit); - fuckingsun->X.D.maxY = clampr(iCeil(scissor.max.y), 0, limit); - - // full-xform - FPU::m24r(); - } - - // Begin SMAP-render - { - bool bSpecialFull = mapNormalPasses[1][0].size() || mapMatrixPasses[1][0].size() || mapSorted.size(); - VERIFY(!bSpecialFull); - HOM.Disable(); - phase = PHASE_SMAP; - if (RImplementation.o.Tshadows) r_pmask(true, true); - else r_pmask(true, false); - // fuckingsun->svis.begin (); - } - - // Fill the database - r_dsgraph_render_subspace(cull_sector, &cull_frustum, cull_xform, cull_COP, TRUE); - - // Finalize & Cleanup - fuckingsun->X.D.combine = cull_xform; //*((Fmatrix*)&m_LightViewProj); - - // Render shadow-map - //. !!! We should clip based on shrinked frustum (again) - { - bool bNormal = mapNormalPasses[0][0].size() || mapMatrixPasses[0][0].size(); - bool bSpecial = mapNormalPasses[1][0].size() || mapMatrixPasses[1][0].size() || mapSorted.size(); - if (bNormal || bSpecial) - { - Target->phase_smap_direct(fuckingsun, SE_SUN_NEAR); - RCache.set_xform_world(Fidentity); - RCache.set_xform_view(Fidentity); - RCache.set_xform_project(fuckingsun->X.D.combine); - r_dsgraph_render_graph(0); - if (ps_r2_ls_flags.test(R2FLAG_SUN_DETAILS)) - Details->Render(); - fuckingsun->X.D.transluent = FALSE; - if (bSpecial) - { - fuckingsun->X.D.transluent = TRUE; - Target->phase_smap_direct_tsh(fuckingsun, SE_SUN_NEAR); - r_dsgraph_render_graph(1); // normal level, secondary priority - r_dsgraph_render_sorted(); // strict-sorted geoms - } - } - } - - // End SMAP-render - { - // fuckingsun->svis.end (); - r_pmask(true, false); - } - - // Accumulate - Target->phase_accumulator(); - - if (Target->use_minmax_sm_this_frame()) - { - PIX_EVENT(SE_SUN_NEAR_MINMAX_GENERATE); - Target->create_minmax_SM(); - } - - PIX_EVENT(SE_SUN_NEAR); - Target->accum_direct(SE_SUN_NEAR); - - // Restore XForms - RCache.set_xform_world(Fidentity); - RCache.set_xform_view(Device.mView); - RCache.set_xform_project(Device.mProject); -} - -void CRender::render_sun_filtered() -{ - if (!RImplementation.o.sunfilter) return; - Target->phase_accumulator(); - PIX_EVENT(SE_SUN_LUMINANCE); - Target->accum_direct(SE_SUN_LUMINANCE); -} - -void CRender::init_cacades() -{ - u32 cascade_count = 3; - m_sun_cascades.resize(cascade_count); - - float fBias = -0.0000025f; - // float size = MAP_SIZE_START; - m_sun_cascades[0].reset_chain = true; - m_sun_cascades[0].size = 20; - m_sun_cascades[0].bias = m_sun_cascades[0].size * fBias; - - m_sun_cascades[1].size = 40; - m_sun_cascades[1].bias = m_sun_cascades[1].size * fBias; - - m_sun_cascades[2].size = 160; - m_sun_cascades[2].bias = m_sun_cascades[2].size * fBias; - - // for( u32 i = 0; i < cascade_count; ++i ) - // { - // m_sun_cascades[i].size = size; - // size *= MAP_GROW_FACTOR; - // } - /// m_sun_cascades[m_sun_cascades.size()-1].size = 80; -} - -void CRender::render_sun_cascades() -{ - bool b_need_to_render_sunshafts = RImplementation.Target->need_to_render_sunshafts(); - bool last_cascade_chain_mode = m_sun_cascades.back().reset_chain; - if (b_need_to_render_sunshafts) - m_sun_cascades[m_sun_cascades.size() - 1].reset_chain = true; - - for (u32 i = 0; i < m_sun_cascades.size(); ++i) - render_sun_cascade(i); - - if (b_need_to_render_sunshafts) - m_sun_cascades[m_sun_cascades.size() - 1].reset_chain = last_cascade_chain_mode; -} - -void CRender::render_sun_cascade(u32 cascade_ind) -{ - light* fuckingsun = (light*)Lights.sun_adapted._get(); - - // calculate view-frustum bounds in world space - Fmatrix ex_project, ex_full, ex_full_inverse; - { - ex_project = Device.mProject; - ex_full.mul(ex_project, Device.mView); - D3DXMatrixInverse((D3DXMATRIX*)&ex_full_inverse, 0, (D3DXMATRIX*)&ex_full); - } - - // Compute volume(s) - something like a frustum for infinite directional light - // Also compute virtual light position and sector it is inside - CFrustum cull_frustum; - xr_vector cull_planes; - Fvector3 cull_COP; - CSector* cull_sector; - Fmatrix cull_xform; - { - FPU::m64r(); - // Lets begin from base frustum - Fmatrix fullxform_inv = ex_full_inverse; -#ifdef _DEBUG - typedef DumbConvexVolume t_volume; -#else - typedef DumbConvexVolume t_volume; -#endif - - //******************************* Need to be placed after cuboid built ************************** - // Search for default sector - assume "default" or "outdoor" sector is the largest one - //. hack: need to know real outdoor sector - CSector* largest_sector = 0; - float largest_sector_vol = 0; - for (u32 s = 0; s < Sectors.size(); s++) - { - CSector* S = (CSector*)Sectors[s]; - dxRender_Visual* V = S->root(); - float vol = V->vis.box.getvolume(); - if (vol > largest_sector_vol) - { - largest_sector_vol = vol; - largest_sector = S; - } - } - cull_sector = largest_sector; - - // COP - 100 km away - cull_COP.mad(Device.vCameraPosition, fuckingsun->direction, -tweak_COP_initial_offs); - - // Create approximate ortho-xform - // view: auto find 'up' and 'right' vectors - Fmatrix mdir_View, mdir_Project; - Fvector L_dir, L_up, L_right, L_pos; - L_pos.set(fuckingsun->position); - L_dir.set(fuckingsun->direction).normalize(); - L_right.set(1, 0, 0); - if (_abs(L_right.dotproduct(L_dir)) > .99f) L_right.set(0, 0, 1); - L_up.crossproduct(L_dir, L_right).normalize(); - L_right.crossproduct(L_up, L_dir).normalize(); - mdir_View.build_camera_dir(L_pos, L_dir, L_up); - - - ////////////////////////////////////////////////////////////////////////// -#ifdef _DEBUG - typedef FixedConvexVolume t_cuboid; -#else - typedef FixedConvexVolume t_cuboid; -#endif - - t_cuboid light_cuboid; - { - // Initialize the first cascade rays, then each cascade will initialize rays for next one. - if (cascade_ind == 0 || m_sun_cascades[cascade_ind].reset_chain) - { - Fvector3 near_p, edge_vec; - for (int p = 0; p < 4; p++) - { - // Fvector asd = Device.vCameraDirection; - // asd.mul(-2); - // asd.add(Device.vCameraPosition); - // near_p = Device.vCameraPosition;//wform (fullxform_inv,asd); // - near_p = wform(fullxform_inv, corners[facetable[4][p]]); - - edge_vec = wform(fullxform_inv, corners[facetable[5][p]]); - edge_vec.sub(near_p); - edge_vec.normalize(); - - light_cuboid.view_frustum_rays.push_back(sun::ray(near_p, edge_vec)); - } - } - else - light_cuboid.view_frustum_rays = m_sun_cascades[cascade_ind].rays; - - light_cuboid.view_ray.P = Device.vCameraPosition; - light_cuboid.view_ray.D = Device.vCameraDirection; - light_cuboid.light_ray.P = L_pos; - light_cuboid.light_ray.D = L_dir; - } - - // THIS NEED TO BE A CONSTATNT - Fplane light_top_plane; - light_top_plane.build_unit_normal(L_pos, L_dir); - float dist = light_top_plane.classify(Device.vCameraPosition); - - float map_size = m_sun_cascades[cascade_ind].size; - D3DXMatrixOrthoOffCenterLH((D3DXMATRIX*)&mdir_Project, -map_size * 0.5f, map_size * 0.5f, -map_size * 0.5f, - map_size * 0.5f, 0.1, dist + map_size); - - ////////////////////////////////////////////////////////////////////////// - - - /**/ - - // build viewport xform - float view_dim = float(RImplementation.o.smapsize); - Fmatrix m_viewport = { - view_dim / 2.f, 0.0f, 0.0f, 0.0f, - 0.0f, -view_dim / 2.f, 0.0f, 0.0f, - 0.0f, 0.0f, 1.0f, 0.0f, - view_dim / 2.f, view_dim / 2.f, 0.0f, 1.0f - }; - Fmatrix m_viewport_inv; - D3DXMatrixInverse((D3DXMATRIX*)&m_viewport_inv, 0, (D3DXMATRIX*)&m_viewport); - - // snap view-position to pixel - cull_xform.mul(mdir_Project, mdir_View); - Fmatrix cull_xform_inv; - cull_xform_inv.invert(cull_xform); - - - // light_cuboid.light_cuboid_points.reserve (9); - for (int p = 0; p < 8; p++) - { - Fvector3 xf = wform(cull_xform_inv, corners[p]); - light_cuboid.light_cuboid_points[p] = xf; - } - - // only side planes - for (int plane = 0; plane < 4; plane++) - for (int pt = 0; pt < 4; pt++) - { - int asd = facetable[plane][pt]; - light_cuboid.light_cuboid_polys[plane].points[pt] = asd; - } - - - Fvector lightXZshift; - light_cuboid.compute_caster_model_fixed(cull_planes, lightXZshift, m_sun_cascades[cascade_ind].size, - m_sun_cascades[cascade_ind].reset_chain); - Fvector proj_view = Device.vCameraDirection; - proj_view.y = 0; - proj_view.normalize(); - // lightXZshift.mad(proj_view, 20); - - // Initialize rays for the next cascade - if (cascade_ind < m_sun_cascades.size() - 1) - m_sun_cascades[cascade_ind + 1].rays = light_cuboid.view_frustum_rays; - - // #ifdef _DEBUG - - static bool draw_debug = false; - if (draw_debug && cascade_ind == 0) - for (u32 it = 0; it < cull_planes.size(); it++) - RImplementation.Target->dbg_addplane(cull_planes[it], it * 0xFFF); - //#endifDDS - - Fvector cam_shifted = L_pos; - cam_shifted.add(lightXZshift); - - // rebuild the view transform with the shift. - mdir_View.identity(); - mdir_View.build_camera_dir(cam_shifted, L_dir, L_up); - cull_xform.identity(); - cull_xform.mul(mdir_Project, mdir_View); - cull_xform_inv.invert(cull_xform); - - - // Create frustum for query - cull_frustum._clear(); - for (u32 p = 0; p < cull_planes.size(); p++) - cull_frustum._add(cull_planes[p]); - - { - Fvector cam_proj = Device.vCameraPosition; - const float align_aim_step_coef = 4.f; - cam_proj.set(floorf(cam_proj.x / align_aim_step_coef) + align_aim_step_coef / 2, - floorf(cam_proj.y / align_aim_step_coef) + align_aim_step_coef / 2, - floorf(cam_proj.z / align_aim_step_coef) + align_aim_step_coef / 2); - cam_proj.mul(align_aim_step_coef); - Fvector cam_pixel = wform(cull_xform, cam_proj); - cam_pixel = wform(m_viewport, cam_pixel); - Fvector shift_proj = lightXZshift; - cull_xform.transform_dir(shift_proj); - m_viewport.transform_dir(shift_proj); - - const float align_granularity = 4.f; - shift_proj.x = shift_proj.x > 0 ? align_granularity : -align_granularity; - shift_proj.y = shift_proj.y > 0 ? align_granularity : -align_granularity; - shift_proj.z = 0; - - cam_pixel.x = cam_pixel.x / align_granularity - floorf(cam_pixel.x / align_granularity); - cam_pixel.y = cam_pixel.y / align_granularity - floorf(cam_pixel.y / align_granularity); - cam_pixel.x *= align_granularity; - cam_pixel.y *= align_granularity; - cam_pixel.z = 0; - - cam_pixel.sub(shift_proj); - - m_viewport_inv.transform_dir(cam_pixel); - cull_xform_inv.transform_dir(cam_pixel); - Fvector diff = cam_pixel; - static float sign_test = -1.f; - diff.mul(sign_test); - Fmatrix adjust; - adjust.translate(diff); - cull_xform.mulB_44(adjust); - } - - m_sun_cascades[cascade_ind].xform = cull_xform; - - s32 limit = RImplementation.o.smapsize - 1; - fuckingsun->X.D.minX = 0; - fuckingsun->X.D.maxX = limit; - fuckingsun->X.D.minY = 0; - fuckingsun->X.D.maxY = limit; - - // full-xform - FPU::m24r(); - } - - // Begin SMAP-render - { - bool bSpecialFull = mapNormalPasses[1][0].size() || mapMatrixPasses[1][0].size() || mapSorted.size(); - VERIFY(!bSpecialFull); - HOM.Disable(); - phase = PHASE_SMAP; - if (RImplementation.o.Tshadows) r_pmask(true, true); - else r_pmask(true, false); - // fuckingsun->svis.begin (); - } - - // Fill the database - r_dsgraph_render_subspace(cull_sector, &cull_frustum, cull_xform, cull_COP, TRUE); - - // Finalize & Cleanup - fuckingsun->X.D.combine = cull_xform; //*((Fmatrix*)&m_LightViewProj); - - // Render shadow-map - //. !!! We should clip based on shrinked frustum (again) - { - bool bNormal = mapNormalPasses[0][0].size() || mapMatrixPasses[0][0].size(); - bool bSpecial = mapNormalPasses[1][0].size() || mapMatrixPasses[1][0].size() || mapSorted.size(); - if (bNormal || bSpecial) - { - Target->phase_smap_direct(fuckingsun, SE_SUN_FAR); - RCache.set_xform_world(Fidentity); - RCache.set_xform_view(Fidentity); - RCache.set_xform_project(fuckingsun->X.D.combine); - r_dsgraph_render_graph(0); - if (ps_r2_ls_flags.test(R2FLAG_SUN_DETAILS)) - Details->Render(); - fuckingsun->X.D.transluent = FALSE; - if (bSpecial) - { - fuckingsun->X.D.transluent = TRUE; - Target->phase_smap_direct_tsh(fuckingsun, SE_SUN_FAR); - r_dsgraph_render_graph(1); // normal level, secondary priority - r_dsgraph_render_sorted(); // strict-sorted geoms - } - } - } - - // End SMAP-render - { - // fuckingsun->svis.end (); - r_pmask(true, false); - } - - // Accumulate - Target->phase_accumulator(); - - if (Target->use_minmax_sm_this_frame()) - { - PIX_EVENT(SE_SUN_NEAR_MINMAX_GENERATE); - Target->create_minmax_SM(); - } - - PIX_EVENT(SE_SUN_NEAR); - - if (cascade_ind == 0) - Target->accum_direct_cascade(SE_SUN_NEAR, m_sun_cascades[cascade_ind].xform, m_sun_cascades[cascade_ind].xform, - m_sun_cascades[cascade_ind].bias); - else if (cascade_ind < m_sun_cascades.size() - 1) - Target->accum_direct_cascade(SE_SUN_MIDDLE, m_sun_cascades[cascade_ind].xform, - m_sun_cascades[cascade_ind - 1].xform, m_sun_cascades[cascade_ind].bias); - else - Target->accum_direct_cascade(SE_SUN_FAR, m_sun_cascades[cascade_ind].xform, - m_sun_cascades[cascade_ind - 1].xform, m_sun_cascades[cascade_ind].bias); - - // Restore XForms - RCache.set_xform_world(Fidentity); - RCache.set_xform_view(Device.mView); - RCache.set_xform_project(Device.mProject); -} diff --git a/src/Layers/xrRenderPC_R3/r2_blenders.cpp b/src/Layers/xrRenderPC_R3/r2_blenders.cpp deleted file mode 100644 index b2928d5c37..0000000000 --- a/src/Layers/xrRenderPC_R3/r2_blenders.cpp +++ /dev/null @@ -1,51 +0,0 @@ -#include "stdafx.h" - -#include "../xrRender/uber_deffer.h" - -#include "../xrRender/blender_BmmD.h" -#include "blender_deffer_flat.h" -#include "blender_deffer_model.h" -#include "blender_deffer_aref.h" -#include "../xrRender/blender_screen_set.h" -#include "../xrRender/blender_editor_wire.h" -#include "../xrRender/blender_editor_selection.h" -#include "../xrRender/blender_tree.h" -#include "../xrRender/blender_detail_still.h" -#include "../xrRender/blender_particle.h" -#include "../xrRender/Blender_Model_EbB.h" -#include "../xrRender/blender_Lm(EbB).h" - -IBlender* CRender::blender_create(CLASS_ID cls) -{ - switch (cls) - { - case B_DEFAULT: return xr_new(); - case B_DEFAULT_AREF: return xr_new(true); - case B_VERT: return xr_new(); - case B_VERT_AREF: return xr_new(false); - case B_SCREEN_SET: return xr_new(); - case B_SCREEN_GRAY: return 0; - case B_EDITOR_WIRE: return xr_new(); - case B_EDITOR_SEL: return xr_new(); - case B_LIGHT: return 0; - case B_LmBmmD: return xr_new(); - case B_LaEmB: return 0; - case B_LmEbB: return xr_new(); - case B_B: return 0; - case B_BmmD: return xr_new(); - case B_SHADOW_TEX: return 0; - case B_SHADOW_WORLD: return 0; - case B_BLUR: return 0; - case B_MODEL: return xr_new(); - case B_MODEL_EbB: return xr_new(); - case B_DETAIL: return xr_new(); - case B_TREE: return xr_new(); - case B_PARTICLE: return xr_new(); - } - return 0; -} - -void CRender::blender_destroy(IBlender* & B) -{ - xr_delete(B); -} diff --git a/src/Layers/xrRenderPC_R3/r2_sector_detect.cpp b/src/Layers/xrRenderPC_R3/r2_sector_detect.cpp deleted file mode 100644 index bd678945e0..0000000000 --- a/src/Layers/xrRenderPC_R3/r2_sector_detect.cpp +++ /dev/null @@ -1,89 +0,0 @@ -#include "stdafx.h" -#include "r3.h" - -int CRender::translateSector(IRender_Sector* pSector) -{ - if (!pSector) - return -1; - - for (u32 i = 0; i < Sectors.size(); ++i) - { - if (Sectors[i] == pSector) - return i; - } - - FATAL("Sector was not found!"); - NODEFAULT; - -#ifdef DEBUG - return (-1); -#endif // #ifdef DEBUG -} - -IRender_Sector* CRender::detectSector(const Fvector& P) -{ - IRender_Sector* S = NULL; - Fvector dir; - Sectors_xrc.ray_options(CDB::OPT_ONLYNEAREST); - - dir.set(0, -1, 0); - S = detectSector(P, dir); - if (NULL == S) - { - dir.set(0, 1, 0); - S = detectSector(P, dir); - } - return S; -} - -IRender_Sector* CRender::detectSector(const Fvector& P, Fvector& dir) -{ - // Portals model - int id1 = -1; - float range1 = 500.f; - if (rmPortals) - { - Sectors_xrc.ray_query(rmPortals, P, dir, range1); - if (Sectors_xrc.r_count()) - { - CDB::RESULT* RP1 = Sectors_xrc.r_begin(); - id1 = RP1->id; - range1 = RP1->range; - } - } - - // Geometry model - int id2 = -1; - float range2 = range1; - Sectors_xrc.ray_query(g_pGameLevel->ObjectSpace.GetStaticModel(), P, dir, range2); - if (Sectors_xrc.r_count()) - { - CDB::RESULT* RP2 = Sectors_xrc.r_begin(); - id2 = RP2->id; - range2 = RP2->range; - } - - // Select ID - int ID; - if (id1 >= 0) - { - if (id2 >= 0) ID = (range1 <= range2 + EPS) ? id1 : id2; // both was found - else ID = id1; // only id1 found - } - else if (id2 >= 0) ID = id2; // only id2 found - else return 0; - - if (ID == id1) - { - // Take sector, facing to our point from portal - CDB::TRI* pTri = rmPortals->get_tris() + ID; - CPortal* pPortal = (CPortal*)Portals[pTri->dummy]; - return pPortal->getSectorFacing(P); - } - else - { - // Take triangle at ID and use it's Sector - CDB::TRI* pTri = g_pGameLevel->ObjectSpace.GetStaticTris() + ID; - return getSector(pTri->sector); - } -} diff --git a/src/Layers/xrRenderPC_R3/r3.cpp b/src/Layers/xrRenderPC_R3/r3.cpp index c4d5ba40ea..24952ac1d3 100644 --- a/src/Layers/xrRenderPC_R3/r3.cpp +++ b/src/Layers/xrRenderPC_R3/r3.cpp @@ -178,7 +178,7 @@ void CRender::create() { Device.seqFrame.Add(this,REG_PRIORITY_HIGH + 0x12345678); - m_skinning = -1; + Engine.External.SetSkinningMode(); m_MSAASample = -1; // hardware @@ -275,9 +275,9 @@ void CRender::create() o.fp16_blend = true; // search for ATI formats - if (!o.HW_smap && (0 == strstr(Core.Params, "-nodf24"))) + if (!o.HW_smap && !Core.ParamsData.test(ECoreParams::nodf24)) { - o.HW_smap = HW.support((D3DFORMAT)(MAKEFOURCC('D', 'F', '2', '4')), D3DRTYPE_TEXTURE,D3DUSAGE_DEPTHSTENCIL); + o.HW_smap = HW.support((D3DFORMAT)(MAKEFOURCC('D', 'F', '2', '4')), D3DRTYPE_TEXTURE, D3DUSAGE_DEPTHSTENCIL); if (o.HW_smap) { o.HW_smap_FORMAT = MAKEFOURCC('D', 'F', '2', '4'); @@ -288,7 +288,7 @@ void CRender::create() } // emulate ATI-R4xx series - if (strstr(Core.Params, "-r4xx")) + if (Core.ParamsData.test(ECoreParams::r4xx)) { o.mrtmixdepth = FALSE; o.HW_smap = FALSE; @@ -304,8 +304,8 @@ void CRender::create() // nvstencil on NV40 and up o.nvstencil = FALSE; - //if ((HW.Caps.id_vendor==0x10DE)&&(HW.Caps.id_device>=0x40)) o.nvstencil = TRUE; - if (strstr(Core.Params, "-nonvs")) o.nvstencil = FALSE; + if (Core.ParamsData.test(ECoreParams::nonvs)) + o.nvstencil = FALSE; // nv-dbt // DX10 disabled @@ -313,42 +313,41 @@ void CRender::create() o.nvdbt = false; if (o.nvdbt) Msg("* NV-DBT supported and used"); - o.no_ram_textures = (strstr(Core.Params, "-noramtex")) ? TRUE : ps_r__common_flags.test(RFLAG_NO_RAM_TEXTURES); + o.no_ram_textures = Core.ParamsData.test(ECoreParams::noramtex) ? TRUE : ps_r__common_flags.test(RFLAG_NO_RAM_TEXTURES); if (o.no_ram_textures) Msg("* Managed textures disabled"); else Msg("* Managed textures enabled"); // options (smap-pool-size) - if (strstr(Core.Params, "-smap1536")) o.smapsize = 1536; - if (strstr(Core.Params, "-smap2048")) o.smapsize = 2048; - if (strstr(Core.Params, "-smap2560")) o.smapsize = 2560; - if (strstr(Core.Params, "-smap3072")) o.smapsize = 3072; - if (strstr(Core.Params, "-smap4096")) o.smapsize = 4096; + if (Core.ParamsData.test(ECoreParams::smap1536)) o.smapsize = 1536; + if (Core.ParamsData.test(ECoreParams::smap2048)) o.smapsize = 2048; + if (Core.ParamsData.test(ECoreParams::smap2560)) o.smapsize = 2560; + if (Core.ParamsData.test(ECoreParams::smap3072)) o.smapsize = 3072; + if (Core.ParamsData.test(ECoreParams::smap4096)) o.smapsize = 4096; // gloss char* g = strstr(Core.Params, "-gloss "); - o.forcegloss = g ? TRUE : FALSE; + o.forcegloss = Core.ParamsData.test(ECoreParams::gloss); if (g) { o.forcegloss_v = float(atoi(g + xr_strlen("-gloss "))) / 255.f; } // options - o.bug = (strstr(Core.Params, "-bug")) ? TRUE : FALSE; - o.sunfilter = (strstr(Core.Params, "-sunfilter")) ? TRUE : FALSE; - //. o.sunstatic = (strstr(Core.Params,"-sunstatic"))? TRUE :FALSE ; + o.bug = Core.ParamsData.test(ECoreParams::bug); + o.sunfilter = Core.ParamsData.test(ECoreParams::sunfilter); o.sunstatic = r2_sun_static; o.advancedpp = r2_advanced_pp; o.volumetricfog = ps_r2_ls_flags.test(R3FLAG_VOLUMETRIC_SMOKE); - o.sjitter = (strstr(Core.Params, "-sjitter")) ? TRUE : FALSE; - o.depth16 = (strstr(Core.Params, "-depth16")) ? TRUE : FALSE; - o.noshadows = (strstr(Core.Params, "-noshadows")) ? TRUE : FALSE; - o.Tshadows = (strstr(Core.Params, "-tsh")) ? TRUE : FALSE; - o.distortion_enabled = (strstr(Core.Params, "-nodistort")) ? FALSE : TRUE; + o.sjitter = Core.ParamsData.test(ECoreParams::sjitter); + o.depth16 = Core.ParamsData.test(ECoreParams::depth16); + o.noshadows = Core.ParamsData.test(ECoreParams::noshadows); + o.Tshadows = Core.ParamsData.test(ECoreParams::tsh); + o.distortion_enabled = !Core.ParamsData.test(ECoreParams::nodistort); o.distortion = o.distortion_enabled; - o.disasm = (strstr(Core.Params, "-disasm")) ? TRUE : FALSE; - o.forceskinw = (strstr(Core.Params, "-skinw")) ? TRUE : FALSE; + o.disasm = Core.ParamsData.test(ECoreParams::disasm); + o.forceskinw = Core.ParamsData.test(ECoreParams::skinw); o.ssao_blur_on = ps_r2_ls_flags_ext.test(R2FLAGEXT_SSAO_BLUR) && (ps_r_ssao != 0); o.ssao_opt_data = ps_r2_ls_flags_ext.test(R2FLAGEXT_SSAO_OPT_DATA) && (ps_r_ssao != 0); @@ -461,67 +460,31 @@ void CRender::create() HWOCC.occq_create(occq_size); rmNormal(); - marker = 0; - D3D10_QUERY_DESC qdesc; - qdesc.MiscFlags = 0; - qdesc.Query = D3D10_QUERY_EVENT; - ZeroMemory(q_sync_point, sizeof(q_sync_point)); - //R_CHK (HW.pDevice->CreateQuery(&qdesc,&q_sync_point[0])); - //R_CHK (HW.pDevice->CreateQuery(&qdesc,&q_sync_point[1])); - // Prevent error on first get data - //q_sync_point[0]->End(); - //q_sync_point[1]->End(); - //R_CHK (HW.pDevice->CreateQuery(D3DQUERYTYPE_EVENT,&q_sync_point[0])); - //R_CHK (HW.pDevice->CreateQuery(D3DQUERYTYPE_EVENT,&q_sync_point[1])); - for (u32 i = 0; i < HW.Caps.iGPUNum; ++i) - R_CHK(HW.pDevice->CreateQuery(&qdesc,&q_sync_point[i])); - q_sync_point[0]->End(); - - ::PortalTraverser.initialize(); + + GMBase.initialize(); FluidManager.Initialize(70, 70, 70); // FluidManager.Initialize( 100, 100, 100 ); FluidManager.SetScreenSize(Device.dwWidth, Device.dwHeight); + + Device.ModelDefferClear = xr_make_delegate(Models, &CModelPool::DeleteQueuedDeffer); } void CRender::destroy() { m_bMakeAsyncSS = false; FluidManager.Destroy(); - ::PortalTraverser.destroy(); - //_RELEASE (q_sync_point[1]); - //_RELEASE (q_sync_point[0]); - for (u32 i = 0; i < HW.Caps.iGPUNum; ++i) - _RELEASE(q_sync_point[i]); + GMBase.destroy(); HWOCC.occq_destroy(); xr_delete(Models); xr_delete(Target); PSLibrary.OnDestroy(); Device.seqFrame.Remove(this); - r_dsgraph_destroy(); + Device.ModelDefferClear = nullptr; } void CRender::reset_begin() { - // Update incremental shadowmap-visibility solver - // BUG-ID: 10646 - { - u32 it = 0; - for (it = 0; it < Lights_LastFrame.size(); it++) - { - if (0 == Lights_LastFrame[it]) continue ; - try - { - Lights_LastFrame[it]->svis.resetoccq(); - } - catch (...) - { - Msg("! Failed to flush-OCCq on light [%d] %X", it, *(u32*)(&Lights_LastFrame[it])); - } - } - Lights_LastFrame.clear(); - } - //AVO: let's reload details while changed details options on vid_restart if (b_loaded && ((dm_current_size != dm_size) || (ps_r__Detail_density != ps_current_detail_density) || ( ps_r__Detail_height != ps_current_detail_height))) @@ -533,26 +496,10 @@ void CRender::reset_begin() xr_delete(Target); HWOCC.occq_destroy(); - //_RELEASE (q_sync_point[1]); - //_RELEASE (q_sync_point[0]); - for (u32 i = 0; i < HW.Caps.iGPUNum; ++i) - _RELEASE(q_sync_point[i]); } void CRender::reset_end() { - D3D10_QUERY_DESC qdesc; - qdesc.MiscFlags = 0; - qdesc.Query = D3D10_QUERY_EVENT; - //R_CHK (HW.pDevice->CreateQuery(&qdesc,&q_sync_point[0])); - //R_CHK (HW.pDevice->CreateQuery(&qdesc,&q_sync_point[1])); - for (u32 i = 0; i < HW.Caps.iGPUNum; ++i) - R_CHK(HW.pDevice->CreateQuery(&qdesc,&q_sync_point[i])); - // Prevent error on first get data - q_sync_point[0]->End(); - //q_sync_point[1]->End(); - //R_CHK (HW.pDevice->CreateQuery(D3DQUERYTYPE_EVENT,&q_sync_point[0])); - //R_CHK (HW.pDevice->CreateQuery(D3DQUERYTYPE_EVENT,&q_sync_point[1])); HWOCC.occq_create(occq_size); Target = xr_new(); @@ -573,29 +520,14 @@ void CRender::reset_end() m_bFirstFrameAfterReset = true; } -/* -void CRender::OnFrame() -{ - Models->DeleteQueue (); - if (ps_r2_ls_flags.test(R2FLAG_EXP_MT_CALC)) { - Device.seqParallel.insert (Device.seqParallel.begin(), - fastdelegate::FastDelegate0<>(&HOM,&CHOM::MT_RENDER)); - } -}*/ void CRender::OnFrame() { Models->DeleteQueue(); - if (ps_r2_ls_flags.test(R2FLAG_EXP_MT_CALC)) - { - // MT-details (@front) - if (Details) - Device.seqParallel.insert(Device.seqParallel.begin(), - fastdelegate::FastDelegate0<>(Details, &CDetailManager::MT_CALC)); - // MT-HOM (@front) - Device.seqParallel.insert(Device.seqParallel.begin(), - fastdelegate::FastDelegate0<>(&HOM, &CHOM::MT_RENDER)); - } + //Lights Delete queue + for (light*L:v_all_lights_dque) + xr_delete(L); + v_all_lights_dque.clear(); } // Particles @@ -625,7 +557,15 @@ IRenderVisual* CRender::model_Duplicate(IRenderVisual* V) { return Models->Insta void CRender::model_Delete(IRenderVisual* & V, BOOL bDiscard) { dxRender_Visual* pVisual = (dxRender_Visual*)V; - Models->Delete(pVisual, bDiscard); + if (Models) + Models->Delete(pVisual, bDiscard); + V = 0; +} + +void CRender::model_Delete_Deffered(IRenderVisual* & V) +{ + dxRender_Visual* pVisual = (dxRender_Visual*)V; + Models->DeleteDeffered(pVisual); V = 0; } @@ -685,8 +625,10 @@ IRender_Portal* CRender::getPortal(int id) IRender_Sector* CRender::getSector(int id) { - VERIFY(id=0 && id(); } -void CRender::flush() { r_dsgraph_render_graph(0); } +void CRender::flush() { RImplementation.GMBase.r_dsgraph_render_graph(0); } BOOL CRender::occ_visible(vis_data& P) { return HOM.visible(P); } BOOL CRender::occ_visible(sPoly& P) { return HOM.visible(P); } BOOL CRender::occ_visible(Fbox& P) { return HOM.visible(P); } -void CRender::add_Visual(IRenderVisual* V) { add_leafs_Dynamic((dxRender_Visual*)V); } -void CRender::add_Geometry(IRenderVisual* V) { add_Static((dxRender_Visual*)V, View->getMask()); } // demonized: add user defined rotation to wallmark void CRender::add_StaticWallmark(ref_shader& S, const Fvector& P, float s, CDB::TRI* T, Fvector* verts, float ttl, bool ignore_opt, bool random_rotation) @@ -797,7 +737,7 @@ void CRender::clear_static_wallmarks() void CRender::add_SkeletonWallmark(intrusive_ptr wm) { - Wallmarks->AddSkeletonWallmark(wm); + Wallmarks->AddSkeletonWallmark(std::move(wm)); } void CRender::add_SkeletonWallmark(const Fmatrix* xf, CKinematics* obj, ref_shader& sh, const Fvector& start, @@ -814,16 +754,22 @@ void CRender::add_SkeletonWallmark(const Fmatrix* xf, IKinematics* obj, IWallMar if (pShader) add_SkeletonWallmark(xf, (CKinematics*)obj, *pShader, start, dir, size, ttl, ignore_opt); } -void CRender::add_Occluder(Fbox2& bb_screenspace) +void CRender::remove_SkeletonWallmarksFromObject(IKinematics* obj) { - HOM.occlude(bb_screenspace); + Wallmarks->RemoveSkeletonWallmarksFromObject(static_cast(obj)); } -void CRender::set_Object(IRenderable* O) +void CRender::update_Wallmarks() { - val_pObject = O; + Wallmarks->UpdateWallmarks(); } +void CRender::add_Occluder(Fbox2& bb_screenspace) +{ + HOM.occlude(bb_screenspace); +} + + void CRender::rmNear() { IRender_Target* T = getTarget(); @@ -862,7 +808,7 @@ CRender::CRender() CRender::~CRender() { - for (FSlideWindowItem it : SWIs) + for (auto& it : SWIs) { xr_free(it.sw); it.sw = nullptr; @@ -879,6 +825,22 @@ void CRender::Statistics(CGameFont* _F) F.OutNext(" **** LT:%2d,LV:%2d **** ", stats.l_total, stats.l_visible); stats.l_visible = 0; F.OutNext(" S(%2d) | (%2d)NS ", stats.l_shadowed, stats.l_unshadowed); + F.OutNext("LP sh(in:%u,vis:%u,r:%u) pk(%u/%u)", stats.ls_shadowed_in, stats.ls_shadowed_after_vis, + stats.ls_shadowed_rendered, stats.ls_shadowed_peak_in, stats.ls_shadowed_peak_after_vis); + F.OutNext("LP uns p(in:%u,r:%u) s(in:%u,r:%u)", stats.ls_unshadowed_point_in, stats.ls_unshadowed_point_rendered, + stats.ls_unshadowed_spot_in, stats.ls_unshadowed_spot_rendered); + F.OutNext("LP sh skip: pend[%u] inv[%u]", stats.ls_shadowed_pending_skipped, stats.ls_shadowed_invisible_skipped); + stats.ls_shadowed_in = 0; + stats.ls_shadowed_after_vis = 0; + stats.ls_shadowed_rendered = 0; + stats.ls_shadowed_pending_skipped = 0; + stats.ls_shadowed_invisible_skipped = 0; + stats.ls_shadowed_peak_in = 0; + stats.ls_shadowed_peak_after_vis = 0; + stats.ls_unshadowed_point_in = 0; + stats.ls_unshadowed_spot_in = 0; + stats.ls_unshadowed_point_rendered = 0; + stats.ls_unshadowed_spot_rendered = 0; F.OutNext("smap use[%2d], merge[%2d], finalclip[%2d]", stats.s_used, stats.s_merged - stats.s_used, stats.s_finalclip); stats.s_used = 0; @@ -1127,6 +1089,7 @@ HRESULT CRender::shader_compile( char sh_name[MAX_PATH] = ""; u32 len = 0; // options + const int m_skinning = Engine.External.GetSkinningMode(); { xr_sprintf(c_smapsize, "%04d", u32(o.smapsize)); defines[def_it].Name = "SMAP_size"; diff --git a/src/Layers/xrRenderPC_R3/r3.h b/src/Layers/xrRenderPC_R3/r3.h index a862b67cbd..08b1b909bd 100644 --- a/src/Layers/xrRenderPC_R3/r3.h +++ b/src/Layers/xrRenderPC_R3/r3.h @@ -1,6 +1,7 @@ -#pragma once +#pragma once -#include "../xrRender/r__dsgraph_structure.h" +#include "../xrRender/r__dsgraph_manager.h" +#include "../xrRender/r__sector.h" #include "../xrRender/r__occlusion.h" #include "../xrRender/PSLibrary.h" @@ -15,7 +16,6 @@ #include "smap_allocator.h" #include "../xrRender/light_db.h" -#include "light_render_direct.h" #include "../xrRender/LightTrack.h" #include "../xrRender/r_sun_cascades.h" @@ -26,17 +26,9 @@ class dxRender_Visual; // definition -class CRender : public R_dsgraph_structure +class CRender : public IRender_interface, public pureFrame { public: - enum - { - PHASE_NORMAL = 0, - // E[0] - PHASE_SMAP = 1, - // E[1] - }; - enum { MSAA_ATEST_NONE = 0x0, @@ -47,14 +39,6 @@ class CRender : public R_dsgraph_structure MSAA_ATEST_DX10_1_ATOC = 0x3, }; - enum - { - MMSM_OFF = 0, - MMSM_ON, - MMSM_AUTO, - MMSM_AUTODETECT - }; - public: struct _options { @@ -120,12 +104,24 @@ class CRender : public R_dsgraph_structure s32 s_used, s_merged, s_finalclip; u32 o_queries, o_culled; u32 ic_total, ic_culled; + u32 ls_shadowed_in; + u32 ls_shadowed_after_vis; + u32 ls_shadowed_rendered; + u32 ls_shadowed_pending_skipped; + u32 ls_shadowed_invisible_skipped; + u32 ls_shadowed_peak_in; + u32 ls_shadowed_peak_after_vis; + u32 ls_unshadowed_point_in; + u32 ls_unshadowed_spot_in; + u32 ls_unshadowed_point_rendered; + u32 ls_unshadowed_spot_rendered; } stats; public: bool is_sun(); // Sector detection and visibility CSector* pLastSector; + CSector* pOutdoorSector; Fvector vLastCameraPos; u32 uLastLTRACK; xr_vector Portals; @@ -152,26 +148,33 @@ class CRender : public R_dsgraph_structure CRenderTarget* Target; // Render-target CLight_DB Lights; - CLight_Compute_XFORM_and_VIS LR; - xr_vector Lights_LastFrame; SMAP_Allocator LP_smap_pool; light_Package LP_normal; light_Package LP_pending; - xr_vector> main_coarse_structure; - shared_str c_sbase; shared_str c_lmaterial; float o_hemi; float o_hemi_cube[CROS_impl::NUM_FACES]; float o_sun; - ID3DQuery* q_sync_point[CHWCaps::MAX_GPUS]; - u32 q_sync_count; bool m_bMakeAsyncSS; bool m_bFirstFrameAfterReset; // Determines weather the frame is the first after resetting device. xr_vector m_sun_cascades; + CFrustum rainwet_cull_frustum; + Fvector3 rainwet_cull_COP; + Fmatrix rainwet_cull_xform; + + CDSGraphManager GMRainWet = CDSGraphManager(u32(0), u32(STYPE_RENDERABLE), { true,false,false,false,true,false,false }); + CDSGraphManager GMBase = CDSGraphManager(u32(CDSGraphManager::VQ_HOM + CDSGraphManager::VQ_SSA + CDSGraphManager::VQ_FADE), + u32(STYPE_RENDERABLE + STYPE_PARTICLE + STYPE_LIGHTSOURCE), + { true, true, true, true, false, false, false }); + + xr_task_group main_task_static, main_task_dynamic, sun_cascades_task, raimwet_task; + + xr_set v_all_lights; + xr_list v_all_lights_dque; private: // Loading / Unloading @@ -183,21 +186,12 @@ class CRender : public R_dsgraph_structure void LoadSWIs(CStreamReader* fs); void Load3DFluid(); - BOOL add_Dynamic(dxRender_Visual* pVisual, u32 planes); // normal processing - void add_Static(dxRender_Visual* pVisual, u32 planes); - void add_leafs_Dynamic(dxRender_Visual* pVisual); // if detected node's full visibility - void add_leafs_Static(dxRender_Visual* pVisual); // if detected node's full visibility - public: IRender_Sector* rimp_detectSector(Fvector& P, Fvector& D); - void render_main(Fmatrix& mCombined, bool _fportals); void render_forward(); void render_smap_direct(Fmatrix& mCombined); void render_indirect(light* L); void render_lights(light_Package& LP); - void render_sun(); - void render_sun_near(); - void render_sun_filtered(); void render_menu(); void render_rain(); @@ -216,6 +210,9 @@ class CRender : public R_dsgraph_structure IRender_Sector* getSectorActive(); IRenderVisual* model_CreatePE(LPCSTR name); IRender_Sector* detectSector(const Fvector& P, Fvector& D); + IRender_Sector* detectLastSector(const Fvector& P); + void detectSectors_sphere(CSector* sector, FixedSet& m_sectors, const Fvector& b_center, const Fvector& b_dim); + void detectSectors_frustum(CSector* sector, FixedSet& m_sectors, CFrustum* _frustum); int translateSector(IRender_Sector* pSector); // HW-occlusion culling @@ -305,10 +302,7 @@ class CRender : public R_dsgraph_structure // Main virtual void flush(); - virtual void set_Object(IRenderable* O); virtual void add_Occluder(Fbox2& bb_screenspace); // mask screen region as oclluded - virtual void add_Visual(IRenderVisual* V); // add visual leaf (no culling performed at all) - virtual void add_Geometry(IRenderVisual* V); // add visual(s) (all culling performed) // wallmarks // demonized: add user defined rotation to wallmark @@ -325,6 +319,9 @@ class CRender : public R_dsgraph_structure virtual void add_SkeletonWallmark(const Fmatrix* xf, IKinematics* obj, IWallMarkArray* pArray, const Fvector& start, const Fvector& dir, float size, float ttl = 0.f, bool ignore_opt = false); + virtual void remove_SkeletonWallmarksFromObject(IKinematics* obj); + virtual void update_Wallmarks(); + // virtual IBlender* blender_create(CLASS_ID cls); virtual void blender_destroy(IBlender* &); @@ -345,6 +342,7 @@ class CRender : public R_dsgraph_structure virtual IRenderVisual* model_Duplicate(IRenderVisual* V); virtual void model_Delete(IRenderVisual* & V, BOOL bDiscard); virtual void model_Delete(IRender_DetailModel* & F); + virtual void model_Delete_Deffered(IRenderVisual* & V); virtual void model_Logging(BOOL bEnable) { Models->Logging(bEnable); } virtual void models_Prefetch(); virtual void models_PrefetchOne(LPCSTR name, bool assert = true); @@ -412,6 +410,8 @@ class CRender : public R_dsgraph_structure // Constructor/destructor/loader CRender(); virtual ~CRender(); + + virtual size_t SectorsCount() { return Sectors.size(); } protected: virtual void ScreenshotImpl(ScreenshotMode mode, LPCSTR name, CMemoryWriter* memory_writer); diff --git a/src/Layers/xrRenderPC_R3/r3_R_rain.cpp b/src/Layers/xrRenderPC_R3/r3_R_rain.cpp index ea2a2ca9e4..7348e25e75 100644 --- a/src/Layers/xrRenderPC_R3/r3_R_rain.cpp +++ b/src/Layers/xrRenderPC_R3/r3_R_rain.cpp @@ -3,7 +3,7 @@ #include "../../xrEngine/irenderable.h" #include "../xrRender/FBasicVisual.h" -#include "r3_R_sun_support.h" +#include "../xrRender/R_sun_support.h" const float tweak_rain_COP_initial_offs = 1200.f; const float tweak_rain_ortho_xform_initial_offs = 1000.f; //. ? @@ -38,7 +38,8 @@ void CRender::render_rain() D3DXMATRIX m_LightViewProj; // Use light as placeholder for rain data. - light RainLight; + // нет необходимости создавать каждый кадр структуру размером почти в киллобайт на стеке. + light& RainLight = *Lights.rain_light; //static const float source_offset = 40.f; @@ -74,11 +75,7 @@ void CRender::render_rain() // Compute volume(s) - something like a frustum for infinite directional light // Also compute virtual light position and sector it is inside - CFrustum cull_frustum; xr_vector cull_planes; - Fvector3 cull_COP; - CSector* cull_sector; - Fmatrix cull_xform; { FPU::m64r(); // Lets begin from base frustum @@ -88,15 +85,14 @@ void CRender::render_rain() #else typedef DumbConvexVolume t_volume; #endif - t_volume hull; + static t_volume hull; + hull.polys.clear(); + hull.edges.clear(); + hull.points.clear(); { - hull.points.reserve(9); - for (int p = 0; p < 8; p++) - { - Fvector3 xf = wform(fullxform_inv, corners[p]); - hull.points.push_back(xf); - } - for (int plane = 0; plane < 6; plane++) + for(int p = 0; p < 8; p++) + hull.points.push_back(wform(fullxform_inv, corners[p])); + for(int plane = 0; plane < 6; plane++) { hull.polys.push_back(t_volume::_poly()); for (int pt = 0; pt < 4; pt++) @@ -107,35 +103,18 @@ void CRender::render_rain() hull.compute_caster_model(cull_planes, RainLight.direction); #ifdef _DEBUG for (u32 it=0; itdbg_addplane(cull_planes[it],0xffffffff); + Target->dbg_addplane(cull_planes[it], 0xffffffff); #endif - // Search for default sector - assume "default" or "outdoor" sector is the largest one - //. hack: need to know real outdoor sector - CSector* largest_sector = 0; - float largest_sector_vol = 0; - for (u32 s = 0; s < Sectors.size(); s++) - { - CSector* S = (CSector*)Sectors[s]; - dxRender_Visual* V = S->root(); - float vol = V->vis.box.getvolume(); - if (vol > largest_sector_vol) - { - largest_sector_vol = vol; - largest_sector = S; - } - } - cull_sector = largest_sector; - // COP - 100 km away - cull_COP.mad(Device.vCameraPosition, RainLight.direction, -tweak_rain_COP_initial_offs); - cull_COP.x += fBoundingSphereRadius * Device.vCameraDirection.x; - cull_COP.z += fBoundingSphereRadius * Device.vCameraDirection.z; + rainwet_cull_COP.mad(Device.vCameraPosition, RainLight.direction, -tweak_rain_COP_initial_offs); + rainwet_cull_COP.x += fBoundingSphereRadius * Device.vCameraDirection.x; + rainwet_cull_COP.z += fBoundingSphereRadius * Device.vCameraDirection.z; // Create frustum for query - cull_frustum._clear(); + rainwet_cull_frustum._clear(); for (u32 p = 0; p < cull_planes.size(); p++) - cull_frustum._add(cull_planes[p]); + rainwet_cull_frustum._add(cull_planes[p]); // Create approximate ortho-xform @@ -185,13 +164,13 @@ void CRender::render_rain() bb.min.z - tweak_rain_ortho_xform_initial_offs, bb.min.z + 2 * tweak_rain_ortho_xform_initial_offs); - cull_xform.mul(mdir_Project, mdir_View); + rainwet_cull_xform.mul(mdir_Project, mdir_View); - s32 limit = _min(RImplementation.o.smapsize, ps_r3_dyn_wet_surf_sm_res); + s32 limit = _min(o.smapsize, ps_r3_dyn_wet_surf_sm_res); // build viewport xform float view_dim = float(limit); - float fTexelOffs = (.5f / RImplementation.o.smapsize); + float fTexelOffs = (.5f / o.smapsize); Fmatrix m_viewport = { view_dim / 2.f, 0.0f, 0.0f, 0.0f, 0.0f, -view_dim / 2.f, 0.0f, 0.0f, @@ -203,8 +182,8 @@ void CRender::render_rain() // snap view-position to pixel // snap zero point to pixel - Fvector cam_proj = wform(cull_xform, Fvector().set(0, 0, 0)); - Fvector cam_pixel = wform(m_viewport, cam_proj); + Fvector cam_proj = wform(rainwet_cull_xform, Fvector().set(0, 0, 0)); + Fvector cam_pixel = wform(m_viewport, cam_proj); cam_pixel.x = floorf(cam_pixel.x); cam_pixel.y = floorf(cam_pixel.y); Fvector cam_snapped = wform(m_viewport_inv, cam_pixel); @@ -212,7 +191,7 @@ void CRender::render_rain() diff.sub(cam_snapped, cam_proj); Fmatrix adjust; adjust.translate(diff); - cull_xform.mulA_44(adjust); + rainwet_cull_xform.mulA_44(adjust); RainLight.X.D.minX = 0; RainLight.X.D.maxX = limit; @@ -224,42 +203,31 @@ void CRender::render_rain() } // Begin SMAP-render - { - bool bSpecialFull = mapNormalPasses[1][0].size() || mapMatrixPasses[1][0].size() || mapSorted.size(); - VERIFY(!bSpecialFull); - HOM.Disable(); - phase = PHASE_SMAP; - r_pmask(true, false); - } - - // Fill the database - //r_dsgraph_render_subspace (cull_sector, &cull_frustum, cull_xform, cull_COP, TRUE); - r_dsgraph_render_subspace(cull_sector, &cull_frustum, cull_xform, cull_COP, FALSE); + phase = PHASE_SMAP; + GMRainWet.traverse(pOutdoorSector, rainwet_cull_frustum, rainwet_cull_COP, rainwet_cull_xform); + GMRainWet.r_dsgraph_capture_static(); // Finalize & Cleanup - RainLight.X.D.combine = cull_xform; //*((Fmatrix*)&m_LightViewProj); + RainLight.X.D.combine = rainwet_cull_xform; // Render shadow-map //. !!! We should clip based on shrinked frustum (again) { - bool bNormal = mapNormalPasses[0][0].size() || mapMatrixPasses[0][0].size(); - bool bSpecial = mapNormalPasses[1][0].size() || mapMatrixPasses[1][0].size() || mapSorted.size(); - if (bNormal || bSpecial) + bool bDeffered_Shadows = GMRainWet.RGraph.mapStaticPasses[0][0].size() || GMRainWet.RGraph.mapDynamicPasses[0][0].size(); + bool bForward_Shadows = GMRainWet.RGraph.mapStaticPasses[1][0].size() || GMRainWet.RGraph.mapDynamicPasses[1][0].size() || GMRainWet.RGraph.mapStaticSorted.Sorted.size() || GMRainWet.RGraph.mapDynamicSorted.Sorted.size(); + if(bDeffered_Shadows || bForward_Shadows) { Target->phase_smap_direct(&RainLight, SE_SUN_RAIN_SMAP); RCache.set_xform_world(Fidentity); RCache.set_xform_view(Fidentity); RCache.set_xform_project(RainLight.X.D.combine); - r_dsgraph_render_graph(0); - //if (ps_r2_ls_flags.test(R2FLAG_SUN_DETAILS)) - // Details->Render () ; + GMRainWet.r_dsgraph_render_graph(0); } } // End SMAP-render { // fuckingsun->svis.end (); - r_pmask(true, false); } // Restore XForms diff --git a/src/Layers/xrRenderPC_R3/r3_R_render.cpp b/src/Layers/xrRenderPC_R3/r3_R_render.cpp index 90efd4b94c..49efb1a5a7 100644 --- a/src/Layers/xrRenderPC_R3/r3_R_render.cpp +++ b/src/Layers/xrRenderPC_R3/r3_R_render.cpp @@ -3,170 +3,12 @@ #include "../xrRender/FBasicVisual.h" #include "../../xrEngine/customhud.h" #include "../../xrEngine/xr_object.h" +#include "../xrRender/SkeletonCustom.h" +#include "../../xrParticles/ParticlesAsyncManager.h" #include "../xrRender/QueryHelper.h" -IC bool pred_sp_sort(ISpatial* _1, ISpatial* _2) -{ - float d1 = _1->spatial.sphere.P.distance_to_sqr(Device.vCameraPosition); - float d2 = _2->spatial.sphere.P.distance_to_sqr(Device.vCameraPosition); - return d1 < d2; -} -void CRender::render_main(Fmatrix& m_ViewProjection, bool _fportals) -{ - PIX_EVENT(render_main); - // Msg ("---begin"); - marker ++; - - // Calculate sector(s) and their objects - if (pLastSector) - { - //!!! - //!!! BECAUSE OF PARALLEL HOM RENDERING TRY TO DELAY ACCESS TO HOM AS MUCH AS POSSIBLE - //!!! - { - // Traverse object database - g_SpatialSpace->q_frustum - ( - lstRenderables, - ISpatial_DB::O_ORDERED, - STYPE_RENDERABLE + STYPE_LIGHTSOURCE, - ViewBase - ); - - // (almost) Exact sorting order (front-to-back) - std::sort(lstRenderables.begin(), lstRenderables.end(), pred_sp_sort); - - // Determine visibility for dynamic part of scene - set_Object(0); - u32 uID_LTRACK = 0xffffffff; - if (phase == PHASE_NORMAL) - { - uLastLTRACK ++; - if (lstRenderables.size()) uID_LTRACK = uLastLTRACK % lstRenderables.size(); - - // update light-vis for current entity / actor - CObject* O = g_pGameLevel->CurrentViewEntity(); - if (O) - { - CROS_impl* R = (CROS_impl*)O->ROS(); - if (R) R->update(O); - } - - // update light-vis for selected entity - // track lighting environment - if (lstRenderables.size()) - { - IRenderable* renderable = lstRenderables[uID_LTRACK]->dcast_Renderable(); - if (renderable) - { - CROS_impl* T = (CROS_impl*)renderable->renderable_ROS(); - if (T) T->update(renderable); - } - } - } - } - - // Traverse sector/portal structure - PortalTraverser.traverse - ( - pLastSector, - ViewBase, - Device.vCameraPosition, - m_ViewProjection, - CPortalTraverser::VQ_HOM + CPortalTraverser::VQ_SSA + CPortalTraverser::VQ_FADE - //. disabled scissoring (HW.Caps.bScissor?CPortalTraverser::VQ_SCISSOR:0) // generate scissoring info - ); - - // Determine visibility for static geometry hierrarhy - for (u32 s_it = 0; s_it < PortalTraverser.r_sectors.size(); s_it++) - { - CSector* sector = (CSector*)PortalTraverser.r_sectors[s_it]; - dxRender_Visual* root = sector->root(); - for (u32 v_it = 0; v_it < sector->r_frustums.size(); v_it++) - { - set_Frustum(&(sector->r_frustums[v_it])); - add_Geometry(root); - } - } - - // Traverse frustums - for (u32 o_it = 0; o_it < lstRenderables.size(); o_it++) - { - ISpatial* spatial = lstRenderables[o_it]; - spatial->spatial_updatesector(); - CSector* sector = (CSector*)spatial->spatial.sector; - if (0 == sector) continue; // disassociated from S/P structure - - if (spatial->spatial.type & STYPE_LIGHTSOURCE) - { - // lightsource - light* L = (light*)(spatial->dcast_Light()); - VERIFY(L); - float lod = L->get_LOD(); - if (lod > EPS_L) - { - vis_data& vis = L->get_homdata(); - if (HOM.visible(vis)) Lights.add_light(L); - } - continue ; - } - - if (PortalTraverser.i_marker != sector->r_marker) continue; // inactive (untouched) sector - for (u32 v_it = 0; v_it < sector->r_frustums.size(); v_it++) - { - CFrustum& view = sector->r_frustums[v_it]; - if (!view.testSphere_dirty(spatial->spatial.sphere.P, spatial->spatial.sphere.R)) continue; - - if (spatial->spatial.type & STYPE_RENDERABLE) - { - // renderable - IRenderable* renderable = spatial->dcast_Renderable(); - VERIFY(renderable); - - // Occlusion - // casting is faster then using getVis method - vis_data& v_orig = ((dxRender_Visual*)renderable->renderable.visual)->vis; - vis_data v_copy = v_orig; - v_copy.box.xform(renderable->renderable.xform); - BOOL bVisible = HOM.visible(v_copy); - v_orig.marker = v_copy.marker; - v_orig.accept_frame = v_copy.accept_frame; - v_orig.hom_frame = v_copy.hom_frame; - v_orig.hom_tested = v_copy.hom_tested; - if (!bVisible) break; // exit loop on frustums - - // Rendering - set_Object(renderable); - renderable->renderable_Render(); - set_Object(0); - } - break; // exit loop on frustums - } - } - if (g_pGameLevel && (phase == PHASE_NORMAL)) - { - g_hud->Render_Last(); // HUD - if (g_hud->RenderActiveItemUIQuery()) - r_dsgraph_render_hud_ui(); - if (g_hud->RenderCamAttachedUIQuery()) - r_dsgraph_render_cam_ui(); - } - } - else - { - set_Object(0); - if (g_pGameLevel && (phase == PHASE_NORMAL)) - { - g_hud->Render_Last(); // HUD - if (g_hud->RenderActiveItemUIQuery()) - r_dsgraph_render_hud_ui(); - if (g_hud->RenderCamAttachedUIQuery()) - r_dsgraph_render_cam_ui(); - } - } -} void CRender::render_menu() { @@ -197,7 +39,7 @@ void CRender::render_menu() Fvector2 p0, p1; u32 Offset; - u32 C = color_rgba(255, 255, 255, 255); + auto C = color_rgba(255, 255, 255, 255); float _w = float(Device.dwWidth); float _h = float(Device.dwHeight); float d_Z = EPS_S; @@ -224,8 +66,6 @@ void CRender::Render() { PIX_EVENT(CRender_Render); - VERIFY(0==mapDistort.size()); - rmNormal(); bool _menu_pp = g_pGamePersistent ? g_pGamePersistent->OnRenderPPUI_query() : false; @@ -247,6 +87,9 @@ void CRender::Render() if (m_bFirstFrameAfterReset) { + for (light* L : v_all_lights)//critical!!! + L->m_moving_frames = 0; + m_bFirstFrameAfterReset = false; return; } @@ -262,190 +105,53 @@ void CRender::Render() // HOM ViewBase.CreateFromMatrix(Device.mFullTransform, FRUSTUM_P_LRTB + FRUSTUM_P_FAR); - View = 0; - if (!ps_r2_ls_flags.test(R2FLAG_EXP_MT_CALC)) - { - HOM.Enable(); - HOM.Render(ViewBase); - } + HOM.MT_RENDER(); - //******* Z-prefill calc - DEFERRER RENDERER - if (ps_r2_ls_flags.test(R2FLAG_ZFILL)) - { - PIX_EVENT(DEFER_Z_FILL); - Device.Statistic->RenderCALC.Begin(); - float z_distance = ps_r2_zfill; - Fmatrix m_zfill, m_project; - m_project.build_projection( - deg2rad(Device.fFOV/* *Device.fASPECT*/), - Device.fASPECT, VIEWPORT_NEAR, - z_distance * g_pGamePersistent->Environment().CurrentEnv->far_plane); - m_zfill.mul(m_project, Device.mView); - r_pmask(true, false); // enable priority "0" - set_Recorder(NULL); - phase = PHASE_SMAP; - render_main(m_zfill, false); - r_pmask(true, false); // disable priority "1" - Device.Statistic->RenderCALC.End(); - - // flush - Target->phase_scene_prepare(); - RCache.set_ColorWriteEnable(FALSE); - r_dsgraph_render_graph(0); - RCache.set_ColorWriteEnable(); - } - else - { - Target->phase_scene_prepare(); - } + Target->phase_scene_prepare(); - //******* - // Sync point - Device.Statistic->RenderDUMP_Wait_S.Begin(); - if (ps_r2_qsync) - { - CTimer T; - T.Start(); - BOOL result = FALSE; - HRESULT hr = S_FALSE; - //while ((hr=q_sync_point[q_sync_count]->GetData (&result,sizeof(result),D3DGETDATA_FLUSH))==S_FALSE) { - while ((hr = GetData(q_sync_point[q_sync_count], &result, sizeof(result))) == S_FALSE) - { - if (!SwitchToThread()) Sleep(ps_r2_wait_sleep); - if (T.GetElapsed_ms() > 500) - { - result = FALSE; - break; - } - } - } - Device.Statistic->RenderDUMP_Wait_S.End(); - q_sync_count = (q_sync_count + 1) % HW.Caps.iGPUNum; - //CHK_DX (q_sync_point[q_sync_count]->Issue(D3DISSUE_END)); - CHK_DX(EndQuery(q_sync_point[q_sync_count])); //******* Main calc - DEFERRER RENDERER - // Main calc - Device.Statistic->RenderCALC.Begin(); - r_pmask(true, false, true); // enable priority "0",+ capture wmarks - if (bSUN) set_Recorder(&main_coarse_structure); - else set_Recorder(NULL); phase = PHASE_NORMAL; - render_main(Device.mFullTransform, true); - set_Recorder(NULL); - r_pmask(true, false); // disable priority "1" - Device.Statistic->RenderCALC.End(); if (ps_r2_ls_flags.test(R2FLAG_TERRAIN_PREPASS)) { Target->u_setrt(Device.dwWidth, Device.dwHeight, NULL, NULL, NULL, !RImplementation.o.dx10_msaa ? HW.pBaseZB : Target->rt_MSAADepth->pZRT); - r_dsgraph_render_landscape(0, false); } - BOOL split_the_scene_to_minimize_wait = FALSE; - if (ps_r2_ls_flags.test(R2FLAG_EXP_SPLIT_SCENE)) split_the_scene_to_minimize_wait = TRUE; - //******* Main render :: PART-0 -- first - if (!split_the_scene_to_minimize_wait) - { - PIX_EVENT(DEFER_PART0_NO_SPLIT); - // level, DO NOT SPLIT - Target->phase_scene_begin(); - r_dsgraph_render_hud(); - r_dsgraph_render_graph(0); - r_dsgraph_render_lods(true, true); - if (Details) Details->Render(); - if (ps_r2_ls_flags.test(R2FLAG_TERRAIN_PREPASS)) r_dsgraph_render_landscape(1, true); - Target->phase_scene_end(); - } - else { PIX_EVENT(DEFER_PART0_SPLIT); // level, SPLIT Target->phase_scene_begin(); - r_dsgraph_render_graph(0); + GMBase.traverse(RImplementation.pLastSector, ViewBase, Device.vCameraPosition, Device.mFullTransform); + GMBase.r_dsgraph_capture_static(); + GMBase.r_dsgraph_render_static(0); + GMBase.r_dsgraph_capture_dynamic(); + GMBase.r_dsgraph_render_dynamic(0); Target->disable_aniso(); } - //******* Occlusion testing of volume-limited light-sources - Target->phase_occq(); - LP_normal.clear(); - LP_pending.clear(); if (RImplementation.o.dx10_msaa) RCache.set_ZB(RImplementation.Target->rt_MSAADepth->pZRT); + { PIX_EVENT(DEFER_TEST_LIGHT_VIS); - // perform tests - u32 count = 0; - light_Package& LP = Lights.package; - - // stats - stats.l_shadowed = LP.v_shadowed.size(); - stats.l_unshadowed = LP.v_point.size() + LP.v_spot.size(); - stats.l_total = stats.l_shadowed + stats.l_unshadowed; - - // perform tests - count = _max(count, LP.v_point.size()); - count = _max(count, LP.v_spot.size()); - count = _max(count, LP.v_shadowed.size()); - for (u32 it = 0; it < count; it++) - { - if (it < LP.v_point.size()) - { - light* L = LP.v_point[it]; - L->vis_prepare(); - if (L->vis.pending) LP_pending.v_point.push_back(L); - else LP_normal.v_point.push_back(L); - } - if (it < LP.v_spot.size()) - { - light* L = LP.v_spot[it]; - L->vis_prepare(); - if (L->vis.pending) LP_pending.v_spot.push_back(L); - else LP_normal.v_spot.push_back(L); - } - if (it < LP.v_shadowed.size()) - { - light* L = LP.v_shadowed[it]; - L->vis_prepare(); - if (L->vis.pending) LP_pending.v_shadowed.push_back(L); - else LP_normal.v_shadowed.push_back(L); - } - } + //******* Occlusion testing of volume-limited light-sources + Target->phase_occq(); + LP_normal.clear(); + LP_pending.clear(); + GMBase.r_dsgraph_capture_lights(); } - LP_normal.sort(); - LP_pending.sort(); - + //******* Main render :: PART-1 (second) - if (split_the_scene_to_minimize_wait) { PIX_EVENT(DEFER_PART1_SPLIT); - // skybox can be drawn here - if (0) - { - if (!RImplementation.o.dx10_msaa) - Target->u_setrt(Target->rt_Generic_0, Target->rt_Generic_1, 0, HW.pBaseZB); - else - Target->u_setrt(Target->rt_Generic_0_r, Target->rt_Generic_1, 0, - RImplementation.Target->rt_MSAADepth->pZRT); - RCache.set_CullMode(CULL_NONE); - RCache.set_Stencil(FALSE); - - // draw skybox - RCache.set_ColorWriteEnable(); - //CHK_DX(HW.pDevice->SetRenderState ( D3DRS_ZENABLE, FALSE )); - RCache.set_Z(FALSE); - g_pGamePersistent->Environment().RenderSky(); - //CHK_DX(HW.pDevice->SetRenderState ( D3DRS_ZENABLE, TRUE )); - RCache.set_Z(TRUE); - } - // level Target->phase_scene_begin(); - r_dsgraph_render_hud(); - r_dsgraph_render_lods(true, true); + GMBase.r_dsgraph_capture_hud(); + GMBase.r_dsgraph_render_hud(); + GMBase.r_dsgraph_render_lods(true, true); if (Details) Details->Render(); - if (ps_r2_ls_flags.test(R2FLAG_TERRAIN_PREPASS)) r_dsgraph_render_landscape(1, true); Target->phase_scene_end(); } @@ -458,25 +164,6 @@ void CRender::Render() Wallmarks->Render(); // wallmarks has priority as normal geometry } - // Update incremental shadowmap-visibility solver - { - PIX_EVENT(DEFER_FLUSH_OCCLUSION); - u32 it = 0; - for (it = 0; it < Lights_LastFrame.size(); it++) - { - if (0 == Lights_LastFrame[it]) continue ; - try - { - Lights_LastFrame[it]->svis.flushoccq(); - } - catch (...) - { - Msg("! Failed to flush-OCCq on light [%d] %X", it, *(u32*)(&Lights_LastFrame[it])); - } - } - Lights_LastFrame.clear(); - } - // full screen pass to mark msaa-edge pixels in highest stencil bit if (RImplementation.o.dx10_msaa) { @@ -496,17 +183,13 @@ void CRender::Render() { PIX_EVENT(DEFER_SUN); RImplementation.stats.l_visible ++; - if (!ps_r2_ls_flags_ext.is(R2FLAGEXT_SUN_OLD)) - render_sun_cascades(); - else - { - render_sun_near(); - render_sun(); - render_sun_filtered(); - } + render_sun_cascades(); + Target->increment_light_marker(); Target->accum_direct_blend(); } + phase = PHASE_NORMAL; + { PIX_EVENT(DEFER_SELF_ILLUM); Target->phase_accumulator(); @@ -523,14 +206,13 @@ void CRender::Render() //RCache.set_Stencil (TRUE,D3DCMP_ALWAYS,0x00,0xff,0xff,D3DSTENCILOP_KEEP,D3DSTENCILOP_REPLACE,D3DSTENCILOP_KEEP); RCache.set_CullMode(CULL_CCW); RCache.set_ColorWriteEnable(); - RImplementation.r_dsgraph_render_emissive(); + GMBase.r_dsgraph_render_emissive(); } // Lighting, non dependant on OCCQ { PIX_EVENT(DEFER_LIGHT_NO_OCCQ); Target->phase_accumulator(); - HOM.Disable(); render_lights(LP_normal); } @@ -540,33 +222,45 @@ void CRender::Render() render_lights(LP_pending); } + phase = PHASE_NORMAL; + // Postprocess { PIX_EVENT(DEFER_LIGHT_COMBINE); Target->phase_combine(); } - VERIFY(0==mapDistort.size()); + if (Details) + Details->details_clear(); + + if (g_hud) + { + if (g_hud->RenderActiveItemUIQuery()) + GMBase.r_dsgraph_render_hud_ui(); + if (g_hud->RenderCamAttachedUIQuery()) + GMBase.r_dsgraph_render_cam_ui(); + } + } +#include "../xrRender/CHudInitializer.h" void CRender::render_forward() { - VERIFY(0==mapDistort.size()); RImplementation.o.distortion = RImplementation.o.distortion_enabled; // enable distorion //******* Main render - second order geometry (the one, that doesn't support deffering) //.todo: should be done inside "combine" with estimation of of luminance, tone-mapping, etc. { // level - r_pmask(false, true); // enable priority "1" phase = PHASE_NORMAL; - render_main(Device.mFullTransform, false); // // Igor: we don't want to render old lods on next frame. - mapLOD.clear(); - r_dsgraph_render_graph(1); // normal level, secondary priority - PortalTraverser.fade_render(); // faded-portals - r_dsgraph_render_sorted(); // strict-sorted geoms + GMBase.r_dsgraph_render_static(1); // normal level, secondary priority + CParticlesAsync::Wait(); + GMBase.r_dsgraph_render_dynamic(1); + GMBase.fade_render(); // faded-portals + GMBase.r_dsgraph_render_sorted(false); // strict-sorted geoms g_pGamePersistent->Environment().RenderLast(); // rain/thunder-bolts + GMBase.r_dsgraph_render_sorted_hud(); } RImplementation.o.distortion = FALSE; // disable distorion @@ -593,4 +287,5 @@ void CRender::RenderToTarget(RRT target) HW.m_pSwapChain->GetBuffer(0, __uuidof(ID3D10Texture2D), (LPVOID*)&pBuffer); HW.pDevice->CopyResource((*RT)->pSurface, pBuffer); pBuffer->Release(); -} \ No newline at end of file +} + diff --git a/src/Layers/xrRenderPC_R3/r3_R_sun_support.cpp b/src/Layers/xrRenderPC_R3/r3_R_sun_support.cpp deleted file mode 100644 index 761bc25896..0000000000 --- a/src/Layers/xrRenderPC_R3/r3_R_sun_support.cpp +++ /dev/null @@ -1,2 +0,0 @@ -#include "stdafx.h" -#include "r3_R_sun_support.h" diff --git a/src/Layers/xrRenderPC_R3/r3_loader.cpp b/src/Layers/xrRenderPC_R3/r3_loader.cpp index 159fa564ad..fa63def835 100644 --- a/src/Layers/xrRenderPC_R3/r3_loader.cpp +++ b/src/Layers/xrRenderPC_R3/r3_loader.cpp @@ -109,11 +109,6 @@ void CRender::level_Load(IReader* fs) // End pApp->LoadEnd(); - // sanity-clear - lstLODs.clear(); - lstLODgroups.clear(); - mapLOD.clear(); - // signal loaded b_loaded = TRUE; } @@ -123,6 +118,11 @@ void CRender::level_Unload() if (0 == g_pGameLevel) return; if (!b_loaded) return; + GMBase.clear(); + GMRainWet.clear(); + for (sun::cascade& cascade : m_sun_cascades) + cascade.GMCascade.clear(); + u32 I; // HOM @@ -195,10 +195,17 @@ void CRender::level_Unload() //*** Shaders Shaders.clear_and_free(); - if (psDeviceFlags2.test(rsClearModels)) + const bool clearResources = psDeviceFlags2.test(rsClearAllResources); + if (psDeviceFlags2.test(rsClearModels) || clearResources) { Models->ClearPool(true); Visuals.clear_and_free(); + if (clearResources) + { + dxRenderDeviceRender::Instance().Resources->UnloadAllTexturesOnLevelUnload(); + dxRenderDeviceRender::Instance().ResourcesDestroyNecessaryTextures(); + dxRenderDeviceRender::Instance().Resources->Evict(); + } dxRenderDeviceRender::Instance().Resources->Dump(false); //static int unload_counter = 0; //Msg("The Level Unloaded.======================== %d", ++unload_counter); @@ -395,6 +402,23 @@ void CRender::LoadSectors(IReader* fs) // Sectors[d]->DebugDump (); pLastSector = 0; + + // Search for default sector - assume "default" or "outdoor" sector is the largest one + //. hack: need to know real outdoor sector + CSector* largest_sector = 0; + float largest_sector_vol = 0; + for (u32 s = 0; s < Sectors.size(); s++) + { + CSector* S = (CSector*)Sectors[s]; + dxRender_Visual* V = S->root(); + float vol = V->vis.box.getvolume(); + if (vol > largest_sector_vol) + { + largest_sector_vol = vol; + largest_sector = S; + } + } + pOutdoorSector = largest_sector; } void CRender::LoadSWIs(CStreamReader* base_fs) @@ -432,7 +456,6 @@ void CRender::LoadSWIs(CStreamReader* base_fs) void CRender::Load3DFluid() { - //if (strstr(Core.Params,"-no_volumetric_fog")) if (!RImplementation.o.volumetricfog) return; diff --git a/src/Layers/xrRenderPC_R3/r3_rendertarget.cpp b/src/Layers/xrRenderPC_R3/r3_rendertarget.cpp index 160183b94e..ee7c593483 100644 --- a/src/Layers/xrRenderPC_R3/r3_rendertarget.cpp +++ b/src/Layers/xrRenderPC_R3/r3_rendertarget.cpp @@ -701,14 +701,12 @@ CRenderTarget::CRenderTarget() t_LUM_dest.create(r2_RT_luminance_cur); // create pool - for (u32 it = 0; it < HW.Caps.iGPUNum * 2; it++) + for (u32 it = 0; it < 2; it++) { - string256 name; - xr_sprintf(name, "%s_%d", r2_RT_luminance_pool, it); - rt_LUM_pool[it].create(name, 1, 1, D3DFMT_R32F); - //u_setrt (rt_LUM_pool[it], 0, 0, 0 ); - //CHK_DX (HW.pDevice->Clear( 0L, NULL, D3DCLEAR_TARGET, 0x7f7f7f7f, 1.0f, 0L)); - FLOAT ColorRGBA[4] = {127.0f / 255.0f, 127.0f / 255.0f, 127.0f / 255.0f, 127.0f / 255.0f}; + shared_str name; name.printf("%s_%d", r2_RT_luminance_pool, it); + rt_LUM_pool[it].create(name.c_str(), 1, 1, D3DFMT_R32F); + + FLOAT ColorRGBA[4] = { 127.0f / 255.0f, 127.0f / 255.0f, 127.0f / 255.0f, 127.0f / 255.0f }; HW.pDevice->ClearRenderTargetView(rt_LUM_pool[it]->pRT, ColorRGBA); } u_setrt(Device.dwWidth, Device.dwHeight, HW.pBaseRT,NULL,NULL, HW.pBaseZB); diff --git a/src/Layers/xrRenderPC_R3/r3_rendertarget.h b/src/Layers/xrRenderPC_R3/r3_rendertarget.h index 43165f2696..0d9975e59b 100644 --- a/src/Layers/xrRenderPC_R3/r3_rendertarget.h +++ b/src/Layers/xrRenderPC_R3/r3_rendertarget.h @@ -126,7 +126,7 @@ class CRenderTarget : public IRender_Target ref_rt rt_LUM_64; // 64bit, 64x64, log-average in all components ref_rt rt_LUM_8; // 64bit, 8x8, log-average in all components - ref_rt rt_LUM_pool[CHWCaps::MAX_GPUS * 2]; // 1xfp32,1x1, exp-result -> scaler + ref_rt rt_LUM_pool[2]; // 1xfp32,1x1, exp-result -> scaler ref_texture t_LUM_src; // source ref_texture t_LUM_dest; // destination & usage for current frame @@ -359,6 +359,7 @@ class CRenderTarget : public IRender_Target void accum_reflected(light* L); // Igor: for volumetric lights void accum_volumetric(light* L); + void accum_volumetric_lv(light* L); void phase_bloom(); void phase_luminance(); void phase_combine(); diff --git a/src/Layers/xrRenderPC_R3/r3_rendertarget_accum_point.cpp b/src/Layers/xrRenderPC_R3/r3_rendertarget_accum_point.cpp index 07b3ae06a1..399f0535fd 100644 --- a/src/Layers/xrRenderPC_R3/r3_rendertarget_accum_point.cpp +++ b/src/Layers/xrRenderPC_R3/r3_rendertarget_accum_point.cpp @@ -24,7 +24,6 @@ void CRenderTarget::accum_point(light* L) Device.mView.transform_tiny(L_pos, L->position); // Xforms - L->xform_calc(); RCache.set_xform_world(L->m_xform); RCache.set_xform_view(Device.mView); RCache.set_xform_project(Device.mProject); diff --git a/src/Layers/xrRenderPC_R3/r3_rendertarget_accum_reflected.cpp b/src/Layers/xrRenderPC_R3/r3_rendertarget_accum_reflected.cpp index d76d38f21c..9d810ddc5a 100644 --- a/src/Layers/xrRenderPC_R3/r3_rendertarget_accum_reflected.cpp +++ b/src/Layers/xrRenderPC_R3/r3_rendertarget_accum_reflected.cpp @@ -11,7 +11,6 @@ void CRenderTarget::accum_reflected(light* L) ref_shader* shader_msaa = s_accum_reflected_msaa; BOOL bIntersect = FALSE; //enable_scissor(L); - L->xform_calc(); RCache.set_xform_world(L->m_xform); RCache.set_xform_view(Device.mView); RCache.set_xform_project(Device.mProject); diff --git a/src/Layers/xrRenderPC_R3/r3_rendertarget_accum_spot.cpp b/src/Layers/xrRenderPC_R3/r3_rendertarget_accum_spot.cpp index 11d4484d4e..9654494441 100644 --- a/src/Layers/xrRenderPC_R3/r3_rendertarget_accum_spot.cpp +++ b/src/Layers/xrRenderPC_R3/r3_rendertarget_accum_spot.cpp @@ -1,5 +1,6 @@ #include "stdafx.h" #include "../xrRender/du_cone.h" +#include "..\xrRender\CHudInitializer.h" //extern Fvector du_cone_vertices[DU_CONE_NUMVERTEX]; @@ -36,7 +37,6 @@ void CRenderTarget::accum_spot(light* L) BOOL bIntersect = FALSE; //enable_scissor(L); { // setup xform - L->xform_calc(); RCache.set_xform_world(L->m_xform); RCache.set_xform_view(Device.mView); RCache.set_xform_project(Device.mProject); @@ -268,10 +268,15 @@ void CRenderTarget::accum_spot(light* L) u_DBT_disable(); } +// Stub to use vanilla +void CRenderTarget::accum_volumetric_lv(light* L) +{ + accum_volumetric(L); +} + void CRenderTarget::accum_volumetric(light* L) { //if (L->flags.type != IRender_Light::SPOT) return; - if (!L->flags.bVolumetric) return; phase_vol_accumulator(); @@ -291,7 +296,6 @@ void CRenderTarget::accum_volumetric(light* L) BOOL bIntersect = FALSE; //enable_scissor(L); { // setup xform - L->xform_calc(); RCache.set_xform_world(L->m_xform); RCache.set_xform_view(Device.mView); RCache.set_xform_project(Device.mProject); @@ -383,9 +387,9 @@ void CRenderTarget::accum_volumetric(light* L) Fbox aabb; //float scaledRadius = L->spatial.sphere.R * (1+L->m_volumetric_distance)*0.5f; - float scaledRadius = L->spatial.sphere.R * L->m_volumetric_distance; - Fvector rr = Fvector().set(scaledRadius, scaledRadius, scaledRadius); - Fvector pt = L->spatial.sphere.P; + float scaledRadius = L->SpatialComponent->spatial.sphere.R * L->m_volumetric_distance; + Fvector rr = Fvector().set(scaledRadius, scaledRadius, scaledRadius); + Fvector pt = L->SpatialComponent->spatial.sphere.P; pt.sub(L->position); pt.mul(L->m_volumetric_distance); pt.add(L->position); diff --git a/src/Layers/xrRenderPC_R3/r3_rendertarget_enable_scissor.cpp b/src/Layers/xrRenderPC_R3/r3_rendertarget_enable_scissor.cpp index 4de402a4f2..c1a0f1992c 100644 --- a/src/Layers/xrRenderPC_R3/r3_rendertarget_enable_scissor.cpp +++ b/src/Layers/xrRenderPC_R3/r3_rendertarget_enable_scissor.cpp @@ -16,14 +16,14 @@ void CRenderTarget::enable_dbt_bounds(light* L) if (!ps_r2_ls_flags.test(R2FLAG_USE_NVDBT)) return; u32 mask = 0xffffffff; - EFC_Visible vis = RImplementation.ViewBase.testSphere(L->spatial.sphere.P, L->spatial.sphere.R * 1.01f, mask); + EFC_Visible vis = RImplementation.ViewBase.testSphere(L->SpatialComponent->spatial.sphere.P, L->SpatialComponent->spatial.sphere.R * 1.01f, mask); if (vis != fcvFully) return; // xform BB Fbox BB; Fvector rr; - rr.set(L->spatial.sphere.R, L->spatial.sphere.R, L->spatial.sphere.R); - BB.setb(L->spatial.sphere.P, rr); + rr.set(L->SpatialComponent->spatial.sphere.R, L->SpatialComponent->spatial.sphere.R, L->SpatialComponent->spatial.sphere.R); + BB.setb(L->SpatialComponent->spatial.sphere.P, rr); Fbox bbp; bbp.invalidate(); @@ -79,13 +79,13 @@ BOOL CRenderTarget::enable_scissor(light* L) // true if intersects near plane Fplane P; P.n.set(plane.x, plane.y, plane.z); P.d = plane.w; - float p_dist = P.classify(L->spatial.sphere.P) - L->spatial.sphere.R; + float p_dist = P.classify(L->SpatialComponent->spatial.sphere.P) - L->SpatialComponent->spatial.sphere.R; near_intersect = (p_dist <= 0); } #ifdef DEBUG if (1) { - Fsphere S; S.set (L->spatial.sphere.P,L->spatial.sphere.R); + Fsphere S; S.set (L->SpatialComponent->spatial.sphere.P,L->SpatialComponent->spatial.sphere.R); dbg_spheres.push_back (mk_pair(S,L->color)); } #endif diff --git a/src/Layers/xrRenderPC_R3/r3_rendertarget_phase_combine.cpp b/src/Layers/xrRenderPC_R3/r3_rendertarget_phase_combine.cpp index b5030289b5..9366ede748 100644 --- a/src/Layers/xrRenderPC_R3/r3_rendertarget_phase_combine.cpp +++ b/src/Layers/xrRenderPC_R3/r3_rendertarget_phase_combine.cpp @@ -47,22 +47,19 @@ void CRenderTarget::phase_combine() Fvector2 p0, p1; //*** exposure-pipeline - u32 gpu_id = Device.dwFrame%HW.Caps.iGPUNum; - if (Device.m_SecondViewport.IsSVPActive()) //--#SM+#-- +SecondVP+ Fix for screen flickering + if (Device.m_SecondViewport.IsSVPActive()) //--#SM+#-- +SecondVP+ Fix for screen flickering { - // clang-format off - gpu_id = (Device.dwFrame - 1) % HW.Caps.iGPUNum; // Фeen "ia?цaнey" tonemapping (HDR) iоnлa вueл?чaнey двойноaо ?aндa?a. - // Iобочнuй эффaeo - i?e ?aбоoa двойноaо ?aндa?a neо?оnoь eзiaнaнey tonemapping (HDR) iaдaao в двa ?aзa - // Ia?цaнea nвyзaно n oai, чoо HDR длy nвоaй ?aбоou o?aнeo уiaньoaннea eоiee "i?оoлuo eaд?ов" - // Эoe eaд?u оoноneoaльно iоoоae д?уa нa д?уaa, однaeо i?e вeл?чaнноi двойноi ?aндa?a - // в iоловeнa eaд?ов оeaзuвaaony ea?oeнea eз вoо?оaо ?aндa?a, e iоneольeу онa чanoо iоaao оoлeчaony iо цвaoу\y?eоnoe - // oо i?e iоiuoea nоздaнey "iлaвноaо" ia?aoодa iaaду нeie iолучaaony эффaeo ia?цaнey - + if (t_LUM_src != rt_LUM_pool[0]->pTexture) + t_LUM_src->surface_set(rt_LUM_pool[0]->pSurface); + if (t_LUM_dest != rt_LUM_pool[1]->pTexture) + t_LUM_dest->surface_set(rt_LUM_pool[1]->pSurface); } - + else { - t_LUM_src->surface_set (rt_LUM_pool[gpu_id*2+0]->pSurface); - t_LUM_dest->surface_set (rt_LUM_pool[gpu_id*2+1]->pSurface); + if (t_LUM_src != rt_LUM_pool[0]->pTexture) + t_LUM_src->surface_set(rt_LUM_pool[0]->pSurface); + if (t_LUM_dest != rt_LUM_pool[1]->pTexture) + t_LUM_dest->surface_set(rt_LUM_pool[1]->pSurface); } if (RImplementation.o.ssao_hdao) @@ -330,8 +327,13 @@ void CRenderTarget::phase_combine() // Distortion filter BOOL bDistort = RImplementation.o.distortion_enabled; // This can be modified { - if ((0 == RImplementation.mapDistort.size()) && !_menu_pp) - bDistort = FALSE; + if (( + 0 == RImplementation.GMBase.RGraph.mapStaticSorted.Distort.size() && + 0 == RImplementation.GMBase.RGraph.mapDynamicSorted.Distort.size() && + 0 == RImplementation.GMBase.RGraph.mapHUDSorted.Distort.size() + ) && !_menu_pp + ) + bDistort = FALSE; if (bDistort) { PIX_EVENT(render_distort_objects); @@ -351,7 +353,7 @@ void CRenderTarget::phase_combine() RCache.set_Stencil(FALSE); RCache.set_ColorWriteEnable(); //CHK_DX(HW.pDevice->Clear ( 0L, NULL, D3DCLEAR_TARGET, color_rgba(127,127,0,127), 1.0f, 0L)); - RImplementation.r_dsgraph_render_distort(); + RImplementation.GMBase.r_dsgraph_render_distort(); if (g_pGamePersistent) g_pGamePersistent->OnRenderPPUI_PP(); // PP-UI } } @@ -566,7 +568,7 @@ void CRenderTarget::phase_combine() //*** exposure-pipeline-clear { - std::swap(rt_LUM_pool[gpu_id * 2 + 0], rt_LUM_pool[gpu_id * 2 + 1]); + std::swap(rt_LUM_pool[0], rt_LUM_pool[1]); t_LUM_src->surface_set(NULL); t_LUM_dest->surface_set(NULL); } diff --git a/src/Layers/xrRenderPC_R3/r3_rendertarget_phase_luminance.cpp b/src/Layers/xrRenderPC_R3/r3_rendertarget_phase_luminance.cpp index 1b3fe3ca3a..4748dcc356 100644 --- a/src/Layers/xrRenderPC_R3/r3_rendertarget_phase_luminance.cpp +++ b/src/Layers/xrRenderPC_R3/r3_rendertarget_phase_luminance.cpp @@ -117,8 +117,7 @@ void CRenderTarget::phase_luminance() } // 222: Perform LUM-SAT, pass 2, 8x8 => 1x1 - u32 gpu_id = Device.dwFrame % HW.Caps.iGPUNum; - u_setrt(rt_LUM_pool[gpu_id * 2 + 1],NULL,NULL,NULL); + u_setrt(rt_LUM_pool[1],NULL,NULL,NULL); //RImplementation.rmNormal(); { // Build filter-kernel diff --git a/src/Layers/xrRenderPC_R3/stdafx.h b/src/Layers/xrRenderPC_R3/stdafx.h index 5d9dee26a2..2cdc657abb 100644 --- a/src/Layers/xrRenderPC_R3/stdafx.h +++ b/src/Layers/xrRenderPC_R3/stdafx.h @@ -48,6 +48,8 @@ #include "../xrRender/xrRender_console.h" #include "r3.h" +#include "../../xrCore/profiler.h" + IC void jitter(CBlender_Compile& C) { // C.r_Sampler ("jitter0", JITTER(0), true, D3DTADDRESS_WRAP, D3DTEXF_POINT, D3DTEXF_NONE, D3DTEXF_POINT); diff --git a/src/Layers/xrRenderPC_R3/xrRender_R3.vcxproj b/src/Layers/xrRenderPC_R3/xrRender_R3.vcxproj index f85372250d..eb8e775616 100644 --- a/src/Layers/xrRenderPC_R3/xrRender_R3.vcxproj +++ b/src/Layers/xrRenderPC_R3/xrRender_R3.vcxproj @@ -13,6 +13,10 @@ Release x64 + + VerifiedDX11ASAN + x64 + VerifiedDX11 x64 @@ -57,6 +61,14 @@ false x64 + + StaticLibrary + v143 + MultiByte + false + x64 + true + StaticLibrary v143 @@ -87,6 +99,11 @@ + + + + + @@ -116,6 +133,11 @@ $(xrGameDir)bin_dbg\$(Platform)\$(Configuration)\ $(xrIntDir)$(ProjectName)\ + + false + $(xrGameDir)bin_dbg\$(Platform)\$(Configuration)\ + $(xrIntDir)$(ProjectName)\ + false $(xrGameDir)bin_dbg\$(Platform)\$(Configuration)\ @@ -200,7 +222,7 @@ false false .;$(SolutionDir)3rd party\imgui\;$(SolutionDir)3rd party\luajit-2\src\;$(SolutionDir)3rd party\luabind\;$(SolutionDir)xrCore;$(SolutionDir)3rd party\luajit-2\src\;$(SolutionDir)3rd party\luabind\;$(xrSdkDir)include;$(XRAY_16X_LIBS)OpenAutomate\inc;$(XRAY_16X_LIBS)nvapi;%(AdditionalIncludeDirectories) - USE_VERIFY_IN_RELEASE;USE_DX10;WIN32;NDEBUG;_WINDOWS;_USRDLL;XRRENDER_R3_EXPORTS;_SECURE_SCL=0;%(PreprocessorDefinitions) + XRCORE_PROFILER;USE_VERIFY_IN_RELEASE;USE_DX10;WIN32;NDEBUG;_WINDOWS;_USRDLL;XRRENDER_R3_EXPORTS;_SECURE_SCL=0;%(PreprocessorDefinitions) NotSet Use EditAndContinue @@ -239,7 +261,7 @@ false false .;$(SolutionDir)3rd party\imgui\;$(SolutionDir)3rd party\luajit-2\src\;$(SolutionDir)3rd party\luabind\;$(SolutionDir)xrCore;$(xrSdkDir)include;$(XRAY_16X_LIBS)OpenAutomate\inc;$(XRAY_16X_LIBS)nvapi;%(AdditionalIncludeDirectories) - USE_VERIFY_IN_RELEASE;USE_DX10;WIN32;NDEBUG;_WINDOWS;_USRDLL;XRRENDER_R3_EXPORTS;_SECURE_SCL=0;%(PreprocessorDefinitions) + XRCORE_PROFILER;USE_VERIFY_IN_RELEASE;USE_DX10;WIN32;NDEBUG;_WINDOWS;_USRDLL;XRRENDER_R3_EXPORTS;_SECURE_SCL=0;%(PreprocessorDefinitions) NotSet Use EditAndContinue @@ -268,6 +290,45 @@ true + + + Disabled + Disabled + false + Neither + false + false + false + .;$(SolutionDir)3rd party\imgui\;$(SolutionDir)3rd party\luajit-2\src\;$(SolutionDir)3rd party\luabind\;$(SolutionDir)xrCore;$(xrSdkDir)include;$(XRAY_16X_LIBS)OpenAutomate\inc;$(XRAY_16X_LIBS)nvapi;%(AdditionalIncludeDirectories) + XRCORE_PROFILER;USE_VERIFY_IN_RELEASE;_DISABLE_VECTOR_ANNOTATION;_DISABLE_STRING_ANNOTATION;USE_DX10;WIN32;NDEBUG;_WINDOWS;_USRDLL;XRRENDER_R3_EXPORTS;_SECURE_SCL=0;%(PreprocessorDefinitions) + NotSet + Use + ProgramDatabase + -Zm110 %(AdditionalOptions) + USE_LUAJIT_ONE + 4005;4099 + true + Level4 + false + MultiThreadedDLL + false + stdcpp17 + true + + + dxguid.lib;d3dcompiler.lib;d3d10.lib;d3dx10.lib;dxgi.lib;nvapi.lib;%(AdditionalDependencies) + $(SolutionDir)3rd party\luajit-2\src\;$(xrSdkDir)libraries\x64;$(xrLibDir);$(XRAY_16X_LIBS)OpenAutomate\libraries;$(SolutionDir)x64\Release;%(AdditionalLibraryDirectories) + NotSet + true + true + true + Default + false + $(xrLibDir)$(TargetName).lib + LIBCMT + true + + .;$(SolutionDir)3rd party\imgui\;$(SolutionDir)3rd party\luajit-2\src\;$(SolutionDir)3rd party\luabind\;$(SolutionDir)xrCore;$(SolutionDir)3rd party\luajit-2\src\;$(SolutionDir)3rd party\luabind\;$(xrSdkDir)include;$(XRAY_16X_LIBS)OpenAutomate\inc;$(XRAY_16X_LIBS)nvapi;%(AdditionalIncludeDirectories) @@ -368,6 +429,7 @@ + @@ -435,7 +497,8 @@ - + + @@ -489,13 +552,10 @@ - - - @@ -546,6 +606,7 @@ + @@ -592,9 +653,11 @@ + + @@ -605,6 +668,7 @@ + @@ -623,16 +687,20 @@ + + + + - + @@ -676,15 +744,6 @@ - - - - - - - - - @@ -714,12 +773,12 @@ - Create Create Create Create + Create Create diff --git a/src/Layers/xrRenderPC_R3/xrRender_R3.vcxproj.filters b/src/Layers/xrRenderPC_R3/xrRender_R3.vcxproj.filters index 2ce1aff95f..625bb1a527 100644 --- a/src/Layers/xrRenderPC_R3/xrRender_R3.vcxproj.filters +++ b/src/Layers/xrRenderPC_R3/xrRender_R3.vcxproj.filters @@ -210,12 +210,6 @@ Core - - Core - - - Core - Core @@ -255,12 +249,6 @@ Lights - - Lights - - - Lights - Lights @@ -770,6 +758,12 @@ Core + + Core + + + + Core @@ -788,21 +782,6 @@ Core - - Core - - - Core - - - Core - - - Core - - - Core - Core @@ -818,9 +797,6 @@ Core - - Core - Core @@ -887,18 +863,6 @@ Lights - - Lights - - - Lights - - - Lights - - - Lights - Lights @@ -1016,9 +980,6 @@ Visibility\Sector/Portal - - Visibility\Sector/Portal - Visibility\HOM Occlusion @@ -1424,5 +1385,30 @@ Core + + Core + + + Visibility\Sector/Portal + + + Core + + + + Core + + + Core + + + Core + + + Core + + + Lights + - \ No newline at end of file + diff --git a/src/Layers/xrRenderPC_R4/Light_Render_Direct.cpp b/src/Layers/xrRenderPC_R4/Light_Render_Direct.cpp deleted file mode 100644 index 5f6f1f7b2c..0000000000 --- a/src/Layers/xrRenderPC_R4/Light_Render_Direct.cpp +++ /dev/null @@ -1,2 +0,0 @@ -#include "StdAfx.h" -#include "light_render_direct.h" diff --git a/src/Layers/xrRenderPC_R4/Light_Render_Direct.h b/src/Layers/xrRenderPC_R4/Light_Render_Direct.h deleted file mode 100644 index 15b4214acb..0000000000 --- a/src/Layers/xrRenderPC_R4/Light_Render_Direct.h +++ /dev/null @@ -1,7 +0,0 @@ -#pragma once - -class CLight_Compute_XFORM_and_VIS -{ -public: - void compute_xf_spot(light* L); // -}; diff --git a/src/Layers/xrRenderPC_R4/Light_Render_Direct_ComputeXFS.cpp b/src/Layers/xrRenderPC_R4/Light_Render_Direct_ComputeXFS.cpp deleted file mode 100644 index 561543dab0..0000000000 --- a/src/Layers/xrRenderPC_R4/Light_Render_Direct_ComputeXFS.cpp +++ /dev/null @@ -1,103 +0,0 @@ -#include "stdafx.h" -#include "light_render_direct.h" - -void CLight_Compute_XFORM_and_VIS::compute_xf_spot(light* L) -{ - // Build EYE-space xform - Fvector L_dir, L_up, L_right, L_pos; - L_dir.set(L->direction); - L_dir.normalize(); - - if (L->right.square_magnitude() > EPS) - { - // use specified 'up' and 'right', just enshure ortho-normalization - L_right.set(L->right); - L_right.normalize(); - L_up.crossproduct(L_dir, L_right); - L_up.normalize(); - L_right.crossproduct(L_up, L_dir); - L_right.normalize(); - } - else - { - // auto find 'up' and 'right' vectors - L_up.set(0, 1, 0); - if (_abs(L_up.dotproduct(L_dir)) > .99f) L_up.set(0, 0, 1); - L_right.crossproduct(L_up, L_dir); - L_right.normalize(); - L_up.crossproduct(L_dir, L_right); - L_up.normalize(); - } - L_pos.set(L->position); - - // - int _cached_size = L->X.S.size; - L->X.S.posX = L->X.S.posY = 0; - L->X.S.size = SMAP_adapt_max; - L->X.S.transluent = FALSE; - - // Compute approximate screen area (treating it as an point light) - R*R/dist_sq - // Note: we clamp screen space area to ONE, although it is not correct at all - float dist = Device.vCameraPosition.distance_to(L->spatial.sphere.P) - L->spatial.sphere.R; - if (dist < 0) dist = 0; - float ssa = clampr(L->range * L->range / (1.f + dist * dist), 0.f, 1.f); - - // compute intensity - float intensity0 = (L->color.r + L->color.g + L->color.b) / 3.f; - float intensity1 = (L->color.r * 0.2125f + L->color.g * 0.7154f + L->color.b * 0.0721f); - float intensity = (intensity0 + intensity1) / 2.f; // intensity1 tends to underestimate... - - // [SSS 19] Improve this code later? - // compute how much duelling frusta occurs [-1..1]-> 1 + [-0.5 .. +0.5] - //float duel_dot = 1.f - 0.5f * Device.vCameraDirection.dotproduct(L_dir); - - // compute how large the light is - give more texels to larger lights, assume 8m as being optimal radius - float sizefactor = L->range / 8.f; // 4m = .5, 8m=1.f, 16m=2.f, 32m=4.f - - // compute how wide the light frustum is - assume 90deg as being optimal - float widefactor = L->cone / deg2rad(90.f); // - - // factors - float factor0 = powf(ssa, 1.f / 2.f); // ssa is quadratic - float factor1 = powf(intensity, 1.f / 16.f); // less perceptually important? - //float factor2 = powf(duel_dot, 1.f / 4.f); // difficult to fast-change this -> visible - float factor3 = powf(sizefactor, 1.f / 4.f); // this shouldn't make much difference - float factor4 = powf(widefactor, 1.f / 2.f); // make it linear ??? - //float factor = ps_r2_ls_squality * factor0 * factor1 * factor2 * factor3 * factor4; - float factor = ps_r2_ls_squality * factor0 * factor1 * factor3 * factor4; - - // final size calc - u32 max_size = RImplementation.o.smapsize <= ps_ssfx_shadows.y ? RImplementation.o.smapsize : ps_ssfx_shadows.y; - u32 _size = iFloor(factor * SMAP_adapt_optimal); - if (_size < ps_ssfx_shadows.x) _size = ps_ssfx_shadows.x; - if (_size > max_size) _size = max_size; - int _epsilon = iCeil(float(_size) * 0.01f); - int _diff = _abs(int(_size) - int(_cached_size)); - L->X.S.size = (_diff >= _epsilon) ? _size : _cached_size; - - // make N pixel border - L->X.S.view.build_camera_dir(L_pos, L_dir, L_up); - //float n = 2.f ; - //float x = float(L->X.S.size) ; - //float alpha = L->cone/2 ; - //float tan_beta = (x+2*n)*tanf(alpha) / x ; - //float g_alpha = 2*rad2deg (alpha); - //float g_beta = 2*rad2deg (atanf(tan_beta)); - //Msg ("x(%f) : a(%f), b(%f)",x,g_alpha,g_beta); - - // _min(L->cone + deg2rad(4.5f), PI*0.98f) - Here, it is needed to enlarge the shadow map frustum to include also - // displaced pixels and the pixels neighbor to the examining one. - - /* Ray Twitty */ - float tan_shift; - if (L->flags.type == IRender_Light::OMNIPART) // [ SSS ] 0.3f fix almost all frustum problems... 0.5f was the old value ( SSS 19 ) but was causing issues? - tan_shift = 0.3f; - else if (L->flags.type == IRender_Light::POINT) - tan_shift = 0.2007129f; // deg2rad(11.5f); - else - tan_shift = 0.0610865f; //deg2rad(3.5f); - - /* Ray Twitty end */ - L->X.S.project.build_projection(L->cone + tan_shift, 1.f, L->virtual_size, L->range + EPS_S); - L->X.S.combine.mul(L->X.S.project, L->X.S.view); -} diff --git a/src/Layers/xrRenderPC_R4/blender_combine.cpp b/src/Layers/xrRenderPC_R4/blender_combine.cpp index 00a143c04f..f53c3018e8 100644 --- a/src/Layers/xrRenderPC_R4/blender_combine.cpp +++ b/src/Layers/xrRenderPC_R4/blender_combine.cpp @@ -182,6 +182,15 @@ void CBlender_combine::Compile(CBlender_Compile& C) C.r_End(); break; case 5: // post-processing + C.r_Pass("pfx_volumetric_light", "pfx_volumetric_light", false, FALSE, FALSE, TRUE, D3DBLEND_ONE, D3DBLEND_ONE); + + C.r_dx10Texture("s_position", r2_RT_P); + C.r_dx10Texture("s_smap", r2_RT_smap_depth); + + C.r_dx10Sampler("smp_rtlinear"); + C.r_dx10Sampler("smp_smap"); + C.r_dx10Sampler("smp_nofilter"); + C.r_End(); break; } } diff --git a/src/Layers/xrRenderPC_R4/light_GI.cpp b/src/Layers/xrRenderPC_R4/light_GI.cpp index 9720b60f13..315b95a31f 100644 --- a/src/Layers/xrRenderPC_R4/light_GI.cpp +++ b/src/Layers/xrRenderPC_R4/light_GI.cpp @@ -72,7 +72,7 @@ void light::gi_generate() if (LI.E < ps_r2_GI_clip) continue; - LI.S = spatial.sector; //. BUG + LI.S = SpatialComponent->spatial.sector; //. BUG indirect.push_back(LI); } diff --git a/src/Layers/xrRenderPC_R4/light_smapvis.cpp b/src/Layers/xrRenderPC_R4/light_smapvis.cpp deleted file mode 100644 index 5a25a987d2..0000000000 --- a/src/Layers/xrRenderPC_R4/light_smapvis.cpp +++ /dev/null @@ -1,131 +0,0 @@ -#include "StdAfx.h" -#include "../xrRender/light.h" -#include "../xrRender/FBasicVisual.h" - -smapvis::smapvis() -{ - invalidate(); - frame_sleep = 0; -} - -smapvis::~smapvis() -{ - flushoccq(); - invalidate(); -} - -void smapvis::invalidate() -{ - state = state_counting; - testQ_V = 0; - frame_sleep = Device.dwFrame + ps_r__LightSleepFrames; - invisible.clear(); -} - -void smapvis::begin() -{ - RImplementation.clear_Counters(); - switch (state) - { - case state_counting: - // do nothing -> we just prepare for testing process - break; - case state_working: - // mark already known to be invisible visuals, set breakpoint - testQ_V = 0; - testQ_id = 0; - mark(); - RImplementation.set_Feedback(this, test_current); - break; - case state_usingTC: - // just mark - mark(); - break; - } -} - -void smapvis::end() -{ - // Gather stats - u32 ts, td; - RImplementation.get_Counters(ts, td); - RImplementation.stats.ic_total += ts; - RImplementation.set_Feedback(0, 0); - - switch (state) - { - case state_counting: - // switch to 'working' - if (sleep()) - { - test_count = ts; - test_current = 0; - state = state_working; - } - break; - case state_working: - // feedback should be called at this time -> clear feedback - // issue query - if (testQ_V) - { - RImplementation.occq_begin(testQ_id); - RImplementation.marker += 1; - RImplementation.r_dsgraph_insert_static(testQ_V); - RImplementation.r_dsgraph_render_graph(0); - RImplementation.occq_end(testQ_id); - testQ_frame = Device.dwFrame + 1; // get result on next frame - } - break; - case state_usingTC: - // nothing to do - break; - } -} - -void smapvis::flushoccq() -{ - // the tough part - if (testQ_frame != Device.dwFrame) return; - if ((state != state_working) || (!testQ_V)) return; - u64 fragments = RImplementation.occq_get(testQ_id); - if (0 == fragments) - { - // this is invisible shadow-caster, register it - // next time we will not get this caster, so 'test_current' remains the same - invisible.push_back(testQ_V); - test_count --; - } - else - { - // this is visible shadow-caster, advance testing - test_current ++; - } - - testQ_V = 0; - - if (test_current == test_count) - { - // we are at the end of list - if (state == state_working) state = state_usingTC; - } -} - -void smapvis::resetoccq() -{ - if (testQ_frame == (Device.dwFrame + 1)) testQ_frame--; - flushoccq(); -} - -void smapvis::mark() -{ - RImplementation.stats.ic_culled += invisible.size(); - u32 marker = RImplementation.marker + 1; // we are called befor marker increment - for (u32 it = 0; it < invisible.size(); it++) - invisible[it]->vis.marker = marker; // this effectively disables processing -} - -void smapvis::rfeedback_static(dxRender_Visual* V) -{ - testQ_V = V; - RImplementation.set_Feedback(0, 0); -} diff --git a/src/Layers/xrRenderPC_R4/light_smapvis.h b/src/Layers/xrRenderPC_R4/light_smapvis.h deleted file mode 100644 index 29bca1ce7b..0000000000 --- a/src/Layers/xrRenderPC_R4/light_smapvis.h +++ /dev/null @@ -1,36 +0,0 @@ -#pragma once - -class smapvis : public R_feedback -{ -public: - enum - { - state_counting = 0, - state_working = 1, - state_usingTC = 3, - } state; - - xr_vector invisible; - - u32 frame_sleep; - u32 test_count; - u32 test_current; - dxRender_Visual* testQ_V; - u32 testQ_id; - u32 testQ_frame; -public: - smapvis(); - ~smapvis(); - - void invalidate(); - void begin(); // should be called before 'marker++' and before graph-build - void end(); - void mark(); - void flushoccq(); // should be called when no rendering of light is supposed - - void resetoccq(); - - IC bool sleep() { return Device.dwFrame > frame_sleep; } - - virtual void rfeedback_static(dxRender_Visual* V); -}; diff --git a/src/Layers/xrRenderPC_R4/light_vis.cpp b/src/Layers/xrRenderPC_R4/light_vis.cpp deleted file mode 100644 index d53e081152..0000000000 --- a/src/Layers/xrRenderPC_R4/light_vis.cpp +++ /dev/null @@ -1,90 +0,0 @@ -#include "StdAfx.h" -#include "../xrRender/light.h" -#include "../../xrEngine/cl_intersect.h" - -const u32 delay_small_min = 1; -const u32 delay_small_max = 3; -const u32 delay_large_min = 10; -const u32 delay_large_max = 20; -const u32 cullfragments = 4; - -void light::vis_prepare() -{ - if (int(indirect_photons) != ps_r2_GI_photons) gi_generate(); - - // . test is sheduled for future = keep old result - // . test time comes :) - // . camera inside light volume = visible, shedule for 'small' interval - // . perform testing = ???, pending - - u32 frame = Device.dwFrame; - if (frame < vis.frame2test) return; - - float safe_area = VIEWPORT_NEAR; - { - float a0 = deg2rad(Device.fFOV * Device.fASPECT / 2.f); - float a1 = deg2rad(Device.fFOV / 2.f); - float x0 = VIEWPORT_NEAR / _cos(a0); - float x1 = VIEWPORT_NEAR / _cos(a1); - float c = _sqrt(x0 * x0 + x1 * x1); - safe_area = _max(_max(VIEWPORT_NEAR, _max(x0, x1)), c); - } - - //Msg ("sc[%f,%f,%f]/c[%f,%f,%f] - sr[%f]/r[%f]",VPUSH(spatial.center),VPUSH(position),spatial.radius,range); - //Msg ("dist:%f, sa:%f",Device.vCameraPosition.distance_to(spatial.center),safe_area); - bool skiptest = false; - if (ps_r2_ls_flags.test(R2FLAG_EXP_DONT_TEST_UNSHADOWED) && !flags.bShadow) skiptest = true; - if (ps_r2_ls_flags.test(R2FLAG_EXP_DONT_TEST_SHADOWED) && flags.bShadow) skiptest = true; - //if (ps_ssfx_volumetric.x > 0 && flags.bShadow) skiptest = true; // Temp Fix - - vis.distance = Device.vCameraPosition.distance_to(spatial.sphere.P); - - if (skiptest || vis.distance <= (spatial.sphere.R * 1.01f + safe_area)) - { - // small error - vis.visible = true; - vis.pending = false; - vis.frame2test = frame + ::Random.randI(delay_small_min, delay_small_max); - return; - } - - // testing - vis.pending = true; - xform_calc(); - RCache.set_xform_world(m_xform); - vis.query_order = RImplementation.occq_begin(vis.query_id); - // Hack: Igor. Light is visible if it's frutum is visible. (Only for volumetric) - // Hope it won't slow down too much since there's not too much volumetric lights - // TODO: sort for performance improvement if this technique hurts - if ((flags.type == IRender_Light::SPOT) && flags.bShadow && flags.bVolumetric) - RCache.set_Stencil(FALSE); - else - RCache.set_Stencil(TRUE, D3DCMP_LESSEQUAL, 0x01, 0xff, 0x00); - RImplementation.Target->draw_volume(this); - RImplementation.occq_end(vis.query_id); -} - -void light::vis_update() -{ - // . not pending ->>> return (early out) - // . test-result: visible: - // . shedule for 'large' interval - // . test-result: invisible: - // . shedule for 'next-frame' interval - - if (!vis.pending) return; - - u32 frame = Device.dwFrame; - u64 fragments = RImplementation.occq_get(vis.query_id); - - vis.visible = (fragments > cullfragments); - vis.pending = false; - if (vis.visible) - { - vis.frame2test = frame + ::Random.randI(delay_large_min, delay_large_max); - } - else - { - vis.frame2test = frame + 1; - } -} diff --git a/src/Layers/xrRenderPC_R4/r2_R_calculate.cpp b/src/Layers/xrRenderPC_R4/r2_R_calculate.cpp deleted file mode 100644 index 10bc156d00..0000000000 --- a/src/Layers/xrRenderPC_R4/r2_R_calculate.cpp +++ /dev/null @@ -1,75 +0,0 @@ -#include "stdafx.h" -#include "../../xrEngine/customhud.h" - -float g_fSCREEN; - -extern float r_dtex_range; -extern float r_ssaDISCARD; -extern float r_ssaDONTSORT; -extern float r_ssaLOD_A; -extern float r_ssaLOD_B; -extern float r_ssaHZBvsTEX; -extern float r_ssaGLOD_start, r_ssaGLOD_end; - -void CRender::Calculate() -{ - // Transfer to global space to avoid deep pointer access - IRender_Target* T = getTarget(); - float fov_factor = _sqr(90.f / Device.fFOV); - g_fSCREEN = float(T->get_width() * T->get_height()) * fov_factor * (EPS_S + ps_r__LOD); - r_ssaDISCARD = _sqr(ps_r__ssaDISCARD) / g_fSCREEN; - r_ssaDONTSORT = _sqr(ps_r__ssaDONTSORT / 3) / g_fSCREEN; - r_ssaLOD_A = _sqr(ps_r2_ssaLOD_A / 3) / g_fSCREEN; - r_ssaLOD_B = _sqr(ps_r2_ssaLOD_B / 3) / g_fSCREEN; - r_ssaGLOD_start = _sqr(ps_r__GLOD_ssa_start / 3) / g_fSCREEN; - r_ssaGLOD_end = _sqr(ps_r__GLOD_ssa_end / 3) / g_fSCREEN; - r_ssaHZBvsTEX = _sqr(ps_r__ssaHZBvsTEX / 3) / g_fSCREEN; - r_dtex_range = ps_r2_df_parallax_range * g_fSCREEN / (1024.f * 768.f); - - // Detect camera-sector - if (!vLastCameraPos.similar(Device.vCameraPosition, EPS_S)) - { - CSector* pSector = (CSector*)detectSector(Device.vCameraPosition); - if (pSector && (pSector != pLastSector)) - g_pGamePersistent->OnSectorChanged(translateSector(pSector)); - - if (0 == pSector) pSector = pLastSector; - pLastSector = pSector; - vLastCameraPos.set(Device.vCameraPosition); - } - - // Check if camera is too near to some portal - if so force DualRender - if (rmPortals) - { - float eps = VIEWPORT_NEAR + EPS_L; - Fvector box_radius; - box_radius.set(eps, eps, eps); - Sectors_xrc.box_options(CDB::OPT_FULL_TEST); - Sectors_xrc.box_query(rmPortals, Device.vCameraPosition, box_radius); - for (int K = 0; K < Sectors_xrc.r_count(); K++) - { - CPortal* pPortal = (CPortal*)Portals[rmPortals->get_tris()[Sectors_xrc.r_begin()[K].id].dummy]; - pPortal->bDualRender = TRUE; - } - } - - // - Lights.Update(); - - // Check if we touch some light even trough portal - lstRenderables.clear(); - g_SpatialSpace->q_sphere(lstRenderables, 0, STYPE_LIGHTSOURCE, Device.vCameraPosition, EPS_L); - for (u32 _it = 0; _it < lstRenderables.size(); _it++) - { - ISpatial* spatial = lstRenderables[_it]; - spatial->spatial_updatesector(); - CSector* sector = (CSector*)spatial->spatial.sector; - if (0 == sector) continue; // disassociated from S/P structure - - VERIFY(spatial->spatial.type & STYPE_LIGHTSOURCE); - // lightsource - light* L = (light*)(spatial->dcast_Light()); - VERIFY(L); - Lights.add_light(L); - } -} diff --git a/src/Layers/xrRenderPC_R4/r2_R_lights.cpp b/src/Layers/xrRenderPC_R4/r2_R_lights.cpp deleted file mode 100644 index 07f8a0cabf..0000000000 --- a/src/Layers/xrRenderPC_R4/r2_R_lights.cpp +++ /dev/null @@ -1,352 +0,0 @@ -#include "stdafx.h" - -IC bool pred_area(light* _1, light* _2) -{ - u32 a0 = _1->X.S.size; - u32 a1 = _2->X.S.size; - return a0 > a1; // reverse -> descending -} - -bool check_grass_shadow(light* L, CFrustum VB) -{ - // Grass shadows are allowed? - if (ps_ssfx_grass_shadows.x < 3 || !psDeviceFlags2.test(rsGrassShadow)) - return false; - - // Inside the range? - if (L->vis.distance > ps_ssfx_grass_shadows.z) - return false; - - // Is in view? L->vis.visible? - u32 mask = 0xff; - if (!VB.testSphere(L->position, L->range * 0.6f, mask)) - return false; - - return true; -} - -IC void hud_light_apply(xr_map>& saved_pos, xr_vector& source) -{ - for (u32 it = 0; it < source.size(); it++) - { - light* L = source[it]; - if (!L->get_hud_mode()) continue; - - saved_pos.emplace(L, mk_pair(L->position, L->direction)); - - Device.hud_to_world(L->position); - Device.hud_to_world_dir(L->direction); - } -} - -IC void hud_light_restore(xr_map>& saved_pos, xr_vector& source) -{ - for (const auto& saved : saved_pos) - { - light* L = saved.first; - if (!L->get_hud_mode()) continue; - - L->position = saved.second.first; - L->direction = saved.second.second; - } -} - -void CRender::render_lights(light_Package& LP) -{ - xr_map> saved_pos; - ////////////////////////////////////////////////////////////////////////// - // 0. apply hud_mode projection if necessary - hud_light_apply(saved_pos, LP.v_shadowed); - hud_light_apply(saved_pos, LP.v_point); - hud_light_apply(saved_pos, LP.v_spot); - // Refactor order based on ability to pack shadow-maps - // 1. calculate area + sort in descending order - // const u16 smap_unassigned = u16(-1); - { - xr_vector& source = LP.v_shadowed; - for (u32 it = 0; it < source.size(); it++) - { - light* L = source[it]; - L->vis_update(); - if (!L->vis.visible) - { - source.erase(source.begin() + it); - it--; - } - else - { - LR.compute_xf_spot(L); - } - } - } - - // 2. refactor - infact we could go from the backside and sort in ascending order - { - xr_vector& source = LP.v_shadowed; - xr_vector refactored; - refactored.reserve(source.size()); - u32 total = source.size(); - - for (u16 smap_ID = 0; refactored.size() != total; smap_ID++) - { - LP_smap_pool.initialize(RImplementation.o.smapsize); - std::sort(source.begin(), source.end(), pred_area); - for (u32 test = 0; test < source.size(); test++) - { - light* L = source[test]; - SMAP_Rect R; - if (LP_smap_pool.push(R, L->X.S.size)) - { - // OK - L->X.S.posX = R.min.x; - L->X.S.posY = R.min.y; - L->vis.smap_ID = smap_ID; - refactored.push_back(L); - source.erase(source.begin() + test); - test --; - } - } - } - - // save (lights are popped from back) - std::reverse(refactored.begin(), refactored.end()); - LP.v_shadowed = refactored; - } - - PIX_EVENT(SHADOWED_LIGHTS); - - ////////////////////////////////////////////////////////////////////////// - // sort lights by importance??? - // while (has_any_lights_that_cast_shadows) { - // if (has_point_shadowed) -> generate point shadowmap - // if (has_spot_shadowed) -> generate spot shadowmap - // switch-to-accumulator - // if (has_point_unshadowed) -> accum point unshadowed - // if (has_spot_unshadowed) -> accum spot unshadowed - // if (was_point_shadowed) -> accum point shadowed - // if (was_spot_shadowed) -> accum spot shadowed - // } - // if (left_some_lights_that_doesn't cast shadows) - // accumulate them - HOM.Disable(); - while (LP.v_shadowed.size()) - { - // if (has_spot_shadowed) - xr_vector L_spot_s; - stats.s_used ++; - - // generate spot shadowmap - Target->phase_smap_spot_clear(); - xr_vector& source = LP.v_shadowed; - light* L = source.back(); - u16 sid = L->vis.smap_ID; - while (true) - { - if (source.empty()) break; - L = source.back(); - if (L->vis.smap_ID != sid) break; - source.pop_back(); - Lights_LastFrame.push_back(L); - - // render - phase = PHASE_SMAP; - if (RImplementation.o.Tshadows) r_pmask(true, true); - else r_pmask(true, false); - L->svis.begin(); - PIX_EVENT(SHADOWED_LIGHTS_RENDER_SUBSPACE); - r_dsgraph_render_subspace(L->spatial.sector, L->X.S.combine, L->position, TRUE); - bool bNormal = mapNormalPasses[0][0].size() || mapMatrixPasses[0][0].size(); - bool bSpecial = mapNormalPasses[1][0].size() || mapMatrixPasses[1][0].size() || mapSorted.size(); - if (bNormal || bSpecial) - { - stats.s_merged ++; - L_spot_s.push_back(L); - Target->phase_smap_spot(L); - RCache.set_xform_world(Fidentity); - RCache.set_xform_view(L->X.S.view); - RCache.set_xform_project(L->X.S.project); - r_dsgraph_render_graph(0); - if (Details) - { - if (check_grass_shadow(L, ViewBase)) - { - Details->fade_distance = -1; // Use light position to calc "fade" - Details->light_position.set(L->position); - Details->Render(); - } - } - L->X.S.transluent = FALSE; - if (bSpecial) - { - L->X.S.transluent = TRUE; - Target->phase_smap_spot_tsh(L); - PIX_EVENT(SHADOWED_LIGHTS_RENDER_GRAPH); - r_dsgraph_render_graph(1); // normal level, secondary priority - PIX_EVENT(SHADOWED_LIGHTS_RENDER_SORTED); - r_dsgraph_render_sorted(); // strict-sorted geoms - } - } - else - { - stats.s_finalclip ++; - } - L->svis.end(); - r_pmask(true, false); - } - - PIX_EVENT(UNSHADOWED_LIGHTS); - - // switch-to-accumulator - Target->phase_accumulator(); - HOM.Disable(); - - PIX_EVENT(POINT_LIGHTS); - - // if (has_point_unshadowed) -> accum point unshadowed - if (!LP.v_point.empty()) - { - light* L = LP.v_point.back(); - LP.v_point.pop_back(); - L->vis_update(); - if (L->vis.visible) - { - Target->accum_point(L); - render_indirect(L); - } - } - - PIX_EVENT(SPOT_LIGHTS); - - // if (has_spot_unshadowed) -> accum spot unshadowed - if (!LP.v_spot.empty()) - { - light* L = LP.v_spot.back(); - LP.v_spot.pop_back(); - L->vis_update(); - if (L->vis.visible) - { - LR.compute_xf_spot(L); - Target->accum_spot(L); - render_indirect(L); - } - } - - PIX_EVENT(SPOT_LIGHTS_ACCUM_VOLUMETRIC); - - // if (was_spot_shadowed) -> accum spot shadowed - if (!L_spot_s.empty()) - { - PIX_EVENT(ACCUM_SPOT); - PIX_EVENT(ACCUM_VOLUMETRIC); - for (u32 it = 0; it < L_spot_s.size(); it++) - { - Target->accum_spot(L_spot_s[it]); - render_indirect(L_spot_s[it]); - - if (RImplementation.o.advancedpp && ps_r2_ls_flags.is(R2FLAG_VOLUMETRIC_LIGHTS)) - { - // Current Resolution - float w = float(Device.dwWidth); - float h = float(Device.dwHeight); - - // Adjust resolution - if (RImplementation.o.ssfx_volumetric) - Target->set_viewport_size(HW.pContext, w / 8, h / 8); - - Target->accum_volumetric(L_spot_s[it]); - - // Restore resolution - if (RImplementation.o.ssfx_volumetric) - Target->set_viewport_size(HW.pContext, w, h); - } - } - - L_spot_s.clear(); - } - } - - PIX_EVENT(POINT_LIGHTS_ACCUM); - // Point lighting (unshadowed, if left) - if (!LP.v_point.empty()) - { - xr_vector& Lvec = LP.v_point; - for (u32 pid = 0; pid < Lvec.size(); pid++) - { - Lvec[pid]->vis_update(); - if (Lvec[pid]->vis.visible) - { - render_indirect(Lvec[pid]); - Target->accum_point(Lvec[pid]); - } - } - Lvec.clear(); - } - - PIX_EVENT(SPOT_LIGHTS_ACCUM); - // Spot lighting (unshadowed, if left) - if (!LP.v_spot.empty()) - { - xr_vector& Lvec = LP.v_spot; - for (u32 pid = 0; pid < Lvec.size(); pid++) - { - Lvec[pid]->vis_update(); - if (Lvec[pid]->vis.visible) - { - LR.compute_xf_spot(Lvec[pid]); - render_indirect(Lvec[pid]); - Target->accum_spot(Lvec[pid]); - } - } - Lvec.clear(); - } - - // restore world projection if necessary - hud_light_restore(saved_pos, LP.v_shadowed); - hud_light_restore(saved_pos, LP.v_point); - hud_light_restore(saved_pos, LP.v_spot); -} - -void CRender::render_indirect(light* L) -{ - if (!ps_r2_ls_flags.test(R2FLAG_GI)) return; - - light LIGEN; - LIGEN.set_type(IRender_Light::REFLECTED); - LIGEN.set_shadow(false); - LIGEN.set_cone(PI_DIV_2 * 2.f); - - xr_vector& Lvec = L->indirect; - if (Lvec.empty()) return; - float LE = L->color.intensity(); - for (u32 it = 0; it < Lvec.size(); it++) - { - light_indirect& LI = Lvec[it]; - - // energy and color - float LIE = LE * LI.E; - if (LIE < ps_r2_GI_clip) continue; - Fvector T; - T.set(L->color.r, L->color.g, L->color.b).mul(LI.E); - LIGEN.set_color(T.x, T.y, T.z); - - // geometric - Fvector L_up, L_right; - L_up.set(0, 1, 0); - if (_abs(L_up.dotproduct(LI.D)) > .99f) L_up.set(0, 0, 1); - L_right.crossproduct(L_up, LI.D).normalize(); - LIGEN.spatial.sector = LI.S; - LIGEN.set_position(LI.P); - LIGEN.set_rotation(LI.D, L_right); - - // range - // dist^2 / range^2 = A - has infinity number of solutions - // approximate energy by linear fallof Emax / (1 + x) = Emin - float Emax = LIE; - float Emin = 1.f / 255.f; - float x = (Emax - Emin) / Emin; - if (x < 0.1f) continue; - LIGEN.set_range(x); - - Target->accum_reflected(&LIGEN); - } -} diff --git a/src/Layers/xrRenderPC_R4/r2_R_sun.cpp b/src/Layers/xrRenderPC_R4/r2_R_sun.cpp deleted file mode 100644 index 2b0671cb41..0000000000 --- a/src/Layers/xrRenderPC_R4/r2_R_sun.cpp +++ /dev/null @@ -1,1434 +0,0 @@ -#include "stdafx.h" -#include "../../xrEngine/igame_persistent.h" -#include "../../xrEngine/irenderable.h" -#include "../xrRender/FBasicVisual.h" - -#include "r4_R_sun_support.h" - -const float tweak_COP_initial_offs = 1200.f; -const float tweak_ortho_xform_initial_offs = 1000.f; //. ? -const float tweak_guaranteed_range = 20.f; //. ? - -//float OLES_SUN_LIMIT_27_01_07 = 180.f ; -float OLES_SUN_LIMIT_27_01_07 = 100.f; - -const float MAP_SIZE_START = 6.f; -const float MAP_GROW_FACTOR = 4.f; - -////////////////////////////////////////////////////////////////////////// -// tables to calculate view-frustum bounds in world space -// note: D3D uses [0..1] range for Z -static Fvector3 corners [8] = { - {-1, -1, 0}, {-1, -1, +1}, - {-1, +1, +1}, {-1, +1, 0}, - {+1, +1, +1}, {+1, +1, 0}, - {+1, -1, +1}, {+1, -1, 0} -}; -static int facetable[6][4] = { - {6, 7, 5, 4}, {1, 0, 7, 6}, - {1, 2, 3, 0}, {3, 2, 4, 5}, - // near and far planes - {0, 3, 5, 7}, {1, 6, 4, 2}, -}; -////////////////////////////////////////////////////////////////////////// -#define DW_AS_FLT(DW) (*(FLOAT*)&(DW)) -#define FLT_AS_DW(F) (*(DWORD*)&(F)) -#define FLT_SIGN(F) ((FLT_AS_DW(F) & 0x80000000L)) -#define ALMOST_ZERO(F) ((FLT_AS_DW(F) & 0x7f800000L)==0) -#define IS_SPECIAL(F) ((FLT_AS_DW(F) & 0x7f800000L)==0x7f800000L) - -////////////////////////////////////////////////////////////////////////// -struct Frustum -{ - Frustum(); - Frustum(const D3DXMATRIX* matrix); - - D3DXPLANE camPlanes [6]; - int nVertexLUT [6]; - D3DXVECTOR3 pntList [8]; -}; - -struct BoundingBox -{ - D3DXVECTOR3 minPt; - D3DXVECTOR3 maxPt; - - BoundingBox(): minPt(1e33f, 1e33f, 1e33f), maxPt(-1e33f, -1e33f, -1e33f) - { - } - - BoundingBox(const BoundingBox& other): minPt(other.minPt), maxPt(other.maxPt) - { - } - - explicit BoundingBox(const D3DXVECTOR3* points, UINT n): minPt(1e33f, 1e33f, 1e33f), maxPt(-1e33f, -1e33f, -1e33f) - { - for (unsigned int i = 0; i < n; i++) - Merge(&points[i]); - } - - explicit BoundingBox(const std::vector* points): minPt(1e33f, 1e33f, 1e33f), - maxPt(-1e33f, -1e33f, -1e33f) - { - for (unsigned int i = 0; i < points->size(); i++) - Merge(&(*points)[i]); - } - - explicit BoundingBox(const std::vector* boxes): minPt(1e33f, 1e33f, 1e33f), - maxPt(-1e33f, -1e33f, -1e33f) - { - for (unsigned int i = 0; i < boxes->size(); i++) - { - Merge(&(*boxes)[i].maxPt); - Merge(&(*boxes)[i].minPt); - } - } - - void Centroid(D3DXVECTOR3* vec) const { *vec = 0.5f * (minPt + maxPt); } - - void Merge(const D3DXVECTOR3* vec) - { - minPt.x = _min(minPt.x, vec->x); - minPt.y = _min(minPt.y, vec->y); - minPt.z = _min(minPt.z, vec->z); - maxPt.x = _max(maxPt.x, vec->x); - maxPt.y = _max(maxPt.y, vec->y); - maxPt.z = _max(maxPt.z, vec->z); - } - - D3DXVECTOR3 Point(int i) const - { - return D3DXVECTOR3((i & 1) ? minPt.x : maxPt.x, (i & 2) ? minPt.y : maxPt.y, (i & 4) ? minPt.z : maxPt.z); - } -}; - -/////////////////////////////////////////////////////////////////////////// -BOOL LineIntersection2D(D3DXVECTOR2* result, const D3DXVECTOR2* lineA, const D3DXVECTOR2* lineB) -{ - // if the lines are parallel, the lines will not intersect in a point - // NOTE: assumes the rays are already normalized!!!! - VERIFY(_abs(D3DXVec2Dot(&lineA[1], &lineB[1]))<1.f); - - float x[2] = {lineA[0].x, lineB[0].x}; - float y[2] = {lineA[0].y, lineB[0].y}; - float dx[2] = {lineA[1].x, lineB[1].x}; - float dy[2] = {lineA[1].y, lineB[1].y}; - - float x_diff = x[0] - x[1]; - float y_diff = y[0] - y[1]; - - float s = (x_diff - (dx[1] / dy[1]) * y_diff) / ((dx[1] * dy[0] / dy[1]) - dx[0]); - // float t = (x_diff + s*dx[0]) / dx[1]; - - *result = lineA[0] + s * lineA[1]; - return TRUE; -} - -/////////////////////////////////////////////////////////////////////////// -// PlaneIntersection -// computes the point where three planes intersect -// returns whether or not the point exists. -static inline BOOL PlaneIntersection(D3DXVECTOR3* intersectPt, const D3DXPLANE* p0, const D3DXPLANE* p1, - const D3DXPLANE* p2) -{ - D3DXVECTOR3 n0(p0->a, p0->b, p0->c); - D3DXVECTOR3 n1(p1->a, p1->b, p1->c); - D3DXVECTOR3 n2(p2->a, p2->b, p2->c); - - D3DXVECTOR3 n1_n2, n2_n0, n0_n1; - - D3DXVec3Cross(&n1_n2, &n1, &n2); - D3DXVec3Cross(&n2_n0, &n2, &n0); - D3DXVec3Cross(&n0_n1, &n0, &n1); - - float cosTheta = D3DXVec3Dot(&n0, &n1_n2); - - if (ALMOST_ZERO(cosTheta) || IS_SPECIAL(cosTheta)) - return FALSE; - - float secTheta = 1.f / cosTheta; - - n1_n2 = n1_n2 * p0->d; - n2_n0 = n2_n0 * p1->d; - n0_n1 = n0_n1 * p2->d; - - *intersectPt = -(n1_n2 + n2_n0 + n0_n1) * secTheta; - return TRUE; -} - -Frustum::Frustum() -{ - for (int i = 0; i < 6; i++) - camPlanes[i] = D3DXPLANE(0.f, 0.f, 0.f, 0.f); -} - -// build a frustum from a camera (projection, or viewProjection) matrix -Frustum::Frustum(const D3DXMATRIX* matrix) -{ - // build a view frustum based on the current view & projection matrices... - D3DXVECTOR4 column4(matrix->_14, matrix->_24, matrix->_34, matrix->_44); - D3DXVECTOR4 column1(matrix->_11, matrix->_21, matrix->_31, matrix->_41); - D3DXVECTOR4 column2(matrix->_12, matrix->_22, matrix->_32, matrix->_42); - D3DXVECTOR4 column3(matrix->_13, matrix->_23, matrix->_33, matrix->_43); - - D3DXVECTOR4 planes[6]; - planes[0] = column4 - column1; // left - planes[1] = column4 + column1; // right - planes[2] = column4 - column2; // bottom - planes[3] = column4 + column2; // top - planes[4] = column4 - column3; // near - planes[5] = column4 + column3; // far - // ignore near & far plane - - int p; - - for (p = 0; p < 6; p++) // normalize the planes - { - float dot = planes[p].x * planes[p].x + planes[p].y * planes[p].y + planes[p].z * planes[p].z; - dot = 1.f / _sqrt(dot); - planes[p] = planes[p] * dot; - } - - for (p = 0; p < 6; p++) - camPlanes[p] = D3DXPLANE(planes[p].x, planes[p].y, planes[p].z, planes[p].w); - - // build a bit-field that will tell us the indices for the nearest and farthest vertices from each plane... - for (int i = 0; i < 6; i++) - nVertexLUT[i] = ((planes[i].x < 0.f) ? 1 : 0) | ((planes[i].y < 0.f) ? 2 : 0) | ((planes[i].z < 0.f) ? 4 : 0); - - for (int i = 0; i < 8; i++) // compute extrema - { - const D3DXPLANE& p0 = (i & 1) ? camPlanes[4] : camPlanes[5]; - const D3DXPLANE& p1 = (i & 2) ? camPlanes[3] : camPlanes[2]; - const D3DXPLANE& p2 = (i & 4) ? camPlanes[0] : camPlanes[1]; - PlaneIntersection(&pntList[i], &p0, &p1, &p2); - } -} - -////////////////////////////////////////////////////////////////////////// -Fvector3 wform(Fmatrix& m, Fvector3 const& v) -{ - Fvector4 r; - r.x = v.x * m._11 + v.y * m._21 + v.z * m._31 + m._41; - r.y = v.x * m._12 + v.y * m._22 + v.z * m._32 + m._42; - r.z = v.x * m._13 + v.y * m._23 + v.z * m._33 + m._43; - r.w = v.x * m._14 + v.y * m._24 + v.z * m._34 + m._44; - // VERIFY (r.w>0.f); - float invW = 1.0f / r.w; - Fvector3 r3 = {r.x * invW, r.y * invW, r.z * invW}; - return r3; -} - -////////////////////////////////////////////////////////////////////////// -// OLES: naive 3D clipper - roubustness around 0, but works for this sample -// note: normals points to 'outside' -////////////////////////////////////////////////////////////////////////// -const float _eps = 0.000001f; - -struct DumbClipper -{ - CFrustum frustum; - xr_vector planes; - - BOOL clip(D3DXVECTOR3& p0, D3DXVECTOR3& p1) // returns TRUE if result meaningfull - { - float denum; - D3DXVECTOR3 D; - for (int it = 0; it < int(planes.size()); it++) - { - D3DXPLANE& P = planes[it]; - float cls0 = D3DXPlaneDotCoord(&P, &p0); - float cls1 = D3DXPlaneDotCoord(&P, &p1); - if (cls0 > 0 && cls1 > 0) return false; // fully outside - - if (cls0 > 0) - { - // clip p0 - D = p1 - p0; - denum = D3DXPlaneDotNormal(&P, &D); - if (denum != 0) p0 += - D * cls0 / denum; - } - if (cls1 > 0) - { - // clip p1 - D = p0 - p1; - denum = D3DXPlaneDotNormal(&P, &D); - if (denum != 0) p1 += - D * cls1 / denum; - } - } - return true; - } - - D3DXVECTOR3 point(Fbox& bb, int i) const - { - return D3DXVECTOR3((i & 1) ? bb.min.x : bb.max.x, (i & 2) ? bb.min.y : bb.max.y, (i & 4) ? bb.min.z : bb.max.z); - } - - Fbox clipped_AABB(xr_vector>& src, Fmatrix& xf) - { - Fbox3 result; - result.invalidate(); - for (int it = 0; it < int(src.size()); it++) - { - Fbox& bb = src[it]; - u32 mask = frustum.getMask(); - EFC_Visible res = frustum.testAABB(&bb.min.x, mask); - switch (res) - { - case fcvNone: continue; - case fcvFully: - for (int c = 0; c < 8; c++) - { - D3DXVECTOR3 p0 = point(bb, c); - Fvector x0 = wform(xf, *((Fvector*)(&p0))); - result.modify(x0); - } - break; - case fcvPartial: - for (int c0 = 0; c0 < 8; c0++) - { - for (int c1 = 0; c1 < 8; c1++) - { - if (c0 == c1) continue; - D3DXVECTOR3 p0 = point(bb, c0); - D3DXVECTOR3 p1 = point(bb, c1); - if (!clip(p0, p1)) continue; - Fvector x0 = wform(xf, *((Fvector*)(&p0))); - Fvector x1 = wform(xf, *((Fvector*)(&p1))); - result.modify(x0); - result.modify(x1); - } - } - break; - }; - } - return result; - } -}; - -template -inline const _Tp& min(const _Tp& __a, const _Tp& __b) -{ - return __b < __a ? __b : __a; -} - -template -inline const _Tp& max(const _Tp& __a, const _Tp& __b) -{ - return __a < __b ? __b : __a; -} - -xr_vector> s_casters; - -D3DXVECTOR2 BuildTSMProjectionMatrix_caster_depth_bounds(D3DXMATRIX& lightSpaceBasis) -{ - float min_z = 1e32f, max_z = -1e32f; - D3DXMATRIX minmax_xf; - D3DXMatrixMultiply(&minmax_xf, (D3DXMATRIX*)&Device.mView, &lightSpaceBasis); - Fmatrix& minmax_xform = *((Fmatrix*)&minmax_xf); - for (u32 c = 0; c < s_casters.size(); c++) - { - Fvector3 pt; - for (int e = 0; e < 8; e++) - { - s_casters[c].getpoint(e, pt); - pt = wform(minmax_xform, pt); - min_z = _min(min_z, pt.z); - max_z = _max(max_z, pt.z); - } - } - return D3DXVECTOR2(min_z, max_z); -} - -void CRender::render_sun() -{ - PIX_EVENT(render_sun); - light* fuckingsun = (light*)Lights.sun_adapted._get(); - D3DXMATRIX m_LightViewProj; - - // calculate view-frustum bounds in world space - Fmatrix ex_project, ex_full, ex_full_inverse; - { - float _far_ = min(OLES_SUN_LIMIT_27_01_07, g_pGamePersistent->Environment().CurrentEnv->far_plane); - //ex_project.build_projection (deg2rad(Device.fFOV/* *Device.fASPECT*/),Device.fASPECT,ps_r2_sun_near,_far_); - ex_project.build_projection(deg2rad(Device.fFOV/* *Device.fASPECT*/), Device.fASPECT,VIEWPORT_NEAR, _far_); - //VIEWPORT_NEAR - ex_full.mul(ex_project, Device.mView); - D3DXMatrixInverse((D3DXMATRIX*)&ex_full_inverse, 0, (D3DXMATRIX*)&ex_full); - } - - // Compute volume(s) - something like a frustum for infinite directional light - // Also compute virtual light position and sector it is inside - CFrustum cull_frustum; - xr_vector cull_planes; - Fvector3 cull_COP; - CSector* cull_sector; - Fmatrix cull_xform; - { - FPU::m64r(); - // Lets begin from base frustum - Fmatrix fullxform_inv = ex_full_inverse; - DumbConvexVolume hull; - { - hull.points.reserve(8); - for (int p = 0; p < 8; p++) - { - Fvector3 xf = wform(fullxform_inv, corners[p]); - hull.points.push_back(xf); - } - for (int plane = 0; plane < 6; plane++) - { - hull.polys.push_back(DumbConvexVolume::_poly()); - for (int pt = 0; pt < 4; pt++) - hull.polys.back().points.push_back(facetable[plane][pt]); - } - } - hull.compute_caster_model(cull_planes, fuckingsun->direction); - - // Search for default sector - assume "default" or "outdoor" sector is the largest one - //. hack: need to know real outdoor sector - CSector* largest_sector = 0; - float largest_sector_vol = 0; - for (u32 s = 0; s < Sectors.size(); s++) - { - CSector* S = (CSector*)Sectors[s]; - dxRender_Visual* V = S->root(); - float vol = V->vis.box.getvolume(); - if (vol > largest_sector_vol) - { - largest_sector_vol = vol; - largest_sector = S; - } - } - cull_sector = largest_sector; - - // COP - 100 km away - cull_COP.mad(Device.vCameraPosition, fuckingsun->direction, -tweak_COP_initial_offs); - - // Create frustum for query - cull_frustum._clear(); - for (u32 p = 0; p < cull_planes.size(); p++) - cull_frustum._add(cull_planes[p]); - - // Create approximate ortho-xform - // view: auto find 'up' and 'right' vectors - Fmatrix mdir_View, mdir_Project; - Fvector L_dir, L_up, L_right, L_pos; - L_pos.set(fuckingsun->position); - L_dir.set(fuckingsun->direction).normalize(); - L_up.set(0, 1, 0); - if (_abs(L_up.dotproduct(L_dir)) > .99f) L_up.set(0, 0, 1); - L_right.crossproduct(L_up, L_dir).normalize(); - L_up.crossproduct(L_dir, L_right).normalize(); - mdir_View.build_camera_dir(L_pos, L_dir, L_up); - - // projection: box - Fbox frustum_bb; - frustum_bb.invalidate(); - for (int it = 0; it < 8; it++) - { - Fvector xf = wform(mdir_View, hull.points[it]); - frustum_bb.modify(xf); - } - Fbox& bb = frustum_bb; - bb.grow(EPS); - D3DXMatrixOrthoOffCenterLH((D3DXMATRIX*)&mdir_Project, bb.min.x, bb.max.x, bb.min.y, bb.max.y, - bb.min.z - tweak_ortho_xform_initial_offs, bb.max.z); - - // full-xform - cull_xform.mul(mdir_Project, mdir_View); - FPU::m24r(); - } - - // Begin SMAP-render - { - HOM.Disable(); - phase = PHASE_SMAP; - if (RImplementation.o.Tshadows) r_pmask(true, true); - else r_pmask(true, false); - // fuckingsun->svis.begin (); - } - - // Fill the database - xr_vector>& s_receivers = main_coarse_structure; - s_casters.reserve(s_receivers.size()); - set_Recorder(&s_casters); - r_dsgraph_render_subspace(cull_sector, &cull_frustum, cull_xform, cull_COP, TRUE); - - // IGNORE PORTALS - if (ps_r2_ls_flags.test(R2FLAG_SUN_IGNORE_PORTALS)) - { - for (u32 s = 0; s < Sectors.size(); s++) - { - CSector* S = (CSector*)Sectors[s]; - dxRender_Visual* root = S->root(); - - set_Frustum(&cull_frustum); - add_Geometry(root); - } - } - set_Recorder(NULL); - - // Prepare to interact with D3DX code - const D3DXMATRIX& m_View = *((D3DXMATRIX*)(&Device.mView)); - const D3DXMATRIX& m_Projection = *((D3DXMATRIX*)(&ex_project)); - const D3DXVECTOR3 m_lightDir = -D3DXVECTOR3(fuckingsun->direction.x, fuckingsun->direction.y, - fuckingsun->direction.z); - - // these are the limits specified by the physical camera - // gamma is the "tilt angle" between the light and the view direction. - float m_fCosGamma = m_lightDir.x * m_View._13 + - m_lightDir.y * m_View._23 + - m_lightDir.z * m_View._33; - float m_fTSM_Delta = ps_r2_sun_tsm_projection; - - // Compute REAL sheared xform based on receivers/casters information - FPU::m64r(); - if (_abs(m_fCosGamma) < 0.99f && ps_r2_ls_flags.test(R2FLAG_SUN_TSM)) - { - // get the near and the far plane (points) in eye space. - D3DXVECTOR3 frustumPnts[8]; - - Frustum eyeFrustum(&m_Projection); // autocomputes all the extrema points - - for (int i = 0; i < 4; i++) - { - frustumPnts[i] = eyeFrustum.pntList[(i << 1)]; // far plane - frustumPnts[i + 4] = eyeFrustum.pntList[(i << 1) | 0x1]; // near plane - } - - // we need to transform the eye into the light's post-projective space. - // however, the sun is a directional light, so we first need to find an appropriate - // rotate/translate matrix, before constructing an ortho projection. - // this matrix is a variant of "light space" from LSPSMs, with the Y and Z axes permuted - - D3DXVECTOR3 leftVector, upVector, viewVector; - const D3DXVECTOR3 eyeVector(0.f, 0.f, -1.f); // eye is always -Z in eye space - - // code copied straight from BuildLSPSMProjectionMatrix - D3DXVec3TransformNormal(&upVector, &m_lightDir, &m_View); // lightDir is defined in eye space, so xform it - D3DXVec3Cross(&leftVector, &upVector, &eyeVector); - D3DXVec3Normalize(&leftVector, &leftVector); - D3DXVec3Cross(&viewVector, &upVector, &leftVector); - - D3DXMATRIX lightSpaceBasis; - lightSpaceBasis._11 = leftVector.x; - lightSpaceBasis._12 = viewVector.x; - lightSpaceBasis._13 = -upVector.x; - lightSpaceBasis._14 = 0.f; - lightSpaceBasis._21 = leftVector.y; - lightSpaceBasis._22 = viewVector.y; - lightSpaceBasis._23 = -upVector.y; - lightSpaceBasis._24 = 0.f; - lightSpaceBasis._31 = leftVector.z; - lightSpaceBasis._32 = viewVector.z; - lightSpaceBasis._33 = -upVector.z; - lightSpaceBasis._34 = 0.f; - lightSpaceBasis._41 = 0.f; - lightSpaceBasis._42 = 0.f; - lightSpaceBasis._43 = 0.f; - lightSpaceBasis._44 = 1.f; - - // rotate the view frustum into light space - D3DXVec3TransformCoordArray(frustumPnts, sizeof(D3DXVECTOR3), frustumPnts, sizeof(D3DXVECTOR3), - &lightSpaceBasis, sizeof(frustumPnts) / sizeof(D3DXVECTOR3)); - - // build an off-center ortho projection that translates and scales the eye frustum's 3D AABB to the unit cube - BoundingBox frustumBox(frustumPnts, sizeof(frustumPnts) / sizeof(D3DXVECTOR3)); - - // also - transform the shadow caster bounding boxes into light projective space. we want to translate along the Z axis so that - // all shadow casters are in front of the near plane. - D3DXVECTOR2 depthbounds = BuildTSMProjectionMatrix_caster_depth_bounds(lightSpaceBasis); - - float min_z = min(depthbounds.x, frustumBox.minPt.z); - float max_z = max(depthbounds.y, frustumBox.maxPt.z); - - if (min_z <= 1.f) //? - { - D3DXMATRIX lightSpaceTranslate; - D3DXMatrixTranslation(&lightSpaceTranslate, 0.f, 0.f, -min_z + 1.f); - max_z = -min_z + max_z + 1.f; - min_z = 1.f; - D3DXMatrixMultiply(&lightSpaceBasis, &lightSpaceBasis, &lightSpaceTranslate); - D3DXVec3TransformCoordArray(frustumPnts, sizeof(D3DXVECTOR3), frustumPnts, sizeof(D3DXVECTOR3), - &lightSpaceTranslate, sizeof(frustumPnts) / sizeof(D3DXVECTOR3)); - frustumBox = BoundingBox(frustumPnts, sizeof(frustumPnts) / sizeof(D3DXVECTOR3)); - } - - D3DXMATRIX lightSpaceOrtho; - D3DXMatrixOrthoOffCenterLH(&lightSpaceOrtho, frustumBox.minPt.x, frustumBox.maxPt.x, frustumBox.minPt.y, - frustumBox.maxPt.y, min_z, max_z); - - // transform the view frustum by the new matrix - D3DXVec3TransformCoordArray(frustumPnts, sizeof(D3DXVECTOR3), frustumPnts, sizeof(D3DXVECTOR3), - &lightSpaceOrtho, sizeof(frustumPnts) / sizeof(D3DXVECTOR3)); - - D3DXVECTOR2 centerPts [2]; - // near plane - centerPts[0].x = 0.25f * (frustumPnts[4].x + frustumPnts[5].x + frustumPnts[6].x + frustumPnts[7].x); - centerPts[0].y = 0.25f * (frustumPnts[4].y + frustumPnts[5].y + frustumPnts[6].y + frustumPnts[7].y); - // far plane - centerPts[1].x = 0.25f * (frustumPnts[0].x + frustumPnts[1].x + frustumPnts[2].x + frustumPnts[3].x); - centerPts[1].y = 0.25f * (frustumPnts[0].y + frustumPnts[1].y + frustumPnts[2].y + frustumPnts[3].y); - - D3DXVECTOR2 centerOrig = (centerPts[0] + centerPts[1]) * 0.5f; - - D3DXMATRIX trapezoid_space; - - D3DXMATRIX xlate_center(1.f, 0.f, 0.f, 0.f, - 0.f, 1.f, 0.f, 0.f, - 0.f, 0.f, 1.f, 0.f, - -centerOrig.x, -centerOrig.y, 0.f, 1.f); - - D3DXVECTOR2 center_dirl = D3DXVECTOR2(centerPts[1] - centerOrig); - float half_center_len = D3DXVec2Length(¢er_dirl); - float x_len = centerPts[1].x - centerOrig.x; - float y_len = centerPts[1].y - centerOrig.y; - - float cos_theta = x_len / half_center_len; - float sin_theta = y_len / half_center_len; - - D3DXMATRIX rot_center(cos_theta, -sin_theta, 0.f, 0.f, - sin_theta, cos_theta, 0.f, 0.f, - 0.f, 0.f, 1.f, 0.f, - 0.f, 0.f, 0.f, 1.f); - - // this matrix transforms the center line to y=0. - // since Top and Base are orthogonal to Center, we can skip computing the convex hull, and instead - // just find the view frustum X-axis extrema. The most negative is Top, the most positive is Base - // Point Q (trapezoid projection point) will be a point on the y=0 line. - D3DXMatrixMultiply(&trapezoid_space, &xlate_center, &rot_center); - D3DXVec3TransformCoordArray(frustumPnts, sizeof(D3DXVECTOR3), frustumPnts, sizeof(D3DXVECTOR3), - &trapezoid_space, sizeof(frustumPnts) / sizeof(D3DXVECTOR3)); - - BoundingBox frustumAABB2D(frustumPnts, sizeof(frustumPnts) / sizeof(D3DXVECTOR3)); - - float x_scale = max(_abs(frustumAABB2D.maxPt.x), _abs(frustumAABB2D.minPt.x)); - float y_scale = max(_abs(frustumAABB2D.maxPt.y), _abs(frustumAABB2D.minPt.y)); - x_scale = 1.f / x_scale; - y_scale = 1.f / y_scale; - - // maximize the area occupied by the bounding box - D3DXMATRIX scale_center(x_scale, 0.f, 0.f, 0.f, - 0.f, y_scale, 0.f, 0.f, - 0.f, 0.f, 1.f, 0.f, - 0.f, 0.f, 0.f, 1.f); - - D3DXMatrixMultiply(&trapezoid_space, &trapezoid_space, &scale_center); - - // scale the frustum AABB up by these amounts (keep all values in the same space) - frustumAABB2D.minPt.x *= x_scale; - frustumAABB2D.maxPt.x *= x_scale; - frustumAABB2D.minPt.y *= y_scale; - frustumAABB2D.maxPt.y *= y_scale; - - // compute eta. - float lambda = frustumAABB2D.maxPt.x - frustumAABB2D.minPt.x; - float delta_proj = m_fTSM_Delta * lambda; //focusPt.x - frustumAABB2D.minPt.x; - const float xi = -0.6f; // - 0.6f; // 80% line - float eta = (lambda * delta_proj * (1.f + xi)) / (lambda * (1.f - xi) - 2.f * delta_proj); - - // compute the projection point a distance eta from the top line. this point is on the center line, y=0 - D3DXVECTOR2 projectionPtQ(frustumAABB2D.maxPt.x + eta, 0.f); - - // find the maximum slope from the projection point to any point in the frustum. this will be the - // projection field-of-view - float max_slope = -1e32f; - float min_slope = 1e32f; - - for (int i = 0; i < sizeof(frustumPnts) / sizeof(D3DXVECTOR3); i++) - { - D3DXVECTOR2 tmp(frustumPnts[i].x * x_scale, frustumPnts[i].y * y_scale); - float x_dist = tmp.x - projectionPtQ.x; - if (!(ALMOST_ZERO(tmp.y) || ALMOST_ZERO(x_dist))) - { - max_slope = max(max_slope, tmp.y / x_dist); - min_slope = min(min_slope, tmp.y / x_dist); - } - } - - float xn = eta; - float xf = lambda + eta; - - D3DXMATRIX ptQ_xlate(-1.f, 0.f, 0.f, 0.f, - 0.f, 1.f, 0.f, 0.f, - 0.f, 0.f, 1.f, 0.f, - projectionPtQ.x, 0.f, 0.f, 1.f); - D3DXMatrixMultiply(&trapezoid_space, &trapezoid_space, &ptQ_xlate); - - // this shear balances the "trapezoid" around the y=0 axis (no change to the projection pt position) - // since we are redistributing the trapezoid, this affects the projection field of view (shear_amt) - float shear_amt = (max_slope + _abs(min_slope)) * 0.5f - max_slope; - max_slope = max_slope + shear_amt; - - D3DXMATRIX trapezoid_shear(1.f, shear_amt, 0.f, 0.f, - 0.f, 1.f, 0.f, 0.f, - 0.f, 0.f, 1.f, 0.f, - 0.f, 0.f, 0.f, 1.f); - - D3DXMatrixMultiply(&trapezoid_space, &trapezoid_space, &trapezoid_shear); - - - float z_aspect = (frustumBox.maxPt.z - frustumBox.minPt.z) / (frustumAABB2D.maxPt.y - frustumAABB2D.minPt.y); - - // perform a 2DH projection to 'unsqueeze' the top line. - D3DXMATRIX trapezoid_projection(xf / (xf - xn), 0.f, 0.f, 1.f, - 0.f, 1.f / max_slope, 0.f, 0.f, - 0.f, 0.f, 1.f / (z_aspect * max_slope), 0.f, - -xn * xf / (xf - xn), 0.f, 0.f, 0.f); - - D3DXMatrixMultiply(&trapezoid_space, &trapezoid_space, &trapezoid_projection); - - // the x axis is compressed to [0..1] as a result of the projection, so expand it to [-1,1] - D3DXMATRIX biasedScaleX(2.f, 0.f, 0.f, 0.f, - 0.f, 1.f, 0.f, 0.f, - 0.f, 0.f, 1.f, 0.f, - -1.f, 0.f, 0.f, 1.f); - D3DXMatrixMultiply(&trapezoid_space, &trapezoid_space, &biasedScaleX); - - D3DXMatrixMultiply(&m_LightViewProj, &m_View, &lightSpaceBasis); - D3DXMatrixMultiply(&m_LightViewProj, &m_LightViewProj, &lightSpaceOrtho); - D3DXMatrixMultiply(&m_LightViewProj, &m_LightViewProj, &trapezoid_space); - } - else - { - m_LightViewProj = *((D3DXMATRIX*)(&cull_xform)); - } - FPU::m24r(); - - // perform "refit" or "focusing" on relevant - if (ps_r2_ls_flags.test(R2FLAG_SUN_FOCUS)) - { - FPU::m64r(); - - // create clipper - DumbClipper view_clipper; - Fmatrix& xform = *((Fmatrix*)&m_LightViewProj); - view_clipper.frustum.CreateFromMatrix(ex_full,FRUSTUM_P_ALL); - for (int p = 0; p < view_clipper.frustum.p_count; p++) - { - Fplane& P = view_clipper.frustum.planes[p]; - view_clipper.planes.push_back(D3DXPLANE(P.n.x, P.n.y, P.n.z, P.d)); - } - - // - Fbox3 b_casters, b_receivers; - Fvector3 pt; - - // casters - b_casters.invalidate(); - for (u32 c = 0; c < s_casters.size(); c++) - { - for (int e = 0; e < 8; e++) - { - s_casters[c].getpoint(e, pt); - pt = wform(xform, pt); - b_casters.modify(pt); - } - } - - // receivers - b_receivers.invalidate(); - b_receivers = view_clipper.clipped_AABB(s_receivers, xform); - Fmatrix x_project, x_full, x_full_inverse; - { - x_project.build_projection(deg2rad(Device.fFOV/* *Device.fASPECT*/), Device.fASPECT, ps_r2_sun_near, - ps_r2_sun_near + tweak_guaranteed_range); - x_project.build_projection(deg2rad(Device.fFOV/* *Device.fASPECT*/), Device.fASPECT,VIEWPORT_NEAR, - ps_r2_sun_near + tweak_guaranteed_range); - x_full.mul(x_project, Device.mView); - D3DXMatrixInverse((D3DXMATRIX*)&x_full_inverse, 0, (D3DXMATRIX*)&x_full); - } - for (int e = 0; e < 8; e++) - { - pt = wform(x_full_inverse, corners[e]); // world space - pt = wform(xform, pt); // trapezoid space - b_receivers.modify(pt); - } - - // some tweaking - b_casters.grow(EPS); - b_receivers.grow(EPS); - - // because caster points are from coarse representation only allow to "shrink" box, not grow - // that is the same as if we first clip casters by frustum - if (b_receivers.min.x < -1) b_receivers.min.x = -1; - if (b_receivers.min.y < -1) b_receivers.min.y = -1; - if (b_casters.min.z < 0) b_casters.min.z = 0; - if (b_receivers.max.x > +1) b_receivers.max.x = +1; - if (b_receivers.max.y > +1) b_receivers.max.y = +1; - if (b_casters.max.z > +1) b_casters.max.z = +1; - - // refit? - /* - const float EPS = 0.001f; - D3DXMATRIX refit; - D3DXMatrixOrthoOffCenterLH ( &refit, b_receivers.min.x, b_receivers.max.x, b_receivers.min.y, b_receivers.max.y, b_casters.min.z-EPS, b_casters.max.z+EPS ); - D3DXMatrixMultiply ( &m_LightViewProj, &m_LightViewProj, &refit); - */ - - float boxWidth = b_receivers.max.x - b_receivers.min.x; - float boxHeight = b_receivers.max.y - b_receivers.min.y; - // the divide by two's cancel out in the translation, but included for clarity - float boxX = (b_receivers.max.x + b_receivers.min.x) / 2.f; - float boxY = (b_receivers.max.y + b_receivers.min.y) / 2.f; - D3DXMATRIX trapezoidUnitCube(2.f / boxWidth, 0.f, 0.f, 0.f, - 0.f, 2.f / boxHeight, 0.f, 0.f, - 0.f, 0.f, 1.f, 0.f, - -2.f * boxX / boxWidth, -2.f * boxY / boxHeight, 0.f, 1.f); - D3DXMatrixMultiply(&m_LightViewProj, &m_LightViewProj, &trapezoidUnitCube); - //D3DXMatrixMultiply( &trapezoid_space, &trapezoid_space, &trapezoidUnitCube ); - FPU::m24r(); - } - - // Finalize & Cleanup - fuckingsun->X.D.combine = *((Fmatrix*)&m_LightViewProj); - s_receivers.clear(); - s_casters.clear(); - - // Render shadow-map - //. !!! We should clip based on shrinked frustum (again) - { - bool bNormal = mapNormalPasses[0][0].size() || mapMatrixPasses[0][0].size(); - bool bSpecial = mapNormalPasses[1][0].size() || mapMatrixPasses[1][0].size() || mapSorted.size(); - if (bNormal || bSpecial) - { - Target->phase_smap_direct(fuckingsun, SE_SUN_FAR); - RCache.set_xform_world(Fidentity); - RCache.set_xform_view(Fidentity); - RCache.set_xform_project(fuckingsun->X.D.combine); - r_dsgraph_render_graph(0); - fuckingsun->X.D.transluent = FALSE; - if (bSpecial) - { - fuckingsun->X.D.transluent = TRUE; - Target->phase_smap_direct_tsh(fuckingsun, SE_SUN_FAR); - r_dsgraph_render_graph(1); // normal level, secondary priority - r_dsgraph_render_sorted(); // strict-sorted geoms - } - } - } - - // End SMAP-render - { - // fuckingsun->svis.end (); - r_pmask(true, false); - } - - // Accumulate - Target->phase_accumulator(); - - if (Target->use_minmax_sm_this_frame()) - { - PIX_EVENT(SE_SUN_FAR_MINMAX_GENERATE); - Target->create_minmax_SM(); - } - - PIX_EVENT(SE_SUN_FAR); - Target->accum_direct(SE_SUN_FAR); - - // Restore XForms - RCache.set_xform_world(Fidentity); - RCache.set_xform_view(Device.mView); - RCache.set_xform_project(Device.mProject); -} - -void CRender::render_sun_near() -{ - light* fuckingsun = (light*)Lights.sun_adapted._get(); - D3DXMATRIX m_LightViewProj; - - // calculate view-frustum bounds in world space - Fmatrix ex_project, ex_full, ex_full_inverse; - { - ex_project.build_projection(deg2rad(Device.fFOV/* *Device.fASPECT*/), Device.fASPECT,VIEWPORT_NEAR, - ps_r2_sun_near); - ex_full.mul(ex_project, Device.mView); - D3DXMatrixInverse((D3DXMATRIX*)&ex_full_inverse, 0, (D3DXMATRIX*)&ex_full); - } - - // Compute volume(s) - something like a frustum for infinite directional light - // Also compute virtual light position and sector it is inside - CFrustum cull_frustum; - xr_vector cull_planes; - Fvector3 cull_COP; - CSector* cull_sector; - Fmatrix cull_xform; - { - FPU::m64r(); - // Lets begin from base frustum - Fmatrix fullxform_inv = ex_full_inverse; -#ifdef _DEBUG - typedef DumbConvexVolume t_volume; -#else - typedef DumbConvexVolume t_volume; -#endif - t_volume hull; - { - hull.points.reserve(9); - for (int p = 0; p < 8; p++) - { - Fvector3 xf = wform(fullxform_inv, corners[p]); - hull.points.push_back(xf); - } - for (int plane = 0; plane < 6; plane++) - { - hull.polys.push_back(t_volume::_poly()); - for (int pt = 0; pt < 4; pt++) - hull.polys.back().points.push_back(facetable[plane][pt]); - } - } - hull.compute_caster_model(cull_planes, fuckingsun->direction); -#ifdef _DEBUG - for (u32 it=0; itdbg_addplane(cull_planes[it],0xffffffff); -#endif - - // Search for default sector - assume "default" or "outdoor" sector is the largest one - //. hack: need to know real outdoor sector - CSector* largest_sector = 0; - float largest_sector_vol = 0; - for (u32 s = 0; s < Sectors.size(); s++) - { - CSector* S = (CSector*)Sectors[s]; - dxRender_Visual* V = S->root(); - float vol = V->vis.box.getvolume(); - if (vol > largest_sector_vol) - { - largest_sector_vol = vol; - largest_sector = S; - } - } - cull_sector = largest_sector; - - // COP - 100 km away - cull_COP.mad(Device.vCameraPosition, fuckingsun->direction, -tweak_COP_initial_offs); - - // Create frustum for query - cull_frustum._clear(); - for (u32 p = 0; p < cull_planes.size(); p++) - cull_frustum._add(cull_planes[p]); - - // Create approximate ortho-xform - // view: auto find 'up' and 'right' vectors - Fmatrix mdir_View, mdir_Project; - Fvector L_dir, L_up, L_right, L_pos; - L_pos.set(fuckingsun->position); - L_dir.set(fuckingsun->direction).normalize(); - L_right.set(1, 0, 0); - if (_abs(L_right.dotproduct(L_dir)) > .99f) L_right.set(0, 0, 1); - L_up.crossproduct(L_dir, L_right).normalize(); - L_right.crossproduct(L_up, L_dir).normalize(); - mdir_View.build_camera_dir(L_pos, L_dir, L_up); - - // projection: box - /* - // Original - float _D = ps_r2_sun_near; - float a0 = deg2rad(Device.fFOV*Device.fASPECT)/2.f; - float a1 = deg2rad(Device.fFOV)/2.f; - float c0 = _D/_cos(a0); - float c1 = _D/_cos(a1); - float k0 = 2.f*c0*_sin(a0); - float k1 = 2.f*c1*_sin(a1); - float borderalpha = (Device.fFOV-10) / (90-10); - - float nearborder = 1*borderalpha + 1.136363636364f*(1-borderalpha); - float spherical_range = ps_r2_sun_near_border * nearborder * _max(_max(c0,c1), _max(k0,k1)*1.414213562373f ); - Fbox frustum_bb; frustum_bb.invalidate (); - hull.points.push_back (Device.vCameraPosition); - for (int it=0; it<9; it++) { - Fvector xf = wform (mdir_View,hull.points[it]); - frustum_bb.modify (xf); - } - float size_x = frustum_bb.max.x - frustum_bb.min.x; - float size_y = frustum_bb.max.y - frustum_bb.min.y; - float diff_x = (spherical_range - size_x)/2.f; //VERIFY(diff_x>=0); - float diff_y = (spherical_range - size_y)/2.f; //VERIFY(diff_y>=0); - frustum_bb.min.x -= diff_x; frustum_bb.max.x += diff_x; - frustum_bb.min.y -= diff_y; frustum_bb.max.y += diff_y; - Fbox& bb = frustum_bb; - D3DXMatrixOrthoOffCenterLH ((D3DXMATRIX*)&mdir_Project,bb.min.x,bb.max.x, bb.min.y,bb.max.y, bb.min.z-tweak_ortho_xform_initial_offs,bb.max.z); - /**/ - - // Simple - Fbox frustum_bb; - frustum_bb.invalidate(); - for (int it = 0; it < 8; it++) - { - //for (int it=0; it<9; it++) { - Fvector xf = wform(mdir_View, hull.points[it]); - frustum_bb.modify(xf); - } - Fbox& bb = frustum_bb; - bb.grow(EPS); - D3DXMatrixOrthoOffCenterLH((D3DXMATRIX*)&mdir_Project, bb.min.x, bb.max.x, bb.min.y, bb.max.y, - bb.min.z - tweak_ortho_xform_initial_offs, bb.max.z); - /**/ - - - // build viewport xform - float view_dim = float(RImplementation.o.smapsize); - Fmatrix m_viewport = { - view_dim / 2.f, 0.0f, 0.0f, 0.0f, - 0.0f, -view_dim / 2.f, 0.0f, 0.0f, - 0.0f, 0.0f, 1.0f, 0.0f, - view_dim / 2.f, view_dim / 2.f, 0.0f, 1.0f - }; - Fmatrix m_viewport_inv; - D3DXMatrixInverse((D3DXMATRIX*)&m_viewport_inv, 0, (D3DXMATRIX*)&m_viewport); - - // snap view-position to pixel - cull_xform.mul(mdir_Project, mdir_View); - Fvector cam_proj = wform(cull_xform, Device.vCameraPosition); - Fvector cam_pixel = wform(m_viewport, cam_proj); - cam_pixel.x = floorf(cam_pixel.x); - cam_pixel.y = floorf(cam_pixel.y); - Fvector cam_snapped = wform(m_viewport_inv, cam_pixel); - Fvector diff; - diff.sub(cam_snapped, cam_proj); - Fmatrix adjust; - adjust.translate(diff); - cull_xform.mulA_44(adjust); - - // calculate scissor - Fbox scissor; - scissor.invalidate(); - Fmatrix scissor_xf; - scissor_xf.mul(m_viewport, cull_xform); - for (int it = 0; it < 9; it++) - { - Fvector xf = wform(scissor_xf, hull.points[it]); - scissor.modify(xf); - } - s32 limit = RImplementation.o.smapsize - 1; - fuckingsun->X.D.minX = clampr(iFloor(scissor.min.x), 0, limit); - fuckingsun->X.D.maxX = clampr(iCeil(scissor.max.x), 0, limit); - fuckingsun->X.D.minY = clampr(iFloor(scissor.min.y), 0, limit); - fuckingsun->X.D.maxY = clampr(iCeil(scissor.max.y), 0, limit); - - // full-xform - FPU::m24r(); - } - - // Begin SMAP-render - { - bool bSpecialFull = mapNormalPasses[1][0].size() || mapMatrixPasses[1][0].size() || mapSorted.size(); - VERIFY(!bSpecialFull); - HOM.Disable(); - phase = PHASE_SMAP; - if (RImplementation.o.Tshadows) r_pmask(true, true); - else r_pmask(true, false); - // fuckingsun->svis.begin (); - } - - // Fill the database - r_dsgraph_render_subspace(cull_sector, &cull_frustum, cull_xform, cull_COP, TRUE); - - // Finalize & Cleanup - fuckingsun->X.D.combine = cull_xform; //*((Fmatrix*)&m_LightViewProj); - - // Render shadow-map - //. !!! We should clip based on shrinked frustum (again) - { - bool bNormal = mapNormalPasses[0][0].size() || mapMatrixPasses[0][0].size(); - bool bSpecial = mapNormalPasses[1][0].size() || mapMatrixPasses[1][0].size() || mapSorted.size(); - if (bNormal || bSpecial) - { - Target->phase_smap_direct(fuckingsun, SE_SUN_NEAR); - RCache.set_xform_world(Fidentity); - RCache.set_xform_view(Fidentity); - RCache.set_xform_project(fuckingsun->X.D.combine); - r_dsgraph_render_graph(0); - if (ps_r2_ls_flags.test(R2FLAG_SUN_DETAILS)) - Details->Render(); - fuckingsun->X.D.transluent = FALSE; - if (bSpecial) - { - fuckingsun->X.D.transluent = TRUE; - Target->phase_smap_direct_tsh(fuckingsun, SE_SUN_NEAR); - r_dsgraph_render_graph(1); // normal level, secondary priority - r_dsgraph_render_sorted(); // strict-sorted geoms - } - } - } - - // End SMAP-render - { - // fuckingsun->svis.end (); - r_pmask(true, false); - } - - // Accumulate - Target->phase_accumulator(); - - if (Target->use_minmax_sm_this_frame()) - { - PIX_EVENT(SE_SUN_NEAR_MINMAX_GENERATE); - Target->create_minmax_SM(); - } - - PIX_EVENT(SE_SUN_NEAR); - Target->accum_direct(SE_SUN_NEAR); - - // Restore XForms - RCache.set_xform_world(Fidentity); - RCache.set_xform_view(Device.mView); - RCache.set_xform_project(Device.mProject); -} - -void CRender::render_sun_filtered() -{ - if (!RImplementation.o.sunfilter) return; - Target->phase_accumulator(); - PIX_EVENT(SE_SUN_LUMINANCE); - Target->accum_direct(SE_SUN_LUMINANCE); -} - -void CRender::init_cacades() -{ - u32 cascade_count = 3; - m_sun_cascades.resize(cascade_count); - - float fBias = -0.0000025f; - // float size = MAP_SIZE_START; - m_sun_cascades[0].reset_chain = true; - m_sun_cascades[0].size = ps_ssfx_shadow_cascades.x; //20 - m_sun_cascades[0].bias = m_sun_cascades[0].size * fBias; - - m_sun_cascades[1].size = ps_ssfx_shadow_cascades.y; //40 - m_sun_cascades[1].bias = m_sun_cascades[1].size * fBias; - - m_sun_cascades[2].size = ps_ssfx_shadow_cascades.z; //160 - m_sun_cascades[2].bias = m_sun_cascades[2].size * fBias; - - // for( u32 i = 0; i < cascade_count; ++i ) - // { - // m_sun_cascades[i].size = size; - // size *= MAP_GROW_FACTOR; - // } - /// m_sun_cascades[m_sun_cascades.size()-1].size = 80; -} - -void CRender::render_sun_cascades() -{ - bool b_need_to_render_sunshafts = RImplementation.Target->need_to_render_sunshafts(); - bool last_cascade_chain_mode = m_sun_cascades.back().reset_chain; - if (b_need_to_render_sunshafts) - m_sun_cascades[m_sun_cascades.size() - 1].reset_chain = true; - - for (u32 i = 0; i < m_sun_cascades.size(); ++i) - render_sun_cascade(i); - - if (b_need_to_render_sunshafts) - m_sun_cascades[m_sun_cascades.size() - 1].reset_chain = last_cascade_chain_mode; -} - -void CRender::render_sun_cascade(u32 cascade_ind) -{ - light* fuckingsun = (light*)Lights.sun_adapted._get(); - - // calculate view-frustum bounds in world space - Fmatrix ex_project, ex_full, ex_full_inverse; - { - ex_project = Device.mProject; - ex_full.mul(ex_project, Device.mView); - D3DXMatrixInverse((D3DXMATRIX*)&ex_full_inverse, 0, (D3DXMATRIX*)&ex_full); - } - - // Compute volume(s) - something like a frustum for infinite directional light - // Also compute virtual light position and sector it is inside - CFrustum cull_frustum; - xr_vector cull_planes; - Fvector3 cull_COP; - CSector* cull_sector; - Fmatrix cull_xform; - { - FPU::m64r(); - // Lets begin from base frustum - Fmatrix fullxform_inv = ex_full_inverse; -#ifdef _DEBUG - typedef DumbConvexVolume t_volume; -#else - typedef DumbConvexVolume t_volume; -#endif - - //******************************* Need to be placed after cuboid built ************************** - // Search for default sector - assume "default" or "outdoor" sector is the largest one - //. hack: need to know real outdoor sector - CSector* largest_sector = 0; - float largest_sector_vol = 0; - for (u32 s = 0; s < Sectors.size(); s++) - { - CSector* S = (CSector*)Sectors[s]; - dxRender_Visual* V = S->root(); - float vol = V->vis.box.getvolume(); - if (vol > largest_sector_vol) - { - largest_sector_vol = vol; - largest_sector = S; - } - } - cull_sector = largest_sector; - - // COP - 100 km away - cull_COP.mad(Device.vCameraPosition, fuckingsun->direction, -tweak_COP_initial_offs); - - // Create approximate ortho-xform - // view: auto find 'up' and 'right' vectors - Fmatrix mdir_View, mdir_Project; - Fvector L_dir, L_up, L_right, L_pos; - L_pos.set(fuckingsun->position); - L_dir.set(fuckingsun->direction).normalize(); - L_right.set(1, 0, 0); - if (_abs(L_right.dotproduct(L_dir)) > .99f) L_right.set(0, 0, 1); - L_up.crossproduct(L_dir, L_right).normalize(); - L_right.crossproduct(L_up, L_dir).normalize(); - mdir_View.build_camera_dir(L_pos, L_dir, L_up); - - - ////////////////////////////////////////////////////////////////////////// -#ifdef _DEBUG - typedef FixedConvexVolume t_cuboid; -#else - typedef FixedConvexVolume t_cuboid; -#endif - - t_cuboid light_cuboid; - { - // Initialize the first cascade rays, then each cascade will initialize rays for next one. - if (cascade_ind == 0 || m_sun_cascades[cascade_ind].reset_chain) - { - Fvector3 near_p, edge_vec; - for (int p = 0; p < 4; p++) - { - // Fvector asd = Device.vCameraDirection; - // asd.mul(-2); - // asd.add(Device.vCameraPosition); - // near_p = Device.vCameraPosition;//wform (fullxform_inv,asd); // - near_p = wform(fullxform_inv, corners[facetable[4][p]]); - - edge_vec = wform(fullxform_inv, corners[facetable[5][p]]); - edge_vec.sub(near_p); - edge_vec.normalize(); - - light_cuboid.view_frustum_rays.push_back(sun::ray(near_p, edge_vec)); - } - } - else - light_cuboid.view_frustum_rays = m_sun_cascades[cascade_ind].rays; - - light_cuboid.view_ray.P = Device.vCameraPosition; - light_cuboid.view_ray.D = Device.vCameraDirection; - light_cuboid.light_ray.P = L_pos; - light_cuboid.light_ray.D = L_dir; - } - - // THIS NEED TO BE A CONSTATNT - Fplane light_top_plane; - light_top_plane.build_unit_normal(L_pos, L_dir); - float dist = light_top_plane.classify(Device.vCameraPosition); - - float map_size = m_sun_cascades[cascade_ind].size; - D3DXMatrixOrthoOffCenterLH((D3DXMATRIX*)&mdir_Project, -map_size * 0.5f, map_size * 0.5f, -map_size * 0.5f, - map_size * 0.5f, 0.1, dist + map_size); - - ////////////////////////////////////////////////////////////////////////// - - - /**/ - - // build viewport xform - float view_dim = float(RImplementation.o.smapsize); - Fmatrix m_viewport = { - view_dim / 2.f, 0.0f, 0.0f, 0.0f, - 0.0f, -view_dim / 2.f, 0.0f, 0.0f, - 0.0f, 0.0f, 1.0f, 0.0f, - view_dim / 2.f, view_dim / 2.f, 0.0f, 1.0f - }; - Fmatrix m_viewport_inv; - D3DXMatrixInverse((D3DXMATRIX*)&m_viewport_inv, 0, (D3DXMATRIX*)&m_viewport); - - // snap view-position to pixel - cull_xform.mul(mdir_Project, mdir_View); - Fmatrix cull_xform_inv; - cull_xform_inv.invert(cull_xform); - - - // light_cuboid.light_cuboid_points.reserve (9); - for (int p = 0; p < 8; p++) - { - Fvector3 xf = wform(cull_xform_inv, corners[p]); - light_cuboid.light_cuboid_points[p] = xf; - } - - // only side planes - for (int plane = 0; plane < 4; plane++) - for (int pt = 0; pt < 4; pt++) - { - int asd = facetable[plane][pt]; - light_cuboid.light_cuboid_polys[plane].points[pt] = asd; - } - - - Fvector lightXZshift; - light_cuboid.compute_caster_model_fixed(cull_planes, lightXZshift, m_sun_cascades[cascade_ind].size, - m_sun_cascades[cascade_ind].reset_chain); - Fvector proj_view = Device.vCameraDirection; - proj_view.y = 0; - proj_view.normalize(); - // lightXZshift.mad(proj_view, 20); - - // Initialize rays for the next cascade - if (cascade_ind < m_sun_cascades.size() - 1) - m_sun_cascades[cascade_ind + 1].rays = light_cuboid.view_frustum_rays; - - // #ifdef _DEBUG - - static bool draw_debug = false; - if (draw_debug && cascade_ind == 0) - for (u32 it = 0; it < cull_planes.size(); it++) - RImplementation.Target->dbg_addplane(cull_planes[it], it * 0xFFF); - //#endifDDS - - Fvector cam_shifted = L_pos; - cam_shifted.add(lightXZshift); - - // rebuild the view transform with the shift. - mdir_View.identity(); - mdir_View.build_camera_dir(cam_shifted, L_dir, L_up); - cull_xform.identity(); - cull_xform.mul(mdir_Project, mdir_View); - cull_xform_inv.invert(cull_xform); - - - // Create frustum for query - cull_frustum._clear(); - for (u32 p = 0; p < cull_planes.size(); p++) - cull_frustum._add(cull_planes[p]); - - { - Fvector cam_proj = Device.vCameraPosition; - const float align_aim_step_coef = 4.f; - cam_proj.set(floorf(cam_proj.x / align_aim_step_coef) + align_aim_step_coef / 2, - floorf(cam_proj.y / align_aim_step_coef) + align_aim_step_coef / 2, - floorf(cam_proj.z / align_aim_step_coef) + align_aim_step_coef / 2); - cam_proj.mul(align_aim_step_coef); - Fvector cam_pixel = wform(cull_xform, cam_proj); - cam_pixel = wform(m_viewport, cam_pixel); - Fvector shift_proj = lightXZshift; - cull_xform.transform_dir(shift_proj); - m_viewport.transform_dir(shift_proj); - - const float align_granularity = 4.f; - shift_proj.x = shift_proj.x > 0 ? align_granularity : -align_granularity; - shift_proj.y = shift_proj.y > 0 ? align_granularity : -align_granularity; - shift_proj.z = 0; - - cam_pixel.x = cam_pixel.x / align_granularity - floorf(cam_pixel.x / align_granularity); - cam_pixel.y = cam_pixel.y / align_granularity - floorf(cam_pixel.y / align_granularity); - cam_pixel.x *= align_granularity; - cam_pixel.y *= align_granularity; - cam_pixel.z = 0; - - cam_pixel.sub(shift_proj); - - m_viewport_inv.transform_dir(cam_pixel); - cull_xform_inv.transform_dir(cam_pixel); - Fvector diff = cam_pixel; - static float sign_test = -1.f; - diff.mul(sign_test); - Fmatrix adjust; - adjust.translate(diff); - cull_xform.mulB_44(adjust); - } - - m_sun_cascades[cascade_ind].xform = cull_xform; - - s32 limit = RImplementation.o.smapsize - 1; - fuckingsun->X.D.minX = 0; - fuckingsun->X.D.maxX = limit; - fuckingsun->X.D.minY = 0; - fuckingsun->X.D.maxY = limit; - - // full-xform - FPU::m24r(); - } - - // Begin SMAP-render - { - bool bSpecialFull = mapNormalPasses[1][0].size() || mapMatrixPasses[1][0].size() || mapSorted.size(); - VERIFY(!bSpecialFull); - HOM.Disable(); - phase = PHASE_SMAP; - if (RImplementation.o.Tshadows) r_pmask(true, true); - else r_pmask(true, false); - // fuckingsun->svis.begin (); - } - - // Fill the database - r_dsgraph_render_subspace(cull_sector, &cull_frustum, cull_xform, cull_COP, TRUE); - - // Finalize & Cleanup - fuckingsun->X.D.combine = cull_xform; //*((Fmatrix*)&m_LightViewProj); - - // Render shadow-map - //. !!! We should clip based on shrinked frustum (again) - { - bool bNormal = mapNormalPasses[0][0].size() || mapMatrixPasses[0][0].size(); - bool bSpecial = mapNormalPasses[1][0].size() || mapMatrixPasses[1][0].size() || mapSorted.size(); - if (bNormal || bSpecial) - { - Target->phase_smap_direct(fuckingsun, SE_SUN_FAR); - RCache.set_xform_world(Fidentity); - RCache.set_xform_view(Fidentity); - RCache.set_xform_project(fuckingsun->X.D.combine); - r_dsgraph_render_graph(0); - if (psDeviceFlags2.test(rsGrassShadow) && cascade_ind <= ps_ssfx_grass_shadows.x) - { - Details->fade_distance = dm_fade * dm_fade * ps_ssfx_grass_shadows.y; - Details->Render(); - } - fuckingsun->X.D.transluent = FALSE; - if (bSpecial) - { - fuckingsun->X.D.transluent = TRUE; - Target->phase_smap_direct_tsh(fuckingsun, SE_SUN_FAR); - r_dsgraph_render_graph(1); // normal level, secondary priority - r_dsgraph_render_sorted(); // strict-sorted geoms - } - } - } - - // End SMAP-render - { - // fuckingsun->svis.end (); - r_pmask(true, false); - } - - // Accumulate - Target->phase_accumulator(); - - if (Target->use_minmax_sm_this_frame()) - { - PIX_EVENT(SE_SUN_NEAR_MINMAX_GENERATE); - Target->create_minmax_SM(); - } - - PIX_EVENT(SE_SUN_NEAR); - - if (cascade_ind == 0) - Target->accum_direct_cascade(SE_SUN_NEAR, m_sun_cascades[cascade_ind].xform, m_sun_cascades[cascade_ind].xform, - m_sun_cascades[cascade_ind].bias); - else if (cascade_ind < m_sun_cascades.size() - 1) - Target->accum_direct_cascade(SE_SUN_MIDDLE, m_sun_cascades[cascade_ind].xform, - m_sun_cascades[cascade_ind - 1].xform, m_sun_cascades[cascade_ind].bias); - else - Target->accum_direct_cascade(SE_SUN_FAR, m_sun_cascades[cascade_ind].xform, - m_sun_cascades[cascade_ind - 1].xform, m_sun_cascades[cascade_ind].bias); - - // Restore XForms - RCache.set_xform_world(Fidentity); - RCache.set_xform_view(Device.mView); - RCache.set_xform_project(Device.mProject); -} diff --git a/src/Layers/xrRenderPC_R4/r2_blenders.cpp b/src/Layers/xrRenderPC_R4/r2_blenders.cpp deleted file mode 100644 index b2928d5c37..0000000000 --- a/src/Layers/xrRenderPC_R4/r2_blenders.cpp +++ /dev/null @@ -1,51 +0,0 @@ -#include "stdafx.h" - -#include "../xrRender/uber_deffer.h" - -#include "../xrRender/blender_BmmD.h" -#include "blender_deffer_flat.h" -#include "blender_deffer_model.h" -#include "blender_deffer_aref.h" -#include "../xrRender/blender_screen_set.h" -#include "../xrRender/blender_editor_wire.h" -#include "../xrRender/blender_editor_selection.h" -#include "../xrRender/blender_tree.h" -#include "../xrRender/blender_detail_still.h" -#include "../xrRender/blender_particle.h" -#include "../xrRender/Blender_Model_EbB.h" -#include "../xrRender/blender_Lm(EbB).h" - -IBlender* CRender::blender_create(CLASS_ID cls) -{ - switch (cls) - { - case B_DEFAULT: return xr_new(); - case B_DEFAULT_AREF: return xr_new(true); - case B_VERT: return xr_new(); - case B_VERT_AREF: return xr_new(false); - case B_SCREEN_SET: return xr_new(); - case B_SCREEN_GRAY: return 0; - case B_EDITOR_WIRE: return xr_new(); - case B_EDITOR_SEL: return xr_new(); - case B_LIGHT: return 0; - case B_LmBmmD: return xr_new(); - case B_LaEmB: return 0; - case B_LmEbB: return xr_new(); - case B_B: return 0; - case B_BmmD: return xr_new(); - case B_SHADOW_TEX: return 0; - case B_SHADOW_WORLD: return 0; - case B_BLUR: return 0; - case B_MODEL: return xr_new(); - case B_MODEL_EbB: return xr_new(); - case B_DETAIL: return xr_new(); - case B_TREE: return xr_new(); - case B_PARTICLE: return xr_new(); - } - return 0; -} - -void CRender::blender_destroy(IBlender* & B) -{ - xr_delete(B); -} diff --git a/src/Layers/xrRenderPC_R4/r2_sector_detect.cpp b/src/Layers/xrRenderPC_R4/r2_sector_detect.cpp deleted file mode 100644 index e71e7ad9b7..0000000000 --- a/src/Layers/xrRenderPC_R4/r2_sector_detect.cpp +++ /dev/null @@ -1,89 +0,0 @@ -#include "stdafx.h" -#include "r4.h" - -int CRender::translateSector(IRender_Sector* pSector) -{ - if (!pSector) - return -1; - - for (u32 i = 0; i < Sectors.size(); ++i) - { - if (Sectors[i] == pSector) - return i; - } - - FATAL("Sector was not found!"); - NODEFAULT; - -#ifdef DEBUG - return (-1); -#endif // #ifdef DEBUG -} - -IRender_Sector* CRender::detectSector(const Fvector& P) -{ - IRender_Sector* S = NULL; - Fvector dir; - Sectors_xrc.ray_options(CDB::OPT_ONLYNEAREST); - - dir.set(0, -1, 0); - S = detectSector(P, dir); - if (NULL == S) - { - dir.set(0, 1, 0); - S = detectSector(P, dir); - } - return S; -} - -IRender_Sector* CRender::detectSector(const Fvector& P, Fvector& dir) -{ - // Portals model - int id1 = -1; - float range1 = 500.f; - if (rmPortals) - { - Sectors_xrc.ray_query(rmPortals, P, dir, range1); - if (Sectors_xrc.r_count()) - { - CDB::RESULT* RP1 = Sectors_xrc.r_begin(); - id1 = RP1->id; - range1 = RP1->range; - } - } - - // Geometry model - int id2 = -1; - float range2 = range1; - Sectors_xrc.ray_query(g_pGameLevel->ObjectSpace.GetStaticModel(), P, dir, range2); - if (Sectors_xrc.r_count()) - { - CDB::RESULT* RP2 = Sectors_xrc.r_begin(); - id2 = RP2->id; - range2 = RP2->range; - } - - // Select ID - int ID; - if (id1 >= 0) - { - if (id2 >= 0) ID = (range1 <= range2 + EPS) ? id1 : id2; // both was found - else ID = id1; // only id1 found - } - else if (id2 >= 0) ID = id2; // only id2 found - else return 0; - - if (ID == id1) - { - // Take sector, facing to our point from portal - CDB::TRI* pTri = rmPortals->get_tris() + ID; - CPortal* pPortal = (CPortal*)Portals[pTri->dummy]; - return pPortal->getSectorFacing(P); - } - else - { - // Take triangle at ID and use it's Sector - CDB::TRI* pTri = g_pGameLevel->ObjectSpace.GetStaticTris() + ID; - return getSector(pTri->sector); - } -} diff --git a/src/Layers/xrRenderPC_R4/r4.cpp b/src/Layers/xrRenderPC_R4/r4.cpp index 965b953722..1d4853f060 100644 --- a/src/Layers/xrRenderPC_R4/r4.cpp +++ b/src/Layers/xrRenderPC_R4/r4.cpp @@ -201,8 +201,12 @@ void CRender::create() { Device.seqFrame.Add(this,REG_PRIORITY_HIGH + 0x12345678); - m_skinning = -1; + Engine.External.SetSkinningMode(); m_MSAASample = -1; + o.volsize = 8; + if (Core.ParamsData.test(ECoreParams::volumetric1)) o.volsize = 1; + if (Core.ParamsData.test(ECoreParams::volumetric2)) o.volsize = 2; + if (Core.ParamsData.test(ECoreParams::volumetric4)) o.volsize = 4; // hardware o.smapsize = 2048; @@ -298,9 +302,9 @@ void CRender::create() o.fp16_blend = true; // search for ATI formats - if (!o.HW_smap && (0 == strstr(Core.Params, "-nodf24"))) + if (!o.HW_smap && !Core.ParamsData.test(ECoreParams::nodf24)) { - o.HW_smap = HW.support((D3DFORMAT)(MAKEFOURCC('D', 'F', '2', '4')), D3DRTYPE_TEXTURE,D3DUSAGE_DEPTHSTENCIL); + o.HW_smap = HW.support((D3DFORMAT)(MAKEFOURCC('D', 'F', '2', '4')), D3DRTYPE_TEXTURE, D3DUSAGE_DEPTHSTENCIL); if (o.HW_smap) { o.HW_smap_FORMAT = MAKEFOURCC('D', 'F', '2', '4'); @@ -311,7 +315,7 @@ void CRender::create() } // emulate ATI-R4xx series - if (strstr(Core.Params, "-r4xx")) + if (Core.ParamsData.test(ECoreParams::r4xx)) { o.mrtmixdepth = FALSE; o.HW_smap = FALSE; @@ -327,8 +331,8 @@ void CRender::create() // nvstencil on NV40 and up o.nvstencil = FALSE; - //if ((HW.Caps.id_vendor==0x10DE)&&(HW.Caps.id_device>=0x40)) o.nvstencil = TRUE; - if (strstr(Core.Params, "-nonvs")) o.nvstencil = FALSE; + if (Core.ParamsData.test(ECoreParams::nonvs)) + o.nvstencil = FALSE; // nv-dbt // DX10 disabled @@ -336,46 +340,41 @@ void CRender::create() o.nvdbt = false; if (o.nvdbt) Msg("* NV-DBT supported and used"); - o.no_ram_textures = (strstr(Core.Params, "-noramtex")) ? TRUE : ps_r__common_flags.test(RFLAG_NO_RAM_TEXTURES); + o.no_ram_textures = Core.ParamsData.test(ECoreParams::noramtex) ? TRUE : ps_r__common_flags.test(RFLAG_NO_RAM_TEXTURES); if (o.no_ram_textures) Msg("* Managed textures disabled"); else Msg("* Managed textures enabled"); // options (smap-pool-size) - if (strstr(Core.Params, "-smap1536")) o.smapsize = 1536; - if (strstr(Core.Params, "-smap2048")) o.smapsize = 2048; - if (strstr(Core.Params, "-smap2560")) o.smapsize = 2560; - if (strstr(Core.Params, "-smap3072")) o.smapsize = 3072; - if (strstr(Core.Params, "-smap4096")) o.smapsize = 4096; + if (Core.ParamsData.test(ECoreParams::smap1536)) o.smapsize = 1536; + if (Core.ParamsData.test(ECoreParams::smap2048)) o.smapsize = 2048; + if (Core.ParamsData.test(ECoreParams::smap2560)) o.smapsize = 2560; + if (Core.ParamsData.test(ECoreParams::smap3072)) o.smapsize = 3072; + if (Core.ParamsData.test(ECoreParams::smap4096)) o.smapsize = 4096; // gloss char* g = strstr(Core.Params, "-gloss "); - o.forcegloss = g ? TRUE : FALSE; + o.forcegloss = Core.ParamsData.test(ECoreParams::gloss); if (g) { o.forcegloss_v = float(atoi(g + xr_strlen("-gloss "))) / 255.f; } // options - o.bug = (strstr(Core.Params, "-bug")) ? TRUE : FALSE; - o.sunfilter = (strstr(Core.Params, "-sunfilter")) ? TRUE : FALSE; - //. o.sunstatic = (strstr(Core.Params,"-sunstatic"))? TRUE :FALSE ; + o.bug = Core.ParamsData.test(ECoreParams::bug); + o.sunfilter = Core.ParamsData.test(ECoreParams::sunfilter); o.sunstatic = r2_sun_static; o.advancedpp = r2_advanced_pp; o.volumetricfog = ps_r2_ls_flags.test(R3FLAG_VOLUMETRIC_SMOKE); - o.sjitter = (strstr(Core.Params, "-sjitter")) ? TRUE : FALSE; - o.depth16 = (strstr(Core.Params, "-depth16")) ? TRUE : FALSE; - if (strstr(Core.Params, "-noshadows") || strstr(Core.Params, "-r4_dev")) - o.noshadows = TRUE; - else - o.noshadows = FALSE; - o.Tshadows = (strstr(Core.Params, "-tsh")) ? TRUE : FALSE; - - o.distortion_enabled = (strstr(Core.Params, "-nodistort")) ? FALSE : TRUE; + o.sjitter = Core.ParamsData.test(ECoreParams::sjitter); + o.depth16 = Core.ParamsData.test(ECoreParams::depth16); + o.noshadows = Core.ParamsData.test(ECoreParams::noshadows) || Core.ParamsData.test(ECoreParams::r4_dev); + o.Tshadows = Core.ParamsData.test(ECoreParams::tsh); + o.distortion_enabled = !Core.ParamsData.test(ECoreParams::nodistort); o.distortion = o.distortion_enabled; - o.disasm = (strstr(Core.Params, "-disasm")) ? TRUE : FALSE; - o.forceskinw = (strstr(Core.Params, "-skinw")) ? TRUE : FALSE; + o.disasm = Core.ParamsData.test(ECoreParams::disasm); + o.forceskinw = Core.ParamsData.test(ECoreParams::skinw); o.ssao_blur_on = ps_r2_ls_flags_ext.test(R2FLAGEXT_SSAO_BLUR) && (ps_r_ssao != 0); o.ssao_opt_data = ps_r2_ls_flags_ext.test(R2FLAGEXT_SSAO_OPT_DATA) && (ps_r_ssao != 0); @@ -537,67 +536,31 @@ void CRender::create() HWOCC.occq_create(occq_size); rmNormal(); - marker = 0; - D3D_QUERY_DESC qdesc; - qdesc.MiscFlags = 0; - qdesc.Query = D3D_QUERY_EVENT; - ZeroMemory(q_sync_point, sizeof(q_sync_point)); - //R_CHK (HW.pDevice->CreateQuery(&qdesc,&q_sync_point[0])); - //R_CHK (HW.pDevice->CreateQuery(&qdesc,&q_sync_point[1])); - // Prevent error on first get data - //q_sync_point[0]->End(); - //q_sync_point[1]->End(); - //R_CHK (HW.pDevice->CreateQuery(D3DQUERYTYPE_EVENT,&q_sync_point[0])); - //R_CHK (HW.pDevice->CreateQuery(D3DQUERYTYPE_EVENT,&q_sync_point[1])); - for (u32 i = 0; i < HW.Caps.iGPUNum; ++i) - R_CHK(HW.pDevice->CreateQuery(&qdesc,&q_sync_point[i])); - HW.pContext->End(q_sync_point[0]); - - ::PortalTraverser.initialize(); + + GMBase.initialize(); FluidManager.Initialize(70, 70, 70); // FluidManager.Initialize( 100, 100, 100 ); FluidManager.SetScreenSize(Device.dwWidth, Device.dwHeight); + + Device.ModelDefferClear = xr_make_delegate(Models, &CModelPool::DeleteQueuedDeffer); } void CRender::destroy() { m_bMakeAsyncSS = false; FluidManager.Destroy(); - ::PortalTraverser.destroy(); - //_RELEASE (q_sync_point[1]); - //_RELEASE (q_sync_point[0]); - for (u32 i = 0; i < HW.Caps.iGPUNum; ++i) - _RELEASE(q_sync_point[i]); + GMBase.destroy(); HWOCC.occq_destroy(); xr_delete(Models); xr_delete(Target); PSLibrary.OnDestroy(); Device.seqFrame.Remove(this); - r_dsgraph_destroy(); + Device.ModelDefferClear = nullptr; } void CRender::reset_begin() { - // Update incremental shadowmap-visibility solver - // BUG-ID: 10646 - { - u32 it = 0; - for (it = 0; it < Lights_LastFrame.size(); it++) - { - if (0 == Lights_LastFrame[it]) continue ; - try - { - Lights_LastFrame[it]->svis.resetoccq(); - } - catch (...) - { - Msg("! Failed to flush-OCCq on light [%d] %X", it, *(u32*)(&Lights_LastFrame[it])); - } - } - Lights_LastFrame.clear(); - } - //AVO: let's reload details while changed details options on vid_restart if (b_loaded && ((dm_current_size != dm_size) || (ps_r__Detail_density != ps_current_detail_density) || ( ps_r__Detail_height != ps_current_detail_height))) @@ -609,26 +572,10 @@ void CRender::reset_begin() xr_delete(Target); HWOCC.occq_destroy(); - //_RELEASE (q_sync_point[1]); - //_RELEASE (q_sync_point[0]); - for (u32 i = 0; i < HW.Caps.iGPUNum; ++i) - _RELEASE(q_sync_point[i]); } void CRender::reset_end() { - D3D_QUERY_DESC qdesc; - qdesc.MiscFlags = 0; - qdesc.Query = D3D_QUERY_EVENT; - //R_CHK (HW.pDevice->CreateQuery(&qdesc,&q_sync_point[0])); - //R_CHK (HW.pDevice->CreateQuery(&qdesc,&q_sync_point[1])); - for (u32 i = 0; i < HW.Caps.iGPUNum; ++i) - R_CHK(HW.pDevice->CreateQuery(&qdesc,&q_sync_point[i])); - // Prevent error on first get data - HW.pContext->End(q_sync_point[0]); - //q_sync_point[1]->End(); - //R_CHK (HW.pDevice->CreateQuery(D3DQUERYTYPE_EVENT,&q_sync_point[0])); - //R_CHK (HW.pDevice->CreateQuery(D3DQUERYTYPE_EVENT,&q_sync_point[1])); HWOCC.occq_create(occq_size); Target = xr_new(); @@ -649,30 +596,16 @@ void CRender::reset_end() m_bFirstFrameAfterReset = true; } -/* -void CRender::OnFrame() -{ -Models->DeleteQueue (); -if (ps_r2_ls_flags.test(R2FLAG_EXP_MT_CALC)) { -Device.seqParallel.insert (Device.seqParallel.begin(), -fastdelegate::FastDelegate0<>(&HOM,&CHOM::MT_RENDER)); -} -}*/ void CRender::OnFrame() { PROF_EVENT("CRender::OnFrame()"); + Models->DeleteQueue(); - if (ps_r2_ls_flags.test(R2FLAG_EXP_MT_CALC)) - { - // MT-details (@front) - if (Details) - Device.seqParallel.insert(Device.seqParallel.begin(), - fastdelegate::FastDelegate0<>(Details, &CDetailManager::MT_CALC)); - // MT-HOM (@front) - Device.seqParallel.insert(Device.seqParallel.begin(), - fastdelegate::FastDelegate0<>(&HOM, &CHOM::MT_RENDER)); - } + //Lights Delete queue + for (light* L : v_all_lights_dque) + xr_delete(L); + v_all_lights_dque.clear(); if (Details) g_pGamePersistent->GrassBendersUpdateAnimations(); @@ -703,10 +636,18 @@ IRenderVisual* CRender::model_Create(LPCSTR name, IReader* data) { return Models IRenderVisual* CRender::model_CreateChild(LPCSTR name, IReader* data) { return Models->CreateChild(name, data); } IRenderVisual* CRender::model_Duplicate(IRenderVisual* V) { return Models->Instance_Duplicate((dxRender_Visual*)V); } -void CRender::model_Delete(IRenderVisual* & V, BOOL bDiscard) +void CRender::model_Delete(IRenderVisual*& V, BOOL bDiscard) { dxRender_Visual* pVisual = (dxRender_Visual*)V; - Models->Delete(pVisual, bDiscard); + if (Models) + Models->Delete(pVisual, bDiscard); + V = 0; +} + +void CRender::model_Delete_Deffered(IRenderVisual*& V) +{ + dxRender_Visual* pVisual = (dxRender_Visual*)V; + Models->DeleteDeffered(pVisual); V = 0; } @@ -766,8 +707,10 @@ IRender_Portal* CRender::getPortal(int id) IRender_Sector* CRender::getSector(int id) { - VERIFY(id= 0 && id < int(Sectors.size())) + return Sectors[id]; + + return NULL; } IRender_Sector* CRender::getSectorActive() { return pLastSector; } @@ -831,15 +774,12 @@ IRender_Target* CRender::getTarget() { return Target; } IRender_Light* CRender::light_create() { return Lights.Create(); } IRender_Glow* CRender::glow_create() { return xr_new(); } -void CRender::flush() { r_dsgraph_render_graph(0); } +void CRender::flush() { RImplementation.GMBase.r_dsgraph_render_graph(0); } BOOL CRender::occ_visible(vis_data& P) { return HOM.visible(P); } BOOL CRender::occ_visible(sPoly& P) { return HOM.visible(P); } BOOL CRender::occ_visible(Fbox& P) { return HOM.visible(P); } -void CRender::add_Visual(IRenderVisual* V) { add_leafs_Dynamic((dxRender_Visual*)V); } -void CRender::add_Geometry(IRenderVisual* V) { add_Static((dxRender_Visual*)V, View->getMask()); } - // demonized: add user defined rotation to wallmark void CRender::add_StaticWallmark(ref_shader& S, const Fvector& P, float s, CDB::TRI* T, Fvector* verts, float ttl, bool ignore_opt, bool random_rotation) { @@ -878,7 +818,7 @@ void CRender::clear_static_wallmarks() void CRender::add_SkeletonWallmark(intrusive_ptr wm) { - Wallmarks->AddSkeletonWallmark(wm); + Wallmarks->AddSkeletonWallmark(std::move(wm)); } void CRender::add_SkeletonWallmark(const Fmatrix* xf, CKinematics* obj, ref_shader& sh, const Fvector& start, @@ -895,14 +835,19 @@ void CRender::add_SkeletonWallmark(const Fmatrix* xf, IKinematics* obj, IWallMar if (pShader) add_SkeletonWallmark(xf, (CKinematics*)obj, *pShader, start, dir, size, ttl, ignore_opt); } -void CRender::add_Occluder(Fbox2& bb_screenspace) +void CRender::remove_SkeletonWallmarksFromObject(IKinematics* obj) { - HOM.occlude(bb_screenspace); + Wallmarks->RemoveSkeletonWallmarksFromObject(static_cast(obj)); +} + +void CRender::update_Wallmarks() +{ + Wallmarks->UpdateWallmarks(); } -void CRender::set_Object(IRenderable* O) +void CRender::add_Occluder(Fbox2& bb_screenspace) { - val_pObject = O; + HOM.occlude(bb_screenspace); } void CRender::rmNear() @@ -943,8 +888,7 @@ CRender::CRender() CRender::~CRender() { - for (FSlideWindowItem it : SWIs) - { + for (auto& it : SWIs) { xr_free(it.sw); it.sw = nullptr; it.count = 0; @@ -960,6 +904,22 @@ void CRender::Statistics(CGameFont* _F) F.OutNext(" **** LT:%2d,LV:%2d **** ", stats.l_total, stats.l_visible); stats.l_visible = 0; F.OutNext(" S(%2d) | (%2d)NS ", stats.l_shadowed, stats.l_unshadowed); + F.OutNext("LP sh(in:%u,vis:%u,r:%u) pk(%u/%u)", stats.ls_shadowed_in, stats.ls_shadowed_after_vis, + stats.ls_shadowed_rendered, stats.ls_shadowed_peak_in, stats.ls_shadowed_peak_after_vis); + F.OutNext("LP uns p(in:%u,r:%u) s(in:%u,r:%u)", stats.ls_unshadowed_point_in, stats.ls_unshadowed_point_rendered, + stats.ls_unshadowed_spot_in, stats.ls_unshadowed_spot_rendered); + F.OutNext("LP sh skip: pend[%u] inv[%u]", stats.ls_shadowed_pending_skipped, stats.ls_shadowed_invisible_skipped); + stats.ls_shadowed_in = 0; + stats.ls_shadowed_after_vis = 0; + stats.ls_shadowed_rendered = 0; + stats.ls_shadowed_pending_skipped = 0; + stats.ls_shadowed_invisible_skipped = 0; + stats.ls_shadowed_peak_in = 0; + stats.ls_shadowed_peak_after_vis = 0; + stats.ls_unshadowed_point_in = 0; + stats.ls_unshadowed_spot_in = 0; + stats.ls_unshadowed_point_rendered = 0; + stats.ls_unshadowed_spot_rendered = 0; F.OutNext("smap use[%2d], merge[%2d], finalclip[%2d]", stats.s_used, stats.s_merged - stats.s_used, stats.s_finalclip); stats.s_used = 0; @@ -1314,6 +1274,7 @@ HRESULT CRender::shader_compile( u32 len = xr_strlen(sh_name); // options + const int m_skinning = Engine.External.GetSkinningMode(); { xr_sprintf(c_smapsize, "%04d", u32(o.smapsize)); defines[def_it].Name = "SMAP_size"; diff --git a/src/Layers/xrRenderPC_R4/r4.h b/src/Layers/xrRenderPC_R4/r4.h index 16b3eb4f72..af5a6e0ebd 100644 --- a/src/Layers/xrRenderPC_R4/r4.h +++ b/src/Layers/xrRenderPC_R4/r4.h @@ -1,6 +1,7 @@ -#pragma once +#pragma once -#include "../xrRender/r__dsgraph_structure.h" +#include "../xrRender/r__dsgraph_manager.h" +#include "../xrRender/r__sector.h" #include "../xrRender/r__occlusion.h" #include "../xrRender/PSLibrary.h" @@ -15,7 +16,6 @@ #include "smap_allocator.h" #include "../xrRender/light_db.h" -#include "light_render_direct.h" #include "../xrRender/LightTrack.h" #include "../xrRender/r_sun_cascades.h" @@ -25,17 +25,9 @@ class dxRender_Visual; // definition -class CRender : public R_dsgraph_structure +class CRender : public IRender_interface, public pureFrame { public: - enum - { - PHASE_NORMAL = 0, - // E[0] - PHASE_SMAP = 1, - // E[1] - }; - enum { MSAA_ATEST_NONE = 0x0, @@ -46,14 +38,6 @@ class CRender : public R_dsgraph_structure MSAA_ATEST_DX10_1_ATOC = 0x3, }; - enum - { - MMSM_OFF = 0, - MMSM_ON, - MMSM_AUTO, - MMSM_AUTODETECT - }; - public: struct _options { @@ -86,6 +70,7 @@ class CRender : public R_dsgraph_structure u32 ssao_ultra : 1; u32 hbao_vectorized : 1; + u32 volsize : 16; u32 smapsize : 16; u32 depth16 : 1; u32 mrt : 1; @@ -145,12 +130,24 @@ class CRender : public R_dsgraph_structure s32 s_used, s_merged, s_finalclip; u32 o_queries, o_culled; u32 ic_total, ic_culled; + u32 ls_shadowed_in; + u32 ls_shadowed_after_vis; + u32 ls_shadowed_rendered; + u32 ls_shadowed_pending_skipped; + u32 ls_shadowed_invisible_skipped; + u32 ls_shadowed_peak_in; + u32 ls_shadowed_peak_after_vis; + u32 ls_unshadowed_point_in; + u32 ls_unshadowed_spot_in; + u32 ls_unshadowed_point_rendered; + u32 ls_unshadowed_spot_rendered; } stats; public: bool is_sun(); // Sector detection and visibility CSector* pLastSector; + CSector* pOutdoorSector; Fvector vLastCameraPos; u32 uLastLTRACK; xr_vector Portals; @@ -177,26 +174,36 @@ class CRender : public R_dsgraph_structure CRenderTarget* Target; // Render-target CLight_DB Lights; - CLight_Compute_XFORM_and_VIS LR; - xr_vector Lights_LastFrame; SMAP_Allocator LP_smap_pool; light_Package LP_normal; light_Package LP_pending; - xr_vector> main_coarse_structure; + shared_str c_sbase; shared_str c_lmaterial; float o_hemi; float o_hemi_cube[CROS_impl::NUM_FACES]; float o_sun; - ID3DQuery* q_sync_point[CHWCaps::MAX_GPUS]; - u32 q_sync_count; bool m_bMakeAsyncSS; bool m_bFirstFrameAfterReset; // Determines weather the frame is the first after resetting device. xr_vector m_sun_cascades; + CFrustum rainwet_cull_frustum; + Fvector3 rainwet_cull_COP; + Fmatrix rainwet_cull_xform; + + CDSGraphManager GMRainWet = CDSGraphManager(u32(0), u32(STYPE_RENDERABLE), { true,false,false,false,true,false,false }); + CDSGraphManager GMBase = CDSGraphManager(u32(CDSGraphManager::VQ_HOM + CDSGraphManager::VQ_SSA + CDSGraphManager::VQ_FADE), + u32(STYPE_RENDERABLE + STYPE_PARTICLE + STYPE_LIGHTSOURCE), + { true,true,true,true,false,false,false }); + + xr_task_group main_task_static, main_task_dynamic, sun_cascades_task, raimwet_task; + + xr_set v_all_lights; + xr_list v_all_lights_dque; + private: // Loading / Unloading void LoadBuffers(CStreamReader* fs, BOOL _alternative); @@ -207,22 +214,13 @@ class CRender : public R_dsgraph_structure void LoadSWIs(CStreamReader* fs); void Load3DFluid(); - BOOL add_Dynamic(dxRender_Visual* pVisual, u32 planes); // normal processing - void add_Static(dxRender_Visual* pVisual, u32 planes); - void add_leafs_Dynamic(dxRender_Visual* pVisual); // if detected node's full visibility - void add_leafs_Static(dxRender_Visual* pVisual); // if detected node's full visibility - public: IRender_Sector* rimp_detectSector(Fvector& P, Fvector& D); - void render_main(Fmatrix& mCombined, bool _fportals); void render_forward(); void render_Reticle(); void render_smap_direct(Fmatrix& mCombined); void render_indirect(light* L); void render_lights(light_Package& LP); - void render_sun(); - void render_sun_near(); - void render_sun_filtered(); void render_menu(); void render_rain(); @@ -241,6 +239,9 @@ class CRender : public R_dsgraph_structure IRender_Sector* getSectorActive(); IRenderVisual* model_CreatePE(LPCSTR name); IRender_Sector* detectSector(const Fvector& P, Fvector& D); + IRender_Sector* detectLastSector(const Fvector& P); + void detectSectors_sphere (CSector* sector, FixedSet& m_sectors, const Fvector& b_center, const Fvector& b_dim); + void detectSectors_frustum (CSector* sector, FixedSet& m_sectors, CFrustum* _frustum); int translateSector(IRender_Sector* pSector); // HW-occlusion culling @@ -328,12 +329,9 @@ class CRender : public R_dsgraph_structure virtual IRender_Sector* detectSector(const Fvector& P); virtual IRender_Target* getTarget(); - // Main + // Main virtual void flush(); - virtual void set_Object(IRenderable* O); virtual void add_Occluder(Fbox2& bb_screenspace); // mask screen region as oclluded - virtual void add_Visual(IRenderVisual* V); // add visual leaf (no culling performed at all) - virtual void add_Geometry(IRenderVisual* V); // add visual(s) (all culling performed) // wallmarks // demonized: add user defined rotation to wallmark @@ -350,6 +348,9 @@ class CRender : public R_dsgraph_structure virtual void add_SkeletonWallmark(const Fmatrix* xf, IKinematics* obj, IWallMarkArray* pArray, const Fvector& start, const Fvector& dir, float size, float ttl = 0.f, bool ignore_opt = false); + virtual void remove_SkeletonWallmarksFromObject(IKinematics* obj); + virtual void update_Wallmarks(); + // virtual IBlender* blender_create(CLASS_ID cls); virtual void blender_destroy(IBlender* &); @@ -369,6 +370,7 @@ class CRender : public R_dsgraph_structure virtual IRenderVisual* model_CreateChild(LPCSTR name, IReader* data); virtual IRenderVisual* model_Duplicate(IRenderVisual* V); virtual void model_Delete(IRenderVisual* & V, BOOL bDiscard); + virtual void model_Delete_Deffered(IRenderVisual* & V); virtual void model_Delete(IRender_DetailModel* & F); virtual void model_Logging(BOOL bEnable) { Models->Logging(bEnable); } virtual void models_Prefetch(); @@ -440,6 +442,8 @@ class CRender : public R_dsgraph_structure void addShaderOption(const char* name, const char* value); void clearAllShaderOptions() { m_ShaderOptions.clear(); } + virtual size_t SectorsCount() { return Sectors.size(); } + private: xr_vector m_ShaderOptions; diff --git a/src/Layers/xrRenderPC_R4/r4_R_rain.cpp b/src/Layers/xrRenderPC_R4/r4_R_rain.cpp index 0e9ffa61e3..8c70904610 100644 --- a/src/Layers/xrRenderPC_R4/r4_R_rain.cpp +++ b/src/Layers/xrRenderPC_R4/r4_R_rain.cpp @@ -3,7 +3,7 @@ #include "../../xrEngine/irenderable.h" #include "../xrRender/FBasicVisual.h" -#include "r4_R_sun_support.h" +#include "../xrRender/R_sun_support.h" const float tweak_rain_COP_initial_offs = 1200.f; const float tweak_rain_ortho_xform_initial_offs = 1000.f; //. ? @@ -43,7 +43,8 @@ void CRender::render_rain() D3DXMATRIX m_LightViewProj; // Use light as placeholder for rain data. - light RainLight; + // нет необходимости создавать каждый кадр структуру размером почти в киллобайт на стеке. + light& RainLight = *Lights.rain_light; //static const float source_offset = 40.f; @@ -79,11 +80,7 @@ void CRender::render_rain() // Compute volume(s) - something like a frustum for infinite directional light // Also compute virtual light position and sector it is inside - CFrustum cull_frustum; xr_vector cull_planes; - Fvector3 cull_COP; - CSector* cull_sector; - Fmatrix cull_xform; { FPU::m64r(); // Lets begin from base frustum @@ -93,15 +90,14 @@ void CRender::render_rain() #else typedef DumbConvexVolume t_volume; #endif - t_volume hull; + static t_volume hull; + hull.polys.clear(); + hull.edges.clear(); + hull.points.clear(); { - hull.points.reserve(9); - for (int p = 0; p < 8; p++) - { - Fvector3 xf = wform(fullxform_inv, corners[p]); - hull.points.push_back(xf); - } - for (int plane = 0; plane < 6; plane++) + for(int p = 0; p < 8; p++) + hull.points.push_back(wform(fullxform_inv, corners[p])); + for(int plane = 0; plane < 6; plane++) { hull.polys.push_back(t_volume::_poly()); for (int pt = 0; pt < 4; pt++) @@ -112,35 +108,18 @@ void CRender::render_rain() hull.compute_caster_model(cull_planes, RainLight.direction); #ifdef _DEBUG for (u32 it=0; itdbg_addplane(cull_planes[it],0xffffffff); + Target->dbg_addplane(cull_planes[it], 0xffffffff); #endif - // Search for default sector - assume "default" or "outdoor" sector is the largest one - //. hack: need to know real outdoor sector - CSector* largest_sector = 0; - float largest_sector_vol = 0; - for (u32 s = 0; s < Sectors.size(); s++) - { - CSector* S = (CSector*)Sectors[s]; - dxRender_Visual* V = S->root(); - float vol = V->vis.box.getvolume(); - if (vol > largest_sector_vol) - { - largest_sector_vol = vol; - largest_sector = S; - } - } - cull_sector = largest_sector; - // COP - 100 km away - cull_COP.mad(Device.vCameraPosition, RainLight.direction, -tweak_rain_COP_initial_offs); - cull_COP.x += fBoundingSphereRadius * Device.vCameraDirection.x; - cull_COP.z += fBoundingSphereRadius * Device.vCameraDirection.z; + rainwet_cull_COP.mad(Device.vCameraPosition, RainLight.direction, -tweak_rain_COP_initial_offs); + rainwet_cull_COP.x += fBoundingSphereRadius * Device.vCameraDirection.x; + rainwet_cull_COP.z += fBoundingSphereRadius * Device.vCameraDirection.z; // Create frustum for query - cull_frustum._clear(); + rainwet_cull_frustum._clear(); for (u32 p = 0; p < cull_planes.size(); p++) - cull_frustum._add(cull_planes[p]); + rainwet_cull_frustum._add(cull_planes[p]); // Create approximate ortho-xform @@ -189,14 +168,13 @@ void CRender::render_rain() D3DXMatrixOrthoOffCenterLH((D3DXMATRIX*)&mdir_Project, bb.min.x, bb.max.x, bb.min.y, bb.max.y, bb.min.z - tweak_rain_ortho_xform_initial_offs, bb.min.z + 2 * tweak_rain_ortho_xform_initial_offs); + rainwet_cull_xform.mul(mdir_Project, mdir_View); - cull_xform.mul(mdir_Project, mdir_View); - - s32 limit = _min(RImplementation.o.smapsize, ps_r3_dyn_wet_surf_sm_res); + s32 limit = _min(o.smapsize, ps_r3_dyn_wet_surf_sm_res); // build viewport xform float view_dim = float(limit); - float fTexelOffs = (.5f / RImplementation.o.smapsize); + float fTexelOffs = (.5f / o.smapsize); Fmatrix m_viewport = { view_dim / 2.f, 0.0f, 0.0f, 0.0f, 0.0f, -view_dim / 2.f, 0.0f, 0.0f, @@ -208,8 +186,8 @@ void CRender::render_rain() // snap view-position to pixel // snap zero point to pixel - Fvector cam_proj = wform(cull_xform, Fvector().set(0, 0, 0)); - Fvector cam_pixel = wform(m_viewport, cam_proj); + Fvector cam_proj = wform(rainwet_cull_xform, Fvector().set(0, 0, 0)); + Fvector cam_pixel = wform(m_viewport, cam_proj); cam_pixel.x = floorf(cam_pixel.x); cam_pixel.y = floorf(cam_pixel.y); Fvector cam_snapped = wform(m_viewport_inv, cam_pixel); @@ -217,7 +195,7 @@ void CRender::render_rain() diff.sub(cam_snapped, cam_proj); Fmatrix adjust; adjust.translate(diff); - cull_xform.mulA_44(adjust); + rainwet_cull_xform.mulA_44(adjust); RainLight.X.D.minX = 0; RainLight.X.D.maxX = limit; @@ -229,42 +207,31 @@ void CRender::render_rain() } // Begin SMAP-render - { - bool bSpecialFull = mapNormalPasses[1][0].size() || mapMatrixPasses[1][0].size() || mapSorted.size(); - VERIFY(!bSpecialFull); - HOM.Disable(); - phase = PHASE_SMAP; - r_pmask(true, false); - } - - // Fill the database - //r_dsgraph_render_subspace (cull_sector, &cull_frustum, cull_xform, cull_COP, TRUE); - r_dsgraph_render_subspace(cull_sector, &cull_frustum, cull_xform, cull_COP, FALSE); + phase = PHASE_SMAP; + GMRainWet.traverse(pOutdoorSector, rainwet_cull_frustum, rainwet_cull_COP, rainwet_cull_xform); + GMRainWet.r_dsgraph_capture_static(); // Finalize & Cleanup - RainLight.X.D.combine = cull_xform; //*((Fmatrix*)&m_LightViewProj); + RainLight.X.D.combine = rainwet_cull_xform; // Render shadow-map //. !!! We should clip based on shrinked frustum (again) { - bool bNormal = mapNormalPasses[0][0].size() || mapMatrixPasses[0][0].size(); - bool bSpecial = mapNormalPasses[1][0].size() || mapMatrixPasses[1][0].size() || mapSorted.size(); - if (bNormal || bSpecial) + bool bDeffered_Shadows = GMRainWet.RGraph.mapStaticPasses[0][0].size() || GMRainWet.RGraph.mapDynamicPasses[0][0].size(); + bool bForward_Shadows = GMRainWet.RGraph.mapStaticPasses[1][0].size() || GMRainWet.RGraph.mapDynamicPasses[1][0].size() || GMRainWet.RGraph.mapStaticSorted.Sorted.size() || GMRainWet.RGraph.mapDynamicSorted.Sorted.size(); + if(bDeffered_Shadows || bForward_Shadows) { Target->phase_smap_direct(&RainLight, SE_SUN_RAIN_SMAP); RCache.set_xform_world(Fidentity); RCache.set_xform_view(Fidentity); RCache.set_xform_project(RainLight.X.D.combine); - r_dsgraph_render_graph(0); - //if (ps_r2_ls_flags.test(R2FLAG_SUN_DETAILS)) - // Details->Render () ; + GMRainWet.r_dsgraph_render_graph(0); } } // End SMAP-render { // fuckingsun->svis.end (); - r_pmask(true, false); } // Restore XForms diff --git a/src/Layers/xrRenderPC_R4/r4_R_render.cpp b/src/Layers/xrRenderPC_R4/r4_R_render.cpp index 2b323819d6..19346b4664 100644 --- a/src/Layers/xrRenderPC_R4/r4_R_render.cpp +++ b/src/Layers/xrRenderPC_R4/r4_R_render.cpp @@ -3,170 +3,12 @@ #include "../xrRender/FBasicVisual.h" #include "../../xrEngine/customhud.h" #include "../../xrEngine/xr_object.h" +#include "../xrRender/SkeletonCustom.h" +#include "../../xrParticles/ParticlesAsyncManager.h" #include "../xrRender/QueryHelper.h" -IC bool pred_sp_sort(ISpatial* _1, ISpatial* _2) -{ - float d1 = _1->spatial.sphere.P.distance_to_sqr(Device.vCameraPosition); - float d2 = _2->spatial.sphere.P.distance_to_sqr(Device.vCameraPosition); - return d1 < d2; -} - -void CRender::render_main(Fmatrix& m_ViewProjection, bool _fportals) -{ - PIX_EVENT(render_main); - // Msg ("---begin"); - marker ++; - - // Calculate sector(s) and their objects - if (pLastSector) - { - //!!! - //!!! BECAUSE OF PARALLEL HOM RENDERING TRY TO DELAY ACCESS TO HOM AS MUCH AS POSSIBLE - //!!! - { - // Traverse object database - g_SpatialSpace->q_frustum - ( - lstRenderables, - ISpatial_DB::O_ORDERED, - STYPE_RENDERABLE + STYPE_LIGHTSOURCE, - ViewBase - ); - - // (almost) Exact sorting order (front-to-back) - std::sort(lstRenderables.begin(), lstRenderables.end(), pred_sp_sort); - - // Determine visibility for dynamic part of scene - set_Object(0); - u32 uID_LTRACK = 0xffffffff; - if (phase == PHASE_NORMAL) - { - uLastLTRACK ++; - if (lstRenderables.size()) uID_LTRACK = uLastLTRACK % lstRenderables.size(); - - // update light-vis for current entity / actor - CObject* O = g_pGameLevel->CurrentViewEntity(); - if (O) - { - CROS_impl* R = (CROS_impl*)O->ROS(); - if (R) R->update(O); - } - - // update light-vis for selected entity - // track lighting environment - if (lstRenderables.size()) - { - IRenderable* renderable = lstRenderables[uID_LTRACK]->dcast_Renderable(); - if (renderable) - { - CROS_impl* T = (CROS_impl*)renderable->renderable_ROS(); - if (T) T->update(renderable); - } - } - } - } - - // Traverse sector/portal structure - PortalTraverser.traverse - ( - pLastSector, - ViewBase, - Device.vCameraPosition, - m_ViewProjection, - CPortalTraverser::VQ_HOM + CPortalTraverser::VQ_SSA + CPortalTraverser::VQ_FADE - //. disabled scissoring (HW.Caps.bScissor?CPortalTraverser::VQ_SCISSOR:0) // generate scissoring info - ); - - // Determine visibility for static geometry hierrarhy - for (u32 s_it = 0; s_it < PortalTraverser.r_sectors.size(); s_it++) - { - CSector* sector = (CSector*)PortalTraverser.r_sectors[s_it]; - dxRender_Visual* root = sector->root(); - for (u32 v_it = 0; v_it < sector->r_frustums.size(); v_it++) - { - set_Frustum(&(sector->r_frustums[v_it])); - add_Geometry(root); - } - } - - // Traverse frustums - for (u32 o_it = 0; o_it < lstRenderables.size(); o_it++) - { - ISpatial* spatial = lstRenderables[o_it]; - spatial->spatial_updatesector(); - CSector* sector = (CSector*)spatial->spatial.sector; - if (0 == sector) continue; // disassociated from S/P structure - - if (spatial->spatial.type & STYPE_LIGHTSOURCE) - { - // lightsource - light* L = (light*)(spatial->dcast_Light()); - VERIFY(L); - float lod = L->get_LOD(); - if (lod > EPS_L) - { - vis_data& vis = L->get_homdata(); - if (HOM.visible(vis)) Lights.add_light(L); - } - continue ; - } - - if (PortalTraverser.i_marker != sector->r_marker) continue; // inactive (untouched) sector - for (u32 v_it = 0; v_it < sector->r_frustums.size(); v_it++) - { - CFrustum& view = sector->r_frustums[v_it]; - if (!view.testSphere_dirty(spatial->spatial.sphere.P, spatial->spatial.sphere.R)) continue; - - if (spatial->spatial.type & STYPE_RENDERABLE) - { - // renderable - IRenderable* renderable = spatial->dcast_Renderable(); - VERIFY(renderable); - - // Occlusion - // casting is faster then using getVis method - vis_data& v_orig = ((dxRender_Visual*)renderable->renderable.visual)->vis; - vis_data v_copy = v_orig; - v_copy.box.xform(renderable->renderable.xform); - BOOL bVisible = HOM.visible(v_copy); - v_orig.marker = v_copy.marker; - v_orig.accept_frame = v_copy.accept_frame; - v_orig.hom_frame = v_copy.hom_frame; - v_orig.hom_tested = v_copy.hom_tested; - if (!bVisible) break; // exit loop on frustums - - // Rendering - set_Object(renderable); - renderable->renderable_Render(); - set_Object(0); - } - break; // exit loop on frustums - } - } - if (g_pGameLevel && (phase == PHASE_NORMAL)) - { - g_hud->Render_Last(); // HUD - if (g_hud->RenderActiveItemUIQuery()) - r_dsgraph_render_hud_ui(); - if (g_hud->RenderCamAttachedUIQuery()) - r_dsgraph_render_cam_ui(); - } - } - else - { - set_Object(0); - if (g_pGameLevel && (phase == PHASE_NORMAL)) - { - g_hud->Render_Last(); // HUD - if (g_hud->RenderActiveItemUIQuery()) - r_dsgraph_render_hud_ui(); - if (g_hud->RenderCamAttachedUIQuery()) - r_dsgraph_render_cam_ui(); - } - } -} +#include "../xrRender/dxRenderDeviceRender.h" void CRender::render_menu() { @@ -197,7 +39,7 @@ void CRender::render_menu() Fvector2 p0, p1; u32 Offset; - u32 C = color_rgba(255, 255, 255, 255); + auto C = color_rgba(255, 255, 255, 255); float _w = float(Device.dwWidth); float _h = float(Device.dwHeight); float d_Z = EPS_S; @@ -224,8 +66,6 @@ void CRender::Render() { PIX_EVENT(CRender_Render); - VERIFY(0 == mapDistort.size() + mapHUDDistort.size()); - rmNormal(); bool _menu_pp = g_pGamePersistent ? g_pGamePersistent->OnRenderPPUI_query() : false; @@ -247,94 +87,34 @@ void CRender::Render() if (m_bFirstFrameAfterReset) { + for (light* L : v_all_lights)//critical!!! + L->m_moving_frames = 0; + m_bFirstFrameAfterReset = false; return; } + if ((Device.dwFrame % (u32)ps_r__tex_evict_interval) == 0) + dxRenderDeviceRender::Instance().Resources->EvictStalledTextures(); + //. VERIFY (g_pGameLevel && g_pGameLevel->pHUD); // Configure RImplementation.o.distortion = FALSE; // disable distorion Fcolor sun_color = ((light*)Lights.sun_adapted._get())->color; - BOOL bSUN = ps_r2_ls_flags.test(R2FLAG_SUN) && (u_diffuse2s(sun_color.r, sun_color.g, sun_color.b)>EPS) && !strstr(Core.Params, "-r4_dev"); + BOOL bSUN = ps_r2_ls_flags.test(R2FLAG_SUN) && (u_diffuse2s(sun_color.r, sun_color.g, sun_color.b)>EPS) && !Core.ParamsData.test(ECoreParams::r4_dev); if (o.sunstatic) bSUN = FALSE; // Msg ("sstatic: %s, sun: %s",o.sunstatic?;"true":"false", bSUN?"true":"false"); // HOM ViewBase.CreateFromMatrix(Device.mFullTransform, FRUSTUM_P_LRTB + FRUSTUM_P_FAR); - View = 0; - if (!ps_r2_ls_flags.test(R2FLAG_EXP_MT_CALC)) - { - HOM.Enable(); - HOM.Render(ViewBase); - } + HOM.MT_RENDER(); - //******* Z-prefill calc - DEFERRER RENDERER - if (ps_r2_ls_flags.test(R2FLAG_ZFILL)) - { - PIX_EVENT(DEFER_Z_FILL); - Device.Statistic->RenderCALC.Begin(); - float z_distance = ps_r2_zfill; - Fmatrix m_zfill, m_project; - m_project.build_projection( - deg2rad(Device.fFOV/* *Device.fASPECT*/), - Device.fASPECT, VIEWPORT_NEAR, - z_distance * g_pGamePersistent->Environment().CurrentEnv->far_plane); - m_zfill.mul(m_project, Device.mView); - r_pmask(true, false); // enable priority "0" - set_Recorder(NULL); - phase = PHASE_SMAP; - render_main(m_zfill, false); - r_pmask(true, false); // disable priority "1" - Device.Statistic->RenderCALC.End(); - - // flush - Target->phase_scene_prepare(); - RCache.set_ColorWriteEnable(FALSE); - r_dsgraph_render_graph(0); - RCache.set_ColorWriteEnable(); - } - else - { - Target->phase_scene_prepare(); - } + Target->phase_scene_prepare(); - //******* - // Sync point - Device.Statistic->RenderDUMP_Wait_S.Begin(); - if (ps_r2_qsync) - { - CTimer T; - T.Start(); - BOOL result = FALSE; - HRESULT hr = S_FALSE; - //while ((hr=q_sync_point[q_sync_count]->GetData (&result,sizeof(result),D3DGETDATA_FLUSH))==S_FALSE) { - while ((hr = GetData(q_sync_point[q_sync_count], &result, sizeof(result))) == S_FALSE) - { - if (!SwitchToThread()) Sleep(ps_r2_wait_sleep); - if (T.GetElapsed_ms() > 500) - { - result = FALSE; - break; - } - } - } - Device.Statistic->RenderDUMP_Wait_S.End(); - q_sync_count = (q_sync_count + 1) % HW.Caps.iGPUNum; - //CHK_DX (q_sync_point[q_sync_count]->Issue(D3DISSUE_END)); - CHK_DX(EndQuery(q_sync_point[q_sync_count])); //******* Main calc - DEFERRER RENDERER - // Main calc - Device.Statistic->RenderCALC.Begin(); - r_pmask(true, false, true); // enable priority "0",+ capture wmarks - if (bSUN) set_Recorder(&main_coarse_structure); - else set_Recorder(NULL); phase = PHASE_NORMAL; - render_main(Device.mFullTransform, true); - set_Recorder(NULL); - r_pmask(true, false); // disable priority "1" - Device.Statistic->RenderCALC.End(); /*if (RImplementation.o.ssfx_core) // SSS23: DEPRECATED { @@ -349,50 +129,38 @@ void CRender::Render() HW.pContext->ClearDepthStencilView(HW.pBaseZB, D3D_CLEAR_DEPTH, 1.0f, 0); }*/ - if (RImplementation.o.ssfx_motionvectors) - { - Target->u_setrt(Device.dwWidth, Device.dwHeight, 0, 0, Target->rt_ssfx_motion_vectors->pRT, 0); + GMBase.traverse(RImplementation.pLastSector, ViewBase, Device.vCameraPosition, Device.mFullTransform); + GMBase.r_dsgraph_capture_static(); + GMBase.r_dsgraph_capture_dynamic(); - FLOAT ColorRGBA[4] = { 0.0f, 0.0f, 0.0f, 0.0f }; - HW.pContext->ClearRenderTargetView(Target->rt_ssfx_motion_vectors->pRT, ColorRGBA); + if (RImplementation.o.ssfx_motionvectors) + { + Target->u_setrt(Device.dwWidth, Device.dwHeight, 0, 0, Target->rt_ssfx_motion_vectors->pRT, 0); - RCache.set_Stencil(FALSE); - g_pGamePersistent->Environment().RenderSky(true); + FLOAT ColorRGBA[4] = { 0.0f, 0.0f, 0.0f, 0.0f }; + HW.pContext->ClearRenderTargetView(Target->rt_ssfx_motion_vectors->pRT, ColorRGBA); - RCache.Index.Flush(); - RCache.Vertex.Flush(); + RCache.set_Stencil(FALSE); + g_pGamePersistent->Environment().RenderSky(true); - RCache.set_xform_world(Fidentity); - } + RCache.Index.Flush(); + RCache.Vertex.Flush(); + + RCache.set_xform_world(Fidentity); + } if (ps_r2_ls_flags.test(R2FLAG_TERRAIN_PREPASS)) { Target->u_setrt(Device.dwWidth, Device.dwHeight, NULL, NULL, NULL, !RImplementation.o.dx10_msaa ? HW.pBaseZB : Target->rt_MSAADepth->pZRT); - r_dsgraph_render_landscape(0, false); } - BOOL split_the_scene_to_minimize_wait = FALSE; - if (ps_r2_ls_flags.test(R2FLAG_EXP_SPLIT_SCENE)) split_the_scene_to_minimize_wait = TRUE; - //******* Main render :: PART-0 -- first - if (!split_the_scene_to_minimize_wait) - { - PIX_EVENT(DEFER_PART0_NO_SPLIT); - // level, DO NOT SPLIT - Target->phase_scene_begin(); - r_dsgraph_render_hud(); - r_dsgraph_render_graph(0); - r_dsgraph_render_lods(true, true); - if (Details) Details->Render(); - if (ps_r2_ls_flags.test(R2FLAG_TERRAIN_PREPASS)) r_dsgraph_render_landscape(1, true); - Target->phase_scene_end(); - } - else { PIX_EVENT(DEFER_PART0_SPLIT); // level, SPLIT Target->phase_scene_begin(); - r_dsgraph_render_graph(0); + GMBase.r_dsgraph_render_static(0); + GMBase.r_dsgraph_render_dynamic(0); Target->disable_aniso(); } @@ -404,86 +172,27 @@ void CRender::Render() HW.pContext->CopyResource(RImplementation.Target->rt_tempzb->pSurface, zbuffer_res); } - //******* Occlusion testing of volume-limited light-sources - Target->phase_occq(); - LP_normal.clear(); - LP_pending.clear(); if (RImplementation.o.dx10_msaa) RCache.set_ZB(RImplementation.Target->rt_MSAADepth->pZRT); + { PIX_EVENT(DEFER_TEST_LIGHT_VIS); - // perform tests - u32 count = 0; - light_Package& LP = Lights.package; - - // stats - stats.l_shadowed = LP.v_shadowed.size(); - stats.l_unshadowed = LP.v_point.size() + LP.v_spot.size(); - stats.l_total = stats.l_shadowed + stats.l_unshadowed; - - // perform tests - count = _max(count, LP.v_point.size()); - count = _max(count, LP.v_spot.size()); - count = _max(count, LP.v_shadowed.size()); - for (u32 it = 0; it < count; it++) - { - if (it < LP.v_point.size()) - { - light* L = LP.v_point[it]; - L->vis_prepare(); - if (L->vis.pending) LP_pending.v_point.push_back(L); - else LP_normal.v_point.push_back(L); - } - if (it < LP.v_spot.size()) - { - light* L = LP.v_spot[it]; - L->vis_prepare(); - if (L->vis.pending) LP_pending.v_spot.push_back(L); - else LP_normal.v_spot.push_back(L); - } - if (it < LP.v_shadowed.size()) - { - light* L = LP.v_shadowed[it]; - L->vis_prepare(); - if (L->vis.pending) LP_pending.v_shadowed.push_back(L); - else LP_normal.v_shadowed.push_back(L); - } - } + //******* Occlusion testing of volume-limited light-sources + Target->phase_occq(); + LP_normal.clear(); + LP_pending.clear(); + GMBase.r_dsgraph_capture_lights(); } - LP_normal.sort(); - LP_pending.sort(); //******* Main render :: PART-1 (second) - if (split_the_scene_to_minimize_wait) { PIX_EVENT(DEFER_PART1_SPLIT); - // skybox can be drawn here - - if (0) - { - if (!RImplementation.o.dx10_msaa) - Target->u_setrt(Target->rt_Generic_0, Target->rt_Generic_1, 0, HW.pBaseZB); - else - Target->u_setrt(Target->rt_Generic_0_r, Target->rt_Generic_1, 0, - RImplementation.Target->rt_MSAADepth->pZRT); - RCache.set_CullMode(CULL_NONE); - RCache.set_Stencil(FALSE); - - // draw skybox - RCache.set_ColorWriteEnable(); - //CHK_DX(HW.pDevice->SetRenderState ( D3DRS_ZENABLE, FALSE )); - RCache.set_Z(FALSE); - g_pGamePersistent->Environment().RenderSky(); - //CHK_DX(HW.pDevice->SetRenderState ( D3DRS_ZENABLE, TRUE )); - RCache.set_Z(TRUE); - } - // level Target->phase_scene_begin(); - r_dsgraph_render_hud(); - r_dsgraph_render_lods(true, true); + GMBase.r_dsgraph_capture_hud(); + GMBase.r_dsgraph_render_hud(); + GMBase.r_dsgraph_render_lods(true,true); if (Details) Details->Render(); - if (ps_r2_ls_flags.test(R2FLAG_TERRAIN_PREPASS)) r_dsgraph_render_landscape(1, true); Target->phase_scene_end(); } @@ -496,25 +205,6 @@ void CRender::Render() Wallmarks->Render(); // wallmarks has priority as normal geometry } - // Update incremental shadowmap-visibility solver - { - PIX_EVENT(DEFER_FLUSH_OCCLUSION); - u32 it = 0; - for (it = 0; it < Lights_LastFrame.size(); it++) - { - if (0 == Lights_LastFrame[it]) continue ; - try - { - Lights_LastFrame[it]->svis.flushoccq(); - } - catch (...) - { - Msg("! Failed to flush-OCCq on light [%d] %X", it, *(u32*)(&Lights_LastFrame[it])); - } - } - Lights_LastFrame.clear(); - } - // full screen pass to mark msaa-edge pixels in highest stencil bit if (RImplementation.o.dx10_msaa) { @@ -565,7 +255,7 @@ void CRender::Render() if (ps_ssfx_sss_quality.w > 0) { // Extra lights - Target->phase_ssfx_sss_ext(Lights.package); + Target->phase_ssfx_sss_ext(RImplementation.LP_normal); sss_extended_rendered = true; } else @@ -585,17 +275,13 @@ void CRender::Render() { PIX_EVENT(DEFER_SUN); RImplementation.stats.l_visible ++; - if (!ps_r2_ls_flags_ext.is(R2FLAGEXT_SUN_OLD)) - render_sun_cascades(); - else - { - render_sun_near(); - render_sun(); - render_sun_filtered(); - } + render_sun_cascades(); + Target->increment_light_marker(); Target->accum_direct_blend(); } + phase = PHASE_NORMAL; + { PIX_EVENT(DEFER_SELF_ILLUM); Target->phase_accumulator(); @@ -612,7 +298,7 @@ void CRender::Render() //RCache.set_Stencil (TRUE,D3DCMP_ALWAYS,0x00,0xff,0xff,D3DSTENCILOP_KEEP,D3DSTENCILOP_REPLACE,D3DSTENCILOP_KEEP); RCache.set_CullMode(CULL_CCW); RCache.set_ColorWriteEnable(); - RImplementation.r_dsgraph_render_emissive(RImplementation.o.ssfx_bloom ? false : true); + GMBase.r_dsgraph_render_emissive(RImplementation.o.ssfx_bloom ? false : true); } if (RImplementation.o.ssfx_bloom) @@ -621,14 +307,16 @@ void CRender::Render() FLOAT ColorRGBA[4] = { 0,0,0,0 }; HW.pContext->ClearRenderTargetView(Target->rt_ssfx_bloom_emissive->pRT, ColorRGBA); Target->u_setrt(Target->rt_ssfx_bloom_emissive, NULL, NULL, !RImplementation.o.dx10_msaa ? HW.pBaseZB : Target->rt_MSAADepth->pZRT); - RImplementation.r_dsgraph_render_emissive(true, true); + // Keep regular HUD geometry out of the emissive target. It is already + // present in the scene texture sampled by the bloom build pass; drawing it + // here again treats every strict-sorted HUD surface as an emissive source. + GMBase.r_dsgraph_render_emissive(true, false); } // Lighting, non dependant on OCCQ { PIX_EVENT(DEFER_LIGHT_NO_OCCQ); Target->phase_accumulator(); - HOM.Disable(); render_lights(LP_normal); } @@ -643,6 +331,8 @@ void CRender::Render() Target->phase_ssfx_volumetric_blur(); } + phase = PHASE_NORMAL; + // Postprocess { PIX_EVENT(DEFER_LIGHT_COMBINE); @@ -652,27 +342,35 @@ void CRender::Render() if (Details) Details->details_clear(); - VERIFY(0 == mapDistort.size() + mapHUDDistort.size()); + if (g_hud) + { + PROF_EVENT("render_hud"); + if (g_hud->RenderActiveItemUIQuery()) + GMBase.r_dsgraph_render_hud_ui(); + if (g_hud->RenderCamAttachedUIQuery()) + GMBase.r_dsgraph_render_cam_ui(); + } + } +#include "../xrRender/CHudInitializer.h" void CRender::render_forward() { - VERIFY(0 == mapDistort.size() + mapHUDDistort.size()); RImplementation.o.distortion = RImplementation.o.distortion_enabled; // enable distorion //******* Main render - second order geometry (the one, that doesn't support deffering) //.todo: should be done inside "combine" with estimation of of luminance, tone-mapping, etc. { // level - r_pmask(false, true); // enable priority "1" phase = PHASE_NORMAL; - render_main(Device.mFullTransform, false); // // Igor: we don't want to render old lods on next frame. - mapLOD.clear(); - r_dsgraph_render_graph(1); // normal level, secondary priority - PortalTraverser.fade_render(); // faded-portals - r_dsgraph_render_sorted(); // strict-sorted geoms - //g_pGamePersistent->Environment().RenderLast(); // rain/thunder-bolts + GMBase.r_dsgraph_render_static(1); // normal level, secondary priority + CParticlesAsync::Wait(); + GMBase.r_dsgraph_render_dynamic(1); + GMBase.fade_render(); // faded-portals + GMBase.r_dsgraph_render_sorted(false); // strict-sorted geoms + g_pGamePersistent->Environment().RenderLast(); // rain/thunder-bolts + GMBase.r_dsgraph_render_sorted_hud(); } RImplementation.o.distortion = FALSE; // disable distorion @@ -681,10 +379,10 @@ void CRender::render_forward() // Redotix99: for 3D Shader Based Scopes void CRender::render_Reticle() { - VERIFY(0 == mapDistort.size() + mapHUDDistort.size()); + VERIFY(0 == GMBase.RGraph.mapHUDSorted.Distort.size() + GMBase.RGraph.mapStaticSorted.Distort.size() + GMBase.RGraph.mapDynamicSorted.Distort.size()); RImplementation.o.distortion = RImplementation.o.distortion_enabled; - r_dsgraph_render_ScopeSorted(); + GMBase.r_dsgraph_render_ScopeSorted(); RImplementation.o.distortion = FALSE; } diff --git a/src/Layers/xrRenderPC_R4/r4_R_sun_support.cpp b/src/Layers/xrRenderPC_R4/r4_R_sun_support.cpp deleted file mode 100644 index e6bd177fa4..0000000000 --- a/src/Layers/xrRenderPC_R4/r4_R_sun_support.cpp +++ /dev/null @@ -1,2 +0,0 @@ -#include "stdafx.h" -#include "r4_R_sun_support.h" diff --git a/src/Layers/xrRenderPC_R4/r4_R_sun_support.h b/src/Layers/xrRenderPC_R4/r4_R_sun_support.h deleted file mode 100644 index 06b898f104..0000000000 --- a/src/Layers/xrRenderPC_R4/r4_R_sun_support.h +++ /dev/null @@ -1,492 +0,0 @@ -#ifndef r4_R_sun_support_included -#define r4_R_sun_support_included -#pragma once - -const u32 LIGHT_CUBOIDSIDEPOLYS_COUNT = 4; -const u32 LIGHT_CUBOIDVERTICES_COUNT = 2 * LIGHT_CUBOIDSIDEPOLYS_COUNT; - -template -class FixedConvexVolume -{ -public: - - struct _poly - { - int points[4]; - Fplane plane; - }; - - xr_vector view_frustum_rays; - sun::ray view_ray; - sun::ray light_ray; - Fvector3 light_cuboid_points [LIGHT_CUBOIDVERTICES_COUNT]; - _poly light_cuboid_polys [LIGHT_CUBOIDSIDEPOLYS_COUNT]; - -public: - - void compute_planes() - { - for (u32 it = 0; it < LIGHT_CUBOIDSIDEPOLYS_COUNT; it++) - { - _poly& P = light_cuboid_polys[it]; - - P.plane.build(light_cuboid_points[P.points[0]], light_cuboid_points[P.points[2]], - light_cuboid_points[P.points[1]]); - - // verify - if (_debug) - { - Fvector& p0 = light_cuboid_points[P.points[0]]; - Fvector& p1 = light_cuboid_points[P.points[1]]; - Fvector& p2 = light_cuboid_points[P.points[2]]; - Fvector& p3 = light_cuboid_points[P.points[3]]; - Fplane p012; - p012.build(p0, p1, p2); - Fplane p123; - p123.build(p1, p2, p3); - Fplane p230; - p230.build(p2, p3, p0); - Fplane p301; - p301.build(p3, p0, p1); - VERIFY(p012.n.similar(p123.n) && p012.n.similar(p230.n) && p012.n.similar(p301.n)); - } - } - } - - void compute_caster_model_fixed(xr_vector& dest, Fvector3& translation, float map_size, - bool clip_by_view_near) - { - translation.set(0.f, 0.f, 0.f); - - if (fis_zero(1 - abs(view_ray.D.dotproduct(light_ray.D)), EPS_S)) - return; - - // compute planes for each polygon. - compute_planes(); - - for (u32 i = 0; i < LIGHT_CUBOIDSIDEPOLYS_COUNT; i++) - VERIFY(light_cuboid_polys[i].plane.classify(light_ray.P) > 0); - - int align_planes[2]; - int align_planes_count = 0; - - // find one or two planes that align to view frustum from behind. - for (u32 i = 0; i < LIGHT_CUBOIDSIDEPOLYS_COUNT; i++) - { - float tmp_dot = view_ray.D.dotproduct(light_cuboid_polys[i].plane.n); - if (tmp_dot <= EPS_L) - continue; - - align_planes[align_planes_count] = i; - ++align_planes_count; - - if (align_planes_count == 2) - break; - } - - - Fvector align_vector; - align_vector.set(0.f, 0.f, 0.f); - - // Align ray points to the align planes. - for (int p = 0; p < align_planes_count; ++p) - { - // Hack ! - float min_dist = 10000; - for (u32 i = 0; i < view_frustum_rays.size(); ++i) - { - float tmp_dist = 0; - Fvector tmp_point = view_frustum_rays[i].P; - - tmp_dist = light_cuboid_polys[align_planes[p]].plane.classify(tmp_point); - min_dist = _min(tmp_dist, min_dist); - } - - Fvector shift = light_cuboid_polys[align_planes[p]].plane.n; - shift.mul(min_dist); - align_vector.add(shift); - } - - translation.add(align_vector); - - // Move light ray by the alignment shift. - light_ray.P.add(align_vector); - - // Here we can skip this stage us in the next pass we need only normals of planes. - // in the next translate_light_model call will contain this shift as well. - // translate_light_model ( align_vector ); - - // Reset to reuse. - align_vector.set(0.f, 0.f, 0.f); - - // Check if view edges intersect, and push planes................ - for (int p = 0; p < align_planes_count; ++p) - { - float max_mag = 0; - for (u32 i = 0; i < view_frustum_rays.size(); ++i) - { - float plane_dot_ray = view_frustum_rays[i].D.dotproduct(light_cuboid_polys[align_planes[p]].plane.n); - if (plane_dot_ray < 0) - { - Fvector per_plane_view; - per_plane_view.crossproduct(light_cuboid_polys[align_planes[p]].plane.n, view_ray.D); - Fvector per_view_to_plane; - per_view_to_plane.crossproduct(per_plane_view, view_ray.D); - - float tmp_mag = -plane_dot_ray / view_frustum_rays[i].D.dotproduct(per_view_to_plane); - - max_mag = (max_mag < tmp_mag) ? tmp_mag : max_mag; - } - } - - if (fis_zero(max_mag)) - continue; - - VERIFY(max_mag <= 1.f); - - float dist = -light_cuboid_polys[align_planes[p]].plane.n.dotproduct(translation); - align_vector.mad(light_cuboid_polys[align_planes[p]].plane.n, dist * max_mag); - } - - translation.add(align_vector); - light_ray.P.add(align_vector); - translate_light_model(translation); - - - // compute culling planes by rays as edges - for (u32 i = 0; i < view_frustum_rays.size(); ++i) - { - Fvector tmp_vector; - tmp_vector.crossproduct(view_frustum_rays[i].D, light_ray.D); - - // check if the vectors are parallel - if (fis_zero(tmp_vector.square_magnitude(), EPS)) - continue; - - Fplane tmp_plane; - tmp_plane.build(view_frustum_rays[i].P, tmp_vector); - - float sign = 0; - if (check_cull_plane_valid(tmp_plane, sign, 5)) - { - tmp_plane.n.mul(-sign); - tmp_plane.d *= -sign; - dest.push_back(tmp_plane); - } - } - - // compute culling planes by ray points pairs as edges - if (clip_by_view_near && abs(view_ray.D.dotproduct(light_ray.D)) < 0.8) - { - Fvector perp_light_view, perp_light_to_view; - perp_light_view.crossproduct(view_ray.D, light_ray.D); - perp_light_to_view.crossproduct(perp_light_view, light_ray.D); - - Fplane plane; - plane.build(view_ray.P, perp_light_to_view); - - float max_dist = -1000; - for (u32 i = 0; i < view_frustum_rays.size(); ++i) - max_dist = _max(plane.classify(view_frustum_rays[i].P), max_dist); - - for (u32 i = 0; i < view_frustum_rays.size(); ++i) - { - Fvector P = view_frustum_rays[i].P; - P.mad(view_frustum_rays[i].D, 5); - - if (plane.classify(P) > max_dist) - { - max_dist = 0.f; - break; - } - } - - if (max_dist > -1000) - { - plane.d += max_dist; - dest.push_back(plane); - } - } - - for (u32 i = 0; i < LIGHT_CUBOIDSIDEPOLYS_COUNT; i++) - { - dest.push_back(light_cuboid_polys[i].plane); - dest.back().n.mul(-1); - dest.back().d *= -1; - VERIFY(light_cuboid_polys[i].plane.classify(light_ray.P) > 0); - } - - // Compute ray intersection with light model, this is needed to next cascade to start it's placement. - for (u32 i = 0; i < view_frustum_rays.size(); ++i) - { - float min_dist = 2 * map_size; - for (int p = 0; p < 4; ++p) - { - float dist; - if ((light_cuboid_polys[p].plane.n.dotproduct(view_frustum_rays[i].D)) > -0.1) - dist = map_size; - else - light_cuboid_polys[p].plane.intersectRayDist(view_frustum_rays[i].P, view_frustum_rays[i].D, dist); - - if (dist > EPS_L && dist < min_dist) - min_dist = dist; - } - - view_frustum_rays[i].P.mad(view_frustum_rays[i].D, min_dist); - } - } - - bool check_cull_plane_valid(Fplane const& plane, float& sign, float mad_factor = 0.f) - { - bool valid = false; - bool oriented = false; - float orient = 0; - for (u32 j = 0; j < view_frustum_rays.size(); ++j) - { - float tmp_dist = 0.f; - Fvector tmp_pt = view_frustum_rays[j].P; - tmp_pt.mad(view_frustum_rays[j].D, mad_factor); - tmp_dist = plane.classify(tmp_pt); - - if (fis_zero(tmp_dist, EPS_L)) - continue; - - if (!oriented) - { - orient = tmp_dist > 0.f ? 1.f : -1.f; - valid = true; - oriented = true; - continue; - } - - if (tmp_dist < 0 && orient < 0 || tmp_dist > 0 && orient > 0) - continue; - - valid = false; - break; - } - sign = orient; - return valid; - } - - void translate_light_model(Fvector translate) - { - Fmatrix trans_mat; - trans_mat.translate(translate); - for (int i = 0; i < LIGHT_CUBOIDSIDEPOLYS_COUNT; ++i) - light_cuboid_polys[i].plane.d -= translate.dotproduct(light_cuboid_polys[i].plane.n); - } -}; - -////////////////////////////////////////////////////////////////////////// -// OLES: naive builder of infinite volume expanded from base frustum towards -// light source. really slow, but it works for our simple usage :) -// note: normals points to 'outside' -////////////////////////////////////////////////////////////////////////// -template -class DumbConvexVolume -{ -public: - struct _poly - { - xr_vector points; - Fvector3 planeN; - float planeD; - float classify(Fvector3& p) { return planeN.dotproduct(p) + planeD; } - }; - - struct _edge - { - int p0, p1; - int counter; - _edge(int _p0, int _p1, int m) : p0(_p0), p1(_p1), counter(m) { if (p0 > p1) swap(p0, p1); } - bool equal(_edge& E) { return p0 == E.p0 && p1 == E.p1; } - }; - -public: - xr_vector points; - xr_vector<_poly> polys; - xr_vector<_edge> edges; -public: - void compute_planes() - { - for (int it = 0; it < int(polys.size()); it++) - { - _poly& P = polys[it]; - Fvector3 t1, t2; - float len; - - t1.sub(points[P.points[0]], points[P.points[1]]); - t2.sub(points[P.points[0]], points[P.points[2]]); - - P.planeN.crossproduct(t1, t2); - - len = P.planeN.magnitude(); - - if (len > std::numeric_limits::min()) - { - P.planeN.mul(1 / len); - } - else - { - t2.sub(points[P.points[0]], points[P.points[3]]); - P.planeN.crossproduct(t1, t2); - if (len > std::numeric_limits::min()) - { - P.planeN.mul(1 / len); - } - else - { - // HACK: Remove plane. - //VERIFY(!"Can't build normal to plane!"); - polys.erase(polys.begin() + it); - --it; - continue; - } - } - - P.planeD = - P.planeN.dotproduct(points[P.points[0]]); - - // verify - if (_debug) - { - Fvector& p0 = points[P.points[0]]; - Fvector& p1 = points[P.points[1]]; - Fvector& p2 = points[P.points[2]]; - Fvector& p3 = points[P.points[3]]; - Fplane p012; - p012.build(p0, p1, p2); - Fplane p123; - p123.build(p1, p2, p3); - Fplane p230; - p230.build(p2, p3, p0); - Fplane p301; - p301.build(p3, p0, p1); - VERIFY(p012.n.similar(p123.n) && p012.n.similar(p230.n) && p012.n.similar(p301.n)); - } - - /* - t1.sub (points[P.points[0]], points[P.points[1]]); - - - // HACK: Igor: just make sure we calculated the plane - - t2.sub (points[P.points[0]], points[P.points[2]]); - P.planeN.crossproduct (t1,t2).normalize(); - - - P.planeD = - P.planeN.dotproduct(points[P.points[0]]); - - // verify - if (_debug) - { - Fvector& p0 = points[P.points[0]]; - Fvector& p1 = points[P.points[1]]; - Fvector& p2 = points[P.points[2]]; - Fvector& p3 = points[P.points[3]]; - Fplane p012; p012.build(p0,p1,p2); - Fplane p123; p123.build(p1,p2,p3); - Fplane p230; p230.build(p2,p3,p0); - Fplane p301; p301.build(p3,p0,p1); - VERIFY (p012.n.similar(p123.n) && p012.n.similar(p230.n) && p012.n.similar(p301.n)); - } - */ - } - } - - void compute_caster_model(xr_vector& dest, Fvector3 direction) - { - CRenderTarget& T = *RImplementation.Target; - - // COG - Fvector3 cog = {0, 0, 0}; - for (int it = 0; it < int(points.size()); it++) cog.add(points[it]); - cog.div(float(points.size())); - - // planes - compute_planes(); - for (int it = 0; it < int(polys.size()); it++) - { - _poly& base = polys[it]; - if (base.classify(cog) > 0) std::reverse(base.points.begin(), base.points.end()); - } - - // remove faceforward polys, build list of edges -> find open ones - compute_planes(); - for (int it = 0; it < int(polys.size()); it++) - { - _poly& base = polys[it]; - VERIFY(base.classify(cog)<0); // debug - - int marker = (base.planeN.dotproduct(direction) <= 0) ? -1 : 1; - - // register edges - xr_vector& plist = polys[it].points; - for (int p = 0; p < int(plist.size()); p++) - { - _edge E(plist[p], plist[(p + 1) % plist.size()], marker); - bool found = false; - for (int e = 0; e < int(edges.size()); e++) - if (edges[e].equal(E)) - { - edges[e].counter += marker; - found = true; - break; - } - if (!found) - { - edges.push_back(E); - if (_debug) T.dbg_addline(points[E.p0], points[E.p1], color_rgba(255, 0, 0, 255)); - } - } - - // remove if unused - if (marker < 0) - { - polys.erase(polys.begin() + it); - it--; - } - } - - // Extend model to infinity, the volume is not capped, so this is indeed up to infinity - for (int e = 0; e < int(edges.size()); e++) - { - if (edges[e].counter != 0) continue; - _edge& E = edges[e]; - if (_debug) T.dbg_addline(points[E.p0], points[E.p1], color_rgba(255, 255, 255, 255)); - Fvector3 point; - points.push_back(point.sub(points[E.p0], direction)); - points.push_back(point.sub(points[E.p1], direction)); - polys.push_back(_poly()); - _poly& P = polys.back(); - int pend = int(points.size()); - P.points.push_back(E.p0); - P.points.push_back(E.p1); - P.points.push_back(pend - 1); //p1 mod - P.points.push_back(pend - 2); //p0 mod - if (_debug) T.dbg_addline(points[E.p0], point.mad(points[E.p0], direction, -1000), - color_rgba(0, 255, 0, 255)); - if (_debug) T.dbg_addline(points[E.p1], point.mad(points[E.p1], direction, -1000), - color_rgba(0, 255, 0, 255)); - } - - // Reorient planes (try to write more inefficient code :) - compute_planes(); - for (int it = 0; it < int(polys.size()); it++) - { - _poly& base = polys[it]; - if (base.classify(cog) > 0) std::reverse(base.points.begin(), base.points.end()); - } - - // Export - compute_planes(); - for (int it = 0; it < int(polys.size()); it++) - { - _poly& P = polys[it]; - Fplane pp = {P.planeN, P.planeD}; - dest.push_back(pp); - } - } -}; - -#endif // r3_R_sun_support_included diff --git a/src/Layers/xrRenderPC_R4/r4_loader.cpp b/src/Layers/xrRenderPC_R4/r4_loader.cpp index 899a21af7e..9333cfd964 100644 --- a/src/Layers/xrRenderPC_R4/r4_loader.cpp +++ b/src/Layers/xrRenderPC_R4/r4_loader.cpp @@ -109,12 +109,6 @@ void CRender::level_Load(IReader* fs) // End pApp->LoadEnd(); - // sanity-clear - lstLODs.clear(); - lstLODgroups.clear(); - mapLOD.clear(); - mapWater.clear(); - // signal loaded b_loaded = TRUE; } @@ -124,6 +118,11 @@ void CRender::level_Unload() if (0 == g_pGameLevel) return; if (!b_loaded) return; + GMBase.clear(); + GMRainWet.clear(); + for (sun::cascade& cascade : m_sun_cascades) + cascade.GMCascade.clear(); + u32 I; // HOM @@ -136,6 +135,7 @@ void CRender::level_Unload() // 1. xr_delete(rmPortals); pLastSector = 0; + pOutdoorSector = 0; vLastCameraPos.set(0, 0, 0); // 2. for (I = 0; I < Sectors.size(); I++) xr_delete(Sectors[I]); @@ -179,10 +179,17 @@ void CRender::level_Unload() //*** Shaders Shaders.clear_and_free(); - if (psDeviceFlags2.test(rsClearModels)) + const bool clearResources = psDeviceFlags2.test(rsClearAllResources); + if (psDeviceFlags2.test(rsClearModels) || clearResources) { Models->ClearPool(true); Visuals.clear_and_free(); + if (clearResources) + { + dxRenderDeviceRender::Instance().Resources->UnloadAllTexturesOnLevelUnload(); + dxRenderDeviceRender::Instance().ResourcesDestroyNecessaryTextures(); + dxRenderDeviceRender::Instance().Resources->Evict(); + } dxRenderDeviceRender::Instance().Resources->Dump(false); //static int unload_counter = 0; //Msg("The Level Unloaded.======================== %d", ++unload_counter); @@ -377,6 +384,23 @@ void CRender::LoadSectors(IReader* fs) // Sectors[d]->DebugDump (); pLastSector = 0; + + // Search for default sector - assume "default" or "outdoor" sector is the largest one + //. hack: need to know real outdoor sector + CSector* largest_sector = 0; + float largest_sector_vol = 0; + for (u32 s = 0; s < Sectors.size(); s++) + { + CSector* S = (CSector*)Sectors[s]; + dxRender_Visual* V = S->root(); + float vol = V->vis.box.getvolume(); + if (vol > largest_sector_vol) + { + largest_sector_vol = vol; + largest_sector = S; + } + } + pOutdoorSector = largest_sector; } void CRender::LoadSWIs(CStreamReader* base_fs) @@ -414,7 +438,6 @@ void CRender::LoadSWIs(CStreamReader* base_fs) void CRender::Load3DFluid() { - //if (strstr(Core.Params,"-no_volumetric_fog")) if (!RImplementation.o.volumetricfog) return; diff --git a/src/Layers/xrRenderPC_R4/r4_rendertarget.cpp b/src/Layers/xrRenderPC_R4/r4_rendertarget.cpp index 7ec99470ec..03db2f91b8 100644 --- a/src/Layers/xrRenderPC_R4/r4_rendertarget.cpp +++ b/src/Layers/xrRenderPC_R4/r4_rendertarget.cpp @@ -910,14 +910,12 @@ CRenderTarget::CRenderTarget() t_LUM_dest.create(r2_RT_luminance_cur); // create pool - for (u32 it = 0; it < HW.Caps.iGPUNum * 2; it++) + for (u32 it = 0; it < 2; it++) { - string256 name; - xr_sprintf(name, "%s_%d", r2_RT_luminance_pool, it); - rt_LUM_pool[it].create(name, 1, 1, D3DFMT_R32F); - //u_setrt (rt_LUM_pool[it], 0, 0, 0 ); - //CHK_DX (HW.pDevice->Clear( 0L, NULL, D3DCLEAR_TARGET, 0x7f7f7f7f, 1.0f, 0L)); - FLOAT ColorRGBA[4] = {127.0f / 255.0f, 127.0f / 255.0f, 127.0f / 255.0f, 127.0f / 255.0f}; + shared_str name; name.printf("%s_%d", r2_RT_luminance_pool, it); + rt_LUM_pool[it].create(name.c_str(), 1, 1, D3DFMT_R32F); + + FLOAT ColorRGBA[4] = { 127.0f / 255.0f, 127.0f / 255.0f, 127.0f / 255.0f, 127.0f / 255.0f }; HW.pContext->ClearRenderTargetView(rt_LUM_pool[it]->pRT, ColorRGBA); } u_setrt(Device.dwWidth, Device.dwHeight, HW.pBaseRT,NULL,NULL, HW.pBaseZB); diff --git a/src/Layers/xrRenderPC_R4/r4_rendertarget.h b/src/Layers/xrRenderPC_R4/r4_rendertarget.h index 16c93f6647..2b56a81308 100644 --- a/src/Layers/xrRenderPC_R4/r4_rendertarget.h +++ b/src/Layers/xrRenderPC_R4/r4_rendertarget.h @@ -153,7 +153,7 @@ class CRenderTarget : public IRender_Target ref_rt rt_LUM_64; // 64bit, 64x64, log-average in all components ref_rt rt_LUM_8; // 64bit, 8x8, log-average in all components - ref_rt rt_LUM_pool[CHWCaps::MAX_GPUS * 2]; // 1xfp32,1x1, exp-result -> scaler + ref_rt rt_LUM_pool[2]; // 1xfp32,1x1, exp-result -> scaler ref_texture t_LUM_src; // source ref_texture t_LUM_dest; // destination & usage for current frame @@ -495,6 +495,7 @@ class CRenderTarget : public IRender_Target void accum_reflected(light* L); // Igor: for volumetric lights void accum_volumetric(light* L); + void accum_volumetric_lv(light* L); void phase_bloom(); void phase_luminance(); void phase_combine(); diff --git a/src/Layers/xrRenderPC_R4/r4_rendertarget_accum_point.cpp b/src/Layers/xrRenderPC_R4/r4_rendertarget_accum_point.cpp index f576c70dce..91fad57698 100644 --- a/src/Layers/xrRenderPC_R4/r4_rendertarget_accum_point.cpp +++ b/src/Layers/xrRenderPC_R4/r4_rendertarget_accum_point.cpp @@ -2,6 +2,7 @@ void CRenderTarget::accum_point(light* L) { + PROF_EVENT("CRenderTarget::accum_point"); phase_accumulator(); RImplementation.stats.l_visible ++; @@ -24,7 +25,6 @@ void CRenderTarget::accum_point(light* L) Device.mView.transform_tiny(L_pos, L->position); // Xforms - L->xform_calc(); RCache.set_xform_world(L->m_xform); RCache.set_xform_view(Device.mView); RCache.set_xform_project(Device.mProject); diff --git a/src/Layers/xrRenderPC_R4/r4_rendertarget_accum_reflected.cpp b/src/Layers/xrRenderPC_R4/r4_rendertarget_accum_reflected.cpp index d76d38f21c..9d810ddc5a 100644 --- a/src/Layers/xrRenderPC_R4/r4_rendertarget_accum_reflected.cpp +++ b/src/Layers/xrRenderPC_R4/r4_rendertarget_accum_reflected.cpp @@ -11,7 +11,6 @@ void CRenderTarget::accum_reflected(light* L) ref_shader* shader_msaa = s_accum_reflected_msaa; BOOL bIntersect = FALSE; //enable_scissor(L); - L->xform_calc(); RCache.set_xform_world(L->m_xform); RCache.set_xform_view(Device.mView); RCache.set_xform_project(Device.mProject); diff --git a/src/Layers/xrRenderPC_R4/r4_rendertarget_accum_spot.cpp b/src/Layers/xrRenderPC_R4/r4_rendertarget_accum_spot.cpp index aeca39b4d2..41f0fc095d 100644 --- a/src/Layers/xrRenderPC_R4/r4_rendertarget_accum_spot.cpp +++ b/src/Layers/xrRenderPC_R4/r4_rendertarget_accum_spot.cpp @@ -1,10 +1,12 @@ #include "stdafx.h" #include "../xrRender/du_cone.h" +#include "..\xrRender\CHudInitializer.h" //extern Fvector du_cone_vertices[DU_CONE_NUMVERTEX]; void CRenderTarget::accum_spot(light* L) { + PROF_EVENT("CRenderTarget::accum_spot"); phase_accumulator(); RImplementation.stats.l_visible ++; @@ -36,7 +38,6 @@ void CRenderTarget::accum_spot(light* L) BOOL bIntersect = FALSE; //enable_scissor(L); { // setup xform - L->xform_calc(); RCache.set_xform_world(L->m_xform); RCache.set_xform_view(Device.mView); RCache.set_xform_project(Device.mProject); @@ -273,6 +274,114 @@ void CRenderTarget::accum_spot(light* L) u_DBT_disable(); } +void CRenderTarget::accum_volumetric_lv(light* L) +{ + //LV: Point lights will be fixed later... I hope + if (L == nullptr) + return; + + // [ SSS ] Fade through distance volumetric lights. + if (ps_ssfx_volumetric.x > 0) + { + float Falloff = ps_ssfx_volumetric.y - std::min(std::max((L->vis.distance - 20) * 0.01f, 0.0f), 1.0f) * ps_ssfx_volumetric.y; + L->m_volumetric_intensity = Falloff; + L->flags.bVolumetric = Falloff <= 0 ? false : true; + } + + if (!L->flags.bVolumetric) + return; + + if (!RImplementation.o.ssfx_volumetric) + { + phase_vol_accumulator(); + } + else + { + if (!m_bHasActiveVolumetric_spot) + { + m_bHasActiveVolumetric_spot = true; + + FLOAT ColorRGBA[4] = { 0.0f, 0.0f, 0.0f, 0.0f }; + HW.pContext->ClearRenderTargetView(rt_ssfx_volumetric->pRT, ColorRGBA); + } + + u_setrt(rt_ssfx_volumetric, NULL, NULL, NULL); + + RCache.set_Stencil(FALSE); + RCache.set_CullMode(CULL_NONE); + RCache.set_ColorWriteEnable(); + } + + //Set XFORMs, we gonna transform our geometry in VS + L->xform_calc(); + RCache.set_xform_world(L->m_xform); + RCache.set_xform_view(Device.mView); + RCache.set_xform_project(Device.mProject); + + //Shadow xform (+texture adjustment matrix) + Fmatrix m_Shadow, m_Lmap; + { + float smapsize = float(RImplementation.o.smapsize); + float fTexelOffs = (.5f / smapsize); + float view_dim = float(L->X.S.size - 2) / smapsize; + float view_sx = float(L->X.S.posX + 1) / smapsize; + float view_sy = float(L->X.S.posY + 1) / smapsize; + float fRange = float(1.f) * ps_r2_ls_depth_scale; + float fBias = ps_r2_ls_depth_bias; + + Fmatrix m_TexelAdjust = { + view_dim / 2.f, 0.0f, 0.0f, 0.0f, + 0.0f, -view_dim / 2.f, 0.0f, 0.0f, + 0.0f, 0.0f, fRange, 0.0f, + view_dim / 2.f + view_sx + fTexelOffs, view_dim / 2.f + view_sy + fTexelOffs, fBias, 1.0f + }; + + //Compute xforms + Fmatrix xf_world; + xf_world.invert(Device.mView); + Fmatrix xf_view = L->X.S.view; + Fmatrix xf_project; + xf_project.mul(m_TexelAdjust, L->X.S.project); + + m_Shadow.set(xf_view); + m_Shadow.mulA_44(xf_project); + } + + //Light direction (spot), color, and position. All in world space + Fvector L_dir, L_clr, L_pos; + L_clr.set(L->color.r, L->color.g, L->color.b); + L_clr.mul(L->m_volumetric_intensity); + L_clr.mul(L->m_volumetric_distance); + L_clr.mul(L->get_LOD()); + + // Lower intensity to be comparable to SSS + L_clr.mul(0.33f); + + L_pos.set(L->position); + L_dir.set(L->direction); + L_dir.normalize(); + + //Attenuation + float att_R = L->m_volumetric_distance * L->range * .95f; + float att_factor = 1.f / (att_R * att_R); + + //Set the shader + RCache.set_Element(s_combine->E[5]); + RCache.set_CullMode(CULL_CW); + RCache.set_Stencil(FALSE); + + RCache.set_ColorWriteEnable(); + //Set constants + RCache.set_c("Ldynamic_pos", L_pos.x, L_pos.y, L_pos.z, att_factor); + RCache.set_c("Ldynamic_dir", L_dir.x, L_dir.y, L_dir.z, -cos(L->cone * 0.5)); + RCache.set_c("Ldynamic_color", L_clr.x, L_clr.y, L_clr.z, L->get_LOD()); + + RCache.set_c("m_shadow", m_Shadow); + + //Render, no IB/VB - geometry in VS + draw_volume(L); +} + void CRenderTarget::accum_volumetric(light* L) { // [ SSS ] Fade through distance volumetric lights. @@ -284,7 +393,7 @@ void CRenderTarget::accum_volumetric(light* L) } //if (L->flags.type != IRender_Light::SPOT) return; - if (!L->flags.bVolumetric) return; + PROF_EVENT("CRenderTarget::accum_volumetric"); if (!RImplementation.o.ssfx_volumetric) { @@ -323,7 +432,6 @@ void CRenderTarget::accum_volumetric(light* L) BOOL bIntersect = FALSE; //enable_scissor(L); { // setup xform - L->xform_calc(); RCache.set_xform_world(L->m_xform); RCache.set_xform_view(Device.mView); RCache.set_xform_project(Device.mProject); @@ -415,9 +523,9 @@ void CRenderTarget::accum_volumetric(light* L) Fbox aabb; //float scaledRadius = L->spatial.sphere.R * (1+L->m_volumetric_distance)*0.5f; - float scaledRadius = L->spatial.sphere.R * L->m_volumetric_distance; - Fvector rr = Fvector().set(scaledRadius, scaledRadius, scaledRadius); - Fvector pt = L->spatial.sphere.P; + float scaledRadius = L->SpatialComponent->spatial.sphere.R * L->m_volumetric_distance; + Fvector rr = Fvector().set(scaledRadius, scaledRadius, scaledRadius); + Fvector pt = L->SpatialComponent->spatial.sphere.P; pt.sub(L->position); pt.mul(L->m_volumetric_distance); pt.add(L->position); diff --git a/src/Layers/xrRenderPC_R4/r4_rendertarget_enable_scissor.cpp b/src/Layers/xrRenderPC_R4/r4_rendertarget_enable_scissor.cpp index 4de402a4f2..c1a0f1992c 100644 --- a/src/Layers/xrRenderPC_R4/r4_rendertarget_enable_scissor.cpp +++ b/src/Layers/xrRenderPC_R4/r4_rendertarget_enable_scissor.cpp @@ -16,14 +16,14 @@ void CRenderTarget::enable_dbt_bounds(light* L) if (!ps_r2_ls_flags.test(R2FLAG_USE_NVDBT)) return; u32 mask = 0xffffffff; - EFC_Visible vis = RImplementation.ViewBase.testSphere(L->spatial.sphere.P, L->spatial.sphere.R * 1.01f, mask); + EFC_Visible vis = RImplementation.ViewBase.testSphere(L->SpatialComponent->spatial.sphere.P, L->SpatialComponent->spatial.sphere.R * 1.01f, mask); if (vis != fcvFully) return; // xform BB Fbox BB; Fvector rr; - rr.set(L->spatial.sphere.R, L->spatial.sphere.R, L->spatial.sphere.R); - BB.setb(L->spatial.sphere.P, rr); + rr.set(L->SpatialComponent->spatial.sphere.R, L->SpatialComponent->spatial.sphere.R, L->SpatialComponent->spatial.sphere.R); + BB.setb(L->SpatialComponent->spatial.sphere.P, rr); Fbox bbp; bbp.invalidate(); @@ -79,13 +79,13 @@ BOOL CRenderTarget::enable_scissor(light* L) // true if intersects near plane Fplane P; P.n.set(plane.x, plane.y, plane.z); P.d = plane.w; - float p_dist = P.classify(L->spatial.sphere.P) - L->spatial.sphere.R; + float p_dist = P.classify(L->SpatialComponent->spatial.sphere.P) - L->SpatialComponent->spatial.sphere.R; near_intersect = (p_dist <= 0); } #ifdef DEBUG if (1) { - Fsphere S; S.set (L->spatial.sphere.P,L->spatial.sphere.R); + Fsphere S; S.set (L->SpatialComponent->spatial.sphere.P,L->SpatialComponent->spatial.sphere.R); dbg_spheres.push_back (mk_pair(S,L->color)); } #endif diff --git a/src/Layers/xrRenderPC_R4/r4_rendertarget_phase_combine.cpp b/src/Layers/xrRenderPC_R4/r4_rendertarget_phase_combine.cpp index 7dc1a54700..17346a0f5a 100644 --- a/src/Layers/xrRenderPC_R4/r4_rendertarget_phase_combine.cpp +++ b/src/Layers/xrRenderPC_R4/r4_rendertarget_phase_combine.cpp @@ -40,6 +40,7 @@ float hclip(float v, float dim) { return 2.f * v / dim - 1.f; } void CRenderTarget::phase_combine() { PIX_EVENT(phase_combine); + PROF_EVENT("phase_combine"); bool ssfx_PrevPos_Requiered = false; @@ -50,21 +51,26 @@ void CRenderTarget::phase_combine() Fvector2 p0, p1; //*** exposure-pipeline - u32 gpu_id = Device.dwFrame % HW.Caps.iGPUNum; - if (Device.m_SecondViewport.IsSVPActive()) //--#SM+#-- +SecondVP+ + if (Device.m_SecondViewport.IsSVPActive()) //--#SM+#-- +SecondVP+ Fix for screen flickering { - // clang-format off - gpu_id = (Device.dwFrame - 1) % HW.Caps.iGPUNum; + if (t_LUM_src != rt_LUM_pool[0]->pTexture) + t_LUM_src->surface_set(rt_LUM_pool[0]->pSurface); + if (t_LUM_dest != rt_LUM_pool[1]->pTexture) + t_LUM_dest->surface_set(rt_LUM_pool[1]->pSurface); } + else { - t_LUM_src->surface_set(rt_LUM_pool[gpu_id * 2 + 0]->pSurface); - t_LUM_dest->surface_set(rt_LUM_pool[gpu_id * 2 + 1]->pSurface); + if (t_LUM_src != rt_LUM_pool[0]->pTexture) + t_LUM_src->surface_set(rt_LUM_pool[0]->pSurface); + if (t_LUM_dest != rt_LUM_pool[1]->pTexture) + t_LUM_dest->surface_set(rt_LUM_pool[1]->pSurface); } if (RImplementation.o.ssao_hdao && RImplementation.o.ssao_ultra) { if (ps_r_ssao > 0) { + PROF_EVENT("PHASE_AMBIENT_OCCLUSION"); phase_hdao(); } } @@ -354,7 +360,7 @@ void CRenderTarget::phase_combine() // Render Water SSR RCache.set_xform_world(Fidentity); - RImplementation.r_dsgraph_render_water_ssr(); + RImplementation.GMBase.r_dsgraph_render_water_ssr(); // Restore Viewport set_viewport_size(HW.pContext, w, h); @@ -376,7 +382,7 @@ void CRenderTarget::phase_combine() // Final water rendering ( All the code above can be omitted if the Water module isn't installed ) RCache.set_xform_world(Fidentity); - RImplementation.r_dsgraph_render_water(); + RImplementation.GMBase.r_dsgraph_render_water(); { if (RImplementation.o.ssfx_rain) @@ -458,11 +464,13 @@ void CRenderTarget::phase_combine() // Distortion filter BOOL bDistort = RImplementation.o.distortion_enabled; // This can be modified { - u32 count = RImplementation.mapDistort.size() + RImplementation.mapHUDDistort.size(); - if ((count < 1 && !_menu_pp)) - { + if (( + 0 == RImplementation.GMBase.RGraph.mapStaticSorted.Distort.size() && + 0 == RImplementation.GMBase.RGraph.mapDynamicSorted.Distort.size() && + 0 == RImplementation.GMBase.RGraph.mapHUDSorted.Distort.size() + ) && !_menu_pp + ) bDistort = FALSE; - } if (bDistort) { PIX_EVENT(render_distort_objects); @@ -482,7 +490,7 @@ void CRenderTarget::phase_combine() RCache.set_Stencil(FALSE); RCache.set_ColorWriteEnable(); //CHK_DX(HW.pDevice->Clear ( 0L, NULL, D3DCLEAR_TARGET, color_rgba(127,127,0,127), 1.0f, 0L)); - RImplementation.r_dsgraph_render_distort(); + RImplementation.GMBase.r_dsgraph_render_distort(); if (g_pGamePersistent) g_pGamePersistent->OnRenderPPUI_PP(); // PP-UI } } @@ -743,7 +751,7 @@ void CRenderTarget::phase_combine() //*** exposure-pipeline-clear { - std::swap(rt_LUM_pool[gpu_id * 2 + 0], rt_LUM_pool[gpu_id * 2 + 1]); + std::swap(rt_LUM_pool[0], rt_LUM_pool[1]); t_LUM_src->surface_set(NULL); t_LUM_dest->surface_set(NULL); } diff --git a/src/Layers/xrRenderPC_R4/r4_rendertarget_phase_luminance.cpp b/src/Layers/xrRenderPC_R4/r4_rendertarget_phase_luminance.cpp index 1b3fe3ca3a..4748dcc356 100644 --- a/src/Layers/xrRenderPC_R4/r4_rendertarget_phase_luminance.cpp +++ b/src/Layers/xrRenderPC_R4/r4_rendertarget_phase_luminance.cpp @@ -117,8 +117,7 @@ void CRenderTarget::phase_luminance() } // 222: Perform LUM-SAT, pass 2, 8x8 => 1x1 - u32 gpu_id = Device.dwFrame % HW.Caps.iGPUNum; - u_setrt(rt_LUM_pool[gpu_id * 2 + 1],NULL,NULL,NULL); + u_setrt(rt_LUM_pool[1],NULL,NULL,NULL); //RImplementation.rmNormal(); { // Build filter-kernel diff --git a/src/Layers/xrRenderPC_R4/stdafx.h b/src/Layers/xrRenderPC_R4/stdafx.h index cdab762e28..e7107f3a0f 100644 --- a/src/Layers/xrRenderPC_R4/stdafx.h +++ b/src/Layers/xrRenderPC_R4/stdafx.h @@ -48,6 +48,8 @@ #include "../xrRender/xrRender_console.h" #include "r4.h" +#include "../../xrCore/profiler.h" + IC void jitter(CBlender_Compile& C) { // C.r_Sampler ("jitter0", JITTER(0), true, D3DTADDRESS_WRAP, D3DTEXF_POINT, D3DTEXF_NONE, D3DTEXF_POINT); diff --git a/src/Layers/xrRenderPC_R4/xrRender_R4.vcxproj b/src/Layers/xrRenderPC_R4/xrRender_R4.vcxproj index 637e0422b6..274570d703 100644 --- a/src/Layers/xrRenderPC_R4/xrRender_R4.vcxproj +++ b/src/Layers/xrRenderPC_R4/xrRender_R4.vcxproj @@ -13,6 +13,10 @@ Release x64 + + VerifiedDX11ASAN + x64 + VerifiedDX11 x64 @@ -57,6 +61,14 @@ false x64 + + StaticLibrary + v143 + MultiByte + false + x64 + true + StaticLibrary v143 @@ -87,6 +99,11 @@ + + + + + @@ -116,6 +133,11 @@ $(xrGameDir)bin_dbg\$(Platform)\$(Configuration)\ $(xrIntDir)$(ProjectName)\ + + false + $(xrGameDir)bin_dbg\$(Platform)\$(Configuration)\ + $(xrIntDir)$(ProjectName)\ + false $(xrGameDir)bin_dbg\$(Platform)\$(Configuration)\ @@ -200,7 +222,7 @@ false false .;$(SolutionDir)3rd party\imgui\;$(SolutionDir)3rd party\luajit-2\src\;$(SolutionDir)3rd party\luabind\;$(SolutionDir)xrCore;$(xrSdkDir)include;$(XRAY_16X_LIBS)OpenAutomate\inc;$(XRAY_16X_LIBS)nvapi;%(AdditionalIncludeDirectories) - USE_VERIFY_IN_RELEASE;USE_DX11;WIN32;NDEBUG;_WINDOWS;_USRDLL;XRRENDER_R4_EXPORTS;_SECURE_SCL=0;%(PreprocessorDefinitions) + XRCORE_PROFILER;USE_VERIFY_IN_RELEASE;USE_DX11;WIN32;NDEBUG;_WINDOWS;_USRDLL;XRRENDER_R4_EXPORTS;_SECURE_SCL=0;%(PreprocessorDefinitions) NotSet Use EditAndContinue @@ -239,7 +261,7 @@ false false .;$(SolutionDir)3rd party\imgui\;$(SolutionDir)3rd party\luajit-2\src\;$(SolutionDir)3rd party\luabind\;$(SolutionDir)xrCore;$(xrSdkDir)include;$(XRAY_16X_LIBS)OpenAutomate\inc;$(XRAY_16X_LIBS)nvapi;%(AdditionalIncludeDirectories) - USE_VERIFY_IN_RELEASE;USE_DX11;WIN32;NDEBUG;_WINDOWS;_USRDLL;XRRENDER_R4_EXPORTS;_SECURE_SCL=0;%(PreprocessorDefinitions) + XRCORE_PROFILER;USE_VERIFY_IN_RELEASE;USE_DX11;WIN32;NDEBUG;_WINDOWS;_USRDLL;XRRENDER_R4_EXPORTS;_SECURE_SCL=0;%(PreprocessorDefinitions) NotSet Use EditAndContinue @@ -268,6 +290,45 @@ true + + + Disabled + Disabled + false + Neither + false + false + false + .;$(SolutionDir)3rd party\imgui\;$(SolutionDir)3rd party\luajit-2\src\;$(SolutionDir)3rd party\luabind\;$(SolutionDir)xrCore;$(xrSdkDir)include;$(XRAY_16X_LIBS)OpenAutomate\inc;$(XRAY_16X_LIBS)nvapi;%(AdditionalIncludeDirectories) + XRCORE_PROFILER;USE_VERIFY_IN_RELEASE;_DISABLE_VECTOR_ANNOTATION;_DISABLE_STRING_ANNOTATION;USE_DX11;WIN32;NDEBUG;_WINDOWS;_USRDLL;XRRENDER_R4_EXPORTS;_SECURE_SCL=0;%(PreprocessorDefinitions) + NotSet + Use + ProgramDatabase + -Zm113 %(AdditionalOptions) + USE_LUAJIT_ONE + 4005;4099 + true + Level4 + false + MultiThreadedDLL + false + stdcpp17 + true + + + dxguid.lib;d3dx11.lib;D3DCompiler.lib;d3d11.lib;dxgi.lib;nvapi.lib;dxerr.lib;d3d10.lib;%(AdditionalDependencies) + $(SolutionDir)3rd party\luajit-2\src\;$(xrSdkDir)libraries\x64;$(xrLibDir);$(XRAY_16X_LIBS)OpenAutomate\libraries;$(SolutionDir)x64\Release;$(xrGameDir)bin_dbg;%(AdditionalLibraryDirectories) + NotSet + true + true + true + Default + false + $(xrLibDir)$(TargetName).lib + LIBCMT + true + + .;$(SolutionDir)3rd party\imgui\;$(SolutionDir)3rd party\luajit-2\src\;$(SolutionDir)3rd party\luabind\;$(SolutionDir)xrCore;$(xrSdkDir)include;$(XRAY_16X_LIBS)OpenAutomate\inc;$(XRAY_16X_LIBS)nvapi;%(AdditionalIncludeDirectories) @@ -369,6 +430,7 @@ + @@ -426,6 +488,7 @@ + @@ -436,7 +499,7 @@ - + @@ -496,13 +559,10 @@ - - - @@ -555,6 +615,7 @@ + @@ -601,9 +662,11 @@ + + @@ -614,6 +677,9 @@ + + + @@ -632,16 +698,18 @@ + + - + @@ -690,15 +758,6 @@ - - - - - - - - - @@ -731,7 +790,6 @@ - @@ -739,6 +797,7 @@ Create Create Create + Create Create diff --git a/src/Layers/xrRenderPC_R4/xrRender_R4.vcxproj.filters b/src/Layers/xrRenderPC_R4/xrRender_R4.vcxproj.filters index 0aa32b9f40..5a751ca2f2 100644 --- a/src/Layers/xrRenderPC_R4/xrRender_R4.vcxproj.filters +++ b/src/Layers/xrRenderPC_R4/xrRender_R4.vcxproj.filters @@ -213,12 +213,6 @@ Core - - Core - - - Core - Core @@ -258,12 +252,6 @@ Lights - - Lights - - - Lights - Lights @@ -798,6 +786,13 @@ Core + + Core + + + + Core + @@ -815,21 +810,6 @@ Core - - Core - - - Core - - - Core - - - Core - - - Core - Core @@ -845,9 +825,6 @@ Core - - Core - Core @@ -914,18 +891,6 @@ Lights - - Lights - - - Lights - - - Lights - - - Lights - Lights @@ -1046,9 +1011,6 @@ Visibility\Sector/Portal - - Visibility\Sector/Portal - Visibility\HOM Occlusion @@ -1481,5 +1443,30 @@ Core + + Core + + + Visibility\Sector/Portal + + + Core + + + + Core + + + Core + + + Core + + + Core + + + Lights + - \ No newline at end of file + diff --git a/src/ReShadeCompat/ReShadeCompat.vcxproj b/src/ReShadeCompat/ReShadeCompat.vcxproj index 98f5179f56..01d6e5689d 100644 --- a/src/ReShadeCompat/ReShadeCompat.vcxproj +++ b/src/ReShadeCompat/ReShadeCompat.vcxproj @@ -13,6 +13,10 @@ Release x64 + + VerifiedDX11ASAN + x64 + VerifiedDX11 x64 @@ -57,6 +61,14 @@ false x64 + + StaticLibrary + v143 + MultiByte + false + x64 + true + StaticLibrary v143 @@ -87,6 +99,11 @@ + + + + + @@ -116,6 +133,11 @@ $(xrGameDir)bin_dbg\$(Platform)\$(Configuration)\ $(xrIntDir)$(ProjectName)\ + + false + $(xrGameDir)bin_dbg\$(Platform)\$(Configuration)\ + $(xrIntDir)$(ProjectName)\ + false $(xrGameDir)bin_dbg\$(Platform)\$(Configuration)\ @@ -270,6 +292,38 @@ true + + + Disabled + false + Neither + false + .;$(XRAY_16X_LIBS);$(xrSdkDir)include;%(AdditionalIncludeDirectories) + _DISABLE_VECTOR_ANNOTATION;_DISABLE_STRING_ANNOTATION;USE_VERIFY_IN_RELEASE;PURE_ALLOC;WIN32;NDEBUG;_WINDOWS;_USRDLL;XRCORE_EXPORTS;_SECURE_SCL=0;%(PreprocessorDefinitions) + NotSet + Use + Level3 + ProgramDatabase + stdcpp17 + false + Disabled + false + true + + + $(xrSdkDir)libraries;$(XRAY_16X_LIBS)BugTrap\Bin;$(xrLibDir);%(AdditionalLibraryDirectories) + NotSet + true + true + true + Default + false + + + $(xrLibDir)$(TargetName).lib + true + + MaxSpeed @@ -319,6 +373,7 @@ Create Create + Create Create Create Create diff --git a/src/engine-vs2022.sln b/src/engine-vs2022.sln index 1cba32913e..5eaf17b014 100644 --- a/src/engine-vs2022.sln +++ b/src/engine-vs2022.sln @@ -280,6 +280,7 @@ Global Release-AVX|x64 = Release-AVX|x64 Verified|x64 = Verified|x64 VerifiedDX11|x64 = VerifiedDX11|x64 + VerifiedDX11ASAN|x64 = VerifiedDX11ASAN|x64 VerifiedDX8|x64 = VerifiedDX8|x64 VerifiedDX9|x64 = VerifiedDX9|x64 EndGlobalSection @@ -318,6 +319,8 @@ Global {2578C6D8-660D-48AE-9322-7422F8664F06}.Verified|x64.Build.0 = VerifiedDX11|x64 {2578C6D8-660D-48AE-9322-7422F8664F06}.VerifiedDX11|x64.ActiveCfg = VerifiedDX11|x64 {2578C6D8-660D-48AE-9322-7422F8664F06}.VerifiedDX11|x64.Build.0 = VerifiedDX11|x64 + {2578C6D8-660D-48AE-9322-7422F8664F06}.VerifiedDX11ASAN|x64.ActiveCfg = VerifiedDX11ASAN|x64 + {2578C6D8-660D-48AE-9322-7422F8664F06}.VerifiedDX11ASAN|x64.Build.0 = VerifiedDX11ASAN|x64 {2578C6D8-660D-48AE-9322-7422F8664F06}.VerifiedDX8|x64.ActiveCfg = VerifiedDX8|x64 {2578C6D8-660D-48AE-9322-7422F8664F06}.VerifiedDX8|x64.Build.0 = VerifiedDX8|x64 {2578C6D8-660D-48AE-9322-7422F8664F06}.VerifiedDX8|x64.Deploy.0 = VerifiedDX8|x64 @@ -349,6 +352,8 @@ Global {1BF75FEB-87DD-486C-880B-227987D191C2}.Verified|x64.Build.0 = Verified|x64 {1BF75FEB-87DD-486C-880B-227987D191C2}.VerifiedDX11|x64.ActiveCfg = Verified|x64 {1BF75FEB-87DD-486C-880B-227987D191C2}.VerifiedDX11|x64.Build.0 = Verified|x64 + {1BF75FEB-87DD-486C-880B-227987D191C2}.VerifiedDX11ASAN|x64.ActiveCfg = VerifiedDX11ASAN|x64 + {1BF75FEB-87DD-486C-880B-227987D191C2}.VerifiedDX11ASAN|x64.Build.0 = VerifiedDX11ASAN|x64 {1BF75FEB-87DD-486C-880B-227987D191C2}.VerifiedDX8|x64.ActiveCfg = Verified|x64 {1BF75FEB-87DD-486C-880B-227987D191C2}.VerifiedDX8|x64.Build.0 = Verified|x64 {1BF75FEB-87DD-486C-880B-227987D191C2}.VerifiedDX9|x64.ActiveCfg = Verified|x64 @@ -379,6 +384,8 @@ Global {A19B1DF2-82EC-4364-8BDF-85D13A1C89B5}.Verified|x64.Build.0 = Verified|x64 {A19B1DF2-82EC-4364-8BDF-85D13A1C89B5}.VerifiedDX11|x64.ActiveCfg = Verified|x64 {A19B1DF2-82EC-4364-8BDF-85D13A1C89B5}.VerifiedDX11|x64.Build.0 = Verified|x64 + {A19B1DF2-82EC-4364-8BDF-85D13A1C89B5}.VerifiedDX11ASAN|x64.ActiveCfg = VerifiedDX11ASAN|x64 + {A19B1DF2-82EC-4364-8BDF-85D13A1C89B5}.VerifiedDX11ASAN|x64.Build.0 = VerifiedDX11ASAN|x64 {A19B1DF2-82EC-4364-8BDF-85D13A1C89B5}.VerifiedDX8|x64.ActiveCfg = Verified|x64 {A19B1DF2-82EC-4364-8BDF-85D13A1C89B5}.VerifiedDX8|x64.Build.0 = Verified|x64 {A19B1DF2-82EC-4364-8BDF-85D13A1C89B5}.VerifiedDX9|x64.ActiveCfg = Verified|x64 @@ -409,6 +416,8 @@ Global {A0F7D1FB-59A7-4717-A7E4-96F37E91998E}.Verified|x64.Build.0 = Verified|x64 {A0F7D1FB-59A7-4717-A7E4-96F37E91998E}.VerifiedDX11|x64.ActiveCfg = Verified|x64 {A0F7D1FB-59A7-4717-A7E4-96F37E91998E}.VerifiedDX11|x64.Build.0 = Verified|x64 + {A0F7D1FB-59A7-4717-A7E4-96F37E91998E}.VerifiedDX11ASAN|x64.ActiveCfg = VerifiedDX11ASAN|x64 + {A0F7D1FB-59A7-4717-A7E4-96F37E91998E}.VerifiedDX11ASAN|x64.Build.0 = VerifiedDX11ASAN|x64 {A0F7D1FB-59A7-4717-A7E4-96F37E91998E}.VerifiedDX8|x64.ActiveCfg = Verified|x64 {A0F7D1FB-59A7-4717-A7E4-96F37E91998E}.VerifiedDX8|x64.Build.0 = Verified|x64 {A0F7D1FB-59A7-4717-A7E4-96F37E91998E}.VerifiedDX9|x64.ActiveCfg = Verified|x64 @@ -439,6 +448,8 @@ Global {CA0649DD-D089-423A-981C-46B57A884EB9}.Verified|x64.Build.0 = Verified|x64 {CA0649DD-D089-423A-981C-46B57A884EB9}.VerifiedDX11|x64.ActiveCfg = Verified|x64 {CA0649DD-D089-423A-981C-46B57A884EB9}.VerifiedDX11|x64.Build.0 = Verified|x64 + {CA0649DD-D089-423A-981C-46B57A884EB9}.VerifiedDX11ASAN|x64.ActiveCfg = VerifiedDX11ASAN|x64 + {CA0649DD-D089-423A-981C-46B57A884EB9}.VerifiedDX11ASAN|x64.Build.0 = VerifiedDX11ASAN|x64 {CA0649DD-D089-423A-981C-46B57A884EB9}.VerifiedDX8|x64.ActiveCfg = Verified|x64 {CA0649DD-D089-423A-981C-46B57A884EB9}.VerifiedDX8|x64.Build.0 = Verified|x64 {CA0649DD-D089-423A-981C-46B57A884EB9}.VerifiedDX9|x64.ActiveCfg = Verified|x64 @@ -469,6 +480,8 @@ Global {200652A6-043E-4634-8837-87983B3BD5E0}.Verified|x64.Build.0 = Verified|x64 {200652A6-043E-4634-8837-87983B3BD5E0}.VerifiedDX11|x64.ActiveCfg = Verified|x64 {200652A6-043E-4634-8837-87983B3BD5E0}.VerifiedDX11|x64.Build.0 = Verified|x64 + {200652A6-043E-4634-8837-87983B3BD5E0}.VerifiedDX11ASAN|x64.ActiveCfg = VerifiedDX11ASAN|x64 + {200652A6-043E-4634-8837-87983B3BD5E0}.VerifiedDX11ASAN|x64.Build.0 = VerifiedDX11ASAN|x64 {200652A6-043E-4634-8837-87983B3BD5E0}.VerifiedDX8|x64.ActiveCfg = Verified|x64 {200652A6-043E-4634-8837-87983B3BD5E0}.VerifiedDX8|x64.Build.0 = Verified|x64 {200652A6-043E-4634-8837-87983B3BD5E0}.VerifiedDX9|x64.ActiveCfg = Verified|x64 @@ -499,6 +512,8 @@ Global {435BAC9A-B225-457D-AB40-C9BD0CC8838C}.Verified|x64.Build.0 = Verified|x64 {435BAC9A-B225-457D-AB40-C9BD0CC8838C}.VerifiedDX11|x64.ActiveCfg = Verified|x64 {435BAC9A-B225-457D-AB40-C9BD0CC8838C}.VerifiedDX11|x64.Build.0 = Verified|x64 + {435BAC9A-B225-457D-AB40-C9BD0CC8838C}.VerifiedDX11ASAN|x64.ActiveCfg = VerifiedDX11ASAN|x64 + {435BAC9A-B225-457D-AB40-C9BD0CC8838C}.VerifiedDX11ASAN|x64.Build.0 = VerifiedDX11ASAN|x64 {435BAC9A-B225-457D-AB40-C9BD0CC8838C}.VerifiedDX8|x64.ActiveCfg = Verified|x64 {435BAC9A-B225-457D-AB40-C9BD0CC8838C}.VerifiedDX8|x64.Build.0 = Verified|x64 {435BAC9A-B225-457D-AB40-C9BD0CC8838C}.VerifiedDX9|x64.ActiveCfg = Verified|x64 @@ -529,6 +544,8 @@ Global {94A1C366-3D19-48E6-8170-4ADC2E70DF97}.Verified|x64.Build.0 = Verified|x64 {94A1C366-3D19-48E6-8170-4ADC2E70DF97}.VerifiedDX11|x64.ActiveCfg = Verified|x64 {94A1C366-3D19-48E6-8170-4ADC2E70DF97}.VerifiedDX11|x64.Build.0 = Verified|x64 + {94A1C366-3D19-48E6-8170-4ADC2E70DF97}.VerifiedDX11ASAN|x64.ActiveCfg = VerifiedDX11ASAN|x64 + {94A1C366-3D19-48E6-8170-4ADC2E70DF97}.VerifiedDX11ASAN|x64.Build.0 = VerifiedDX11ASAN|x64 {94A1C366-3D19-48E6-8170-4ADC2E70DF97}.VerifiedDX8|x64.ActiveCfg = Verified|x64 {94A1C366-3D19-48E6-8170-4ADC2E70DF97}.VerifiedDX8|x64.Build.0 = Verified|x64 {94A1C366-3D19-48E6-8170-4ADC2E70DF97}.VerifiedDX9|x64.ActiveCfg = Verified|x64 @@ -559,6 +576,8 @@ Global {57A498C9-A741-4DDF-8EFC-BFB9EB6B00E2}.Verified|x64.Build.0 = Verified|x64 {57A498C9-A741-4DDF-8EFC-BFB9EB6B00E2}.VerifiedDX11|x64.ActiveCfg = Verified|x64 {57A498C9-A741-4DDF-8EFC-BFB9EB6B00E2}.VerifiedDX11|x64.Build.0 = Verified|x64 + {57A498C9-A741-4DDF-8EFC-BFB9EB6B00E2}.VerifiedDX11ASAN|x64.ActiveCfg = VerifiedDX11ASAN|x64 + {57A498C9-A741-4DDF-8EFC-BFB9EB6B00E2}.VerifiedDX11ASAN|x64.Build.0 = VerifiedDX11ASAN|x64 {57A498C9-A741-4DDF-8EFC-BFB9EB6B00E2}.VerifiedDX8|x64.ActiveCfg = Verified|x64 {57A498C9-A741-4DDF-8EFC-BFB9EB6B00E2}.VerifiedDX8|x64.Build.0 = Verified|x64 {57A498C9-A741-4DDF-8EFC-BFB9EB6B00E2}.VerifiedDX9|x64.ActiveCfg = Verified|x64 @@ -589,6 +608,8 @@ Global {963BA4E5-499A-454D-B002-1D5ECE0527A6}.Verified|x64.Build.0 = Verified|x64 {963BA4E5-499A-454D-B002-1D5ECE0527A6}.VerifiedDX11|x64.ActiveCfg = Verified|x64 {963BA4E5-499A-454D-B002-1D5ECE0527A6}.VerifiedDX11|x64.Build.0 = Verified|x64 + {963BA4E5-499A-454D-B002-1D5ECE0527A6}.VerifiedDX11ASAN|x64.ActiveCfg = VerifiedDX11ASAN|x64 + {963BA4E5-499A-454D-B002-1D5ECE0527A6}.VerifiedDX11ASAN|x64.Build.0 = VerifiedDX11ASAN|x64 {963BA4E5-499A-454D-B002-1D5ECE0527A6}.VerifiedDX8|x64.ActiveCfg = Verified|x64 {963BA4E5-499A-454D-B002-1D5ECE0527A6}.VerifiedDX8|x64.Build.0 = Verified|x64 {963BA4E5-499A-454D-B002-1D5ECE0527A6}.VerifiedDX9|x64.ActiveCfg = Verified|x64 @@ -619,6 +640,8 @@ Global {CCCA7859-EB86-493E-9B53-C4235F45B3C5}.Verified|x64.Build.0 = Verified|x64 {CCCA7859-EB86-493E-9B53-C4235F45B3C5}.VerifiedDX11|x64.ActiveCfg = Verified|x64 {CCCA7859-EB86-493E-9B53-C4235F45B3C5}.VerifiedDX11|x64.Build.0 = Verified|x64 + {CCCA7859-EB86-493E-9B53-C4235F45B3C5}.VerifiedDX11ASAN|x64.ActiveCfg = VerifiedDX11ASAN|x64 + {CCCA7859-EB86-493E-9B53-C4235F45B3C5}.VerifiedDX11ASAN|x64.Build.0 = VerifiedDX11ASAN|x64 {CCCA7859-EB86-493E-9B53-C4235F45B3C5}.VerifiedDX8|x64.ActiveCfg = Verified|x64 {CCCA7859-EB86-493E-9B53-C4235F45B3C5}.VerifiedDX8|x64.Build.0 = Verified|x64 {CCCA7859-EB86-493E-9B53-C4235F45B3C5}.VerifiedDX9|x64.ActiveCfg = Verified|x64 @@ -649,6 +672,8 @@ Global {94A1C366-3D19-48E6-8170-4ADC2E70DF98}.Verified|x64.Build.0 = Verified|x64 {94A1C366-3D19-48E6-8170-4ADC2E70DF98}.VerifiedDX11|x64.ActiveCfg = Verified|x64 {94A1C366-3D19-48E6-8170-4ADC2E70DF98}.VerifiedDX11|x64.Build.0 = Verified|x64 + {94A1C366-3D19-48E6-8170-4ADC2E70DF98}.VerifiedDX11ASAN|x64.ActiveCfg = VerifiedDX11ASAN|x64 + {94A1C366-3D19-48E6-8170-4ADC2E70DF98}.VerifiedDX11ASAN|x64.Build.0 = VerifiedDX11ASAN|x64 {94A1C366-3D19-48E6-8170-4ADC2E70DF98}.VerifiedDX8|x64.ActiveCfg = Verified|x64 {94A1C366-3D19-48E6-8170-4ADC2E70DF98}.VerifiedDX8|x64.Build.0 = Verified|x64 {94A1C366-3D19-48E6-8170-4ADC2E70DF98}.VerifiedDX9|x64.ActiveCfg = Verified|x64 @@ -679,6 +704,8 @@ Global {1DAEC516-E52C-4A3C-A4DA-AE3553E6E0F8}.Verified|x64.Build.0 = Verified|x64 {1DAEC516-E52C-4A3C-A4DA-AE3553E6E0F8}.VerifiedDX11|x64.ActiveCfg = Verified|x64 {1DAEC516-E52C-4A3C-A4DA-AE3553E6E0F8}.VerifiedDX11|x64.Build.0 = Verified|x64 + {1DAEC516-E52C-4A3C-A4DA-AE3553E6E0F8}.VerifiedDX11ASAN|x64.ActiveCfg = VerifiedDX11ASAN|x64 + {1DAEC516-E52C-4A3C-A4DA-AE3553E6E0F8}.VerifiedDX11ASAN|x64.Build.0 = VerifiedDX11ASAN|x64 {1DAEC516-E52C-4A3C-A4DA-AE3553E6E0F8}.VerifiedDX8|x64.ActiveCfg = Verified|x64 {1DAEC516-E52C-4A3C-A4DA-AE3553E6E0F8}.VerifiedDX8|x64.Build.0 = Verified|x64 {1DAEC516-E52C-4A3C-A4DA-AE3553E6E0F8}.VerifiedDX9|x64.ActiveCfg = Verified|x64 @@ -709,6 +736,8 @@ Global {3F383D3C-FCD8-4170-990B-EB4833F09248}.Verified|x64.Build.0 = Verified|x64 {3F383D3C-FCD8-4170-990B-EB4833F09248}.VerifiedDX11|x64.ActiveCfg = Verified|x64 {3F383D3C-FCD8-4170-990B-EB4833F09248}.VerifiedDX11|x64.Build.0 = Verified|x64 + {3F383D3C-FCD8-4170-990B-EB4833F09248}.VerifiedDX11ASAN|x64.ActiveCfg = VerifiedDX11ASAN|x64 + {3F383D3C-FCD8-4170-990B-EB4833F09248}.VerifiedDX11ASAN|x64.Build.0 = VerifiedDX11ASAN|x64 {3F383D3C-FCD8-4170-990B-EB4833F09248}.VerifiedDX8|x64.ActiveCfg = Verified|x64 {3F383D3C-FCD8-4170-990B-EB4833F09248}.VerifiedDX8|x64.Build.0 = Verified|x64 {3F383D3C-FCD8-4170-990B-EB4833F09248}.VerifiedDX9|x64.ActiveCfg = Verified|x64 @@ -739,6 +768,8 @@ Global {98D24A3D-7666-4C11-9D6E-B10393CE8CBA}.Verified|x64.Build.0 = Verified|x64 {98D24A3D-7666-4C11-9D6E-B10393CE8CBA}.VerifiedDX11|x64.ActiveCfg = Verified|x64 {98D24A3D-7666-4C11-9D6E-B10393CE8CBA}.VerifiedDX11|x64.Build.0 = Verified|x64 + {98D24A3D-7666-4C11-9D6E-B10393CE8CBA}.VerifiedDX11ASAN|x64.ActiveCfg = VerifiedDX11ASAN|x64 + {98D24A3D-7666-4C11-9D6E-B10393CE8CBA}.VerifiedDX11ASAN|x64.Build.0 = VerifiedDX11ASAN|x64 {98D24A3D-7666-4C11-9D6E-B10393CE8CBA}.VerifiedDX8|x64.ActiveCfg = Verified|x64 {98D24A3D-7666-4C11-9D6E-B10393CE8CBA}.VerifiedDX8|x64.Build.0 = Verified|x64 {98D24A3D-7666-4C11-9D6E-B10393CE8CBA}.VerifiedDX9|x64.ActiveCfg = Verified|x64 @@ -769,6 +800,8 @@ Global {FA169092-EA3E-40C1-8E5A-A2B575700FE8}.Verified|x64.Build.0 = Verified|x64 {FA169092-EA3E-40C1-8E5A-A2B575700FE8}.VerifiedDX11|x64.ActiveCfg = Verified|x64 {FA169092-EA3E-40C1-8E5A-A2B575700FE8}.VerifiedDX11|x64.Build.0 = Verified|x64 + {FA169092-EA3E-40C1-8E5A-A2B575700FE8}.VerifiedDX11ASAN|x64.ActiveCfg = VerifiedDX11ASAN|x64 + {FA169092-EA3E-40C1-8E5A-A2B575700FE8}.VerifiedDX11ASAN|x64.Build.0 = VerifiedDX11ASAN|x64 {FA169092-EA3E-40C1-8E5A-A2B575700FE8}.VerifiedDX8|x64.ActiveCfg = Verified|x64 {FA169092-EA3E-40C1-8E5A-A2B575700FE8}.VerifiedDX8|x64.Build.0 = Verified|x64 {FA169092-EA3E-40C1-8E5A-A2B575700FE8}.VerifiedDX9|x64.ActiveCfg = Verified|x64 @@ -799,6 +832,8 @@ Global {AC9B12ED-A2D7-4337-A981-5BD8430E96D8}.Verified|x64.Build.0 = Verified|x64 {AC9B12ED-A2D7-4337-A981-5BD8430E96D8}.VerifiedDX11|x64.ActiveCfg = Verified|x64 {AC9B12ED-A2D7-4337-A981-5BD8430E96D8}.VerifiedDX11|x64.Build.0 = Verified|x64 + {AC9B12ED-A2D7-4337-A981-5BD8430E96D8}.VerifiedDX11ASAN|x64.ActiveCfg = VerifiedDX11ASAN|x64 + {AC9B12ED-A2D7-4337-A981-5BD8430E96D8}.VerifiedDX11ASAN|x64.Build.0 = VerifiedDX11ASAN|x64 {AC9B12ED-A2D7-4337-A981-5BD8430E96D8}.VerifiedDX8|x64.ActiveCfg = Verified|x64 {AC9B12ED-A2D7-4337-A981-5BD8430E96D8}.VerifiedDX8|x64.Build.0 = Verified|x64 {AC9B12ED-A2D7-4337-A981-5BD8430E96D8}.VerifiedDX9|x64.ActiveCfg = Verified|x64 @@ -829,6 +864,8 @@ Global {880CD250-BA77-4DAF-A8D4-552F12DD3AE4}.Verified|x64.Build.0 = Verified|x64 {880CD250-BA77-4DAF-A8D4-552F12DD3AE4}.VerifiedDX11|x64.ActiveCfg = Verified|x64 {880CD250-BA77-4DAF-A8D4-552F12DD3AE4}.VerifiedDX11|x64.Build.0 = Verified|x64 + {880CD250-BA77-4DAF-A8D4-552F12DD3AE4}.VerifiedDX11ASAN|x64.ActiveCfg = VerifiedDX11ASAN|x64 + {880CD250-BA77-4DAF-A8D4-552F12DD3AE4}.VerifiedDX11ASAN|x64.Build.0 = VerifiedDX11ASAN|x64 {880CD250-BA77-4DAF-A8D4-552F12DD3AE4}.VerifiedDX8|x64.ActiveCfg = Verified|x64 {880CD250-BA77-4DAF-A8D4-552F12DD3AE4}.VerifiedDX8|x64.Build.0 = Verified|x64 {880CD250-BA77-4DAF-A8D4-552F12DD3AE4}.VerifiedDX9|x64.ActiveCfg = Verified|x64 @@ -859,6 +896,8 @@ Global {44F716E7-05BD-4390-AB02-5F7DAF7FEFDE}.Verified|x64.Build.0 = Verified|x64 {44F716E7-05BD-4390-AB02-5F7DAF7FEFDE}.VerifiedDX11|x64.ActiveCfg = Verified|x64 {44F716E7-05BD-4390-AB02-5F7DAF7FEFDE}.VerifiedDX11|x64.Build.0 = Verified|x64 + {44F716E7-05BD-4390-AB02-5F7DAF7FEFDE}.VerifiedDX11ASAN|x64.ActiveCfg = VerifiedDX11ASAN|x64 + {44F716E7-05BD-4390-AB02-5F7DAF7FEFDE}.VerifiedDX11ASAN|x64.Build.0 = VerifiedDX11ASAN|x64 {44F716E7-05BD-4390-AB02-5F7DAF7FEFDE}.VerifiedDX8|x64.ActiveCfg = Verified|x64 {44F716E7-05BD-4390-AB02-5F7DAF7FEFDE}.VerifiedDX8|x64.Build.0 = Verified|x64 {44F716E7-05BD-4390-AB02-5F7DAF7FEFDE}.VerifiedDX9|x64.ActiveCfg = Verified|x64 @@ -889,6 +928,8 @@ Global {938C5808-85A1-4B5A-8CB4-D2D9D7851CB8}.Verified|x64.Build.0 = Verified|x64 {938C5808-85A1-4B5A-8CB4-D2D9D7851CB8}.VerifiedDX11|x64.ActiveCfg = Verified|x64 {938C5808-85A1-4B5A-8CB4-D2D9D7851CB8}.VerifiedDX11|x64.Build.0 = Verified|x64 + {938C5808-85A1-4B5A-8CB4-D2D9D7851CB8}.VerifiedDX11ASAN|x64.ActiveCfg = VerifiedDX11ASAN|x64 + {938C5808-85A1-4B5A-8CB4-D2D9D7851CB8}.VerifiedDX11ASAN|x64.Build.0 = VerifiedDX11ASAN|x64 {938C5808-85A1-4B5A-8CB4-D2D9D7851CB8}.VerifiedDX8|x64.ActiveCfg = Verified|x64 {938C5808-85A1-4B5A-8CB4-D2D9D7851CB8}.VerifiedDX8|x64.Build.0 = Verified|x64 {938C5808-85A1-4B5A-8CB4-D2D9D7851CB8}.VerifiedDX9|x64.ActiveCfg = Verified|x64 @@ -919,6 +960,8 @@ Global {893887A1-3ABF-40A0-B931-CD0867010785}.Verified|x64.Build.0 = Verified|x64 {893887A1-3ABF-40A0-B931-CD0867010785}.VerifiedDX11|x64.ActiveCfg = Verified|x64 {893887A1-3ABF-40A0-B931-CD0867010785}.VerifiedDX11|x64.Build.0 = Verified|x64 + {893887A1-3ABF-40A0-B931-CD0867010785}.VerifiedDX11ASAN|x64.ActiveCfg = VerifiedDX11ASAN|x64 + {893887A1-3ABF-40A0-B931-CD0867010785}.VerifiedDX11ASAN|x64.Build.0 = VerifiedDX11ASAN|x64 {893887A1-3ABF-40A0-B931-CD0867010785}.VerifiedDX8|x64.ActiveCfg = Verified|x64 {893887A1-3ABF-40A0-B931-CD0867010785}.VerifiedDX8|x64.Build.0 = Verified|x64 {893887A1-3ABF-40A0-B931-CD0867010785}.VerifiedDX9|x64.ActiveCfg = Verified|x64 @@ -949,6 +992,8 @@ Global {0BDF3377-F84E-4B42-A605-B45AAA244CB6}.Verified|x64.Build.0 = Verified|x64 {0BDF3377-F84E-4B42-A605-B45AAA244CB6}.VerifiedDX11|x64.ActiveCfg = Verified|x64 {0BDF3377-F84E-4B42-A605-B45AAA244CB6}.VerifiedDX11|x64.Build.0 = Verified|x64 + {0BDF3377-F84E-4B42-A605-B45AAA244CB6}.VerifiedDX11ASAN|x64.ActiveCfg = VerifiedDX11ASAN|x64 + {0BDF3377-F84E-4B42-A605-B45AAA244CB6}.VerifiedDX11ASAN|x64.Build.0 = VerifiedDX11ASAN|x64 {0BDF3377-F84E-4B42-A605-B45AAA244CB6}.VerifiedDX8|x64.ActiveCfg = Verified|x64 {0BDF3377-F84E-4B42-A605-B45AAA244CB6}.VerifiedDX8|x64.Build.0 = Verified|x64 {0BDF3377-F84E-4B42-A605-B45AAA244CB6}.VerifiedDX9|x64.ActiveCfg = Verified|x64 @@ -979,6 +1024,8 @@ Global {3A214E06-B95E-4D61-A291-1F8DF2EC10FD}.Verified|x64.Build.0 = Verified|x64 {3A214E06-B95E-4D61-A291-1F8DF2EC10FD}.VerifiedDX11|x64.ActiveCfg = Verified|x64 {3A214E06-B95E-4D61-A291-1F8DF2EC10FD}.VerifiedDX11|x64.Build.0 = Verified|x64 + {3A214E06-B95E-4D61-A291-1F8DF2EC10FD}.VerifiedDX11ASAN|x64.ActiveCfg = VerifiedDX11ASAN|x64 + {3A214E06-B95E-4D61-A291-1F8DF2EC10FD}.VerifiedDX11ASAN|x64.Build.0 = VerifiedDX11ASAN|x64 {3A214E06-B95E-4D61-A291-1F8DF2EC10FD}.VerifiedDX8|x64.ActiveCfg = Verified|x64 {3A214E06-B95E-4D61-A291-1F8DF2EC10FD}.VerifiedDX8|x64.Build.0 = Verified|x64 {3A214E06-B95E-4D61-A291-1F8DF2EC10FD}.VerifiedDX9|x64.ActiveCfg = Verified|x64 @@ -1009,6 +1056,8 @@ Global {CEBDE98B-A6AA-46E6-BC79-FAAF823DB9EC}.Verified|x64.Build.0 = Verified|x64 {CEBDE98B-A6AA-46E6-BC79-FAAF823DB9EC}.VerifiedDX11|x64.ActiveCfg = Verified|x64 {CEBDE98B-A6AA-46E6-BC79-FAAF823DB9EC}.VerifiedDX11|x64.Build.0 = Verified|x64 + {CEBDE98B-A6AA-46E6-BC79-FAAF823DB9EC}.VerifiedDX11ASAN|x64.ActiveCfg = VerifiedDX11ASAN|x64 + {CEBDE98B-A6AA-46E6-BC79-FAAF823DB9EC}.VerifiedDX11ASAN|x64.Build.0 = VerifiedDX11ASAN|x64 {CEBDE98B-A6AA-46E6-BC79-FAAF823DB9EC}.VerifiedDX8|x64.ActiveCfg = Verified|x64 {CEBDE98B-A6AA-46E6-BC79-FAAF823DB9EC}.VerifiedDX8|x64.Build.0 = Verified|x64 {CEBDE98B-A6AA-46E6-BC79-FAAF823DB9EC}.VerifiedDX9|x64.ActiveCfg = Verified|x64 @@ -1039,6 +1088,8 @@ Global {632AEEB6-DC06-4E15-9551-B2B09A4B73C5}.Verified|x64.Build.0 = Verified|x64 {632AEEB6-DC06-4E15-9551-B2B09A4B73C5}.VerifiedDX11|x64.ActiveCfg = Verified|x64 {632AEEB6-DC06-4E15-9551-B2B09A4B73C5}.VerifiedDX11|x64.Build.0 = Verified|x64 + {632AEEB6-DC06-4E15-9551-B2B09A4B73C5}.VerifiedDX11ASAN|x64.ActiveCfg = VerifiedDX11ASAN|x64 + {632AEEB6-DC06-4E15-9551-B2B09A4B73C5}.VerifiedDX11ASAN|x64.Build.0 = VerifiedDX11ASAN|x64 {632AEEB6-DC06-4E15-9551-B2B09A4B73C5}.VerifiedDX8|x64.ActiveCfg = Verified|x64 {632AEEB6-DC06-4E15-9551-B2B09A4B73C5}.VerifiedDX8|x64.Build.0 = Verified|x64 {632AEEB6-DC06-4E15-9551-B2B09A4B73C5}.VerifiedDX9|x64.ActiveCfg = Verified|x64 @@ -1069,6 +1120,8 @@ Global {772FE450-F4F3-4687-A2A7-5624825089D7}.Verified|x64.Build.0 = Verified|x64 {772FE450-F4F3-4687-A2A7-5624825089D7}.VerifiedDX11|x64.ActiveCfg = Verified|x64 {772FE450-F4F3-4687-A2A7-5624825089D7}.VerifiedDX11|x64.Build.0 = Verified|x64 + {772FE450-F4F3-4687-A2A7-5624825089D7}.VerifiedDX11ASAN|x64.ActiveCfg = VerifiedDX11ASAN|x64 + {772FE450-F4F3-4687-A2A7-5624825089D7}.VerifiedDX11ASAN|x64.Build.0 = VerifiedDX11ASAN|x64 {772FE450-F4F3-4687-A2A7-5624825089D7}.VerifiedDX8|x64.ActiveCfg = Verified|x64 {772FE450-F4F3-4687-A2A7-5624825089D7}.VerifiedDX8|x64.Build.0 = Verified|x64 {772FE450-F4F3-4687-A2A7-5624825089D7}.VerifiedDX9|x64.ActiveCfg = Verified|x64 @@ -1099,6 +1152,8 @@ Global {0EB257DC-5CFC-44B0-82C9-CE6B158BE473}.Verified|x64.Build.0 = Verified|x64 {0EB257DC-5CFC-44B0-82C9-CE6B158BE473}.VerifiedDX11|x64.ActiveCfg = Verified|x64 {0EB257DC-5CFC-44B0-82C9-CE6B158BE473}.VerifiedDX11|x64.Build.0 = Verified|x64 + {0EB257DC-5CFC-44B0-82C9-CE6B158BE473}.VerifiedDX11ASAN|x64.ActiveCfg = VerifiedDX11ASAN|x64 + {0EB257DC-5CFC-44B0-82C9-CE6B158BE473}.VerifiedDX11ASAN|x64.Build.0 = VerifiedDX11ASAN|x64 {0EB257DC-5CFC-44B0-82C9-CE6B158BE473}.VerifiedDX8|x64.ActiveCfg = Verified|x64 {0EB257DC-5CFC-44B0-82C9-CE6B158BE473}.VerifiedDX8|x64.Build.0 = Verified|x64 {0EB257DC-5CFC-44B0-82C9-CE6B158BE473}.VerifiedDX9|x64.ActiveCfg = Verified|x64 @@ -1129,6 +1184,8 @@ Global {9646DBF8-1A5E-41F0-9328-F65910706666}.Verified|x64.Build.0 = Verified|x64 {9646DBF8-1A5E-41F0-9328-F65910706666}.VerifiedDX11|x64.ActiveCfg = Verified|x64 {9646DBF8-1A5E-41F0-9328-F65910706666}.VerifiedDX11|x64.Build.0 = Verified|x64 + {9646DBF8-1A5E-41F0-9328-F65910706666}.VerifiedDX11ASAN|x64.ActiveCfg = VerifiedDX11ASAN|x64 + {9646DBF8-1A5E-41F0-9328-F65910706666}.VerifiedDX11ASAN|x64.Build.0 = VerifiedDX11ASAN|x64 {9646DBF8-1A5E-41F0-9328-F65910706666}.VerifiedDX8|x64.ActiveCfg = Verified|x64 {9646DBF8-1A5E-41F0-9328-F65910706666}.VerifiedDX8|x64.Build.0 = Verified|x64 {9646DBF8-1A5E-41F0-9328-F65910706666}.VerifiedDX9|x64.ActiveCfg = Verified|x64 @@ -1159,6 +1216,8 @@ Global {D0843040-7706-4FBF-A931-582748BAFBB1}.Verified|x64.Build.0 = Verified|x64 {D0843040-7706-4FBF-A931-582748BAFBB1}.VerifiedDX11|x64.ActiveCfg = Verified|x64 {D0843040-7706-4FBF-A931-582748BAFBB1}.VerifiedDX11|x64.Build.0 = Verified|x64 + {D0843040-7706-4FBF-A931-582748BAFBB1}.VerifiedDX11ASAN|x64.ActiveCfg = VerifiedDX11ASAN|x64 + {D0843040-7706-4FBF-A931-582748BAFBB1}.VerifiedDX11ASAN|x64.Build.0 = VerifiedDX11ASAN|x64 {D0843040-7706-4FBF-A931-582748BAFBB1}.VerifiedDX8|x64.ActiveCfg = Verified|x64 {D0843040-7706-4FBF-A931-582748BAFBB1}.VerifiedDX8|x64.Build.0 = Verified|x64 {D0843040-7706-4FBF-A931-582748BAFBB1}.VerifiedDX9|x64.ActiveCfg = Verified|x64 @@ -1189,6 +1248,8 @@ Global {4DDC8F7A-3B57-4250-9404-D2EE1991BE78}.Verified|x64.Build.0 = Verified|x64 {4DDC8F7A-3B57-4250-9404-D2EE1991BE78}.VerifiedDX11|x64.ActiveCfg = Verified|x64 {4DDC8F7A-3B57-4250-9404-D2EE1991BE78}.VerifiedDX11|x64.Build.0 = Verified|x64 + {4DDC8F7A-3B57-4250-9404-D2EE1991BE78}.VerifiedDX11ASAN|x64.ActiveCfg = VerifiedDX11ASAN|x64 + {4DDC8F7A-3B57-4250-9404-D2EE1991BE78}.VerifiedDX11ASAN|x64.Build.0 = VerifiedDX11ASAN|x64 {4DDC8F7A-3B57-4250-9404-D2EE1991BE78}.VerifiedDX8|x64.ActiveCfg = Verified|x64 {4DDC8F7A-3B57-4250-9404-D2EE1991BE78}.VerifiedDX8|x64.Build.0 = Verified|x64 {4DDC8F7A-3B57-4250-9404-D2EE1991BE78}.VerifiedDX9|x64.ActiveCfg = Verified|x64 @@ -1219,6 +1280,8 @@ Global {10D13331-3282-43F9-BEA0-150D80388B52}.Verified|x64.Build.0 = Verified|x64 {10D13331-3282-43F9-BEA0-150D80388B52}.VerifiedDX11|x64.ActiveCfg = Verified|x64 {10D13331-3282-43F9-BEA0-150D80388B52}.VerifiedDX11|x64.Build.0 = Verified|x64 + {10D13331-3282-43F9-BEA0-150D80388B52}.VerifiedDX11ASAN|x64.ActiveCfg = VerifiedDX11ASAN|x64 + {10D13331-3282-43F9-BEA0-150D80388B52}.VerifiedDX11ASAN|x64.Build.0 = VerifiedDX11ASAN|x64 {10D13331-3282-43F9-BEA0-150D80388B52}.VerifiedDX8|x64.ActiveCfg = Verified|x64 {10D13331-3282-43F9-BEA0-150D80388B52}.VerifiedDX8|x64.Build.0 = Verified|x64 {10D13331-3282-43F9-BEA0-150D80388B52}.VerifiedDX9|x64.ActiveCfg = Verified|x64 @@ -1249,6 +1312,8 @@ Global {8FDD9DAC-8E9F-677E-C93A-81986A581F89}.Verified|x64.Build.0 = Verified|x64 {8FDD9DAC-8E9F-677E-C93A-81986A581F89}.VerifiedDX11|x64.ActiveCfg = Verified|x64 {8FDD9DAC-8E9F-677E-C93A-81986A581F89}.VerifiedDX11|x64.Build.0 = Verified|x64 + {8FDD9DAC-8E9F-677E-C93A-81986A581F89}.VerifiedDX11ASAN|x64.ActiveCfg = VerifiedDX11ASAN|x64 + {8FDD9DAC-8E9F-677E-C93A-81986A581F89}.VerifiedDX11ASAN|x64.Build.0 = VerifiedDX11ASAN|x64 {8FDD9DAC-8E9F-677E-C93A-81986A581F89}.VerifiedDX8|x64.ActiveCfg = Verified|x64 {8FDD9DAC-8E9F-677E-C93A-81986A581F89}.VerifiedDX8|x64.Build.0 = Verified|x64 {8FDD9DAC-8E9F-677E-C93A-81986A581F89}.VerifiedDX9|x64.ActiveCfg = Verified|x64 @@ -1283,6 +1348,8 @@ Global {DB4ECFCD-1F1F-4436-8A44-95FCC20C91E9}.VerifiedDX8|x64.Build.0 = Verified|x64 {DB4ECFCD-1F1F-4436-8A44-95FCC20C91E9}.VerifiedDX9|x64.ActiveCfg = Verified|x64 {DB4ECFCD-1F1F-4436-8A44-95FCC20C91E9}.VerifiedDX9|x64.Build.0 = Verified|x64 + {DB4ECFCD-1F1F-4436-8A44-95FCC20C91E9}.VerifiedDX11ASAN|x64.ActiveCfg = Verified|x64 + {DB4ECFCD-1F1F-4436-8A44-95FCC20C91E9}.VerifiedDX11ASAN|x64.Build.0 = Verified|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/src/xrCDB/Frustum.h b/src/xrCDB/Frustum.h index 177cade9f4..69ce8555de 100644 --- a/src/xrCDB/Frustum.h +++ b/src/xrCDB/Frustum.h @@ -1,18 +1,11 @@ // Frustum.h: interface for the CFrustum class. // ////////////////////////////////////////////////////////////////////// - -#if !defined(AFX_FRUSTUM_H__E66ED755_F741_49CF_8B2A_404CCF7067F2__INCLUDED_) -#define AFX_FRUSTUM_H__E66ED755_F741_49CF_8B2A_404CCF7067F2__INCLUDED_ +#pragma once #include "xrCDB.h" - -//#pragma once - #include "../xrcore/fixedvector.h" -#pragma pack(push,4) - enum EFC_Visible { fcvNone = 0, @@ -103,6 +96,3 @@ class XRCDB_API CFrustum return testPolyInside(src); } }; -#pragma pack(pop) - -#endif // !defined(AFX_FRUSTUM_H__E66ED755_F741_49CF_8B2A_404CCF7067F2__INCLUDED_) diff --git a/src/xrCDB/ISpatial.cpp b/src/xrCDB/ISpatial.cpp index 08bc7b93b7..21c14dfae9 100644 --- a/src/xrCDB/ISpatial.cpp +++ b/src/xrCDB/ISpatial.cpp @@ -10,6 +10,7 @@ ISpatial_DB* g_SpatialSpace = NULL; ISpatial_DB* g_SpatialSpacePhysic = NULL; +ISpatial_DB* g_SpatialSpaceLights = NULL; Fvector c_spatial_offset [8] = { @@ -23,9 +24,41 @@ Fvector c_spatial_offset [8] = {1, 1, 1} }; +CObject* ISpatial::dcast_CObject() +{ + return RawOwner ? RawOwner->dcast_CObject() : nullptr; +} + +IRender_Light* ISpatial::dcast_Light() +{ + return RawOwner ? RawOwner->dcast_Light() : nullptr; +} + +Feel::Sound* ISpatial::dcast_FeelSound() +{ + return RawOwner ? RawOwner->dcast_FeelSound() : nullptr; +} + +IRenderable* ISpatial::dcast_Renderable() +{ + return RawOwner ? RawOwner->dcast_Renderable() : nullptr; +} + +CPHObject* ISpatial::dcast_CPHObject() +{ + return RawOwner ? RawOwner->dcast_CPHObject() : nullptr; +} + +CGlow* ISpatial::dcast_CGlow() +{ + return RawOwner ? RawOwner->dcast_CGlow() : nullptr; +} + ////////////////////////////////////////////////////////////////////////// -ISpatial::ISpatial(ISpatial_DB* space) +ISpatial::ISpatial(ISpatial_DB* space, ISpatialOwner* Owner) { + RawOwner = Owner; + spatial.sphere.P.set(0, 0, 0); spatial.sphere.R = 0; spatial.node_center.set(0, 0, 0); @@ -37,7 +70,7 @@ ISpatial::ISpatial(ISpatial_DB* space) ISpatial::~ISpatial(void) { - spatial_unregister(); + Unregister(); } BOOL ISpatial::spatial_inside() @@ -52,7 +85,7 @@ BOOL ISpatial::spatial_inside() return TRUE; } -BOOL verify_sp(ISpatial* sp, Fvector& node_center, float node_radius) +BOOL verify_sp(ISpatialShared sp, Fvector& node_center, float node_radius) { float dr = -(- node_radius + sp->spatial.sphere.R); if (sp->spatial.sphere.P.x < node_center.x - dr) return FALSE; @@ -64,30 +97,34 @@ BOOL verify_sp(ISpatial* sp, Fvector& node_center, float node_radius) return TRUE; } -void ISpatial::spatial_register() +void ISpatial::Register() { - spatial.type |= STYPEFLAG_INVALIDSECTOR; if (spatial.node_ptr) { // already registered - nothing to do } - else + else { // register R_ASSERT(spatial.space); + xrSRWLockGuard guard(&spatial.space->db_lock, false); spatial.space->insert(this); spatial.sector = 0; } } -void ISpatial::spatial_unregister() +void ISpatial::Unregister() { if (spatial.node_ptr) { // remove - spatial.space->remove(this); - spatial.node_ptr = NULL; - spatial.sector = NULL; + xrSRWLockGuard guard(&spatial.space->db_lock, false); + if (spatial.node_ptr) + { + spatial.space->remove(this); + spatial.node_ptr = nullptr; + spatial.sector = nullptr; + } } else { @@ -95,21 +132,20 @@ void ISpatial::spatial_unregister() } } -void ISpatial::spatial_move() +void ISpatial::Move() { if (spatial.node_ptr) { - float spatial_sector_threshold_sqr = 1.0f; - float spatial_distance_sqr = last_sector_point.distance_to_sqr(spatial_sector_point()); - - //*** somehow it was determined that object has been moved - if (spatial_distance_sqr > spatial_sector_threshold_sqr) - spatial.type |= STYPEFLAG_INVALIDSECTOR; - - //*** check if we are supposed to correct it's spatial location - if (spatial_inside()) return; // ??? - spatial.space->remove(this); - spatial.space->insert(this); + xrSRWLockGuard guard(&spatial.space->db_lock, false); + if (spatial.node_ptr) + { + //*** check if we are supposed to correct it's spatial location + if (spatial_inside()) + return; // ??? + + spatial.space->remove(this); + spatial.space->insert(this); + } } else { @@ -118,12 +154,46 @@ void ISpatial::spatial_move() } } -void ISpatial::spatial_updatesector_internal() +Fvector ISpatial::SectorPoint() +{ + return spatial.sphere.P; +} + +Fvector ISpatial::OwnerSectorPoint() +{ + Fvector result = spatial.sphere.P; + ISpatialOwner* owner = RawOwner; + if (owner) + { + ISpatialShared ptr = owner->SpatialComponent; + result = owner->spatial_sector_point(); + } + + // Validate that position contains no NaN or infinity values + if (!_finite(result.x) || !_finite(result.y) || !_finite(result.z)) + { +#ifdef DEBUG + VERIFY(!"Invalid spatial position detected - NaN or infinity in sector point"); +#endif + // Fallback to last valid position + return spatial.last_sector_point; + } + + return result; +} + +void ISpatial::spatial_updatesector() { - last_sector_point = spatial_sector_point(); - IRender_Sector* S = ::Render->detectSector(last_sector_point); - spatial.type &= ~STYPEFLAG_INVALIDSECTOR; - if (S) spatial.sector = S; + Fvector curr_sector_point = OwnerSectorPoint(); + + if ((FALSE == curr_sector_point.similar(spatial.last_sector_point) || spatial.sector == nullptr)) + { + PROF_EVENT("spatial_updatesector"); + if (IRender_Sector* S = ::Render->detectSector(curr_sector_point)) + spatial.sector = S; + } + + spatial.last_sector_point = curr_sector_point; } ////////////////////////////////////////////////////////////////////////// @@ -135,19 +205,19 @@ void ISpatial_NODE::_init(ISpatial_NODE* _parent) items.clear(); } -void ISpatial_NODE::_insert(ISpatial* S) +void ISpatial_NODE::_insert(ISpatialShared S) { S->spatial.node_ptr = this; items.push_back(S); S->spatial.space->stat_objects ++; } -void ISpatial_NODE::_remove(ISpatial* S) +void ISpatial_NODE::_remove(ISpatialShared S) { - S->spatial.node_ptr = NULL; - xr_vector::iterator it = std::find(items.begin(), items.end(), S); + S->spatial.node_ptr = nullptr; + auto it = std::find(items.begin(),items.end(),S); VERIFY(it!=items.end()); - items.erase(it); + items.erase_fast(it); S->spatial.space->stat_objects --; } @@ -160,7 +230,6 @@ ISpatial_DB::ISpatial_DB() { rt_insert_object = NULL; m_bounds = NULL; - q_result = NULL; m_root = NULL; stat_nodes = 0; stat_objects = 0; @@ -173,10 +242,9 @@ ISpatial_DB::~ISpatial_DB() _node_destroy(m_root); } - while (!allocator_pool.empty()) + while (!nodes.empty()) { - allocator.destroy(allocator_pool.back()); - allocator_pool.pop_back(); + nodes.pop_back(); } } @@ -191,7 +259,7 @@ void ISpatial_DB::initialize(Fbox& BB) bbc.set(0, 0, 0); // generic bbd.set(1024, 1024, 1024); // generic - allocator_pool.reserve(128); + nodes.reserve(512); m_center.set(bbc); m_bounds = _max(_max(bbd.x, bbd.y), bbd.z); rt_insert_object = NULL; @@ -202,22 +270,19 @@ void ISpatial_DB::initialize(Fbox& BB) ISpatial_NODE* ISpatial_DB::_node_create() { - stat_nodes ++; - if (allocator_pool.empty()) return allocator.create(); - else - { - ISpatial_NODE* N = allocator_pool.back(); - allocator_pool.pop_back(); - return N; - } + stat_nodes++; + return nodes.emplace_back(xr_new()); } -void ISpatial_DB::_node_destroy(ISpatial_NODE* & P) +void ISpatial_DB::_node_destroy(ISpatial_NODE* &P) { - VERIFY(P->_empty()); - stat_nodes --; - allocator_pool.push_back(P); - P = NULL; + //VERIFY (P->_empty()); + stat_nodes--; + auto it = std::find(nodes.begin(), nodes.end(), P); + if (it != nodes.end()) + nodes.erase(it); + + xr_delete(P); } void ISpatial_DB::_insert(ISpatial_NODE* N, Fvector& n_C, float n_R) @@ -270,26 +335,9 @@ void ISpatial_DB::_insert(ISpatial_NODE* N, Fvector& n_C, float n_R) } } -void ISpatial_DB::insert(ISpatial* S) +void ISpatial_DB::insert(ISpatialShared S) { - cs.Enter(); -#ifdef DEBUG - stat_insert.Begin (); - - BOOL bValid = _valid(S->spatial.sphere.R) && _valid(S->spatial.sphere.P); - if (!bValid) - { - CObject* O = fast_dynamic_cast(S); - if (O) Debug.fatal(DEBUG_INFO, "Invalid OBJECT position or radius (%s)", O->cName().c_str()); - else { - CPS_Instance* P = fast_dynamic_cast(S); - if (P) Debug.fatal(DEBUG_INFO,"Invalid PS spatial position{%3.2f,%3.2f,%3.2f} or radius{%3.2f}",VPUSH(S->spatial.sphere.P),S->spatial.sphere.R); - else Debug.fatal(DEBUG_INFO,"Invalid OTHER spatial position{%3.2f,%3.2f,%3.2f} or radius{%3.2f}",VPUSH(S->spatial.sphere.P),S->spatial.sphere.R); - } - } -#endif - - if (verify_sp(S, m_center, m_bounds)) + if (m_root && verify_sp(S, m_center, m_bounds)) { // Object inside our DB rt_insert_object = S; @@ -300,14 +348,16 @@ void ISpatial_DB::insert(ISpatial* S) { // Object outside our DB, put it into root node and hack bounds // Object will reinsert itself until fits into "real", "controlled" space - m_root->_insert(S); - S->spatial.node_center.set(m_center); - S->spatial.node_radius = m_bounds; + if (m_root) + { + m_root->_insert(S); + S->spatial.node_center.set(m_center); + S->spatial.node_radius = m_bounds; + } } #ifdef DEBUG stat_insert.End (); #endif - cs.Leave(); } void ISpatial_DB::_remove(ISpatial_NODE* N, ISpatial_NODE* N_sub) @@ -332,9 +382,8 @@ void ISpatial_DB::_remove(ISpatial_NODE* N, ISpatial_NODE* N_sub) if (N->_empty()) _remove(N->parent, N); } -void ISpatial_DB::remove(ISpatial* S) +void ISpatial_DB::remove(ISpatialShared S) { - cs.Enter(); #ifdef DEBUG stat_remove.Begin (); #endif @@ -347,15 +396,13 @@ void ISpatial_DB::remove(ISpatial* S) #ifdef DEBUG stat_remove.End (); #endif - cs.Leave(); } -void ISpatial_DB::update(u32 nodes/* =8 */) +void ISpatial_DB::update(u32) { #ifdef DEBUG - if (0==m_root) return; - cs.Enter (); - VERIFY (verify()); - cs.Leave (); + if (0 == m_root) + return; + VERIFY(verify()); #endif } diff --git a/src/xrCDB/ISpatial.h b/src/xrCDB/ISpatial.h index f6153a4d73..9a48d80626 100644 --- a/src/xrCDB/ISpatial.h +++ b/src/xrCDB/ISpatial.h @@ -1,12 +1,10 @@ -#ifndef XRENGINE_ISPATIAL_H_INCLUDED -#define XRENGINE_ISPATIAL_H_INCLUDED +#pragma once -//#pragma once +#include #include "../xrCore/xrPool.h" #include "xr_collide_defs.h" - -#pragma pack(push,4) +#include "../xrCore/intrusive_ptr.h" /* Requirements: @@ -26,6 +24,7 @@ * Should have at least "bounding-sphere" or "bounding-box" */ + const float c_spatial_min = 8.f; ////////////////////////////////////////////////////////////////////////// @@ -40,11 +39,12 @@ enum STYPE_OBSTACLE = (1 << 6), STYPE_SHAPE = (1 << 7), STYPE_LIGHTSOURCEHEMI = (1 << 8), + STYPE_RENDERABLESHADOW = (1 << 9), + STYPE_PARTICLE = (1 << 10), #ifdef SPATIAL_CHANGE - STYPE_FEELVISIONIGNORE = (1 << 9), + STYPE_FEELVISIONIGNORE = (1 << 11), #endif - - STYPEFLAG_INVALIDSECTOR = (1 << 16) + STYPE_GLOW = (1 << 12) }; ////////////////////////////////////////////////////////////////////////// @@ -69,6 +69,12 @@ enum // //namespace Feel { class Sound; } +class CPHObject; +class CGlow; + +#include +class ISpatialOwner; + ////////////////////////////////////////////////////////////////////////// class ISpatial_NODE; class IRender_Sector; @@ -82,67 +88,109 @@ namespace Feel class IRenderable; class IRender_Light; -class XRCDB_API ISpatial +class XRCDB_API ISpatial: + public intrusive_base_strict { -private: - Fvector last_sector_point; + friend class ISpatialOwner; public: - struct _spatial + struct SpatialData { - u32 type; - Fsphere sphere; - Fvector node_center; // Cached node center for TBV optimization - float node_radius; // Cached node bounds for TBV optimization - ISpatial_NODE* node_ptr; // Cached parent node for "empty-members" optimization - IRender_Sector* sector; - ISpatial_DB* space; // allow different spaces - - _spatial() : type(0) - { - } // safe way to enhure type is zero before any contstructors takes place - } spatial; + u32 type = 0; + Fsphere sphere = {}; + + // Cached node center for TBV optimization + Fvector node_center = {}; + Fvector last_sector_point = {0.f,0.f,0.f}; + // Cached node bounds for TBV optimization + float node_radius=EPS; + + // Cached parent node for "empty-members" optimization + ISpatial_NODE* node_ptr = nullptr; + IRender_Sector* sector = nullptr; + + // allow different spaces + ISpatial_DB* space = nullptr; + }; + + SpatialData spatial; + +private: + ISpatialOwner* RawOwner = nullptr; public: - BOOL spatial_inside(); - void spatial_updatesector_internal(); + BOOL spatial_inside () ; + +private: + void Register(); + void Unregister(); + + void Move(); + Fvector SectorPoint(); + public: - virtual void spatial_register(); - virtual void spatial_unregister(); - BENCH_SEC_SCRAMBLEVTBL2 - virtual void spatial_move(); - virtual Fvector spatial_sector_point() { return spatial.sphere.P; } - ICF void spatial_updatesector() - { - if (0 == (spatial.type & STYPEFLAG_INVALIDSECTOR)) return; - spatial_updatesector_internal(); - }; + Fvector OwnerSectorPoint(); + void OwnerReset(ISpatialOwner* ptr) { RawOwner = ptr; }; + + void spatial_updatesector(); - virtual CObject* dcast_CObject() { return 0; } - virtual Feel::Sound* dcast_FeelSound() { return 0; } - virtual IRenderable* dcast_Renderable() { return 0; } - virtual IRender_Light* dcast_Light() { return 0; } + CObject* dcast_CObject (); + Feel::Sound* dcast_FeelSound (); + IRenderable* dcast_Renderable (); + IRender_Light* dcast_Light (); + CPHObject* dcast_CPHObject (); + CGlow* dcast_CGlow (); // demonized: Check if eligible for bone calc optimizations - virtual bool canOptimizeCalculateBones() { return true; } + bool canOptimizeCalculateBones = true; - ISpatial(ISpatial_DB* space); + ISpatial(ISpatial_DB* space, ISpatialOwner* TypeObject); +protected: virtual ~ISpatial(); }; +using ISpatialShared = intrusive_ptr; + +class ISpatialOwner +{ +public: + ISpatialShared SpatialComponent; + +public: + virtual void spatial_create(ISpatial_DB* db, ISpatialOwner* owner, u32 type) { SpatialComponent = xr_new(db, owner); SpatialComponent->spatial.type = type; } + virtual void spatial_register() { SpatialComponent->Register(); }; + virtual void spatial_unregister() { SpatialComponent->Unregister(); }; + + virtual void spatial_move() { SpatialComponent->Move(); }; + virtual Fvector spatial_sector_point() { return SpatialComponent->SectorPoint(); } + + + virtual CObject* dcast_CObject () { return nullptr; }; + virtual Feel::Sound* dcast_FeelSound () { return nullptr; }; + virtual IRenderable* dcast_Renderable () { return nullptr; }; + virtual IRender_Light* dcast_Light () { return nullptr; }; + virtual CPHObject* dcast_CPHObject () { return nullptr; }; + virtual CGlow* dcast_CGlow () { return nullptr; }; + + virtual ~ISpatialOwner() { SpatialComponent->OwnerReset(nullptr); } +}; + ////////////////////////////////////////////////////////////////////////// //class ISpatial_NODE; class ISpatial_NODE { public: - typedef __w64 unsigned ptrt; + using ptrt = ptrdiff_t; public: - ISpatial_NODE* parent; // parent node for "empty-members" optimization - ISpatial_NODE* children [8]; // children nodes - xr_vector items; // own items + // parent node for "empty-members" optimization + ISpatial_NODE* parent; + // children nodes + ISpatial_NODE* children[8]; + // own items + xr_vector items; public: - void _init(ISpatial_NODE* _parent); - void _remove(ISpatial* _S); - void _insert(ISpatial* _S); + void _init (ISpatial_NODE* _parent); + void _remove (ISpatialShared _S); + void _insert (ISpatialShared _S); BOOL _empty() { @@ -170,17 +218,13 @@ class ISpatial_NODE class XRCDB_API ISpatial_DB { private: - xrCriticalSection cs; - - poolSS allocator; - - xr_vector allocator_pool; - ISpatial* rt_insert_object; + xr_vector nodes; + ISpatialShared rt_insert_object; public: + xrSRWLock db_lock; ISpatial_NODE* m_root; Fvector m_center; float m_bounds; - xr_vector* q_result; u32 stat_nodes; u32 stat_objects; CStatTimer stat_insert; @@ -208,8 +252,8 @@ class XRCDB_API ISpatial_DB // managing void initialize(Fbox& BB); //void destroy (); - void insert(ISpatial* S); - void remove(ISpatial* S); + void insert (ISpatialShared S); + void remove (ISpatialShared S); void update(u32 nodes = 8); BOOL verify(); @@ -223,16 +267,12 @@ class XRCDB_API ISpatial_DB }; // query - void q_ray(xr_vector& R, u32 _o, u32 _mask_and, const Fvector& _start, const Fvector& _dir, - float _range); - void q_box(xr_vector& R, u32 _o, u32 _mask_or, const Fvector& _center, const Fvector& _size); - void q_sphere(xr_vector& R, u32 _o, u32 _mask_or, const Fvector& _center, const float _radius); - void q_frustum(xr_vector& R, u32 _o, u32 _mask_or, const CFrustum& _frustum); + void q_ray (xr_vector& R, u32 _o, u32 _mask_and, const Fvector& _start, const Fvector& _dir, float _range); + void q_box (xr_vector& R, u32 _o, u32 _mask_or, const Fvector& _center, const Fvector& _size); + void q_sphere (xr_vector& R, u32 _o, u32 _mask_or, const Fvector& _center, const float _radius); + void q_frustum (xr_vector& R, u32 _o, u32 _mask_or, const CFrustum& _frustum); }; XRCDB_API extern ISpatial_DB* g_SpatialSpace; XRCDB_API extern ISpatial_DB* g_SpatialSpacePhysic; - -#pragma pack(pop) - -#endif // #ifndef XRENGINE_ISPATIAL_H_INCLUDED +XRCDB_API extern ISpatial_DB* g_SpatialSpaceLights; diff --git a/src/xrCDB/ISpatial_q_box.cpp b/src/xrCDB/ISpatial_q_box.cpp index ec5b07d391..2018b69a06 100644 --- a/src/xrCDB/ISpatial_q_box.cpp +++ b/src/xrCDB/ISpatial_q_box.cpp @@ -3,8 +3,7 @@ extern Fvector c_spatial_offset[8]; -template -class walker +class _MM_ALIGN16 spatial_box_walker { public: u32 mask; @@ -12,8 +11,10 @@ class walker Fvector size; Fbox box; ISpatial_DB* space; + + bool bFirst = false; public: - walker(ISpatial_DB* _space, u32 _mask, const Fvector& _center, const Fvector& _size) + spatial_box_walker(ISpatial_DB* _space, u32 _mask, const Fvector& _center, const Fvector& _size) { mask = _mask; center = _center; @@ -22,21 +23,21 @@ class walker space = _space; } - void walk(ISpatial_NODE* N, Fvector& n_C, float n_R) + void walk(xr_vector& R, ISpatial_NODE* N, Fvector& n_C, float n_R) { // box float n_vR = 2 * n_R; Fbox BB; BB.set(n_C.x - n_vR, n_C.y - n_vR, n_C.z - n_vR, n_C.x + n_vR, n_C.y + n_vR, n_C.z + n_vR); - if (!BB.intersect(box)) return; + if (!BB.intersect(box)) + return; // test items - xr_vector::iterator _it = N->items.begin(); - xr_vector::iterator _end = N->items.end(); - for (; _it != _end; _it++) + for (ISpatialShared S : N->items) { - ISpatial* S = *_it; - if (0 == (S->spatial.type & mask)) continue; + if (!S.get()) continue; + if (0 == (S->spatial.type & mask)) + continue; Fvector& sC = S->spatial.sphere.P; float sR = S->spatial.sphere.R; @@ -44,8 +45,8 @@ class walker sB.set(sC.x - sR, sC.y - sR, sC.z - sR, sC.x + sR, sC.y + sR, sC.z + sR); if (!sB.intersect(box)) continue; - space->q_result->push_back(S); - if (b_first) return; + R.push_back(S); + if (bFirst) return; } // recurse @@ -55,31 +56,27 @@ class walker if (0 == N->children[octant]) continue; Fvector c_C; c_C.mad(n_C, c_spatial_offset[octant], c_R); - walk(N->children[octant], c_C, c_R); - if (b_first && !space->q_result->empty()) return; + walk(R, N->children[octant], c_C, c_R); + if (bFirst && !R.empty()) return; } } }; -void ISpatial_DB::q_box(xr_vector& R, u32 _o, u32 _mask, const Fvector& _center, const Fvector& _size) +void ISpatial_DB::q_box(xr_vector& R, u32 _o, u32 _mask, const Fvector& _center, const Fvector& _size) { - cs.Enter(); - q_result = &R; - q_result->clear_not_free(); - if (_o & O_ONLYFIRST) - { - walker W(this, _mask, _center, _size); - W.walk(m_root, m_center, m_bounds); - } - else - { - walker W(this, _mask, _center, _size); - W.walk(m_root, m_center, m_bounds); - } - cs.Leave(); + PROF_EVENT(); + xrSRWLockGuard guard(&db_lock, true); + if (!m_root) + return; + + R.clear(); + + spatial_box_walker W(this, _mask, _center, _size); + W.bFirst = !!(_o&O_ONLYFIRST); + W.walk(R, m_root, m_center, m_bounds); } -void ISpatial_DB::q_sphere(xr_vector& R, u32 _o, u32 _mask, const Fvector& _center, const float _radius) +void ISpatial_DB::q_sphere(xr_vector& R, u32 _o, u32 _mask, const Fvector& _center, const float _radius) { Fvector _size = {_radius, _radius, _radius}; q_box(R, _o, _mask, _center, _size); diff --git a/src/xrCDB/ISpatial_q_frustum.cpp b/src/xrCDB/ISpatial_q_frustum.cpp index 5b1b3e8c99..4f94a27997 100644 --- a/src/xrCDB/ISpatial_q_frustum.cpp +++ b/src/xrCDB/ISpatial_q_frustum.cpp @@ -4,62 +4,70 @@ extern Fvector c_spatial_offset[8]; -class walker +class _MM_ALIGN16 spatial_frustum_walker { public: u32 mask; CFrustum* F; ISpatial_DB* space; + Fbox BB; + public: - walker(ISpatial_DB* _space, u32 _mask, const CFrustum* _F) + spatial_frustum_walker(ISpatial_DB* _space, u32 _mask, const CFrustum* _F) { mask = _mask; F = (CFrustum*)_F; space = _space; } - void walk(ISpatial_NODE* N, Fvector& n_C, float n_R, u32 fmask) + void walk(xr_vector& R, ISpatial_NODE* N, Fvector& n_C, float n_R, u32 fmask) { // box float n_vR = 2 * n_R; - Fbox BB; BB.set(n_C.x - n_vR, n_C.y - n_vR, n_C.z - n_vR, n_C.x + n_vR, n_C.y + n_vR, n_C.z + n_vR); - if (fcvNone == F->testAABB(BB.data(), fmask)) return; + + if (fcvNone == F->testAABB(BB.data(), fmask)) + return; // test items - xr_vector::iterator _it = N->items.begin(); - xr_vector::iterator _end = N->items.end(); - for (; _it != _end; _it++) + for (ISpatialShared S : N->items) { - ISpatial* S = *_it; - if (0 == (S->spatial.type & mask)) continue; + if (!S.get()) continue; + if (0 == (S->spatial.type & mask)) + continue; Fvector& sC = S->spatial.sphere.P; float sR = S->spatial.sphere.R; u32 tmask = fmask; - if (fcvNone == F->testSphere(sC, sR, tmask)) continue; - space->q_result->push_back(S); + if (fcvNone == F->testSphere(sC, sR, tmask)) + continue; + + R.push_back(S); } // recurse float c_R = n_R / 2; for (u32 octant = 0; octant < 8; octant++) { - if (0 == N->children[octant]) continue; + if (0 == N->children[octant]) + continue; + Fvector c_C; c_C.mad(n_C, c_spatial_offset[octant], c_R); - walk(N->children[octant], c_C, c_R, fmask); + walk(R, N->children[octant], c_C, c_R, fmask); } } }; -void ISpatial_DB::q_frustum(xr_vector& R, u32 _o, u32 _mask, const CFrustum& _frustum) +void ISpatial_DB::q_frustum(xr_vector& R, u32 _o, u32 _mask, const CFrustum& _frustum) { - cs.Enter(); - q_result = &R; - q_result->clear_not_free(); - walker W(this, _mask, &_frustum); - W.walk(m_root, m_center, m_bounds, _frustum.getMask()); - cs.Leave(); + PROF_EVENT("ISpatial_DB::q_frustum"); + xrSRWLockGuard guard(&db_lock, true); + if (!m_root) + return; + + R.clear(); + spatial_frustum_walker W(this,_mask,&_frustum); + W.walk(R,m_root,m_center,m_bounds,_frustum.getMask()); } diff --git a/src/xrCDB/ISpatial_q_ray.cpp b/src/xrCDB/ISpatial_q_ray.cpp index 8e6ac897bc..475a53cadb 100644 --- a/src/xrCDB/ISpatial_q_ray.cpp +++ b/src/xrCDB/ISpatial_q_ray.cpp @@ -1,208 +1,11 @@ -#include "stdafx.h" +#include "StdAfx.h" #include "ISpatial.h" -#pragma warning(push) -#pragma warning(disable:4995) -#include -#pragma warning(pop) -// can you say "barebone"? -#ifndef _MM_ALIGN16 -# define _MM_ALIGN16 __declspec(align(16)) -#endif // _MM_ALIGN16 - -struct _MM_ALIGN16 vec_t : public Fvector3 -{ - float pad; -}; - -//static vec_t vec_c ( float _x, float _y, float _z) { vec_t v; v.x=_x;v.y=_y;v.z=_z;v.pad=0; return v; } - -struct _MM_ALIGN16 aabb_t -{ - vec_t min; - vec_t max; -}; - -struct _MM_ALIGN16 ray_t -{ - vec_t pos; - vec_t inv_dir; - vec_t fwd_dir; -}; - -struct ray_segment_t -{ - float t_near, t_far; -}; - -ICF u32& uf(float& x) { return (u32&)x; } -ICF BOOL isect_fpu(const Fvector& min, const Fvector& max, const ray_t& ray, Fvector& coord) -{ - Fvector MaxT; - MaxT.x = MaxT.y = MaxT.z = -1.0f; - BOOL Inside = TRUE; - - // Find candidate planes. - if (ray.pos[0] < min[0]) - { - coord[0] = min[0]; - Inside = FALSE; - if (uf(ray.inv_dir[0])) MaxT[0] = (min[0] - ray.pos[0]) * ray.inv_dir[0]; - // Calculate T distances to candidate planes - } - else if (ray.pos[0] > max[0]) - { - coord[0] = max[0]; - Inside = FALSE; - if (uf(ray.inv_dir[0])) MaxT[0] = (max[0] - ray.pos[0]) * ray.inv_dir[0]; - // Calculate T distances to candidate planes - } - if (ray.pos[1] < min[1]) - { - coord[1] = min[1]; - Inside = FALSE; - if (uf(ray.inv_dir[1])) MaxT[1] = (min[1] - ray.pos[1]) * ray.inv_dir[1]; - // Calculate T distances to candidate planes - } - else if (ray.pos[1] > max[1]) - { - coord[1] = max[1]; - Inside = FALSE; - if (uf(ray.inv_dir[1])) MaxT[1] = (max[1] - ray.pos[1]) * ray.inv_dir[1]; - // Calculate T distances to candidate planes - } - if (ray.pos[2] < min[2]) - { - coord[2] = min[2]; - Inside = FALSE; - if (uf(ray.inv_dir[2])) MaxT[2] = (min[2] - ray.pos[2]) * ray.inv_dir[2]; - // Calculate T distances to candidate planes - } - else if (ray.pos[2] > max[2]) - { - coord[2] = max[2]; - Inside = FALSE; - if (uf(ray.inv_dir[2])) MaxT[2] = (max[2] - ray.pos[2]) * ray.inv_dir[2]; - // Calculate T distances to candidate planes - } - - // Ray ray.pos inside bounding box - if (Inside) - { - coord = ray.pos; - return true; - } - - // Get largest of the maxT's for final choice of intersection - u32 WhichPlane = 0; - if (MaxT[1] > MaxT[0]) WhichPlane = 1; - if (MaxT[2] > MaxT[WhichPlane]) WhichPlane = 2; - - // Check final candidate actually inside box (if max < 0) - if (uf(MaxT[WhichPlane]) & 0x80000000) return false; - - if (0 == WhichPlane) - { - // 1 & 2 - coord[1] = ray.pos[1] + MaxT[0] * ray.fwd_dir[1]; - if ((coord[1] < min[1]) || (coord[1] > max[1])) return false; - coord[2] = ray.pos[2] + MaxT[0] * ray.fwd_dir[2]; - if ((coord[2] < min[2]) || (coord[2] > max[2])) return false; - return true; - } - if (1 == WhichPlane) - { - // 0 & 2 - coord[0] = ray.pos[0] + MaxT[1] * ray.fwd_dir[0]; - if ((coord[0] < min[0]) || (coord[0] > max[0])) return false; - coord[2] = ray.pos[2] + MaxT[1] * ray.fwd_dir[2]; - if ((coord[2] < min[2]) || (coord[2] > max[2])) return false; - return true; - } - if (2 == WhichPlane) - { - // 0 & 1 - coord[0] = ray.pos[0] + MaxT[2] * ray.fwd_dir[0]; - if ((coord[0] < min[0]) || (coord[0] > max[0])) return false; - coord[1] = ray.pos[1] + MaxT[2] * ray.fwd_dir[1]; - if ((coord[1] < min[1]) || (coord[1] > max[1])) return false; - return true; - } - return false; -} - -// turn those verbose intrinsics into something readable. -#define loadps(mem) _mm_load_ps((const float * const)(mem)) -#define storess(ss,mem) _mm_store_ss((float * const)(mem),(ss)) -#define minss _mm_min_ss -#define maxss _mm_max_ss -#define minps _mm_min_ps -#define maxps _mm_max_ps -#define mulps _mm_mul_ps -#define subps _mm_sub_ps -#define rotatelps(ps) _mm_shuffle_ps((ps),(ps), 0x39) // a,b,c,d -> b,c,d,a -#define muxhps(low,high) _mm_movehl_ps((low),(high)) // low{a,b,c,d}|high{e,f,g,h} = {c,d,g,h} - - -static const float flt_plus_inf = -logf(0); // let's keep C and C++ compilers happy. -static const float _MM_ALIGN16 - ps_cst_plus_inf [4] = {flt_plus_inf, flt_plus_inf, flt_plus_inf, flt_plus_inf}, - ps_cst_minus_inf[4] = {-flt_plus_inf, -flt_plus_inf, -flt_plus_inf, -flt_plus_inf}; - -ICF BOOL isect_sse(const aabb_t& box, const ray_t& ray, float& dist) -{ - // you may already have those values hanging around somewhere - const __m128 - plus_inf = loadps(ps_cst_plus_inf), - minus_inf = loadps(ps_cst_minus_inf); - - // use whatever's apropriate to load. - const __m128 - box_min = loadps(&box.min), - box_max = loadps(&box.max), - pos = loadps(&ray.pos), - inv_dir = loadps(&ray.inv_dir); - - // use a div if inverted directions aren't available - const __m128 l1 = mulps(subps(box_min, pos), inv_dir); - const __m128 l2 = mulps(subps(box_max, pos), inv_dir); - - // the order we use for those min/max is vital to filter out - // NaNs that happens when an inv_dir is +/- inf and - // (box_min - pos) is 0. inf * 0 = NaN - const __m128 filtered_l1a = minps(l1, plus_inf); - const __m128 filtered_l2a = minps(l2, plus_inf); - - const __m128 filtered_l1b = maxps(l1, minus_inf); - const __m128 filtered_l2b = maxps(l2, minus_inf); - - // now that we're back on our feet, test those slabs. - __m128 lmax = maxps(filtered_l1a, filtered_l2a); - __m128 lmin = minps(filtered_l1b, filtered_l2b); - - // unfold back. try to hide the latency of the shufps & co. - const __m128 lmax0 = rotatelps(lmax); - const __m128 lmin0 = rotatelps(lmin); - lmax = minss(lmax, lmax0); - lmin = maxss(lmin, lmin0); - - const __m128 lmax1 = muxhps(lmax, lmax); - const __m128 lmin1 = muxhps(lmin, lmin); - lmax = minss(lmax, lmax1); - lmin = maxss(lmin, lmin1); - - const BOOL ret = _mm_comige_ss(lmax, _mm_setzero_ps()) & _mm_comige_ss(lmax, lmin); - - storess(lmin, &dist); - //storess (lmax, &rs.t_far); - - return ret; -} +#include "sse_intersect.h" extern Fvector c_spatial_offset[8]; -template -class _MM_ALIGN16 walker +class _MM_ALIGN16 spatial_ray_walker { public: ray_t ray; @@ -210,14 +13,21 @@ class _MM_ALIGN16 walker float range; float range2; ISpatial_DB* space; + + bool bSSE = false; + bool bFirst = false; + bool bNearest = false; public: - walker(ISpatial_DB* _space, u32 _mask, const Fvector& _start, const Fvector& _dir, float _range) + spatial_ray_walker(bool SSE, bool First, bool Nearest) + :bSSE(SSE), bFirst(First), bNearest(Nearest) {} + + void _init(ISpatial_DB* _space, u32 _mask, const Fvector& _start, const Fvector& _dir, float _range) { mask = _mask; ray.pos.set(_start); ray.inv_dir.set(1.f, 1.f, 1.f).div(_dir); ray.fwd_dir.set(_dir); - if (!b_use_sse) + if (!bSSE) { // for FPU - zero out inf if (_abs(_dir.x) > flt_eps) @@ -238,61 +48,28 @@ class _MM_ALIGN16 walker space = _space; } - // fpu - ICF BOOL _box_fpu(const Fvector& n_C, const float n_R, Fvector& coord) - { - // box - float n_vR = 2 * n_R; - Fbox BB; - BB.set(n_C.x - n_vR, n_C.y - n_vR, n_C.z - n_vR, n_C.x + n_vR, n_C.y + n_vR, n_C.z + n_vR); - return isect_fpu(BB.min, BB.max, ray, coord); - } - - // sse - ICF BOOL _box_sse(const Fvector& n_C, const float n_R, float& dist) - { - aabb_t box; - /* - float n_vR = 2*n_R; - box.min.set (n_C.x-n_vR, n_C.y-n_vR, n_C.z-n_vR); box.min.pad = 0; - box.max.set (n_C.x+n_vR, n_C.y+n_vR, n_C.z+n_vR); box.max.pad = 0; - */ - __m128 NR = _mm_load_ss((float*)&n_R); - __m128 NC = _mm_unpacklo_ps(_mm_load_ss((float*)&n_C.x), _mm_load_ss((float*)&n_C.y)); - NR = _mm_add_ss(NR, NR); - NC = _mm_movelh_ps(NC, _mm_load_ss((float*)&n_C.z)); - NR = _mm_shuffle_ps(NR, NR, _MM_SHUFFLE(1, 0, 0, 0)); - - _mm_store_ps((float*)&box.min, _mm_sub_ps(NC, NR)); - _mm_store_ps((float*)&box.max, _mm_add_ps(NC, NR)); - - return isect_sse(box, ray, dist); - } - - void walk(ISpatial_NODE* N, Fvector& n_C, float n_R) + void walk(xr_vector& R, ISpatial_NODE* N, Fvector& n_C, float n_R) { // Actual ray/aabb test - if (b_use_sse) + if (bSSE) { // use SSE float d; - if (!_box_sse(n_C, n_R, d)) return; + if (!_box_sse(ray, n_C, n_R, d)) return; if (d > range) return; } else { // use FPU Fvector P; - if (!_box_fpu(n_C, n_R, P)) return; + if (!_box_fpu(ray, n_C, n_R, P)) return; if (P.distance_to_sqr(ray.pos) > range2) return; } // test items - xr_vector::iterator _it = N->items.begin(); - xr_vector::iterator _end = N->items.end(); - for (; _it != _end; _it++) + for (ISpatialShared S : N->items) { - ISpatial* S = *_it; + if (!S.get()) continue; if (mask != (S->spatial.type & mask)) continue; Fsphere& sS = S->spatial.sphere; int quantity; @@ -301,7 +78,7 @@ class _MM_ALIGN16 walker if (result == Fsphere::rpOriginInside || ((result == Fsphere::rpOriginOutside) && (afT[0] < range))) { - if (b_nearest) + if (bNearest) { switch (result) { @@ -312,8 +89,8 @@ class _MM_ALIGN16 walker } range2 = range * range; } - space->q_result->push_back(S); - if (b_first) return; + R.push_back(S); + if (bFirst) return; } } @@ -324,75 +101,22 @@ class _MM_ALIGN16 walker if (0 == N->children[octant]) continue; Fvector c_C; c_C.mad(n_C, c_spatial_offset[octant], c_R); - walk(N->children[octant], c_C, c_R); - if (b_first && !space->q_result->empty()) return; + walk(R, N->children[octant], c_C, c_R); + if (bFirst && !R.empty()) return; } } }; -void ISpatial_DB::q_ray(xr_vector& R, u32 _o, u32 _mask_and, const Fvector& _start, const Fvector& _dir, - float _range) +void ISpatial_DB::q_ray(xr_vector& R, u32 _o, u32 _mask_and, const Fvector& _start, const Fvector& _dir, float _range) { - cs.Enter(); - q_result = &R; - q_result->clear_not_free(); - if (CPU::ID.feature & _CPU_FEATURE_SSE) - { - if (_o & O_ONLYFIRST) - { - if (_o & O_ONLYNEAREST) - { - walker W(this, _mask_and, _start, _dir, _range); - W.walk(m_root, m_center, m_bounds); - } - else - { - walker W(this, _mask_and, _start, _dir, _range); - W.walk(m_root, m_center, m_bounds); - } - } - else - { - if (_o & O_ONLYNEAREST) - { - walker W(this, _mask_and, _start, _dir, _range); - W.walk(m_root, m_center, m_bounds); - } - else - { - walker W(this, _mask_and, _start, _dir, _range); - W.walk(m_root, m_center, m_bounds); - } - } - } - else - { - if (_o & O_ONLYFIRST) - { - if (_o & O_ONLYNEAREST) - { - walker W(this, _mask_and, _start, _dir, _range); - W.walk(m_root, m_center, m_bounds); - } - else - { - walker W(this, _mask_and, _start, _dir, _range); - W.walk(m_root, m_center, m_bounds); - } - } - else - { - if (_o & O_ONLYNEAREST) - { - walker W(this, _mask_and, _start, _dir, _range); - W.walk(m_root, m_center, m_bounds); - } - else - { - walker W(this, _mask_and, _start, _dir, _range); - W.walk(m_root, m_center, m_bounds); - } - } - } - cs.Leave(); + PROF_EVENT("ISpatial_DB::q_ray"); + xrSRWLockGuard guard(&db_lock, true); + if (!m_root) + return; + + R.clear(); + + spatial_ray_walker W(CPU::ID.feature && _CPU_FEATURE_SSE, !!(_o&O_ONLYFIRST), !!(_o&O_ONLYNEAREST)); + W._init(this, _mask_and, _start, _dir, _range); + W.walk(R, m_root, m_center, m_bounds); } diff --git a/src/xrCDB/OPC_RayCollider.cpp b/src/xrCDB/OPC_RayCollider.cpp index 14f31ed1c5..b33a8bbca6 100644 --- a/src/xrCDB/OPC_RayCollider.cpp +++ b/src/xrCDB/OPC_RayCollider.cpp @@ -572,6 +572,7 @@ bool RayCollider::Collide(const Ray& world_ray, const AABBTree* tree, Container& /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void RayCollider::_Stab(const AABBCollisionNode* node) { + PROF_EVENT("RayCollider::_Stab AABBCollisionNode"); // Perform Segment-AABB overlap test if (!SegmentAABBOverlap(node->mAABB.mCenter, node->mAABB.mExtents)) return; @@ -597,6 +598,7 @@ void RayCollider::_Stab(const AABBCollisionNode* node) /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void RayCollider::_Stab(const AABBQuantizedNode* node) { + PROF_EVENT("RayCollider::_Stab AABBQuantizedNode"); // Dequantize box const QuantizedAABB* Box = &node->mAABB; const Point Center(float(Box->mCenter[0]) * mCenterCoeff.x, float(Box->mCenter[1]) * mCenterCoeff.y, @@ -629,6 +631,7 @@ void RayCollider::_Stab(const AABBQuantizedNode* node) /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void RayCollider::_Stab(const AABBNoLeafNode* node) { + PROF_EVENT("RayCollider::_Stab AABBNoLeafNode"); // Perform Segment-AABB overlap test if (!SegmentAABBOverlap(node->mAABB.mCenter, node->mAABB.mExtents)) return; @@ -655,6 +658,7 @@ void RayCollider::_Stab(const AABBNoLeafNode* node) /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void RayCollider::_Stab(const AABBQuantizedNoLeafNode* node) { + PROF_EVENT("RayCollider::_Stab AABBQuantizedNoLeafNode"); // Dequantize box const QuantizedAABB* Box = &node->mAABB; const Point Center(float(Box->mCenter[0]) * mCenterCoeff.x, float(Box->mCenter[1]) * mCenterCoeff.y, @@ -689,6 +693,7 @@ void RayCollider::_Stab(const AABBQuantizedNoLeafNode* node) /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void RayCollider::_Stab(const AABBTreeNode* node, Container& box_indices) { + PROF_EVENT("RayCollider::_Stab AABBTreeNode"); // Test the box against the segment Point Center, Extents; node->GetAABB()->GetCenter(Center); diff --git a/src/xrCDB/StdAfx.h b/src/xrCDB/StdAfx.h index 8d113bc8cb..b09633b16d 100644 --- a/src/xrCDB/StdAfx.h +++ b/src/xrCDB/StdAfx.h @@ -8,6 +8,7 @@ //#pragma once #include "../xrCore/xrCore.h" +#include "../xrCore/profiler.h" #ifdef USE_ARENA_ALLOCATOR // extern doug_lea_allocator g_collision_allocator; diff --git a/src/xrCDB/sse_intersect.h b/src/xrCDB/sse_intersect.h new file mode 100644 index 0000000000..ca75e16a3e --- /dev/null +++ b/src/xrCDB/sse_intersect.h @@ -0,0 +1,228 @@ +#pragma once +#include "StdAfx.h" + +#pragma warning(push) +#pragma warning(disable:4995) +#include +#pragma warning(pop) + +// can you say "barebone"? +#ifndef _MM_ALIGN16 +# define _MM_ALIGN16 __declspec(align(16)) +#endif // _MM_ALIGN16 + +struct _MM_ALIGN16 vec_t : public Fvector3 { + float pad; +}; +//static vec_t vec_c ( float _x, float _y, float _z) { vec_t v; v.x=_x;v.y=_y;v.z=_z;v.pad=0; return v; } + +struct _MM_ALIGN16 aabb_t { + vec_t min; + vec_t max; +}; +struct _MM_ALIGN16 ray_t { + vec_t pos; + vec_t inv_dir; + vec_t fwd_dir; +}; +struct ray_segment_t { + float t_near, t_far; +}; + +ICF u32& uf(float& x) { return (u32&)x; } +ICF BOOL isect_fpu(const Fvector& min, const Fvector& max, const ray_t& ray, Fvector& coord) +{ + Fvector MaxT; + MaxT.x = MaxT.y = MaxT.z = -1.0f; + BOOL Inside = TRUE; + + // Find candidate planes. + if (ray.pos[0] < min[0]) { + coord[0] = min[0]; + Inside = FALSE; + if (uf(ray.inv_dir[0])) MaxT[0] = (min[0] - ray.pos[0]) * ray.inv_dir[0]; // Calculate T distances to candidate planes + } + else if (ray.pos[0] > max[0]) { + coord[0] = max[0]; + Inside = FALSE; + if (uf(ray.inv_dir[0])) MaxT[0] = (max[0] - ray.pos[0]) * ray.inv_dir[0]; // Calculate T distances to candidate planes + } + if (ray.pos[1] < min[1]) { + coord[1] = min[1]; + Inside = FALSE; + if (uf(ray.inv_dir[1])) MaxT[1] = (min[1] - ray.pos[1]) * ray.inv_dir[1]; // Calculate T distances to candidate planes + } + else if (ray.pos[1] > max[1]) { + coord[1] = max[1]; + Inside = FALSE; + if (uf(ray.inv_dir[1])) MaxT[1] = (max[1] - ray.pos[1]) * ray.inv_dir[1]; // Calculate T distances to candidate planes + } + if (ray.pos[2] < min[2]) { + coord[2] = min[2]; + Inside = FALSE; + if (uf(ray.inv_dir[2])) MaxT[2] = (min[2] - ray.pos[2]) * ray.inv_dir[2]; // Calculate T distances to candidate planes + } + else if (ray.pos[2] > max[2]) { + coord[2] = max[2]; + Inside = FALSE; + if (uf(ray.inv_dir[2])) MaxT[2] = (max[2] - ray.pos[2]) * ray.inv_dir[2]; // Calculate T distances to candidate planes + } + + // Ray ray.pos inside bounding box + if (Inside) { + coord = ray.pos; + return true; + } + + // Get largest of the maxT's for final choice of intersection + u32 WhichPlane = 0; + if (MaxT[1] > MaxT[0]) WhichPlane = 1; + if (MaxT[2] > MaxT[WhichPlane]) WhichPlane = 2; + + // Check final candidate actually inside box (if max < 0) + if (uf(MaxT[WhichPlane]) & 0x80000000) return false; + + if (0 == WhichPlane) { // 1 & 2 + coord[1] = ray.pos[1] + MaxT[0] * ray.fwd_dir[1]; + if ((coord[1] < min[1]) || (coord[1] > max[1])) return false; + coord[2] = ray.pos[2] + MaxT[0] * ray.fwd_dir[2]; + if ((coord[2] < min[2]) || (coord[2] > max[2])) return false; + return true; + } + if (1 == WhichPlane) { // 0 & 2 + coord[0] = ray.pos[0] + MaxT[1] * ray.fwd_dir[0]; + if ((coord[0] < min[0]) || (coord[0] > max[0])) return false; + coord[2] = ray.pos[2] + MaxT[1] * ray.fwd_dir[2]; + if ((coord[2] < min[2]) || (coord[2] > max[2])) return false; + return true; + } + if (2 == WhichPlane) { // 0 & 1 + coord[0] = ray.pos[0] + MaxT[2] * ray.fwd_dir[0]; + if ((coord[0] < min[0]) || (coord[0] > max[0])) return false; + coord[1] = ray.pos[1] + MaxT[2] * ray.fwd_dir[1]; + if ((coord[1] < min[1]) || (coord[1] > max[1])) return false; + return true; + } + return false; +} + +// turn those verbose intrinsics into something readable. +#define loadps(mem) _mm_load_ps((const float * const)(mem)) +#define storess(ss,mem) _mm_store_ss((float * const)(mem),(ss)) +#define minss _mm_min_ss +#define maxss _mm_max_ss +#define minps _mm_min_ps +#define maxps _mm_max_ps +#define mulps _mm_mul_ps +#define subps _mm_sub_ps +#define rotatelps(ps) _mm_shuffle_ps((ps),(ps), 0x39) // a,b,c,d -> b,c,d,a +#define muxhps(low,high) _mm_movehl_ps((low),(high)) // low{a,b,c,d}|high{e,f,g,h} = {c,d,g,h} + + +static const float flt_plus_inf = -logf(0); // let's keep C and C++ compilers happy. +static const float _MM_ALIGN16 +ps_cst_plus_inf[4] = { flt_plus_inf, flt_plus_inf, flt_plus_inf, flt_plus_inf }, +ps_cst_minus_inf[4] = { -flt_plus_inf, -flt_plus_inf, -flt_plus_inf, -flt_plus_inf }; + +ICF BOOL isect_sse(const aabb_t& box, const ray_t& ray, float& dist) { + // you may already have those values hanging around somewhere + const __m128 + plus_inf = loadps(ps_cst_plus_inf), + minus_inf = loadps(ps_cst_minus_inf); + + // use whatever's apropriate to load. + const __m128 + box_min = loadps(&box.min), + box_max = loadps(&box.max), + pos = loadps(&ray.pos), + inv_dir = loadps(&ray.inv_dir); + + // use a div if inverted directions aren't available + const __m128 l1 = mulps(subps(box_min, pos), inv_dir); + const __m128 l2 = mulps(subps(box_max, pos), inv_dir); + + // the order we use for those min/max is vital to filter out + // NaNs that happens when an inv_dir is +/- inf and + // (box_min - pos) is 0. inf * 0 = NaN + const __m128 filtered_l1a = minps(l1, plus_inf); + const __m128 filtered_l2a = minps(l2, plus_inf); + + const __m128 filtered_l1b = maxps(l1, minus_inf); + const __m128 filtered_l2b = maxps(l2, minus_inf); + + // now that we're back on our feet, test those slabs. + __m128 lmax = maxps(filtered_l1a, filtered_l2a); + __m128 lmin = minps(filtered_l1b, filtered_l2b); + + // unfold back. try to hide the latency of the shufps & co. + const __m128 lmax0 = rotatelps(lmax); + const __m128 lmin0 = rotatelps(lmin); + lmax = minss(lmax, lmax0); + lmin = maxss(lmin, lmin0); + + const __m128 lmax1 = muxhps(lmax, lmax); + const __m128 lmin1 = muxhps(lmin, lmin); + lmax = minss(lmax, lmax1); + lmin = maxss(lmin, lmin1); + + const BOOL ret = _mm_comige_ss(lmax, _mm_setzero_ps()) & _mm_comige_ss(lmax, lmin); + + storess(lmin, &dist); + //storess (lmax, &rs.t_far); + + return ret; +} + +// fpu +ICF BOOL _box_fpu(ray_t& ray, const Fvector& n_C, const float n_R, Fvector& coord) +{ + // box + float n_vR = 2 * n_R; + Fbox BB; BB.set(n_C.x - n_vR, n_C.y - n_vR, n_C.z - n_vR, n_C.x + n_vR, n_C.y + n_vR, n_C.z + n_vR); + return isect_fpu(BB.min, BB.max, ray, coord); +} +ICF BOOL _box_fpu(ray_t& ray, const Fvector& bCenter, const Fvector& bExtents, Fvector& coord) +{ + Fbox BB; + BB.min.sub(bCenter, bExtents); + BB.max.add(bCenter, bExtents); + return isect_fpu(BB.min, BB.max, ray, coord); +} + +// sse +ICF BOOL _box_sse(ray_t& ray, const Fvector& n_C, const float n_R, float& dist) +{ + aabb_t box; + /* + float n_vR = 2*n_R; + box.min.set (n_C.x-n_vR, n_C.y-n_vR, n_C.z-n_vR); box.min.pad = 0; + box.max.set (n_C.x+n_vR, n_C.y+n_vR, n_C.z+n_vR); box.max.pad = 0; + */ + __m128 NR = _mm_load_ss((float*)&n_R); + __m128 NC = _mm_unpacklo_ps(_mm_load_ss((float*)&n_C.x), _mm_load_ss((float*)&n_C.y)); + NR = _mm_add_ss(NR, NR); + NC = _mm_movelh_ps(NC, _mm_load_ss((float*)&n_C.z)); + NR = _mm_shuffle_ps(NR, NR, _MM_SHUFFLE(1, 0, 0, 0)); + + _mm_store_ps((float*)&box.min, _mm_sub_ps(NC, NR)); + _mm_store_ps((float*)&box.max, _mm_add_ps(NC, NR)); + + return isect_sse(box, ray, dist); +} +ICF BOOL _box_sse(ray_t& ray, const Fvector& bCenter, const Fvector& bExtents, float& dist) +{ + aabb_t box; + /* + box.min.sub (bCenter,bExtents); box.min.pad = 0; + box.max.add (bCenter,bExtents); box.max.pad = 0; + */ + __m128 CN = _mm_unpacklo_ps(_mm_load_ss((float*)&bCenter.x), _mm_load_ss((float*)&bCenter.y)); + CN = _mm_movelh_ps(CN, _mm_load_ss((float*)&bCenter.z)); + __m128 EX = _mm_unpacklo_ps(_mm_load_ss((float*)&bExtents.x), _mm_load_ss((float*)&bExtents.y)); + EX = _mm_movelh_ps(EX, _mm_load_ss((float*)&bExtents.z)); + + _mm_store_ps((float*)&box.min, _mm_sub_ps(CN, EX)); + _mm_store_ps((float*)&box.max, _mm_add_ps(CN, EX)); + + return isect_sse(box, ray, dist); +} \ No newline at end of file diff --git a/src/xrCDB/xrCDB.cpp b/src/xrCDB/xrCDB.cpp index 0f5a0293e4..7164fc2008 100644 --- a/src/xrCDB/xrCDB.cpp +++ b/src/xrCDB/xrCDB.cpp @@ -63,57 +63,12 @@ MODEL::~MODEL() verts_count = 0; } -struct BTHREAD_params -{ - MODEL* M; - Fvector* V; - int Vcnt; - TRI* T; - int Tcnt; - build_callback* BC; - void* BCP; -}; - -void MODEL::build_thread(void* params) -{ - PROF_EVENT(); - - _initialize_cpu_thread(); - FPU::m64r(); - BTHREAD_params P = *((BTHREAD_params*)params); - P.M->cs.Enter(); - P.M->build_internal(P.V, P.Vcnt, P.T, P.Tcnt, P.BC, P.BCP); - P.M->status = S_READY; - P.M->cs.Leave(); - //Msg ("* xrCDB: cform build completed, memory usage: %d K",P.M->memory()/1024); -} - void MODEL::build(Fvector* V, int Vcnt, TRI* T, int Tcnt, build_callback* bc, void* bcp) { R_ASSERT(S_INIT == status); R_ASSERT((Vcnt>=4)&&(Tcnt>=2)); - _initialize_cpu_thread(); -#ifdef _EDITOR - build_internal (V,Vcnt,T,Tcnt,bc,bcp); -#else - if (!strstr(Core.Params, "-mt_cdb")) - { - build_internal(V, Vcnt, T, Tcnt, bc, bcp); - status = S_READY; - } - else - { - BTHREAD_params P = {this, V, Vcnt, T, Tcnt, bc, bcp}; - thread_spawn(build_thread, "CDB-construction", 0, &P); - while (S_INIT == status) - { - if (status != S_INIT) - break; - Sleep(5); - } - } -#endif + build_internal(V, Vcnt, T, Tcnt, bc, bcp); } void MODEL::build_internal(Fvector* V, int Vcnt, TRI* T, int Tcnt, build_callback* bc, void* bcp) @@ -121,6 +76,7 @@ void MODEL::build_internal(Fvector* V, int Vcnt, TRI* T, int Tcnt, build_callbac PROF_EVENT(); // verts + status = S_BUILD; verts_count = Vcnt; verts = CALLOC(Fvector, verts_count); CopyMemory(verts, V, verts_count*sizeof(Fvector)); @@ -133,9 +89,6 @@ void MODEL::build_internal(Fvector* V, int Vcnt, TRI* T, int Tcnt, build_callbac // callback if (bc) bc(verts, Vcnt, tris, Tcnt, bcp); - // Release data pointers - status = S_BUILD; - // Allocate temporary "OPCODE" tris + convert tris to 'pointer' form u32* temp_tris = CALLOC(u32, tris_count*3); if (0 == temp_tris) @@ -174,7 +127,8 @@ void MODEL::build_internal(Fvector* V, int Vcnt, TRI* T, int Tcnt, build_callbac // Free temporary tris CFREE(temp_tris); - return; + + status = S_READY; } u32 MODEL::memory() @@ -196,6 +150,7 @@ COLLIDER::COLLIDER() ray_mode = 0; box_mode = 0; frustum_mode = 0; + obb_mode = 0; } COLLIDER::~COLLIDER() diff --git a/src/xrCDB/xrCDB.h b/src/xrCDB/xrCDB.h index ef084d3936..90999aa7ee 100644 --- a/src/xrCDB/xrCDB.h +++ b/src/xrCDB/xrCDB.h @@ -71,9 +71,8 @@ namespace CDB }; private: - xrCriticalSection cs; Opcode::OPCODE_Model* tree; - u32 status; // 0=ready, 1=init, 2=building + xr_atomic_bool status; // 0=ready, 1=init, 2=building // tris TRI* tris; @@ -90,14 +89,13 @@ namespace CDB IC const TRI* get_tris() const { return tris; } IC TRI* get_tris() { return tris; } IC int get_tris_count() const { return tris_count; } - IC void syncronize() const + xr_task_group async_cform_load; + IC void syncronize() { if (S_READY != status) { Log ("! WARNING: syncronized CDB::query"); - xrCriticalSection* C = (xrCriticalSection*)&cs; - C->Enter(); - C->Leave(); + async_cform_load.wait(); } } @@ -145,6 +143,7 @@ namespace CDB u32 ray_mode; u32 box_mode; u32 frustum_mode; + u32 obb_mode; // Result management xr_vector rd; @@ -161,6 +160,9 @@ namespace CDB ICF void frustum_options(u32 f) { frustum_mode = f; } void frustum_query(const MODEL* m_def, const CFrustum& F); + ICF void obb_options(u32 f) { obb_mode = f; } + void obb_query(const MODEL* m_def, const Fobb& _obb); + ICF RESULT* r_begin() { return &*rd.begin(); }; ICF RESULT* r_end() { return &*rd.end(); }; RESULT& r_add(); @@ -168,16 +170,29 @@ namespace CDB ICF int r_count() { return rd.size(); }; ICF void r_clear() { rd.clear_not_free(); }; ICF void r_clear_compact() { rd.clear_and_free(); }; + IC xr_vector& r_vec() { return rd; }; }; // class XRCDB_API Collector { + public: +#pragma pack(push,1) + struct edge + { + u32 face_id; + u32 edge_id; + u32 vertex_id0; + u32 vertex_id1; + }; +#pragma pack(pop) + xr_vector verts; xr_vector faces; + xr_vector edges; u32 VPack(const Fvector& V, float eps); - public: + void add_face(const Fvector& v0, const Fvector& v1, const Fvector& v2, u16 material, u16 sector); void add_face_D(const Fvector& v0, const Fvector& v1, const Fvector& v2, u32 dummy); void add_face_packed(const Fvector& v0, const Fvector& v1, const Fvector& v2, u16 material, u16 sector, @@ -190,6 +205,7 @@ namespace CDB size_t getVS() { return verts.size(); } TRI* getT() { return &*faces.begin(); } size_t getTS() { return faces.size(); } + ICF void reserve (u32 tris_size){ faces.reserve(tris_size); verts.reserve(tris_size*3); } void clear() { diff --git a/src/xrCDB/xrCDB.vcxproj b/src/xrCDB/xrCDB.vcxproj index 17bfee531f..cb86df49ca 100644 --- a/src/xrCDB/xrCDB.vcxproj +++ b/src/xrCDB/xrCDB.vcxproj @@ -13,6 +13,10 @@ Release x64 + + VerifiedDX11ASAN + x64 + VerifiedDX11 x64 @@ -58,6 +62,15 @@ false x64 + + StaticLibrary + v143 + false + MultiByte + false + x64 + true + StaticLibrary v143 @@ -88,6 +101,11 @@ + + + + + @@ -117,6 +135,11 @@ $(xrGameDir)bin_dbg\$(Platform)\$(Configuration)\ $(xrIntDir)$(ProjectName)\ + + false + $(xrGameDir)bin_dbg\$(Platform)\$(Configuration)\ + $(xrIntDir)$(ProjectName)\ + false $(xrGameDir)bin_dbg\$(Platform)\$(Configuration)\ @@ -236,7 +259,7 @@ false false $(SolutionDir)xrCore;$(xrSdkDir)include;%(AdditionalIncludeDirectories) - USE_VERIFY_IN_RELEASE;WIN32;NDEBUG;_WINDOWS;_USRDLL;XRCDB_EXPORTS;_SECURE_SCL=0;%(PreprocessorDefinitions) + XRCORE_PROFILER;USE_VERIFY_IN_RELEASE;WIN32;NDEBUG;_WINDOWS;_USRDLL;XRCDB_EXPORTS;_SECURE_SCL=0;%(PreprocessorDefinitions) NotSet Use stdafx.h @@ -287,7 +310,7 @@ false false $(SolutionDir)xrCore;$(xrSdkDir)include;%(AdditionalIncludeDirectories) - USE_VERIFY_IN_RELEASE;WIN32;NDEBUG;_WINDOWS;_USRDLL;XRCDB_EXPORTS;_SECURE_SCL=0;%(PreprocessorDefinitions) + XRCORE_PROFILER;USE_VERIFY_IN_RELEASE;WIN32;NDEBUG;_WINDOWS;_USRDLL;XRCDB_EXPORTS;_SECURE_SCL=0;%(PreprocessorDefinitions) NotSet Use stdafx.h @@ -322,6 +345,57 @@ true + + + NDEBUG;%(PreprocessorDefinitions) + true + true + $(OutDir)$(TargetName).tlb + + + Disabled + Disabled + false + Neither + false + false + false + $(SolutionDir)xrCore;$(xrSdkDir)include;%(AdditionalIncludeDirectories) + XRCORE_PROFILER;_DISABLE_VECTOR_ANNOTATION;_DISABLE_STRING_ANNOTATION;USE_VERIFY_IN_RELEASE;WIN32;NDEBUG;_WINDOWS;_USRDLL;XRCDB_EXPORTS;_SECURE_SCL=0;%(PreprocessorDefinitions) + NotSet + Use + stdafx.h + ProgramDatabase + USE_LUAJIT_ONE + true + Level4 + false + MultiThreadedDLL + false + stdcpp17 + true + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + + + + + true + $(xrSdkDir)libraries;$(xrLibDir);%(AdditionalLibraryDirectories) + NotSet + true + true + true + Default + false + + + $(xrLibDir)$(TargetName).lib + true + + NDEBUG;%(PreprocessorDefinitions) @@ -378,6 +452,7 @@ true true true + true true @@ -414,6 +489,7 @@ Create Create Create + Create Create @@ -423,7 +499,6 @@ - @@ -468,6 +543,7 @@ + diff --git a/src/xrCDB/xrCDB.vcxproj.filters b/src/xrCDB/xrCDB.vcxproj.filters index 765391b61d..eca6d62e64 100644 --- a/src/xrCDB/xrCDB.vcxproj.filters +++ b/src/xrCDB/xrCDB.vcxproj.filters @@ -123,9 +123,6 @@ engine - - engine - engine @@ -263,6 +260,9 @@ engine + + engine + engine @@ -276,4 +276,4 @@ - \ No newline at end of file + diff --git a/src/xrCDB/xrCDB_Collector.cpp b/src/xrCDB/xrCDB_Collector.cpp index fc0ef39780..e769a6df15 100644 --- a/src/xrCDB/xrCDB_Collector.cpp +++ b/src/xrCDB/xrCDB_Collector.cpp @@ -81,19 +81,9 @@ namespace CDB #include #pragma warning(pop) -#pragma pack(push,1) - struct edge - { - u32 face_id : 30; - u32 edge_id : 2; - u16 vertex_id0; - u16 vertex_id1; - }; -#pragma pack(pop) - struct sort_predicate { - IC bool operator()(const edge& edge0, const edge& edge1) const + IC bool operator()(const Collector::edge& edge0, const Collector::edge& edge1) const { if (edge0.vertex_id0 < edge1.vertex_id0) return (true); @@ -111,154 +101,45 @@ namespace CDB } }; - void Collector::calc_adjacency(xr_vector& dest) - { -#if 1 - VERIFY(faces.size() < 65536); - const u32 edge_count = faces.size() * 3; -#ifdef _EDITOR - xr_vector _edges (edge_count); - edge *edges = &*_edges.begin(); -#else - edge* edges = xr_alloc(edge_count); -#endif - edge* i = edges; - xr_vector::const_iterator B = faces.begin(), I = B; - xr_vector::const_iterator E = faces.end(); - for (; I != E; ++I) - { - u32 face_id = u32(I - B); - - VERIFY(i < (edges + edge_count)); - (*i).face_id = face_id; - (*i).edge_id = 0; - (*i).vertex_id0 = (u16)(*I).verts[0]; - (*i).vertex_id1 = (u16)(*I).verts[1]; - if ((*i).vertex_id0 > (*i).vertex_id1) - std::swap((*i).vertex_id0, (*i).vertex_id1); - ++i; - - VERIFY(i < (edges + edge_count)); - (*i).face_id = face_id; - (*i).edge_id = 1; - (*i).vertex_id0 = (u16)(*I).verts[1]; - (*i).vertex_id1 = (u16)(*I).verts[2]; - if ((*i).vertex_id0 > (*i).vertex_id1) - std::swap((*i).vertex_id0, (*i).vertex_id1); - ++i; - - VERIFY(i < (edges + edge_count)); - (*i).face_id = face_id; - (*i).edge_id = 2; - (*i).vertex_id0 = (u16)(*I).verts[2]; - (*i).vertex_id1 = (u16)(*I).verts[0]; - if ((*i).vertex_id0 > (*i).vertex_id1) - std::swap((*i).vertex_id0, (*i).vertex_id1); - ++i; - } - - std::sort(edges, edges + edge_count, sort_predicate()); - - dest.assign(edge_count, u32(-1)); - - { - edge *I = edges, *J; - edge* E = edges + edge_count; - for (; I != E; ++I) - { - if (I + 1 == E) - continue; - - J = I + 1; - - if ((*I).vertex_id0 != (*J).vertex_id0) - continue; - - if ((*I).vertex_id1 != (*J).vertex_id1) - continue; - - dest[(*I).face_id * 3 + (*I).edge_id] = (*J).face_id; - dest[(*J).face_id * 3 + (*J).edge_id] = (*I).face_id; - } - } -# if 0 - xr_vector test = dest; - - dest.assign (faces.size()*3,0xffffffff); - // Dumb algorithm O(N^2) :) - for (u32 f=0; ff2) std::swap(f1,f2); - - for (u32 t_e=0; t_e<3; t_e++) - { - u32 t1 = faces[t].verts[(t_e+0)%3]; - u32 t2 = faces[t].verts[(t_e+1)%3]; - if (t1>t2) std::swap(t1,t2); - - if (f1==t1 && f2==t2) - { - // f.edge[f_e] linked to t.edge[t_e] - dest[f*3+f_e] = t; - break; - } - } - } - } - } - - { - xr_vector::const_iterator I = test.begin(); - xr_vector::const_iterator E = test.end(); - xr_vector::const_iterator J = dest.begin(); - for ( ; I != E; ++I, ++J) { - VERIFY (*I == *J); - } - } -# endif -#else - dest.assign (faces.size()*3,0xffffffff); - // Dumb algorithm O(N^2) :) - for (u32 f=0; ff2) std::swap(f1,f2); - - for (u32 t_e=0; t_e<3; t_e++) - { - u32 t1 = faces[t].verts[(t_e+0)%3]; - u32 t2 = faces[t].verts[(t_e+1)%3]; - if (t1>t2) std::swap(t1,t2); - - if (f1==t1 && f2==t2) - { - // f.edge[f_e] linked to t.edge[t_e] - dest[f*3+f_e] = t; - break; - } - } - } - } - } -#endif - - xr_free(edges); - } + void Collector::calc_adjacency(xr_vector& dest) + { + edges.clear(); + const size_t edge_count = faces.size() * 3; + edges.resize(edge_count); + + size_t edge_idx = 0; + for (size_t face_id = 0; face_id < faces.size(); ++face_id) + { + const auto& F = faces[face_id]; + + for (u32 edge_id = 0; edge_id < 3; ++edge_id) + { + u32 v0 = F.verts[edge_id]; + u32 v1 = F.verts[(edge_id + 1) % 3]; + if (v0 > v1) + std::swap(v0, v1); + + edges[edge_idx++] = { (u32)face_id, edge_id, v0, v1 }; + } + } + + std::sort(edges.begin(), edges.end(), sort_predicate()); + dest.assign(edge_count, u32(-1)); + + // Сопоставление рёбер между треугольниками + for (size_t i = 0; i + 1 < edge_count; ++i) + { + const edge& e1 = edges[i]; + const edge& e2 = edges[i + 1]; + + if (e1.vertex_id0 == e2.vertex_id0 && e1.vertex_id1 == e2.vertex_id1) + { + dest[e1.face_id * 3 + e1.edge_id] = e2.face_id; + dest[e2.face_id * 3 + e2.edge_id] = e1.face_id; + ++i; + } + } + } IC BOOL similar(TRI& T1, TRI& T2) { diff --git a/src/xrCDB/xrCDB_box.cpp b/src/xrCDB/xrCDB_box.cpp index 542a948f83..f943b5c179 100644 --- a/src/xrCDB/xrCDB_box.cpp +++ b/src/xrCDB/xrCDB_box.cpp @@ -87,8 +87,7 @@ ICF bool planeBoxOverlap(const Point& normal, const float d, const Point& maxbox if(min>rad || max<-rad) return false; -template -class box_collider +class _MM_ALIGN16 cform_box_collider { public: COLLIDER* dest; @@ -100,6 +99,14 @@ class box_collider Point mLeafVerts [3]; + bool bClass3 = false; + + bool bFirst = false; + + cform_box_collider(bool bClass, bool bFrst) + + :bClass3(bClass), bFirst(bFrst) {} + IC void _init(COLLIDER* CL, Fvector* V, TRI* T, const Fvector& C, const Fvector& E) { dest = CL; @@ -240,42 +247,82 @@ class box_collider void COLLIDER::box_query(const MODEL* m_def, const Fvector& b_center, const Fvector& b_dim) { - m_def->syncronize(); + PROF_EVENT("COLLIDER::box_query"); + if (!m_def) + return; + const_cast(m_def)->syncronize(); // Get nodes const AABBNoLeafTree* T = (const AABBNoLeafTree*)m_def->tree->GetTree(); const AABBNoLeafNode* N = T->GetNodes(); r_clear(); - // Binary dispatcher - if (box_mode & OPT_FULL_TEST) + cform_box_collider BC(!!(box_mode&OPT_FULL_TEST), !!(box_mode&OPT_ONLYFIRST)); + BC._init(this, m_def->verts, m_def->tris, b_center, b_dim); + BC._stab(N); +} + +struct obb_collider +{ + COLLIDER* dest; + TRI* tris; + Fvector* verts; + Fobb obb; + + bool bClass3 = false; + bool bFirst = false; + + Fvector mLeafVerts[3]; + + void _prim(DWORD prim) { - if (box_mode & OPT_ONLYFIRST) - { - box_collider BC; - BC._init(this, m_def->verts, m_def->tris, b_center, b_dim); - BC._stab(N); - } - else - { - box_collider BC; - BC._init(this, m_def->verts, m_def->tris, b_center, b_dim); - BC._stab(N); - } + TRI& T = tris[prim]; + mLeafVerts[0] = verts[T.verts[0]]; + mLeafVerts[1] = verts[T.verts[1]]; + mLeafVerts[2] = verts[T.verts[2]]; + + if (!obb.intersectTri(mLeafVerts, bClass3)) + return; + + RESULT& R = dest->r_add(); + R.id = prim; + R.verts[0] = mLeafVerts[0]; + R.verts[1] = mLeafVerts[1]; + R.verts[2] = mLeafVerts[2]; + R.dummy = T.dummy; } - else + + void _stab(const AABBNoLeafNode* node) { - if (box_mode & OPT_ONLYFIRST) - { - box_collider BC; - BC._init(this, m_def->verts, m_def->tris, b_center, b_dim); - BC._stab(N); - } - else - { - box_collider BC; - BC._init(this, m_def->verts, m_def->tris, b_center, b_dim); - BC._stab(N); - } + // Actual OBB-AABB test + if (!obb.intersectAABB((Fvector&)node->mAABB.mCenter, (Fvector&)node->mAABB.mExtents)) return; + + // 1st child + if (node->HasLeaf()) _prim(node->GetPrimitive()); + else _stab(node->GetPos()); + + // Early exit for "only first" + if (bFirst && dest->r_count()) return; + + // 2nd child + if (node->HasLeaf2()) _prim(node->GetPrimitive2()); + else _stab(node->GetNeg()); } +}; + +void COLLIDER::obb_query(const MODEL* m_def, const Fobb& obb) +{ + PROF_EVENT("COLLIDER::obb_query"); + if (!m_def) + return; + + const_cast(m_def)->syncronize(); + + // Get nodes + const AABBNoLeafTree* T = (const AABBNoLeafTree*)m_def->tree->GetTree(); + const AABBNoLeafNode* N = T->GetNodes(); + r_clear(); + + obb_collider OC{ this, m_def->tris, m_def->verts, obb, !!(box_mode & OPT_FULL_TEST), !!(box_mode & OPT_ONLYFIRST) }; + OC._stab(N); } diff --git a/src/xrCDB/xrCDB_frustum.cpp b/src/xrCDB/xrCDB_frustum.cpp index 8a5f02a661..e03a83dc0f 100644 --- a/src/xrCDB/xrCDB_frustum.cpp +++ b/src/xrCDB/xrCDB_frustum.cpp @@ -7,8 +7,7 @@ using namespace CDB; using namespace Opcode; -template -class frustum_collider +class _MM_ALIGN16 cform_frustum_collider { public: COLLIDER* dest; @@ -17,6 +16,18 @@ class frustum_collider const CFrustum* F; + Fvector mM[2]; + + sPoly Src, Dst; + + bool bClass3 = false; + + bool bFirst = false; + + cform_frustum_collider(bool bClass, bool bFrst) + + :bClass3(bClass), bFirst(bFrst) {} + IC void _init(COLLIDER* CL, Fvector* V, TRI* T, const CFrustum* _F) { dest = CL; @@ -25,102 +36,79 @@ class frustum_collider F = _F; } - IC EFC_Visible _box(Fvector& C, Fvector& E, u32& mask) + IC void SetByVerts(Fvector* Val, DWORD prim) + { + Val[0] = verts[tris[prim].verts[0]]; + Val[1] = verts[tris[prim].verts[1]]; + Val[2] = verts[tris[prim].verts[2]]; + } + + IC EFC_Visible Box(const Fvector& C, const Fvector& E, u32& mask) { - Fvector mM[2]; mM[0].sub(C, E); mM[1].add(C, E); return F->testAABB(&mM[0].x, mask); } - void _prim(DWORD prim) + void Prim(DWORD InPrim) { if (bClass3) { - sPoly src, dst; - src.resize(3); - src[0] = verts[tris[prim].verts[0]]; - src[1] = verts[tris[prim].verts[1]]; - src[2] = verts[tris[prim].verts[2]]; - if (F->ClipPoly(src, dst)) + Src.resize(3); + SetByVerts(Src.begin(), InPrim); + if (F->ClipPoly(Src, Dst)) { RESULT& R = dest->r_add(); - R.id = prim; - R.verts[0] = verts[tris[prim].verts[0]]; - R.verts[1] = verts[tris[prim].verts[1]]; - R.verts[2] = verts[tris[prim].verts[2]]; - R.dummy = tris[prim].dummy; + R.id = InPrim; + R.verts[0] = verts[tris[InPrim].verts[0]]; + R.verts[1] = verts[tris[InPrim].verts[1]]; + R.verts[2] = verts[tris[InPrim].verts[2]]; + R.dummy = tris[InPrim].dummy; } } else { RESULT& R = dest->r_add(); - R.id = prim; - R.verts[0] = verts[tris[prim].verts[0]]; - R.verts[1] = verts[tris[prim].verts[1]]; - R.verts[2] = verts[tris[prim].verts[2]]; - R.dummy = tris[prim].dummy; + R.id = InPrim; + R.verts[0] = verts[tris[InPrim].verts[0]]; + R.verts[1] = verts[tris[InPrim].verts[1]]; + R.verts[2] = verts[tris[InPrim].verts[2]]; + R.dummy = tris[InPrim].dummy; } } - void _stab(const AABBNoLeafNode* node, u32 mask) + void Stab(const AABBNoLeafNode* node, u32 mask) { // Actual frustum/aabb test - EFC_Visible result = _box((Fvector&)node->mAABB.mCenter, (Fvector&)node->mAABB.mExtents, mask); + EFC_Visible result = Box((Fvector&)node->mAABB.mCenter, (Fvector&)node->mAABB.mExtents, mask); if (fcvNone == result) return; // 1st chield - if (node->HasLeaf()) _prim(node->GetPrimitive()); - else _stab(node->GetPos(), mask); + if (node->HasLeaf()) Prim(node->GetPrimitive()); + else Stab(node->GetPos(), mask); // Early exit for "only first" if (bFirst && dest->r_count()) return; // 2nd chield - if (node->HasLeaf2()) _prim(node->GetPrimitive2()); - else _stab(node->GetNeg(), mask); + if (node->HasLeaf2()) Prim(node->GetPrimitive2()); + else Stab(node->GetNeg(), mask); } }; void COLLIDER::frustum_query(const MODEL* m_def, const CFrustum& F) { - m_def->syncronize(); + PROF_EVENT("COLLIDER::frustum_query") + if (!m_def) + return; + const_cast(m_def)->syncronize(); // Get nodes - const AABBNoLeafTree* T = (const AABBNoLeafTree*)m_def->tree->GetTree(); - const AABBNoLeafNode* N = T->GetNodes(); + const AABBNoLeafNode* pNodes = ((AABBNoLeafTree*)m_def->tree->GetTree())->GetNodes(); const DWORD mask = F.getMask(); r_clear(); - // Binary dispatcher - if (frustum_mode & OPT_FULL_TEST) - { - if (frustum_mode & OPT_ONLYFIRST) - { - frustum_collider BC; - BC._init(this, m_def->verts, m_def->tris, &F); - BC._stab(N, mask); - } - else - { - frustum_collider BC; - BC._init(this, m_def->verts, m_def->tris, &F); - BC._stab(N, mask); - } - } - else - { - if (frustum_mode & OPT_ONLYFIRST) - { - frustum_collider BC; - BC._init(this, m_def->verts, m_def->tris, &F); - BC._stab(N, mask); - } - else - { - frustum_collider BC; - BC._init(this, m_def->verts, m_def->tris, &F); - BC._stab(N, mask); - } - } + cform_frustum_collider BC(!!(frustum_mode&OPT_FULL_TEST), !!(frustum_mode&OPT_ONLYFIRST)); + BC._init(this, m_def->verts, m_def->tris, &F); + BC.Stab(pNodes, mask); } diff --git a/src/xrCDB/xrCDB_ray.cpp b/src/xrCDB/xrCDB_ray.cpp index 5e91ad30bb..f66e6b8e6b 100644 --- a/src/xrCDB/xrCDB_ray.cpp +++ b/src/xrCDB/xrCDB_ray.cpp @@ -6,206 +6,12 @@ #pragma warning(pop) #include "xrCDB.h" +#include "sse_intersect.h" using namespace CDB; using namespace Opcode; -// can you say "barebone"? -#ifndef _MM_ALIGN16 -# define _MM_ALIGN16 __declspec(align(16)) -#endif // _MM_ALIGN16 - -struct _MM_ALIGN16 vec_t : public Fvector3 -{ - float pad; -}; - -//static vec_t vec_c ( float _x, float _y, float _z) { vec_t v; v.x=_x;v.y=_y;v.z=_z;v.pad=0; return v; } - -struct _MM_ALIGN16 aabb_t -{ - vec_t min; - vec_t max; -}; - -struct _MM_ALIGN16 ray_t -{ - vec_t pos; - vec_t inv_dir; - vec_t fwd_dir; -}; - -struct ray_segment_t -{ - float t_near, t_far; -}; - -ICF u32& uf(float& x) { return (u32&)x; } -ICF BOOL isect_fpu(const Fvector& min, const Fvector& max, const ray_t& ray, Fvector& coord) -{ - Fvector MaxT; - MaxT.x = MaxT.y = MaxT.z = -1.0f; - BOOL Inside = TRUE; - - // Find candidate planes. - if (ray.pos[0] < min[0]) - { - coord[0] = min[0]; - Inside = FALSE; - if (uf(ray.inv_dir[0])) MaxT[0] = (min[0] - ray.pos[0]) * ray.inv_dir[0]; - // Calculate T distances to candidate planes - } - else if (ray.pos[0] > max[0]) - { - coord[0] = max[0]; - Inside = FALSE; - if (uf(ray.inv_dir[0])) MaxT[0] = (max[0] - ray.pos[0]) * ray.inv_dir[0]; - // Calculate T distances to candidate planes - } - if (ray.pos[1] < min[1]) - { - coord[1] = min[1]; - Inside = FALSE; - if (uf(ray.inv_dir[1])) MaxT[1] = (min[1] - ray.pos[1]) * ray.inv_dir[1]; - // Calculate T distances to candidate planes - } - else if (ray.pos[1] > max[1]) - { - coord[1] = max[1]; - Inside = FALSE; - if (uf(ray.inv_dir[1])) MaxT[1] = (max[1] - ray.pos[1]) * ray.inv_dir[1]; - // Calculate T distances to candidate planes - } - if (ray.pos[2] < min[2]) - { - coord[2] = min[2]; - Inside = FALSE; - if (uf(ray.inv_dir[2])) MaxT[2] = (min[2] - ray.pos[2]) * ray.inv_dir[2]; - // Calculate T distances to candidate planes - } - else if (ray.pos[2] > max[2]) - { - coord[2] = max[2]; - Inside = FALSE; - if (uf(ray.inv_dir[2])) MaxT[2] = (max[2] - ray.pos[2]) * ray.inv_dir[2]; - // Calculate T distances to candidate planes - } - - // Ray ray.pos inside bounding box - if (Inside) - { - coord = ray.pos; - return true; - } - - // Get largest of the maxT's for final choice of intersection - u32 WhichPlane = 0; - if (MaxT[1] > MaxT[0]) WhichPlane = 1; - if (MaxT[2] > MaxT[WhichPlane]) WhichPlane = 2; - - // Check final candidate actually inside box (if max < 0) - if (uf(MaxT[WhichPlane]) & 0x80000000) return false; - - if (0 == WhichPlane) - { - // 1 & 2 - coord[1] = ray.pos[1] + MaxT[0] * ray.fwd_dir[1]; - if ((coord[1] < min[1]) || (coord[1] > max[1])) return false; - coord[2] = ray.pos[2] + MaxT[0] * ray.fwd_dir[2]; - if ((coord[2] < min[2]) || (coord[2] > max[2])) return false; - return true; - } - if (1 == WhichPlane) - { - // 0 & 2 - coord[0] = ray.pos[0] + MaxT[1] * ray.fwd_dir[0]; - if ((coord[0] < min[0]) || (coord[0] > max[0])) return false; - coord[2] = ray.pos[2] + MaxT[1] * ray.fwd_dir[2]; - if ((coord[2] < min[2]) || (coord[2] > max[2])) return false; - return true; - } - if (2 == WhichPlane) - { - // 0 & 1 - coord[0] = ray.pos[0] + MaxT[2] * ray.fwd_dir[0]; - if ((coord[0] < min[0]) || (coord[0] > max[0])) return false; - coord[1] = ray.pos[1] + MaxT[2] * ray.fwd_dir[1]; - if ((coord[1] < min[1]) || (coord[1] > max[1])) return false; - return true; - } - return false; -} - -// turn those verbose intrinsics into something readable. -#define loadps(mem) _mm_load_ps((const float * const)(mem)) -#define storess(ss,mem) _mm_store_ss((float * const)(mem),(ss)) -#define minss _mm_min_ss -#define maxss _mm_max_ss -#define minps _mm_min_ps -#define maxps _mm_max_ps -#define mulps _mm_mul_ps -#define subps _mm_sub_ps -#define rotatelps(ps) _mm_shuffle_ps((ps),(ps), 0x39) // a,b,c,d -> b,c,d,a -#define muxhps(low,high) _mm_movehl_ps((low),(high)) // low{a,b,c,d}|high{e,f,g,h} = {c,d,g,h} - - -static const float flt_plus_inf = -logf(0); // let's keep C and C++ compilers happy. -static const float _MM_ALIGN16 - ps_cst_plus_inf [4] = {flt_plus_inf, flt_plus_inf, flt_plus_inf, flt_plus_inf}, - ps_cst_minus_inf[4] = {-flt_plus_inf, -flt_plus_inf, -flt_plus_inf, -flt_plus_inf}; - -ICF BOOL isect_sse(const aabb_t& box, const ray_t& ray, float& dist) -{ - // you may already have those values hanging around somewhere - const __m128 - plus_inf = loadps(ps_cst_plus_inf), - minus_inf = loadps(ps_cst_minus_inf); - - // use whatever's apropriate to load. - const __m128 - box_min = loadps(&box.min), - box_max = loadps(&box.max), - pos = loadps(&ray.pos), - inv_dir = loadps(&ray.inv_dir); - - // use a div if inverted directions aren't available - const __m128 l1 = mulps(subps(box_min, pos), inv_dir); - const __m128 l2 = mulps(subps(box_max, pos), inv_dir); - - // the order we use for those min/max is vital to filter out - // NaNs that happens when an inv_dir is +/- inf and - // (box_min - pos) is 0. inf * 0 = NaN - const __m128 filtered_l1a = minps(l1, plus_inf); - const __m128 filtered_l2a = minps(l2, plus_inf); - - const __m128 filtered_l1b = maxps(l1, minus_inf); - const __m128 filtered_l2b = maxps(l2, minus_inf); - - // now that we're back on our feet, test those slabs. - __m128 lmax = maxps(filtered_l1a, filtered_l2a); - __m128 lmin = minps(filtered_l1b, filtered_l2b); - - // unfold back. try to hide the latency of the shufps & co. - const __m128 lmax0 = rotatelps(lmax); - const __m128 lmin0 = rotatelps(lmin); - lmax = minss(lmax, lmax0); - lmin = maxss(lmin, lmin0); - - const __m128 lmax1 = muxhps(lmax, lmax); - const __m128 lmin1 = muxhps(lmin, lmin); - lmax = minss(lmax, lmax1); - lmin = maxss(lmin, lmin1); - - const BOOL ret = _mm_comige_ss(lmax, _mm_setzero_ps()) & _mm_comige_ss(lmax, lmin); - - storess(lmin, &dist); - //storess (lmax, &rs.t_far); - - return ret; -} - -template -class _MM_ALIGN16 ray_collider +class _MM_ALIGN16 cform_ray_collider { public: COLLIDER* dest; @@ -216,6 +22,14 @@ class _MM_ALIGN16 ray_collider float rRange; float rRange2; + bool bSSE = false; + bool bCull = false; + bool bFirst = false; + bool bNearest = false; + + cform_ray_collider(bool SSE, bool Cull, bool First, bool Nearest) + :bSSE(SSE), bCull(Cull), bFirst(First), bNearest(Nearest) {} + IC void _init(COLLIDER* CL, Fvector* V, TRI* T, const Fvector& C, const Fvector& D, float R) { dest = CL; @@ -226,7 +40,7 @@ class _MM_ALIGN16 ray_collider ray.fwd_dir.set(D); rRange = R; rRange2 = R * R; - if (!bUseSSE) + if (!bSSE) { // for FPU - zero out inf if (_abs(D.x) > flt_eps) @@ -371,189 +185,71 @@ class _MM_ALIGN16 ray_collider } } - void _stab(const AABBNoLeafNode* node) +void _stab(const AABBNoLeafNode* node) +{ + PROF_EVENT("xrCDB_ray::_stab") + // Intersection filter stoping + //if (!continue_work) + // return; + + // Actual ray/aabb test + if (bSSE) { // Should help - _mm_prefetch((char *)node->GetNeg(), _MM_HINT_NTA); + _mm_prefetch((char*)node->GetNeg(), _MM_HINT_NTA); - // Actual ray/aabb test - if (bUseSSE) - { - // use SSE - float d; - if (!_box_sse((Fvector&)node->mAABB.mCenter, (Fvector&)node->mAABB.mExtents, d)) return; - if (d > rRange) return; - } - else - { - // use FPU - Fvector P; - if (!_box_fpu((Fvector&)node->mAABB.mCenter, (Fvector&)node->mAABB.mExtents, P)) return; - if (P.distance_to_sqr(ray.pos) > rRange2) return; - } + // use SSE + float d; + if (!_box_sse((Fvector&)node->mAABB.mCenter, (Fvector&)node->mAABB.mExtents, d)) return; + if (d > rRange) return; + } + else + { + // use FPU + Fvector P; + if (!_box_fpu((Fvector&)node->mAABB.mCenter, (Fvector&)node->mAABB.mExtents, P)) return; + if (P.distance_to_sqr(ray.pos) > rRange2) return; + } - // 1st chield - if (node->HasLeaf()) _prim(node->GetPrimitive()); - else _stab(node->GetPos()); + // 1st chield + if (node->HasLeaf()) _prim(node->GetPrimitive()); + else _stab(node->GetPos()); - // Early exit for "only first" - if (bFirst && dest->r_count()) return; + // Early exit for "only first" + if (bFirst && dest->r_count()) return; - // 2nd chield - if (node->HasLeaf2()) _prim(node->GetPrimitive2()); - else _stab(node->GetNeg()); - } + // 2nd chield + if (node->HasLeaf2()) _prim(node->GetPrimitive2()); + else _stab(node->GetNeg()); +} }; void COLLIDER::ray_query(const MODEL* m_def, const Fvector& r_start, const Fvector& r_dir, float r_range) { - m_def->syncronize(); + PROF_EVENT("COLLIDER::ray_query"); + if (!m_def) + return; + + if (!_finite(r_start.x) || !_finite(r_start.y) || !_finite(r_start.z)) + { + VERIFY("![COLLIDER::ray_query] r_start has NaN members, abort ray_query"); + return; + } + + const_cast(m_def)->syncronize(); // Get nodes const AABBNoLeafTree* T = (const AABBNoLeafTree*)m_def->tree->GetTree(); const AABBNoLeafNode* N = T->GetNodes(); r_clear(); - if (CPU::ID.feature & _CPU_FEATURE_SSE) - { - // SSE - // Binary dispatcher - if (ray_mode & OPT_CULL) - { - if (ray_mode & OPT_ONLYFIRST) - { - if (ray_mode & OPT_ONLYNEAREST) - { - ray_collider RC; - RC._init(this, m_def->verts, m_def->tris, r_start, r_dir, r_range); - RC._stab(N); - } - else - { - ray_collider RC; - RC._init(this, m_def->verts, m_def->tris, r_start, r_dir, r_range); - RC._stab(N); - } - } - else - { - if (ray_mode & OPT_ONLYNEAREST) - { - ray_collider RC; - RC._init(this, m_def->verts, m_def->tris, r_start, r_dir, r_range); - RC._stab(N); - } - else - { - ray_collider RC; - RC._init(this, m_def->verts, m_def->tris, r_start, r_dir, r_range); - RC._stab(N); - } - } - } - else - { - if (ray_mode & OPT_ONLYFIRST) - { - if (ray_mode & OPT_ONLYNEAREST) - { - ray_collider RC; - RC._init(this, m_def->verts, m_def->tris, r_start, r_dir, r_range); - RC._stab(N); - } - else - { - ray_collider RC; - RC._init(this, m_def->verts, m_def->tris, r_start, r_dir, r_range); - RC._stab(N); - } - } - else - { - if (ray_mode & OPT_ONLYNEAREST) - { - ray_collider RC; - RC._init(this, m_def->verts, m_def->tris, r_start, r_dir, r_range); - RC._stab(N); - } - else - { - ray_collider RC; - RC._init(this, m_def->verts, m_def->tris, r_start, r_dir, r_range); - RC._stab(N); - } - } - } - } - else - { - // FPU - // Binary dispatcher - if (ray_mode & OPT_CULL) - { - if (ray_mode & OPT_ONLYFIRST) - { - if (ray_mode & OPT_ONLYNEAREST) - { - ray_collider RC; - RC._init(this, m_def->verts, m_def->tris, r_start, r_dir, r_range); - RC._stab(N); - } - else - { - ray_collider RC; - RC._init(this, m_def->verts, m_def->tris, r_start, r_dir, r_range); - RC._stab(N); - } - } - else - { - if (ray_mode & OPT_ONLYNEAREST) - { - ray_collider RC; - RC._init(this, m_def->verts, m_def->tris, r_start, r_dir, r_range); - RC._stab(N); - } - else - { - ray_collider RC; - RC._init(this, m_def->verts, m_def->tris, r_start, r_dir, r_range); - RC._stab(N); - } - } - } - else - { - if (ray_mode & OPT_ONLYFIRST) - { - if (ray_mode & OPT_ONLYNEAREST) - { - ray_collider RC; - RC._init(this, m_def->verts, m_def->tris, r_start, r_dir, r_range); - RC._stab(N); - } - else - { - ray_collider RC; - RC._init(this, m_def->verts, m_def->tris, r_start, r_dir, r_range); - RC._stab(N); - } - } - else - { - if (ray_mode & OPT_ONLYNEAREST) - { - ray_collider RC; - RC._init(this, m_def->verts, m_def->tris, r_start, r_dir, r_range); - RC._stab(N); - } - else - { - ray_collider RC; - RC._init(this, m_def->verts, m_def->tris, r_start, r_dir, r_range); - RC._stab(N); - } - } - } - } + // SSE + // Binary dispatcher + const bool OptCull = ray_mode & OPT_CULL; + const bool OptFirst = ray_mode & OPT_ONLYFIRST; + const bool OptNearest = ray_mode & OPT_ONLYNEAREST; + + cform_ray_collider RC(CPU::ID.feature && _CPU_FEATURE_SSE, !!(ray_mode&OPT_CULL), !!(ray_mode&OPT_ONLYFIRST), !!(ray_mode&OPT_ONLYNEAREST)); + RC._init(this, m_def->verts, m_def->tris, r_start, r_dir, r_range); + RC._stab(N); } diff --git a/src/xrCDB/xrXRC.h b/src/xrCDB/xrXRC.h index a7a2008383..192ecd6f0d 100644 --- a/src/xrCDB/xrXRC.h +++ b/src/xrCDB/xrXRC.h @@ -66,13 +66,28 @@ class XRCDB_API xrXRC #endif } + IC void obb_options(u32 f) + { + CL.obb_options(f); + } + IC void obb_query(const CDB::MODEL* m_def, const Fobb& obb) + { +#ifdef DEBUG + cdb_clBOX->Begin(); +#endif + CL.obb_query(m_def, obb); +#ifdef DEBUG + cdb_clBOX->End(); +#endif + } + IC CDB::RESULT* r_begin() { return CL.r_begin(); }; IC CDB::RESULT* r_end() { return CL.r_end(); }; IC void r_free() { CL.r_free(); } IC int r_count() { return CL.r_count(); }; IC void r_clear() { CL.r_clear(); }; IC void r_clear_compact() { CL.r_clear_compact(); }; - + IC xr_vector& r_vec() { return CL.r_vec(); }; xrXRC(); ~xrXRC(); }; diff --git a/src/xrCDB/xr_area.cpp b/src/xrCDB/xr_area.cpp index 0a8bca0b6d..6b84d8d8bf 100644 --- a/src/xrCDB/xr_area.cpp +++ b/src/xrCDB/xr_area.cpp @@ -1,27 +1,17 @@ #include "stdafx.h" -//#include "igame_level.h" #include "xr_area.h" #include "../xrengine/xr_object.h" #include "../xrengine/xrLevel.h" #include "../xrengine/xr_collide_form.h" -//#include "../xrsound/sound.h" -//#include "x_ray.h" -//#include "GameFont.h" - using namespace collide; - //---------------------------------------------------------------------- // Class : CObjectSpace // Purpose : stores space slots //---------------------------------------------------------------------- -CObjectSpace::CObjectSpace(): - xrc() -#ifdef PROFILE_CRITICAL_SECTIONS - ,Lock(MUTEX_PROFILE_ID(CObjectSpace::Lock)) -#endif // PROFILE_CRITICAL_SECTIONS +CObjectSpace::CObjectSpace() #ifdef DEBUG ,m_pRender(0) #endif @@ -51,8 +41,7 @@ CObjectSpace::~CObjectSpace() //---------------------------------------------------------------------- //---------------------------------------------------------------------- -int CObjectSpace::GetNearest(xr_vector& q_spatial, xr_vector& q_nearest, const Fvector& point, - float range, CObject* ignore_object) +int CObjectSpace::GetNearest(xr_vector& q_spatial, xr_vector& q_nearest, const Fvector& point, float range, CObject* ignore_object) { q_spatial.clear_not_free(); // Query objects @@ -64,39 +53,30 @@ int CObjectSpace::GetNearest(xr_vector& q_spatial, xr_vectorq_box(q_spatial, 0, STYPE_COLLIDEABLE, point, B); // Iterate - xr_vector::iterator it = q_spatial.begin(); - xr_vector::iterator end = q_spatial.end(); + auto it = q_spatial.begin(); + auto end = q_spatial.end(); for (; it != end; it++) { CObject* O = (*it)->dcast_CObject(); - if (0 == O) continue; - if (O == ignore_object) continue; - Fsphere mS = {O->spatial.sphere.P, O->spatial.sphere.R}; - if (Q.intersect(mS)) q_nearest.push_back(O); - } + if (0 == O) + continue; - return q_nearest.size(); -} + if (O == ignore_object) + continue; -//---------------------------------------------------------------------- -int CObjectSpace::GetNearest(xr_vector& q_nearest, const Fvector& point, float range, CObject* ignore_object) -{ - return ( - GetNearest( - r_spatial, - q_nearest, - point, - range, - ignore_object - ) - ); + Fsphere mS = { O->SpatialComponent->spatial.sphere.P, O->SpatialComponent->spatial.sphere.R }; + if (Q.intersect(mS)) + q_nearest.push_back(O); + } + + return (int)q_nearest.size(); } //---------------------------------------------------------------------- int CObjectSpace::GetNearest(xr_vector& q_nearest, ICollisionForm* obj, float range) { CObject* O = obj->Owner(); - return GetNearest(q_nearest, O->spatial.sphere.P, range + O->spatial.sphere.R, O); + return GetNearest(q_nearest, O->SpatialComponent->spatial.sphere.P, range + O->SpatialComponent->spatial.sphere.R, O); } //---------------------------------------------------------------------- @@ -118,26 +98,44 @@ void CObjectSpace::Load(LPCSTR path, LPCSTR fname, CDB::build_callback build_cal } void CObjectSpace::Load(IReader* F, CDB::build_callback build_callback) - - { + static IReader* pReader = nullptr; + pReader = F; + hdrCFORM H; - F->r(&H, sizeof(hdrCFORM)); - Fvector* verts = (Fvector*)F->pointer(); - CDB::TRI* tris = (CDB::TRI*)(verts + H.vertcount); - Create(verts, tris, H, build_callback); - FS.r_close(F); + pReader->r(&H, sizeof(hdrCFORM)); + R_ASSERT(CFORM_CURRENT_VERSION == H.version); + m_BoundingVolume.set(H.aabb); + + g_SpatialSpace->initialize(m_BoundingVolume); + g_SpatialSpacePhysic->initialize(m_BoundingVolume); + g_SpatialSpaceLights->initialize(m_BoundingVolume); + + static DWORD this_thread_id = 0; + this_thread_id = GetCurrentThreadId(); + Static.async_cform_load.run([=]() + { + if (this_thread_id != GetCurrentThreadId()) { PROF_THREAD("X-Ray PPL Thread") } + PROF_EVENT("Async cform loading"); + Fvector* verts = (Fvector*)F->pointer(); + CDB::TRI* tris = (CDB::TRI*)(verts + H.vertcount); + Create(verts, tris, H, build_callback, false); + FS.r_close(pReader); + }); } -void CObjectSpace::Create(Fvector* verts, CDB::TRI* tris, const hdrCFORM& H, CDB::build_callback build_callback) +void CObjectSpace::Create(Fvector* verts, CDB::TRI* tris, const hdrCFORM& H, CDB::build_callback build_callback, bool init_bounds) { - R_ASSERT(CFORM_CURRENT_VERSION==H.version); Static.build(verts, H.vertcount, tris, H.facecount, build_callback); - m_BoundingVolume.set(H.aabb); - g_SpatialSpace->initialize(m_BoundingVolume); - g_SpatialSpacePhysic->initialize(m_BoundingVolume); - //Sound->set_geometry_occ ( &Static ); - //Sound->set_handler ( _sound_event ); + + if (init_bounds) + { + m_BoundingVolume.set(H.aabb); + + g_SpatialSpace->initialize(m_BoundingVolume); + g_SpatialSpacePhysic->initialize(m_BoundingVolume); + g_SpatialSpaceLights->initialize(m_BoundingVolume); + } } //---------------------------------------------------------------------- diff --git a/src/xrCDB/xr_area.h b/src/xrCDB/xr_area.h index d4cdfc4c58..02fbebda17 100644 --- a/src/xrCDB/xr_area.h +++ b/src/xrCDB/xr_area.h @@ -1,11 +1,14 @@ -#ifndef __XR_AREA_H__ -#define __XR_AREA_H__ +#pragma once //#include "xr_collide_form.h" #include "xr_collide_defs.h" +#include "../xrCore/intrusive_ptr.h" + // refs class ISpatial; +using ISpatialShared = intrusive_ptr; + class ICollisionForm; class CObject; @@ -23,22 +26,12 @@ struct hdrCFORM; class XRCDB_API CObjectSpace { private: - // Debug - xrCriticalSection Lock; CDB::MODEL Static; Fbox m_BoundingVolume; - xrXRC xrc; // MT: dangerous - collide::rq_results r_temp; // MT: dangerous - xr_vector r_spatial; // MT: dangerous public: - #ifdef DEBUG - FactoryPtr *m_pRender; - //ref_shader sh_debug; - //clQueryCollision q_debug; // MT: dangerous - //xr_vector > dbg_S; // MT: dangerous + FactoryPtr *m_pRender; #endif - private: BOOL _RayTest(const Fvector& start, const Fvector& dir, float range, collide::rq_target tgt, collide::ray_cache* cache, CObject* ignore_object); @@ -59,7 +52,7 @@ class XRCDB_API CObjectSpace void Load(CDB::build_callback build_callback); void Load(LPCSTR path, LPCSTR fname, CDB::build_callback build_callback); void Load(IReader* R, CDB::build_callback build_callback); - void Create(Fvector* verts, CDB::TRI* tris, const hdrCFORM& H, CDB::build_callback build_callback); + void Create(Fvector* verts, CDB::TRI* tris, const hdrCFORM& H, CDB::build_callback build_callback, bool init_bounds = true); // Occluded/No BOOL RayTest(const Fvector& start, const Fvector& dir, float range, collide::rq_target tgt, collide::ray_cache* cache, CObject* ignore_object); @@ -83,7 +76,7 @@ class XRCDB_API CObjectSpace int GetNearest(xr_vector& q_nearest, ICollisionForm* obj, float range); int GetNearest(xr_vector& q_nearest, const Fvector& point, float range, CObject* ignore_object); - int GetNearest(xr_vector& q_spatial, xr_vector& q_nearest, const Fvector& point, float range, + int GetNearest(xr_vector& q_spatial, xr_vector& q_nearest, const Fvector& point, float range, CObject* ignore_object); CDB::TRI* GetStaticTris() { return Static.get_tris(); } @@ -94,10 +87,6 @@ class XRCDB_API CObjectSpace // Debugging #ifdef DEBUG - void dbgRender (); - //ref_shader dbgGetShader () { return sh_debug; } + void dbgRender(); #endif }; - - -#endif //__XR_AREA_H__ diff --git a/src/xrCDB/xr_area_query.cpp b/src/xrCDB/xr_area_query.cpp deleted file mode 100644 index 0785e5b85d..0000000000 --- a/src/xrCDB/xr_area_query.cpp +++ /dev/null @@ -1,97 +0,0 @@ -#include "stdafx.h" -#include "xr_area.h" -#include "frustum.h" - -#include "../xrCore/_vector3d_ext.h" - -using namespace collide; - -bool CObjectSpace::BoxQuery(Fvector const& box_center, - Fvector const& box_z_axis, - Fvector const& box_y_axis, - Fvector const& box_sizes, - xr_vector* out_tris) -{ - Fvector z_axis = box_z_axis; - z_axis.normalize(); - Fvector y_axis = box_y_axis; - y_axis.normalize(); - Fvector x_axis; - x_axis.crossproduct(box_y_axis, box_z_axis).normalize(); - - Fplane planes[6]; - enum { left_plane, right_plane, top_plane, bottom_plane, front_plane, near_plane }; - - planes[left_plane].build(box_center - (x_axis * (box_sizes.x * 0.5f)), - x_axis); - planes[right_plane].build(box_center + (x_axis * (box_sizes.x * 0.5f)), x_axis); - planes[top_plane].build(box_center + (y_axis * (box_sizes.y * 0.5f)), y_axis); - planes[bottom_plane].build(box_center - (y_axis * (box_sizes.y * 0.5f)), - y_axis); - planes[front_plane].build(box_center - (z_axis * (box_sizes.z * 0.5f)), - z_axis); - planes[near_plane].build(box_center + (z_axis * (box_sizes.z * 0.5f)), z_axis); - - CFrustum frustum; - frustum.CreateFromPlanes(planes, sizeof(planes) / sizeof(planes[0])); - - xrc.frustum_options(CDB::OPT_FULL_TEST); - xrc.frustum_query(&Static, frustum); - - if (out_tris) - { - for (CDB::RESULT* result = xrc.r_begin(); - result != xrc.r_end(); - ++result) - { - out_tris->push_back(result->verts[0]); - out_tris->push_back(result->verts[1]); - out_tris->push_back(result->verts[2]); - } - } - - return !!xrc.r_count(); -} - - -/* -const u32 clStatic = clQUERY_STATIC+clGET_TRIS; - -void CObjectSpace::BoxQuery (collide::rq_results& r_dest, const Fbox& B, const Fmatrix& M, u32 flags) -{ - Fvector bc,bd; - Fbox xf; - xf.xform (B,M); - xf.get_CD (bc,bd); - - q_result.Clear (); - xrc.box_options ( - (flags&clCOARSE?0:CDB::OPT_FULL_TEST)| - (flags&clQUERY_ONLYFIRST?CDB::OPT_ONLYFIRST:0) - ); - - if ((flags&clStatic) == clStatic) - { - xrc.box_query (&Static, bc, bd); - if (xrc.r_count()) - { - CDB::RESULT* it =xrc.r_begin(); - CDB::RESULT* end=xrc.r_end (); - for (; it!=end; it++) - q_result.AddTri(&Static.get_tris() [it->id],Static.get_verts()); - } - }; - - if (flags&clQUERY_DYNAMIC) - { - // Traverse object database - g_SpatialSpace->q_box (r_spatial,0,STYPE_COLLIDEABLE,bc,bd); - - // Determine visibility for dynamic part of scene - for (u32 o_it=0; o_itdcast_CObject (); - if (0==collidable) continue; - collidable->collidable.model->_BoxQuery (B,M,flags); - } - }; -} -*/ diff --git a/src/xrCDB/xr_area_raypick.cpp b/src/xrCDB/xr_area_raypick.cpp index fd2e2b98ae..fe3157a2bf 100644 --- a/src/xrCDB/xr_area_raypick.cpp +++ b/src/xrCDB/xr_area_raypick.cpp @@ -5,9 +5,9 @@ #include "../xrengine/xr_object.h" #include "../xrengine/cl_intersect.h" #include "d3d9types.h" -//#include "igame_level.h" -//#include "x_ray.h" -//#include "GameFont.h" + +#include "../xrCore/_vector3d_ext.h" + #ifdef DEBUG static BOOL _cdb_bDebug = false; extern XRCDB_API BOOL *cdb_bDebug = &_cdb_bDebug; @@ -18,16 +18,19 @@ bool bDebug() #endif using namespace collide; +namespace CObjectSpaceThreadData { + thread_local xrXRC xrc; + thread_local collide::rq_results r_temp; + thread_local xr_vector r_spatial; +} + //-------------------------------------------------------------------------------- // RayTest - Occluded/No //-------------------------------------------------------------------------------- BOOL CObjectSpace::RayTest(const Fvector& start, const Fvector& dir, float range, collide::rq_target tgt, collide::ray_cache* cache, CObject* ignore_object) { - Lock.Enter(); BOOL _ret = _RayTest(start, dir, range, tgt, cache, ignore_object); - r_spatial.clear(); - Lock.Leave(); return _ret; } @@ -35,9 +38,9 @@ BOOL CObjectSpace::_RayTest(const Fvector& start, const Fvector& dir, float rang collide::ray_cache* cache, CObject* ignore_object) { VERIFY(_abs(dir.magnitude()-1)q_ray(r_spatial, 0, d_flags, start, dir, range); + g_SpatialSpace->q_ray(CObjectSpaceThreadData::r_spatial, 0, d_flags, start, dir, range); // Determine visibility for dynamic part of scene - for (u32 o_it = 0; o_it < r_spatial.size(); o_it++) + for (u32 o_it = 0; o_it < CObjectSpaceThreadData::r_spatial.size(); o_it++) { - ISpatial* spatial = r_spatial[o_it]; + ISpatialShared spatial = CObjectSpaceThreadData::r_spatial[o_it]; CObject* collidable = spatial->dcast_CObject(); - if (collidable && (collidable != ignore_object)) + if (collidable && (collidable != ignore_object) && collidable->collidable.model) { ECollisionFormType tp = collidable->collidable.model->Type(); - if ((tgt & (rqtObject | rqtObstacle)) && (tp == cftObject) && collidable - ->collidable.model->_RayQuery(Q, r_temp)) + if ((tgt & (rqtObject | rqtObstacle)) && (tp == cftObject) && collidable->collidable.model->_RayQuery(Q, CObjectSpaceThreadData::r_temp)) return TRUE; - if ((tgt & rqtShape) && (tp == cftShape) && collidable->collidable.model->_RayQuery(Q, r_temp)) return + + if ((tgt & rqtShape) && (tp == cftShape) && collidable->collidable.model->_RayQuery(Q, CObjectSpaceThreadData::r_temp)) return TRUE; } } @@ -83,8 +86,8 @@ BOOL CObjectSpace::_RayTest(const Fvector& start, const Fvector& dir, float rang } // 2. Polygon doesn't pick - real database query - xrc.ray_query(&Static, start, dir, range); - if (0 == xrc.r_count()) + CObjectSpaceThreadData::xrc.ray_query(&Static, start, dir, range); + if (0 == CObjectSpaceThreadData::xrc.r_count()) { cache->set(start, dir, range,FALSE); return FALSE; @@ -92,8 +95,8 @@ BOOL CObjectSpace::_RayTest(const Fvector& start, const Fvector& dir, float rang else { // cache polygon - cache->set(start, dir, range,TRUE); - CDB::RESULT* R = xrc.r_begin(); + cache->set(start, dir, range, TRUE); + CDB::RESULT* R = CObjectSpaceThreadData::xrc.r_begin(); CDB::TRI& T = Static.get_tris()[R->id]; Fvector* V = Static.get_verts(); cache->verts[0].set(V[T.verts[0]]); @@ -104,8 +107,8 @@ BOOL CObjectSpace::_RayTest(const Fvector& start, const Fvector& dir, float rang } else { - xrc.ray_query(&Static, start, dir, range); - return xrc.r_count(); + CObjectSpaceThreadData::xrc.ray_query(&Static, start, dir, range); + return CObjectSpaceThreadData::xrc.r_count(); } } return FALSE; @@ -126,10 +129,7 @@ BOOL CObjectSpace::RayPick(const Fvector& start, const Fvector& dir, float range BOOL CObjectSpace::RayPick(const Fvector& start, const Fvector& dir, float range, rq_target tgt, rq_result& R, xr_vector& ignore_objects) { - Lock.Enter(); BOOL _res = _RayPick(start, dir, range, tgt, R, ignore_objects); - r_spatial.clear(); - Lock.Leave(); return _res; } @@ -145,16 +145,16 @@ BOOL CObjectSpace::_RayPick(const Fvector& start, const Fvector& dir, float rang BOOL CObjectSpace::_RayPick(const Fvector& start, const Fvector& dir, float range, rq_target tgt, rq_result& R, xr_vector& ignore_objects) { - r_temp.r_clear(); + CObjectSpaceThreadData::r_temp.r_clear(); R.O = 0; R.range = range; R.element = -1; // static test if (tgt & rqtStatic) { - xrc.ray_options(CDB::OPT_ONLYNEAREST | CDB::OPT_CULL); - xrc.ray_query(&Static, start, dir, range); - if (xrc.r_count()) R.set_if_less(xrc.r_begin()); + CObjectSpaceThreadData::xrc.ray_options(CDB::OPT_ONLYNEAREST | CDB::OPT_CULL); + CObjectSpaceThreadData::xrc.ray_query(&Static, start, dir, range); + if (CObjectSpaceThreadData::xrc.r_count()) R.set_if_less(CObjectSpaceThreadData::xrc.r_begin()); } // dynamic test if (tgt & rqtDyn) @@ -163,11 +163,11 @@ BOOL CObjectSpace::_RayPick(const Fvector& start, const Fvector& dir, float rang // traverse object database u32 d_flags = STYPE_COLLIDEABLE | ((tgt & rqtObstacle) ? STYPE_OBSTACLE : 0) | ( (tgt & rqtShape) ? STYPE_SHAPE : 0); - g_SpatialSpace->q_ray(r_spatial, 0, d_flags, start, dir, range); + g_SpatialSpace->q_ray(CObjectSpaceThreadData::r_spatial, 0, d_flags, start, dir, range); // Determine visibility for dynamic part of scene - for (u32 o_it = 0; o_it < r_spatial.size(); o_it++) + for (u32 o_it = 0; o_it < CObjectSpaceThreadData::r_spatial.size(); o_it++) { - ISpatial* spatial = r_spatial[o_it]; + ISpatialShared spatial = CObjectSpaceThreadData::r_spatial[o_it]; CObject* collidable = spatial->dcast_CObject(); if (0 == collidable) continue; @@ -186,10 +186,10 @@ BOOL CObjectSpace::_RayPick(const Fvector& start, const Fvector& dir, float rang { u32 C = D3DCOLOR_XRGB(64, 64, 64); Q.range = R.range; - if (collidable->collidable.model->_RayQuery(Q, r_temp)) + if (collidable->collidable.model->_RayQuery(Q, CObjectSpaceThreadData::r_temp)) { C = D3DCOLOR_XRGB(128, 128, 196); - R.set_if_less(r_temp.r_begin()); + R.set_if_less(CObjectSpaceThreadData::r_temp.r_begin()); } #ifdef DEBUG if (bDebug()) { @@ -210,10 +210,7 @@ BOOL CObjectSpace::_RayPick(const Fvector& start, const Fvector& dir, float rang BOOL CObjectSpace::RayQuery(collide::rq_results& dest, const collide::ray_defs& R, collide::rq_callback* CB, LPVOID user_data, collide::test_callback* tb, CObject* ignore_object) { - Lock.Enter(); BOOL _res = _RayQuery2(dest, R, CB, user_data, tb, ignore_object); - r_spatial.clear_not_free(); - Lock.Leave(); return (_res); } @@ -222,7 +219,7 @@ BOOL CObjectSpace::_RayQuery2(collide::rq_results& r_dest, const collide::ray_de { // initialize query r_dest.r_clear(); - r_temp.r_clear(); + CObjectSpaceThreadData::r_temp.r_clear(); rq_target s_mask = rqtStatic; rq_target d_mask = rq_target(((R.tgt & rqtObject) ? rqtObject : rqtNone) | @@ -234,40 +231,42 @@ BOOL CObjectSpace::_RayQuery2(collide::rq_results& r_dest, const collide::ray_de // Test static if (R.tgt & s_mask) { - xrc.ray_options(R.flags); - xrc.ray_query(&Static, R.start, R.dir, R.range); - if (xrc.r_count()) + CObjectSpaceThreadData::xrc.ray_options(R.flags); + CObjectSpaceThreadData::xrc.ray_query(&Static, R.start, R.dir, R.range); + if (CObjectSpaceThreadData::xrc.r_count()) { - CDB::RESULT* _I = xrc.r_begin(); - CDB::RESULT* _E = xrc.r_end(); + CDB::RESULT* _I = CObjectSpaceThreadData::xrc.r_begin(); + CDB::RESULT* _E = CObjectSpaceThreadData::xrc.r_end(); for (; _I != _E; _I++) - r_temp.append_result(rq_result().set(0, _I->range, _I->id)); + CObjectSpaceThreadData::r_temp.append_result(rq_result().set(0, _I->range, _I->id)); } } // Test dynamic if (R.tgt & d_mask) { // Traverse object database - g_SpatialSpace->q_ray(r_spatial, 0, d_flags, R.start, R.dir, R.range); - for (u32 o_it = 0; o_it < r_spatial.size(); o_it++) + g_SpatialSpace->q_ray(CObjectSpaceThreadData::r_spatial, 0, d_flags, R.start, R.dir, R.range); + for (u32 o_it = 0; o_it < CObjectSpaceThreadData::r_spatial.size(); o_it++) { - CObject* collidable = r_spatial[o_it]->dcast_CObject(); + CObject* collidable = CObjectSpaceThreadData::r_spatial[o_it]->dcast_CObject(); if (0 == collidable) continue; if (collidable == ignore_object) continue; - ICollisionForm* cform = collidable->collidable.model; - ECollisionFormType tp = collidable->collidable.model->Type(); - if (((R.tgt & (rqtObject | rqtObstacle)) && (tp == cftObject)) || ((R.tgt & rqtShape) && (tp == cftShape))) + + if (ICollisionForm* cform = collidable->collidable.model) { - if (tb && !tb(R, collidable, user_data))continue; - cform->_RayQuery(R, r_temp); + ECollisionFormType tp = cform->Type(); + if (((R.tgt & (rqtObject | rqtObstacle)) && (tp == cftObject)) || ((R.tgt & rqtShape) && (tp == cftShape))) { + if (tb && !tb(R, collidable, user_data))continue; + cform->_RayQuery(R, CObjectSpaceThreadData::r_temp); + } } } } - if (r_temp.r_count()) + if (CObjectSpaceThreadData::r_temp.r_count()) { - r_temp.r_sort(); - collide::rq_result* _I = r_temp.r_begin(); - collide::rq_result* _E = r_temp.r_end(); + CObjectSpaceThreadData::r_temp.r_sort(); + collide::rq_result* _I = CObjectSpaceThreadData::r_temp.r_begin(); + collide::rq_result* _E = CObjectSpaceThreadData::r_temp.r_end(); for (; _I != _E; _I++) { r_dest.append_result(*_I); @@ -296,27 +295,27 @@ BOOL CObjectSpace::_RayQuery3(collide::rq_results& r_dest, const collide::ray_de do { - r_temp.r_clear(); + CObjectSpaceThreadData::r_temp.r_clear(); if (R.tgt & s_mask) { // static test allowed // test static - xrc.ray_options(s_rd.flags); - xrc.ray_query(&Static, s_rd.start, s_rd.dir, s_rd.range); + CObjectSpaceThreadData::xrc.ray_options(s_rd.flags); + CObjectSpaceThreadData::xrc.ray_query(&Static, s_rd.start, s_rd.dir, s_rd.range); - if (xrc.r_count()) + if (CObjectSpaceThreadData::xrc.r_count()) { - VERIFY(xrc.r_count()==1); + VERIFY(CObjectSpaceThreadData::xrc.r_count()==1); rq_result s_res; - s_res.set(0, xrc.r_begin()->range, xrc.r_begin()->id); + s_res.set(0, CObjectSpaceThreadData::xrc.r_begin()->range, CObjectSpaceThreadData::xrc.r_begin()->id); // update dynamic test range d_rd.range = s_res.range; // set next static start & range s_rd.range -= (s_res.range + EPS_L); s_rd.start.mad(s_rd.dir, s_res.range + EPS_L); s_res.range = R.range - s_rd.range - EPS_L; - r_temp.append_result(s_res); + CObjectSpaceThreadData::r_temp.append_result(s_res); } else { @@ -327,10 +326,10 @@ BOOL CObjectSpace::_RayQuery3(collide::rq_results& r_dest, const collide::ray_de if (R.tgt & d_mask) { // Traverse object database - g_SpatialSpace->q_ray(r_spatial, 0, d_flags, d_rd.start, d_rd.dir, d_rd.range); - for (u32 o_it = 0; o_it < r_spatial.size(); o_it++) + g_SpatialSpace->q_ray(CObjectSpaceThreadData::r_spatial, 0, d_flags, d_rd.start, d_rd.dir, d_rd.range); + for (u32 o_it = 0; o_it < CObjectSpaceThreadData::r_spatial.size(); o_it++) { - CObject* collidable = r_spatial[o_it]->dcast_CObject(); + CObject* collidable = CObjectSpaceThreadData::r_spatial[o_it]->dcast_CObject(); if (0 == collidable) continue; if (collidable == ignore_object) continue; ICollisionForm* cform = collidable->collidable.model; @@ -339,11 +338,11 @@ BOOL CObjectSpace::_RayQuery3(collide::rq_results& r_dest, const collide::ray_de ))) { if (tb && !tb(d_rd, collidable, user_data))continue; - u32 r_cnt = r_temp.r_count(); - cform->_RayQuery(d_rd, r_temp); - for (int k = r_cnt; k < r_temp.r_count(); k++) + u32 r_cnt = CObjectSpaceThreadData::r_temp.r_count(); + cform->_RayQuery(d_rd, CObjectSpaceThreadData::r_temp); + for (int k = r_cnt; k < CObjectSpaceThreadData::r_temp.r_count(); k++) { - rq_result& d_res = *(r_temp.r_begin() + k); + rq_result& d_res = *(CObjectSpaceThreadData::r_temp.r_begin() + k); d_res.range += d_range; } } @@ -352,11 +351,11 @@ BOOL CObjectSpace::_RayQuery3(collide::rq_results& r_dest, const collide::ray_de // set dynamic ray def d_rd.start = s_rd.start; d_range = R.range - s_rd.range; - if (r_temp.r_count()) + if (CObjectSpaceThreadData::r_temp.r_count()) { - r_temp.r_sort(); - collide::rq_result* _I = r_temp.r_begin(); - collide::rq_result* _E = r_temp.r_end(); + CObjectSpaceThreadData::r_temp.r_sort(); + collide::rq_result* _I = CObjectSpaceThreadData::r_temp.r_begin(); + collide::rq_result* _E = CObjectSpaceThreadData::r_temp.r_end(); for (; _I != _E; _I++) { r_dest.append_result(*_I); @@ -366,7 +365,7 @@ BOOL CObjectSpace::_RayQuery3(collide::rq_results& r_dest, const collide::ray_de } if ((R.flags & (CDB::OPT_ONLYNEAREST | CDB::OPT_ONLYFIRST)) && r_dest.r_count()) return r_dest.r_count(); } - while (r_temp.r_count()); + while (CObjectSpaceThreadData::r_temp.r_count()); return r_dest.r_count(); } @@ -379,7 +378,7 @@ BOOL CObjectSpace::_RayQuery(collide::rq_results& r_dest, const collide::ray_def #endif // initialize query r_dest.r_clear(); - r_temp.r_clear(); + CObjectSpaceThreadData::r_temp.r_clear(); Flags32 sd_test; sd_test.assign(R.tgt); @@ -404,11 +403,11 @@ BOOL CObjectSpace::_RayQuery(collide::rq_results& r_dest, const collide::ray_def // Test static model if (s_rd.range > EPS) { - xrc.ray_options(s_rd.flags); - xrc.ray_query(&Static, s_rd.start, s_rd.dir, s_rd.range); - if (xrc.r_count()) + CObjectSpaceThreadData::xrc.ray_options(s_rd.flags); + CObjectSpaceThreadData::xrc.ray_query(&Static, s_rd.start, s_rd.dir, s_rd.range); + if (CObjectSpaceThreadData::xrc.r_count()) { - if (s_res.set_if_less(xrc.r_begin())) + if (s_res.set_if_less(CObjectSpaceThreadData::xrc.r_begin())) { // set new static start & range s_rd.range -= (s_res.range + EPS_L); @@ -425,16 +424,16 @@ BOOL CObjectSpace::_RayQuery(collide::rq_results& r_dest, const collide::ray_def } if ((R.tgt & d_mask) && sd_test.is_any(d_mask) && (next_test & d_mask)) { - r_temp.r_clear(); + CObjectSpaceThreadData::r_temp.r_clear(); if (d_rd.range > EPS) { // Traverse object database - g_SpatialSpace->q_ray(r_spatial, 0, d_flags, d_rd.start, d_rd.dir, d_rd.range); + g_SpatialSpace->q_ray(CObjectSpaceThreadData::r_spatial, 0, d_flags, d_rd.start, d_rd.dir, d_rd.range); // Determine visibility for dynamic part of scene - for (u32 o_it = 0; o_it < r_spatial.size(); o_it++) + for (u32 o_it = 0; o_it < CObjectSpaceThreadData::r_spatial.size(); o_it++) { - CObject* collidable = r_spatial[o_it]->dcast_CObject(); + CObject* collidable = CObjectSpaceThreadData::r_spatial[o_it]->dcast_CObject(); if (0 == collidable) continue; if (collidable == ignore_object) continue; ICollisionForm* cform = collidable->collidable.model; @@ -443,18 +442,18 @@ BOOL CObjectSpace::_RayQuery(collide::rq_results& r_dest, const collide::ray_def cftShape))) { if (tb && !tb(d_rd, collidable, user_data))continue; - cform->_RayQuery(d_rd, r_temp); + cform->_RayQuery(d_rd, CObjectSpaceThreadData::r_temp); } #ifdef DEBUG - if (!((0==r_temp.r_count()) || (r_temp.r_count()&&(fis_zero(r_temp.r_begin()->range, EPS)||(r_temp.r_begin()->range>=0.f))))) - Debug.fatal(DEBUG_INFO,"Invalid RayQuery dynamic range: %f (%f). /#2/",r_temp.r_begin()->range,d_rd.range); + if (!((0==CObjectSpaceThreadData::r_temp.r_count()) || (CObjectSpaceThreadData::r_temp.r_count()&&(fis_zero(CObjectSpaceThreadData::r_temp.r_begin()->range, EPS)||(CObjectSpaceThreadData::r_temp.r_begin()->range>=0.f))))) + Debug.fatal(DEBUG_INFO,"Invalid RayQuery dynamic range: %f (%f). /#2/",CObjectSpaceThreadData::r_temp.r_begin()->range,d_rd.range); #endif } } - if (r_temp.r_count()) + if (CObjectSpaceThreadData::r_temp.r_count()) { // set new dynamic start & range - rq_result& d_res = *r_temp.r_begin(); + rq_result& d_res = *CObjectSpaceThreadData::r_temp.r_begin(); d_rd.range -= (d_res.range + EPS_L); d_rd.start.mad(d_rd.dir, d_res.range + EPS_L); d_res.range = R.range - d_rd.range - EPS_L; @@ -468,10 +467,10 @@ BOOL CObjectSpace::_RayQuery(collide::rq_results& r_dest, const collide::ray_def sd_test.set(d_mask,FALSE); } } - if (s_res.valid() && r_temp.r_count()) + if (s_res.valid() && CObjectSpaceThreadData::r_temp.r_count()) { // all test return result - if (s_res.range < r_temp.r_begin()->range) + if (s_res.range < CObjectSpaceThreadData::r_temp.r_begin()->range) { // static nearer BOOL need_calc = CB ? CB(s_res, user_data) : TRUE; @@ -481,9 +480,9 @@ BOOL CObjectSpace::_RayQuery(collide::rq_results& r_dest, const collide::ray_def else { // dynamic nearer - BOOL need_calc = CB ? CB(*r_temp.r_begin(), user_data) : TRUE; + BOOL need_calc = CB ? CB(*CObjectSpaceThreadData::r_temp.r_begin(), user_data) : TRUE; next_test = need_calc ? d_mask : rqtNone; - r_dest.append_result(*r_temp.r_begin()); + r_dest.append_result(*CObjectSpaceThreadData::r_temp.r_begin()); } } else if (s_res.valid()) @@ -493,12 +492,12 @@ BOOL CObjectSpace::_RayQuery(collide::rq_results& r_dest, const collide::ray_def next_test = need_calc ? s_mask : rqtNone; r_dest.append_result(s_res); } - else if (r_temp.r_count()) + else if (CObjectSpaceThreadData::r_temp.r_count()) { // only dynamic return result - BOOL need_calc = CB ? CB(*r_temp.r_begin(), user_data) : TRUE; + BOOL need_calc = CB ? CB(*CObjectSpaceThreadData::r_temp.r_begin(), user_data) : TRUE; next_test = need_calc ? d_mask : rqtNone; - r_dest.append_result(*r_temp.r_begin()); + r_dest.append_result(*CObjectSpaceThreadData::r_temp.r_begin()); } else { @@ -517,3 +516,58 @@ BOOL CObjectSpace::RayQuery(collide::rq_results& r_dest, ICollisionForm* target, r_dest.r_clear(); return target->_RayQuery(R, r_dest); } + +bool CObjectSpace::BoxQuery(Fvector const& box_center, + Fvector const& box_z_axis, + Fvector const& box_y_axis, + Fvector const& box_sizes, + xr_vector* out_tris) +{ + Fvector z_axis = box_z_axis; + z_axis.normalize(); + Fvector y_axis = box_y_axis; + y_axis.normalize(); + Fvector x_axis; + x_axis.crossproduct(box_y_axis, box_z_axis).normalize(); + + Fplane planes[6]; + enum { left_plane, right_plane, top_plane, bottom_plane, front_plane, near_plane }; + + planes[left_plane].build(box_center - (x_axis * (box_sizes.x * 0.5f)), -x_axis); + planes[right_plane].build(box_center + (x_axis * (box_sizes.x * 0.5f)), x_axis); + planes[top_plane].build(box_center + (y_axis * (box_sizes.y * 0.5f)), y_axis); + planes[bottom_plane].build(box_center - (y_axis * (box_sizes.y * 0.5f)), -y_axis); + planes[front_plane].build(box_center - (z_axis * (box_sizes.z * 0.5f)), -z_axis); + planes[near_plane].build(box_center + (z_axis * (box_sizes.z * 0.5f)), z_axis); + + CFrustum frustum; + frustum.CreateFromPlanes(planes, sizeof(planes) / sizeof(planes[0])); + + CObjectSpaceThreadData::xrc.frustum_options(CDB::OPT_FULL_TEST); + CObjectSpaceThreadData::xrc.frustum_query(&Static, frustum); + + if (out_tris) + { + for (CDB::RESULT* result = CObjectSpaceThreadData::xrc.r_begin(); + result != CObjectSpaceThreadData::xrc.r_end(); + ++result) + { + out_tris->push_back(result->verts[0]); + out_tris->push_back(result->verts[1]); + out_tris->push_back(result->verts[2]); + } + } + + return !!CObjectSpaceThreadData::xrc.r_count(); +} + +int CObjectSpace::GetNearest(xr_vector& q_nearest, const Fvector& point, float range, CObject* ignore_object) +{ + return GetNearest( + CObjectSpaceThreadData::r_spatial, + q_nearest, + point, + range, + ignore_object + ); +} diff --git a/src/xrCPU_Pipe/xrCPU_Pipe.vcxproj b/src/xrCPU_Pipe/xrCPU_Pipe.vcxproj index 2f2ad08fac..9212f86808 100644 --- a/src/xrCPU_Pipe/xrCPU_Pipe.vcxproj +++ b/src/xrCPU_Pipe/xrCPU_Pipe.vcxproj @@ -13,6 +13,10 @@ Release x64 + + VerifiedDX11ASAN + x64 + VerifiedDX11 x64 @@ -58,6 +62,15 @@ false x64 + + StaticLibrary + v143 + false + MultiByte + false + x64 + true + StaticLibrary v143 @@ -88,6 +101,11 @@ + + + + + @@ -117,6 +135,11 @@ $(xrGameDir)bin_dbg\$(Platform)\$(Configuration)\ $(xrIntDir)$(ProjectName)\ + + false + $(xrGameDir)bin_dbg\$(Platform)\$(Configuration)\ + $(xrIntDir)$(ProjectName)\ + false $(xrGameDir)bin_dbg\$(Platform)\$(Configuration)\ @@ -232,7 +255,7 @@ false false $(xrSdkDir)include;%(AdditionalIncludeDirectories) - USE_VERIFY_IN_RELEASE;WIN32;NDEBUG;_WINDOWS;_USRDLL;XRCPU_PIPE_EXPORTS;_SECURE_SCL=0;%(PreprocessorDefinitions) + XRCORE_PROFILER;USE_VERIFY_IN_RELEASE;WIN32;NDEBUG;_WINDOWS;_USRDLL;XRCPU_PIPE_EXPORTS;_SECURE_SCL=0;%(PreprocessorDefinitions) NotSet Use stdafx.h @@ -281,7 +304,7 @@ false false $(xrSdkDir)include;%(AdditionalIncludeDirectories) - USE_VERIFY_IN_RELEASE;WIN32;NDEBUG;_WINDOWS;_USRDLL;XRCPU_PIPE_EXPORTS;_SECURE_SCL=0;%(PreprocessorDefinitions) + XRCORE_PROFILER;USE_VERIFY_IN_RELEASE;WIN32;NDEBUG;_WINDOWS;_USRDLL;XRCPU_PIPE_EXPORTS;_SECURE_SCL=0;%(PreprocessorDefinitions) NotSet Use stdafx.h @@ -314,6 +337,55 @@ true + + + NDEBUG;%(PreprocessorDefinitions) + true + true + $(OutDir)$(TargetName).tlb + + + Disabled + Disabled + false + Neither + false + false + false + $(xrSdkDir)include;%(AdditionalIncludeDirectories) + XRCORE_PROFILER;_DISABLE_VECTOR_ANNOTATION;_DISABLE_STRING_ANNOTATION;USE_VERIFY_IN_RELEASE;WIN32;NDEBUG;_WINDOWS;_USRDLL;XRCPU_PIPE_EXPORTS;_SECURE_SCL=0;%(PreprocessorDefinitions) + NotSet + Use + stdafx.h + ProgramDatabase + 4995 + USE_LUAJIT_ONE + true + Level4 + false + MultiThreadedDLL + false + stdcpp17 + true + + + NDEBUG;%(PreprocessorDefinitions) + 0x0419 + + + /MACHINE:X64 %(AdditionalOptions) + true + $(xrSdkDir)libraries;$(xrLibDir);%(AdditionalLibraryDirectories) + NotSet + true + true + true + Default + false + $(xrLibDir)$(TargetName).lib + true + + NDEBUG;%(PreprocessorDefinitions) @@ -369,6 +441,7 @@ Create Create Create + Create Create diff --git a/src/xrCore/ChooseTypes.H b/src/xrCore/ChooseTypes.H index 7c5c8da00b..9d5202b0a2 100644 --- a/src/xrCore/ChooseTypes.H +++ b/src/xrCore/ChooseTypes.H @@ -46,10 +46,10 @@ struct SChooseItem DEFINE_VECTOR(SChooseItem, ChooseItemVec, ChooseItemVecIt); // typedef -typedef fastdelegate::FastDelegate2 TOnChooseFillItems; -typedef fastdelegate::FastDelegate2 TOnChooseSelectItem; -typedef fastdelegate::FastDelegate3 TOnDrawThumbnail; -typedef fastdelegate::FastDelegate0<> TOnChooseClose; +typedef xr_delegate TOnChooseFillItems; +typedef xr_delegate TOnChooseSelectItem; +typedef xr_delegate TOnDrawThumbnail; +typedef xr_delegate TOnChooseClose; typedef void (*TOnChooseFillEvents)(); diff --git a/src/xrCore/DateTime.cpp b/src/xrCore/DateTime.cpp new file mode 100644 index 0000000000..6e319ae027 --- /dev/null +++ b/src/xrCore/DateTime.cpp @@ -0,0 +1,68 @@ +#include "stdafx.h" +#include "DateTime.hpp" + +Time::Time() +{ + t = time(nullptr); + aTm = *localtime(&t); +} + +int Time::GetSeconds() const +{ + return aTm.tm_sec; +} + +int Time::GetMinutes() const +{ + return aTm.tm_min; +} + +int Time::GetHours() const +{ + return aTm.tm_hour; +} + +int Time::GetDay() const +{ + return aTm.tm_mday; +} + +int Time::GetMonth() const +{ + return aTm.tm_mon + 1; +} + +int Time::GetYear() const +{ + return aTm.tm_year + 1900; +} + +Time::string Time::GetSecondsString() const +{ + return (GetSeconds() < 10) ? "0" + xr_string::ToString(GetSeconds()) : xr_string::ToString(GetSeconds()); +} + +Time::string Time::GetMinutesString() const +{ + return (GetMinutes() < 10) ? "0" + xr_string::ToString(GetMinutes()) : xr_string::ToString(GetMinutes()); +} + +Time::string Time::GetHoursString() const +{ + return (GetHours() < 10) ? "0" + xr_string::ToString(GetHours()) : xr_string::ToString(GetHours()); +} + +Time::string Time::GetDayString() const +{ + return (GetDay() < 10) ? "0" + xr_string::ToString(GetDay()) : xr_string::ToString(GetDay()); +} + +Time::string Time::GetMonthString() const +{ + return (GetMonth() < 10) ? "0" + xr_string::ToString(GetMonth()) : xr_string::ToString(GetMonth()); +} + +Time::string Time::GetYearString() const +{ + return xr_string::ToString(GetYear()); +} \ No newline at end of file diff --git a/src/xrCore/DateTime.hpp b/src/xrCore/DateTime.hpp new file mode 100644 index 0000000000..cc82c8d331 --- /dev/null +++ b/src/xrCore/DateTime.hpp @@ -0,0 +1,32 @@ +#pragma once +#include +#include + +class XRCORE_API Time +{ +private: + time_t t; + tm aTm; + using string = xr_string; + +public: + Time(); + + // Convert time to string + string GetSecondsString() const; + string GetMinutesString() const; + string GetHoursString() const; + + // Convert date to string + string GetDayString() const; + string GetMonthString() const; + string GetYearString() const; + + int GetSeconds() const; + int GetMinutes() const; + int GetHours() const; + + int GetDay() const; + int GetMonth() const; + int GetYear() const; +}; \ No newline at end of file diff --git a/src/xrCore/FS.cpp b/src/xrCore/FS.cpp index 6107c24858..c6b0a68cd1 100644 --- a/src/xrCore/FS.cpp +++ b/src/xrCore/FS.cpp @@ -22,9 +22,12 @@ XRCORE_API u32 g_file_mapped_memory = 0; u32 g_file_mapped_count = 0; typedef xr_map > FILE_MAPPINGS; FILE_MAPPINGS g_file_mappings; +static xrCriticalSection CSFileMapping; void register_file_mapping(void* address, const u32& size, LPCSTR file_name) { + xrCriticalSectionGuard guard(CSFileMapping); + FILE_MAPPINGS::const_iterator I = g_file_mappings.find(*(u32*)&address); VERIFY(I == g_file_mappings.end()); g_file_mappings.insert(std::make_pair(*(u32*)&address, std::make_pair(size, shared_str(file_name)))); @@ -43,6 +46,8 @@ void register_file_mapping(void* address, const u32& size, LPCSTR file_name) void unregister_file_mapping(void* address, const u32& size) { + xrCriticalSectionGuard guard(CSFileMapping); + FILE_MAPPINGS::iterator I = g_file_mappings.find(*(u32*)&address); VERIFY(I != g_file_mappings.end()); // VERIFY2 ((*I).second.first == size,make_string("file mapping sizes are different: %d -> %d",(*I).second.first,size)); diff --git a/src/xrCore/FTimer.cpp b/src/xrCore/FTimer.cpp index a8022d2e5e..0703d94706 100644 --- a/src/xrCore/FTimer.cpp +++ b/src/xrCore/FTimer.cpp @@ -54,5 +54,5 @@ void pauseMngr::UnRegister(CTimer_paused& t) { const auto it = std::find(m_timers.cbegin(), m_timers.cend(), &t); if (it != m_timers.end()) - m_timers.erase(it); + m_timers.erase_fast(it); } diff --git a/src/xrCore/FTimer.h b/src/xrCore/FTimer.h index c981b20da3..7bd2d37c32 100644 --- a/src/xrCore/FTimer.h +++ b/src/xrCore/FTimer.h @@ -131,6 +131,10 @@ class XRCORE_API CTimer : public CTimerBase return (u32(GetElapsed_ticks() * u64(1000) / CPU::qpc_freq)); } + IC float GetElapsed_ms_f() const { + return float(double(GetElapsed_ticks() * u64(1000)) / CPU::qpc_freq); + } + IC float GetElapsed_sec() const { #ifndef _EDITOR diff --git a/src/xrCore/FileSystem.cpp b/src/xrCore/FileSystem.cpp index adc93a352c..e5d40e7f79 100644 --- a/src/xrCore/FileSystem.cpp +++ b/src/xrCore/FileSystem.cpp @@ -72,7 +72,7 @@ xr_string EFS_Utils::ChangeFileExt(const xr_string& src, LPCSTR ext) //---------------------------------------------------- void MakeFilter(string1024& dest, LPCSTR info, LPCSTR ext) { - std::string res; + xr_string res; if (ext) { diff --git a/src/xrCore/FixedMap.h b/src/xrCore/FixedMap.h index 3d9e3dc300..e39733e092 100644 --- a/src/xrCore/FixedMap.h +++ b/src/xrCore/FixedMap.h @@ -1,331 +1,354 @@ -#ifndef _FIXEDMAP_H +#ifndef _FIXEDMAP_H #define _FIXEDMAP_H #pragma once -template -class FixedMAP -{ - enum - { - SG_REALLOC_ADVANCE = 64 - }; - +template +class FixedMAP { + enum { + SG_REALLOC_ADVANCE = 64 + }; public: - struct TNode - { - K key; - T val; - TNode *left, *right; - }; - - typedef void __fastcall callback(TNode*); - typedef bool __fastcall callback_cmp(TNode& N1, TNode& N2); + struct TNode { + K key; + T val; + TNode* left, * right; + }; + typedef void __fastcall callback(TNode*); + typedef bool __fastcall callback_cmp(TNode& N1, TNode& N2); private: - TNode* nodes; - u32 pool; - u32 limit; - - IC u32 Size(u32 Count) - { - return Count * sizeof(TNode); - } - - void Realloc() - { - u32 newLimit = limit + SG_REALLOC_ADVANCE; - VERIFY(newLimit%SG_REALLOC_ADVANCE == 0); - TNode* newNodes = (TNode*)allocator::alloc(sizeof(TNode) * newLimit); - VERIFY(newNodes); - - ZeroMemory(newNodes, Size(newLimit)); - if (limit) - CopyMemory(newNodes, nodes, Size(limit)); - - for (u32 I = 0; I < pool; I++) - { - VERIFY(nodes); - TNode* Nold = nodes + I; - TNode* Nnew = newNodes + I; - - if (Nold->left) - { - size_t Lid = Nold->left - nodes; - Nnew->left = newNodes + Lid; - } - if (Nold->right) - { - size_t Rid = Nold->right - nodes; - Nnew->right = newNodes + Rid; - } - } - if (nodes) allocator::dealloc(nodes); - - nodes = newNodes; - limit = newLimit; - } - - IC TNode* Alloc(const K& key) - { - if (pool == limit) Realloc(); - TNode* node = nodes + pool; - node->key = key; - node->right = node->left = 0; - pool++; - return node; - } - - IC TNode* CreateChild(TNode*& parent, const K& key) - { - size_t PID = size_t(parent - nodes); - TNode* N = Alloc(key); - parent = nodes + PID; - return N; - } - - IC void recurseLR(TNode* N, callback CB) - { - if (N->left) recurseLR(N->left, CB); - CB(N); - if (N->right) recurseLR(N->right, CB); - } - - IC void recurseRL(TNode* N, callback CB) - { - if (N->right) recurseRL(N->right, CB); - CB(N); - if (N->left) recurseRL(N->left, CB); - } - - IC void getLR(TNode* N, xr_vector::result>& D) - { - if (N->left) getLR(N->left, D); - D.push_back(N->val); - if (N->right) getLR(N->right, D); - } - - IC void getRL(TNode* N, xr_vector::result>& D) - { - if (N->right) getRL(N->right, D); - D.push_back(N->val); - if (N->left) getRL(N->left, D); - } - - IC void getLR_P(TNode* N, xr_vector::result>& D) - { - if (N->left) getLR_P(N->left, D); - D.push_back(N); - if (N->right) getLR_P(N->right, D); - } - - IC void getRL_P(TNode* N, xr_vector::result>& D) - { - if (N->right) getRL_P(N->right, D); - D.push_back(N); - if (N->left) getRL_P(N->left, D); - } + TNode* nodes; + u32 pool; + u32 limit; + + IC u32 Size(u32 Count) { + return Count * sizeof(TNode); + } + + void Realloc() { + u32 newLimit = limit + SG_REALLOC_ADVANCE; + VERIFY(newLimit % SG_REALLOC_ADVANCE == 0); + + // Выделяем новую память + TNode* newNodes = (TNode*)allocator::alloc(sizeof(TNode) * newLimit); + VERIFY(newNodes); + + // Инициализируем новую память + ZeroMemory(newNodes, Size(newLimit)); + + // Копируем только используемые узлы (pool вместо limit) + if (pool > 0) { + CopyMemory(newNodes, nodes, Size(pool)); + + // Обновляем указатели только для используемых узлов + for (u32 I = 0; I < pool; I++) { + TNode* Nold = nodes + I; + TNode* Nnew = newNodes + I; + + if (Nold->left) { + size_t Lid = Nold->left - nodes; + Nnew->left = newNodes + Lid; + } + if (Nold->right) { + size_t Rid = Nold->right - nodes; + Nnew->right = newNodes + Rid; + } + } + } + + // Освобождаем старую память + if (nodes) { + allocator::dealloc(nodes); + } + + // Обновляем указатели + nodes = newNodes; + limit = newLimit; + } + + IC TNode* Alloc(const K& key) { + if (pool == limit) Realloc(); + TNode* node = nodes + pool; + node->key = key; + node->right = node->left = nullptr; + pool++; + return node; + } + + IC TNode* CreateChild(TNode*& parent, const K& key) { + size_t PID = size_t(parent - nodes); + TNode* N = Alloc(key); + parent = nodes + PID; + return N; + } + + IC void recurseLR(TNode* N, callback CB) { + if (N->left) recurseLR(N->left, CB); + CB(N); + if (N->right) recurseLR(N->right, CB); + } + + IC void recurseRL(TNode* N, callback CB) { + if (N->right) recurseRL(N->right, CB); + CB(N); + if (N->left) recurseRL(N->left, CB); + } + + IC void getLR(TNode* N, xr_vector::result>& D) { + if (N->left) getLR(N->left, D); + D.push_back(N->val); + if (N->right) getLR(N->right, D); + } + + IC void getRL(TNode* N, xr_vector::result>& D) { + if (N->right) getRL(N->right, D); + D.push_back(N->val); + if (N->left) getRL(N->left, D); + } + + IC void getLR_P(TNode* N, xr_vector::result>& D) { + if (N->left) getLR_P(N->left, D); + D.push_back(N); + if (N->right) getLR_P(N->right, D); + } + + IC void getRL_P(TNode* N, xr_vector::result>& D) { + if (N->right) getRL_P(N->right, D); + D.push_back(N); + if (N->left) getRL_P(N->left, D); + } public: - FixedMAP() - { - pool = 0; - limit = 0; - nodes = 0; - } - - ~FixedMAP() - { - destroy(); - } - - void destroy() - { - if (nodes) - { - for (TNode* cur = begin(); cur != last(); cur++) - cur->~TNode(); - allocator::dealloc(nodes); - } - } - - IC TNode* insert(const K& k) - { - if (pool) - { - TNode* node = nodes; - - once_more: - if (k < node->key) - { - if (node->left) - { - node = node->left; - goto once_more; - } - else - { - TNode* N = CreateChild(node, k); - node->left = N; - return N; - } - } - else if (k > node->key) - { - if (node->right) - { - node = node->right; - goto once_more; - } - else - { - TNode* N = CreateChild(node, k); - node->right = N; - return N; - } - } - else return node; - } - else - { - return Alloc(k); - } - } - - IC TNode* insertInAnyWay(const K& k) - { - if (pool) - { - TNode* node = nodes; - - once_more: - if (k <= node->key) - { - if (node->left) - { - node = node->left; - goto once_more; - } - else - { - TNode* N = CreateChild(node, k); - node->left = N; - return N; - } - } - else - { - if (node->right) - { - node = node->right; - goto once_more; - } - else - { - TNode* N = CreateChild(node, k); - node->right = N; - return N; - } - } - } - else - { - return Alloc(k); - } - } - - IC TNode* insert(const K& k, const T& v) - { - TNode* N = insert(k); - N->val = v; - return N; - } - - IC TNode* insertInAnyWay(const K& k, const T& v) - { - TNode* N = insertInAnyWay(k); - N->val = v; - return N; - } - - IC void discard() - { - if (nodes) allocator::dealloc(nodes); - nodes = 0; - pool = 0; - limit = 0; - } - - IC u32 allocated() { return this->limit; } - IC void clear() { pool = 0; } - IC TNode* begin() { return nodes; } - IC TNode* end() { return nodes + pool; } - IC TNode* last() { return nodes + limit; } // for setup only - IC u32 size() { return pool; } - IC TNode& operator[](int v) { return nodes[v]; } - - IC void traverseLR(callback CB) - { - if (pool) recurseLR(nodes, CB); - } - - IC void traverseRL(callback CB) - { - if (pool) recurseRL(nodes, CB); - } - - IC void traverseANY(callback CB) - { - TNode* _end = end(); - for (TNode* cur = begin(); cur != _end; cur++) - CB(cur); - } - - IC void getLR(xr_vector::result>& D) - { - if (pool) getLR(nodes, D); - } - - IC void getLR_P(xr_vector::result>& D) - { - if (pool) getLR_P(nodes, D); - } - - IC void getRL(xr_vector::result>& D) - { - if (pool) getRL(nodes, D); - } - - IC void getRL_P(xr_vector::result>& D) - { - if (pool) getRL_P(nodes, D); - } - - IC void getANY(xr_vector::result>& D) - { - TNode* _end = end(); - for (TNode* cur = begin(); cur != _end; cur++) D.push_back(cur->val); - } - - IC void getANY_P(xr_vector::result>& D) - { - D.resize(size()); - TNode** _it = &*D.begin(); - TNode* _end = end(); - for (TNode* cur = begin(); cur != _end; cur++, _it++) *_it = cur; - } - - IC void getANY_P(xr_vector::result>& D) - { - D.resize(size()); - void** _it = &*D.begin(); - TNode* _end = end(); - for (TNode* cur = begin(); cur != _end; cur++, _it++) *_it = cur; - } - - IC void setup(callback CB) - { - for (int i = 0; i < limit; i++) - CB(nodes + i); - } + FixedMAP() : pool(0), limit(0), nodes(nullptr) {} + ~FixedMAP() { destroy(); } + + void destroy() { + if (nodes) { + for (TNode* cur = begin(); cur != end(); cur++) + cur->~TNode(); + allocator::dealloc(nodes); + } + pool = 0; + limit = 0; + nodes = 0; + } + + IC TNode* insert(const K& k) { + if (pool == 0) { + return Alloc(k); + } + + TNode* node = nodes; + while (true) { + if (k < node->key) { + if (node->left) { + node = node->left; + } + else { + TNode* N = CreateChild(node, k); + node->left = N; + return N; + } + } + else if (k > node->key) { + if (node->right) { + node = node->right; + } + else { + TNode* N = CreateChild(node, k); + node->right = N; + return N; + } + } + else { + return node; + } + } + } + + IC TNode* insertInAnyWay(const K& k) { + if (pool == 0) { + return Alloc(k); + } + + TNode* node = nodes; + while (true) { + if (k <= node->key) { + if (node->left) { + node = node->left; + } + else { + TNode* N = CreateChild(node, k); + node->left = N; + return N; + } + } + else { + if (node->right) { + node = node->right; + } + else { + TNode* N = CreateChild(node, k); + node->right = N; + return N; + } + } + } + } + + IC void insertInAnyWay(const K& k, const T&& val) { + if (pool == 0) { + Alloc(k)->val = val; + return; + } + + TNode* node = nodes; + while (true) { + if (k <= node->key) { + if (node->left) { + node = node->left; + } + else { + TNode* N = CreateChild(node, k); + node->left = N; + N->val = val; + return; + } + } + else { + if (node->right) { + node = node->right; + } + else { + TNode* N = CreateChild(node, k); + node->right = N; + N->val = val; + return; + } + } + } + } + + IC TNode* find(const K& key) { + if (pool == 0) return nullptr; + + TNode* node = nodes; + while (node != nullptr) { + if (key < node->key) { + node = node->left; + } + else if (key > node->key) { + node = node->right; + } + else { + return node; + } + } + return nullptr; + } + + IC TNode* insert(const K& k, const T& v) { + TNode* N = insert(k); + N->val = v; + return N; + } + + IC TNode* insertInAnyWay(const K& k, const T& v) { + TNode* N = insertInAnyWay(k); + N->val = v; + return N; + } + + IC void discard() { + if (nodes) allocator::dealloc(nodes); + nodes = nullptr; + pool = 0; + limit = 0; + } + + IC u32 allocated() { return limit; } + IC void clear() { pool = 0; } + IC TNode* last() { return nodes + limit; } // for setup only + IC u32 size() { return pool; } + IC TNode& operator[] (int v) { return nodes[v]; } + + IC void traverseLR(callback CB) { + if (pool) recurseLR(nodes, CB); + } + + IC void traverseRL(callback CB) { + if (pool) recurseRL(nodes, CB); + } + + IC void traverseANY(callback CB) { + TNode* _end = end(); + for (TNode* cur = begin(); cur != _end; cur++) + CB(cur); + } + + IC void getLR(xr_vector::result>& D) { + if (pool) getLR(nodes, D); + } + + IC void getLR_P(xr_vector::result>& D) { + if (pool) getLR_P(nodes, D); + } + + IC void getRL(xr_vector::result>& D) { + if (pool) getRL(nodes, D); + } + + IC void getRL_P(xr_vector::result>& D) { + if (pool) getRL_P(nodes, D); + } + + IC void getANY(xr_vector::result>& D) { + TNode* _end = end(); + for (TNode* cur = begin(); cur != _end; cur++) D.push_back(cur->val); + } + + IC void getANY_P(xr_vector::result>& D) { + D.resize(size()); + TNode** _it = &*D.begin(); + TNode* _end = end(); + for (TNode* cur = begin(); cur != _end; cur++, _it++) *_it = cur; + } + + IC void getANY_P(xr_vector::result>& D) { + D.resize(size()); + void** _it = &*D.begin(); + TNode* _end = end(); + for (TNode* cur = begin(); cur != _end; cur++, _it++) *_it = cur; + } + + IC void setup(callback CB) { + for (int i = 0; i < limit; i++) + CB(nodes + i); + } + + IC TNode* begin() { + VERIFY(nodes); + return nodes; + } + + IC TNode* end() { + VERIFY(nodes + pool >= nodes); + return nodes + pool; + } + + // Convert a pointer to a stable index + IC u32 get_index(TNode* N) { + return (u32)(N - nodes); + } + + // Get the pointer back from the index + IC TNode* get_node(u32 index) { + return nodes + index; + } +}; + +template +class FixedSet : public FixedMAP { + // Переопределить необходимые методы }; -#endif +#endif \ No newline at end of file diff --git a/src/xrCore/LocatorAPI.cpp b/src/xrCore/LocatorAPI.cpp index 656fa6d268..a2354a8754 100644 --- a/src/xrCore/LocatorAPI.cpp +++ b/src/xrCore/LocatorAPI.cpp @@ -491,7 +491,7 @@ void CLocatorAPI::ProcessArchive(LPCSTR _path) } // g_temporary_stuff = g_temporary_stuff_subst; - if (bProcessArchiveLoading || strstr(Core.Params, "-auto_load_arch")) + if (bProcessArchiveLoading || Core.ParamsData.test(ECoreParams::auto_load_arch)) LoadArchive(A); else A.close(); @@ -822,7 +822,7 @@ void CLocatorAPI::_initialize(u32 flags, LPCSTR target_folder, LPCSTR fs_name) //Old good fsltx //replace root with predefined path //xr_strcpy(root, fsRoot.generic_string().c_str()); - FS_Path* P = new FS_Path(xr_strdup(fsRoot.generic_string().c_str()), nullptr, nullptr, nullptr, 0); + FS_Path* P = new FS_Path(fsRoot.generic_string().c_str(), nullptr, nullptr, nullptr, 0); pathes.insert(std::make_pair(xr_strdup("$fs_root$"), P)); p_it = pathes.find(root); } @@ -850,7 +850,7 @@ void CLocatorAPI::_initialize(u32 flags, LPCSTR target_folder, LPCSTR fs_name) Msg("Init FileSystem %f sec", t.GetElapsed_sec()); //----------------------------------------------------------- - if (strstr(Core.Params, "-overlaypath")) + if (Core.ParamsData.test(ECoreParams::overlaypath)) { string1024 c_newAppPathRoot; sscanf(strstr(Core.Params, "-overlaypath ") + 13, "%[^ ] ", c_newAppPathRoot); @@ -869,12 +869,15 @@ void CLocatorAPI::_initialize(u32 flags, LPCSTR target_folder, LPCSTR fs_name) rec_files.clear(); //----------------------------------------------------------- - CreateLog(0 != strstr(Core.Params, "-nolog")); + if (!Core.ParamsData.test(ECoreParams::nolog)) + { + xrLogger::OpenLogFile(); + } } void CLocatorAPI::_destroy() { - CloseLog(); + xrLogger::CloseLog(); for (files_it I = m_files.begin(); I != m_files.end(); I++) { @@ -1344,6 +1347,7 @@ bool CLocatorAPI::check_for_file(LPCSTR path, LPCSTR _fname, string_path& fname, template T* CLocatorAPI::r_open_impl(LPCSTR path, LPCSTR _fname) { + PROF_EVENT("r_open_impl"); T* R = 0; string_path fname; const file* desc = 0; diff --git a/src/xrCore/LocatorAPI_Notifications.h b/src/xrCore/LocatorAPI_Notifications.h index 35176ef67b..d4203ec53c 100644 --- a/src/xrCore/LocatorAPI_Notifications.h +++ b/src/xrCore/LocatorAPI_Notifications.h @@ -35,7 +35,7 @@ class CFS_PathNotificator : public CThread { shared_str FDirectory; void* FWaitHandle; - fastdelegate::FastDelegate0<> FChangeEvent; + xr_delegate FChangeEvent; BOOL bRecurse; }; diff --git a/src/xrCore/LocatorAPI_auth.cpp b/src/xrCore/LocatorAPI_auth.cpp index c98c1b5b30..6d6e9b0848 100644 --- a/src/xrCore/LocatorAPI_auth.cpp +++ b/src/xrCore/LocatorAPI_auth.cpp @@ -47,78 +47,46 @@ void CLocatorAPI::auth_runtime(void* params) pSettingsAuth->save_as(writer); m_auth_code = crc32(writer.pointer(), writer.size()); -#ifdef DEBUG - if (strstr(Core.Params, "auth_debug")) - { - string_path tmp_path; - update_path(tmp_path, "$app_data_root$", "auth_psettings.ltx"); - IWriter* tmp_dst = w_open(tmp_path); - pSettingsAuth->save_as(*tmp_dst, false); - w_close(tmp_dst); - } -#endif - bool do_break = false; -#ifdef DEBUG - bool b_extern_auth = !!strstr(Core.Params, "asdf"); - if (!b_extern_auth) -#endif // DEBUG + for (files_it it = m_files.begin(); it != m_files.end(); ++it) { - for (files_it it = m_files.begin(); it != m_files.end(); ++it) - { - const file& f = *it; + const file& f = *it; - // test for skip - BOOL bSkip = FALSE; - for (u32 s = 0; s < _o->ignore.size(); s++) - { - if (strstr(f.name, _o->ignore[s].c_str())) - bSkip = TRUE; - } + // test for skip + BOOL bSkip = FALSE; + for (u32 s = 0; s < _o->ignore.size(); s++) + { + if (strstr(f.name, _o->ignore[s].c_str())) + bSkip = TRUE; + } - if (bSkip) - continue; + if (bSkip) + continue; - // test for important - for (u32 s = 0; s < _o->important.size(); s++) + // test for important + for (u32 s = 0; s < _o->important.size(); s++) + { + if ((f.size_real != 0) && strstr(f.name, _o->important[s].c_str())) { - if ((f.size_real != 0) && strstr(f.name, _o->important[s].c_str())) + // crc for file + IReader* r = FS.r_open(f.name); + if (!r) { - // crc for file - IReader* r = FS.r_open(f.name); - if (!r) - { - do_break = true; - break; - } - u32 crc = crc32(r->pointer(), r->length()); - -#ifdef DEBUG - if (strstr(Core.Params, "auth_debug")) - Msg("auth %s = 0x%08x", f.name, crc); -#endif // DEBUG - - FS.r_close(r); - m_auth_code ^= u64(crc); + do_break = true; + break; } - } + u32 crc = crc32(r->pointer(), r->length()); - if (do_break) - break; + FS.r_close(r); + m_auth_code ^= u64(crc); + } } -#ifdef DEBUG - Msg("auth_code = %d", m_auth_code); -#endif // DEBUG + + if (do_break) + break; } -#ifdef DEBUG - else - { - string64 c_auth_code; - sscanf(strstr(Core.Params, "asdf ") + 5, "%[^ ] ", c_auth_code); - m_auth_code = _atoi64(c_auth_code); - } -#endif // DEBUG + xr_delete(_o); m_auth_lock.Leave(); diff --git a/src/xrCore/LocatorAPI_defs.cpp b/src/xrCore/LocatorAPI_defs.cpp index 6feb0988fb..e25b78c2de 100644 --- a/src/xrCore/LocatorAPI_defs.cpp +++ b/src/xrCore/LocatorAPI_defs.cpp @@ -33,18 +33,42 @@ void FS_File::set(const xr_string& nm, long sz, time_t modif, unsigned attr) ////////////////////////////////////////////////////////////////////// // FS_Path ////////////////////////////////////////////////////////////////////// +namespace +{ +LPSTR xr_strdup_lwr(LPCSTR value) +{ + return value ? xr_strlwr(xr_strdup(value)) : 0; +} + +void append_path_separator(LPSTR path, size_t path_size) +{ + if (path[0] && path[xr_strlen(path) - 1] != '\\') + xr_strcat(path, path_size, "\\"); +} +} + FS_Path::FS_Path(LPCSTR _Root, LPCSTR _Add, LPCSTR _DefExt, LPCSTR _FilterCaption, u32 flags) { // VERIFY (_Root&&_Root[0]); + m_Path = 0; + m_Root = 0; + m_Add = 0; + m_DefExt = 0; + m_FilterCaption = 0; + + LPCSTR root = _Root ? _Root : ""; + LPCSTR add = _Add ? _Add : ""; + string_path temp; - xr_strcpy(temp, sizeof(temp), _Root); - if (_Add) xr_strcat(temp, _Add); - if (temp[0] && temp[xr_strlen(temp) - 1] != '\\') xr_strcat(temp, "\\"); - m_Path = xr_strlwr(xr_strdup(temp)); - m_DefExt = _DefExt ? xr_strlwr(xr_strdup(_DefExt)) : 0; - m_FilterCaption = _FilterCaption ? xr_strlwr(xr_strdup(_FilterCaption)) : 0; - m_Add = _Add ? xr_strlwr(xr_strdup(_Add)) : 0; - m_Root = _Root ? xr_strlwr(xr_strdup(_Root)) : 0; + xr_strcpy(temp, sizeof(temp), root); + xr_strcat(temp, sizeof(temp), add); + append_path_separator(temp, sizeof(temp)); + + m_Path = xr_strdup_lwr(temp); + m_DefExt = xr_strdup_lwr(_DefExt); + m_FilterCaption = xr_strdup_lwr(_FilterCaption); + m_Add = xr_strdup_lwr(_Add); + m_Root = xr_strdup_lwr(_Root); m_Flags.assign(flags); #ifdef _EDITOR // Editor(s)/User(s) wants pathes already created in "real" file system :) @@ -64,31 +88,40 @@ FS_Path::~FS_Path() void FS_Path::_set(LPCSTR add) { // m_Add - R_ASSERT(add); - xr_free(m_Add); - m_Add = xr_strlwr(xr_strdup(add)); + LPCSTR new_add = add ? add : ""; + LPSTR duplicated_add = xr_strdup_lwr(new_add); // m_Path string_path temp; - strconcat(sizeof(temp), temp, m_Root, m_Add); - if (temp[xr_strlen(temp) - 1] != '\\') xr_strcat(temp, "\\"); + strconcat(sizeof(temp), temp, m_Root ? m_Root : "", new_add); + append_path_separator(temp, sizeof(temp)); + LPSTR duplicated_path = xr_strdup_lwr(temp); + + xr_free(m_Add); + m_Add = duplicated_add; xr_free(m_Path); - m_Path = xr_strlwr(xr_strdup(temp)); + m_Path = duplicated_path; } void FS_Path::_set_root(LPCSTR root) { + LPCSTR new_root = root ? root : ""; + string_path temp; - xr_strcpy(temp, root); - if (m_Root[0] && m_Root[xr_strlen(m_Root) - 1] != '\\') xr_strcat(temp, "\\"); - xr_free(m_Root); - m_Root = xr_strlwr(xr_strdup(temp)); + xr_strcpy(temp, sizeof(temp), new_root); + append_path_separator(temp, sizeof(temp)); + LPSTR duplicated_root = xr_strdup_lwr(temp); // m_Path - strconcat(sizeof(temp), temp, m_Root, m_Add ? m_Add : ""); - if (*temp && temp[xr_strlen(temp) - 1] != '\\') xr_strcat(temp, "\\"); + strconcat(sizeof(temp), temp, duplicated_root ? duplicated_root : "", m_Add ? m_Add : ""); + append_path_separator(temp, sizeof(temp)); + LPSTR duplicated_path = xr_strdup_lwr(temp); + + xr_free(m_Root); + m_Root = duplicated_root; + xr_free(m_Path); - m_Path = xr_strlwr(xr_strdup(temp)); + m_Path = duplicated_path; } LPCSTR FS_Path::_update(string_path& dest, LPCSTR src) const diff --git a/src/xrCore/LocatorAPI_defs.h b/src/xrCore/LocatorAPI_defs.h index cd0495ef45..dd441a1c01 100644 --- a/src/xrCore/LocatorAPI_defs.h +++ b/src/xrCore/LocatorAPI_defs.h @@ -31,6 +31,8 @@ class XRCORE_API FS_Path Flags32 m_Flags; public: FS_Path(LPCSTR _Root, LPCSTR _Add, LPCSTR _DefExt = 0, LPCSTR _FilterString = 0, u32 flags = 0); + FS_Path(const FS_Path&) = delete; + FS_Path& operator=(const FS_Path&) = delete; ~FS_Path(); LPCSTR _update(string_path& dest, LPCSTR src) const; void _set(LPCSTR add); diff --git a/src/xrCore/NET_utils.cpp b/src/xrCore/NET_utils.cpp index 9c0bdb55a0..f031ede203 100644 --- a/src/xrCore/NET_utils.cpp +++ b/src/xrCore/NET_utils.cpp @@ -8,16 +8,12 @@ void NET_Packet::read_start() { r_pos = 0; - INI_W(move_begin()); } u32 NET_Packet::r_begin(u16& type) // returns time of receiving { r_pos = 0; - if (!inistream) - r_u16(type); - else - inistream->r_u16(type); + r_u16(type); return timeReceive; } @@ -31,7 +27,6 @@ void NET_Packet::w_seek(u32 pos, const void* p, u32 count) void NET_Packet::r_seek(u32 pos) { - INI_ASSERT(r_seek) //AVO: changed changed condition to <= as all net packet script utils are using r_seek(0) to read the entire packet. VERIFY(pos <= B.count); //VERIFY(pos < B.count); @@ -40,25 +35,21 @@ void NET_Packet::r_seek(u32 pos) u32 NET_Packet::r_tell() { - INI_ASSERT(r_tell) return r_pos; } BOOL NET_Packet::r_eof() { - INI_ASSERT(r_eof) return (r_pos >= B.count); } u32 NET_Packet::r_elapsed() { - INI_ASSERT(r_elapsed) return (B.count - r_pos); } void NET_Packet::r_advance(u32 size) { - INI_ASSERT(r_advance) r_pos += size; VERIFY(r_pos <= B.count); } @@ -66,90 +57,57 @@ void NET_Packet::r_advance(u32 size) // reading - utilities void NET_Packet::r_vec3(Fvector& A) { - if (!inistream) - r(&A, sizeof(Fvector)); - else - inistream->r_vec3(A); + r(&A, sizeof(Fvector)); } // vec3 void NET_Packet::r_vec4(Fvector4& A) { - if (!inistream) - r(&A, sizeof(Fvector4)); - else - inistream->r_vec4(A); + r(&A, sizeof(Fvector4)); } // vec4 void NET_Packet::r_float(float& A) { - if (!inistream) - r(&A, sizeof(float)); - else - inistream->r_float(A); + r(&A, sizeof(float)); } // float void NET_Packet::r_u64(u64& A) { - if (!inistream) - r(&A, sizeof(u64)); - else - inistream->r_u64(A); + r(&A, sizeof(u64)); } // qword (8b) void NET_Packet::r_s64(s64& A) { - if (!inistream) - r(&A, sizeof(s64)); - else - inistream->r_s64(A); + r(&A, sizeof(s64)); } // qword (8b) void NET_Packet::r_u32(u32& A) { - if (!inistream) - r(&A, sizeof(u32)); - else - inistream->r_u32(A); + r(&A, sizeof(u32)); } // dword (4b) void NET_Packet::r_s32(s32& A) { - if (!inistream) - r(&A, sizeof(s32)); - else - inistream->r_s32(A); + r(&A, sizeof(s32)); } // dword (4b) void NET_Packet::r_u16(u16& A) { - if (!inistream) - r(&A, sizeof(u16)); - else - inistream->r_u16(A); + r(&A, sizeof(u16)); } // word (2b) void NET_Packet::r_s16(s16& A) { - if (!inistream) - r(&A, sizeof(s16)); - else - inistream->r_s16(A); + r(&A, sizeof(s16)); } // word (2b) void NET_Packet::r_u8(u8& A) { - if (!inistream) - r(&A, sizeof(u8)); - else - inistream->r_u8(A); + r(&A, sizeof(u8)); } // byte (1b) void NET_Packet::r_s8(s8& A) { - if (!inistream) - r(&A, sizeof(s8)); - else - inistream->r_s8(A); + r(&A, sizeof(s8)); } // byte (1b) // IReader compatibility @@ -289,60 +247,28 @@ void NET_Packet::r_sdir(Fvector& A) void NET_Packet::r_stringZ(LPSTR S) { - if (!inistream) - { - LPCSTR data = LPCSTR(&B.data[r_pos]); - size_t len = xr_strlen(data); - r(S, (u32)len + 1); - } - else - { - inistream->r_string(S, 4096); //??? - } + LPCSTR data = LPCSTR(&B.data[r_pos]); + size_t len = xr_strlen(data); + r(S, (u32)len + 1); } void NET_Packet::r_stringZ(xr_string& dest) { - if (!inistream) - { - dest = LPCSTR(&B.data[r_pos]); - r_advance(u32(dest.size() + 1)); - } - else - { - string4096 buff; - inistream->r_string(buff, sizeof(buff)); - dest = buff; - } + dest = LPCSTR(&B.data[r_pos]); + r_advance(u32(dest.size() + 1)); } void NET_Packet::r_stringZ(shared_str& dest) { - if (!inistream) - { - dest = LPCSTR(&B.data[r_pos]); - r_advance(dest.size() + 1); - } - else - { - string4096 buff; - inistream->r_string(buff, sizeof(buff)); - dest = buff; - } + dest = LPCSTR(&B.data[r_pos]); + r_advance(dest.size() + 1); } void NET_Packet::skip_stringZ() { - if (!inistream) - { - LPCSTR data = LPCSTR(&B.data[r_pos]); - u32 len = xr_strlen(data); - r_advance(len + 1); - } - else - { - inistream->skip_stringZ(); - } + LPCSTR data = LPCSTR(&B.data[r_pos]); + u32 len = xr_strlen(data); + r_advance(len + 1); } void NET_Packet::r_matrix(Fmatrix& M) @@ -366,12 +292,6 @@ void NET_Packet::r_clientID(ClientID& C) void NET_Packet::r_stringZ_s(LPSTR string, u32 const size) { - if (inistream) - { - inistream->r_string(string, size); - return; - } - LPCSTR data = LPCSTR(B.data + r_pos); u32 length = xr_strlen(data); R_ASSERT2((length + 1) <= size, "buffer overrun"); diff --git a/src/xrCore/RingBuffer.h b/src/xrCore/RingBuffer.h new file mode 100644 index 0000000000..5090b47810 --- /dev/null +++ b/src/xrCore/RingBuffer.h @@ -0,0 +1,142 @@ +//Giperion May 2018 +//[EUREKA] 3.6 + +// Allowed for XRay Oxygen +#pragma once +#include + +///Buffer for storing last BufferSize items pushed. Good option for history +template +class RingBuffer +{ +public: + std::size_t Position = 0; + + RingBuffer() + { + //if stored type is fundamental, we must clear all with zero + constexpr bool isFundamental = std::is_fundamental::value; + if constexpr (isFundamental) + { + memset(&Buffer[0], 0, sizeof(StoredType) * BufferSize); + } + //otherwise, the default constructor will be called, clearing all without us + } + + void Write(StoredType Value) { + Buffer[(Position++ % BufferSize)] = Value; + } + + //Get first element of this container. + unsigned int GetHead() const + { + return PosHead; + } + + //Get current end of this container + unsigned int GetTail() const + { + if (GetHead() == 0) + return BufferSize - 1; + + if (GetHead() == (BufferSize - 1)) + return 0; + + return GetHead() - 1; + } + + unsigned int GetSize() const + { + return BufferSize; + } + + void MoveHead(unsigned int DeltaPos) + { + PosHead += DeltaPos; + PosHead %= BufferSize; + } + + const StoredType& Get(unsigned int Pos) const + { + return Buffer[Pos]; + } + + const StoredType& GetLooped(unsigned int Pos) const + { + return Buffer[Pos % GetSize()]; + } + + StoredType& Get(unsigned int Pos) + { + return Buffer[Pos]; + } + + void Push(StoredType&& Elem) + { + if (PosHead == 0) + { + PosHead = BufferSize - 1; + } + else + { + --PosHead; + } + Buffer[PosHead] = Elem; + } + + void Push(StoredType& Elem) + { + if (PosHead == 0) + { + PosHead = BufferSize - 1; + } + else + { + --PosHead; + } + Buffer[PosHead] = Elem; + } + + // write elements to storage, but don't move head pointer. So after this the head will point to first copied element + bool WriteFromHeadNoMove(const StoredType* pElems, unsigned int ElemsCount) + { + if (ElemsCount >= BufferSize) return false; + + // don't use Push. Push works great for single item, for thing like history and etc. + // But for large arrays it's better have classic forward (like) data chain. + unsigned int RemainElems = ElemsCount; + + if (int FirstChunkSize = BufferSize - GetHead()) + { + unsigned int CopySize = FirstChunkSize >= ElemsCount ? ElemsCount : FirstChunkSize; + memcpy(&Buffer[PosHead], pElems, CopySize * sizeof(StoredType)); + RemainElems = FirstChunkSize >= ElemsCount ? 0 : ElemsCount - FirstChunkSize; + } + + if (RemainElems > 0) + { + memcpy(&Buffer[0], pElems + (ElemsCount - RemainElems), RemainElems * sizeof(StoredType)); + } + + return true; + } + + template + void ForEachElementFromHead(Functor& FuncElem) const + { + unsigned int TailPos = GetTail(); + + unsigned int Pos = GetHead(); + while (Pos != TailPos) + { + FuncElem(Get(Pos)); + + ++Pos; + Pos %= BufferSize; + } + } + +private: + unsigned int PosHead = 0; + StoredType Buffer[BufferSize]; +}; \ No newline at end of file diff --git a/src/xrCore/TimeUtils.h b/src/xrCore/TimeUtils.h new file mode 100644 index 0000000000..d8366b31ec --- /dev/null +++ b/src/xrCore/TimeUtils.h @@ -0,0 +1,53 @@ +#pragma once + +#include +#include +#include +#include +#include +#include + +using xr_time_t = std::time_t; + +template +xr_time_t xr_chrono_to_time_t(TP tp) +{ + using namespace std::chrono; + auto sctp = time_point_cast(tp - TP::clock::now() + system_clock::now()); + + return system_clock::to_time_t(sctp); +} + +xr_string getCurrentTimeStamp(const char* format = "%H:%M:%S") +{ + using namespace std::chrono; + + // get current time + auto now = system_clock::now(); + + // get number of milliseconds for the current second + // (remainder after division into seconds) + auto ms = duration_cast(now.time_since_epoch()) % 1000; + + // convert to std::time_t in order to convert to std::tm (broken time) + xr_time_t timer = system_clock::to_time_t(now); + + // convert to broken time + std::tm bt = *std::localtime(&timer); + + std::ostringstream oss; + + oss << std::put_time(&bt, format); // HH:MM:SS + oss << '.' << std::setfill('0') << std::setw(3) << ms.count(); + + return oss.str().c_str(); +} + +xr_string timeInDMYHMSMMM() +{ + return getCurrentTimeStamp("%d.%m.%Y %H:%M:%S"); +} +xr_string timeInHMSMMM() +{ + return getCurrentTimeStamp("%H:%M:%S"); +} \ No newline at end of file diff --git a/src/xrCore/Xr_ini.cpp b/src/xrCore/Xr_ini.cpp index e29b68304d..371d807fa5 100644 --- a/src/xrCore/Xr_ini.cpp +++ b/src/xrCore/Xr_ini.cpp @@ -152,6 +152,7 @@ CInifile::CInifile(IReader* F, LPCSTR path #endif ) { + PROF_EVENT("CInifile::CInifile IReader"); m_file_name[0] = 0; m_flags.zero(); m_flags.set(eSaveAtEnd, FALSE); @@ -175,6 +176,7 @@ CInifile::CInifile(LPCSTR szFileName, ) { + PROF_EVENT("CInifile::CInifile FileName"); if (szFileName && strstr(szFileName, "system")) Msg("-----loading %s", szFileName); @@ -1510,9 +1512,7 @@ void CInifile::save_as(IWriter& writer, bool bcheck) const writer.w_string(temp); if (bcheck) { - xr_sprintf(temp, sizeof(temp), "; %d %d %d", (*r_it).Name._get()->dwCRC, - (*r_it).Name._get()->dwReference, - (*r_it).Name._get()->dwLength); + xr_sprintf(temp, sizeof(temp), "; %d %d", (*r_it).Name._get()->intrusive_ref_count(), xr_strlen((*r_it).Name._get()->value)); writer.w_string(temp); } diff --git a/src/xrCore/_flags.h b/src/xrCore/_flags.h index d941b10386..df9f474c22 100644 --- a/src/xrCore/_flags.h +++ b/src/xrCore/_flags.h @@ -1,6 +1,11 @@ #ifndef __FLAGS_H__ #define __FLAGS_H__ +#include +#include +#include +#include "../3rd party/magic_enum/magic_enum.hpp" + template struct _flags { @@ -102,4 +107,110 @@ typedef _flags flags32; typedef _flags Flags64; typedef _flags flags64; +// demonized: bitset flags for flag enums with more than 64 possible values +/* https://m-peko.github.io/craft-cpp/posts/different-ways-to-define-binary-flags/ */ +template +class xr_bitsetflags { + static_assert(std::is_enum_v, "xr_bitsetflags can only be specialized for enum types"); + + using UnderlyingT = typename std::make_unsigned_t>; + +public: + IC xr_bitsetflags& set(EnumT e, bool value = true) noexcept { + bits_.set(underlying(e), value); + return *this; + } + + IC xr_bitsetflags& reset(EnumT e) noexcept { + set(e, false); + return *this; + } + + IC xr_bitsetflags& reset() noexcept { + bits_.reset(); + return *this; + } + + [[nodiscard]] IC bool all() const noexcept { + return bits_.all(); + } + + [[nodiscard]] IC bool any() const noexcept { + return bits_.any(); + } + + [[nodiscard]] IC bool none() const noexcept { + return bits_.none(); + } + + [[nodiscard]] IC constexpr std::size_t size() const noexcept { + return enum_size; + } + + [[nodiscard]] IC std::size_t count() const noexcept { + return bits_.count(); + } + + IC constexpr bool operator[](EnumT e) const { + return bits_[underlying(e)]; + } + + IC constexpr BOOL test(EnumT e) const { + return !!bits_[underlying(e)]; + } + + IC constexpr BOOL test(const std::size_t pos) const { + return bits_.test(pos); + } + + IC xr_bitsetflags& zero() noexcept + { + return reset(); + } + + IC xr_bitsetflags& set() noexcept + { + bits_.set(); + return *this; + } + + IC xr_bitsetflags& one() noexcept + { + return set(); + } + + IC xr_bitsetflags& flip() noexcept + { + bits_.flip(); + return *this; + } + + IC xr_bitsetflags& invert() noexcept + { + return flip(); + } + + IC std::map getBitsetAsMap() const { + std::map result; + for (std::size_t pos = 0; pos < enum_size; pos++) + { + EnumT value = magic_enum::enum_value(pos); + std::string_view name = magic_enum::enum_name(value); + BOOL r = test(pos); + result.emplace(name, r); + } + return result; + } + +private: + static constexpr UnderlyingT underlying(EnumT e) { + return static_cast(e); + } + +private: + // Use magic_enum to get the enum size at compile time + static constexpr std::size_t enum_size = magic_enum::enum_count(); + std::bitset bits_; +}; + #endif //__FLAGS_H__ diff --git a/src/xrCore/_global_functions.h b/src/xrCore/_global_functions.h new file mode 100644 index 0000000000..a2d35bab4f --- /dev/null +++ b/src/xrCore/_global_functions.h @@ -0,0 +1,20 @@ +#pragma once + +// extra functions +// Base case for hash_combine with one argument +IC size_t hash_combine(size_t value) noexcept +{ + return value; +} + +// Recursive case for hash_combine with multiple arguments +// Usage example: size_t h = hash_combine(0, h1, h2); +template +IC size_t hash_combine(size_t seed, size_t value, Args... args) noexcept +{ + if constexpr (sizeof(size_t) >= 8) + seed ^= value + 0x517cc1b727220a95 + (seed << 6) + (seed >> 2); + else + seed ^= value + 0x9e3779b9 + (seed << 6) + (seed >> 2); + return hash_combine(seed, args...); +} diff --git a/src/xrCore/_math.cpp b/src/xrCore/_math.cpp index bfa9c3fc6e..6675d7d353 100644 --- a/src/xrCore/_math.cpp +++ b/src/xrCore/_math.cpp @@ -258,7 +258,7 @@ void _initialize_cpu(void) // DUMP_PHASE; - if (strstr(Core.Params, "-x86")) + if (Core.ParamsData.test(ECoreParams::x86)) { CPU::ID.feature &= ~_CPU_FEATURE_MMX; CPU::ID.feature &= ~_CPU_FEATURE_3DNOW; diff --git a/src/xrCore/_matrix.h b/src/xrCore/_matrix.h index 69d2416be4..0f061fc0e3 100644 --- a/src/xrCore/_matrix.h +++ b/src/xrCore/_matrix.h @@ -61,6 +61,60 @@ struct _matrix T m[4][4]; // Array }; + IC bool has_inited() { + if ( + _11 == 0 && + _12 == 0 && + _13 == 0 && + _14 == 0 && + + _21 == 0 && + _22 == 0 && + _23 == 0 && + _24 == 0 && + + _31 == 0 && + _32 == 0 && + _33 == 0 && + _34 == 0 && + + _41 == 0 && + _42 == 0 && + _43 == 0 && + _44 == 0 + ) + return true; + + return false; + } + + IC bool has_identity() { + if ( + _11 == 1 && + _12 == 0 && + _13 == 0 && + _14 == 0 && + + _21 == 0 && + _22 == 1 && + _23 == 0 && + _24 == 0 && + + _31 == 0 && + _32 == 0 && + _33 == 1 && + _34 == 0 && + + _41 == 0 && + _42 == 0 && + _43 == 0 && + _44 == 1 + ) + return true; + + return false; + } + // Class members ICF SelfRef set(const Self& a) { diff --git a/src/xrCore/_matrix33.h b/src/xrCore/_matrix33.h index 8e77e317c6..5b9e41112e 100644 --- a/src/xrCore/_matrix33.h +++ b/src/xrCore/_matrix33.h @@ -26,7 +26,9 @@ struct _matrix33 Tvector k; }; - float m[3][3]; // Array + Tvector row[3]; + float m[3][3]; + float mm[9]; }; // Class members diff --git a/src/xrCore/_obb.h b/src/xrCore/_obb.h index 0daf008543..ec5dac8003 100644 --- a/src/xrCore/_obb.h +++ b/src/xrCore/_obb.h @@ -1,6 +1,6 @@ #ifndef FOBB_H #define FOBB_H - +#include "_plane.h" template struct _obb { @@ -150,6 +150,287 @@ struct _obb } return false; } + + IC bool contains(const Tvector& point) const + { + Tvector localPoint; + localPoint.sub(point, m_translate); + + T x = localPoint.dotproduct(m_rotate.i); + T y = localPoint.dotproduct(m_rotate.j); + T z = localPoint.dotproduct(m_rotate.k); + + return (x >= -m_halfsize.x) && (x <= m_halfsize.x) && + (y >= -m_halfsize.y) && (y <= m_halfsize.y) && + (z >= -m_halfsize.z) && (z <= m_halfsize.z); + } + + IC bool intersectAABB(const _box3& aabb) const + { + Tvector aabbCenter, aabbExtents; + aabb.get_CD(aabbCenter, aabbExtents); + return intersectAABB(aabbCenter, aabbExtents); + } + + + IC bool intersectAABB(const Tvector& aabbCenter, const Tvector& aabbExtents) const + { + Tvector diff; + diff.sub(m_translate, aabbCenter); + + const _matrix33& R = m_rotate; + + T absR[3][3]; + for (int i = 0; i < 3; i++) + { + absR[0][i] = _abs(R.i[i]); + absR[1][i] = _abs(R.j[i]); + absR[2][i] = _abs(R.k[i]); + } + + for (int i = 0; i < 3; i++) + { + T r = m_halfsize.x * absR[0][i] + + m_halfsize.y * absR[1][i] + + m_halfsize.z * absR[2][i]; + if (_abs(diff[i]) > aabbExtents[i] + r) + return false; + } + + for (int i = 0; i < 3; i++) + { + T r = aabbExtents.x * absR[i][0] + + aabbExtents.y * absR[i][1] + + aabbExtents.z * absR[i][2]; + + T projection; + if (i == 0) projection = _abs(diff.dotproduct(R.i)); + else if (i == 1) projection = _abs(diff.dotproduct(R.j)); + else projection = _abs(diff.dotproduct(R.k)); + + if (projection > m_halfsize[i] + r) + return false; + } + + return true; + } + + IC bool intersectTri(const Tvector* verts, bool bClass3 = true) + { + Tvector axes[13]; + u32 total_axes = 3; + + axes[0] = m_rotate.i; + axes[1] = m_rotate.j; + axes[2] = m_rotate.k; + + Tvector edge1, edge2; + edge1.sub(verts[1], verts[0]); + edge2.sub(verts[2], verts[0]); + + Tvector tri_normal; + tri_normal.crossproduct(edge1, edge2); + + if (tri_normal.square_magnitude() > 0.0001f) { + axes[total_axes].normalize(tri_normal); + total_axes++; + } + + if (bClass3) + { + Tvector edges[3]; + edges[0] = edge1; + edges[1].sub(verts[2], verts[1]); + edges[2].sub(verts[0], verts[2]); + + for (u8 i = 0; i < 3; i++) + { + for (u8 j = 0; j < 3; j++) + { + Tvector axis; + axis.crossproduct(m_rotate.row[j], edges[i]); + + if (axis.square_magnitude() > 0.0001f && total_axes < 13) { + axes[total_axes].normalize(axis); + total_axes++; + } + } + } + } + + for (u32 i = 0; i < total_axes; i++) + { + if (axes[i].square_magnitude() < 0.0001f) continue; + + T p0 = verts[0].dotproduct(axes[i]); + T p1 = verts[1].dotproduct(axes[i]); + T p2 = verts[2].dotproduct(axes[i]); + + T minTri = _min(p0, _min(p1, p2)); + T maxTri = _max(p0, _max(p1, p2)); + + T obbProj = m_translate.dotproduct(axes[i]); + T obbHalf = + m_halfsize.x * _abs(m_rotate.i.dotproduct(axes[i])) + + m_halfsize.y * _abs(m_rotate.j.dotproduct(axes[i])) + + m_halfsize.z * _abs(m_rotate.k.dotproduct(axes[i])); + + T obbMin = obbProj - obbHalf; + T obbMax = obbProj + obbHalf; + + const T epsilon = 0.0001f; + if (maxTri < obbMin - epsilon || minTri > obbMax + epsilon) + return false; + } + + return true; + } + + IC void ClampPointOBB(Tvector& clamped_point) + { + Tvector local_point; + local_point.sub(clamped_point, m_translate); + + T x = local_point.dotproduct(m_rotate.i); + T y = local_point.dotproduct(m_rotate.j); + T z = local_point.dotproduct(m_rotate.k); + + int outside_count = 0; + if (x < -m_halfsize.x || x > m_halfsize.x) outside_count++; + if (y < -m_halfsize.y || y > m_halfsize.y) outside_count++; + if (z < -m_halfsize.z || z > m_halfsize.z) outside_count++; + + if (outside_count == 0) + return; + + if (outside_count == 1) + { + x = _max(-m_halfsize.x, _min(x, m_halfsize.x)); + y = _max(-m_halfsize.y, _min(y, m_halfsize.y)); + z = _max(-m_halfsize.z, _min(z, m_halfsize.z)); + } + else if (outside_count == 2) + { + T dist[6]; + dist[0] = _abs(x + m_halfsize.x); + dist[1] = _abs(x - m_halfsize.x); + dist[2] = _abs(y + m_halfsize.y); + dist[3] = _abs(y - m_halfsize.y); + dist[4] = _abs(z + m_halfsize.z); + dist[5] = _abs(z - m_halfsize.z); + + int closest_face = 0; + T min_dist = dist[0]; + for (int i = 1; i < 6; i++) + { + if (dist[i] < min_dist) + { + min_dist = dist[i]; + closest_face = i; + } + } + + switch (closest_face) + { + case 0: x = -m_halfsize.x; break; + case 1: x = m_halfsize.x; break; + case 2: y = -m_halfsize.y; break; + case 3: y = m_halfsize.y; break; + case 4: z = -m_halfsize.z; break; + case 5: z = m_halfsize.z; break; + } + + x = _max(-m_halfsize.x, _min(x, m_halfsize.x)); + y = _max(-m_halfsize.y, _min(y, m_halfsize.y)); + z = _max(-m_halfsize.z, _min(z, m_halfsize.z)); + } + else + { + T vertex_x = (x > 0) ? m_halfsize.x : -m_halfsize.x; + T vertex_y = (y > 0) ? m_halfsize.y : -m_halfsize.y; + T vertex_z = (z > 0) ? m_halfsize.z : -m_halfsize.z; + + x = vertex_x; + y = vertex_y; + z = vertex_z; + } + + clamped_point = m_translate; + clamped_point.mad(m_rotate.i, x); + clamped_point.mad(m_rotate.j, y); + clamped_point.mad(m_rotate.k, z); + } + + IC void FindContactsClipping(Tvector* tri, void (*callback)(const Tvector& contact, void* user_data), void* user_data = nullptr) + { + Tvector polygon[12]; + u8 poly_count = 3; + + for (u8 i = 0; i < 3; i++) + { + Tvector local; local.sub(tri[i], m_translate); + polygon[i].set(local.dotproduct(m_rotate.i), local.dotproduct(m_rotate.j), local.dotproduct(m_rotate.k)); + } + + _plane planes[6] + { + {{-1.f,0.f,0.f}, m_halfsize.x}, + {{1.f,0.f,0.f}, m_halfsize.x}, + {{0.f,-1.f,0.f}, m_halfsize.y}, + {{0.f,+1.f,0.f}, m_halfsize.y}, + {{0.f,0.f,-1.f}, m_halfsize.z}, + {{0.f,0.f,+1.f}, m_halfsize.z} + }; + + Tvector temp[12]; + + for (u8 i = 0; i < 6 && poly_count >= 3; i++) + { + u8 temp_count = 0; + + for (u8 j = 0; j < poly_count; j++) + { + Tvector& a = polygon[j]; + Tvector& b = polygon[(j + 1) % poly_count]; + + T da = planes[i].classify(a); + T db = da * planes[i].classify(b); + + if (da >= -EPS) + { + if (temp_count < 12) + temp[temp_count++] = a; + } + + if (db < 0.0f) + { + Tvector ab; ab.sub(b, a); + T denom = planes[i].n.dotproduct(ab); + + if (_abs(denom) > EPS && temp_count < 12) + { + T t = _max(0.0f, _min(1.0f, -da / denom)); + temp[temp_count++].mad(a, ab, t); + } + } + } + + poly_count = temp_count; + CopyMemory(polygon, temp, poly_count * sizeof(Tvector)); + } + + if (poly_count >= 3) + { + for (u8 i = 0; i < poly_count; i++) + { + Tvector world_point = m_translate; + world_point.mad(m_rotate.i, polygon[i].x); + world_point.mad(m_rotate.j, polygon[i].y); + world_point.mad(m_rotate.k, polygon[i].z); + callback(world_point, user_data); + } + } + } }; typedef _obb Fobb; diff --git a/src/xrCore/_std_extensions.h b/src/xrCore/_std_extensions.h index 59bb1eb4ea..ec3c7130dc 100644 --- a/src/xrCore/_std_extensions.h +++ b/src/xrCore/_std_extensions.h @@ -102,22 +102,27 @@ struct XRCORE_API xr_token2 // generic template -IC T _min(T a, T b) { return a < b ? a : b; } +IC T _min(T a, T b) { return std::min(a, b); } template -IC T _max(T a, T b) { return a > b ? a : b; } +IC T _max(T a, T b) { return std::max(a, b); } template IC T _sqr(T a) { return a * a; } // float IC float _abs(float x) { return fabsf(x); } +#include +IC float _sqrt_sse(float x) +{ + return _mm_cvtss_f32(_mm_sqrt_ss(_mm_set_ps1(x))); +} IC float _sqrt(float x) { return sqrtf(x); } IC float _sin(float x) { return sinf(x); } IC float _cos(float x) { return cosf(x); } IC BOOL _valid(const float x) { - // check for: Signaling NaN, Quiet NaN, Negative infinity ( –INF), Positive infinity (+INF), Negative denormalized, Positive denormalized + // check for: Signaling NaN, Quiet NaN, Negative infinity (-INF), Positive infinity (+INF), Negative denormalized, Positive denormalized int cls = _fpclass(double(x)); if (cls & (_FPCLASS_SNAN + _FPCLASS_QNAN + _FPCLASS_NINF + _FPCLASS_PINF + _FPCLASS_ND + _FPCLASS_PD)) return false; @@ -155,29 +160,43 @@ IC BOOL _valid(const double x) // int8 IC s8 _abs(s8 x) { return (x >= 0) ? x : s8(-x); } -IC s8 _min(s8 x, s8 y) { return y + ((x - y) & ((x - y) >> (sizeof(s8) * 8 - 1))); }; -IC s8 _max(s8 x, s8 y) { return x - ((x - y) & ((x - y) >> (sizeof(s8) * 8 - 1))); }; +IC s8 _min(s8 x, s8 y) { return std::min(x, y); } +IC s8 _max(s8 x, s8 y) { return std::max(x, y); } // unsigned int8 IC u8 _abs(u8 x) { return x; } // int16 IC s16 _abs(s16 x) { return (x >= 0) ? x : s16(-x); } -IC s16 _min(s16 x, s16 y) { return y + ((x - y) & ((x - y) >> (sizeof(s16) * 8 - 1))); }; -IC s16 _max(s16 x, s16 y) { return x - ((x - y) & ((x - y) >> (sizeof(s16) * 8 - 1))); }; +IC s16 _min(s16 x, s16 y) { return std::min(x, y); } +IC s16 _max(s16 x, s16 y) { return std::max(x, y); } // unsigned int16 IC u16 _abs(u16 x) { return x; } // int32 IC s32 _abs(s32 x) { return (x >= 0) ? x : s32(-x); } -IC s32 _min(s32 x, s32 y) { return y + ((x - y) & ((x - y) >> (sizeof(s32) * 8 - 1))); }; -IC s32 _max(s32 x, s32 y) { return x - ((x - y) & ((x - y) >> (sizeof(s32) * 8 - 1))); }; +IC s32 _min(s32 x, s32 y) { return std::min(x, y); } +IC s32 _max(s32 x, s32 y) { return std::max(x, y); } // int64 IC s64 _abs(s64 x) { return (x >= 0) ? x : s64(-x); } -IC s64 _min(s64 x, s64 y) { return y + ((x - y) & ((x - y) >> (sizeof(s64) * 8 - 1))); }; -IC s64 _max(s64 x, s64 y) { return x - ((x - y) & ((x - y) >> (sizeof(s64) * 8 - 1))); }; +IC s64 _min(s64 x, s64 y) { return std::min(x, y); } +IC s64 _max(s64 x, s64 y) { return std::max(x, y); } + +IC BOOL _fsimilar(float a, float b, float cmp = EPS) { return _abs(a - b) < cmp; } +IC float _powf(float x, float y) +{ + if (_fsimilar(y, 2.0f)) + return x * x; + if (_fsimilar(y, 0.5f)) + return _sqrt(x); + if (_fsimilar(y, 1.0f)) + return x; + if (_fsimilar(y, 0.0f)) + return 1.0f; + return powf(x, y); +} IC u32 xr_strlen(const char* S); diff --git a/src/xrCore/_stl_extensions.h b/src/xrCore/_stl_extensions.h index bad99c33ad..2b28212348 100644 --- a/src/xrCore/_stl_extensions.h +++ b/src/xrCore/_stl_extensions.h @@ -6,16 +6,25 @@ using std::swap; #include #include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include "_type_traits.h" #ifdef __BORLANDC__ #define M_NOSTDCONTAINERS_EXT #endif -#ifdef _M_AMD64 -#define M_DONTDEFERCLEAR_EXT -#endif -#define M_DONTDEFERCLEAR_EXT //. for mem-debug only +//#ifdef _M_AMD64 +//#define M_DONTDEFERCLEAR_EXT +//#endif +//#define M_DONTDEFERCLEAR_EXT //. for mem-debug only //-------- #ifdef M_NOSTDCONTAINERS_EXT @@ -106,6 +115,13 @@ class xalloc void deallocate(pointer p, size_type n) const { xr_free(p); } void deallocate(void* p, size_type n) const { xr_free(p); } void construct(pointer p, const T& _Val) { ::new((void*)p) T(_Val); } + + template + static void construct(pointer* ptr, Args&&... args) + { + new (ptr) T(std::forward(args)...); + } + void destroy(pointer p) { p->~value_type(); } size_type max_size() const @@ -144,8 +160,9 @@ namespace std inline xalloc<_Tp2> __stl_alloc_create(xalloc<_Tp1>&, const _Tp2*) { return xalloc<_Tp2>(); } }; -// string(char) -typedef std::basic_string, xalloc> xr_string; +// array +template +using xr_array = std::array; // vector template > @@ -172,8 +189,8 @@ class xr_vector : public std::vector u32 size() const { return (u32)inherited::size(); } - void clear_and_free() { inherited::clear(); } - void clear_not_free() { erase(begin(), end()); } + void clear_and_free() { inherited::clear(); inherited::shrink_to_fit(); } + void clear_not_free() { inherited::clear(); } void clear_and_reserve() { @@ -186,6 +203,29 @@ class xr_vector : public std::vector } } + // demonized: Swap and Pop, does NOT preserve order + iterator erase_fast(iterator it) + { + iterator prev = std::prev(end()); + if (it != prev) + { + if constexpr (std::is_trivially_move_assignable_v) + *it = std::move(back()); + else if constexpr (std::is_swappable_v) + std::iter_swap(it, prev); + else + *it = back(); + } + + pop_back(); + return it; + } + + iterator erase_fast(const_iterator cit) + { + return erase_fast(std::next(begin(), std::distance(cbegin(), cit))); + } + #ifdef M_DONTDEFERCLEAR_EXT void clear() { clear_and_free(); } #else @@ -247,6 +287,37 @@ class xr_deque : public std::deque u32 size() const { return (u32)__super::size(); } }; +// queue +template > +using xr_queue = std::queue; + +// fixed queue +template > +class xr_fixedqueue : public xr_queue +{ +private: + typedef xr_queue inherited; + void check_and_pop_front() + { + if (this->size() == MaxLen) + this->c.pop_front(); + } + +public: + void push(const T& value) + { + check_and_pop_front(); + inherited::push(value); + } + + template + void emplace(Args&&... args) + { + check_and_pop_front(); + inherited::emplace(std::forward(args)...); + } +}; + // stack template > class xr_stack @@ -289,14 +360,14 @@ using xr_pair = robin_hood::pair; template > using xr_unordered_map = robin_hood::unordered_node_map; -template > -using xr_unordered_set = robin_hood::unordered_node_set; +template , class Equal = std::equal_to> +using xr_unordered_set = robin_hood::unordered_node_set; -template > -using xr_unordered_flat_map = robin_hood::unordered_flat_map; +template , class Equal = std::equal_to> +using xr_unordered_flat_map = robin_hood::unordered_flat_map; -template > -using xr_unordered_flat_set = robin_hood::unordered_flat_set; +template , class Equal = std::equal_to> +using xr_unordered_flat_set = robin_hood::unordered_flat_set; #else @@ -329,6 +400,110 @@ class xr_list : public std::list u32 size() const { return (u32)__super::size(); } }; +template > +class xr_forward_list : public std::forward_list +{ +public: + u32 size() const { return (u32)__super::size(); } +}; + +template > +class xr_atomic_list : public std::list +{ +private: + mutable xrSRWLock lock; + +public: + using base_type = std::list; + using iterator = typename base_type::iterator; + using const_iterator = typename base_type::const_iterator; + using reference = typename base_type::reference; + using const_reference = typename base_type::const_reference; + + xrSRWLock& get_lock() { return lock; } + + // Size operations + u32 size() const + { + xrSRWLockGuard guard(lock, true); + return (u32)base_type::size(); + } + + bool empty() const + { + xrSRWLockGuard guard(lock, true); + return base_type::empty(); + } + + // Element access + reference front() + { + xrSRWLockGuard guard(lock, true); + return base_type::front(); + } + + const_reference front() const + { + xrSRWLockGuard guard(lock, true); + return base_type::front(); + } + + reference back() + { + xrSRWLockGuard guard(lock, true); + return base_type::back(); + } + + const_reference back() const + { + xrSRWLockGuard guard(lock, true); + return base_type::back(); + } + + // Modifiers + void push_front(const T& value) + { + xrSRWLockGuard guard(lock); + base_type::push_front(value); + } + + void push_back(const T& value) + { + xrSRWLockGuard guard(lock); + base_type::push_back(value); + } + + void pop_front() + { + xrSRWLockGuard guard(lock); + base_type::pop_front(); + } + + void pop_back() + { + xrSRWLockGuard guard(lock); + base_type::pop_back(); + } + + iterator erase(const_iterator position) + { + xrSRWLockGuard guard(lock); + return base_type::erase(position); + } + + iterator erase(const_iterator first, const_iterator last) + { + xrSRWLockGuard guard(lock); + return base_type::erase(first, last); + } + + void clear() + { + xrSRWLockGuard guard(lock); + base_type::clear(); + } +}; + template , typename allocator = xalloc> class xr_set : public std::set { @@ -357,6 +532,437 @@ class xr_multimap : public std::multimap u32 size() const { return (u32)__super::size(); } }; +// Insertion order map +template +class xr_ordered_map +{ +public: + // --- Standard std::map Typedefs --- + using key_type = Key; + using mapped_type = T; + // VERY IMPORTANT: const Key prevents modifying the key via list iterators + using value_type = std::pair; + using size_type = size_t; + using difference_type = ptrdiff_t; + + using list_type = xr_list; + using iterator = typename list_type::iterator; + using const_iterator = typename list_type::const_iterator; + using reverse_iterator = typename list_type::reverse_iterator; + using const_reverse_iterator = typename list_type::const_reverse_iterator; + + using map_type = xr_map; + +private: + list_type m_sequence; + map_type m_lookup; + +public: + // --- Construction & Assignment --- + xr_ordered_map() = default; + ~xr_ordered_map() = default; + + xr_ordered_map(const xr_ordered_map& other) + { + for (const auto& pair : other.m_sequence) + { + insert(pair); + } + } + + xr_ordered_map(xr_ordered_map&& other) noexcept + : m_sequence(std::move(other.m_sequence)), m_lookup(std::move(other.m_lookup)) {} + + xr_ordered_map(std::initializer_list init) + { + for (const auto& val : init) + { + insert(val); + } + } + + xr_ordered_map& operator=(const xr_ordered_map& other) + { + if (this != &other) + { + clear(); + for (const auto& pair : other.m_sequence) insert(pair); + } + return *this; + } + + xr_ordered_map& operator=(xr_ordered_map&& other) noexcept + { + if (this != &other) + { + m_sequence = std::move(other.m_sequence); + m_lookup = std::move(other.m_lookup); + } + return *this; + } + + // --- Iterators (Preserves Insertion Order) --- + iterator begin() noexcept { return m_sequence.begin(); } + const_iterator begin() const noexcept { return m_sequence.begin(); } + const_iterator cbegin() const noexcept { return m_sequence.cbegin(); } + + iterator end() noexcept { return m_sequence.end(); } + const_iterator end() const noexcept { return m_sequence.end(); } + const_iterator cend() const noexcept { return m_sequence.cend(); } + + reverse_iterator rbegin() noexcept { return m_sequence.rbegin(); } + const_reverse_iterator rbegin() const noexcept { return m_sequence.rbegin(); } + reverse_iterator rend() noexcept { return m_sequence.rend(); } + const_reverse_iterator rend() const noexcept { return m_sequence.rend(); } + + // --- Capacity --- + bool empty() const noexcept { return m_sequence.empty(); } + size_type size() const noexcept { return m_sequence.size(); } + + // --- Modifiers --- + void clear() noexcept + { + m_lookup.clear(); + m_sequence.clear(); + } + + std::pair insert(const value_type& value) + { + auto map_it = m_lookup.find(value.first); + if (map_it != m_lookup.end()) + { + return { map_it->second, false }; + } + m_sequence.push_back(value); + iterator list_it = std::prev(m_sequence.end()); + m_lookup.insert({ value.first, list_it }); + return { list_it, true }; + } + + template + std::pair emplace(Args&&... args) + { + // Construct element temporarily to check key + value_type val(std::forward(args)...); + return insert(std::move(val)); + } + + // Erase by key: O(log N) lookup + O(1) unlinking + size_type erase(const key_type& key) + { + auto map_it = m_lookup.find(key); + if (map_it == m_lookup.end()) return 0; + + m_sequence.erase(map_it->second); + m_lookup.erase(map_it); + return 1; + } + + // Erase by iterator: O(log N) map lookup + O(1) unlinking + iterator erase(const_iterator pos) + { + if (pos == m_sequence.end()) return m_sequence.end(); + + auto next_it = std::next(pos); + m_lookup.erase(pos->first); + m_sequence.erase(pos); + return next_it; + } + + void swap(xr_ordered_map& other) noexcept + { + m_sequence.swap(other.m_sequence); + m_lookup.swap(other.m_lookup); + } + + // --- Lookup --- + iterator find(const key_type& key) + { + auto map_it = m_lookup.find(key); + return (map_it != m_lookup.end()) ? map_it->second : m_sequence.end(); + } + + const_iterator find(const key_type& key) const + { + auto map_it = m_lookup.find(key); + return (map_it != m_lookup.end()) ? map_it->second : m_sequence.end(); + } + + size_type count(const key_type& key) const + { + return m_lookup.find(key) != m_lookup.end() ? 1 : 0; + } + + mapped_type& at(const key_type& key) + { + auto map_it = m_lookup.find(key); + R_ASSERT3(map_it != m_lookup.end(), "xr_ordered_map, key not found ", key); + return map_it->second->second; + } + + const mapped_type& at(const key_type& key) const + { + auto map_it = m_lookup.find(key); + R_ASSERT3(map_it != m_lookup.end(), "xr_ordered_map, key not found ", key); + return map_it->second->second; + } + + mapped_type& operator[](const key_type& key) + { + auto map_it = m_lookup.find(key); + if (map_it == m_lookup.end()) + { + auto res = insert(value_type(key, mapped_type())); + return res.first->second; + } + return map_it->second->second; + } +}; + +template +class xr_sparse_map { + // Ensure Key is an unsigned integer + static_assert(std::is_integral::value, "Key must be an integral type."); + static_assert(std::is_unsigned::value, "Key must be an unsigned type (to avoid negative indexing)."); + + // Ensure Key fits within MaxKeys (if MaxKeys is small) + static_assert(std::numeric_limits::max() >= MaxKeys - 1, "Key type is too small for MaxKeys."); + +public: + using key_type = Key; + using mapped_type = T; + using value_type = std::pair; + using reference = value_type&; + using const_reference = const value_type&; + using size_type = size_t; + using sparse_index_t = Key; + + // Iterators directly wrap the contiguous dense array + using iterator = typename xr_vector::iterator; + using const_iterator = typename xr_vector::const_iterator; + using reverse_iterator = typename xr_vector::reverse_iterator; + using const_reverse_iterator = typename xr_vector::const_reverse_iterator; + +private: + + // sparse[ID] returns the index in the dense array + xr_vector m_sparse; + // dense contains the actual contiguous data for fast iteration + xr_vector m_dense; + + inline void check_bounds(Key key) const + { + VERIFY2(key < MaxKeys, "ID out of bounds"); + } + +public: + xr_sparse_map() : m_sparse(MaxKeys, INVALID_INDEX) + { + m_dense.reserve(std::min(static_cast(MaxKeys), static_cast(16384))); + } + + // --- Iterators --- + iterator begin() noexcept { return m_dense.begin(); } + const_iterator begin() const noexcept { return m_dense.begin(); } + const_iterator cbegin() const noexcept { return m_dense.cbegin(); } + + iterator end() noexcept { return m_dense.end(); } + const_iterator end() const noexcept { return m_dense.end(); } + const_iterator cend() const noexcept { return m_dense.cend(); } + + reverse_iterator rbegin() noexcept { return m_dense.rbegin(); } + const_reverse_iterator rbegin() const noexcept { return m_dense.rbegin(); } + reverse_iterator rend() noexcept { return m_dense.rend(); } + const_reverse_iterator rend() const noexcept { return m_dense.rend(); } + + // --- Capacity --- + bool empty() const { return m_dense.empty(); } + size_type size() const { return m_dense.size(); } + +private: + // Correctly typed size for own logic + sparse_index_t dense_size() const { return static_cast(m_dense.size()); } + +public: + void clear() + { + std::fill(m_sparse.begin(), m_sparse.end(), INVALID_INDEX); + m_dense.clear(); + } + + // --- Lookup --- + iterator find(const Key& key) + { + check_bounds(key); + if (m_sparse[key] == INVALID_INDEX) + return end(); + return m_dense.begin() + m_sparse[key]; + } + + const_iterator find(const Key& key) const + { + check_bounds(key); + if (m_sparse[key] == INVALID_INDEX) + return end(); + return m_dense.begin() + m_sparse[key]; + } + + bool contains(Key key) const + { + check_bounds(key); + return m_sparse[key] != INVALID_INDEX; + } + + // --- Modifiers --- + // Key 0 will always be first in m_dense + template + std::pair emplace(Key key, Args&&... args) + { + check_bounds(key); + + sparse_index_t& idx = m_sparse[key]; + if (idx != INVALID_INDEX) + { + return { m_dense.begin() + idx, false }; // Already exists + } + + if (key == 0 && !m_dense.empty()) + { + Key old_first_key = m_dense[0].first; + m_dense.push_back(std::move(m_dense[0])); + + Key new_back_idx = dense_size() - 1; + m_sparse[old_first_key] = new_back_idx; + + m_dense[0] = value_type(key, T(std::forward(args)...)); + idx = 0; + } + else + { + idx = dense_size(); + m_dense.emplace_back( + std::piecewise_construct, + std::forward_as_tuple(key), + std::forward_as_tuple(std::forward(args)...) + ); + } + + return { m_dense.begin() + idx, true }; + } + + template + iterator emplace_hint(iterator hint, Key key, Args&&... args) + { + return emplace(key, std::forward(args)...).first; + } + + std::pair insert(const value_type& val) + { + return emplace(val.first, val.second); + } + + T& operator[](const Key& key) + { + // Calling emplace with no extra arguments perfectly forwards an empty list, + // resulting in T() being constructed (which acts identically to T{}). + // It returns a pair; .first gets the iterator, ->second gets the value reference. + return emplace(key).first->second; + } + +private: + void erase_at_index(sparse_index_t idx) + { + Key key_to_remove = m_dense[idx].first; + sparse_index_t last_idx = dense_size() - 1; + + if (idx != last_idx) + { + // Move the last element into the deleted spot + m_dense[idx] = std::move(m_dense[last_idx]); + + // Update the moved element's sparse link to the new position + m_sparse[m_dense[idx].first] = idx; + } + + // Clean up + m_sparse[key_to_remove] = INVALID_INDEX; + m_dense.pop_back(); + } + +public: + // Erase by Key + size_type erase(const Key& key) + { + check_bounds(key); + + sparse_index_t idx = m_sparse[key]; + if (idx == INVALID_INDEX) return 0; + + erase_at_index(idx); + return 1; + } + + // Erase by Iterator + iterator erase(iterator pos) + { + if (pos == end()) return end(); + + // Get the index by calculating the distance from the start + sparse_index_t idx = static_cast(std::distance(m_dense.begin(), pos)); + erase_at_index(idx); + + // Return the iterator pointing to the same slot + // (which now contains the swapped-in element or is end()) + return m_dense.begin() + idx; + } + + size_t count(Key key) const + { + return contains(key) ? 1 : 0; + } + + T& at(Key key) + { + check_bounds(key); + sparse_index_t idx = m_sparse[key]; + R_ASSERT3(idx != INVALID_INDEX, "xr_sparse_map: Item not found by ID ", key); + return m_dense[idx].second; + } + + void swap(xr_sparse_map& other) noexcept + { + std::swap(m_sparse, other.m_sparse); + std::swap(m_dense, other.m_dense); + } + + // Re-aligns the dense array by ID. Useful if you need sorted iteration. + // Complexity: O(N log N) for the sort + O(N) for the index rebuild. + void sort() + { + if (m_dense.empty()) return; + + // 1. Sort the dense array by Key (first member of the pair) + std::sort(m_dense.begin(), m_dense.end(), [](const value_type& a, const value_type& b) + { + return a.first < b.first; + }); + + // 2. The indices are now wrong, so we must rebuild the sparse array + rebuild_sparse(); + } + +private: + void rebuild_sparse() + { + std::fill(m_sparse.begin(), m_sparse.end(), INVALID_INDEX); + + for (sparse_index_t i = 0; i < dense_size(); ++i) + { + m_sparse[m_dense[i].first] = i; + } + } +}; + #ifdef STLPORT template , class _EqualKey = std::equal_to, typename allocator = xalloc > class xr_hash_set : public std::hash_set < V, _HashFcn, _EqualKey, allocator > { public: u32 size() const { return (u32)__super::size(); } }; template , class _EqualKey = std::equal_to, typename allocator = xalloc > class xr_hash_multiset : public std::hash_multiset < V, _HashFcn, _EqualKey, allocator > { public: u32 size() const { return (u32)__super::size(); } }; @@ -380,12 +986,12 @@ inline std::pair<_Ty1, _Ty2> mk_pair(_Ty1 _Val1, _Ty2 _Val2) { return (std::pair struct pred_str { - IC bool operator()(const char* x, const char* y) const { return xr_strcmp(x, y) < 0; } + IC bool operator()(const char* x, const char* y) const noexcept { return xr_strcmp(x, y) < 0; } }; struct pred_stri { - IC bool operator()(const char* x, const char* y) const { return stricmp(x, y) < 0; } + IC bool operator()(const char* x, const char* y) const noexcept { return stricmp(x, y) < 0; } }; // STL extensions @@ -423,7 +1029,6 @@ DEFINE_VECTOR(Fcolor*, LPFcolorVec, LPFcolorIt); DEFINE_VECTOR(LPSTR, LPSTRVec, LPSTRIt); DEFINE_VECTOR(LPCSTR, LPCSTRVec, LPCSTRIt); DEFINE_VECTOR(string64, string64Vec, string64It); -DEFINE_VECTOR(xr_string, SStringVec, SStringVecIt); DEFINE_VECTOR(s8, S8Vec, S8It); DEFINE_VECTOR(s8*, LPS8Vec, LPS8It); diff --git a/src/xrCore/_thread_types.h b/src/xrCore/_thread_types.h index f9fbddffd3..74b8203b5b 100644 --- a/src/xrCore/_thread_types.h +++ b/src/xrCore/_thread_types.h @@ -4,6 +4,10 @@ #include #include #include +#include +#include +#include +#include // Atomic types using xr_atomic_u32 = std::atomic_uint32_t; @@ -30,22 +34,20 @@ inline void xr_parallel_foreach(Index Begin, Index End, Body Functor) { concurrency::parallel_for_each(Begin, End, Functor); } +// Helper to deduce the value type for the default predicate +template +using IterValueT = typename std::iterator_traits::value_type; -// PPL behaviour - fallback to std::sort if chunk size < 2048 and cores < 2 -template -inline void xr_parallel_sort(Data& data, Body functor) -{ - concurrency::parallel_sort(std::begin(data), std::end(data), functor); -} +// Helper to check if an iterator is Random Access +template +using IsRandomAccess = std::is_base_of< + std::random_access_iterator_tag, + typename std::iterator_traits::iterator_category +>; -template -inline void xr_sort(Data& data, Body functor) -{ - std::sort(std::begin(data), std::end(data), functor); -} - -template -inline void xr_stable_sort(Data& data, Body functor) +// PPL behaviour - fallback to std::sort if chunk size < 2048 and cores < 2 +template>> +IC void xr_parallel_sort(RandomIt first, RandomIt last, P pred = {}) { - std::stable_sort(std::begin(data), std::end(data), functor); + concurrency::parallel_sort(first, last, pred); } diff --git a/src/xrCore/_vector3d.h b/src/xrCore/_vector3d.h index 68997af188..c75caf0ba2 100644 --- a/src/xrCore/_vector3d.h +++ b/src/xrCore/_vector3d.h @@ -834,4 +834,27 @@ IC BOOL exact_normalize(float* a) IC BOOL exact_normalize(Fvector3& a) { return exact_normalize(&a.x); } #pragma warning(pop) +ICF u32 GetFvectorHash(const Fvector& pos) +{ + // 1. Read bits directly (bypasses slow float-to-int CPU conversions) + u32 x = *(const u32*)&pos.x; + u32 y = *(const u32*)&pos.y; + u32 z = *(const u32*)&pos.z; + + // 2. Mix axes using large, distinct prime numbers + // This separates the axes so X, Y, and Z don't cancel each other out + u32 h = (x * 73856093u) ^ (y * 19349663u) ^ (z * 83492791u); + + // 3. Murmur3 Avalanche step + // Forces a single bit change in the input to cascade across all 32 bits of the output, + // completely shattering the IEEE 754 float memory layout. + h ^= h >> 16; + h *= 0x85ebca6bu; + h ^= h >> 13; + h *= 0xc2b2ae35u; + h ^= h >> 16; + + return h; +} + #endif diff --git a/src/xrCore/intrusive_ptr.h b/src/xrCore/intrusive_ptr.h index 1340cecb6e..5a1c35817b 100644 --- a/src/xrCore/intrusive_ptr.h +++ b/src/xrCore/intrusive_ptr.h @@ -48,7 +48,7 @@ struct ref_count_storage { if constexpr (Counter == CounterPolicy::Atomic) { - u32 t = __ref_count.fetch_sub(1, std::memory_order_acq_rel) + u32 t = __ref_count.fetch_sub(1, std::memory_order_acq_rel); return t - 1; } else @@ -58,17 +58,13 @@ struct ref_count_storage protected: IC bool intrusive_ref_sub_and_check() { - if constexpr (Counter == CounterPolicy::Atomic) + if (intrusive_ref_sub() == 0) { - if (__ref_count.fetch_sub(1, std::memory_order_acq_rel) == 1) - { - std::atomic_thread_fence(std::memory_order_acquire); - return true; - } - return false; + if constexpr (Counter == CounterPolicy::Atomic) std::atomic_thread_fence(std::memory_order_acquire); + return true; } else - return (--__ref_count == 0); + return false; } public: diff --git a/src/xrCore/log.cpp b/src/xrCore/log.cpp index 4298115b17..9036f79e1a 100644 --- a/src/xrCore/log.cpp +++ b/src/xrCore/log.cpp @@ -1,196 +1,53 @@ #include "stdafx.h" -#pragma hdrstop -#include #include "resource.h" #include "log.h" -#ifdef _EDITOR -#include "malloc.h" -#endif - -#include -#include -#include -#include -#include +#include "TimeUtils.h" #include "profiler.h" +#include "string_concatenations.h" -extern BOOL LogExecCB = TRUE; -static string_path logFName = "engine.log"; -static string_path log_file_name = "engine.log"; -static BOOL no_log = TRUE; -#ifdef PROFILE_CRITICAL_SECTIONS -static xrCriticalSection logCS(MUTEX_PROFILE_ID(log)); -#else // PROFILE_CRITICAL_SECTIONS -static xrCriticalSection logCS; -#endif // PROFILE_CRITICAL_SECTIONS -xr_vector LogFile; -static LogCallback LogCB = 0; - -void FlushLog() -{ - PROF_EVENT(); - - if (!no_log) - { - PROF_EVENT("Flushing"); - logCS.Enter(); - IWriter* f = FS.w_open(logFName); - if (f) - { - for (const auto& i : LogFile) - { - LPCSTR s = i.c_str(); - f->w_string(s ? s : ""); - } - FS.w_close(f); - } - logCS.Leave(); - } -} - -std::string getCurrentTimeStamp(LPCSTR format = "%d.%m.%Y %H:%M:%S") { - using namespace std::chrono; - - // get current time - auto now = system_clock::now(); - - // get number of milliseconds for the current second - // (remainder after division into seconds) - auto ms = duration_cast(now.time_since_epoch()) % 1000; +static xrLogger* theLogger = nullptr; +XRCORE_API xr_queue * xrLogger::logData; - // convert to std::time_t in order to convert to std::tm (broken time) - auto timer = system_clock::to_time_t(now); - - // convert to broken time - std::tm bt = *std::localtime(&timer); - - std::ostringstream oss; - - oss << std::put_time(&bt, format); // HH:MM:SS - oss << '.' << std::setfill('0') << std::setw(3) << ms.count(); - - return oss.str(); -} - -std::string timeInDMYHMSMMM() -{ - return getCurrentTimeStamp("%d.%m.%Y %H:%M:%S"); -} - -std::string timeInHMSMMM() +xr_string FormatString(LPCSTR fmt, ...) { - return getCurrentTimeStamp("%H:%M:%S"); + va_list mark; + string2048 buf; + va_start(mark, fmt); + int sz = _vsnprintf(buf, sizeof(buf) - 1, fmt, mark); + buf[sizeof(buf) - 1] = 0; + va_end(mark); + if (sz) return xr_string(buf); + return xr_string(""); } +// Timestamp flag and helpers BOOL logTimestamps = FALSE; enum Console_mark; extern bool is_console_mark(Console_mark type); -void AddOne(const char* split) -{ - - logCS.Enter(); - -#ifdef DEBUG - OutputDebugString(split); - OutputDebugString("\n"); -#endif - - // DUMP_PHASE; - { - // demonized: add timestamps to log - std::string t = split; - if (logTimestamps) { - std::string c = ""; - if (t.length() > 0 && is_console_mark((Console_mark)t[0])) { - c += t[0]; - c += " "; - t.erase(0, 1); - } - t = c + "[" + timeInHMSMMM() + "] " + t; - } - auto temp = shared_str(t.c_str()); - static shared_str last_str; - static int items_count; - - if (last_str.equal(temp)) - { - xr_string tmp = temp.c_str(); - - if (items_count == 0) - items_count = 2; - else - items_count++; - - tmp += " ["; - tmp += std::to_string(items_count).c_str(); - tmp += "]"; - - LogFile.erase(LogFile.end()-1); - LogFile.push_back(xr_string(tmp.c_str())); - } - else - { - // DUMP_PHASE; - LogFile.push_back(xr_string(temp.c_str())); - last_str = temp; - items_count = 0; - } - } - - //exec CallBack - if (LogExecCB && LogCB)LogCB(split); - - logCS.Leave(); -} - void Log(const char* s) { - int i, j; - - u32 length = xr_strlen(s); -#ifndef _EDITOR - PSTR split = (PSTR)_alloca((length + 1) * sizeof(char)); -#else - PSTR split = (PSTR)alloca((length + 1) * sizeof(char)); -#endif - for (i = 0, j = 0; s[i] != 0; i++) - { - if (s[i] == '\n') - { - split[j] = 0; // end of line - if (split[0] == 0) - { - split[0] = ' '; - split[1] = 0; - } - AddOne(split); - j = 0; - } - else - { - split[j++] = s[i]; - } - } - split[j] = 0; - AddOne(split); + theLogger->SimpleMessage(s); } -void __cdecl Msg(const char* format, ...) +void Msg(const char *format, ...) { - va_list mark; - string2048 buf; - va_start(mark, format); - int sz = _vsnprintf(buf, sizeof(buf) - 1, format, mark); - buf[sizeof(buf) - 1] = 0; - va_end(mark); - if (sz) Log(buf); + if (!format) + return; + + va_list mark; + va_start (mark, format ); + theLogger->Msg(format, mark); + va_end (mark); } void Log(const char* msg, const char* dop) { + if (!msg) + return; + if (!dop) { Log(msg); @@ -205,6 +62,9 @@ void Log(const char* msg, const char* dop) void Log(const char* msg, u32 dop) { + if (!msg) + return; + u32 buffer_size = (xr_strlen(msg) + 1 + 10 + 1) * sizeof(char); PSTR buf = (PSTR)_alloca(buffer_size); @@ -214,6 +74,9 @@ void Log(const char* msg, u32 dop) void Log(const char* msg, int dop) { + if (!msg) + return; + u32 buffer_size = (xr_strlen(msg) + 1 + 11 + 1) * sizeof(char); PSTR buf = (PSTR)_alloca(buffer_size); @@ -223,6 +86,9 @@ void Log(const char* msg, int dop) void Log(const char* msg, float dop) { + if (!msg) + return; + // actually, float string representation should be no more, than 40 characters, // but we will count with slight overhead u32 buffer_size = (xr_strlen(msg) + 1 + 64 + 1) * sizeof(char); @@ -232,10 +98,13 @@ void Log(const char* msg, float dop) Log(buf); } -void Log(const char* msg, const Fvector& dop) +void Log (const char *msg, const Fvector &dop) { + if (!msg) + return; + u32 buffer_size = (xr_strlen(msg) + 2 + 3 * (64 + 1) + 1) * sizeof(char); - PSTR buf = (PSTR)_alloca(buffer_size); + char* buf = (char*)_alloca(buffer_size); xr_sprintf(buf, buffer_size, "%s (%f,%f,%f)", msg, VPUSH(dop)); Log(buf); @@ -243,77 +112,342 @@ void Log(const char* msg, const Fvector& dop) void Log(const char* msg, const Fmatrix& dop) { - u32 buffer_size = (xr_strlen(msg) + 2 + 4 * (4 * (64 + 1) + 1) + 1) * sizeof(char); - PSTR buf = (PSTR)_alloca(buffer_size); + if (!msg) + return; + + u32 buffer_size = (xr_strlen(msg) + 2 + 4 * (4 * (64 + 1) + 1) + 1) * sizeof(char); + char* buf = (char*)_alloca(buffer_size); xr_sprintf(buf, buffer_size, "%s:\n%f,%f,%f,%f\n%f,%f,%f,%f\n%f,%f,%f,%f\n%f,%f,%f,%f\n", - msg, - dop.i.x, dop.i.y, dop.i.z, dop._14_, - dop.j.x, dop.j.y, dop.j.z, dop._24_, - dop.k.x, dop.k.y, dop.k.z, dop._34_, - dop.c.x, dop.c.y, dop.c.z, dop._44_ + msg, + dop.i.x, dop.i.y, dop.i.z, dop._14_, + dop.j.x, dop.j.y, dop.j.z, dop._24_, + dop.k.x, dop.k.y, dop.k.z, dop._34_, + dop.c.x, dop.c.y, dop.c.z, dop._44_ ); Log(buf); } void LogWinErr(const char* msg, long err_code) { + if (!msg) + return; + Msg("%s: %s", msg, Debug.error2string(err_code)); } -LogCallback SetLogCB(LogCallback cb) +void xrLogger::Msg(LPCSTR Msg, va_list argList) +{ + if (!Msg) + return; + + string4096 formattedMessage; + int MsgSize = _vsnprintf(formattedMessage, sizeof(formattedMessage) - 1, Msg, argList); + + if (MsgSize < 0) + return; + + formattedMessage[MsgSize] = 0; + + { + OutputDebugStringA(formattedMessage); + OutputDebugStringA("\n"); + } + + SimpleMessage(formattedMessage, MsgSize); +} + +void xrLogger::PauseLogging() +{ + ResetEvent(hLogThread); +} + +void xrLogger::UnpauseLogging() +{ + if (bImmediateMode) + InternalPrintAllRecords(); + else + SetEvent(hLogThread); +} + +void xrLogger::SimpleMessage(LPCSTR Message, u32 MessageSize /*= 0*/) +{ + if (!Message) + return; + + switch (MessageSize) + { + case (u32(-1)): return; + case 0: MessageSize = xr_strlen(Message); break; + default: break; + } + + xr_string msgToLog = Message; + if (logTimestamps) + { + xr_string t = msgToLog; + xr_string c = ""; + if (!t.empty() && is_console_mark((Console_mark)t[0])) + { + c += t[0]; + c += " "; + t.erase(0, 1); + } + msgToLog = c + "[" + timeInHMSMMM() + "] " + t; + } + + xrCriticalSectionGuard guard(&logDataGuard); + if (bIsAlive) + { + logData->emplace(LogRecord(msgToLog.c_str(), (u32)msgToLog.size())); + UnpauseLogging(); + } + +} + +void xrLogger::OpenLogFile() +{ + static bool isLogOpened = false; + if (!isLogOpened) { + theLogger->InternalOpenLogFile(); + isLogOpened = true; + } +} + +const string_path& xrLogger::GetLogPath() +{ + return theLogger->logFileName; +} + +void xrLogger::EnableFastDebugLog() +{ + theLogger->bFastDebugLog = true; +} + +void LogThreadEntryStartup(void* nullParam) +{ + PROF_THREAD("Logger Thread"); + theLogger->UnpauseLogging(); + theLogger->LogThreadEntry(); +} + +void xrLogger::InitLog() +{ + if (theLogger == nullptr) + { + theLogger = new xrLogger; + xrLogger::logData = new xr_queue ; + thread_spawn(LogThreadEntryStartup, "X-Ray Log Thread", 0, nullptr); + } +} + +void xrLogger::InternalFlushLog() +{ + xrCriticalSectionGuard g(logFlushGuard); + PROF_EVENT("Log Flush") + if (logFile != nullptr) + { + IWriter* mutableWritter = (IWriter*)logFile; + mutableWritter->flush(); + } +} + +void xrLogger::FlushLog() +{ + theLogger->bFlushRequested = true; + theLogger->UnpauseLogging(); +} + +void xrLogger::SetImmediateMode(bool enable) { - LogCallback result = LogCB; - LogCB = cb; - return (result); + if (theLogger == nullptr) + return; + + theLogger->bImmediateMode = enable; } -LPCSTR log_name() +void xrLogger::CloseLog() { - return (log_file_name); + theLogger->InternalCloseLog(); } -void InitLog() +void xrLogger::AddLogCallback(LogCallback logCb) { - LogFile.reserve(10000); + if (logCb == nullptr) + return; + + xrCriticalSectionGuard guard(&theLogger->logCallbackGuard); + theLogger->logCallbackList.push_back(logCb); } -void CreateLog(BOOL nl) +void xrLogger::RemoveLogCallback(LogCallback logCb) { - no_log = nl; - strconcat(sizeof(log_file_name), log_file_name, Core.ApplicationName, "_", Core.UserName, ".log"); + xrCriticalSectionGuard guard(&theLogger->logCallbackGuard); + theLogger->logCallbackList.remove(logCb); +} + +void xrLogger::InternalCloseLog() +{ + SimpleMessage("[xrLogger] InternalCloseLog called, terminating thread"); + bIsAlive = false; + + InternalPrintAllRecords(); + InternalFlushLog(); + + IWriter* tempCopy = (IWriter*)logFile; + logFile = nullptr; + + if (tempCopy != nullptr) + FS.w_close(tempCopy); + + UnpauseLogging(); +} + +xrLogger::xrLogger() + : logFile(nullptr), bFastDebugLog(false), + bIsAlive(true), + bFlushRequested(false), + bImmediateMode(false) +{ + hLogThread = CreateEvent(nullptr, TRUE, FALSE, nullptr); +} + +xrLogger::~xrLogger() +{ + InternalCloseLog(); +} + +void xrLogger::InternalOpenLogFile() +{ + // IXRay format + /*string256 CurrentDate; + string256 CurrentTime; + Time time; + xr_strconcat(CurrentDate, time.GetYearString().c_str(), ".", time.GetMonthString().c_str(), ".", time.GetDayString().c_str()); + xr_strconcat(CurrentTime, time.GetHoursString().c_str(), ".", time.GetMinutesString().c_str(), ".", time.GetSecondsString().c_str()); + xr_strconcat(logFileName, Core.ApplicationName, "-", CurrentDate, "-", CurrentTime, "-", Core.UserName, ".log");*/ + + // Vanilla + xr_strconcat(logFileName, Core.ApplicationName, "_", Core.UserName, ".log"); + + //Alun: Backup existing log + xr_string backup_logFName = EFS.ChangeFileExt(logFileName, ".bkp"); + FS.file_rename(logFileName, backup_logFName.c_str(), true); + //-Alun + if (FS.path_exist("$logs$")) - FS.update_path(logFName, "$logs$", log_file_name); - if (!no_log) { - //Alun: Backup existing log - xr_string backup_logFName = EFS.ChangeFileExt(logFName, ".bkp"); - FS.file_rename(logFName, backup_logFName.c_str(), true); - //-Alun - IWriter* f = FS.w_open(logFName); - if (f == NULL) + FS.update_path(logFileName, "$logs$", logFileName); + } + logFile = FS.w_open(logFileName); + CHECK_OR_EXIT(logFile, "Can't create log file"); +} + +void xrLogger::InternalPrintRecord() +{ + LogRecord theRecord; + + { + xrCriticalSectionGuard g(&logDataGuard); + theRecord = logData->front(); + logData->pop(); + } + + xr_vector LogLines = theRecord.Message.Split('\n'); + + string256 TimeOfDay = {}; + + PROF_EVENT("Log: Apply Messages") + int TimeOfDaySize = 0; + for (const xr_string& line : LogLines) + { + string4096 finalLine; + xr_strconcat(finalLine, TimeOfDay, line.c_str()); + + int FinalSize = TimeOfDaySize + (int)line.size(); + // line is ready, ready up everything + + // Output to MSVC debug output + if (IsDebuggerPresent() && !bFastDebugLog) { - MessageBox(NULL, "Can't create log file.", "Error", MB_ICONERROR); - abort(); + OutputDebugStringA(finalLine); + OutputDebugStringA("\n"); + } + + // demonized: add tempLogData in case the logFile initialization takes time + if (logFile != nullptr) + { + IWriter* mutableWritter = (IWriter*)logFile; + + while (!tempLogData.empty()) + { + auto line = tempLogData.front(); + tempLogData.pop(); + mutableWritter->w(line.c_str(), line.size()); + mutableWritter->w("\r\n", 2); + } + + // write to file + mutableWritter->w(finalLine, FinalSize); + mutableWritter->w("\r\n", 2); + if (bImmediateMode) + InternalFlushLog(); + } + else + { + tempLogData.push(finalLine); + } + + xrCriticalSectionGuard guard(&logCallbackGuard); + for (const LogCallback& FnCallback : logCallbackList) + { + FnCallback(finalLine); } - FS.w_close(f); } } -void CloseLog(void) +void xrLogger::InternalPrintAllRecords() { - FlushLog(); - LogFile.clear(); + while (true) + { + { + xrCriticalSectionGuard g(&logDataGuard); + if (logData->empty()) + break; + } + InternalPrintRecord(); + } } -xr_string FormatString(LPCSTR fmt, ...) +void xrLogger::LogThreadEntry() { - va_list mark; - string2048 buf; - va_start(mark, fmt); - int sz = _vsnprintf(buf, sizeof(buf) - 1, fmt, mark); - buf[sizeof(buf) - 1] = 0; - va_end(mark); - if (sz) return xr_string(buf); - return xr_string(""); + auto FlushLogIfRequestedLambda = [this]() + { + if (bFlushRequested) + { + InternalFlushLog(); + bFlushRequested = false; + } + }; + + while (true) + { + if (!bIsAlive) + { + CloseHandle(hLogThread); + return; + } + + WaitForSingleObject(hLogThread, INFINITE); + { + PROF_EVENT("Log Frame"); + InternalPrintAllRecords(); + PauseLogging(); + FlushLogIfRequestedLambda(); + } + } } + +xrLogger::LogRecord::LogRecord(LPCSTR Msg, u32 sizeMsg) + : Message(Msg, sizeMsg) +{} diff --git a/src/xrCore/log.h b/src/xrCore/log.h index cbe22c4312..ac17469419 100644 --- a/src/xrCore/log.h +++ b/src/xrCore/log.h @@ -1,29 +1,83 @@ -#ifndef logH -#define logH - -#define VPUSH(a) ((a).x), ((a).y), ((a).z) - -void XRCORE_API __cdecl Msg(LPCSTR format, ...); -void XRCORE_API Log(LPCSTR msg); -void XRCORE_API Log(LPCSTR msg); -void XRCORE_API Log(LPCSTR msg, LPCSTR dop); -void XRCORE_API Log(LPCSTR msg, u32 dop); -void XRCORE_API Log(LPCSTR msg, int dop); -void XRCORE_API Log(LPCSTR msg, float dop); -void XRCORE_API Log(LPCSTR msg, const Fvector& dop); -void XRCORE_API Log(LPCSTR msg, const Fmatrix& dop); -void XRCORE_API LogWinErr(LPCSTR msg, long err_code); - -typedef void (*LogCallback)(LPCSTR string); -LogCallback XRCORE_API SetLogCB(LogCallback cb); -void XRCORE_API CreateLog(BOOL no_log = FALSE); -void InitLog(); -void CloseLog(); -void XRCORE_API FlushLog(); - -extern XRCORE_API xr_vector LogFile; -extern XRCORE_API BOOL LogExecCB; +#pragma once +#include "DateTime.hpp" +#include +#define VPUSH(a) ((a).x), ((a).y), ((a).z) + +void XRCORE_API Msg (const char* format, ...); + +// Old shit +void XRCORE_API Log (const char* msg); +void XRCORE_API Log (const char* msg, const Fvector& dop); +void XRCORE_API Log (const char* msg, const Fmatrix& dop); +void XRCORE_API Log (const char* msg, const char* dop); +void XRCORE_API Log (const char* msg, u32 dop); +void XRCORE_API Log (const char* msg, int dop); +void XRCORE_API Log (const char* msg, float dop); +void XRCORE_API LogWinErr(const char* msg, long err_code); xr_string FormatString(LPCSTR fmt, ...); -#endif +class XRCORE_API xrLogger +{ +public: + using LogCallback = void(*) (const char* string); + + void Msg(LPCSTR Msg, va_list argList); + void SimpleMessage(LPCSTR Message, u32 MessageSize = 0); + + static void OpenLogFile(); + static const string_path& GetLogPath(); + static void EnableFastDebugLog(); + static void InitLog(); + static void FlushLog(); + static void CloseLog(); + static void SetImmediateMode(bool enable); + + static void AddLogCallback(LogCallback logCb); + static void RemoveLogCallback(LogCallback logCb); + + void PauseLogging(); + void UnpauseLogging(); + + xrLogger(); + ~xrLogger(); + + void LogThreadEntry(); + +private: + void InternalCloseLog(); + volatile bool bIsAlive; + ThreadID hLogThread; + + void InternalOpenLogFile(); + + void InternalPrintRecord(); + void InternalPrintAllRecords(); + + void InternalFlushLog(); + + string_path logFileName; + volatile IWriter* logFile; + + struct LogRecord + { + LogRecord() {} + LogRecord(LPCSTR Msg, u32 sizeMsg); + xr_string Message; + Time time; + }; + + xrCriticalSection logDataGuard; + xrCriticalSection logCallbackGuard; + xrCriticalSection logFlushGuard; + bool bFastDebugLog; + + std::atomic_bool bFlushRequested; + bool bImmediateMode; + + //LogCallback onLogMsg; + xr_list logCallbackList; + xr_fixedqueue tempLogData; +public: + static xr_queue * logData; +}; diff --git a/src/xrCore/memory_usage.cpp b/src/xrCore/memory_usage.cpp index be133d8394..6996391b92 100644 --- a/src/xrCore/memory_usage.cpp +++ b/src/xrCore/memory_usage.cpp @@ -25,8 +25,11 @@ XRCORE_API void vminfo(size_t* _free, size_t* reserved, size_t* committed) } } +xrCriticalSection mem_lock; XRCORE_API void log_vminfo() { + xrCriticalSectionGuard g(mem_lock); + PROF_EVENT("log_vminfo"); size_t w_free, w_reserved, w_committed; vminfo(&w_free, &w_reserved, &w_committed); Msg( @@ -37,8 +40,10 @@ XRCORE_API void log_vminfo() ); } -size_t xrMemory::mem_usage() +size_t xrMemory::mem_usage(bool assert) { + xrCriticalSectionGuard g(mem_lock); + PROF_EVENT("mem_usage"); _HEAPINFO hinfo = {}; int status; size_t bytesUsed = 0; @@ -54,13 +59,13 @@ size_t xrMemory::mem_usage() case _HEAPEND: break; case _HEAPBADPTR: - FATAL("bad pointer to heap"); + if (assert) FATAL("bad pointer to heap"); break; case _HEAPBADBEGIN: - FATAL("bad start of heap"); + if (assert) FATAL("bad start of heap"); break; case _HEAPBADNODE: - FATAL("bad node in heap"); + if (assert) FATAL("bad node in heap"); break; } return bytesUsed; diff --git a/src/xrCore/net_utils.h b/src/xrCore/net_utils.h index ef8df6a910..f8b8b2d1bc 100644 --- a/src/xrCore/net_utils.h +++ b/src/xrCore/net_utils.h @@ -8,54 +8,6 @@ const u32 NET_PacketSizeLimit = 16 * 1024; -struct XRCORE_API IIniFileStream -{ - virtual void __stdcall move_begin() = 0; - - virtual void __stdcall w_float(float a) = 0; - virtual void __stdcall w_vec3(const Fvector& a) = 0; - virtual void __stdcall w_vec4(const Fvector4& a) = 0; - virtual void __stdcall w_u64(u64 a) = 0; - virtual void __stdcall w_s64(s64 a) = 0; - virtual void __stdcall w_u32(u32 a) = 0; - virtual void __stdcall w_s32(s32 a) = 0; - virtual void __stdcall w_u16(u16 a) = 0; - virtual void __stdcall w_s16(s16 a) = 0; - virtual void __stdcall w_u8(u8 a) = 0; - virtual void __stdcall w_s8(s8 a) = 0; - virtual void __stdcall w_stringZ(LPCSTR S) = 0; - - virtual void __stdcall r_vec3(Fvector&) = 0; - virtual void __stdcall r_vec4(Fvector4&) = 0; - virtual void __stdcall r_float(float&) = 0; - virtual void __stdcall r_u8(u8&) = 0; - virtual void __stdcall r_u16(u16&) = 0; - virtual void __stdcall r_u32(u32&) = 0; - virtual void __stdcall r_u64(u64&) = 0; - virtual void __stdcall r_s8(s8&) = 0; - virtual void __stdcall r_s16(s16&) = 0; - virtual void __stdcall r_s32(s32&) = 0; - virtual void __stdcall r_s64(s64&) = 0; - - virtual void __stdcall r_string(LPSTR dest, u32 dest_size) = 0; - // virtual void __stdcall r_tell () = 0; - // virtual void __stdcall r_seek (u32 pos) = 0; - virtual void __stdcall skip_stringZ() = 0; -}; - - -#define INI_W(what_to_do)\ -if(inistream)\ -{\ - inistream->what_to_do;\ -} - -#define INI_ASSERT(what_to_do)\ -{\ -if(inistream)\ - R_ASSERT3(0,#what_to_do,"not implemented");\ -} - struct NET_Buffer { BYTE data[NET_PacketSizeLimit]; @@ -65,8 +17,6 @@ struct NET_Buffer class XRCORE_API NET_Packet { public: - IIniFileStream* inistream; - void construct(const void* data, unsigned size) { memcpy(B.data, data, size); @@ -76,35 +26,23 @@ class XRCORE_API NET_Packet NET_Buffer B; u32 r_pos; u32 timeReceive; - bool w_allow; public: - NET_Packet() : inistream(NULL), w_allow(true) - { - } + NET_Packet() = default; // writing - main IC void write_start() { B.count = 0; - INI_W(move_begin()); } IC void w_begin(u16 type) { B.count = 0; - w_u16(type); + w(&type, sizeof(u16)); } - struct W_guard - { - bool* guarded; - W_guard(bool* b) : guarded(b) { *b = true; } - ~W_guard() { *guarded = false; } - }; - IC void w(const void* p, u32 count) { - R_ASSERT(inistream == NULL || w_allow); VERIFY(p && count); VERIFY(B.count + count < NET_PacketSizeLimit); CopyMemory(&B.data[B.count], p, count); @@ -115,91 +53,52 @@ class XRCORE_API NET_Packet void w_seek(u32 pos, const void* p, u32 count); IC u32 w_tell() { return B.count; } - // writing - utilities - IC void w_float(float a) - { - W_guard g(&w_allow); - w(&a, 4); - INI_W(w_float(a)); - } // float - IC void w_vec3(const Fvector& a) - { - W_guard g(&w_allow); - w(&a, 3 * sizeof(float)); - INI_W(w_vec3(a)); - } // vec3 - IC void w_vec4(const Fvector4& a) + // read/write operators + template + void operator<<(const T& value) { - W_guard g(&w_allow); - w(&a, 4 * sizeof(float)); - INI_W(w_vec4(a)); - } // vec4 - IC void w_u64(u64 a) - { - W_guard g(&w_allow); - w(&a, 8); - INI_W(w_u64(a)); - } // qword (8b) - IC void w_s64(s64 a) - { - W_guard g(&w_allow); - w(&a, 8); - INI_W(w_s64(a)); - } // qword (8b) - IC void w_u32(u32 a) - { - W_guard g(&w_allow); - w(&a, 4); - INI_W(w_u32(a)); - } // dword (4b) - IC void w_s32(s32 a) - { - W_guard g(&w_allow); - w(&a, 4); - INI_W(w_s32(a)); - } // dword (4b) - IC void w_u16(u16 a) - { - W_guard g(&w_allow); - w(&a, 2); - INI_W(w_u16(a)); - } // word (2b) - IC void w_s16(s16 a) - { - W_guard g(&w_allow); - w(&a, 2); - INI_W(w_s16(a)); - } // word (2b) - IC void w_u8(u8 a) - { - W_guard g(&w_allow); - w(&a, 1); - INI_W(w_u8(a)); - } // byte (1b) - IC void w_s8(s8 a) + w(&value, (u32)sizeof(T)); + } + + template + void operator>>(T& value) { - W_guard g(&w_allow); - w(&a, 1); - INI_W(w_s8(a)); - } // byte (1b) + r(&value, (u32)sizeof(T)); + } + + // writing - utilities + IC void w_float(float a) { w(&a, 4); } // float + IC void w_vec3(const Fvector& a) { w(&a, 3 * sizeof(float)); } // vec3 + IC void w_vec4(const Fvector4& a) { w(&a, 4 * sizeof(float)); } // vec4 + IC void w_u64(u64 a) { w(&a, 8); } // qword (8b) + IC void w_s64(s64 a) { w(&a, 8); } // qword (8b) + IC void w_u32(u32 a) { w(&a, 4); } // dword (4b) + IC void w_s32(s32 a) { w(&a, 4); } // dword (4b) + IC void w_u16(u16 a) { w(&a, 2); } // word (2b) + IC void w_s16(s16 a) { w(&a, 2); } // word (2b) + IC void w_u8(u8 a) { w(&a, 1); } // byte (1b) + IC void w_s8(s8 a) { w(&a, 1); } // byte (1b) IC void w_float_q16(float a, float min, float max) { VERIFY(a >= min && a <= max); float q = (a - min) / (max - min); - w_u16(u16(iFloor(q * 65535.f + 0.5f))); + u16 Value = u16(iFloor(q * 65535.f + 0.5f)); + w(&Value, sizeof(u16)); } IC void w_float_q8(float a, float min, float max) { VERIFY(a >= min && a <= max); float q = (a - min) / (max - min); - w_u8(u8(iFloor(q * 255.f + 0.5f))); + + u8 Value = u8(iFloor(q * 255.f + 0.5f)); + w(&Value, sizeof(u8)); } IC void w_angle16(float a) { w_float_q16(angle_normalize(a), 0, PI_MUL_2); } IC void w_angle8(float a) { w_float_q8(angle_normalize(a), 0, PI_MUL_2); } - IC void w_dir(const Fvector& D) { w_u16(pvCompress(D)); } + IC void w_dir(const Fvector& D) { u16 value = pvCompress(D); w(&value, sizeof(u16)); } IC void w_sdir(const Fvector& D) { Fvector C; @@ -214,47 +113,40 @@ class XRCORE_API NET_Packet mag = 0; } w_dir(C); - w_float(mag); + w(&mag, sizeof(float)); } IC void w_stringZ(LPCSTR S) { - W_guard g(&w_allow); w(S, (u32)xr_strlen(S) + 1); - INI_W(w_stringZ(S)); } IC void w_stringZ(const shared_str& p) { - W_guard g(&w_allow); if (*p) w(*p, p.size() + 1); else { - IIniFileStream* tmp = inistream; - inistream = NULL; - w_u8(0); - inistream = tmp; //hack -( + u8 data = 0; + w(&data, sizeof(u8)); } - - INI_W(w_stringZ(p.c_str())); } IC void w_matrix(Fmatrix& M) { - w_vec3(M.i); - w_vec3(M.j); - w_vec3(M.k); - w_vec3(M.c); + w(&M.i, sizeof(Fvector)); + w(&M.j, sizeof(Fvector)); + w(&M.k, sizeof(Fvector)); + w(&M.c, sizeof(Fvector)); } - IC void w_clientID(ClientID& C) { w_u32(C.value()); } + IC void w_clientID(ClientID& C) { u32 val = C.value(); w(&val, sizeof(u32)); } IC void w_chunk_open8(u32& position) { position = w_tell(); - w_u8(0); - INI_ASSERT(w_chunk_open8) + u8 data = 0; + w(&data, sizeof(u8)); } IC void w_chunk_close8(u32 position) @@ -263,14 +155,13 @@ class XRCORE_API NET_Packet VERIFY(size < 256); u8 _size = (u8)size; w_seek(position, &_size, sizeof(_size)); - INI_ASSERT(w_chunk_close8) } IC void w_chunk_open16(u32& position) { position = w_tell(); - w_u16(0); - INI_ASSERT(w_chunk_open16) + u16 data = 0; + w(&data, sizeof(u16)); } IC void w_chunk_close16(u32 position) @@ -279,7 +170,6 @@ class XRCORE_API NET_Packet VERIFY(size < 65536); u16 _size = (u16)size; w_seek(position, &_size, sizeof(_size)); - INI_ASSERT(w_chunk_close16) } // reading @@ -290,7 +180,6 @@ class XRCORE_API NET_Packet IC void r(void* p, u32 count) { - R_ASSERT(inistream == NULL); VERIFY(p && count); CopyMemory(p, &B.data[r_pos], count); r_pos += count; diff --git a/src/xrCore/ppmd_compressor.h b/src/xrCore/ppmd_compressor.h index 980e6e01cf..e12d9b9bff 100644 --- a/src/xrCore/ppmd_compressor.h +++ b/src/xrCore/ppmd_compressor.h @@ -1,7 +1,7 @@ #ifndef PPMD_COMPRESSOR_H #define PPMD_COMPRESSOR_H -#include +#include "xr_delegate.h" namespace compression { @@ -20,7 +20,7 @@ XRCORE_API u32 ppmd_decompress(void* dest_buffer, const u32& dest_buffer_size, c XRCORE_API u32 ppmd_trained_decompress(void* dest_buffer, const u32& dest_buffer_size, const void* source_buffer, const u32& source_buffer_size, compression::ppmd::stream* tmodel); -typedef fastdelegate::FastDelegate ppmd_yield_callback_t; +using ppmd_yield_callback_t = xr_delegate; XRCORE_API u32 ppmd_compress_mt(void* dest_buffer, const u32& dest_buffer_size, const void* source_buffer, const u32& source_buffer_size, ppmd_yield_callback_t ycb); XRCORE_API u32 ppmd_decompress_mt(void* dest_buffer, const u32& dest_buffer_size, const void* source_buffer, diff --git a/src/xrCore/profiler.h b/src/xrCore/profiler.h index efca306db1..b360ff790a 100644 --- a/src/xrCore/profiler.h +++ b/src/xrCore/profiler.h @@ -19,6 +19,9 @@ # define PROF_SAVE_CAPTURE(Name) OPTICK_SAVE_CAPTURE(Name) # define PROF_FRAME(Name) OPTICK_FRAME(Name) # define PROF_EVENT(Name) OPTICK_EVENT(Name) +# define PROF_EVENT_DYNAMIC(...) static ::Optick::EventDescription* OPTICK_CONCAT(autogen_description_, __LINE__) = nullptr; \ + OPTICK_CONCAT(autogen_description_, __LINE__) = ::Optick::CreateDescription(OPTICK_FUNC, __FILE__, __LINE__, ##__VA_ARGS__); \ + ::Optick::Event OPTICK_CONCAT(autogen_event_, __LINE__)( *(OPTICK_CONCAT(autogen_description_, __LINE__)) ); # define START_PROFILE(a) { PROF_EVENT(a) # define STOP_PROFILE } #else diff --git a/src/xrCore/stdafx.h b/src/xrCore/stdafx.h index 3d83c34fa2..5873cb19a3 100644 --- a/src/xrCore/stdafx.h +++ b/src/xrCore/stdafx.h @@ -10,6 +10,7 @@ #include "xrCore.h" #include "xrCore_platform.h" +#include "profiler.h" //.#include "../../Include/xrAPI/xrAPI.h" #endif diff --git a/src/xrCore/string_concatenations.cpp b/src/xrCore/string_concatenations.cpp index e85b18b86d..9e49f3aaf5 100644 --- a/src/xrCore/string_concatenations.cpp +++ b/src/xrCore/string_concatenations.cpp @@ -1,6 +1,20 @@ #include "stdafx.h" #include "string_concatenations.h" +bool XRCORE_API _strconcatSingle(char*& destPtr, char* pDestEnd, const char* src) +{ + if (!src) return true; + + // We stop at pDestEnd - 1 to ensure space for the null terminator + while (*src && (destPtr < (pDestEnd - 1))) + { + *destPtr++ = *src++; + } + + // Return true if we reached the end of the source string successfully + return (*src == '\0'); +} + namespace xray { namespace core @@ -309,16 +323,3 @@ LPSTR strconcat(int dest_sz, char* dest, const char* S1, const char* S2, const c return (dest); } - -int XRCORE_API _strconcatSingle(char*& destPtr, char* pDestEnd, const char* Str) -{ - char* TargetStrCursor = const_cast (Str); - for (; *TargetStrCursor && destPtr < pDestEnd; destPtr++, TargetStrCursor++) - { - *destPtr = *TargetStrCursor; - } - - R_ASSERT3(!(*TargetStrCursor), "Failed to concatenate string", Str); - - return 0; -} \ No newline at end of file diff --git a/src/xrCore/string_concatenations.h b/src/xrCore/string_concatenations.h index 71f680cd89..1386a6dd30 100644 --- a/src/xrCore/string_concatenations.h +++ b/src/xrCore/string_concatenations.h @@ -1,5 +1,11 @@ -#ifndef STRING_CONCATENATIONS_H -#define STRING_CONCATENATIONS_H +////////////////////////////////////////////////////////// +// Desc : String concat system +// Author : Giperion +////////////////////////////////////////////////////////// +// Oxygen Engine 2.0 - 2016-2019(c) +////////////////////////////////////////////////////////// + +#pragma once #ifndef _EDITOR @@ -44,6 +50,8 @@ IC char* strconcat(int dest_sz, char* dest, const char* S1, const char* S2, cons #endif +bool XRCORE_API _strconcatSingle(char*& destPtr, char* pDestEnd, const char* src); + // warning: do not comment this macro, as stack overflow check is very light // (consumes ~1% performance of STRCONCAT macro) #ifndef _EDITOR @@ -78,19 +86,36 @@ IC char* strconcat(int dest_sz, char* dest, const char* S1, const char* S2, cons template char* xr_strconcat(StringReceiverType& receiver, ArgList... args) { - static_assert(std::is_array< StringReceiverType>::value); // must be array... - static_assert(std::is_same::type, char>::value); // ... of chars - - char* pStrCursor = &receiver[0]; - char* pStrEnd = &receiver[0] + sizeof(StringReceiverType); - int dummy[] = { _strconcatSingle(pStrCursor, pStrEnd, args)... }; - (void)dummy; - - *pStrCursor = '\0'; - return &receiver[0]; + static_assert(std::is_array< StringReceiverType>::value); // must be array... + static_assert(std::is_same::type, char>::value); // ... of chars + + char* pStrCursor = &receiver[0]; + char* pStrEnd = &receiver[0] + sizeof(StringReceiverType); + const char* errorSource = nullptr; + + // Use a lambda to process args and catch the first one that fails + auto process = [&](const char* s) + { + if (!errorSource && !_strconcatSingle(pStrCursor, pStrEnd, s)) + { + errorSource = s; + } + }; + + // Fold expression (C++17) or initializer list trick to process args + (process(args), ...); + + // If errorSource is set, one of the strings was truncated + if (errorSource) + { + Debug.fatal(DEBUG_INFO, + "String Buffer Overflow!\n" + "Max Capacity: %zu bytes\n" + "Failed at string: \"%s\"\n" + "Current buffer state: \"%s\"", + sizeof(StringReceiverType), errorSource, &receiver[0]); + } + + *pStrCursor = '\0'; // Guaranteed safe because of the -1 check in _strconcatSingle + return &receiver[0]; } - -int XRCORE_API _strconcatSingle(char*& destPtr, char* pDestEnd, const char* Str); - - -#endif // #ifndef STRING_CONCATENATIONS_H \ No newline at end of file diff --git a/src/xrCore/vector.h b/src/xrCore/vector.h index a09e225528..c01a1d10b5 100644 --- a/src/xrCore/vector.h +++ b/src/xrCore/vector.h @@ -307,6 +307,35 @@ IC float angle_inertion_var(float src, float tgt, float min_speed, float max_spe return src; } +IC Fvector EulerYawPitchRollInertion(const Fvector& current_ypr, const Fvector& target_ypr, float speed, float dt) +{ + Fvector diff; + + for (int i = 0; i < 3; i++) + { + float curr = angle_normalize(current_ypr[i]); + float targ = angle_normalize(target_ypr[i]); + + diff[i] = targ - curr; + if (diff[i] > PI) diff[i] -= PI_MUL_2; + else if (diff[i] < -PI) diff[i] += PI_MUL_2; + } + + float diff_length = diff.magnitude(); + if (diff_length < EPS_S) return Fvector{ current_ypr.x, current_ypr.y, current_ypr.z }; + + float max_move = speed * dt; + + if (diff_length > max_move) + { + float scale = max_move / diff_length; + diff.x *= scale; + diff.y *= scale; + diff.z *= scale; + } + return Fvector{ angle_normalize(current_ypr.x + diff.x), angle_normalize(current_ypr.y + diff.y), angle_normalize(current_ypr.z + diff.z) }; +}; + template IC _matrix& _matrix::rotation(const _quaternion& Q) { diff --git a/src/xrCore/xrCore.cpp b/src/xrCore/xrCore.cpp index 8cebdb786c..b91e56f4ed 100644 --- a/src/xrCore/xrCore.cpp +++ b/src/xrCore/xrCore.cpp @@ -36,22 +36,21 @@ static u32 init_counter = 0; extern int get_modded_exes_version(); extern xr_string get_modded_exes_version_string(); extern LPCSTR get_modded_exes_name(); -extern std::string timeInDMYHMSMMM(); +extern xr_string timeInDMYHMSMMM(); -void xrCore::_initialize(LPCSTR _ApplicationName, LogCallback cb, BOOL init_fs, LPCSTR fs_fname) +void xrCore::_initialize(LPCSTR _ApplicationName, xrLogger::LogCallback cb, BOOL init_fs, LPCSTR fs_fname) { + PROF_EVENT("xrCore::_initialize"); xr_strcpy(ApplicationName, _ApplicationName); if (0 == init_counter) { #ifdef XRCORE_STATIC - _clear87(); - _control87(_PC_53, MCW_PC); - _control87(_RC_CHOP, MCW_RC); - _control87(_RC_NEAR, MCW_RC); - _control87(_MCW_EM, MCW_EM); + _clear87(); + _control87(_PC_53, MCW_PC); + _control87(_RC_CHOP, MCW_RC); + _control87(_RC_NEAR, MCW_RC); + _control87(_MCW_EM, MCW_EM); #endif - // Init COM so we can use CoCreateInstance - // HRESULT co_res = Params = xr_strdup(GetCommandLine()); xr_strlwr(Params); if (!strstr(Params, "-editor")) @@ -64,20 +63,6 @@ void xrCore::_initialize(LPCSTR _ApplicationName, LogCallback cb, BOOL init_fs, _splitpath(fn, dr, di, 0, 0); strconcat(sizeof(ApplicationPath), ApplicationPath, dr, di); -#ifndef _EDITOR - // xr_strcpy(g_application_path, sizeof(g_application_path), ApplicationPath); -#endif - -#ifdef _EDITOR - // working path - if (strstr(Params, "-wf")) - { - string_path c_name; - sscanf(strstr(Core.Params, "-wf ") + 4, "%[^ ] ", c_name); - SetCurrentDirectory(c_name); - } -#endif - GetCurrentDirectory(sizeof(WorkingPath), WorkingPath); // User/Comp Name @@ -90,15 +75,13 @@ void xrCore::_initialize(LPCSTR _ApplicationName, LogCallback cb, BOOL init_fs, // Mathematics & PSI detection CPU::Detect(); - Memory._initialize(strstr(Params, "-mem_debug") ? TRUE : FALSE); + Memory._initialize(Core.ParamsData.test(ECoreParams::mem_debug)); DUMP_PHASE; - InitLog(); + xrLogger::InitLog(); _initialize_cpu(); - // Debug._initialize (); - rtc_initialize(); time_t _time = time(NULL); @@ -140,26 +123,20 @@ void xrCore::_initialize(LPCSTR _ApplicationName, LogCallback cb, BOOL init_fs, Params = xr_strdup(temp); } cmdlineTxt.close(); + + xrParams::LoadParams(); } if (init_fs) { u32 flags = 0; - if (0 != strstr(Params, "-build")) flags |= CLocatorAPI::flBuildCopy; - if (0 != strstr(Params, "-ebuild")) flags |= CLocatorAPI::flBuildCopy | CLocatorAPI::flEBuildCopy; -#ifdef DEBUG - if (strstr(Params, "-cache")) flags |= CLocatorAPI::flCacheFiles; - else flags &= ~CLocatorAPI::flCacheFiles; -#endif // DEBUG + if (Core.ParamsData.test(ECoreParams::build)) + flags |= CLocatorAPI::flBuildCopy; + if (Core.ParamsData.test(ECoreParams::ebuild)) + flags |= CLocatorAPI::flBuildCopy | CLocatorAPI::flEBuildCopy; #ifdef _EDITOR // for EDITORS - no cache - flags &= ~CLocatorAPI::flCacheFiles; + flags &= ~CLocatorAPI::flCacheFiles; #endif // _EDITOR flags |= CLocatorAPI::flScanAppRoot; - -#ifndef _EDITOR -#ifndef ELocatorAPIH - if (0 != strstr(Params, "-file_activity")) flags |= CLocatorAPI::flDumpFileActivity; -#endif -#endif FS._initialize(flags, 0, fs_fname); Msg("'%s' build %d, %s\n", "xrCore", build_id, build_date); @@ -169,11 +146,11 @@ void xrCore::_initialize(LPCSTR _ApplicationName, LogCallback cb, BOOL init_fs, EFS._initialize(); #ifdef DEBUG #ifndef _EDITOR - Msg("Process heap 0x%08x", GetProcessHeap()); + Msg("Process heap 0x%08x", GetProcessHeap()); #endif #endif // DEBUG } - SetLogCB(cb); + xrLogger::AddLogCallback(cb); init_counter++; } diff --git a/src/xrCore/xrCore.h b/src/xrCore/xrCore.h index 6e24e6d5be..2f1906f5d8 100644 --- a/src/xrCore/xrCore.h +++ b/src/xrCore/xrCore.h @@ -301,17 +301,22 @@ DEFINE_VECTOR(xr_rtoken, RTokenVec, RTokenVecIt); #endif #include "FileSystem.h" #include "FTimer.h" -#include +#include "xr_delegate.h" #include "_noncopyable.h" #include "intrusive_ptr.h" #include "net_utils.h" +#include "xrParams.h" + +#include "_thread_types.h" // CRC32 functions XRCORE_API u32 crc32(const void* P, u32 len); XRCORE_API u32 crc32(const void* P, u32 len, u32 starting_crc); XRCORE_API u32 path_crc32(const char* path, u32 len); +#define xr_stdcall __stdcall + // destructor template class destructor @@ -336,12 +341,16 @@ class XRCORE_API xrCore string64 UserName; string64 CompName; char* Params; + xr_bitsetflags ParamsData; DWORD dwFrame; bool april1; public: - void _initialize(LPCSTR ApplicationName, LogCallback cb = 0, BOOL init_fs = TRUE, LPCSTR fs_fname = 0); + void _initialize(LPCSTR ApplicationName, xrLogger::LogCallback cb = 0, BOOL init_fs = TRUE, LPCSTR fs_fname = 0); void _destroy(); + IC bool isDebug() { + return ParamsData.test(ECoreParams::dbg) || ParamsData.test(ECoreParams::dbgdev) || ParamsData.test(ECoreParams::dbgact) || ParamsData.test(ECoreParams::dbgbullet); + } }; //Borland class dll interface diff --git a/src/xrCore/xrCore.vcxproj b/src/xrCore/xrCore.vcxproj index 115c9eaec6..e09f8ca46e 100644 --- a/src/xrCore/xrCore.vcxproj +++ b/src/xrCore/xrCore.vcxproj @@ -13,6 +13,10 @@ Release x64 + + VerifiedDX11ASAN + x64 + VerifiedDX11 x64 @@ -57,6 +61,14 @@ false x64 + + StaticLibrary + v143 + MultiByte + false + x64 + true + StaticLibrary v143 @@ -87,6 +99,11 @@ + + + + + @@ -116,6 +133,11 @@ $(xrGameDir)bin_dbg\$(Platform)\$(Configuration)\ $(xrIntDir)$(ProjectName)\ + + false + $(xrGameDir)bin_dbg\$(Platform)\$(Configuration)\ + $(xrIntDir)$(ProjectName)\ + false $(xrGameDir)bin_dbg\$(Platform)\$(Configuration)\ @@ -202,7 +224,7 @@ false false .;$(SolutionDir)3rd party\optick-git\src;$(XRAY_16X_LIBS);$(xrSdkDir)include;%(AdditionalIncludeDirectories) - PROFILER_OPTICK;USE_VERIFY_IN_RELEASE;PURE_ALLOC;WIN32;NDEBUG;_WINDOWS;_USRDLL;XRCORE_EXPORTS;_SECURE_SCL=0;%(PreprocessorDefinitions) + XRCORE_PROFILER;PROFILER_OPTICK;USE_VERIFY_IN_RELEASE;PURE_ALLOC;WIN32;NDEBUG;_WINDOWS;_USRDLL;XRCORE_EXPORTS;_SECURE_SCL=0;%(PreprocessorDefinitions) NotSet Use EditAndContinue @@ -240,7 +262,7 @@ false false .;$(SolutionDir)3rd party\optick-git\src;$(XRAY_16X_LIBS);$(xrSdkDir)include;%(AdditionalIncludeDirectories) - PROFILER_OPTICK;USE_VERIFY_IN_RELEASE;PURE_ALLOC;WIN32;NDEBUG;_WINDOWS;_USRDLL;XRCORE_EXPORTS;_SECURE_SCL=0;%(PreprocessorDefinitions) + XRCORE_PROFILER;PROFILER_OPTICK;USE_VERIFY_IN_RELEASE;PURE_ALLOC;WIN32;NDEBUG;_WINDOWS;_USRDLL;XRCORE_EXPORTS;_SECURE_SCL=0;%(PreprocessorDefinitions) NotSet Use EditAndContinue @@ -268,6 +290,44 @@ true + + + Disabled + Disabled + false + Neither + false + false + false + .;$(SolutionDir)3rd party\optick-git\src;$(XRAY_16X_LIBS);$(xrSdkDir)include;%(AdditionalIncludeDirectories) + XRCORE_PROFILER;_DISABLE_VECTOR_ANNOTATION;_DISABLE_STRING_ANNOTATION;PROFILER_OPTICK;USE_VERIFY_IN_RELEASE;PURE_ALLOC;WIN32;NDEBUG;_WINDOWS;_USRDLL;XRCORE_EXPORTS;_SECURE_SCL=0;%(PreprocessorDefinitions) + NotSet + Use + ProgramDatabase + USE_LUAJIT_ONE + true + false + Level4 + MultiThreadedDLL + false + stdcpp17 + /Zc:__cplusplus %(AdditionalOptions) + true + + + $(xrSdkDir)libraries;$(XRAY_16X_LIBS)BugTrap\Bin;$(xrLibDir);%(AdditionalLibraryDirectories) + NotSet + true + true + true + Default + false + + + $(xrLibDir)$(TargetName).lib + true + + .;$(SolutionDir)3rd party\optick-git\src;$(XRAY_16X_LIBS);$(xrSdkDir)include;%(AdditionalIncludeDirectories) @@ -314,12 +374,15 @@ + + TurnOffAllWarnings TurnOffAllWarnings TurnOffAllWarnings TurnOffAllWarnings + TurnOffAllWarnings TurnOffAllWarnings @@ -331,12 +394,15 @@ + + TurnOffAllWarnings TurnOffAllWarnings TurnOffAllWarnings TurnOffAllWarnings + TurnOffAllWarnings TurnOffAllWarnings @@ -348,12 +414,15 @@ + + TurnOffAllWarnings TurnOffAllWarnings TurnOffAllWarnings TurnOffAllWarnings + TurnOffAllWarnings TurnOffAllWarnings @@ -361,6 +430,7 @@ true true true + true true @@ -370,12 +440,15 @@ + + TurnOffAllWarnings TurnOffAllWarnings TurnOffAllWarnings TurnOffAllWarnings + TurnOffAllWarnings TurnOffAllWarnings @@ -387,12 +460,15 @@ + + TurnOffAllWarnings TurnOffAllWarnings TurnOffAllWarnings TurnOffAllWarnings + TurnOffAllWarnings TurnOffAllWarnings @@ -404,12 +480,15 @@ + + TurnOffAllWarnings TurnOffAllWarnings TurnOffAllWarnings TurnOffAllWarnings + TurnOffAllWarnings TurnOffAllWarnings @@ -421,12 +500,15 @@ + + TurnOffAllWarnings TurnOffAllWarnings TurnOffAllWarnings TurnOffAllWarnings + TurnOffAllWarnings TurnOffAllWarnings @@ -438,12 +520,15 @@ + + $(IntDir)%(Filename)1.obj $(IntDir)%(Filename)1.obj $(IntDir)%(Filename)1.obj $(IntDir)%(Filename)1.obj + $(IntDir)%(Filename)1.obj $(IntDir)%(Filename)1.obj @@ -455,12 +540,15 @@ + + TurnOffAllWarnings TurnOffAllWarnings TurnOffAllWarnings TurnOffAllWarnings + TurnOffAllWarnings TurnOffAllWarnings @@ -481,6 +569,7 @@ true true true + true true @@ -500,12 +589,15 @@ + + TurnOffAllWarnings TurnOffAllWarnings TurnOffAllWarnings TurnOffAllWarnings + TurnOffAllWarnings TurnOffAllWarnings @@ -525,6 +617,7 @@ Create Create Create + Create Create @@ -535,6 +628,7 @@ true true true + true true @@ -547,6 +641,7 @@ + @@ -557,6 +652,7 @@ + @@ -598,6 +694,7 @@ true true true + true true @@ -631,6 +728,7 @@ + @@ -643,10 +741,12 @@ + + @@ -658,6 +758,7 @@ + @@ -678,6 +779,8 @@ + + diff --git a/src/xrCore/xrCore.vcxproj.filters b/src/xrCore/xrCore.vcxproj.filters index 8028f60d6f..0da4d164cd 100644 --- a/src/xrCore/xrCore.vcxproj.filters +++ b/src/xrCore/xrCore.vcxproj.filters @@ -291,6 +291,10 @@ shared memory/string library + + FS + + @@ -608,14 +612,28 @@ Profiling - - - + Kernel - + + FS + + + FS + + + + Kernel + + Kernel + + + Kernel + + + diff --git a/src/xrCore/xrDebug.cpp b/src/xrCore/xrDebug.cpp index c6ba52729c..513de88cc0 100644 --- a/src/xrCore/xrDebug.cpp +++ b/src/xrCore/xrDebug.cpp @@ -87,7 +87,7 @@ void xrDebug::backend(const char* reason, const char* expression, const char* ar string1024 tmp; xr_sprintf(tmp, "***STOP*** file '%s', line %d.\n***Reason***: %s\n %s", file, line, reason, expression); Msg(tmp); - FlushLog(); + xrLogger::FlushLog(); if (handler) handler(); if (IsDebuggerPresent()) @@ -192,7 +192,7 @@ void __cdecl xrDebug::fatal(const char* file, int line, const char* function, co void xrDebug::do_exit(const std::string& message) { - FlushLog(); + xrLogger::FlushLog(); MessageBox(NULL, message.c_str(), "Error", MB_OK | MB_ICONERROR | MB_SYSTEMMODAL); TerminateProcess(GetCurrentProcess(), 1); } @@ -357,6 +357,7 @@ _CRTIMP _PNH __cdecl _set_new_handler(_PNH); void xrDebug::_initialize(const bool& dedicated) { + PROF_EVENT("xrDebug::_initialize"); handler = 0; _set_new_mode(1); // gen exception if can't allocate memory _set_new_handler(_out_of_memory); // exception-handler for 'out of memory' condition diff --git a/src/xrCore/xrDebugNew.cpp b/src/xrCore/xrDebugNew.cpp index 2f3ff4e9aa..c2fae70382 100644 --- a/src/xrCore/xrDebugNew.cpp +++ b/src/xrCore/xrDebugNew.cpp @@ -193,7 +193,7 @@ void xrDebug::gather_info(const char* expression, const char* description, const if (shared_str_initialized) { Msg("%s", assertion_info); - FlushLog(); + xrLogger::FlushLog(); } buffer = assertion_info; endline = "\r\n"; @@ -230,7 +230,7 @@ void xrDebug::gather_info(const char* expression, const char* description, const // } if (shared_str_initialized) - FlushLog(); + xrLogger::FlushLog(); os_clipboard::copy_to_clipboard(assertion_info); } @@ -238,7 +238,7 @@ void xrDebug::gather_info(const char* expression, const char* description, const void xrDebug::do_exit(const std::string& message) { - FlushLog(); + xrLogger::FlushLog(); MessageBox(NULL, message.c_str(), "Error", MB_OK | MB_ICONERROR | MB_SYSTEMMODAL); TerminateProcess(GetCurrentProcess(), 1); } @@ -272,7 +272,7 @@ void xrDebug::backend(const char* expression, const char* description, const cha if (handler) handler(); - FlushLog(); + xrLogger::FlushLog(); if (IsDebuggerPresent()) DebugBreak(); @@ -498,7 +498,7 @@ void __cdecl xrDebug::fatal(const char* file, int line, const char* function, co backend(nullptr, "fatal error", buffer, 0, file, line, function, ignore_always); } -typedef void (*full_memory_stats_callback_type)(); +typedef void (*full_memory_stats_callback_type)(bool); XRCORE_API full_memory_stats_callback_type g_full_memory_stats_callback = 0; int out_of_memory_handler(size_t size) @@ -506,16 +506,17 @@ int out_of_memory_handler(size_t size) Msg("* [x-ray]: OOM requesting %lld bytes", size); if (g_full_memory_stats_callback) - g_full_memory_stats_callback(); + g_full_memory_stats_callback(true); else { Memory.mem_compact(); size_t process_heap = Memory.mem_usage(); u32 eco_strings_count = 0; - int eco_strings = (int)g_pStringContainer->stat_economy(eco_strings_count); + u32 eco_strings_unique_count = 0; + int eco_strings = (int)g_pStringContainer->stat_economy(eco_strings_count, eco_strings_unique_count); int eco_smem = (int)g_pSharedMemoryContainer->stat_economy(); Msg("* [x-ray]: process heap[%llu K]", process_heap / 1024); - Msg("* [x-ray]: strings: memory[%ld K], count[%lu]", eco_strings / 1024, eco_strings_count); + Msg("* [x-ray]: strings: memory[%ld K], count[%lu], unique[%lu]", eco_strings / 1024, eco_strings_count, eco_strings_unique_count); Msg("* [x-ray]: shared: memory[%ld K]", eco_smem); } @@ -801,6 +802,7 @@ void format_message(LPSTR buffer, const u32& buffer_size) //AVO: simplify function LONG WINAPI UnhandledFilter(_EXCEPTION_POINTERS* pExceptionInfo) { + xrLogger::SetImmediateMode(true); string256 error_message; format_message(error_message, sizeof(error_message)); @@ -851,7 +853,7 @@ LONG WINAPI UnhandledFilter(_EXCEPTION_POINTERS* pExceptionInfo) } //return EXCEPTION_CONTINUE_EXECUTION; - FlushLog(); + xrLogger::FlushLog(); # ifdef USE_OWN_MINI_DUMP save_mini_dump(pExceptionInfo); diff --git a/src/xrCore/xrMemory.cpp b/src/xrCore/xrMemory.cpp index 8b194e3d2e..60daf28f34 100644 --- a/src/xrCore/xrMemory.cpp +++ b/src/xrCore/xrMemory.cpp @@ -82,7 +82,7 @@ void xrMemory::_initialize(BOOL bDebug) #ifndef M_BORLAND #ifndef PURE_ALLOC - if (!strstr(Core.Params, "-pure_alloc")) + if (!Core.ParamsData.test(ECoreParams::pure_alloc)) { // initialize POOLs u32 element = mem_pools_ebase; @@ -97,14 +97,14 @@ void xrMemory::_initialize(BOOL bDebug) #endif // M_BORLAND #ifdef DEBUG_MEMORY_MANAGER - if (0 == strstr(Core.Params, "-memo")) mem_initialized = TRUE; + if (!Core.ParamsData.test(ECoreParams::memo)) mem_initialized = TRUE; else g_bMEMO = TRUE; #else // DEBUG_MEMORY_MANAGER mem_initialized = TRUE; #endif // DEBUG_MEMORY_MANAGER // DUMP_PHASE; - g_pStringContainer = xr_new(); + g_pStringContainer = str_container::create(); shared_str_initialized = true; // DUMP_PHASE; g_pSharedMemoryContainer = xr_new(); @@ -128,8 +128,11 @@ void xrMemory::_destroy() if (debug_mode) dbg_dump_str_leaks(); #endif // DEBUG_MEMORY_MANAGER + // Release own reference of g_pStringContainer + // The actual str_container will be destroyed only when no shared_str instances hold it + g_pStringContainer = nullptr; + xr_delete(g_pSharedMemoryContainer); - xr_delete(g_pStringContainer); #ifndef M_BORLAND # ifdef DEBUG_MEMORY_MANAGER @@ -145,6 +148,7 @@ void xrMemory::_destroy() void xrMemory::mem_compact() { + PROF_EVENT("mem_compact"); #ifdef DEBUG_MEMORY_MANAGER RegFlushKey(HKEY_CLASSES_ROOT); RegFlushKey(HKEY_CURRENT_USER); @@ -153,8 +157,6 @@ void xrMemory::mem_compact() HeapCompact(GetProcessHeap(), 0); if (g_pStringContainer) g_pStringContainer->clean(); if (g_pSharedMemoryContainer) g_pSharedMemoryContainer->clean(); - if (strstr(Core.Params, "-swap_on_compact")) - SetProcessWorkingSetSize(GetCurrentProcess(), size_t(-1), size_t(-1)); #endif } @@ -273,13 +275,11 @@ void xrMemory::mem_statistic(LPCSTR fn) // xr_strdup char* xr_strdup(const char* string) { - VERIFY(string); - u32 len = u32(xr_strlen(string)) + 1; - char* memory = (char*)Memory.mem_alloc(len -#ifdef DEBUG_MEMORY_NAME - , "strdup" -#endif // DEBUG_MEMORY_NAME - ); + if (string == nullptr) + return nullptr; + + const size_t len = xr_strlen(string) + 1; + char* memory = (char*)Memory.mem_alloc(len); CopyMemory(memory, string, len); return memory; } diff --git a/src/xrCore/xrMemory.h b/src/xrCore/xrMemory.h index da97fbe8df..2ba9038b60 100644 --- a/src/xrCore/xrMemory.h +++ b/src/xrCore/xrMemory.h @@ -60,17 +60,17 @@ class XRCORE_API xrMemory void dbg_unregister(void* _p); void dbg_check(); - size_t mem_usage(); + size_t mem_usage(bool assert = true); void mem_compact(); void mem_counter_set(u32 _val) { stat_counter = _val; } u32 mem_counter_get() { return stat_counter; } #ifdef DEBUG_MEMORY_NAME void mem_statistic(LPCSTR fn); - void* mem_alloc(size_t size, const char* _name); + void* mem_alloc(size_t size, const char* _name, bool zeroMemory = true); void* mem_realloc(void* p, size_t size, const char* _name); #else // DEBUG_MEMORY_NAME - void* mem_alloc(size_t size); + void* mem_alloc(size_t size, bool zeroMemory = true); void* mem_realloc(void* p, size_t size); #endif // DEBUG_MEMORY_NAME void mem_free(void* p); diff --git a/src/xrCore/xrMemory_subst_msvc.cpp b/src/xrCore/xrMemory_subst_msvc.cpp index aa17935d58..21f106b875 100644 --- a/src/xrCore/xrMemory_subst_msvc.cpp +++ b/src/xrCore/xrMemory_subst_msvc.cpp @@ -35,10 +35,7 @@ ICF u32 get_pool(size_t size) else return pid; } -#ifdef PURE_ALLOC -const bool g_use_pure_alloc = true; -#endif // PURE_ALLOC - +#define PURE_ALLOC #define PURE_MEMORY_FILL_ZERO #define PURE_MEMORY_ALIGNMENT 1 << 4 @@ -46,17 +43,16 @@ void* xrMemory::mem_alloc(size_t size # ifdef DEBUG_MEMORY_NAME , const char* _name # endif // DEBUG_MEMORY_NAME -) +, bool zeroMemory) { stat_calls++; #ifdef PURE_ALLOC - if (g_use_pure_alloc) { //void* result = malloc(size); void* result = _aligned_malloc(size, PURE_MEMORY_ALIGNMENT); #ifdef PURE_MEMORY_FILL_ZERO - if (result) + if (result && zeroMemory) memset(result, 0, size); #endif // PURE_MEMORY_FILL_ZERO @@ -127,7 +123,8 @@ void* xrMemory::mem_alloc(size_t size #ifdef USE_MEMORY_MONITOR memory_monitor::monitor_alloc(_ptr, size, _name); #endif // USE_MEMORY_MONITOR - memset(_ptr, 0, size); + if (zeroMemory) + memset(_ptr, 0, size); return _ptr; } @@ -139,7 +136,6 @@ void xrMemory::mem_free(void* P) #endif // USE_MEMORY_MONITOR #ifdef PURE_ALLOC - if (g_use_pure_alloc) { //free(P); _aligned_free(P); @@ -194,7 +190,6 @@ void* xrMemory::mem_realloc(void* P, size_t size } #ifdef PURE_ALLOC - if (g_use_pure_alloc) { #ifdef PURE_MEMORY_FILL_ZERO size_t old_size = P ? _aligned_msize(P, PURE_MEMORY_ALIGNMENT, 0) : 0; diff --git a/src/xrCore/xrMemory_subst_msvc.h b/src/xrCore/xrMemory_subst_msvc.h index 7b92abd32b..269548fd36 100644 --- a/src/xrCore/xrMemory_subst_msvc.h +++ b/src/xrCore/xrMemory_subst_msvc.h @@ -1,156 +1,38 @@ +#pragma once +#include + #ifdef DEBUG_MEMORY_NAME -// new(0) -template -IC T* xr_new() -{ - T* ptr = (T*)Memory.mem_alloc(sizeof(T), typeid(T).name()); - return new (ptr)T(); -} -// new(1) -template -IC T* xr_new(const P1& p1) +template +IC T* xr_new(Args&&... args) { T* ptr = (T*)Memory.mem_alloc(sizeof(T), typeid(T).name()); - return new (ptr)T(p1); -} -// new(2) -template -IC T* xr_new(const P1& p1, const P2& p2) -{ - T* ptr = (T*)Memory.mem_alloc(sizeof(T), typeid(T).name()); - return new (ptr)T(p1, p2); -} -// new(3) -template -IC T* xr_new(const P1& p1, const P2& p2, const P3& p3) -{ - T* ptr = (T*)Memory.mem_alloc(sizeof(T), typeid(T).name()); - return new (ptr)T(p1, p2, p3); -} -// new(4) -template -IC T* xr_new(const P1& p1, const P2& p2, const P3& p3, const P4& p4) -{ - T* ptr = (T*)Memory.mem_alloc(sizeof(T), typeid(T).name()); - return new (ptr)T(p1, p2, p3, p4); -} -// new(5) -template -IC T* xr_new(const P1& p1, const P2& p2, const P3& p3, const P4& p4, const P5& p5) -{ - T* ptr = (T*)Memory.mem_alloc(sizeof(T), typeid(T).name()); - return new (ptr)T(p1, p2, p3, p4, p5); -} -// new(6) -template -IC T* xr_new(const P1& p1, const P2& p2, const P3& p3, const P4& p4, const P5& p5, const P6& p6) -{ - T* ptr = (T*)Memory.mem_alloc(sizeof(T), typeid(T).name()); - return new (ptr)T(p1, p2, p3, p4, p5, p6); -} -// new(7) -template -IC T* xr_new(const P1& p1, const P2& p2, const P3& p3, const P4& p4, const P5& p5, const P6& p6, const P7& p7) -{ - T* ptr = (T*)Memory.mem_alloc(sizeof(T), typeid(T).name()); - return new (ptr)T(p1, p2, p3, p4, p5, p6, p7); -} -// new(8) -template -IC T* xr_new(const P1& p1, const P2& p2, const P3& p3, const P4& p4, const P5& p5, const P6& p6, const P7& p7, const P8& p8) -{ - T* ptr = (T*)Memory.mem_alloc(sizeof(T), typeid(T).name()); - return new (ptr)T(p1, p2, p3, p4, p5, p6, p7, p8); -} -// new(9) -template -IC T* xr_new(const P1& p1, const P2& p2, const P3& p3, const P4& p4, const P5& p5, const P6& p6, const P7& p7, const P8& p8, const P8& p9) -{ - T* ptr = (T*)Memory.mem_alloc(sizeof(T), typeid(T).name()); - return new (ptr)T(p1, p2, p3, p4, p5, p6, p7, p8, p9); -} -#else // DEBUG_MEMORY_NAME -// new(0) -template -IC T* xr_new() -{ - T* ptr = (T*)Memory.mem_alloc(sizeof(T)); - return new(ptr)T(); -} - -// new(1) -template -IC T* xr_new(const P1& p1) -{ - T* ptr = (T*)Memory.mem_alloc(sizeof(T)); - return new(ptr)T(p1); -} - -// new(2) -template -IC T* xr_new(const P1& p1, const P2& p2) -{ - T* ptr = (T*)Memory.mem_alloc(sizeof(T)); - return new(ptr)T(p1, p2); -} - -// new(3) -template -IC T* xr_new(const P1& p1, const P2& p2, const P3& p3) -{ - T* ptr = (T*)Memory.mem_alloc(sizeof(T)); - return new(ptr)T(p1, p2, p3); + return new(ptr) T(std::forward(args)...); } -// new(4) -template -IC T* xr_new(const P1& p1, const P2& p2, const P3& p3, const P4& p4) -{ - T* ptr = (T*)Memory.mem_alloc(sizeof(T)); - return new(ptr)T(p1, p2, p3, p4); -} - -// new(5) -template -IC T* xr_new(const P1& p1, const P2& p2, const P3& p3, const P4& p4, const P5& p5) -{ - T* ptr = (T*)Memory.mem_alloc(sizeof(T)); - return new(ptr)T(p1, p2, p3, p4, p5); -} +#else // DEBUG_MEMORY_NAME -// new(6) -template -IC T* xr_new(const P1& p1, const P2& p2, const P3& p3, const P4& p4, const P5& p5, const P6& p6) -{ - T* ptr = (T*)Memory.mem_alloc(sizeof(T)); - return new(ptr)T(p1, p2, p3, p4, p5, p6); -} +// Update xr_new to look for this marker +template +struct handles_own_init : std::false_type {}; -// new(7) -template -IC T* xr_new(const P1& p1, const P2& p2, const P3& p3, const P4& p4, const P5& p5, const P6& p6, const P7& p7) -{ - T* ptr = (T*)Memory.mem_alloc(sizeof(T)); - return new(ptr)T(p1, p2, p3, p4, p5, p6, p7); -} +template +struct handles_own_init> : T::NoZeroMemoryNew {}; -// new(8) -template -IC T* xr_new(const P1& p1, const P2& p2, const P3& p3, const P4& p4, const P5& p5, const P6& p6, const P7& p7, - const P8& p8) -{ - T* ptr = (T*)Memory.mem_alloc(sizeof(T)); - return new(ptr)T(p1, p2, p3, p4, p5, p6, p7, p8); +// Update xr_new to check for `using NoZeroMemoryNew` in class +template +IC T* xr_new(Args&&... args) +{ + size_t size = sizeof(T); + constexpr bool bZero = !handles_own_init::value; + if constexpr (bZero) + { + /*if (size > 1024) + Msg("~ [MEM] allocating object of %s, %zu", typeid(T).name(), size);*/ + } + T* ptr = (T*)Memory.mem_alloc(size, bZero); + return new(ptr) T(std::forward(args)...); } -// new(9) -template -IC T* xr_new(const P1& p1, const P2& p2, const P3& p3, const P4& p4, const P5& p5, const P6& p6, const P7& p7, - const P8& p8, const P8& p9) -{ - T* ptr = (T*)Memory.mem_alloc(sizeof(T)); - return new(ptr)T(p1, p2, p3, p4, p5, p6, p7, p8, p9); -} #endif // DEBUG_MEMORY_NAME #include @@ -160,9 +42,22 @@ struct xr_special_free { IC void operator()(T*& ptr) { - void* _real_ptr = fast_dynamic_cast(ptr); - ptr->~T(); - Memory.mem_free(_real_ptr); + if (ptr == nullptr) + { + return; + } + + if constexpr (_is_pm) + { + void* _real_ptr = fast_dynamic_cast(ptr); + ptr->~T(); + Memory.mem_free(_real_ptr); + } + else + { + ptr->~T(); + Memory.mem_free(ptr); + } } }; @@ -171,6 +66,11 @@ struct xr_special_free { IC void operator()(T*& ptr) { + if (ptr == nullptr) + { + return; + } + ptr->~T(); Memory.mem_free(ptr); } @@ -181,18 +81,17 @@ IC void xr_delete(T*& ptr) { if (ptr) { - xr_special_free::result, T>()(ptr); - ptr = NULL; + xr_special_free::value, T>()(ptr); + ptr = nullptr; } } - template IC void xr_delete(T* const& ptr) { if (ptr) { - xr_special_free::result, T> (ptr); - const_cast(ptr) = NULL; + xr_special_free::value, T>()(const_cast(ptr)); + const_cast(ptr) = nullptr; } } @@ -202,3 +101,50 @@ void XRCORE_API mem_alloc_gather_stats_frequency(const float& value); void XRCORE_API mem_alloc_show_stats(); void XRCORE_API mem_alloc_clear_stats(); #endif // DEBUG_MEMORY_MANAGER + +template +struct xr_allocator_shared_helper { + using value_type = T; + xr_allocator_shared_helper() = default; + template xr_allocator_shared_helper(const xr_allocator_shared_helper&) {} + T* allocate(std::size_t n) { + return static_cast(Memory.mem_alloc(n * sizeof(T))); + } + void deallocate(T* p, std::size_t) noexcept { + Memory.mem_free(p); + } +}; + +template +using xr_weak_ptr = std::weak_ptr; + +template +using xr_shared_ptr = std::shared_ptr; + +template +using xr_unique_ptr = std::unique_ptr>; + +template +xr_shared_ptr xr_make_shared(Args&&... args) +{ + xr_allocator_shared_helper alloc; + return std::allocate_shared(alloc, std::forward(args)...); +} + +// Support for objects already created with a custom deleter +// Useful for the "Null Deleter" or specialized engine cleanup +template +xr_shared_ptr xr_make_shared_with_deleter(T* ptr, D deleter) +{ + xr_allocator_shared_helper alloc; + // We use the constructor here because allocate_shared doesn't take deleters + return xr_shared_ptr(ptr, deleter, alloc); +} + +template +xr_unique_ptr xr_make_unique(ARGS&&... args) +{ + void* TypeMem = Memory.mem_alloc(sizeof(T)); + new (TypeMem)T(std::forward(args)...); + return xr_unique_ptr(static_cast(TypeMem), xr_special_free{}); +} diff --git a/src/xrCore/xrParams.cpp b/src/xrCore/xrParams.cpp new file mode 100644 index 0000000000..d53a6ae591 --- /dev/null +++ b/src/xrCore/xrParams.cpp @@ -0,0 +1,29 @@ +#include "stdafx.h" +#include "xrParams.h" + +#include + +void xrParams::LoadParams() +{ + xr_string CommandLine = Core.Params; + auto CommandList = CommandLine.Split(' '); + + for (auto& Command : CommandList) + { + if (!Command.StartWith("-")) + continue; + + Command = Command.substr(1); + + // Special handle for some commands + if (Command == "60hz") Command = "_" + Command; + else if (Command == "-dxgi-old") Command = "dxgi_old"; + else if (Command == "-dxgi-dbg") Command = "dxgi_dbg"; + + auto EnumData = magic_enum::enum_cast(Command); + if (EnumData.has_value()) + { + Core.ParamsData.set(EnumData.value(), true); + } + } +} \ No newline at end of file diff --git a/src/xrCore/xrParams.h b/src/xrCore/xrParams.h new file mode 100644 index 0000000000..ec869807f0 --- /dev/null +++ b/src/xrCore/xrParams.h @@ -0,0 +1,106 @@ +#pragma once + +enum class ECoreParams : u8 +{ + // Core + auto_load_arch, + overlaypath, + nolog, + build, + ebuild, + mem_debug, + + // Engine + xclsx, + no_center_screen, + dxdebug, + perfhud_hack, + nes_texture_storing, + noprefetch, + demomode, + nosound, + r2, + r4, + + // Render + nocolormap, + skinw, + disasm, + nonvs, + tsh, + noshadows, + ss_tga, + no_occq, + nodistort, + + // Game + use_callstack, + debug_ge, + + // API + renderdoc, + + // Anomaly + no_dialog_header, + game_designer, + r4_dev, + no_bump_mode1, + no_bump_mode2, + noramtex, + nodf24, + r4xx, + smap1536, + smap2048, + smap2560, + smap3072, + smap4096, + bug, + sunfilter, + sjitter, + depth16, + mt_cdb, + pure_alloc, + memo, + x86, + editor, + tune, + dbg, + dbgdev, + ltx, + r2a, + slowdown, + slowdown2x, + dbgact, + dbgbullet, + nointro, + skiplogo, + designer, + netsim, + dump_traffic, + nojit, + _g, + break_on_assert, + prefetch_sounds, + keep_lua, + _60hz, + dxgi_old, + dxgi_dbg, + gloss, + start, + load, + psp, + ignore_save_incompatibility, + sound_constant_speed, + savescreenshots, + lua_studio, + clear_cs_constants, + + //.peak volumetrics + volumetric1, + volumetric2, + volumetric4, +}; + +namespace xrParams { + void LoadParams(); +} diff --git a/src/xrCore/xrSyncronize.cpp b/src/xrCore/xrSyncronize.cpp index 14edfe2ea6..7314dba842 100644 --- a/src/xrCore/xrSyncronize.cpp +++ b/src/xrCore/xrSyncronize.cpp @@ -55,6 +55,7 @@ extern void OutputDebugStackTrace(const char* header); void xrCriticalSection::Enter() { + //PROF_EVENT("xrCriticalSection::Enter"); #ifdef PROFILE_CRITICAL_SECTIONS # if 0//def DEBUG static bool show_call_stack = false; @@ -63,16 +64,18 @@ void xrCriticalSection::Enter() # endif // DEBUG profiler temp(m_id); #endif // PROFILE_CRITICAL_SECTIONS - EnterCriticalSection((CRITICAL_SECTION*)pmutex); + EnterCriticalSection((CRITICAL_SECTION*)pmutex); } void xrCriticalSection::Leave() { + //PROF_EVENT("xrCriticalSection::Leave"); LeaveCriticalSection((CRITICAL_SECTION*)pmutex); } BOOL xrCriticalSection::TryEnter() { + //PROF_EVENT("xrCriticalSection::TryEnter"); return TryEnterCriticalSection((CRITICAL_SECTION*)pmutex); } diff --git a/src/xrCore/xrSyncronize.h b/src/xrCore/xrSyncronize.h index eba6bb3d5b..d270e55aef 100644 --- a/src/xrCore/xrSyncronize.h +++ b/src/xrCore/xrSyncronize.h @@ -2,6 +2,7 @@ #include #include +#include #include "_noncopyable.h" #if 0//def DEBUG # define PROFILE_CRITICAL_SECTIONS @@ -130,3 +131,29 @@ class XRCORE_API xrSRWLockGuard }; //Write functions guard: xrSRWLockGuard guard(lock); ... //Read functions guard: xrSRWLockGuard guard(lock, true); ... + +class XRCORE_API xrSpinWait +{ + u32 spin_count; + u32 current_count = 0; + +public: + xrSpinWait(u32 spin_count = 16) : spin_count(spin_count) {}; + ICF void operator()() + { + // Phase 1: Spin briefly (fast reaction if it finishes instantly) + if (current_count < spin_count) + { + _mm_pause(); + current_count++; + } + // Phase 2: Yield CPU (don't burn 100% CPU waiting for a heavy update) + else + std::this_thread::yield(); + } + + ICF void reset() + { + current_count = 0; + } +}; diff --git a/src/xrCore/xr_delegate.h b/src/xrCore/xr_delegate.h new file mode 100644 index 0000000000..8f80425e95 --- /dev/null +++ b/src/xrCore/xr_delegate.h @@ -0,0 +1,13 @@ +#pragma once +#include + +namespace +{ + //template + //using xr_delegate = xr_delegate; + + template + using xr_delegate = fastdelegate::FastDelegate; +}; + +#define xr_make_delegate fastdelegate::MakeDelegate diff --git a/src/xrCore/xr_ini.h b/src/xrCore/xr_ini.h index 4e546abe4e..621d496568 100644 --- a/src/xrCore/xr_ini.h +++ b/src/xrCore/xr_ini.h @@ -1,6 +1,6 @@ #pragma once -#include +#include "xr_delegate.h" // refs class CInifile; @@ -78,7 +78,7 @@ class XRCORE_API CInifile typedef Root::const_iterator RootCIt; #ifndef _EDITOR - typedef fastdelegate::FastDelegate1 allow_include_func_t; + typedef xr_delegate allow_include_func_t; #endif static CInifile* Create(LPCSTR szFileName, BOOL ReadOnly = TRUE); static void Destroy(CInifile*); @@ -134,6 +134,7 @@ class XRCORE_API CInifile static void InvalidateCache(LPCSTR path = nullptr); static void CInifile::GetCacheStats(u64& files_cached, u64& total_bytes, u64& section_count) { + xrCriticalSectionGuard g(CacheCS); total_bytes = 0; section_count = 0; files_cached = CachedData.size(); diff --git a/src/xrCore/xr_resource.h b/src/xrCore/xr_resource.h index 38fae313fb..778d74ec1d 100644 --- a/src/xrCore/xr_resource.h +++ b/src/xrCore/xr_resource.h @@ -1,4 +1,5 @@ #pragma once +#include "_thread_types.h" #include #include "_thread_types.h" @@ -129,6 +130,7 @@ class resptr_core : public C typedef T* (resptr_core::*unspecified_bool_type)() const; operator unspecified_bool_type() const { return p_ == 0 ? 0 : &resptr_core::_get; } bool operator!() const { return p_ == 0; } + operator bool() const { return p_ != 0; } // fast swapping void swap(self& rhs) @@ -190,4 +192,4 @@ template resptr_core static_pointer_cast(resptr_core const& p) { return static_cast(p.get()); } template -resptr_core dynamic_pointer_cast(resptr_core const& p) { return dynamic_cast(p.get()); } +resptr_core dynamic_pointer_cast(resptr_core const& p) { return fast_dynamic_cast(p.get()); } diff --git a/src/xrCore/xrstring.cpp b/src/xrCore/xrstring.cpp index affcddd835..e9d3bb2ebf 100644 --- a/src/xrCore/xrstring.cpp +++ b/src/xrCore/xrstring.cpp @@ -2,445 +2,559 @@ #pragma hdrstop #include "xrstring.h" +#include #include "FS_impl.h" -XRCORE_API extern str_container* g_pStringContainer = NULL; -#define HEADER (12 + sizeof(void*)) // ref + len + crc + next +XRCORE_API intrusive_ptr g_pStringContainer = nullptr; -#if 1 +str_container::str_container() {} +str_container::str_container(str_container_constructor_key) +{ + auto p = xr_malloc(block_size); + if (!p) + Debug.fatal(DEBUG_INFO, "str_container, failed to allocate block size %zu", block_size); + storage.reserve(16); + storage.emplace_back((char*)p, block_size); + buffer.resize(buffer_size); +} -struct str_container_impl +str_container* str_container::create() { - static const u32 buffer_size = 1024 * 256; - str_value* buffer[buffer_size]; - int num_docs; + return xr_new(str_container_constructor_key{}); +} - str_container_impl() +char* str_container::alloc_in_pool(str_c s, u32 len) +{ + if (storage.back().used + len > storage.back().capacity) { - num_docs = 0; - ZeroMemory(buffer, sizeof(buffer)); + u32 size = _max(block_size, len); + auto p = xr_malloc(size); + if (!p) + Debug.fatal(DEBUG_INFO, "str_container, failed to allocate block size %zu", size); + storage.emplace_back((char*)p, size); } - str_value* find(str_value* value, const char* str) - { - str_value* candidate = buffer[value->dwCRC % buffer_size]; - while (candidate) - { - if (candidate->dwCRC == value->dwCRC && - candidate->dwLength == value->dwLength && - !memcmp(candidate->value, str, value->dwLength)) - { - return candidate; - } + pool_block& b = storage.back(); + char* dest = b.base + b.used; - candidate = candidate->next; - } + // Copy the raw characters + std::memcpy(dest, s, len); + b.used += len; - return NULL; - } + // Round up to 4-byte boundary, more performant but takes more memory, around 300KB more for 200k strings + b.used = (b.used + 3) & ~3; - void insert(str_value* value) - { - str_value** element = &buffer[value->dwCRC % buffer_size]; - value->next = *element; - *element = value; - } + return dest; +} + +intrusive_ptr str_container::dock(str_c value) +{ + if (!value) return nullptr; - void clean() + size_t hash = xr_hash()(value); + u32 len = xr_strlen(value); + u32 slot = u32(hash % buffer_size); + + // Most of the time, the string already exists. Use shared lock { - for (u32 i = 0; i < buffer_size; ++i) + xrSRWLockGuard guard(&rwlock, true); + for (auto& item : buffer[slot]) { - str_value** current = &buffer[i]; - - while (*current != NULL) - { - str_value* value = *current; - if (!value->dwReference) - { - *current = value->next; - xr_free(value); - } - else - { - current = &value->next; - } - } + if (hash == item.hash && len == item.length && std::memcmp(value, item.value, len) == 0) + return &item; } } - void verify() + // String not found, upgrade to exclusive lock { - Msg("strings verify started"); - for (u32 i = 0; i < buffer_size; ++i) + xrSRWLockGuard guard(&rwlock, false); + + // Double-check: Did another thread create this while we were swapping locks? + for (auto& item : buffer[slot]) { - str_value* value = buffer[i]; - while (value) - { - u32 crc = crc32(value->value, value->dwLength); - string32 crc_str; - R_ASSERT3(crc == value->dwCRC, "CorePanic: read-only memory corruption (shared_strings)", - itoa(value->dwCRC, crc_str, 16)); - R_ASSERT3(value->dwLength == xr_strlen(value->value), - "CorePanic: read-only memory corruption (shared_strings, internal structures)", value->value); - value = value->next; - } + if (hash == item.hash && len == item.length && std::memcmp(value, item.value, len) == 0) + return &item; } - Msg("strings verify completed"); + + char* pooled_ptr = alloc_in_pool(value, len + 1); + buffer[slot].emplace_front(pooled_ptr, hash, len); + return &buffer[slot].front(); } +} + +// do nothing for now, persist strings +void str_container::erase(str_c value) +{ + /*if (!value) return; + + size_t hash = xr_hash()(value); + u32 len = xr_strlen(value); + u32 slot = u32(hash % buffer_size); - void dump(FILE* f) const + xrSRWLockGuard guard(&rwlock, false); + auto before = buffer[slot].before_begin(); + for (auto it = buffer[slot].begin(); it != buffer[slot].end(); ) { - for (u32 i = 0; i < buffer_size; ++i) + if (hash == it->hash && len == it->length && std::memcmp(value, it->value, len) == 0) + it = buffer[slot].erase_after(before); + else { - str_value* value = buffer[i]; - while (value) - { - fprintf(f, "ref[%4u]-len[%3u]-crc[%8X] : %s\n", value->dwReference, value->dwLength, value->dwCRC, - value->value); - value = value->next; - } + before = it; + it++; } + }*/ +} + +void str_container::clean() +{ + xrSRWLockGuard guard(&rwlock, false); + for (auto& list : buffer) + list.clear(); + + for (auto& block : storage) + { + if (block.base) + xr_free(block.base); } + storage.clear(); +} - void dump(IWriter* f) const +void str_container::verify() +{ + Msg("strings verify started"); + // do something + Msg("strings verify completed"); +} + +void str_container::dump() +{ + FILE* F = fopen("d:\\$str_dump$.txt", "w"); + xrSRWLockGuard guard(&rwlock, true); + for (const auto& list : buffer) { - for (u32 i = 0; i < buffer_size; ++i) + for (const auto& s: list) + fprintf(F, "ref[%d]-len[%d] : %s\n", s.intrusive_ref_count(), xr_strlen(s.value), s.value); + } + fclose(F); +} + +void str_container::dump(IWriter* W) +{ + xrSRWLockGuard guard(&rwlock, true); + for (const auto& list : buffer) + { + for (const auto& s : list) { - str_value* value = buffer[i]; string4096 temp; - while (value) - { - xr_sprintf(temp, sizeof(temp), "ref[%4u]-len[%3u]-crc[%8X] : %s\n", value->dwReference, value->dwLength, - value->dwCRC, value->value); - f->w_string(temp); - value = value->next; - } + xr_sprintf(temp, sizeof(temp), "ref[%d]-len[%d] : %s\n", s.intrusive_ref_count(), xr_strlen(s.value), s.value); + W->w_string(temp); } } +} + +void str_container::dump_console() +{ + xr_set set; + u32 total_strings = 0; + float load_factor = 0.0f; + u32 max_collisions = 0; - int stat_economy(u32& count) + xrSRWLockGuard guard(&rwlock, true); + for (const auto& list : buffer) { - int counter = 0; - for (u32 i = 0; i < buffer_size; ++i) + u32 count = 0; + for (const auto& s : list) { - str_value* value = buffer[i]; - while (value) - { - count += 1; - counter -= sizeof(str_value); - counter += (value->dwReference - 1) * (value->dwLength + 1); - value = value->next; - } + Msg("ref[%d]-len[%d] : %s\n", s.intrusive_ref_count(), xr_strlen(s.value), s.value); + count++; + set.emplace(s.value); } - - return counter; + if (count > max_collisions) + max_collisions = count; + total_strings += count; + } -}; - -str_container::str_container() -{ - impl = xr_new(); + load_factor = (float)total_strings / (float)buffer_size; + + Msg("* [x-ray]: shared strings: pool blocks[%lu], count[%lu], unique[%lu], load factor[%.2f], max_collisions[%lu], shared_str objects[%lu]", + storage.size(), + total_strings, + set.size(), + load_factor, + max_collisions, + intrusive_ref_count() - 1 + ); + if (total_strings != set.size()) + Msg("! [x-ray]: shared strings, count != unique"); } -str_value* str_container::dock(str_c value) +u32 str_container::stat_economy(u32& count, u32& unique) { - if (0 == value) return 0; - - cs.Enter(); - -#ifdef DEBUG_MEMORY_MANAGER - Memory.stat_strdock++; -#endif // DEBUG_MEMORY_MANAGER + float load_factor = 0.0f; + u32 max_collisions = 0; + count = 0; + + xrSRWLockGuard guard(&rwlock, true); + u32 size = sizeof(*this) + sizeof(shared_str) * intrusive_ref_count() - 1; + size += buffer_size * sizeof(xr_forward_list); + for (const auto& block : storage) { + size += block.capacity; + } - str_value* result = 0; + xr_set strings; + for (const auto& list : buffer) + { + u32 c = 0; + for (const auto& s : list) + { + c++; + size += sizeof(str_value) + sizeof(void*); + strings.emplace(s.value); + } + if (c > max_collisions) + max_collisions = c; + count += c; + } + unique = strings.size(); + load_factor = (float)count / (float)buffer_size; + Msg("* [x-ray]: shared strings: pool blocks[%lu], count[%lu], unique[%lu], load factor[%.2f], max_collisions[%lu], shared_str objects[%lu]", + storage.size(), + count, + unique, + load_factor, + max_collisions, + intrusive_ref_count() - 1 + ); + return size; +} - // calc len - u32 s_len = xr_strlen(value); - u32 s_len_with_zero = (u32)s_len + 1; - VERIFY(HEADER + s_len_with_zero < 4096); +str_container::~str_container() +{ + for (auto& list : buffer) + list.clear(); - // setup find structure - char header[sizeof(str_value)]; - str_value* sv = (str_value*)header; - sv->dwReference = 0; - sv->dwLength = s_len; - sv->dwCRC = crc32(value, s_len); + for (auto& block : storage) + { + if (block.base) + xr_free(block.base); + } + storage.clear(); +} - // search - result = impl->find(sv, value); +//xr_string class +xr_vector xr_string::Split(char splitCh) const +{ + xr_vector Result; -#ifdef DEBUG - bool is_leaked_string = !xr_strcmp(value, "enter leaked string here"); -#endif //DEBUG + u32 SubStrBeginCursor = 0; + u32 Len = 0; - // it may be the case, string is not found or has "non-exact" match - if (0 == result -#ifdef DEBUG - || is_leaked_string -#endif //DEBUG - ) + u32 StrCursor = 0; + for (; StrCursor < size(); ++StrCursor) { - result = (str_value*)Memory.mem_alloc(HEADER + s_len_with_zero -#ifdef DEBUG_MEMORY_NAME - , "storage: sstring" -#endif // DEBUG_MEMORY_NAME - ); - -#ifdef DEBUG - static int num_leaked_string = 0; - if (is_leaked_string) - { - ++num_leaked_string; - Msg("leaked_string: %d 0x%08x", num_leaked_string, result); - } -#endif // DEBUG - - result->dwReference = 0; - result->dwLength = sv->dwLength; - result->dwCRC = sv->dwCRC; - CopyMemory(result->value, value, s_len_with_zero); - - impl->insert(result); + if (at(StrCursor) == splitCh) + { + if ((StrCursor - SubStrBeginCursor) > 0) + { + Len = StrCursor - SubStrBeginCursor; + Result.emplace_back(xr_string(&at(SubStrBeginCursor), Len)); + SubStrBeginCursor = StrCursor + 1; + } + else + { + Result.emplace_back(""); + SubStrBeginCursor = StrCursor + 1; + } + } } - cs.Leave(); - return result; + if (StrCursor > SubStrBeginCursor) + { + Len = StrCursor - SubStrBeginCursor; + Result.emplace_back(xr_string(&at(SubStrBeginCursor), Len)); + } + return Result; } -void str_container::clean() +xr_string::xr_string(LPCSTR Str, u32 Size) + : Super(Str, Size) { - cs.Enter(); - impl->clean(); - cs.Leave(); } -void str_container::verify() +xr_string::xr_string(Super&& other) + : Super(other) { - cs.Enter(); - impl->verify(); - cs.Leave(); } -void str_container::dump() +xr_string::xr_string(LPCSTR Str) + : Super(Str) { - cs.Enter(); - FILE* F = fopen("d:\\$str_dump$.txt", "w"); - impl->dump(F); - fclose(F); - cs.Leave(); } -void str_container::dump(IWriter* W) +xr_string& xr_string::operator=(LPCSTR Str) { - cs.Enter(); - impl->dump(W); - cs.Leave(); + Super::operator=(Str); + return *this; } -u32 str_container::stat_economy(u32& count) +xr_string& xr_string::operator=(const Super& other) { - cs.Enter(); - int counter = 0; - counter -= sizeof(*this); - counter += impl->stat_economy(count); - cs.Leave(); - return u32(counter); + Super::operator=(other); + return *this; } -str_container::~str_container() +xr_vector xr_string::Split(u32 NumberOfSplits, ...) const { - clean(); - //dump (); - xr_delete(impl); + xr_vector intermediateTokens; + xr_vector Result; + + va_list args; + va_start(args, NumberOfSplits); + + for (u32 i = 0; i < NumberOfSplits; ++i) + { + char splitCh = va_arg(args, char); + + //special case for first try + if (i == 0) + { + Result = Split(splitCh); + } + + for (xr_string& str : Result) + { + xr_vector TokenStrResult = str.Split(splitCh); + intermediateTokens.insert(intermediateTokens.end(), TokenStrResult.begin(), TokenStrResult.end()); + } + + if (!intermediateTokens.empty()) + { + Result.clear(); + Result.insert(Result.begin(), intermediateTokens.begin(), intermediateTokens.end()); + intermediateTokens.clear(); + } + } + + va_end(args); + + return Result; } -#else -struct str_container_impl +xr_string xr_string::RemoveWhitespaces() const { - typedef xr_multiset cdb; - int num_docs; - str_container_impl() { num_docs = 0; } + size_t Size = size(); + if (Size == 0) return xr_string(); + xr_string Result; + Result.reserve(Size); - cdb container; -}; + const char* OrigStr = data(); + + for (size_t i = 0; i < Size; ++i) + { + if (*OrigStr != ' ') + { + Result.push_back(OrigStr[i]); + } + } -str_container::str_container() + return Result; +} + +bool xr_string::StartWith(const xr_string& Other) const { - impl = xr_new(); + return StartWith(Other.data(), Other.size()); } -str_value* str_container::dock(str_c value) + +bool xr_string::StartWith(LPCSTR Str) const { - if (0 == value) return 0; + u32 StrLen = xr_strlen(Str); + return StartWith(Str, (int)StrLen); +} - cs.Enter(); +bool xr_string::StartWith(LPCSTR Str, size_t Size) const +{ + size_t OurSize = size(); - // ++impl->num_docs; -// if ( impl->num_docs == 10000000 ) -// { -// Msg("shared_strings"); -// g_find_chunk_counter.flush(); -// } -// -// //#ifdef FIND_CHUNK_BENCHMARK_ENABLE -// find_chunk_auto_timer timer; -// //#endif // FIND_CHUNK_BENCHMARK_ENABLE + //String is greater then our, we can't success + if (OurSize < Size) return false; -#ifdef DEBUG_MEMORY_MANAGER - Memory.stat_strdock++; -#endif // DEBUG_MEMORY_MANAGER + const char* OurStr = data(); - str_value* result = 0; + for (int i = 0; i < Size; ++i) + { + if (OurStr[i] != Str[i]) + { + return false; + } + } - // calc len - u32 s_len = xr_strlen(value); - u32 s_len_with_zero = (u32)s_len + 1; - VERIFY(HEADER + s_len_with_zero < 4096); + return true; +} - // setup find structure - char header[sizeof(str_value)]; - str_value* sv = (str_value*)header; - sv->dwReference = 0; - sv->dwLength = s_len; - sv->dwCRC = crc32(value, s_len); - sv->next = NULL; +bool xr_string::Contains(const xr_string& SubStr) const +{ + return find(SubStr) != npos; +} - // search - str_container_impl::cdb::iterator I = impl->container.find(sv); // only integer compares :) - if (I != impl->container.end()) - { - // something found - verify, it is exactly our string - str_container_impl::cdb::iterator save = I; - for (; I != impl->container.end() && (*I)->dwCRC == sv->dwCRC; ++I) - { - str_value* V = (*I); - if (V->dwLength != sv->dwLength) continue; - if (0 != memcmp(V->value, value, s_len)) continue; - result = V; // found - break; - } - } +xr_string xr_string::ToString(int Value) +{ + string64 buf = { 0 }; + itoa(Value, &buf[0], 10); - bool is_leaked_string = !xr_strcmp(value, "enter leaked string here"); + return xr_string(buf); +} - // it may be the case, string is not found or has "non-exact" match - if (0 == result || is_leaked_string) - { - // Insert string - // DUMP_PHASE; +xr_string xr_string::ToString(unsigned int Value) +{ + string64 buf = { 0 }; + sprintf(buf, "%u", Value); - result = (str_value*)Memory.mem_alloc(HEADER + s_len_with_zero -#ifdef DEBUG_MEMORY_NAME - , "storage: sstring" -#endif // DEBUG_MEMORY_NAME - ); + return xr_string(buf); +} - static int num11 = 0; +xr_string xr_string::ToString(float Value) +{ + string64 buf = { 0 }; + sprintf(buf, "%f", Value); - if (is_leaked_string) - { - ++num11; - Msg("leaked_string: %d 0x%08x", num11, result); - } + return xr_string(buf); +} - // DUMP_PHASE; +xr_string xr_string::ToString(double Value) +{ + string64 buf = { 0 }; + sprintf(buf, "%f", Value); - result->dwReference = 0; - result->dwLength = sv->dwLength; - result->dwCRC = sv->dwCRC; - result->next = NULL; + return xr_string(buf); +} - CopyMemory(result->value, value, s_len_with_zero); +xr_string xr_string::Join(xrStringVector::iterator beginIter, xrStringVector::iterator endIter, const char delimeter /*= '\0'*/) +{ + xr_string Result; + xrStringVector::iterator cursorIter = beginIter; - impl->container.insert(result); - } + while (cursorIter != endIter) + { + Result.append(*cursorIter); + if (delimeter != '\0') + { + Result.push_back(delimeter); + } + cursorIter++; + } - cs.Leave(); + if (delimeter != '\0') + { + Result.erase(Result.end() - 1); + } - return result; + return Result; } -void str_container::clean() -{ - cs.Enter(); - str_container_impl::cdb::iterator it = impl->container.begin(); - str_container_impl::cdb::iterator end = impl->container.end(); - for (; it != end;) - { - str_value* sv = *it; - if (0 == sv->dwReference) - { - str_container_impl::cdb::iterator i_current = it; - str_container_impl::cdb::iterator i_next = ++it; - xr_free(sv); - impl->container.erase(i_current); - it = i_next; - } - else - { - it++; - } - } - if (impl->container.empty()) impl->container.clear(); - cs.Leave(); +// String utils +SStringVec xr_string::SplitStringMulti(xr_string separator, bool includeSeparators, bool trimStrings) const { + std::stringstream stringStream(std::string(this->c_str())); + xr_string line; + SStringVec wordVector; + + while (std::getline(stringStream, line)) + { + std::size_t prev = 0, pos; + while ((pos = line.find_first_of(separator, prev)) != xr_string::npos) + { + if (pos > prev) + wordVector.push_back(line.substr(prev, pos - prev)); + + if (includeSeparators) + wordVector.push_back(line.substr(pos, 1)); + + prev = pos + 1; + } + if (prev < line.length()) + wordVector.push_back(line.substr(prev, xr_string::npos)); + } + if (trimStrings) { + for (auto& s : wordVector) { + s = s.Trim(); + } + } + return wordVector; } -void str_container::verify() +SStringVec xr_string::SplitStringLimit(xr_string separator, int limit, bool trimStrings) const { - cs.Enter(); - str_container_impl::cdb::iterator it = impl->container.begin(); - str_container_impl::cdb::iterator end = impl->container.end(); - for (; it != end; ++it) - { - str_value* sv = *it; - u32 crc = crc32(sv->value, sv->dwLength); - string32 crc_str; - R_ASSERT3(crc == sv->dwCRC, "CorePanic: read-only memory corruption (shared_strings)", itoa(sv->dwCRC, crc_str, 16)); - R_ASSERT3(sv->dwLength == xr_strlen(sv->value), "CorePanic: read-only memory corruption (shared_strings, internal structures)", sv->value); - } - cs.Leave(); + std::stringstream stringStream(std::string(this->c_str())); + xr_string line; + SStringVec wordVector; + + while (std::getline(stringStream, line)) + { + std::size_t prev = 0, pos; + while ((pos = line.find_first_of(separator, prev)) != xr_string::npos) + { + if (pos > prev) + wordVector.push_back(line.substr(prev, pos - prev)); + + prev = pos + 1; + if (limit > 0) { + if (wordVector.size() >= limit) { + wordVector.push_back(line.substr(prev, xr_string::npos)); + return wordVector; + } + } + } + if (prev < line.length()) + wordVector.push_back(line.substr(prev, xr_string::npos)); + } + if (trimStrings) { + for (auto& s : wordVector) { + s = s.Trim(); + } + } + return wordVector; } -void str_container::dump() +xr_string xr_string::Trim(const char* t) const { - cs.Enter(); - str_container_impl::cdb::iterator it = impl->container.begin(); - str_container_impl::cdb::iterator end = impl->container.end(); - FILE* F = fopen("d:\\$str_dump$.txt", "w"); - for (; it != end; it++) - fprintf(F, "ref[%4d]-len[%3d]-crc[%8X] : %s\n", (*it)->dwReference, (*it)->dwLength, (*it)->dwCRC, (*it)->value); - fclose(F); - cs.Leave(); -} + xr_string result = *this; + result.erase(result.find_last_not_of(t) + 1); + result.erase(0, result.find_first_not_of(t)); + return result; +}; -u32 str_container::stat_economy() +void xr_string::TrimInPlace(const char* t) { - cs.Enter(); - str_container_impl::cdb::iterator it = impl->container.begin(); - str_container_impl::cdb::iterator end = impl->container.end(); - int counter = 0; - counter -= sizeof(*this); - counter -= sizeof(str_container_impl::cdb::allocator_type); - const int node_size = 20; - for (; it != end; it++) - { - counter -= HEADER; - counter -= node_size; - counter += int((int((*it)->dwReference) - 1)*int((*it)->dwLength + 1)); - } - cs.Leave(); + erase(find_last_not_of(t) + 1); + erase(0, find_first_not_of(t)); +}; + - return u32(counter); +xr_string xr_string::ToLowerCase() const +{ + xr_string result = *this; + std::transform(result.begin(), result.end(), result.begin(), [](unsigned char c) + { + return std::tolower(c); + }); + return result; } -str_container::~str_container() +xr_string xr_string::ReplaceAll(const xr_string& from, const xr_string& to) const { - clean(); - //dump (); - xr_delete(impl); - //R_ASSERT(impl->container.empty()); + xr_string result = *this; + if (from.empty()) + return result; + + size_t start_pos = 0; + while ((start_pos = result.find(from, start_pos)) != xr_string::npos) + { + result.replace(start_pos, from.length(), to); + start_pos += to.length(); // In case 'to' contains 'from', like replacing 'x' with 'yx' + } + + return result; } -#endif diff --git a/src/xrCore/xrstring.h b/src/xrCore/xrstring.h index 00b59360e3..76e8a2a84d 100644 --- a/src/xrCore/xrstring.h +++ b/src/xrCore/xrstring.h @@ -1,115 +1,213 @@ -#ifndef xrstringH -#define xrstringH #pragma once -#pragma pack(push,4) ////////////////////////////////////////////////////////////////////////// -typedef const char* str_c; +using str_c = const char*; -////////////////////////////////////////////////////////////////////////// -#pragma warning(push) -#pragma warning(disable : 4200) -struct XRCORE_API str_value +#include +#include +#include "_thread_types.h" +#include "_stl_extensions.h" +#include "intrusive_ptr.h" + +class xr_string; + +class XRCORE_API xr_string : public std::basic_string, xalloc> { - u32 dwReference; - u32 dwLength; - u32 dwCRC; - str_value* next; - char value[]; +public: + typedef std::basic_string, xalloc> Super; + + xr_string() = default; + xr_string(const xr_string& other) = default; + xr_string(xr_string&& other) noexcept = default; + + xr_string(LPCSTR Str); + xr_string(LPCSTR Str, u32 Size); + xr_string(Super&& other); + + xr_string& operator=(LPCSTR Str); + xr_string& operator=(const Super& other); + + xr_string& operator=(const xr_string& other) = default; + xr_string& operator=(xr_string&& other) = default; + + template + xr_string(char* (&InArray)[ArrayLenght]); + + xr_vector Split(char splitCh) const; + xr_vector Split(u32 NumberOfSplits, ...) const; + + bool StartWith(const xr_string& Other) const; + bool StartWith(LPCSTR Str) const; + bool StartWith(LPCSTR Str, size_t Size) const; + + bool Contains(const xr_string& SubStr) const; + + xr_string RemoveWhitespaces() const; + + static xr_string ToString(int Value); + static xr_string ToString(unsigned int Value); + static xr_string ToString(float Value); + static xr_string ToString(double Value); + static xr_string ToString(const Fvector& Value); + static xr_string ToString(const Dvector& Value); + + using xrStringVector = xr_vector; + + xrStringVector SplitStringMulti(xr_string separator = " ", bool includeSeparators = false, bool trimStrings = false) const; + xrStringVector SplitStringLimit(xr_string separator = " ", int limit = 0, bool trimStrings = false) const; + xr_string Trim(const char* t = " \t\n\r\f\v") const; + void TrimInPlace(const char* t = " \t\n\r\f\v"); + xr_string ToLowerCase() const; + xr_string ReplaceAll(const xr_string& from, const xr_string& to) const; + + static xr_string Join(xrStringVector::iterator beginIter, xrStringVector::iterator endIter, const char delimeter = '\0'); }; -struct XRCORE_API str_value_cmp +using SStringVec = xr_vector; +using SStringVecIt = SStringVec::iterator; + +// warning +// this function can be used for debug purposes only +//template +//const char* make_string(const char* format, const Args&... args) { +// static constexpr size_t bufferSize = 4096; +// static char temp[bufferSize]; +// snprintf(temp, bufferSize, format, args...); +// return temp; +//} + +namespace std { - // less - IC bool operator ()(const str_value* A, const str_value* B) const { return A->dwCRC < B->dwCRC; }; -}; + template<> + class hash + { + public: + size_t operator()(const xr_string& s) const + { + return xr_hash()(std::string_view(s)); + } + }; +} -struct XRCORE_API str_hash_function +// All str_value will persist in str_container, make counter non atomic, change if there will be erase functionality +struct XRCORE_API str_value: public intrusive_base_impl { - IC u32 operator ()(str_value const* const value) const { return value->dwCRC; }; + char* value; + size_t hash; + u32 length; + + str_value() : value(nullptr), hash(0), length(0) {} + str_value(char* s) : value(s), hash(xr_hash()(s)), length(xr_strlen(s)) {}; + str_value(char* s, size_t hash, u32 length) : value(s), hash(hash), length(length) {}; + + bool operator<(const str_value& other) const + { + return value < other.value; + } + + bool operator==(const str_value& other) const + { + return hash == other.hash && value == other.value; + } + + // do nothing, keep string in memory + void on_deferred_release() + { + // + } }; -#pragma warning(pop) +struct XRCORE_API str_value_hash +{ + size_t operator()(const str_value& s) const noexcept + { + return xr_hash()(s.value); + } +}; -struct str_container_impl; class IWriter; -////////////////////////////////////////////////////////////////////////// -class XRCORE_API str_container +class XRCORE_API str_container : public intrusive_base_impl { private: - xrCriticalSection cs; - str_container_impl* impl; -public: + struct pool_block { + char* base; // Start of the block + u32 used; // How much used in block + const u32 capacity; // Total memory used by block + pool_block(char* base, u32 capacity) : base(base), used(0), capacity(capacity) {} + }; + xr_vector storage; + char* alloc_in_pool(str_c value, u32 len); + static constexpr const u32 block_size = 4 * 1024 * 1024; // 4MB + static constexpr const u32 buffer_size = 1 << 19; // 524288 slots + xr_vector> buffer; + xrSRWLock rwlock; + + // Force create only on heap +private: + struct str_container_constructor_key { explicit str_container_constructor_key() = default; }; str_container(); + +public: + str_container(str_container_constructor_key); + static str_container* create(); ~str_container(); - str_value* dock(str_c value); + intrusive_ptr dock(str_c value); + void erase(str_c value); void clean(); void dump(); void dump(IWriter* W); + void dump_console(); void verify(); - u32 stat_economy(u32& count); -#ifdef PROFILE_CRITICAL_SECTIONS - str_container ():cs(MUTEX_PROFILE_ID(str_container)) {} -#endif // PROFILE_CRITICAL_SECTIONS + u32 stat_economy(u32& count, u32& unique); }; -XRCORE_API extern str_container* g_pStringContainer; +XRCORE_API extern intrusive_ptr g_pStringContainer; -////////////////////////////////////////////////////////////////////////// class shared_str { private: - str_value* p_; -protected: - // ref-counting - void _dec() - { - if (0 == p_) return; - p_->dwReference--; - if (0 == p_->dwReference) p_ = 0; - } + intrusive_ptr p_ = nullptr; + intrusive_ptr container_ptr = nullptr; public: void _set(str_c rhs) { - str_value* v = g_pStringContainer->dock(rhs); - if (0 != v) v->dwReference++; - _dec(); - p_ = v; + auto gc = g_pStringContainer; + if (gc) + { + p_ = gc->dock(rhs); + container_ptr = gc; + } + else + { + p_ = nullptr; + container_ptr = nullptr; + } } void _set(shared_str const& rhs) { - str_value* v = rhs.p_; - if (0 != v) v->dwReference++; - _dec(); - p_ = v; + p_ = rhs.p_; + container_ptr = rhs.container_ptr; } - // void _set (shared_str const &rhs) { str_value* v = g_pStringContainer->dock(rhs.c_str()); if (0!=v) v->dwReference++; _dec(); p_ = v; } + const str_value* _get() const { return p_.get(); } - - const str_value* _get() const { return p_; } -public: // construction - shared_str() { p_ = 0; } + shared_str() {} shared_str(str_c rhs) { - p_ = 0; _set(rhs); } shared_str(shared_str const& rhs) { - p_ = 0; _set(rhs); } - ~shared_str() { _dec(); } - // assignment & accessors shared_str& operator=(str_c rhs) { @@ -132,14 +230,13 @@ class shared_str u32 size() const { if (0 == p_) return 0; - else return p_->dwLength; + else return p_->length; } void swap(shared_str& rhs) { - str_value* tmp = p_; - p_ = rhs.p_; - rhs.p_ = tmp; + std::swap(p_, rhs.p_); + std::swap(container_ptr, rhs.container_ptr); } bool equal(const shared_str& rhs) const { return (p_ == rhs.p_); } @@ -157,7 +254,6 @@ class shared_str } }; - namespace std { template<> @@ -271,7 +367,3 @@ IC xr_string UTF8_to_CP1251(xr_string const& utf8) return utf8; } - -#pragma pack(pop) - -#endif diff --git a/src/xrEngine/CameraDefs.h b/src/xrEngine/CameraDefs.h index cd381190a8..1f05f7b8ca 100644 --- a/src/xrEngine/CameraDefs.h +++ b/src/xrEngine/CameraDefs.h @@ -5,7 +5,7 @@ struct ENGINE_API SBaseEffector { - typedef fastdelegate::FastDelegate0<> CB_ON_B_REMOVE; + typedef xr_delegate CB_ON_B_REMOVE; CB_ON_B_REMOVE m_on_b_remove_callback; virtual ~SBaseEffector() diff --git a/src/xrEngine/CameraManager.cpp b/src/xrEngine/CameraManager.cpp index cfc747df8c..9471a2db1f 100644 --- a/src/xrEngine/CameraManager.cpp +++ b/src/xrEngine/CameraManager.cpp @@ -184,10 +184,12 @@ CCameraManager::~CCameraManager() CEffectorCam* CCameraManager::GetCamEffector(ECamEffectorType type) { for (EffectorCamIt it = m_EffectorsCam.begin(); it != m_EffectorsCam.end(); it++) + { if ((*it)->eType == type) { return *it; } + } return 0; } @@ -203,12 +205,13 @@ void CCameraManager::UpdateDeffered() EffectorCamIt it_e = m_EffectorsCam_added_deffered.end(); for (; it != it_e; ++it) { - RemoveCamEffector((*it)->eType); + CEffectorCam* Effector = *it; + RemoveCamEffector(Effector->eType); - if ((*it)->AbsolutePositioning()) - m_EffectorsCam.push_front(*it); + if (Effector->AbsolutePositioning()) + m_EffectorsCam.push_back(Effector); else - m_EffectorsCam.push_back(*it); + m_EffectorsCam.push_front(Effector); } m_EffectorsCam_added_deffered.clear(); @@ -217,12 +220,14 @@ void CCameraManager::UpdateDeffered() void CCameraManager::RemoveCamEffector(ECamEffectorType type) { for (EffectorCamIt it = m_EffectorsCam.begin(); it != m_EffectorsCam.end(); it++) + { if ((*it)->eType == type) { OnEffectorReleased(*it); m_EffectorsCam.erase(it); return; } + } } // demonized: removecameffector by pointer @@ -268,14 +273,20 @@ void CCameraManager::RemoveHudMotionEffectors() CEffectorPP* CCameraManager::GetPPEffector(EEffectorPPType type) { for (EffectorPPIt it = m_EffectorsPP.begin(); it != m_EffectorsPP.end(); it++) - if ((*it)->Type() == type) return *it; + { + if ((*it)->Type() == type) + { + return *it; + } + } return 0; } ECamEffectorType CCameraManager::RequestCamEffectorId() { - ECamEffectorType index = (ECamEffectorType)effCustomEffectorStartID; - for (; GetCamEffector(index); + ECamEffectorType index; + for (index = (ECamEffectorType)effCustomEffectorStartID; + GetCamEffector(index); index = (ECamEffectorType)(index + 1)) { ; @@ -285,8 +296,9 @@ ECamEffectorType CCameraManager::RequestCamEffectorId() EEffectorPPType CCameraManager::RequestPPEffectorId() { - EEffectorPPType index = (EEffectorPPType)effCustomEffectorStartID; - for (; GetPPEffector(index); + EEffectorPPType index; + for (index = (EEffectorPPType)effCustomEffectorStartID; + GetPPEffector(index); index = (EEffectorPPType)(index + 1)) { ; @@ -304,16 +316,17 @@ CEffectorPP* CCameraManager::AddPPEffector(CEffectorPP* ef) void CCameraManager::RemovePPEffector(EEffectorPPType type) { for (EffectorPPIt it = m_EffectorsPP.begin(); it != m_EffectorsPP.end(); it++) + { if ((*it)->Type() == type) { if ((*it)->FreeOnRemove()) { OnEffectorReleased(*it); - // xr_delete (*it); } m_EffectorsPP.erase(it); return; } + } } void CCameraManager::OnEffectorReleased(SBaseEffector* e) @@ -383,36 +396,37 @@ void CCameraManager::Update(const Fvector& P, const Fvector& D, const Fvector& N bool CCameraManager::ProcessCameraEffector(CEffectorCam* eff) { - bool res = false; if (eff->Valid() && eff->ProcessCam(m_cam_info)) { - res = true; + return true; } - else if (eff->AllowProcessingIfInvalid()) + else { - eff->ProcessIfInvalid(m_cam_info); + if(eff->AllowProcessingIfInvalid()) + { + eff->ProcessIfInvalid(m_cam_info); + } + + return false; } - return res; + return true; } void CCameraManager::UpdateCamEffectors() { if (m_EffectorsCam.empty()) return; - EffectorCamVec::reverse_iterator r_it = m_EffectorsCam.rbegin(); - while (r_it != m_EffectorsCam.rend()) + + for(auto it = m_EffectorsCam.begin(); it != m_EffectorsCam.end();) { - if (ProcessCameraEffector(*r_it)) + CEffectorCam* eff = (*it); + if(!ProcessCameraEffector(eff)) { - ++r_it; + it = m_EffectorsCam.erase(it); + OnEffectorReleased(eff); } else { - // Dereferencing reverse iterator returns previous element of the list, r_it.base() returns current element - // So, we should use base()-1 iterator to delete just processed element. 'Previous' element would be - // automatically changed after deletion, so r_it would dereferencing to another value, no need to change it - OnEffectorReleased(*r_it); - auto r_to_del = r_it.base(); - m_EffectorsCam.erase(--r_to_del); + ++it; } } diff --git a/src/xrEngine/CustomHUD.h b/src/xrEngine/CustomHUD.h index d2e4b18b5a..b55e1d5aaf 100644 --- a/src/xrEngine/CustomHUD.h +++ b/src/xrEngine/CustomHUD.h @@ -16,6 +16,7 @@ ENGINE_API extern Flags32 psHUD_Flags; class ENGINE_API IRender_Visual; class CUI; +class IDSGraphManager; class ENGINE_API CCustomHUD : public DLL_Pure, @@ -28,12 +29,13 @@ class ENGINE_API CCustomHUD : BENCH_SEC_SCRAMBLEVTBL2 - virtual void Render_First() { ; } - virtual void Render_Last() { ; } + virtual void Render_First(IDSGraphManager* DM) { ; } + virtual void Render_Last(IDSGraphManager* DM) { ; } BENCH_SEC_SCRAMBLEVTBL1 - virtual void OnFrame() { ; } - virtual void OnEvent(EVENT E, u64 P1, u64 P2) { ; } + virtual void OnFrame (){;} + virtual void OnFrameMT (){;} + virtual void OnEvent (EVENT E, u64 P1, u64 P2){;} virtual void Load() { ; } virtual void OnDisconnected() = 0; diff --git a/src/xrEngine/Device_Initialize.cpp b/src/xrEngine/Device_Initialize.cpp index e144f16d4b..32e51469f8 100644 --- a/src/xrEngine/Device_Initialize.cpp +++ b/src/xrEngine/Device_Initialize.cpp @@ -41,7 +41,7 @@ PROTECT_API void CRenderDevice::Initialize() TimerMM.Start(); #ifdef INGAME_EDITOR - if (strstr(Core.Params, "-editor")) + if (Core.ParamsData.test(ECoreParams::editor)) initialize_editor(); #endif // #ifdef INGAME_EDITOR diff --git a/src/xrEngine/Device_create.cpp b/src/xrEngine/Device_create.cpp index 70ab0dbdf4..ac24f576d6 100644 --- a/src/xrEngine/Device_create.cpp +++ b/src/xrEngine/Device_create.cpp @@ -167,6 +167,7 @@ extern void GetMonitorPosition(int& x, int& y); PROTECT_API void CRenderDevice::Create() { + PROF_EVENT("CRenderDevice::Create"); //SECUROM_MARKER_SECURITY_ON(4) if (b_is_Ready) return; // prevent double call diff --git a/src/xrEngine/Device_destroy.cpp b/src/xrEngine/Device_destroy.cpp index 601e81fe8d..1ed0b01dd2 100644 --- a/src/xrEngine/Device_destroy.cpp +++ b/src/xrEngine/Device_destroy.cpp @@ -49,6 +49,7 @@ void CRenderDevice::Destroy(void) seqFrameMT.R.clear(); seqDeviceReset.R.clear(); seqParallel.clear(); + seqParallelRender.clear(); RenderFactory->DestroyRenderDeviceRender(m_pRender); m_pRender = 0; @@ -67,6 +68,7 @@ extern ENGINE_API u32 psCurrentVidMode[]; void CRenderDevice::Reset(bool precache) { + PROF_EVENT("CRenderDevice::Reset"); if (use_reshade) unregister_reshade(); diff --git a/src/xrEngine/EngineAPI.cpp b/src/xrEngine/EngineAPI.cpp index 2913943298..e0ea575f4b 100644 --- a/src/xrEngine/EngineAPI.cpp +++ b/src/xrEngine/EngineAPI.cpp @@ -214,6 +214,7 @@ void __cdecl xrFactory_Destroy(DLL_Pure* O); void CEngineAPI::Initialize(void) { + PROF_EVENT("CEngineAPI::Initialize"); ////////////////////////////////////////////////////////////////////////// // render LPCSTR r1_name = "xrRender_R1.dll"; @@ -261,7 +262,7 @@ void CEngineAPI::Initialize(void) ////////////////////////////////////////////////////////////////////////// // vTune tune_enabled = FALSE; - if (strstr(Core.Params, "-tune")) + if (Core.ParamsData.test(ECoreParams::tune)) { LPCSTR g_name = "vTuneAPI.dll"; Log("Loading DLL:", g_name); @@ -310,6 +311,7 @@ bool /*_declspec(dllexport)*/ SupportsDX10Rendering(); void CEngineAPI::CreateRendererList() { + PROF_EVENT("CreateRendererList"); #ifdef DEDICATED_SERVER vid_quality_token = xr_alloc(2); @@ -332,7 +334,7 @@ void CEngineAPI::CreateRendererList() LPCSTR r3_name = "xrRender_R3.dll"; LPCSTR r4_name = "xrRender_R4.dll"; - if (strstr(Core.Params, "-perfhud_hack")) + if (Core.ParamsData.test(ECoreParams::perfhud_hack)) { bSupports_r2 = true; bSupports_r2_5 = true; @@ -441,3 +443,15 @@ void CEngineAPI::CreateRendererList() } #endif //#ifndef DEDICATED_SERVER } + +thread_local int SkinningMode = -1; + +int CEngineAPI::GetSkinningMode() const +{ + return SkinningMode; +} + +void CEngineAPI::SetSkinningMode(int Mode) +{ + SkinningMode = Mode; +} diff --git a/src/xrEngine/EngineAPI.h b/src/xrEngine/EngineAPI.h index 1f699f6563..9be4a9a1e9 100644 --- a/src/xrEngine/EngineAPI.h +++ b/src/xrEngine/EngineAPI.h @@ -60,6 +60,9 @@ class ENGINE_API CEngineAPI CEngineAPI(); ~CEngineAPI(); + + int GetSkinningMode() const; + void SetSkinningMode(int Mode = -1); }; #define NEW_INSTANCE(a) Engine.External.pCreate(a) diff --git a/src/xrEngine/EngineThreading.cpp b/src/xrEngine/EngineThreading.cpp new file mode 100644 index 0000000000..28e2b416d8 --- /dev/null +++ b/src/xrEngine/EngineThreading.cpp @@ -0,0 +1,189 @@ +#include "stdafx.h" +#include "EngineThreading.h" +#include "CustomHUD.h" +#include "IGame_Persistent.h" +#include "IGame_Level.h" +#include "Rain.h" +#include "../../xrCDB/ISpatial.h" +#include "../../xrCDB/Frustum.h" +#include "Render.h" +#include "Irenderable.h" +#include "../../Include/xrRender/Kinematics.h" + +BOOL mt_Scheduler = TRUE; +BOOL mt_SchedulerRT = FALSE; + +void XRay::Engine::PreRenderThread() +{ + PROF_THREAD("Secondary Task 1"); + + if (g_pGamePersistent && g_pGamePersistent->pEnvironment && g_pGamePersistent->pEnvironment->eff_Rain) + { + PROF_EVENT("CEffect_Rain::UpdateItems"); + g_pGamePersistent->pEnvironment->eff_Rain->UpdateItems(); + } + + if (g_pGamePersistent && Device.ParticleWorkerCallback) + { + PROF_EVENT("Process Particles"); + Device.ParticleWorkerCallback(); + } +} + +void XRay::Engine::PreRenderPostTransformsThread() +{ + PROF_THREAD("Secondary Task 1.1"); + { + PROF_EVENT("seqParallelRender"); + for (auto& it : Device.seqParallelRender) + it(); + } +} + +struct SpatialSnapshot +{ + ISpatialShared ptr; + IKinematics* pKin; + float distSq; + + SpatialSnapshot(ISpatialShared _ptr, IKinematics* _pKin, float _distSq) : ptr(_ptr), pKin(_pKin), distSq(_distSq) {}; +}; +void XRay::Engine::CalculateBonesThread() +{ + PROF_THREAD("Secondary Task 3"); + + PROF_EVENT("CalculateBones"); + + if (!g_SpatialSpace) return; + if (Device.Paused()) return; + if (!psDeviceFlags.test(rsDrawDynamic)) return; + if (!g_pGameLevel || !g_pGameLevel->bReady) return; + if (!g_pGameLevel->CurrentEntity()) return; + + static CFrustum ViewBase; + ViewBase.CreateFromMatrix(Device.mFullTransform_saved, FRUSTUM_P_LRTB | FRUSTUM_P_FAR); + + static xr_vector spatials = {}; + spatials.clear(); + g_SpatialSpace->q_sphere( + spatials, + ISpatial_DB::O_ORDERED, + STYPE_RENDERABLE + STYPE_RENDERABLESHADOW + STYPE_PARTICLE + STYPE_LIGHTSOURCE, + Device.vCameraPosition_saved, + g_pGamePersistent->Environment().CurrentEnv->fog_distance + ); + + static xr_vector spatialsSnapshot; + spatialsSnapshot.clear(); + { + for (ISpatialShared spatial : spatials) + { + if (!spatial) + continue; + + float distSq = Device.vCameraPosition_saved.distance_to_sqr(spatial->spatial.sphere.P); + if (!ViewBase.testSphere_dirty(spatial->spatial.sphere.P, spatial->spatial.sphere.R)) + { + if (distSq > 62500.f)//250 m + continue; + } + + spatial->spatial_updatesector(); + + if + ( + (spatial->spatial.type & (STYPE_PARTICLE | STYPE_LIGHTSOURCE)) || + !(spatial->spatial.type & (STYPE_RENDERABLE | STYPE_RENDERABLESHADOW)) + ) + continue; + + auto renderable = spatial->dcast_Renderable(); + if (!(renderable && renderable->renderable.visual)) + continue; + + IKinematics* pKin = renderable->renderable.visual->dcast_PKinematics(); + if (!pKin) + continue; + + spatialsSnapshot.emplace_back(spatial, pKin, distSq); + } + } + + static auto sortFunc = [](const SpatialSnapshot& _1, const SpatialSnapshot& _2) noexcept + { + return _1.distSq < _2.distSq; + }; + std::sort(spatialsSnapshot.begin(), spatialsSnapshot.end(), sortFunc); + + for (const auto& snapshot : spatialsSnapshot) + snapshot.pKin->CalculateBones(TRUE); +} + +extern BOOL psLua_ParallelGC; +int psLua_ParallelGC_CallAmount = 25; +void XRay::Engine::GameThread() +{ + PROF_THREAD("Secondary Task 2") + + // we has granted permission to execute + if (g_hud) + { + PROF_EVENT("g_hud OnFrameMT"); + g_hud->OnFrameMT(); + } + + if (g_pGameLevel && g_pGameLevel->bReady) + { + PROF_EVENT("SoundEvent_Dispatch"); + g_pGameLevel->SoundEvent_Dispatch(); + } + + if (!Device.Paused()) + { + if (mt_Scheduler) + { + PROF_EVENT("Sheduler Deferred"); + if (mt_SchedulerRT) + { + ::Engine.Sheduler.Update(); + } + else + { + ::Engine.Sheduler.UpdateDeferred(); + ::Engine.Sheduler.UpdateFinalize(); + } + } + } + + { + PROF_EVENT("seqParallel"); + for (u32 pit = 0; pit < Device.seqParallel.size(); pit++) + Device.seqParallel[pit](); + Device.seqParallel.clear(); + } + + // demonized: While Renderer prepares frame and GPU renders it, use time opportunity to repeatedly call Lua GC with small step value + // Reduces stutters since less work will be done in main GC step or no work at all + static auto LuaGC = []() + { + PROF_EVENT("seqLuaGC"); + // Do at least once + do + { + Device.LuaGCCount++; + if (Device.LuaGC() == 1) // 1 informs that GC cycle is complete + { + Device.LuaGCDone = true; + break; + } + + } while (Device.isRendering && Device.LuaGCCount < psLua_ParallelGC_CallAmount); + }; + if (psLua_ParallelGC && Device.LuaGC) + Device.secondary_tasks.run(LuaGC); + + { + PROF_EVENT("seqFrameMT"); + Device.seqFrameMT.Process(rp_Frame); + } +} diff --git a/src/xrEngine/EngineThreading.h b/src/xrEngine/EngineThreading.h new file mode 100644 index 0000000000..874f84f5de --- /dev/null +++ b/src/xrEngine/EngineThreading.h @@ -0,0 +1,9 @@ +#pragma once + +namespace XRay::Engine +{ + void PreRenderThread(); + void PreRenderPostTransformsThread(); + void CalculateBonesThread(); + void GameThread(); +} diff --git a/src/xrEngine/Environment.cpp b/src/xrEngine/Environment.cpp index e64f58bde5..eb440da27d 100644 --- a/src/xrEngine/Environment.cpp +++ b/src/xrEngine/Environment.cpp @@ -575,6 +575,7 @@ void CEnvironment::set_lerp(float current_weight) void CEnvironment::OnFrame() { + PROF_EVENT("CEnvironment::OnFrame"); #ifdef _EDITOR SetGameTime(fGameTime + Device.fTimeDelta*fTimeFactor, fTimeFactor); if (fsimilar(ed_to_time, DAY_LENGTH) && fsimilar(ed_from_time, 0.f)) diff --git a/src/xrEngine/FDemoRecord.cpp b/src/xrEngine/FDemoRecord.cpp index ed8750e307..4cec69ebf3 100644 --- a/src/xrEngine/FDemoRecord.cpp +++ b/src/xrEngine/FDemoRecord.cpp @@ -566,7 +566,7 @@ void CDemoRecord::IR_OnKeyboardPress(int dik) //#ifndef MASTER_GOLD if (dik == DIK_RETURN) { - if (strstr(Core.Params, "-dbg")) + if (Core.isDebug()) { if (g_pGameLevel->CurrentEntity()) { diff --git a/src/xrEngine/Feel_Touch.cpp b/src/xrEngine/Feel_Touch.cpp index 0f17103e57..dc85923e10 100644 --- a/src/xrEngine/Feel_Touch.cpp +++ b/src/xrEngine/Feel_Touch.cpp @@ -33,7 +33,7 @@ void Touch::feel_touch_update(Fvector& C, float R) { if (feel_touch_disable[dit].Expire < dwT) { - feel_touch_disable.erase(feel_touch_disable.begin() + dit); + feel_touch_disable.erase_fast(feel_touch_disable.begin() + dit); dit--; } } @@ -82,7 +82,7 @@ void Touch::feel_touch_update(Fvector& C, float R) // Don't touch candidates for destroy { // _delete_ - feel_touch.erase(feel_touch.begin() + d); + feel_touch.erase_fast(feel_touch.begin() + d); feel_touch_delete(O); d--; } @@ -96,13 +96,13 @@ void Touch::feel_touch_relcase(CObject* O) xr_vector::iterator I = std::find(feel_touch.begin(), feel_touch.end(), O); if (I != feel_touch.end()) { - feel_touch.erase(I); + feel_touch.erase_fast(I); feel_touch_delete(O); } xr_vector::iterator Id = feel_touch_disable.begin(), IdE = feel_touch_disable.end(); for (; Id != IdE; ++Id) if ((*Id).O == O) { - feel_touch_disable.erase(Id); + feel_touch_disable.erase_fast(Id); break; } } diff --git a/src/xrEngine/Feel_Vision.cpp b/src/xrEngine/Feel_Vision.cpp index 1d41d83ddb..f1ddbf3ebc 100644 --- a/src/xrEngine/Feel_Vision.cpp +++ b/src/xrEngine/Feel_Vision.cpp @@ -1,162 +1,151 @@ #include "stdafx.h" #include "feel_vision.h" #include "render.h" -#include "xr_object.h" #include "xr_collide_form.h" #include "igame_level.h" #include "cl_intersect.h" -namespace Feel +using Feel::Vision; + +Vision::Vision(CObject* owner) : + pure_relcase(&Vision::feel_vision_relcase), + pure_relcase_visual(&Vision::feel_vision_relcase), + m_owner(owner) { - Vision::Vision(CObject const* owner) : - pure_relcase(&Vision::feel_vision_relcase), - m_owner(owner) - { - } + feel_visible.clear(); +} - Vision::~Vision() - { - } +Vision::~Vision() +{ +} - struct SFeelParam - { - Vision* parent; - Vision::feel_visible_Item* item; - float vis; - float vis_threshold; - - SFeelParam(Vision* _parent, Vision::feel_visible_Item* _item, float _vis_threshold) : parent(_parent), - item(_item), vis(1.f), - vis_threshold( - _vis_threshold) - { - } - }; +struct SFeelParam +{ + Vision* parent; + Vision::feel_visible_Item* item; + float vis; + float vis_threshold; - IC BOOL feel_vision_callback(collide::rq_result& result, LPVOID params) - { - SFeelParam* fp = (SFeelParam*)params; - float vis = fp->parent->feel_vision_mtl_transp(result.O, result.element); - fp->vis *= vis; - if (NULL == result.O && fis_zero(vis)) - { - CDB::TRI* T = g_pGameLevel->ObjectSpace.GetStaticTris() + result.element; - Fvector* V = g_pGameLevel->ObjectSpace.GetStaticVerts(); - fp->item->Cache.verts[0].set(V[T->verts[0]]); - fp->item->Cache.verts[1].set(V[T->verts[1]]); - fp->item->Cache.verts[2].set(V[T->verts[2]]); - } - return (fp->vis > fp->vis_threshold); - } + SFeelParam(Vision* _parent, Vision::feel_visible_Item* _item, float _vis_threshold) : parent(_parent), item(_item), vis(1.f), vis_threshold(_vis_threshold) {} +}; #ifdef SPATIAL_CHANGE - IC BOOL feel_vision_test_callback(const collide::ray_defs &rd, CObject *object, LPVOID user_data) +IC BOOL feel_vision_test_callback(const collide::ray_defs& rd, CObject* object, LPVOID user_data) +{ + /* Return FALSE to see through object. */ + if (object->SpatialComponent->spatial.type & STYPE_FEELVISIONIGNORE) { - /* Return FALSE to see through object. */ - if (object->spatial.type & STYPE_FEELVISIONIGNORE) - { - return FALSE; - } - return TRUE; + return FALSE; } + return TRUE; +} #endif - void Vision::o_new(CObject* O) - { - feel_visible.push_back(feel_visible_Item()); - feel_visible_Item& I = feel_visible.back(); - I.O = O; - I.Cache_vis = 1.f; - I.Cache.verts[0].set(0, 0, 0); - I.Cache.verts[1].set(0, 0, 0); - I.Cache.verts[2].set(0, 0, 0); - I.fuzzy = -EPS_S; - I.cp_LP = O->get_new_local_point_on_mesh(I.bone_id); - I.cp_LAST = O->get_last_local_point_on_mesh(I.cp_LP, I.bone_id); - } +void Vision::o_new(CObject* O) +{ + xrSRWLockGuard guard(&lock_visible, false); + feel_visible.push_back(feel_visible_Item()); + feel_visible_Item& I = feel_visible.back(); + I.O = O; + I.Cache_vis = 1.f; + I.Cache.verts[0].set(0, 0, 0); + I.Cache.verts[1].set(0, 0, 0); + I.Cache.verts[2].set(0, 0, 0); + I.fuzzy = -EPS_S; + I.cp_LP = O->get_new_local_point_on_mesh(I.bone_id); + I.cp_LAST = O->get_last_local_point_on_mesh(I.cp_LP, I.bone_id); +} + +void Vision::o_delete(CObject* O) +{ + xrSRWLockGuard guard(&lock_visible, false); + auto it = std::find_if(feel_visible.begin(), feel_visible.end(), + [O](const feel_visible_Item& item) { return item.O == O; }); - void Vision::o_delete(CObject* O) - { - xr_vector::iterator I = feel_visible.begin(), TE = feel_visible.end(); - for (; I != TE; I++) - if (I->O == O) - { - feel_visible.erase(I); - return; - } + if (it != feel_visible.end()) { + feel_visible.erase(it); } +} - void Vision::feel_vision_clear() +void Vision::feel_vision_clear() +{ { + xrSRWLockGuard guard(&lock_query, false); seen.clear(); query.clear(); diff.clear(); + } + { + xrSRWLockGuard guard(&lock_visible, false); feel_visible.clear(); } +} - void Vision::feel_vision_relcase(CObject* object) +void Vision::feel_vision_relcase(CObject* object) +{ { - xr_vector::iterator Io; - Io = std::find(seen.begin(), seen.end(), object); - if (Io != seen.end()) seen.erase(Io); - Io = std::find(query.begin(), query.end(), object); - if (Io != query.end())query.erase(Io); - Io = std::find(diff.begin(), diff.end(), object); - if (Io != diff.end()) diff.erase(Io); - xr_vector::iterator Ii = feel_visible.begin(), IiE = feel_visible.end(); - for (; Ii != IiE; ++Ii)if (Ii->O == object) - { - feel_visible.erase(Ii); - break; - } + xrSRWLockGuard guard(&lock_query, false); + seen.erase(std::remove(seen.begin(), seen.end(), object), seen.end()); + query.erase(std::remove(query.begin(), query.end(), object), query.end()); + diff.erase(std::remove(diff.begin(), diff.end(), object), diff.end()); + } + { + xrSRWLockGuard guard(&lock_visible, false); + feel_visible.erase( + std::remove_if(feel_visible.begin(), feel_visible.end(), [object](const feel_visible_Item& item) { return item.O == object; }), feel_visible.end()); } +} - void Vision::feel_vision_query(Fmatrix& mFull, Fvector& P) +void Vision::feel_vision_query(Fmatrix& mFull) +{ + xrSRWLockGuard guard(&lock_query, false); + + Frustum.CreateFromMatrix(mFull, FRUSTUM_P_LRTB | FRUSTUM_P_FAR); + + // Traverse object database + g_SpatialSpace->q_frustum + ( + r_spatial, + 0, + STYPE_VISIBLEFORAI, + Frustum + ); + + // Determine visibility for dynamic part of scene + seen.clear_and_reserve(); + for (u32 o_it = 0; o_it < r_spatial.size(); o_it++) { - CFrustum Frustum; - Frustum.CreateFromMatrix(mFull, FRUSTUM_P_LRTB | FRUSTUM_P_FAR); - - // Traverse object database - r_spatial.clear_not_free(); - g_SpatialSpace->q_frustum - ( - r_spatial, - 0, - STYPE_VISIBLEFORAI, - Frustum - ); - - // Determine visibility for dynamic part of scene - seen.clear_and_reserve(); - for (u32 o_it = 0; o_it < r_spatial.size(); o_it++) - { - ISpatial* spatial = r_spatial[o_it]; - CObject* object = spatial->dcast_CObject(); - if (object && feel_vision_isRelevant(object)) seen.push_back(object); - } - if (seen.size() > 1) - { - std::sort(seen.begin(), seen.end()); - xr_vector::iterator end = std::unique(seen.begin(), seen.end()); - if (end != seen.end()) seen.erase(end, seen.end()); - } + ISpatialShared spatial = r_spatial[o_it]; + CObject* object = spatial->dcast_CObject(); + if (object && feel_vision_isRelevant(object)) + seen.push_back(object); } + if (seen.size() > 1) + { + std::sort(seen.begin(), seen.end()); + xr_vector::iterator end = std::unique(seen.begin(), seen.end()); + if (end != seen.end()) seen.erase(end, seen.end()); + } +} - void Vision::feel_vision_update(CObject* parent, Fvector& P, float dt, float vis_threshold) +void Vision::feel_vision_update(Fvector& P, float dt, float vis_threshold) +{ + PROF_EVENT("feel_vision_update"); { + xrSRWLockGuard guard(&lock_query, false); // B-A = objects, that become visible if (!seen.empty()) { - xr_vector::iterator E = std::remove(seen.begin(), seen.end(), parent); + xr_vector::iterator E = std::remove(seen.begin(), seen.end(), m_owner); seen.resize(E - seen.begin()); { diff.resize(_max(seen.size(), query.size())); - xr_vector::iterator E = std::set_difference( + xr_vector::iterator E_ = std::set_difference( seen.begin(), seen.end(), query.begin(), query.end(), diff.begin()); - diff.resize(E - diff.begin()); + diff.resize(E_ - diff.begin()); for (u32 i = 0; i < diff.size(); i++) o_new(diff[i]); } @@ -166,7 +155,7 @@ namespace Feel if (!query.empty()) { diff.resize(_max(seen.size(), query.size())); - xr_vector::iterator E = std::set_difference( + xr_vector::iterator E = std::set_difference( query.begin(), query.end(), seen.begin(), seen.end(), diff.begin()); @@ -177,143 +166,156 @@ namespace Feel // Copy results and perform traces query = seen; - o_trace(P, dt, vis_threshold); } + o_trace(P, dt, vis_threshold); +} - void Vision::o_trace(Fvector& P, float dt, float vis_threshold) +void Vision::o_trace(Fvector& P, float dt, float vis_threshold) +{ + RQR.r_clear(); + xrSRWLockGuard guard(&lock_visible, true); + xr_vector::iterator I = feel_visible.begin(), E = feel_visible.end(); + for (; I != E; I++) { - RQR.r_clear(); - xr_vector::iterator I = feel_visible.begin(), E = feel_visible.end(); - for (; I != E; I++) + if (0 == I->O->CFORM()) { - if (0 == I->O->CFORM()) - { - I->fuzzy = -1; - continue; - } + I->fuzzy = -1; + continue; + } + + // verify relation + // if (positive(I->fuzzy) && I->O->Position().similar(I->cp_LR_dst,lr_granularity) && P.similar(I->cp_LR_src,lr_granularity)) + // continue; - // verify relation - // if (positive(I->fuzzy) && I->O->Position().similar(I->cp_LR_dst,lr_granularity) && P.similar(I->cp_LR_src,lr_granularity)) - // continue; + I->cp_LR_dst = I->O->Position(); + I->cp_LR_src = P; + I->cp_LAST = I->O->get_last_local_point_on_mesh(I->cp_LP, I->bone_id); - I->cp_LR_dst = I->O->Position(); - I->cp_LR_src = P; - I->cp_LAST = I->O->get_last_local_point_on_mesh(I->cp_LP, I->bone_id); + // + Fvector D, OP = I->cp_LAST; + D.sub(OP, P); + if (fis_zero(D.magnitude())) + { + I->fuzzy = 1.f; + continue; + } - // - Fvector D, OP = I->cp_LAST; - D.sub(OP, P); - if (fis_zero(D.magnitude())) + float f = D.magnitude() + .2f; + if (f > fuzzy_guaranteed) + { + D.div(f); + // setup ray defs & feel params + collide::ray_defs RD(P, D, f, CDB::OPT_CULL, + collide::rq_target( + collide::rqtStatic | /**/collide::rqtObject | /**/collide::rqtObstacle)); + SFeelParam feel_params(this, &*I, vis_threshold); + // check cache + if (I->Cache.result && I->Cache.similar(P, D, f)) { - I->fuzzy = 1.f; - continue; + // similar with previous query + feel_params.vis = I->Cache_vis; + // Log("cache 0"); } - - float f = D.magnitude() + .2f; - if (f > fuzzy_guaranteed) + else { - D.div(f); - // setup ray defs & feel params - collide::ray_defs RD(P, D, f, CDB::OPT_CULL, - collide::rq_target( - collide::rqtStatic | /**/collide::rqtObject | /**/collide::rqtObstacle)); - SFeelParam feel_params(this, &*I, vis_threshold); - // check cache - if (I->Cache.result && I->Cache.similar(P, D, f)) + float _u, _v, _range; + if (CDB::TestRayTri(P, D, I->Cache.verts, _u, _v, _range, false) && (_range > 0 && _range < f)) { - // similar with previous query - feel_params.vis = I->Cache_vis; - // Log("cache 0"); + feel_params.vis = 0.f; + // Log("cache 1"); } else { - float _u, _v, _range; - if (CDB::TestRayTri(P, D, I->Cache.verts, _u, _v, _range, false) && (_range > 0 && _range < f)) - { - feel_params.vis = 0.f; - // Log("cache 1"); - } - else + // cache outdated. real query. + VERIFY(!fis_zero(RD.dir.magnitude())); + + auto cb = [](collide::rq_result& result, LPVOID params) -> BOOL { - // cache outdated. real query. - VERIFY(!fis_zero(RD.dir.magnitude())); + SFeelParam* fp = (SFeelParam*)params; + float vis = fp->parent->feel_vision_mtl_transp(result.O, result.element); + fp->vis *= vis; + if (nullptr == result.O && fis_zero(vis)) + { + CDB::TRI* T = g_pGameLevel->ObjectSpace.GetStaticTris() + result.element; + Fvector* V = g_pGameLevel->ObjectSpace.GetStaticVerts(); + fp->item->Cache.verts[0].set(V[T->verts[0]]); + fp->item->Cache.verts[1].set(V[T->verts[1]]); + fp->item->Cache.verts[2].set(V[T->verts[2]]); + } + return BOOL(fp->vis > fp->vis_threshold); + }; #ifdef SPATIAL_CHANGE - if (g_pGameLevel->ObjectSpace.RayQuery(RQR, RD, feel_vision_callback, &feel_params, feel_vision_test_callback, const_cast(m_owner))) + if (g_pGameLevel->ObjectSpace.RayQuery(RQR, RD, cb, &feel_params, feel_vision_test_callback, m_owner)) #else - if (g_pGameLevel->ObjectSpace.RayQuery(RQR, RD, feel_vision_callback, &feel_params, NULL, const_cast(m_owner))) + if (g_pGameLevel->ObjectSpace.RayQuery(RQR, RD, cb, &feel_params, nullptr, m_owner)) #endif - { - I->Cache_vis = feel_params.vis; - I->Cache.set(P, D, f, TRUE); - } - else - { - // feel_params.vis = 0.f; - // I->Cache_vis = feel_params.vis ; - I->Cache.set(P, D, f, FALSE); - } - // Log("query"); + { + I->Cache_vis = feel_params.vis; + I->Cache.set(P, D, f, TRUE); } + else + { + // feel_params.vis = 0.f; + // I->Cache_vis = feel_params.vis ; + I->Cache.set(P, D, f, FALSE); + } + // Log("query"); } - // Log("Vis",feel_params.vis); - r_spatial.clear_not_free(); - g_SpatialSpace->q_ray(r_spatial, 0, STYPE_VISIBLEFORAI, P, D, f); + } + // Log("Vis",feel_params.vis); + g_SpatialSpace->q_ray(r_spatial, 0, STYPE_VISIBLEFORAI, P, D, f); - RD.flags = CDB::OPT_ONLYFIRST; + RD.flags = CDB::OPT_ONLYFIRST; - bool collision_found = false; - xr_vector::const_iterator i = r_spatial.begin(); - xr_vector::const_iterator e = r_spatial.end(); - for (; i != e; ++i) - { - if (*i == m_owner) - continue; + bool collision_found = false; - if (*i == I->O) - continue; + for (ISpatialShared Ptr : r_spatial) + { + CObject const* object = Ptr->dcast_CObject(); + + if (object == m_owner) + continue; - CObject const* object = (*i)->dcast_CObject(); + if (object == I->O) + continue; #ifdef SPATIAL_CHANGE - if (object && object->spatial.type & STYPE_FEELVISIONIGNORE) - { - /* See through objects that have the flag. */ - continue; - } + if (object->SpatialComponent->spatial.type & STYPE_FEELVISIONIGNORE) + /* See through objects that have the flag. */ + continue; #endif + + RQR.r_clear(); + if (object && object->collidable.model && !object->collidable.model->_RayQuery(RD, RQR)) + continue; - RQR.r_clear(); - if (object && object->collidable.model && !object->collidable.model->_RayQuery(RD, RQR)) - continue; - - collision_found = true; - break; - } + collision_found = true; + break; + } - if (collision_found) - feel_params.vis = 0.f; + if (collision_found) + feel_params.vis = 0.f; - if (feel_params.vis < feel_params.vis_threshold) - { - // INVISIBLE, choose next point - I->fuzzy -= fuzzy_update_novis * dt; - clamp(I->fuzzy, -.5f, 1.f); - I->cp_LP = I->O->get_new_local_point_on_mesh(I->bone_id); - } - else - { - // VISIBLE - I->fuzzy += fuzzy_update_vis * dt; - clamp(I->fuzzy, -.5f, 1.f); - } + if (feel_params.vis < feel_params.vis_threshold) + { + // INVISIBLE, choose next point + I->fuzzy -= fuzzy_update_novis * dt; + clamp(I->fuzzy, -.5f, 1.f); + I->cp_LP = I->O->get_new_local_point_on_mesh(I->bone_id); } else { - // VISIBLE, 'cause near + // VISIBLE I->fuzzy += fuzzy_update_vis * dt; clamp(I->fuzzy, -.5f, 1.f); } } + else + { + // VISIBLE, 'cause near + I->fuzzy += fuzzy_update_vis * dt; + clamp(I->fuzzy, -.5f, 1.f); + } } -}; +} diff --git a/src/xrEngine/Feel_Vision.h b/src/xrEngine/Feel_Vision.h index 047f4cf3bc..35b1c09169 100644 --- a/src/xrEngine/Feel_Vision.h +++ b/src/xrEngine/Feel_Vision.h @@ -3,11 +3,13 @@ #include "../xrcdb/xr_collide_defs.h" #include "render.h" #include "pure_relcase.h" +#include "xr_object.h" class IRender_Sector; -class CObject; class ISpatial; +extern BOOL g_ai_enhanced_vision; + namespace Feel { const float fuzzy_update_vis = 1000.f; // speed of fuzzy-logic desisions @@ -15,21 +17,25 @@ namespace Feel const float fuzzy_guaranteed = 0.001f; // distance which is supposed 100% visible const float lr_granularity = 0.1f; // assume similar positions - class ENGINE_API Vision : private pure_relcase + class ENGINE_API Vision: + private pure_relcase, + private pure_relcase_visual { private: xr_vector seen; xr_vector query; xr_vector diff; collide::rq_results RQR; - xr_vector r_spatial; - CObject const* m_owner; + xr_vector r_spatial; + CObject* m_owner; + CFrustum Frustum; + xrSRWLock lock_query, lock_visible; void o_new(CObject* E); void o_delete(CObject* E); void o_trace(Fvector& P, float dt, float vis_threshold); public: - Vision(CObject const* owner); + Vision(CObject* owner); virtual ~Vision(); struct feel_visible_Item @@ -48,28 +54,48 @@ namespace Feel xr_vector feel_visible; public: void feel_vision_clear(); - void feel_vision_query(Fmatrix& mFull, Fvector& P); - void feel_vision_update(CObject* parent, Fvector& P, float dt, float vis_threshold); + void feel_vision_query(Fmatrix& mFull); + void feel_vision_update(Fvector& P, float dt, float vis_threshold); void __stdcall feel_vision_relcase(CObject* object); void feel_vision_get(xr_vector& R) { - R.clear(); - xr_vector::iterator I = feel_visible.begin(), E = feel_visible.end(); - for (; I != E; ++I) if (positive(I->fuzzy)) R.push_back(I->O); + R.clear(); + xrSRWLockGuard guard(&lock_visible, true); + if (feel_visible.size() > 0xffff) + { + Msg("![feel_vision_get] abnormally high size of feel_visible, clear and skip"); + feel_visible.clear_and_free(); + return; + } + for (const feel_visible_Item& item : feel_visible) + { + if (item.O && !item.O->getDestroy() && positive(item.fuzzy)) + R.push_back(item.O); + } } Fvector feel_vision_get_vispoint(CObject* _O) { - xr_vector::iterator I = feel_visible.begin(), E = feel_visible.end(); - for (; I != E; ++I) - if (_O == I->O) - { - VERIFY(positive(I->fuzzy)); - return I->cp_LAST; - } - VERIFY2(0, "There is no such object in the potentially visible list"); - return Fvector().set(flt_max, flt_max, flt_max); + Fvector feel_zero_point = { 0.f,0.f,0.f }; + if (!_O || _O->getDestroy() || feel_visible.empty()) + return feel_zero_point; + + xrSRWLockGuard guard(&lock_visible, true); + auto it = std::find_if(feel_visible.begin(), feel_visible.end(), + [_O](const feel_visible_Item& item) { + if (g_ai_enhanced_vision) + return _O == item.O; + else + return _O == item.O && positive(item.fuzzy); + }); + + if (it != feel_visible.end()) + { + return it->cp_LAST; + } + + return feel_zero_point; } virtual bool feel_vision_isRelevant(CObject* O) = 0; diff --git a/src/xrEngine/Fmesh.h b/src/xrEngine/Fmesh.h index 9e6ff50880..0e3467c25a 100644 --- a/src/xrEngine/Fmesh.h +++ b/src/xrEngine/Fmesh.h @@ -142,7 +142,7 @@ struct ENGINE_API FSlideWindowItem { FSlideWindow* sw; u32 count; - u32 reserved[4]; + u32 reserved[4]{}; FSlideWindowItem() : sw(0), count(0) { diff --git a/src/xrEngine/GameFont.cpp b/src/xrEngine/GameFont.cpp index b503645186..cf4a3887ea 100644 --- a/src/xrEngine/GameFont.cpp +++ b/src/xrEngine/GameFont.cpp @@ -341,6 +341,7 @@ u32 CGameFont::smart_strlen(const char* S) void CGameFont::OnRender() { + PROF_EVENT("Render Font"); pFontRender->OnRender(*this); strings.clear_not_free(); } diff --git a/src/xrEngine/GameMtlLib.cpp b/src/xrEngine/GameMtlLib.cpp index 613e2216c6..d800d17a03 100644 --- a/src/xrEngine/GameMtlLib.cpp +++ b/src/xrEngine/GameMtlLib.cpp @@ -244,8 +244,8 @@ void CGameMtlLibrary::Load() for (const auto& sec : materialsLtx->sections()) { SGameMtlPair* M; - std::string secStr = sec.Name.c_str(); - auto materials = splitStringMulti(secStr, "@", false, true); + xr_string secStr = sec.Name.c_str(); + auto materials = secStr.SplitStringMulti("@", false, true); if (materials.size() < 2) { Msg("![material_pairs.ltx] encountered wrongly defined pair %s, two materials are required", secStr.c_str()); continue; diff --git a/src/xrEngine/ICollidable.cpp b/src/xrEngine/ICollidable.cpp index 76079f328b..c2e3dcd7ae 100644 --- a/src/xrEngine/ICollidable.cpp +++ b/src/xrEngine/ICollidable.cpp @@ -5,12 +5,10 @@ ICollidable::ICollidable() { - collidable.model = NULL; - ISpatial* self = fast_dynamic_cast(this); - if (self) self->spatial.type |= STYPE_COLLIDEABLE; -}; + collidable.model = nullptr; +} ICollidable::~ICollidable() { xr_delete(collidable.model); -}; +} diff --git a/src/xrEngine/IGame_Level.cpp b/src/xrEngine/IGame_Level.cpp index c953c654cc..6747b357f0 100644 --- a/src/xrEngine/IGame_Level.cpp +++ b/src/xrEngine/IGame_Level.cpp @@ -21,6 +21,7 @@ extern BOOL g_bLoaded; IGame_Level::IGame_Level() { + PROF_EVENT("IGame_Level::IGame_Level"); m_pCameras = xr_new(true); g_pGameLevel = this; pLevel = NULL; @@ -34,8 +35,9 @@ IGame_Level::IGame_Level() IGame_Level::~IGame_Level() { - if (strstr(Core.Params, "-nes_texture_storing")) - //Device.Resources->StoreNecessaryTextures(); + Device.secondary_tasks.wait(); + + if (Core.ParamsData.test(ECoreParams::nes_texture_storing)) Device.m_pRender->ResourcesStoreNecessaryTextures(); xr_delete(pLevel); @@ -61,8 +63,12 @@ IGame_Level::~IGame_Level() void IGame_Level::net_Stop() { - for (int i = 0; i < 6; i++) - Objects.Update(false); + for (int i = 0; i < 6; i++) + { + Objects.Update(false); + Objects.ProcessDestroyQueue(); + } + // Destroy all objects Objects.Unload(); IR_Release(); @@ -82,8 +88,14 @@ static void __stdcall build_callback(Fvector* V, int Vcnt, CDB::TRI* T, int Tcnt g_pGameLevel->Load_GameSpecific_CFORM(T, Tcnt); } +xrCriticalSection lloadcs; bool IGame_Level::Load(u32 dwNum) { + PROF_EVENT("IGame_Level::Load"); + xrCriticalSectionGuard guard(&lloadcs); + if (bReady) return TRUE; + extern xr_task_group prefetch_task; + prefetch_task.wait(); //SECUROM_MARKER_PERFORMANCE_ON(10) // Initialize level data @@ -107,7 +119,7 @@ bool IGame_Level::Load(u32 dwNum) // CForms // g_pGamePersistent->LoadTitle ("st_loading_cform"); g_pGamePersistent->LoadTitle(); - ObjectSpace.Load(build_callback); + ObjectSpace.Load( [](Fvector* V, int Vcnt, CDB::TRI* T, int Tcnt, void* params){g_pGameLevel->Load_GameSpecific_CFORM(T, Tcnt);}); //Sound->set_geometry_occ ( &Static ); Sound->set_geometry_occ(ObjectSpace.GetStaticModel()); Sound->set_handler(_sound_event); @@ -167,8 +179,14 @@ void IGame_Level::OnRender() // Level render, only when no client output required if (!g_dedicated_server) { - Render->Calculate(); - Render->Render(); + { + PROF_EVENT("IGame_Level::OnRender: Calculate"); + Render->Calculate(); + } + { + PROF_EVENT("IGame_Level::OnRender: Render"); + Render->Render(); + } } else { @@ -187,7 +205,7 @@ void IGame_Level::OnRender() void IGame_Level::OnFrame() { - PROF_EVENT("IGame_Level::OnFrame()"); + PROF_EVENT("IGame_Level::OnFrame"); // Log ("- level:on-frame: ",u32(Device.dwFrame)); // if (_abs(Device.fTimeDelta)g_object && S->g_object->getDestroy()) @@ -290,8 +309,8 @@ void IGame_Level::SoundEvent_Register(ref_sound_data_ptr S, float range) g_SpatialSpace->q_box(snd_ER, 0, STYPE_REACTTOSOUND, snd_position, bb_size); // Iterate - xr_vector::iterator it = snd_ER.begin(); - xr_vector::iterator end = snd_ER.end(); + auto it = snd_ER.begin(); + auto end = snd_ER.end(); for (; it != end; it++) { Feel::Sound* L = (*it)->dcast_FeelSound(); @@ -325,6 +344,7 @@ void IGame_Level::SoundEvent_Register(ref_sound_data_ptr S, float range) void IGame_Level::SoundEvent_Dispatch() { + PROF_EVENT("IGame_Level::SoundEvent_Dispatch"); while (!snd_Events.empty()) { _esound_delegate& D = snd_Events.back(); @@ -347,6 +367,7 @@ void IGame_Level::SoundEvent_Dispatch() // Lain: added void IGame_Level::SoundEvent_OnDestDestroy(Feel::Sound* obj) { + PROF_EVENT("IGame_Level::SoundEvent_OnDestDestroy"); struct rem_pred { rem_pred(Feel::Sound* obj) : m_obj(obj) diff --git a/src/xrEngine/IGame_Level.h b/src/xrEngine/IGame_Level.h index 0d29d93ce0..cc8bcbae3f 100644 --- a/src/xrEngine/IGame_Level.h +++ b/src/xrEngine/IGame_Level.h @@ -73,7 +73,7 @@ class ENGINE_API IGame_Level : CCameraManager* m_pCameras; // temporary - xr_vector snd_ER; + xr_vector snd_ER; public: CObjectList Objects; CObjectSpace ObjectSpace; @@ -82,6 +82,8 @@ class ENGINE_API IGame_Level : BOOL bReady; CInifile* pLevel; + + bool schedulerFlush; public: // deferred sound events struct _esound_delegate { diff --git a/src/xrEngine/IGame_ObjectPool.cpp b/src/xrEngine/IGame_ObjectPool.cpp index 1433a8ff79..31cf8c734e 100644 --- a/src/xrEngine/IGame_ObjectPool.cpp +++ b/src/xrEngine/IGame_ObjectPool.cpp @@ -53,8 +53,13 @@ CObject* IGame_ObjectPool::create(LPCSTR name) { CLASS_ID CLS = pSettings->r_clsid(name, "class"); CObject* O = (CObject*)NEW_INSTANCE(CLS); - O->cNameSect_set(name); - O->Load(name); + + if (O) + { + O->cNameSect_set(name); + O->Load(name); + } + return O; } diff --git a/src/xrEngine/IGame_Persistent.cpp b/src/xrEngine/IGame_Persistent.cpp index 38a21b65f0..1ead707504 100644 --- a/src/xrEngine/IGame_Persistent.cpp +++ b/src/xrEngine/IGame_Persistent.cpp @@ -147,9 +147,8 @@ void IGame_Persistent::Start(LPCSTR op) DEL_INSTANCE(g_hud); #endif } - else UpdateGameType(); - - VERIFY(ps_destroy.empty()); + else + UpdateGameType(); } void IGame_Persistent::Disconnect() @@ -169,11 +168,12 @@ void IGame_Persistent::OnGameStart() #ifndef _EDITOR // LoadTitle("st_prefetching_objects"); LoadTitle(); - if (!strstr(Core.Params, "-noprefetch")) + if (!Core.ParamsData.test(ECoreParams::noprefetch)) Prefetch(); #endif } +xr_task_group prefetch_task; #ifndef _EDITOR void IGame_Persistent::Prefetch() { @@ -182,67 +182,83 @@ void IGame_Persistent::Prefetch() float p_time = 1000.f * Device.GetTimerGlobal()->GetElapsed_sec(); size_t mem_0 = Memory.mem_usage(); - Log("Loading objects..."); - ObjectPool.prefetch(); - Log("Loading models..."); - Render->models_Prefetch(); - Log("Loading textures..."); - - const auto loadFileFolder = [&](LPCSTR _folder) + PROF_EVENT("Prefetch"); + static DWORD this_thread_id = 0; + this_thread_id = GetCurrentThreadId(); + prefetch_task.run([this]() { - string_path folder; - strconcat(sizeof(folder), folder, _folder, "\\*.dds"); + { + PROF_EVENT("Prefetch Loading models"); + Log("Loading models..."); + Render->models_Prefetch(); + } + { + PROF_EVENT("Loading textures"); + Log("Loading textures..."); + + const auto loadFileFolder = [&](LPCSTR _folder) + { + string_path folder; + strconcat(sizeof(folder), folder, _folder, "\\*.dds"); - FS_FileSet fset; - FS.file_list(fset, "$game_textures$", FS_ListFiles, folder); + FS_FileSet fset; + FS.file_list(fset, "$game_textures$", FS_ListFiles, folder); - for (FS_FileSet::iterator it = fset.begin(); it != fset.end(); it++) - Device.m_pRender->ResourcesPrefetchCreateTexture(it->name.c_str()); - }; + for (FS_FileSet::iterator it = fset.begin(); it != fset.end(); it++) + Device.m_pRender->ResourcesPrefetchCreateTexture(it->name.c_str()); + }; - if (m_textures_prefetch_config->section_exist("prefetch_folders")) - { - CInifile::Sect const& sect_f = m_textures_prefetch_config->r_section("prefetch_folders"); - for (CInifile::SectCIt I = sect_f.Data.begin(); I != sect_f.Data.end(); I++) - { - if (I->second.size() && !xr_strcmp(*I->second, "*")) + if (m_textures_prefetch_config->section_exist("prefetch_folders")) { - string_path folder; - FS.update_path(folder, "$game_textures$", *I->first); - xr_strcat(folder, sizeof(folder), "\\"); + CInifile::Sect const& sect_f = m_textures_prefetch_config->r_section("prefetch_folders"); + for (CInifile::SectCIt I = sect_f.Data.begin(); I != sect_f.Data.end(); I++) + { + if (I->second.size() && !xr_strcmp(*I->second, "*")) + { + string_path folder; + FS.update_path(folder, "$game_textures$", *I->first); + xr_strcat(folder, sizeof(folder), "\\"); - xr_vector *subfolders = FS.file_list_open(folder, FS_ListFolders); + xr_vector* subfolders = FS.file_list_open(folder, FS_ListFolders); - if (subfolders == nullptr) - { - FS.file_list_close(subfolders); - continue; - } + if (subfolders == nullptr) + { + FS.file_list_close(subfolders); + continue; + } - for (LPSTR subfolder : *subfolders) - { - string_path path; - strconcat(sizeof(path), path, folder, subfolder); + for (LPSTR subfolder : *subfolders) + { + string_path path; + strconcat(sizeof(path), path, folder, subfolder); + + loadFileFolder(path); + } + + FS.file_list_close(subfolders); + } - loadFileFolder(path); + loadFileFolder(*I->first); } + } - FS.file_list_close(subfolders); + if (m_textures_prefetch_config->section_exist("prefetch_textures")) + { + CInifile::Sect const& sect = m_textures_prefetch_config->r_section("prefetch_textures"); + for (CInifile::SectCIt I = sect.Data.begin(); I != sect.Data.end(); I++) + Device.m_pRender->ResourcesPrefetchCreateTexture(I->first.c_str()); } - loadFileFolder(*I->first); + Device.m_pRender->ResourcesDeferredUpload(); } - } - - if (m_textures_prefetch_config->section_exist("prefetch_textures")) + }); { - CInifile::Sect const& sect = m_textures_prefetch_config->r_section("prefetch_textures"); - for (CInifile::SectCIt I = sect.Data.begin(); I != sect.Data.end(); I++) - Device.m_pRender->ResourcesPrefetchCreateTexture(I->first.c_str()); + // prefetch game objects & models + PROF_EVENT("Loading objects"); + Log("Loading objects..."); + ObjectPool.prefetch(); } - Device.m_pRender->ResourcesDeferredUpload(); - Msg("* [x-ray]: Prefetched Data"); p_time = 1000.f * Device.GetTimerGlobal()->GetElapsed_sec() - p_time; size_t p_mem = Memory.mem_usage() - mem_0; @@ -267,76 +283,55 @@ void IGame_Persistent::OnFrame() if (!Device.Paused() || Device.dwPrecacheFrame) Environment().OnFrame(); +#endif +} - - Device.Statistic->Particles_starting = ps_needtoplay.size(); - Device.Statistic->Particles_active = ps_active.size(); - Device.Statistic->Particles_destroy = ps_destroy.size(); - +void IGame_Persistent::UpdateParticles() +{ // Play req particle systems - while (ps_needtoplay.size()) + while (!ps_needtoplay.empty()) { - CPS_Instance* psi = ps_needtoplay.back(); + intrusive_ptr pInstance = std::move(ps_needtoplay.back()); ps_needtoplay.pop_back(); - psi->Play(false); + pInstance->Play(false); } - // Destroy inactive particle systems - while (ps_destroy.size()) + + ps_active.insert( + ps_active.end(), + std::make_move_iterator(ps_active_deffer.begin()), + std::make_move_iterator(ps_active_deffer.end()) + ); + ps_active_deffer.clear(); + + static auto eraseFunc = [](const intrusive_ptr& Obj) { - // u32 cnt = ps_destroy.size(); - CPS_Instance* psi = ps_destroy.back(); - VERIFY(psi); - if (psi->Locked()) - { - Log("--locked"); - break; - } - ps_destroy.pop_back(); - psi->PSI_internal_delete(); - } -#endif + return Obj->m_NeedDestroy; + }; + + ps_active.erase(std::remove_if(ps_active.begin(), ps_active.end(), eraseFunc), ps_active.end()); } -void IGame_Persistent::destroy_particles(const bool& all_particles) +void IGame_Persistent::destroy_particles(bool all_particles) { #ifndef _EDITOR ps_needtoplay.clear(); - while (ps_destroy.size()) - { - CPS_Instance* psi = ps_destroy.back(); - VERIFY(psi); - VERIFY(!psi->Locked()); - ps_destroy.pop_back(); - psi->PSI_internal_delete(); - } - // delete active particles if (all_particles) { - for (; !ps_active.empty();) - (*ps_active.begin())->PSI_internal_delete(); + ps_active.clear(); } else { - u32 active_size = ps_active.size(); - CPS_Instance** I = (CPS_Instance**)_alloca(active_size * sizeof(CPS_Instance*)); - std::copy(ps_active.begin(), ps_active.end(), I); - - struct destroy_on_game_load + static auto eraseFunc = [](const intrusive_ptr& Obj) { - static IC bool predicate(CPS_Instance* const& object) - { - return (!object->destroy_on_game_load()); - } + return Obj->destroy_on_game_load(); }; - CPS_Instance** E = std::remove_if(I, I + active_size, &destroy_on_game_load::predicate); - for (; I != E; ++I) - (*I)->PSI_internal_delete(); + ps_active.erase(std::remove_if(ps_active.begin(), ps_active.end(), eraseFunc), ps_active.end()); } - VERIFY(ps_needtoplay.empty() && ps_destroy.empty() && (!all_particles || ps_active.empty())); + VERIFY(ps_needtoplay.empty() && (!all_particles || ps_active.empty())); #endif } diff --git a/src/xrEngine/IGame_Persistent.h b/src/xrEngine/IGame_Persistent.h index c40b35ba2f..6ea7422837 100644 --- a/src/xrEngine/IGame_Persistent.h +++ b/src/xrEngine/IGame_Persistent.h @@ -62,9 +62,9 @@ class ENGINE_API IGame_Persistent : params m_game_params; public: - xr_set ps_active; - xr_vector ps_destroy; - xr_vector ps_needtoplay; + xr_vector> ps_active; + xr_vector> ps_active_deffer; + xr_vector> ps_needtoplay; public: enum GrassBenders_Anim { @@ -107,7 +107,7 @@ class ENGINE_API IGame_Persistent : } grass_shader_data; public: - void destroy_particles(const bool& all_particles); + void destroy_particles(bool all_particles); public: virtual void PreStart(LPCSTR op); @@ -125,6 +125,8 @@ class ENGINE_API IGame_Persistent : ShadersExternalData* m_pGShaderConstants; //--#SM+#-- xr_vector AttachmentUIsToRender; + void UpdateParticles(); + virtual bool OnRenderPPUI_query() { return FALSE; }; // should return true if we want to have second function called virtual void OnRenderPPUI_main() { diff --git a/src/xrEngine/IRenderable.cpp b/src/xrEngine/IRenderable.cpp index 48e6bdde1e..dc02a596a0 100644 --- a/src/xrEngine/IRenderable.cpp +++ b/src/xrEngine/IRenderable.cpp @@ -1,18 +1,19 @@ #include "stdafx.h" #include "../xrcdb/ispatial.h" #include "irenderable.h" +#include "ICollidable.h" IRenderable::IRenderable() { + ISpatialOwner::spatial_create(g_SpatialSpace, this, STYPE_RENDERABLE); + renderable.xform.identity(); - renderable.visual = NULL; - renderable.pROS = NULL; + renderable.visual = nullptr; + renderable.pROS = nullptr; renderable.pROS_Allowed = TRUE; - ISpatial* self = fast_dynamic_cast(this); - if (self) self->spatial.type |= STYPE_RENDERABLE; } -extern ENGINE_API BOOL g_bRendering; +extern ENGINE_API xr_atomic_bool g_bRendering; IRenderable::~IRenderable() { diff --git a/src/xrEngine/IRenderable.h b/src/xrEngine/IRenderable.h index da0d6287ad..c801916f38 100644 --- a/src/xrEngine/IRenderable.h +++ b/src/xrEngine/IRenderable.h @@ -5,7 +5,8 @@ ////////////////////////////////////////////////////////////////////////// // definition ("Renderable") -class ENGINE_API IRenderable +class ENGINE_API IRenderable: + public ISpatialOwner { public: struct @@ -21,7 +22,7 @@ class ENGINE_API IRenderable virtual ~IRenderable(); IRender_ObjectSpecific* renderable_ROS(); BENCH_SEC_SCRAMBLEVTBL2 - virtual void renderable_Render() = 0; + virtual void renderable_Render(IDSGraphManager* DM) = 0; virtual BOOL renderable_ShadowGenerate() { return FALSE; }; virtual BOOL renderable_ShadowReceive() { return FALSE; }; @@ -29,6 +30,7 @@ class ENGINE_API IRenderable virtual float GetTransparency() { return 0.0; } //--DSR-- HeatVision virtual float GetGlowing() { return 0.0; } //--DSR-- SilencerOverheat + virtual IRenderable* dcast_Renderable() override { return this; } }; #endif // IRENDERABLE_H_INCLUDED diff --git a/src/xrEngine/ISheduled.cpp b/src/xrEngine/ISheduled.cpp index e7f39f8787..7514faf144 100644 --- a/src/xrEngine/ISheduled.cpp +++ b/src/xrEngine/ISheduled.cpp @@ -13,8 +13,6 @@ ISheduled::ISheduled() #endif } -extern BOOL g_bSheduleInProgress; - ISheduled::~ISheduled() { #ifdef DEBUG diff --git a/src/xrEngine/PS_instance.cpp b/src/xrEngine/PS_instance.cpp index 79cc331063..c881505900 100644 --- a/src/xrEngine/PS_instance.cpp +++ b/src/xrEngine/PS_instance.cpp @@ -8,34 +8,21 @@ #include "IGame_Persistent.h" CPS_Instance::CPS_Instance(bool destroy_on_game_load) : - ISpatial(g_SpatialSpace), m_destroy_on_game_load(destroy_on_game_load) { - g_pGamePersistent->ps_active.insert(this); renderable.pROS_Allowed = FALSE; m_iLifeTime = int_max; m_bAutoRemove = TRUE; m_bDead = FALSE; } - -extern ENGINE_API BOOL g_bRendering; +extern ENGINE_API xr_atomic_bool g_bRendering; //---------------------------------------------------- CPS_Instance::~CPS_Instance() { VERIFY(!g_bRendering); - xr_set::iterator it = g_pGamePersistent->ps_active.find(this); - VERIFY(it != g_pGamePersistent->ps_active.end()); - g_pGamePersistent->ps_active.erase(it); - - xr_vector::iterator it2 = std::find(g_pGamePersistent->ps_destroy.begin(), - g_pGamePersistent->ps_destroy.end(), this); - - VERIFY(it2 == g_pGamePersistent->ps_destroy.end()); - - spatial_unregister(); - shedule_unregister(); + ISpatialOwner::spatial_unregister(); } //---------------------------------------------------- @@ -43,7 +30,7 @@ void CPS_Instance::shedule_Update(u32 dt) { if (renderable.pROS) ::Render->ros_destroy(renderable.pROS); //. particles doesn't need ROS - ISheduled::shedule_Update(dt); + // ISheduled::shedule_Update(dt); m_iLifeTime -= dt; // remove??? @@ -55,10 +42,11 @@ void CPS_Instance::shedule_Update(u32 dt) //---------------------------------------------------- void CPS_Instance::PSI_destroy() { - if (m_bDead) return; m_bDead = TRUE; m_iLifeTime = 0; - g_pGamePersistent->ps_destroy.push_back(this); + m_NeedDestroy = true; + ISpatialOwner::spatial_unregister(); + //g_pGamePersistent->ps_destroy.push_back (this); } //---------------------------------------------------- diff --git a/src/xrEngine/PS_instance.h b/src/xrEngine/PS_instance.h index e01b359970..3700f2314d 100644 --- a/src/xrEngine/PS_instance.h +++ b/src/xrEngine/PS_instance.h @@ -5,12 +5,12 @@ #include "isheduled.h" #include "irenderable.h" -class ENGINE_API CPS_Instance : - public ISpatial, - public ISheduled, - public IRenderable +class ENGINE_API CPS_Instance : + public IRenderable, + public intrusive_base { friend class IGame_Persistent; + friend class CParticlesAsync; template friend struct xr_special_free; @@ -19,9 +19,11 @@ class ENGINE_API CPS_Instance : bool m_destroy_on_game_load; protected: + u32 dwLastTime; int m_iLifeTime; BOOL m_bAutoRemove; BOOL m_bDead; + volatile bool m_NeedDestroy = false; protected: virtual ~CPS_Instance(); @@ -38,6 +40,7 @@ class ENGINE_API CPS_Instance : virtual void Play(bool bHudMode) = 0; virtual BOOL Locked() { return FALSE; } + virtual void Update(u32 dt) {}; virtual shared_str shedule_Name() const { return shared_str("particle_instance"); }; diff --git a/src/xrEngine/Rain.cpp b/src/xrEngine/Rain.cpp index fbe22a9300..5ed22daeb5 100644 --- a/src/xrEngine/Rain.cpp +++ b/src/xrEngine/Rain.cpp @@ -149,6 +149,9 @@ BOOL CEffect_Rain::RayPick(const Fvector& s, const Fvector& d, float& range, col #ifdef _EDITOR Tools->RayPick (s,d,range); #else + if (!g_pGameLevel || !g_pGameLevel->bReady) + return false; + collide::rq_result RQ; CObject* E = g_pGameLevel->CurrentViewEntity(); bRes = g_pGameLevel->ObjectSpace.RayPick(s, d, range, tgt, RQ, E); @@ -176,6 +179,7 @@ void CEffect_Rain::RenewItem(Item& dest, float height, BOOL bHit) void CEffect_Rain::OnFrame() { + PROF_EVENT("CEffect_Rain::OnFrame"); #ifndef _EDITOR if (!g_pGameLevel) return; #endif @@ -246,214 +250,138 @@ void CEffect_Rain::OnFrame() } } -//#include "xr_input.h" -void CEffect_Rain::Render() +extern xr_atomic_u32 current_items; +extern float r_rain_exp; +extern float r_rain_k; +void CEffect_Rain::UpdateItems() { -#ifndef _EDITOR - if (!g_pGameLevel) return; -#endif - - m_pRender->Render(*this); + PROF_EVENT("CEffect_Rain::UpdateItems"); + xrCriticalSectionGuard guard(&rainCS); - /* float factor = g_pGamePersistent->Environment().CurrentEnv->rain_density; - if (factorEnvironment().CurrentEnv->rain_color; - u32 u_rain_color = color_rgba_f(f_rain_color.x,f_rain_color.y,f_rain_color.z,factor_visual); + float _drop_speed = 1.0f; + int rain_max_particles = max_desired_items; + float rain_radius = source_radius; + float b_radius_wrap_sqr = _sqr((rain_radius * 1.5f)); - // born _new_ if needed - float b_radius_wrap_sqr = _sqr((source_radius+.5f)); - if (items.size() desired_items) + items.resize(desired_items); + + // born _new_ if needed + // owner.items.reserve (desired_items); + while (items.size() < desired_items) + { + Born(items.emplace_back(), rain_radius, _drop_speed); } + current_items.store(desired_items, std::memory_order_relaxed); // build source plane Fplane src_plane; - Fvector norm ={0.f,-1.f,0.f}; - Fvector upper; upper.set(Device.vCameraPosition.x,Device.vCameraPosition.y+source_offset,Device.vCameraPosition.z); - src_plane.build(upper,norm); + Fvector norm = { 0.f, -1.f, 0.f }; + Fvector upper; + upper.set(Device.vCameraPosition.x, Device.vCameraPosition.y + source_offset, Device.vCameraPosition.z); + src_plane.build(upper, norm); // perform update - u32 vOffset; - FVF::LIT *verts = (FVF::LIT *) RCache.Vertex.Lock(desired_items*4,hGeom_Rain->vb_stride,vOffset); - FVF::LIT *start = verts; const Fvector& vEye = Device.vCameraPosition; - for (u32 I=0; ITEST1.Begin(); - Fvector wdir; wdir.set(one.P.x-vEye.x,0,one.P.z-vEye.z); - float wlen = wdir.square_magnitude(); - if (wlen>b_radius_wrap_sqr) { - wlen = _sqrt(wlen); - //. Device.Statistic->TEST3.Begin(); - if ((one.P.y-vEye.y)TEST3.End(); - } - Device.Statistic->TEST1.End(); - - // Build line - Fvector& pos_head = one.P; - Fvector pos_trail; pos_trail.mad (pos_head,one.D,-drop_length*factor_visual); - - // Culling - Fvector sC,lineD; float sR; - sC.sub (pos_head,pos_trail); - lineD.normalize (sC); - sC.mul (.5f); - sR = sC.magnitude(); - sC.add (pos_trail); - if (!::Render->ViewBase.testSphere_dirty(sC,sR)) continue; - - static Fvector2 UV[2][4]={ - {{0,1},{0,0},{1,1},{1,0}}, - {{1,0},{1,1},{0,0},{0,1}} - }; - - // Everything OK - build vertices - Fvector P,lineTop,camDir; - camDir.sub (sC,vEye); - camDir.normalize (); - lineTop.crossproduct(camDir,lineD); - float w = drop_width; - u32 s = one.uv_set; - P.mad(pos_trail,lineTop,-w); verts->set(P,u_rain_color,UV[s][0].x,UV[s][0].y); verts++; - P.mad(pos_trail,lineTop,w); verts->set(P,u_rain_color,UV[s][1].x,UV[s][1].y); verts++; - P.mad(pos_head, lineTop,-w); verts->set(P,u_rain_color,UV[s][2].x,UV[s][2].y); verts++; - P.mad(pos_head, lineTop,w); verts->set(P,u_rain_color,UV[s][3].x,UV[s][3].y); verts++; - } - u32 vCount = (u32)(verts-start); - RCache.Vertex.Unlock (vCount,hGeom_Rain->vb_stride); - - // Render if needed - if (vCount) { - HW.pDevice->SetRenderState (D3DRS_CULLMODE,D3DCULL_NONE); - RCache.set_xform_world (Fidentity); - RCache.set_Shader (SH_Rain); - RCache.set_Geometry (hGeom_Rain); - RCache.Render (D3DPT_TRIANGLELIST,vOffset,0,vCount,0,vCount/2); - HW.pDevice->SetRenderState (D3DRS_CULLMODE,D3DCULL_CCW); - } - - // Particles - Particle* P = particle_active; - if (0==P) return; - + for (CEffect_Rain::Item& one : items) { - float dt = Device.fTimeDelta; - _IndexStream& _IS = RCache.Index; - RCache.set_Shader (DM_Drop->shader); - - Fmatrix mXform,mScale; - int pcount = 0; - u32 v_offset,i_offset; - u32 vCount_Lock = particles_cache*DM_Drop->number_vertices; - u32 iCount_Lock = particles_cache*DM_Drop->number_indices; - IRender_DetailModel::fvfVertexOut* v_ptr= (IRender_DetailModel::fvfVertexOut*) RCache.Vertex.Lock (vCount_Lock, hGeom_Drops->vb_stride, v_offset); - u16* i_ptr = _IS.Lock (iCount_Lock, i_offset); - while (P) { - Particle* next = P->next; + if (one.dwTime_Hit < Device.dwTimeGlobal) + { + Hit(one.Phit); + if (current_items.load(std::memory_order_relaxed) > desired_items) + current_items.fetch_sub(1, std::memory_order_relaxed); // Hit something + } + if (one.dwTime_Life < Device.dwTimeGlobal) + { + Born(one, rain_radius, _drop_speed); + if (current_items.load(std::memory_order_relaxed) > desired_items) + current_items.fetch_sub(1, std::memory_order_relaxed); // Out of life ( invalidated, never hit something, etc. ) + } - // Update - // P can be zero sometimes and it crashes - P->time -= dt; - if (P->time<0) { - p_free (P); - P = next; - continue; - } + // последняя дельта ?? + //. float xdt = float(one.dwTime_Hit-Device.dwTimeGlobal)/1000.f; + //. float dt = Device.fTimeDelta;//xdtViewBase.testSphere_dirty(P->bounds.P, P->bounds.R)) - { - // Build matrix - float scale = P->time / particles_time; - mScale.scale (scale,scale,scale); - mXform.mul_43 (P->mXForm,mScale); - - // XForm verts - DM_Drop->transfer (mXform,v_ptr,u_rain_color,i_ptr,pcount*DM_Drop->number_vertices); - v_ptr += DM_Drop->number_vertices; - i_ptr += DM_Drop->number_indices; - pcount ++; - - if (pcount >= particles_cache) { - // flush - u32 dwNumPrimitives = iCount_Lock/3; - RCache.Vertex.Unlock (vCount_Lock,hGeom_Drops->vb_stride); - _IS.Unlock (iCount_Lock); - RCache.set_Geometry (hGeom_Drops); - RCache.Render (D3DPT_TRIANGLELIST,v_offset, 0,vCount_Lock,i_offset,dwNumPrimitives); - - v_ptr = (IRender_DetailModel::fvfVertexOut*) RCache.Vertex.Lock (vCount_Lock, hGeom_Drops->vb_stride, v_offset); - i_ptr = _IS.Lock (iCount_Lock, i_offset); - - pcount = 0; - } + Fvector wdir; + wdir.set(one.P.x - vEye.x, 0, one.P.z - vEye.z); + float wlen = wdir.square_magnitude(); + if (wlen > b_radius_wrap_sqr) + { + wlen = _sqrt(wlen); + if ((one.P.y - vEye.y) < sink_offset) + { + // need born + one.invalidate(); + } + else + { + Fvector inv_dir, src_p; + inv_dir.invert(one.D); + wdir.div(wlen); + one.P.mad(one.P, wdir, -(wlen + rain_radius)); + if (src_plane.intersectRayPoint(one.P, inv_dir, src_p)) + { + float dist_sqr = one.P.distance_to_sqr(src_p); + float height = max_distance; + if (RayPick(src_p, one.D, height, collide::rqtBoth)) + { + if (_sqr(height) <= dist_sqr) + { + one.invalidate(); // need born + } + else + { + RenewItem(one, height - _sqrt(dist_sqr), TRUE); // fly to point + } + } + else + { + RenewItem(one, max_distance - _sqrt(dist_sqr), FALSE); // fly ... + } + } + else + { + // need born + one.invalidate(); + } + } + } } +} - P = next; - } +void CEffect_Rain::Render() +{ + PROF_EVENT("CEffect_Rain::Render"); +#ifndef _EDITOR + if (!g_pGameLevel) return; +#endif - // Flush if needed - vCount_Lock = pcount*DM_Drop->number_vertices; - iCount_Lock = pcount*DM_Drop->number_indices; - u32 dwNumPrimitives = iCount_Lock/3; - RCache.Vertex.Unlock (vCount_Lock,hGeom_Drops->vb_stride); - _IS.Unlock (iCount_Lock); - if (pcount) { - RCache.set_Geometry (hGeom_Drops); - RCache.Render (D3DPT_TRIANGLELIST,v_offset,0,vCount_Lock,i_offset,dwNumPrimitives); - } - } - */ + xrCriticalSectionGuard guard(&rainCS); + m_pRender->Render(*this); } // startup _new_ particle system diff --git a/src/xrEngine/Rain.h b/src/xrEngine/Rain.h index 69402fb3cc..3dc8eb973e 100644 --- a/src/xrEngine/Rain.h +++ b/src/xrEngine/Rain.h @@ -68,6 +68,7 @@ class ENGINE_API CEffect_Rain // Data and logic xr_vector items; States state; + xrCriticalSection rainCS; // Particles xr_vector particle_pool; @@ -114,6 +115,7 @@ class ENGINE_API CEffect_Rain float GetRainVolume() { return rain_volume; } float GetRainHemi() { return rain_hemi; } + void UpdateItems(); }; #endif //RainH diff --git a/src/xrEngine/Render.h b/src/xrEngine/Render.h index 530bdbde4b..5c09ba4062 100644 --- a/src/xrEngine/Render.h +++ b/src/xrEngine/Render.h @@ -2,6 +2,7 @@ #define _RENDER_H_ #include "../xrCDB/frustum.h" +#include "../xrCDB/ISpatial.h" #include "vis_common.h" //#include "IRenderDetailModel.h" @@ -27,6 +28,7 @@ struct ENGINE_API FSlideWindowItem; class IRenderVisual; class IKinematics; class CGameFont; +class CObject; //class IRenderDetailModel; #ifndef _EDITOR @@ -36,7 +38,9 @@ const float fLightSmoothFactor = 4.f; #endif ////////////////////////////////////////////////////////////////////////// // definition (Dynamic Light) -class ENGINE_API IRender_Light : public xr_resource +class ENGINE_API IRender_Light: + public xr_resource, + public ISpatialOwner { public: enum LT @@ -50,6 +54,7 @@ class ENGINE_API IRender_Light : public xr_resource public: virtual void set_type(LT type) = 0; + virtual LT get_type() = 0; virtual void set_active(bool) = 0; virtual bool get_active() = 0; virtual void set_shadow(bool) = 0; @@ -72,12 +77,24 @@ class ENGINE_API IRender_Light : public xr_resource virtual void set_hud_mode(bool b) = 0; virtual bool get_hud_mode() = 0; virtual void set_is_playerlight(bool b) = 0; + virtual vis_data& get_homdata() = 0; + + virtual void set_occq_mode (bool b) = 0; + virtual bool get_occq_mode () = 0; + + virtual void set_ignore_object (CObject* O) = 0; + virtual CObject* get_ignore_object () = 0; + + virtual void set_decor_object (CObject* O, int index = 0) = 0; + virtual CObject* get_decor_object (int index = 0) = 0; + virtual ~IRender_Light(); + virtual void destroy(bool deffered = true) = 0; }; struct ENGINE_API resptrcode_light : public resptr_base { - void destroy() { _set(NULL); } + void destroy() { if(p_){p_->destroy(); p_ = NULL;} } }; typedef resptr_core ref_light; @@ -178,9 +195,64 @@ class ENGINE_API IRender_Target ////////////////////////////////////////////////////////////////////////// // definition (Renderer) +class ENGINE_API IDSGraphManager +{ +public: + enum + { + fl_deffered, + fl_forward, + fl_wmarks, + fl_normal, + fl_shmap, + fl_invisible, + fl_hud, + fl_cam, + fl_max, + }; + IRenderable* val_pObject = nullptr; + bool i_mask[fl_max]{};//deffered,forward,wmarks,normal,shmap,val_invisible,val_hud,val_cam_attached + + virtual void add_Static(IRenderVisual* pVisual, CFrustum& frustum, u32 planes) = 0; + virtual void add_Dynamic(IRenderVisual* piVisual, Fmatrix* xform) = 0; + + virtual void set_Object(IRenderable* O = nullptr) = 0; + IRenderable* get_Object() { return val_pObject; } + + virtual void set_HUD(bool V = false) { i_mask[fl_hud]=V; } + virtual bool get_HUD() { return i_mask[fl_hud]; } + + // Anomaly + virtual void set_CamAttached(bool V) { i_mask[fl_cam] = V; } + virtual bool get_CamAttached() { return i_mask[fl_cam]; } + + virtual void set_Invisible(bool V = false) { i_mask[fl_invisible] = V; } + + virtual IDSGraphManager* dcast_IPortalTraverser() { return this; } +}; + class ENGINE_API IRender_interface { public: + enum + { + PHASE_NORMAL = 0, // E[0] + PHASE_SMAP = 1, // E[1] + PHASE_REFLECT = 2, + //r1 + PHASE_POINT = 3, + PHASE_SPOT = 4, + }; + enum + { + MMSM_OFF = 0, + MMSM_ON, + MMSM_AUTO, + MMSM_AUTODETECT + }; + u32 phase = PHASE_NORMAL; + BOOL b_loaded = FALSE; + enum GenerationLevel { GENERATION_R1 = 81, @@ -223,14 +295,12 @@ class ENGINE_API IRender_interface public: // options bool hud_loading; - s32 m_skinning; s32 m_MSAASample; BENCH_SEC_SCRAMBLEMEMBER1 // data CFrustum ViewBase; - CFrustum* View; public: // feature level virtual GenerationLevel get_generation() = 0; @@ -250,8 +320,9 @@ class ENGINE_API IRender_interface virtual void level_Load(IReader*) = 0; virtual void level_Unload() = 0; + virtual size_t SectorsCount() { return size_t(0); } + //virtual IDirect3DBaseTexture9* texture_load (LPCSTR fname, u32& msize) = 0; - void shader_option_skinning(s32 mode) { m_skinning = mode; } virtual HRESULT shader_compile( LPCSTR name, DWORD const* pSrcData, @@ -275,23 +346,8 @@ class ENGINE_API IRender_interface virtual IRender_Target* getTarget() = 0; // Main - IC void set_Frustum(CFrustum* O) - { - VERIFY(O); - View = O; - } - - virtual void set_Transform(Fmatrix* M) = 0; - virtual void set_HUD(BOOL V) = 0; - virtual BOOL get_HUD() = 0; - virtual void set_CamAttached(BOOL V) = 0; - virtual BOOL get_CamAttached() = 0; - virtual void set_Invisible(BOOL V) = 0; virtual void flush() = 0; - virtual void set_Object(IRenderable* O) = 0; virtual void add_Occluder(Fbox2& bb_screenspace) = 0; // mask screen region as oclluded (-1..1, -1..1) - virtual void add_Visual(IRenderVisual* V) = 0; // add visual leaf (no culling performed at all) - virtual void add_Geometry(IRenderVisual* V) = 0; // add visual(s) (all culling performed) // virtual void add_StaticWallmark (ref_shader& S, const Fvector& P, float s, CDB::TRI* T, Fvector* V)=0; virtual void add_StaticWallmark(const wm_shader& S, const Fvector& P, float s, CDB::TRI* T, Fvector* V) = 0; // Prefer this function when possible @@ -306,6 +362,9 @@ class ENGINE_API IRender_interface virtual void add_SkeletonWallmark(const Fmatrix* xf, IKinematics* obj, IWallMarkArray* pArray, const Fvector& start, const Fvector& dir, float size, float ttl = 0.f, bool ignore_opt = false) = 0; + virtual void remove_SkeletonWallmarksFromObject(IKinematics* obj) = 0; + virtual void update_Wallmarks() = 0; + //virtual IBlender* blender_create (CLASS_ID cls) = 0; //virtual void blender_destroy (IBlender* &) = 0; @@ -334,6 +393,7 @@ class ENGINE_API IRender_interface virtual IRenderVisual* model_Duplicate(IRenderVisual* V) = 0; //virtual void model_Delete (IRenderVisual* & V, BOOL bDiscard=FALSE) = 0; virtual void model_Delete(IRenderVisual*& V, BOOL bDiscard = FALSE) = 0; + virtual void model_Delete_Deffered(IRenderVisual*& V) = 0; // virtual void model_Delete (IRender_DetailModel* & F) = 0; virtual void model_Logging(BOOL bEnable) = 0; virtual void models_Prefetch() = 0; @@ -377,7 +437,7 @@ class ENGINE_API IRender_interface virtual void rmNear() = 0; virtual void rmFar() = 0; virtual void rmNormal() = 0; - virtual u32 memory_usage() = 0; + virtual u32 memory_usage() { return 0; } virtual u32 active_phase() = 0; //Swartz: actor shadow virtual void RenderToTarget(RRT target) = 0; // Constructor/destructor diff --git a/src/xrEngine/Stats.cpp b/src/xrEngine/Stats.cpp index 577aa974da..dbdeb44ad7 100644 --- a/src/xrEngine/Stats.cpp +++ b/src/xrEngine/Stats.cpp @@ -355,13 +355,13 @@ void CStats::Show() ////////////////////////////////////////////////////////////////////////// // Renderer specific F.SetHeightI(f_base_size); - F.OutSet(200, 0); + F.OutSet(500, 0); Render->Statistics(&F); ////////////////////////////////////////////////////////////////////////// // Game specific F.SetHeightI(f_base_size); - F.OutSet(400, 0); + F.OutSet(800, 0); g_pGamePersistent->Statistics(&F); ////////////////////////////////////////////////////////////////////////// @@ -492,9 +492,8 @@ void _LogCallback(LPCSTR string) void CStats::OnDeviceCreate() { - g_bDisableRedText = strstr(Core.Params, "-xclsx") ? TRUE : FALSE; + g_bDisableRedText = Core.ParamsData.test(ECoreParams::xclsx); - // if (!strstr(Core.Params, "-dedicated")) #ifndef DEDICATED_SERVER pFont = xr_new("stat_font", CGameFont::fsDeviceIndependent); #endif @@ -511,13 +510,13 @@ void CStats::OnDeviceCreate() // #ifdef DEBUG - if (!g_bDisableRedText) SetLogCB(_LogCallback); + if (!g_bDisableRedText) xrLogger::AddLogCallback(_LogCallback); #endif } void CStats::OnDeviceDestroy() { - SetLogCB(0); + xrLogger::RemoveLogCallback(_LogCallback); xr_delete(pFont); } diff --git a/src/xrEngine/Text_Console.cpp b/src/xrEngine/Text_Console.cpp index fd6c626d9b..b4a8a579cc 100644 --- a/src/xrEngine/Text_Console.cpp +++ b/src/xrEngine/Text_Console.cpp @@ -272,7 +272,7 @@ void CTextConsole::DrawLog(HDC hDC, RECT* pRect) TextOut(hDC, xb, Height - tm.tmHeight - 3, s_edt, xr_strlen(s_edt)); SetTextColor(hDC, RGB(205, 205, 225)); - u32 log_line = LogFile.size() - 1; + u32 log_line = m_log_line_counter; string16 q, q2; itoa(log_line, q, 10); xr_strcpy(q2, sizeof(q2), "["); @@ -282,51 +282,59 @@ void CTextConsole::DrawLog(HDC hDC, RECT* pRect) TextOut(hDC, Width - 8 * qn, Height - tm.tmHeight - tm.tmHeight, q2, qn); - int ypos = Height - tm.tmHeight - tm.tmHeight; - for (int i = LogFile.size() - 1 - scroll_delta; i >= 0; --i) { - ypos -= tm.tmHeight; - if (ypos < y_top_max) - { - break; - } - LPCSTR ls = LogFile[i].c_str(); + xrCriticalSectionGuard guardLog(&m_log_history_guard); + u32 log_line = m_log_history.GetSize(); - if (!ls) - { - continue; - } - Console_mark cm = (Console_mark)ls[0]; - COLORREF c2 = (COLORREF)bgr2rgb(get_mark_color(cm)); - SetTextColor(hDC, c2); - u8 b = (is_mark(cm)) ? 2 : 0; - LPCSTR pOut = ls + b; - - BOOL res = TextOut(hDC, 10, ypos, pOut, xr_strlen(pOut)); - if (!res) + int ypos = Height - tm.tmHeight - tm.tmHeight; + for (u32 i = scroll_delta; i < log_line; ++i) { - R_ASSERT2(0, "TextOut(..) return NULL"); + const xr_string& logLine = m_log_history.GetLooped(m_log_history.GetTail() - i); + + if (!logLine.size()) { + continue; + } + + ypos -= tm.tmHeight; + if (ypos < y_top_max) + { + break; + } + + LPCSTR ls = logLine.c_str(); + + Console_mark cm = (Console_mark)ls[0]; + COLORREF c2 = (COLORREF)bgr2rgb(get_mark_color(cm)); + SetTextColor(hDC, c2); + u8 b = (is_mark(cm)) ? 2 : 0; + LPCSTR pOut = ls + b; + + BOOL res = TextOut(hDC, 10, ypos, pOut, xr_strlen(pOut)); + if (!res) + { + R_ASSERT2(0, "TextOut(..) return NULL"); + } } - } - if (g_pGameLevel && (Device.dwTimeGlobal - m_last_time > 500)) - { - m_last_time = Device.dwTimeGlobal; - - m_server_info.ResetData(); - g_pGameLevel->GetLevelInfo(&m_server_info); - } + if (g_pGameLevel && (Device.dwTimeGlobal - m_last_time > 500)) + { + m_last_time = Device.dwTimeGlobal; - ypos = 5; - for (u32 i = 0; i < m_server_info.Size(); ++i) - { - SetTextColor(hDC, m_server_info[i].color); - TextOut(hDC, 10, ypos, m_server_info[i].name, xr_strlen(m_server_info[i].name)); + m_server_info.ResetData(); + g_pGameLevel->GetLevelInfo(&m_server_info); + } - ypos += tm.tmHeight; - if (ypos > y_top_max) + ypos = 5; + for (u32 i = 0; i < m_server_info.Size(); ++i) { - break; + SetTextColor(hDC, m_server_info[i].color); + TextOut(hDC, 10, ypos, m_server_info[i].name, xr_strlen(m_server_info[i].name)); + + ypos += tm.tmHeight; + if (ypos > y_top_max) + { + break; + } } } } diff --git a/src/xrEngine/XR_IOConsole.cpp b/src/xrEngine/XR_IOConsole.cpp index 59fd0132fa..b73496ecf3 100644 --- a/src/xrEngine/XR_IOConsole.cpp +++ b/src/xrEngine/XR_IOConsole.cpp @@ -138,14 +138,73 @@ bool CConsole::is_mark(Console_mark type) //////////////////////////////////////////////////////////////////////////////////////////////////// +// Log callback for console +void ConsoleLogCallback(LPCSTR line) { + Console->AddLogEntry(line); +} + CConsole::CConsole() : m_hShader_back(NULL) { + m_log_line_counter = 0; + + m_bHistoryLoaded = false; + + m_cur_cmd.reserve(64); + m_last_cmd.reserve(64); + for (u32 i = 0; i < m_log_history.GetSize(); ++i) + { + m_log_history.Get(i).reserve(256); + } + m_editor = xr_new((u32)CONSOLE_BUF_SIZE); m_cmd_history_max = cmd_history_max; m_disable_tips = false; Register_callbacks(); Device.seqResolutionChanged.Add(this); + + xrLogger::AddLogCallback(ConsoleLogCallback); + +} + +void CConsole::SaveHistory() +{ + // Открываем файл на запись в папке app_data (где логи и настройки) + IWriter* W = FS.w_open("$app_data_root$", "console_history.txt"); + if (W) + { + // Проходим по вектору истории и записываем каждую команду новой строкой + for (const auto& cmd : m_cmd_history) + { + if (cmd.size() > 0) + { + W->w_string(cmd.c_str()); + } + } + FS.w_close(W); + } +} + +void CConsole::LoadHistory() +{ + if (m_bHistoryLoaded) return; + + IReader* R = FS.r_open("$app_data_root$", "console_history.txt"); + if (R) + { + string1024 line; + while (!R->eof() && m_cmd_history.size() < m_cmd_history_max) + { + R->r_string(line, sizeof(line)); + if (xr_strlen(line) > 0) + { + m_cmd_history.push_back(line); + } + } + FS.r_close(R); + reset_cmd_history_idx(); + } + m_bHistoryLoaded = true; } void CConsole::Initialize() @@ -157,7 +216,6 @@ void CConsole::Initialize() m_mouse_pos.x = 0; m_mouse_pos.y = 0; - m_last_cmd = NULL; m_cmd_history.reserve(m_cmd_history_max + 2); m_cmd_history.clear_not_free(); @@ -170,7 +228,6 @@ void CConsole::Initialize() m_tips_mode = 0; m_prev_length_str = 0; - m_cur_cmd = NULL; reset_selected_tip(); // Commands @@ -181,6 +238,8 @@ void CConsole::Initialize() CConsole::~CConsole() { + SaveHistory(); + xrLogger::RemoveLogCallback(ConsoleLogCallback); xr_delete(m_hShader_back); xr_delete(m_editor); Destroy(); @@ -197,6 +256,24 @@ void CConsole::Destroy() Commands.clear(); } +void CConsole::AddLogEntry(LPCSTR line) +{ + xrCriticalSectionGuard guard(&m_log_history_guard); + m_log_history.Get(m_log_history.GetHead()) = line; + m_log_history.MoveHead(1); + m_log_line_counter++; +} + +void CConsole::ClearLog() +{ + xrCriticalSectionGuard guard(&m_log_history_guard); + for (u32 i = 0; i < m_log_history.GetSize(); ++i) + { + m_log_history.Get(i).clear(); + } + m_log_line_counter = 0; +} + void CConsole::AddCommand(IConsole_Command* cc) { Commands[cc->Name()] = cc; @@ -231,7 +308,7 @@ void CConsole::OutFont(LPCSTR text, float& pos_y) int sz = 0; int ln = 0; PSTR one_line = (PSTR)_alloca((CONSOLE_BUF_SIZE + 1) * sizeof(char)); - + while (text[sz] && (ln + sz < CONSOLE_BUF_SIZE - 5)) // перенос строк { one_line[ln + sz] = text[sz]; @@ -397,33 +474,48 @@ void CConsole::OnRender() } // --------------------- - u32 log_line = LogFile.size() - 1; - ypos -= LDIST; - for (int i = log_line - scroll_delta; i >= 0; --i) + m_log_history_guard.Enter(); + u32 log_size = m_log_history.GetSize(); + u32 total_filled = std::min(m_log_line_counter, log_size); + + u32 newest_idx = m_log_history.GetHead(); + + float temp_y = ypos; + + if (total_filled > 0) { - ypos -= LDIST; - if (ypos < -1.0f) - { - break; - } - LPCSTR ls = LogFile[i].c_str(); + if (scroll_delta > (int)total_filled - 1) + scroll_delta = std::max(0, (int)total_filled - 1); + if (scroll_delta < 0) scroll_delta = 0; - if (!ls) + for (u32 i = (u32)scroll_delta; i < total_filled; ++i) { - continue; + const xr_string& logLine = m_log_history.GetLooped(newest_idx - 1 - i); + + if (logLine.empty()) continue; + + temp_y -= LDIST; + + if (temp_y < -1.0f) + break; + + LPCSTR ls = logLine.c_str(); + Console_mark cm = (Console_mark)ls[0]; + pFont->SetColor(get_mark_color(cm)); + + float line_y = temp_y; + OutFont(ls, line_y); + + temp_y = line_y; } - Console_mark cm = (Console_mark)ls[0]; - pFont->SetColor(get_mark_color(cm)); - //u8 b = (is_mark( cm ))? 2 : 0; - //OutFont( ls + b, ypos ); - OutFont(ls, ypos); } + m_log_history_guard.Leave(); string16 q; - itoa(log_line, q, 10); + itoa(m_log_line_counter, q, 10); u32 qn = xr_strlen(q); pFont->SetColor(total_font_color); - pFont->OutI(0.95f - 0.03f * qn, fMaxY - 2.0f * LDIST, "[%d]", log_line); + pFont->OutI(0.95f - 0.03f * qn, fMaxY - 2.0f * LDIST, "[%d]", m_log_line_counter); pFont->OnRender(); pFont2->OnRender(); @@ -609,11 +701,12 @@ void CConsole::ExecuteCommand(LPCSTR cmd_str, bool record_cmd) c[0] = mark2; c[1] = 0; - if (m_last_cmd.c_str() == 0 || xr_strcmp(m_last_cmd, edt) != 0) + if (m_last_cmd.c_str() == 0 || xr_strcmp(m_last_cmd.c_str(), edt) != 0) { - Log(c, edt); + Msg("%s %s", c, edt); add_cmd_history(edt); m_last_cmd = edt; + SaveHistory(); } } text_editor::split_cmd(first, last, edt); @@ -653,12 +746,12 @@ void CConsole::ExecuteCommand(LPCSTR cmd_str, bool record_cmd) } else { - Log("! Command disabled."); + Msg("! Command disabled."); } } else { - Log("! Unknown command: ", first); + Msg("! Unknown command: %s", first); } if (record_cmd) @@ -671,10 +764,14 @@ void CConsole::Show() { //SECUROM_MARKER_HIGH_SECURITY_ON(11) - if (bVisible) + if (bVisible) return; + + if (!m_bHistoryLoaded) { - return; + LoadHistory(); + //m_bHistoryLoaded = true; } + bVisible = true; GetCursorPos(&m_mouse_pos); @@ -685,7 +782,7 @@ void CConsole::Show() reset_selected_tip(); update_tips(); - m_editor->IR_Capture(); + this->IR_Capture(); Device.seqRender.Add(this, 1); Device.seqFrame.Add(this); @@ -718,7 +815,22 @@ void CConsole::Hide() Device.seqFrame.Remove(this); Device.seqRender.Remove(this); - m_editor->IR_Release(); + this->IR_Release(); +} + +void CConsole::IR_OnKeyboardPress(int dik) +{ + static_cast(m_editor)->IR_OnKeyboardPress(dik); +} + +void CConsole::IR_OnKeyboardRelease(int dik) +{ + static_cast(m_editor)->IR_OnKeyboardRelease(dik); +} + +void CConsole::IR_OnKeyboardHold(int dik) +{ + static_cast(m_editor)->IR_OnKeyboardHold(dik); } void CConsole::SelectCommand() @@ -894,7 +1006,7 @@ void CConsole::update_tips() m_temp_tips.clear_not_free(); m_tips.clear_not_free(); - m_cur_cmd = NULL; + m_cur_cmd.clear(); if (!bVisible) { return; @@ -944,7 +1056,7 @@ void CConsole::update_tips() cc->fill_tips(m_temp_tips, mode); m_tips_mode = 2; - m_cur_cmd._set(first); + m_cur_cmd = first; select_for_filter(last, m_temp_tips, m_tips); if (m_tips.size() == 0) @@ -978,6 +1090,20 @@ void CConsole::update_tips() } } +void CConsole::DumpHistoryToLog() +{ + if (m_cmd_history.empty()) return; + + Msg("~ [x-ray]: console history start"); + + for (const auto& cmd : m_cmd_history) + { + Msg("- [history]: %s", cmd.c_str()); + } + + Msg("~ [x-ray]: console history end"); +} + void CConsole::select_for_filter(LPCSTR filter_str, vecTips& in_v, vecTipsEx& out_v) { out_v.clear_not_free(); diff --git a/src/xrEngine/XR_IOConsole.h b/src/xrEngine/XR_IOConsole.h index b4fafd9cf5..3956078e36 100644 --- a/src/xrEngine/XR_IOConsole.h +++ b/src/xrEngine/XR_IOConsole.h @@ -7,6 +7,10 @@ #include "../Include/xrRender/FactoryPtr.h" #include "../Include/xrRender/UIShader.h" +#include "../xrCore/RingBuffer.h" +#include "xr_input.h" +#include "IInputReceiver.h" + //refs class ENGINE_API CGameFont; class ENGINE_API IConsole_Command; @@ -82,7 +86,8 @@ enum Console_mark // (int)=char class ENGINE_API CConsole : public pureRender, public pureFrame, - public pureScreenResolutionChanged + public pureScreenResolutionChanged, + public IInputReceiver { public: struct str_pred @@ -96,8 +101,8 @@ class ENGINE_API CConsole : typedef xr_map vecCMD; typedef vecCMD::iterator vecCMD_IT; typedef vecCMD::const_iterator vecCMD_CIT; - typedef fastdelegate::FastDelegate0 Callback; - typedef xr_vector vecHistory; + typedef xr_delegate Callback; + typedef xr_vector vecHistory; typedef xr_vector vecTips; typedef xr_vector vecTipsEx; @@ -116,17 +121,21 @@ class ENGINE_API CConsole : POINT m_mouse_pos; bool m_disable_tips; + RingBuffer m_log_history; + u32 m_log_line_counter; + xrCriticalSection m_log_history_guard; + private: vecHistory m_cmd_history; u32 m_cmd_history_max; int m_cmd_history_idx; - shared_str m_last_cmd; + xr_string m_last_cmd; BENCH_SEC_SCRAMBLEMEMBER1 vecTips m_temp_tips; vecTipsEx m_tips; u32 m_tips_mode; - shared_str m_cur_cmd; + xr_string m_cur_cmd; int m_select_tip; int m_start_tip; u32 m_prev_length_str; @@ -137,7 +146,17 @@ class ENGINE_API CConsole : virtual void Initialize(); virtual void Destroy(); + void DumpHistoryToLog(); + + void AddLogEntry(LPCSTR line); + void ClearLog(); + + virtual void IR_OnKeyboardPress(int dik) override; + virtual void IR_OnKeyboardRelease(int dik) override; + virtual void IR_OnKeyboardHold(int dik) override; + virtual void OnRender(); + virtual void IR_OnMouseWheel(int direction) override; virtual void _BCL OnFrame(); virtual void OnScreenResolutionChanged(); string64 ConfigFile; @@ -179,6 +198,11 @@ class ENGINE_API CConsole : void OutFont(LPCSTR text, float& pos_y); void Register_callbacks(); + void LoadHistory(); + void SaveHistory(); + + bool m_bHistoryLoaded; + protected: void xr_stdcall Screenshot(); @@ -207,7 +231,7 @@ class ENGINE_API CConsole : void xr_stdcall GamePause(); protected: - void add_cmd_history(shared_str const& str); + void add_cmd_history(const xr_string& str); void next_cmd_history_idx(); void prev_cmd_history_idx(); void reset_cmd_history_idx(); diff --git a/src/xrEngine/XR_IOConsole_callback.cpp b/src/xrEngine/XR_IOConsole_callback.cpp index 7281657950..d6bd9175d5 100644 --- a/src/xrEngine/XR_IOConsole_callback.cpp +++ b/src/xrEngine/XR_IOConsole_callback.cpp @@ -65,9 +65,14 @@ void CConsole::Screenshot() void CConsole::Prev_log() // DIK_PRIOR=PAGE_UP { scroll_delta++; - if (scroll_delta > int(LogFile.size()) - 1) + scroll_delta = std::min(scroll_delta, (int)m_log_history.GetSize()); + + // check for empty line + xrCriticalSectionGuard guard(&m_log_history_guard); + const xr_string& line = m_log_history.GetLooped(m_log_history.GetHead() - u32(scroll_delta) - 5u); + if (line.size() == 0) { - scroll_delta = LogFile.size() - 1; + scroll_delta--; } } @@ -82,7 +87,7 @@ void CConsole::Next_log() // DIK_NEXT=PAGE_DOWN void CConsole::Begin_log() // PAGE_UP+Ctrl { - scroll_delta = LogFile.size() - 1; + scroll_delta = 0; } void CConsole::End_log() // PAGE_DOWN+Ctrl @@ -137,7 +142,7 @@ void CConsole::Next_cmd() // DIK_DOWN + Ctrl void CConsole::Prev_tip() // DIK_UP { - if (xr_strlen(ec().str_edit()) == 0) + if (m_cmd_history_idx != -1 || xr_strlen(ec().str_edit()) == 0 || m_tips.empty()) { prev_cmd_history_idx(); SelectCommand(); @@ -146,12 +151,20 @@ void CConsole::Prev_tip() // DIK_UP prev_selected_tip(); } -void CConsole::Next_tip() // DIK_DOWN + Ctrl +void CConsole::Next_tip() // DIK_DOWN { - if (xr_strlen(ec().str_edit()) == 0) + if (m_cmd_history_idx != -1 || xr_strlen(ec().str_edit()) == 0 || m_tips.empty()) { next_cmd_history_idx(); - SelectCommand(); + + if (m_cmd_history_idx == -1) + { + ec().set_edit(""); + } + else + { + SelectCommand(); + } return; } next_selected_tip(); diff --git a/src/xrEngine/XR_IOConsole_control.cpp b/src/xrEngine/XR_IOConsole_control.cpp index 78f6ebf75f..11fba9b3d8 100644 --- a/src/xrEngine/XR_IOConsole_control.cpp +++ b/src/xrEngine/XR_IOConsole_control.cpp @@ -7,14 +7,16 @@ #include "stdafx.h" #include "XR_IOConsole.h" +#include "line_editor.h" -void CConsole::add_cmd_history(shared_str const& str) +void CConsole::add_cmd_history(const xr_string& str) { - if (str.size() == 0) - { + if (str.empty()) return; + + if (!m_cmd_history.empty() && m_cmd_history.back() == str) return; - } + m_cmd_history.push_back(str); if (m_cmd_history.size() > m_cmd_history_max) { @@ -25,18 +27,33 @@ void CConsole::add_cmd_history(shared_str const& str) void CConsole::next_cmd_history_idx() { --m_cmd_history_idx; - if (m_cmd_history_idx < 0) + + if (m_cmd_history_idx < -1) { - m_cmd_history_idx = 0; + m_cmd_history_idx = -1; } } +void CConsole::IR_OnMouseWheel(int direction) +{ + if (!bVisible) return; + + if (direction > 0) + scroll_delta += 3; + else + scroll_delta -= 3; + + if (scroll_delta < 0) scroll_delta = 0; +} + void CConsole::prev_cmd_history_idx() { + if (m_cmd_history.empty()) return; + ++m_cmd_history_idx; if (m_cmd_history_idx >= (int)m_cmd_history.size()) { - m_cmd_history_idx = m_cmd_history.size() - 1; + m_cmd_history_idx = (int)m_cmd_history.size() - 1; } } diff --git a/src/xrEngine/Xr_input.cpp b/src/xrEngine/Xr_input.cpp index bd94119762..261309bdbf 100644 --- a/src/xrEngine/Xr_input.cpp +++ b/src/xrEngine/Xr_input.cpp @@ -720,6 +720,7 @@ void CInput::DeactivateSoft() void CInput::OnFrame(void) { + PROF_EVENT("CInput::OnFrame"); RDEVICE.Statistic->Input.Begin(); dwCurTime = RDEVICE.TimerAsync_MMT(); if (pKeyboard) KeyUpdate(); diff --git a/src/xrEngine/defines.cpp b/src/xrEngine/defines.cpp index b5a44447f0..e0764c5c80 100644 --- a/src/xrEngine/defines.cpp +++ b/src/xrEngine/defines.cpp @@ -11,7 +11,7 @@ u32 psCurrentVidMode[2] = {0, 0}; u32 psCurrentBPP = 32; // release version always has "mt_*" enabled Flags32 psDeviceFlags = { - rsFullscreen | rsDetails | mtPhysics | mtSound | mtNetwork | rsDrawStatic | rsDrawDynamic + rsFullscreen | rsDetails | mtPhysics | mtSound | mtNetwork | rsDrawStatic | rsDrawDynamic | mtParticles }; // textures diff --git a/src/xrEngine/defines.h b/src/xrEngine/defines.h index 9166dbcdc2..e7df3aa96b 100644 --- a/src/xrEngine/defines.h +++ b/src/xrEngine/defines.h @@ -41,6 +41,7 @@ enum rsR2 = (1ul << 19ul), rsR3 = (1ul << 20ul), rsR4 = (1ul << 21ul), + rsDrawPortals = (1ul<<22ul), // 22-32 bit - reserved to Editor }; @@ -66,6 +67,7 @@ enum rsAimSway = (1 << 10), rsAlwaysActive = (1 << 11), rsBlendMoveAnims = (1 << 12), + rsClearAllResources = (1 << 13), }; // game path definition diff --git a/src/xrEngine/device.cpp b/src/xrEngine/device.cpp index 24009248c2..85fed1c566 100644 --- a/src/xrEngine/device.cpp +++ b/src/xrEngine/device.cpp @@ -33,20 +33,27 @@ #include "xrSash.h" #include "igame_persistent.h" +#include "CustomHUD.h" +#include "EngineThreading.h" +#include "IGame_Level.h" + +#include "Rain.h" + #pragma comment( lib, "d3dx9.lib" ) ENGINE_API CRenderDevice Device; ENGINE_API CLoadScreenRenderer load_screen_renderer; +ENGINE_API CRenderDevice* DevicePtr = nullptr; - -ENGINE_API BOOL g_bRendering = FALSE; +ENGINE_API xr_atomic_bool g_bRendering = false; +extern ENGINE_API float psHUD_FOV; BOOL g_bLoaded = FALSE; ref_light precache_light = 0; +BOOL mt_calc_bones = TRUE; BOOL psLua_ParallelGC = TRUE; BOOL psLua_ParallelGC_debug = FALSE; -int psLua_ParallelGC_CallAmount = 25; extern discord::Core* discord_core; extern bool use_discord; @@ -60,9 +67,10 @@ std::chrono::duration time_span; ENGINE_API float refresh_rate = 0; #endif // ECO_RENDER + BOOL CRenderDevice::Begin() { - PROF_EVENT(); + PROF_EVENT("Render: Begin"); #ifndef DEDICATED_SERVER switch (m_pRender->GetDeviceState()) @@ -88,7 +96,7 @@ BOOL CRenderDevice::Begin() m_pRender->Begin(); FPU::m24r(); - g_bRendering = TRUE; + g_bRendering = true; #endif return TRUE; } @@ -103,7 +111,7 @@ extern void CheckPrivilegySlowdown(); void CRenderDevice::End(void) { - PROF_EVENT(); + PROF_EVENT("Render: End"); #ifndef DEDICATED_SERVER @@ -135,8 +143,8 @@ void CRenderDevice::End(void) Msg("* [x-ray]: Handled Necessary Textures Destruction"); Memory.mem_compact(); - Msg("* MEMORY USAGE: %lld K", Memory.mem_usage() / 1024); - Msg("* End of synchronization A[%d] R[%d]", b_is_Active, b_is_Ready); + //Msg("* MEMORY USAGE: %lld K", Memory.mem_usage() / 1024); + //Msg("* End of synchronization A[%d] R[%d]", b_is_Active, b_is_Ready); #ifdef FIND_CHUNK_BENCHMARK_ENABLE g_find_chunk_counter.flush(); @@ -154,7 +162,7 @@ void CRenderDevice::End(void) } } - g_bRendering = FALSE; + g_bRendering = false; // end scene // Present goes here, so call OA Frame end. if (g_SASH.IsBenchmarkRunning()) @@ -168,75 +176,6 @@ void CRenderDevice::End(void) #endif } - -volatile u32 mt_Thread_marker = 0x12345678; - -void mt_Thread(void* ptr) -{ - auto& device = *static_cast(ptr); - while (true) - { - PROF_EVENT(); - - START_PROFILE("Wait for device"); - // waiting for Device permission to execute - device.mt_csEnter.Enter(); - - if (device.mt_bMustExit) - { - PROF_EVENT("Must exit"); - - device.mt_bMustExit = FALSE; // Important!!! - device.mt_csEnter.Leave(); // Important!!! - return; - } - // we has granted permission to execute - mt_Thread_marker = device.dwFrame; - STOP_PROFILE; - - START_PROFILE("Process seqParallel"); - for (u32 pit = 0; pit < device.seqParallel.size(); pit++) - device.seqParallel[pit](); - device.seqParallel.clear_not_free(); - STOP_PROFILE; - - START_PROFILE("Process seqFrameMT"); - device.seqFrameMT.Process(rp_Frame); - STOP_PROFILE; - - // demonized: While Renderer prepares frame and GPU renders it, use time opportunity to repeatedly call Lua GC with small step value - // Reduces stutters since less work will be done in main GC step or no work at all - { - PROF_EVENT("seqLuaGC"); - if (psLua_ParallelGC && Device.LuaGC) - { - // Do at least once - do - { - Device.LuaGCCount++; - if (Device.LuaGC() == 1) // 1 informs that GC cycle is complete - { - Device.LuaGCDone = true; - break; - } - - } while (Device.isRendering && Device.LuaGCCount < psLua_ParallelGC_CallAmount); - } - } - - START_PROFILE("Synchronization"); - // now we give control to device - signals that we are ended our work - device.mt_csEnter.Leave(); - // waits for device signal to continue - to start again - device.mt_csLeave.Enter(); - // returns sync signal to device - device.mt_csLeave.Leave(); - STOP_PROFILE; - } -} - -#include "igame_level.h" - void CRenderDevice::PreCache(u32 amount, bool b_draw_loadscreen, bool b_wait_user_input) { #ifdef DEDICATED_SERVER @@ -388,7 +327,7 @@ void mt_FreezeThread(void *ptr) { START_PROFILE("Check timer"); if (FreezeTimer.GetElapsed_sec()*1000.f > freezetime) { - FlushLog(); + xrLogger::FlushLog(); repeatcheck = 5000.f; } STOP_PROFILE; @@ -399,6 +338,7 @@ void mt_FreezeThread(void *ptr) { void CRenderDevice::on_idle() { + FreezeTimer.Start(); if (!b_is_Ready) @@ -407,8 +347,7 @@ void CRenderDevice::on_idle() return; } - PROF_FRAME("X-RAY Primary thread"); - PROF_EVENT(); + PROF_FRAME("Main Thread"); #ifdef DEDICATED_SERVER u32 FrameStartTime = TimerGlobal.GetElapsed_ms(); @@ -422,9 +361,12 @@ void CRenderDevice::on_idle() if (g_loading_events.size()) { - PROF_EVENT("Pop loading event"); - if (g_loading_events.front()()) - g_loading_events.pop_front(); + { + PROF_EVENT("Loading..."); + if (g_loading_events.front()()) + g_loading_events.pop_front(); + } + PROF_EVENT("LoadDraw"); pApp->LoadDraw(); return; } @@ -435,8 +377,41 @@ void CRenderDevice::on_idle() g_SASH.StartBenchmark(); } + if (Device.ModelDefferClear) + { + Device.ModelDefferClear(); + } + + { + PROF_EVENT("seqParallelBeforRender"); + xrCriticalSectionGuard guard(&Device.seqParallelBeforRenderCS); + + // A callback invoked here can destroy an object that owns a particle + // group, and PS::CParticleGroup::SItem::~SItem cancels its own pending + // entry in this very vector. That cancellation clears the entry in + // place instead of erasing it, so the vector never changes size while + // we walk it. Skip the cleared entries; the clear() below drops them. + // Index by position and copy each delegate before invoking it, so an + // entry appended by a callback is still handled safely. + for (size_t it = 0; it < Device.seqParallelBeforRender.size(); ++it) + { + auto Callback = Device.seqParallelBeforRender[it]; + if (Callback) + Callback(); + } + + Device.seqParallelBeforRender.clear(); + } + FrameMove(); + if (g_pGamePersistent != nullptr) + { + PROF_EVENT("Update Particles"); + g_pGamePersistent->UpdateParticles(); + } + secondary_tasks.run(&XRay::Engine::PreRenderThread); + // Precache if (dwPrecacheFrame) { @@ -455,15 +430,31 @@ void CRenderDevice::on_idle() START_PROFILE("Matrices"); mFullTransform.mul(mProject, mView); mFullTransformHud.mul(mProjectHud, mView); + mFullTransformCam.mul(mProjectCam, mView); m_pRender->SetCacheXform(mView, mProject); + mViewHud_prev = mViewHud; + mProjectHud_prev = mProjectHud; + mFullTransformHud_prev = mFullTransformHud; + mViewCam_prev = mViewCam; + mProjectCam_prev = mProjectCam; + mFullTransformCam_prev = mFullTransformCam; + // Previous frame data -- mView_prev = mView_saved; mProject_prev = mProject_saved; - //mFullTransform_prev = mFullTransform_saved; // Unused? + mFullTransform_prev = mFullTransform_saved; // Unused? m_pRender->SetCacheXform_prev(mView_prev, mProject_prev); + mProjectHud.build_projection(deg2rad(psHUD_FOV * 83.f), fASPECT, R_VIEWPORT_NEAR, g_pGamePersistent->Environment().CurrentEnv->far_plane); + mProjectCam.build_projection(deg2rad(83.f), fASPECT, R_VIEWPORT_NEAR, g_pGamePersistent->Environment().CurrentEnv->far_plane); + + mViewHud.set(mView); + mViewCam.set(mView); + mFullTransformHud.mul(mProjectHud, mViewHud); + mFullTransformCam.mul(mProjectCam, mViewCam); + // Save previous frame grass benders data IGame_Persistent::grass_data& GData = g_pGamePersistent->grass_shader_data; @@ -488,20 +479,22 @@ void CRenderDevice::on_idle() mFullTransform_saved = mFullTransform; mView_saved = mView; mProject_saved = mProject; + STOP_PROFILE; + // TODO: Try to move this upper + secondary_tasks.run(&XRay::Engine::PreRenderPostTransformsThread); + if (mt_calc_bones) + secondary_tasks.run(&XRay::Engine::CalculateBonesThread); + else + XRay::Engine::CalculateBonesThread(); + Device.isRendering = true; - Device.LuaGCCount = 0; Device.LuaGCDone = false; + Device.LuaGCCount = 0; - // *** Resume threads - // Capture end point - thread must run only ONE cycle - // Release start point - allow thread to run - START_PROFILE("Resume threads"); - mt_csLeave.Enter(); - mt_csEnter.Leave(); - STOP_PROFILE; - + secondary_tasks.run(&XRay::Engine::GameThread); + #ifdef ECO_RENDER // ECO_RENDER START if (Device.Paused() || IsMainMenuActive() || ps_framelimiter) { @@ -548,26 +541,10 @@ void CRenderDevice::on_idle() Statistic->RenderTOTAL_Real.End(); Statistic->RenderTOTAL_Real.FrameEnd(); Statistic->RenderTOTAL.accum = Statistic->RenderTOTAL_Real.accum; -#endif // #ifndef DEDICATED_SERVER +#endif Device.isRendering = false; - // *** Suspend threads - // Capture startup point - // Release end point - allow thread to wait for startup point - START_PROFILE("Suspend threads"); - mt_csEnter.Enter(); - mt_csLeave.Leave(); - STOP_PROFILE; - - // Ensure, that second thread gets chance to execute anyway - if (dwFrame != mt_Thread_marker) - { - PROF_EVENT("Execute second thread"); - for (u32 pit = 0; pit < Device.seqParallel.size(); pit++) - Device.seqParallel[pit](); - Device.seqParallel.clear_not_free(); - seqFrameMT.Process(rp_Frame); - } + secondary_tasks.wait(); if (psLua_ParallelGC_debug && psLua_ParallelGC && Device.LuaGCDebug) { @@ -665,26 +642,22 @@ void CRenderDevice::Run() u32 time_local = TimerAsync(); Timer_MM_Delta = time_system - time_local; } - // Start all threads - // InitializeCriticalSection (&mt_csEnter); - // InitializeCriticalSection (&mt_csLeave); - mt_csEnter.Enter(); - mt_bMustExit = FALSE; + + // Start extra threads thread_spawn(mt_FreezeThread, "Freeze detecting thread", 0, 0); - thread_spawn(mt_Thread, "X-RAY Secondary thread", 0, this); thread_spawn(mt_DiscordThread, "X-RAY Discord thread", 0, 0); + // Message cycle seqAppStart.Process(rp_AppStart); - m_pRender->ClearTarget(); + + //m_pRender->ClearTarget(); SetForegroundWindow(m_hWnd); message_loop(); + seqAppEnd.Process(rp_AppEnd); - // Stop Balance-Thread - mt_bMustExit = TRUE; - mt_csEnter.Leave(); - while (mt_bMustExit) Sleep(0); - // DeleteCriticalSection (&mt_csEnter); - // DeleteCriticalSection (&mt_csLeave); + + secondary_tasks.wait(); + ParticleWorkerCallback.clear(); } u32 app_inactive_time = 0; @@ -692,7 +665,7 @@ u32 app_inactive_time_start = 0; void CRenderDevice::FrameMove() { - PROF_EVENT(); + PROF_EVENT("Render: Frame Move"); if (InterlockedExchange(&g_monitor_list_dirty, 0)) refresh_vid_monitor_list(); @@ -737,21 +710,20 @@ void CRenderDevice::FrameMove() dwTimeGlobal = TimerGlobal.GetElapsed_ms(); dwTimeDelta = dwTimeGlobal - _old_global; } + // Frame move Statistic->EngineTOTAL.Begin(); - // TODO: HACK to test loading screen. - //if(!g_bLoaded) + START_PROFILE("Process seqFrame"); Device.seqFrame.Process(rp_Frame); STOP_PROFILE; + g_bLoaded = TRUE; - //else - // seqFrame.Process(rp_Frame); + Statistic->EngineTOTAL.End(); } ENGINE_API BOOL bShowPauseString = TRUE; -#include "IGame_Persistent.h" void CRenderDevice::Pause(BOOL bOn, BOOL bTimer, BOOL bSound, LPCSTR reason) { diff --git a/src/xrEngine/device.h b/src/xrEngine/device.h index d307f50d92..e2e14e452d 100644 --- a/src/xrEngine/device.h +++ b/src/xrEngine/device.h @@ -1,5 +1,3 @@ -#ifndef xr_device -#define xr_device #pragma once // Note: @@ -10,6 +8,7 @@ //class ENGINE_API CGammaControl; #include "pure.h" +#include "../xrCore/xrSyncronize.h" //#include "hw.h" #include "../xrcore/ftimer.h" #include "stats.h" @@ -24,7 +23,7 @@ #define DEVICE_RESET_PRECACHE_FRAME_COUNT 10 // demonized: toggle bone optimization -#define OPTIMIZE_CALCULATE_BONES +//#define OPTIMIZE_CALCULATE_BONES #include "../Include/xrRender/FactoryPtr.h" #include "../Include/xrRender/RenderDeviceRender.h" @@ -36,8 +35,6 @@ class engine_impl; -#pragma pack(push,4) - class IRenderDevice { public: @@ -74,14 +71,26 @@ class ENGINE_API CRenderDeviceData Fvector vCameraTop; Fvector vCameraRight; + // demonized: Cam has fixed 83 fov, Hud is psHUD_FOV * 83.f Fmatrix mView; + Fmatrix mViewHud; + Fmatrix mViewCam; Fmatrix mProject; Fmatrix mProjectHud; + Fmatrix mProjectCam; Fmatrix mFullTransform; Fmatrix mFullTransformHud; + Fmatrix mFullTransformCam; Fmatrix mView_prev; + Fmatrix mViewHud_prev; + Fmatrix mViewCam_prev; Fmatrix mProject_prev; + Fmatrix mProjectHud_prev; + Fmatrix mProjectCam_prev; + Fmatrix mFullTransform_prev; + Fmatrix mFullTransformHud_prev; + Fmatrix mFullTransformCam_prev; Fvector4 wind_anim_prev; Fvector4 wind_anim_saved; @@ -128,7 +137,6 @@ class ENGINE_API CRenderDeviceBase : public: }; -#pragma pack(pop) // refs class ENGINE_API CRenderDevice : public CRenderDeviceBase { @@ -218,15 +226,28 @@ class ENGINE_API CRenderDevice : public CRenderDeviceBase //CRegistrator seqFrame; CRegistrator seqFrameMT; CRegistrator seqDeviceReset; - xr_vector> seqParallel; + xr_vector> seqParallel; + + // ForserX: Pre-Render sequence + xr_vector> seqParallelRender; + xr_vector> seqParallelBeforRender; + + // seqParallelBeforRender is filled from the particle worker thread + // (CParticleGroup::SItem::OnFrame) and drained on the main thread in + // CRenderDevice::on_idle(). Guard every access with this section. + // Same pattern as CEventAPI::CS and CEffect_Rain::rainCS. + xrCriticalSection seqParallelBeforRenderCS; + + xr_delegate ParticleWorkerCallback; + xr_delegate ModelDefferClear; bool isRendering; // LuaGC int LuaGCCount; bool LuaGCDone; - fastdelegate::FastDelegate0 LuaGC; - fastdelegate::FastDelegate0 LuaGCDebug; + xr_delegate LuaGC; + xr_delegate LuaGCDebug; // Dependent classes //CResourceManager* Resources; @@ -271,8 +292,7 @@ class ENGINE_API CRenderDevice : public CRenderDeviceBase m_engine(0) #endif // #ifdef INGAME_EDITOR #ifdef PROFILE_CRITICAL_SECTIONS - ,mt_csEnter(MUTEX_PROFILE_ID(CRenderDevice::mt_csEnter)) - ,mt_csLeave(MUTEX_PROFILE_ID(CRenderDevice::mt_csLeave)) + #endif // #ifdef PROFILE_CRITICAL_SECTIONS { m_hWnd = NULL; @@ -284,7 +304,7 @@ class ENGINE_API CRenderDevice : public CRenderDeviceBase m_SecondViewport.SetSVPActive(false); m_SecondViewport.SetSVPFrameDelay(2); - m_SecondViewport.isCamReady = false; + m_SecondViewport.isCamReady = false; }; void Pause(BOOL bOn, BOOL bTimer, BOOL bSound, LPCSTR reason); @@ -430,13 +450,11 @@ class ENGINE_API CRenderDevice : public CRenderDeviceBase } // Multi-threading - xrCriticalSection mt_csEnter; - xrCriticalSection mt_csLeave; - volatile BOOL mt_bMustExit; + xr_task_group secondary_tasks; - ICF void remove_from_seq_parallel(const fastdelegate::FastDelegate0<>& delegate) + ICF void remove_from_seq_parallel(const xr_delegate& delegate) { - xr_vector>::iterator I = std::find( + xr_vector>::iterator I = std::find( seqParallel.begin(), seqParallel.end(), delegate @@ -507,6 +525,7 @@ class ENGINE_API CRenderDevice : public CRenderDeviceBase }; extern ENGINE_API CRenderDevice Device; +extern ENGINE_API CRenderDevice* DevicePtr; #ifndef _EDITOR #define RDEVICE Device @@ -520,7 +539,7 @@ extern ENGINE_API float refresh_rate; extern ENGINE_API bool g_bBenchmark; -typedef fastdelegate::FastDelegate0 LOADING_EVENT; +typedef xr_delegate LOADING_EVENT; extern ENGINE_API xr_list g_loading_events; class ENGINE_API CLoadScreenRenderer : public pureRender @@ -533,7 +552,10 @@ class ENGINE_API CLoadScreenRenderer : public pureRender bool b_registered; bool b_need_user_input; + + bool IsActive() const { + return b_registered; + } }; extern ENGINE_API CLoadScreenRenderer load_screen_renderer; -#endif diff --git a/src/xrEngine/edit_actions.h b/src/xrEngine/edit_actions.h index 29aafd60ea..e741a2fd45 100644 --- a/src/xrEngine/edit_actions.h +++ b/src/xrEngine/edit_actions.h @@ -32,7 +32,7 @@ namespace text_editor class callback_base : public base { private: - typedef fastdelegate::FastDelegate0 Callback; + typedef xr_delegate Callback; public: callback_base(Callback const& callback, u32 const dik, key_state state); diff --git a/src/xrEngine/line_edit_control.h b/src/xrEngine/line_edit_control.h index 84e52283a2..210060c09c 100644 --- a/src/xrEngine/line_edit_control.h +++ b/src/xrEngine/line_edit_control.h @@ -54,7 +54,7 @@ namespace text_editor { private: typedef text_editor::base Base; - typedef fastdelegate::FastDelegate0 Callback; + typedef xr_delegate Callback; public: line_edit_control(u32 str_buffer_size); diff --git a/src/xrEngine/pure_relcase.cpp b/src/xrEngine/pure_relcase.cpp index 1a8506c3dc..1a22d1a660 100644 --- a/src/xrEngine/pure_relcase.cpp +++ b/src/xrEngine/pure_relcase.cpp @@ -8,3 +8,9 @@ pure_relcase::~pure_relcase() if (g_pGameLevel) g_pGameLevel->Objects.relcase_unregister(&m_ID); } + +pure_relcase_visual::~pure_relcase_visual() +{ + if (g_pGameLevel) + g_pGameLevel->Objects.relcase_visual_unregister(&m_ID); +} diff --git a/src/xrEngine/pure_relcase.h b/src/xrEngine/pure_relcase.h index 3bd1322fca..ad225dc914 100644 --- a/src/xrEngine/pure_relcase.h +++ b/src/xrEngine/pure_relcase.h @@ -23,4 +23,26 @@ class ENGINE_API pure_relcase virtual ~pure_relcase(); }; +class ENGINE_API pure_relcase_visual +{ +private: + int m_ID; +public: + template + pure_relcase_visual(void (xr_stdcall class_type::* function_to_bind)(CObject*)) + { + R_ASSERT(g_pGameLevel); + class_type* self = static_cast(this); + g_pGameLevel->Objects.relcase_visual_register( + CObjectList::RELCASE_CALLBACK( + self, + function_to_bind + ), + &m_ID + ); + } + + virtual ~pure_relcase_visual(); +}; + #endif // pure_relcaseH diff --git a/src/xrEngine/stdafx.h b/src/xrEngine/stdafx.h index 6dbfff7256..47a5839cba 100644 --- a/src/xrEngine/stdafx.h +++ b/src/xrEngine/stdafx.h @@ -64,6 +64,8 @@ #include "../xrSound/sound.h" +#include "../xrCore/profiler.h" + extern ENGINE_API CInifile* pGameIni; #pragma comment( lib, "xrCore.lib" ) diff --git a/src/xrEngine/thunderbolt.cpp b/src/xrEngine/thunderbolt.cpp index 651ed52f41..e33e6384fd 100644 --- a/src/xrEngine/thunderbolt.cpp +++ b/src/xrEngine/thunderbolt.cpp @@ -241,6 +241,7 @@ void CEffect_Thunderbolt::Bolt(shared_str id, float period, float lt) void CEffect_Thunderbolt::OnFrame(shared_str id, float period, float duration) { + PROF_EVENT("CEffect_Thunderbolt::OnFrame"); BOOL enabled = !!(id.size()); if (bEnabled != enabled) { diff --git a/src/xrEngine/vis_common.h b/src/xrEngine/vis_common.h index 32ae89a57f..f201570008 100644 --- a/src/xrEngine/vis_common.h +++ b/src/xrEngine/vis_common.h @@ -7,8 +7,6 @@ struct vis_data { Fsphere sphere; // Fbox box; // - u32 marker; // for different sub-renders - u32 accept_frame; // when it was requisted accepted for main render u32 hom_frame; // when to perform test - shedule u32 hom_tested; // when it was last time tested @@ -17,8 +15,6 @@ struct vis_data sphere.P.set(0, 0, 0); sphere.R = 0; box.invalidate(); - marker = 0; - accept_frame = 0; hom_frame = 0; hom_tested = 0; } diff --git a/src/xrEngine/x_ray.cpp b/src/xrEngine/x_ray.cpp index 7c9df2b6ae..4ec9f16429 100644 --- a/src/xrEngine/x_ray.cpp +++ b/src/xrEngine/x_ray.cpp @@ -109,6 +109,7 @@ static char szEngineHash[33] = DEFAULT_MODULE_HASH; void compute_build_id() { + PROF_EVENT("compute_build_id"); build_date = __DATE__; int days; @@ -170,6 +171,9 @@ ENGINE_API string_path g_sLaunchWorkingFolder; // startup point void InitEngine() { + PROF_EVENT("InitEngine"); + DevicePtr = &Device; + Engine.Initialize(); while (!g_bIntroFinished) Sleep(100); Device.Initialize(); @@ -197,6 +201,7 @@ extern float g_fTimeFactor; PROTECT_API void InitSettings() { + PROF_EVENT("InitSettings"); string_path fname; FS.update_path(fname, "$game_config$", "system.ltx"); #ifdef DEBUG @@ -247,7 +252,7 @@ PROTECT_API void InitConsole() Console->Initialize(); xr_strcpy(Console->ConfigFile, "user.ltx"); - if (strstr(Core.Params, "-ltx ")) + if (Core.ParamsData.test(ECoreParams::ltx)) { string64 c_name; sscanf(strstr(Core.Params, "-ltx ") + 5, "%[^ ] ", c_name); @@ -259,7 +264,8 @@ PROTECT_API void InitConsole() PROTECT_API void InitInput() { - BOOL bCaptureInput = FALSE; // !strstr(Core.Params, "-i"); + PROF_EVENT("InitInput"); + BOOL bCaptureInput = FALSE; pInput = xr_new(bCaptureInput); } @@ -303,7 +309,12 @@ void destroyConsole() void destroyEngine() { Device.Destroy(); + + // This should prevent empty log file in some cases + xrLogger::FlushLog(); + Engine.Destroy(); + DevicePtr = nullptr; } void execUserScript() @@ -321,7 +332,6 @@ void slowdownthread(void*) for (;;) { if (Device.Statistic->fFPS < 30) Sleep(1); - if (Device.mt_bMustExit) return; if (0 == pSettings) return; if (0 == Console) return; if (0 == pInput) return; @@ -332,11 +342,11 @@ void slowdownthread(void*) void CheckPrivilegySlowdown() { #ifdef DEBUG - if (strstr(Core.Params, "-slowdown")) + if (Core.ParamsData.test(ECoreParams::slowdown)) { thread_spawn(slowdownthread, "slowdown", 0, 0); } - if (strstr(Core.Params, "-slowdown2x")) + if (Core.ParamsData.test(ECoreParams::slowdown2x)) { thread_spawn(slowdownthread, "slowdown", 0, 0); thread_spawn(slowdownthread, "slowdown", 0, 0); @@ -350,7 +360,7 @@ LPCSTR xr_ToUTF8(LPCSTR input, int max_length) UConverter *conv_from = ucnv_open("cp1251", &errorCode); R_ASSERT3(conv_from, "[Discord RPC] Error creating UConverter!\n", std::to_string(errorCode).c_str()); - std::vector converted(strlen(input) * 2); + xr_vector converted(strlen(input) * 2); int32_t conv_len = ucnv_toUChars(conv_from, &converted[0], converted.size(), input, strlen(input), &errorCode); if (errorCode != U_ZERO_ERROR) { @@ -362,7 +372,7 @@ LPCSTR xr_ToUTF8(LPCSTR input, int max_length) ucnv_close(conv_from); // needs to be static so the data buffer is still valid after this function returns - static std::string g; + static xr_string g; g.clear(); g.resize(converted.size() * 4); @@ -625,11 +635,11 @@ void Startup() // ...command line for auto start { LPCSTR pStartup = strstr(Core.Params, "-start "); - if (pStartup) Console->Execute(pStartup + 1); + if (Core.ParamsData.test(ECoreParams::start)) Console->Execute(pStartup + 1); } { LPCSTR pStartup = strstr(Core.Params, "-load "); - if (pStartup) Console->Execute(pStartup + 1); + if (Core.ParamsData.test(ECoreParams::load)) Console->Execute(pStartup + 1); } // Initialize APP @@ -640,6 +650,7 @@ void Startup() g_pGamePersistent = (IGame_Persistent*)NEW_INSTANCE(CLSID_GAME_PERSISTANT); g_SpatialSpace = xr_new(); g_SpatialSpacePhysic = xr_new(); + g_SpatialSpaceLights = xr_new(); // Destroy LOGO DestroyWindow(logoWindow); @@ -657,7 +668,7 @@ void Startup() // Main cycle Msg("* [x-ray]: Starting Main Loop"); - Memory.mem_usage(); + //Memory.mem_usage(); Device.Run(); @@ -671,6 +682,7 @@ void Startup() // Destroy APP xr_delete(g_SpatialSpacePhysic); xr_delete(g_SpatialSpace); + xr_delete(g_SpatialSpaceLights); DEL_INSTANCE(g_pGamePersistent); xr_delete(pApp); @@ -1146,9 +1158,15 @@ int APIENTRY WinMain_impl(HINSTANCE hInstance, } extern bool ignore_verify; - ignore_verify = !strstr(Core.Params, "-dbgdev"); + ignore_verify = !Core.ParamsData.test(ECoreParams::dbgdev); Msg("command line %s", Core.Params); + /*Msg("params: "); + for (const auto& v: Core.ParamsData.getBitsetAsMap()) + { + Msg("%s: %s", v.first.c_str(), v.second ? "true" : "false"); + }*/ + LPCSTR sashName = "-openautomate "; if (strstr(lpCmdLine, sashName)) { @@ -1169,9 +1187,9 @@ int APIENTRY WinMain_impl(HINSTANCE hInstance, }; #ifndef DEDICATED_SERVER - if (strstr(Core.Params, "-r2a")) + if (Core.ParamsData.test(ECoreParams::r2a)) Console->Execute("renderer renderer_r2a"); - else if (strstr(Core.Params, "-r2")) + else if (Core.ParamsData.test(ECoreParams::r2)) Console->Execute("renderer renderer_r2"); else { @@ -1184,7 +1202,7 @@ int APIENTRY WinMain_impl(HINSTANCE hInstance, #endif //. InitInput ( ); Engine.External.Initialize(); - Console->Execute("stat_memory"); + Console->Execute("stat_memory_async"); Startup(); Core._destroy(); @@ -1401,6 +1419,7 @@ void CApplication::OnEvent(EVENT E, u64 P1, u64 P2) } else if (E == eStart) { + PROF_EVENT("CApplication::OnEvent: eStart"); LPSTR op_server = LPSTR(P1); LPSTR op_client = LPSTR(P2); Level_Current = u32(-1); @@ -1581,7 +1600,7 @@ void CApplication::LoadStage() VERIFY(ll_dwReference); Msg("* phase time: %d ms", phase_timer.GetElapsed_ms()); phase_timer.Start(); - Msg("* phase cmem: %lld K", Memory.mem_usage() / 1024); + //Msg("* phase cmem: %lld K", Memory.mem_usage() / 1024); if (g_pGamePersistent->GameType() == 1 && !xr_strcmp(g_pGamePersistent->m_game_params.m_alife, "alife")) max_load_stage = 17; @@ -1602,8 +1621,6 @@ void CApplication::OnFrame() Engine.Event.OnFrame(); g_SpatialSpace->update(); g_SpatialSpacePhysic->update(); - if (g_pGameLevel) - g_pGameLevel->SoundEvent_Dispatch(); } void CApplication::Level_Append(LPCSTR folder) @@ -1887,7 +1904,7 @@ void doBenchmark(LPCSTR name) Engine.External.Initialize(); xr_strcpy(Console->ConfigFile, "user.ltx"); - if (strstr(Core.Params, "-ltx ")) + if (Core.ParamsData.test(ECoreParams::ltx)) { string64 c_name; sscanf(strstr(Core.Params, "-ltx ") + 5, "%[^ ] ", c_name); diff --git a/src/xrEngine/xrEngine.vcxproj b/src/xrEngine/xrEngine.vcxproj index ebba928607..3b80d77a57 100644 --- a/src/xrEngine/xrEngine.vcxproj +++ b/src/xrEngine/xrEngine.vcxproj @@ -37,6 +37,10 @@ ReleaseR4 x64 + + VerifiedDX11ASAN + x64 + VerifiedDX11 x64 @@ -90,6 +94,13 @@ true x64 + + Application + v143 + true + x64 + true + Application v143 @@ -166,6 +177,11 @@ + + + + + @@ -240,6 +256,12 @@ $(xrIntDir)$(ProjectName)\ true + + $(xrGameDir)bin_dbg\ + VerifiedDX11 + $(xrIntDir)$(ProjectName)\ + true + $(xrGameDir)bin_dbg\ VerifiedDX9 @@ -459,8 +481,8 @@ false false false - .;$(SolutionDir)3rd party\imgui\;$(SolutionDir)3rd party\luajit-2\src\;$(SolutionDir)3rd party\luabind\;$(SolutionDir)3rd party\giflib\;$(XRAY_16X_LIBS)OpenAutomate\inc;$(XRAY_16X_LIBS)libogg-1.1.4\include;$(XRAY_16X_LIBS)libtheora-1.1.1\include;$(xrSdkDir)include;$(xrSdkDir)include\OpenAutomate;%(AdditionalIncludeDirectories) - USE_VERIFY_IN_RELEASE;STATIC_RENDERER_R4;NDEBUG;WIN32;_WINDOWS;ENGINE_BUILD;_SECURE_SCL=0;AL_LIBTYPE_STATIC;%(PreprocessorDefinitions) + .;$(SolutionDir)3rd party\imgui\;$(SolutionDir)3rd party\luajit-2\src\;$(SolutionDir)3rd party\giflib\;$(SolutionDir)3rd party\luabind\;$(XRAY_16X_LIBS)OpenAutomate\inc;$(XRAY_16X_LIBS)libogg-1.1.4\include;$(XRAY_16X_LIBS)libtheora-1.1.1\include;$(xrSdkDir)include;$(xrSdkDir)include\OpenAutomate;%(AdditionalIncludeDirectories) + XRCORE_PROFILER;USE_VERIFY_IN_RELEASE;STATIC_RENDERER_R4;NDEBUG;WIN32;_WINDOWS;ENGINE_BUILD;_SECURE_SCL=0;AL_LIBTYPE_STATIC;%(PreprocessorDefinitions) Use stdafx.h USE_LUAJIT_ONE @@ -494,6 +516,50 @@ $(SolutionDir)xrEngine\as-invoker-manifest-part.xml;%(AdditionalManifestFiles) + + + Disabled + Disabled + false + Neither + false + false + false + .;$(SolutionDir)3rd party\imgui\;$(SolutionDir)3rd party\luajit-2\src\;$(SolutionDir)3rd party\giflib\;$(SolutionDir)3rd party\luabind\;$(SolutionDir)3rd party\giflib\;$(XRAY_16X_LIBS)OpenAutomate\inc;$(XRAY_16X_LIBS)libogg-1.1.4\include;$(XRAY_16X_LIBS)libtheora-1.1.1\include;$(xrSdkDir)include;$(xrSdkDir)include\OpenAutomate;%(AdditionalIncludeDirectories) + XRCORE_PROFILER;USE_VERIFY_IN_RELEASE;STATIC_RENDERER_R4;NDEBUG;WIN32;_WINDOWS;ENGINE_BUILD;_SECURE_SCL=0;AL_LIBTYPE_STATIC;_DISABLE_VECTOR_ANNOTATION;_DISABLE_STRING_ANNOTATION;%(PreprocessorDefinitions) + Use + stdafx.h + USE_LUAJIT_ONE + ProgramDatabase + true + Default + Level4 + false + MultiThreadedDLL + false + stdcpp17 + true + + + NDEBUG;%(PreprocessorDefinitions) + + + vfw32.lib;libogg_static.lib;libtheora_static.lib;winmm.lib;OpenAL32.lib;giflib.lib;%(AdditionalDependencies) + $(OutDir)$(Platform)\VerifiedDX11ASAN\;$(SolutionDir)3rd party\luajit-2\src\;$(XRAY_16X_LIBS)OpenAutomate\libraries;$(SolutionDir)..\lib\$(Platform)\VerifiedDX11ASAN;$(SolutionDir)$(Platform)\VerifiedDX11ASAN;$(xrSdkDir)libraries\x64;$(xrLibDir);%(AdditionalLibraryDirectories) + %(IgnoreSpecificDefaultLibraries) + $(xrLibDir)$(TargetName).lib + /ignore:4099 + true + false + false + Default + false + NotSet + + + $(SolutionDir)xrEngine\as-invoker-manifest-part.xml;%(AdditionalManifestFiles) + + Disabled @@ -503,7 +569,7 @@ false false false - .;$(SolutionDir)3rd party\imgui\;$(SolutionDir)3rd party\luajit-2\src\;$(SolutionDir)3rd party\luabind\;$(SolutionDir)3rd party\giflib\;$(XRAY_16X_LIBS)OpenAutomate\inc;$(XRAY_16X_LIBS)libogg-1.1.4\include;$(XRAY_16X_LIBS)libtheora-1.1.1\include;$(xrSdkDir)include;$(xrSdkDir)include\OpenAutomate;%(AdditionalIncludeDirectories) + .;$(SolutionDir)3rd party\imgui\;$(SolutionDir)3rd party\luajit-2\src\;$(SolutionDir)3rd party\giflib\;$(SolutionDir)3rd party\luabind\;$(SolutionDir)3rd party\giflib\;$(XRAY_16X_LIBS)OpenAutomate\inc;$(XRAY_16X_LIBS)libogg-1.1.4\include;$(XRAY_16X_LIBS)libtheora-1.1.1\include;$(xrSdkDir)include;$(xrSdkDir)include\OpenAutomate;%(AdditionalIncludeDirectories) XRCORE_PROFILER;USE_VERIFY_IN_RELEASE;STATIC_RENDERER_R2;NDEBUG;WIN32;_WINDOWS;ENGINE_BUILD;_SECURE_SCL=0;AL_LIBTYPE_STATIC;%(PreprocessorDefinitions) Use stdafx.h @@ -748,7 +814,7 @@ - .;$(SolutionDir)3rd party\imgui\;$(SolutionDir)3rd party\luajit-2\src\;$(SolutionDir)3rd party\luabind\;$(SolutionDir)3rd party\giflib\;$(XRAY_16X_LIBS)OpenAutomate\inc;$(XRAY_16X_LIBS)libogg-1.1.4\include;$(XRAY_16X_LIBS)libtheora-1.1.1\include;$(xrSdkDir)include;$(xrSdkDir)include\OpenAutomate;%(AdditionalIncludeDirectories) + .;$(SolutionDir)3rd party\imgui\;$(SolutionDir)3rd party\luajit-2\src\;$(SolutionDir)3rd party\giflib\;$(SolutionDir)3rd party\luabind\;$(SolutionDir)3rd party\giflib\;$(XRAY_16X_LIBS)OpenAutomate\inc;$(XRAY_16X_LIBS)libogg-1.1.4\include;$(XRAY_16X_LIBS)libtheora-1.1.1\include;$(xrSdkDir)include;$(xrSdkDir)include\OpenAutomate;%(AdditionalIncludeDirectories) Default true EditAndContinue @@ -867,6 +933,7 @@ + @@ -980,6 +1047,7 @@ + @@ -1031,6 +1099,7 @@ Create Create Create + Create Create Create Create @@ -1160,6 +1229,11 @@ {AC9B12ED-A2D7-4337-A981-5BD8430E96D8} + + + {AC9B12ED-A2D7-4337-A981-5BD8430E96D8} + + {963BA4E5-499A-454D-B002-1D5ECE0527A6} diff --git a/src/xrEngine/xrEngine.vcxproj.filters b/src/xrEngine/xrEngine.vcxproj.filters index 4b104a74ce..feeda89df2 100644 --- a/src/xrEngine/xrEngine.vcxproj.filters +++ b/src/xrEngine/xrEngine.vcxproj.filters @@ -495,6 +495,7 @@ Render\Execution & 3D\Shaders\Textures + @@ -809,6 +810,7 @@ Render\Execution & 3D\Shaders\Textures + @@ -823,4 +825,4 @@ General\Resources - \ No newline at end of file + diff --git a/src/xrEngine/xrSASH.cpp b/src/xrEngine/xrSASH.cpp index d0d596b8c0..35f555e86a 100644 --- a/src/xrEngine/xrSASH.cpp +++ b/src/xrEngine/xrSASH.cpp @@ -150,7 +150,7 @@ void xrSASH::LoopNative() else Msg("oa:: Native path can't find \"%s\" config file.", in_file); - FlushLog(); + xrLogger::FlushLog(); } void xrSASH::ReportNative(LPCSTR pszTestName) @@ -454,16 +454,16 @@ void xrSASH::TryInitEngine(bool bNoRun) } xr_strcpy(Console->ConfigFile, "user.ltx"); - if (strstr(Core.Params, "-ltx ")) + if (Core.ParamsData.test(ECoreParams::ltx)) { string64 c_name; sscanf(strstr(Core.Params, "-ltx ") + 5, "%[^ ] ", c_name); xr_strcpy(Console->ConfigFile, c_name); } - if (strstr(Core.Params, "-r2a")) + if (Core.ParamsData.test(ECoreParams::r2a)) Console->Execute("renderer renderer_r2a"); - else if (strstr(Core.Params, "-r2")) + else if (Core.ParamsData.test(ECoreParams::r2)) Console->Execute("renderer renderer_r2"); else { diff --git a/src/xrEngine/xrSheduler.cpp b/src/xrEngine/xrSheduler.cpp index 543969e989..58ccc4e04d 100644 --- a/src/xrEngine/xrSheduler.cpp +++ b/src/xrEngine/xrSheduler.cpp @@ -1,33 +1,40 @@ #include "stdafx.h" #include "xrSheduler.h" #include "xr_object.h" +#include "IGame_Level.h" -//#define DEBUG_SCHEDULER +#include "../xrCore/profiler.h" float psShedulerCurrent = 10.f; float psShedulerTarget = 10.f; const float psShedulerReaction = 0.1f; -BOOL g_bSheduleInProgress = FALSE; //------------------------------------------------------------------------------------- void CSheduler::Initialize() { m_current_step_obj = NULL; m_processing_now = false; + m_processing_nowRT = false; + m_bTerminating = false; } void CSheduler::Destroy() { + m_bTerminating = true; internal_Registration(); - for (u32 it = 0; it < Items.size(); it++) { - if (0 == Items[it].Object) + xrSRWLockGuard g(ItemsLock); + for (u32 it = 0; it < Items.size(); it++) { - Items.erase(Items.begin() + it); - it--; + if (0 == Items[it].Object) + { + Items.erase(Items.begin() + it); + it--; + } } } + #ifdef DEBUG if (!Items.empty()) { @@ -39,52 +46,38 @@ void CSheduler::Destroy() Msg("%s", Items[it].Object->shedule_Name().c_str()); } #endif // DEBUG + ItemsRT.clear(); - Items.clear(); - ItemsProcessed.clear(); + + { + xrSRWLockGuard g(ItemsLock); + Items.clear(); + } + Registration.clear(); } void CSheduler::internal_Registration() { + xr_unordered_flat_map final_states; + final_states.reserve(Registration.size()); + + // Get latest state of sheduled object for (u32 it = 0; it < Registration.size(); it++) { ItemReg& R = Registration[it]; - if (R.OP) - { - // register - // search for paired "unregister" - BOOL bFoundAndErased = FALSE; - for (u32 pair = it + 1; pair < Registration.size(); pair++) - { - ItemReg& R_pair = Registration[pair]; - if ((!R_pair.OP) && (R_pair.Object == R.Object)) - { - bFoundAndErased = TRUE; - Registration.erase(Registration.begin() + pair); - break; - } - } + final_states[R.Object] = it; + } - // register if non-paired - if (!bFoundAndErased) - { -#ifdef DEBUG_SCHEDULER - Msg("SCHEDULER: internal register [%s][%x][%s]", *R.Object->shedule_Name(), R.Object, R.RT ? "true" : "false"); -#endif // DEBUG_SCHEDULER - internal_Register(R.Object, R.RT); - } -#ifdef DEBUG_SCHEDULER - else - Msg("SCHEDULER: internal register skipped, because unregister found [%s][%x][%s]", "unknown", R.Object, R.RT ? "true" : "false"); -#endif // DEBUG_SCHEDULER - } + for (const auto& [object, it] : final_states) + { + ItemReg& R = Registration[it]; + if (R.OP) + internal_Register(R.Object, R.RT); else - { - // unregister internal_Unregister(R.Object, R.RT); - } } + Registration.clear(); } @@ -101,7 +94,7 @@ void CSheduler::internal_Register(ISheduled* O, BOOL RT) TNext.scheduled_name = O->shedule_Name(); O->shedule.b_RT = TRUE; - ItemsRT.push_back(TNext); + ItemsRT.push_back(std::move(TNext)); } else { @@ -114,7 +107,7 @@ void CSheduler::internal_Register(ISheduled* O, BOOL RT) O->shedule.b_RT = FALSE; // Insert into priority Queue - Push(TNext); + Push(std::move(TNext)); } } @@ -128,9 +121,6 @@ bool CSheduler::internal_Unregister(ISheduled* O, BOOL RT, bool warn_on_not_foun { if (ItemsRT[i].Object == O) { -#ifdef DEBUG_SCHEDULER - Msg("SCHEDULER: internal unregister [%s][%x][%s]", "unknown", O, "true"); -#endif // DEBUG_SCHEDULER ItemsRT.erase(ItemsRT.begin() + i); return (true); } @@ -138,27 +128,22 @@ bool CSheduler::internal_Unregister(ISheduled* O, BOOL RT, bool warn_on_not_foun } else { + if (m_current_step_obj == O) + { + m_current_step_obj = NULL; + return true; + } + + xrSRWLockGuard g(ItemsLock); for (u32 i = 0; i < Items.size(); i++) { if (Items[i].Object == O) { -#ifdef DEBUG_SCHEDULER - Msg("SCHEDULER: internal unregister [%s][%x][%s]", *Items[i].scheduled_name, O, "false"); -#endif // DEBUG_SCHEDULER Items[i].Object = NULL; return (true); } } } - if (m_current_step_obj == O) - { -#ifdef DEBUG_SCHEDULER - Msg("SCHEDULER: internal unregister (self unregistering) [%x][%s]", O, "false"); -#endif // DEBUG_SCHEDULER - - m_current_step_obj = NULL; - return true; - } #ifdef DEBUG if (warn_on_not_found) @@ -254,11 +239,7 @@ void CSheduler::Register(ISheduled* A, BOOL RT) R.Object = A; R.Object->shedule.b_RT = RT; -#ifdef DEBUG_SCHEDULER - Msg("SCHEDULER: register [%s][%x]", *A->shedule_Name(), A); -#endif // DEBUG_SCHEDULER - - Registration.push_back(R); + Registration.push_back(std::move(R)); } void CSheduler::Unregister(ISheduled* A) @@ -266,11 +247,19 @@ void CSheduler::Unregister(ISheduled* A) #ifdef DEBUG VERIFY(Registered(A)); #endif -#ifdef DEBUG_SCHEDULER - Msg("SCHEDULER: unregister [%s][%x]", *A->shedule_Name(), A); -#endif // DEBUG_SCHEDULER - if (m_processing_now) + // wait until done with m_current_step_obj + if (m_current_step_obj == A) + { + // Loop until the worker releases the object + xrSpinWait w; + while (m_current_step_obj == A) + { + w(); + } + } + + if (!( (!A->shedule.b_RT && m_processing_now) || (A->shedule.b_RT && m_processing_nowRT) )) { if (internal_Unregister(A, A->shedule.b_RT, false)) return; @@ -281,7 +270,7 @@ void CSheduler::Unregister(ISheduled* A) R.RT = A->shedule.b_RT; R.Object = A; - Registration.push_back(R); + Registration.push_back(std::move(R)); } void CSheduler::EnsureOrder(ISheduled* Before, ISheduled* After) @@ -294,204 +283,269 @@ void CSheduler::EnsureOrder(ISheduled* Before, ISheduled* After) { Item A = ItemsRT[i]; ItemsRT.erase(ItemsRT.begin() + i); - ItemsRT.push_back(A); + ItemsRT.push_back(std::move(A)); return; } } } -void CSheduler::Push(Item& I) +void CSheduler::PushImpl(Item& I) { Items.push_back(I); std::push_heap(Items.begin(), Items.end()); } -void CSheduler::Pop() +void CSheduler::PushImpl(Item&& I) +{ + Items.push_back(std::move(I)); + std::push_heap(Items.begin(), Items.end()); +} + +void CSheduler::Push(Item& I) +{ + xrSRWLockGuard g(ItemsLock); + PushImpl(I); +} + +void CSheduler::Push(Item&& I) +{ + xrSRWLockGuard g(ItemsLock); + PushImpl(std::move(I)); +} + +void CSheduler::PopImpl() { std::pop_heap(Items.begin(), Items.end()); Items.pop_back(); } +void CSheduler::Pop() +{ + xrSRWLockGuard g(ItemsLock); + PopImpl(); +} + +int SchedulerBatchSize = 256; +BOOL SchedulerLog = FALSE; +extern ENGINE_API IGame_Level* g_pGameLevel; void CSheduler::ProcessStep() { // Normal priority u32 dwTime = Device.dwTimeGlobal; - CTimer eTimer; - for (int i = 0; !Items.empty() && Top().dwTimeForExecute < dwTime; ++i) - { - u32 delta_ms = dwTime - Top().dwTimeForExecute; + static xr_vector ItemsBatch; + ItemsBatch.clear(); + u32 ItemsCount = Items.size(); + float target = psShedulerTarget; - // Update - Item T = Top(); -#ifdef DEBUG_SCHEDULER - Msg("SCHEDULER: process step [%s][%x][false]", *T.scheduled_name, T.Object); -#endif // DEBUG_SCHEDULER - u32 Elapsed = dwTime - T.dwTimeOfLastExecute; - bool condition; + u32 batchSize = g_pGameLevel && g_pGameLevel->schedulerFlush ? 65536 : SchedulerBatchSize; - condition = (NULL == T.Object || !T.Object->shedule_Needed()); - if (condition) + { + xrSRWLockGuard g(ItemsLock); + while (!Items.empty() && Top().dwTimeForExecute < dwTime && ItemsBatch.size() < batchSize) { - // Erase element -#ifdef DEBUG_SCHEDULER - Msg("SCHEDULER: process unregister [%s][%x][%s]", *T.scheduled_name, T.Object, "false"); -#endif // DEBUG_SCHEDULER - // if (T.Object) - // Msg ("0x%08x UNREGISTERS because shedule_Needed() returned false",T.Object); - // else - // Msg ("UNREGISTERS unknown object"); - Pop(); - continue; + // Optional: Also stop collecting if we are already out of time + // (Prevents grabbing items we won't even touch) + if (Device.dwPrecacheFrame == 0 && CPU::QPC() > cycles_limit) + break; + + // Add item to batch + Item& T = Top(); + if (T.Object && T.Object->shedule_Needed()) + { + ItemsBatch.push_back(std::move(T)); + } + PopImpl(); } + } - // Insert into priority Queue - Pop(); + if (ItemsBatch.empty()) + { + // always try to decrease target + psShedulerTarget -= psShedulerReaction; + return; + } - // Real update call - // Msg ("------- %d:",Device.dwFrame); -#ifdef DEBUG - T.Object->dbg_startframe = Device.dwFrame; - eTimer.Start(); - // LPCSTR _obj_name = T.Object->shedule_Name().c_str(); -#endif // DEBUG + static xr_vector ItemsProcessed; + ItemsProcessed.clear(); + int i = 0; + { + for (i = 0; i < ItemsBatch.size(); ++i) + { + // Stop if about to exit + if (m_bTerminating) + break; - // Calc next update interval - u32 dwMin = _max(u32(30), T.Object->shedule.t_min); - u32 dwMax = (1000 + T.Object->shedule.t_max) / 2; - float scale = T.Object->shedule_Scale(); - u32 dwUpdate = dwMin + iFloor(float(dwMax - dwMin) * scale); - clamp(dwUpdate, u32(_max(dwMin, u32(20))), dwMax); + // Stop if really underestimated the cost of batch, check every 8th item + if ((i % 8) == 0 && Device.dwPrecacheFrame == 0 && CPU::QPC() > cycles_limit) + { + psShedulerTarget += (psShedulerReaction * 3); + break; + } + Item& T = ItemsBatch[i]; + if (!T.Object) + continue; + m_current_step_obj = T.Object; - m_current_step_obj = T.Object; - // try { - T.Object->shedule_Update(clampr(Elapsed, u32(1), u32(_max(u32(T.Object->shedule.t_max), u32(1000))))); - if (!m_current_step_obj) - { -#ifdef DEBUG_SCHEDULER - Msg("SCHEDULER: process unregister (self unregistering) [%s][%x][%s]", *T.scheduled_name, T.Object, "false"); -#endif // DEBUG_SCHEDULER - continue; - } - // } catch (...) { -#ifdef DEBUG - // Msg ("! xrSheduler: object '%s' raised an exception", _obj_name); - // throw ; -#endif // DEBUG - // } - m_current_step_obj = NULL; + // Update + u32 Elapsed = dwTime - T.dwTimeOfLastExecute; -#ifdef DEBUG - // u32 execTime = eTimer.GetElapsed_ms (); -#endif // DEBUG + // Calc next update interval + u32 dwMin = _max(u32(30), T.Object->shedule.t_min); + u32 dwMax = (1000 + T.Object->shedule.t_max) / 2; + float scale = T.Object->shedule_Scale(); + u32 dwUpdate = dwMin + iFloor(float(dwMax - dwMin) * scale); + clamp(dwUpdate, u32(_max(dwMin, u32(20))), dwMax); - // Fill item structure - Item TNext; - TNext.dwTimeForExecute = dwTime + dwUpdate; - TNext.dwTimeOfLastExecute = dwTime; - TNext.Object = T.Object; - TNext.scheduled_name = T.Object->shedule_Name(); - ItemsProcessed.push_back(TNext); + T.Object->shedule_Update(clampr(Elapsed, u32(1), u32(_max(u32(T.Object->shedule.t_max), u32(1000))))); + // Fill item structure + Item TNext; + TNext.dwTimeForExecute = dwTime + dwUpdate; + TNext.dwTimeOfLastExecute = dwTime; + TNext.Object = T.Object; + TNext.scheduled_name = T.Object->shedule_Name(); + ItemsProcessed.push_back(std::move(TNext)); -#ifdef DEBUG - // u32 execTime = eTimer.GetElapsed_ms (); - // VERIFY3 (T.Object->dbg_update_shedule == T.Object->dbg_startframe, "Broken sequence of calls to 'shedule_Update'", _obj_name ); - if (delta_ms > 3 * dwUpdate) - { - //Msg ("! xrSheduler: failed to shedule object [%s] (%dms)", _obj_name, delta_ms ); - } - // if (execTime> 15) { - // Msg ("* xrSheduler: too much time consumed by object [%s] (%dms)", _obj_name, execTime ); - // } -#endif // DEBUG + m_current_step_obj = NULL; + } + } - // - if ((i % 3) != (3 - 1)) - continue; + if (SchedulerLog) + Msg("Sheduler: cycles_start[%llu] cycles_limit[%llu] qpc_freq[%llu] Target[%f] psShedulerReaction[%f] NewTarget[%f] ItemsCount[%d] ItemsBatch[%d], ItemsActuallyProcessed [%d]", + cycles_start, + cycles_limit, + CPU::qpc_freq, + target, + psShedulerReaction, + psShedulerTarget, + ItemsCount, + ItemsBatch.size(), + i); + + // Reinsertion + { + // Strategy + // Rule of thumb: if k < n / log2(n), push_heap is faster. With default batch size of 128 its always faster, start choosing only with 256 + // Otherwise, dump and heapify + // For n=3000, log2(n) is ~11.5. n/11.5 is ~260. + // We use a simple approximation: n >> 4 (which is n / 16) for a conservative safety margin. + u32 k = ItemsProcessed.size() + (ItemsBatch.size() - i); + u32 n = Items.size(); + + xrSRWLockGuard g(ItemsLock); - if (Device.dwPrecacheFrame == 0 && CPU::QPC() > cycles_limit) + if (k < 256 || k < (n >> 4)) { - // we have maxed out the load - increase heap - psShedulerTarget += (psShedulerReaction * 3); - break; + // Push finished + for (auto& T : ItemsProcessed) + { + if (T.Object) + PushImpl(std::move(T)); + } + + // Push unprocessed + for (int j = i; j < ItemsBatch.size(); ++j) + { + if (ItemsBatch[j].Object) + PushImpl(std::move(ItemsBatch[j])); + } } - } + else + { + // Push finished + for (auto& T : ItemsProcessed) + { + if (T.Object) + Items.push_back(std::move(T)); + } - // Push "processed" back - while (ItemsProcessed.size()) - { - Push(ItemsProcessed.back()); - ItemsProcessed.pop_back(); - } + // Push unprocessed + for (int j = i; j < ItemsBatch.size(); ++j) + { + if (ItemsBatch[j].Object) + Items.push_back(std::move(ItemsBatch[j])); + } + // Heapify + std::make_heap(Items.begin(), Items.end()); + } + ItemsProcessed.clear(); + } + // always try to decrease target psShedulerTarget -= psShedulerReaction; } -/* -void CSheduler::Switch () -{ -if (fibered) -{ -fibered = FALSE; -SwitchToFiber (fiber_main); -} -} -*/ -void CSheduler::Update() +void CSheduler::UpdateInit() { + PROF_EVENT(); R_ASSERT(Device.Statistic); // Initialize Device.Statistic->Sheduler.Begin(); - cycles_start = CPU::QPC(); - cycles_limit = CPU::qpc_freq * u64(iCeil(psShedulerCurrent)) / 1000i64 + cycles_start; internal_Registration(); - g_bSheduleInProgress = TRUE; +} + +void CSheduler::UpdateRT() +{ + PROF_EVENT(); -#ifdef DEBUG_SCHEDULER - Msg("SCHEDULER: PROCESS STEP %d", Device.dwFrame); -#endif // DEBUG_SCHEDULER // Realtime priority - m_processing_now = true; + m_processing_nowRT = true; u32 dwTime = Device.dwTimeGlobal; for (u32 it = 0; it < ItemsRT.size(); it++) { Item& T = ItemsRT[it]; R_ASSERT(T.Object); -#ifdef DEBUG_SCHEDULER - Msg("SCHEDULER: process step [%s][%x][true]", *T.Object->shedule_Name(), T.Object); -#endif // DEBUG_SCHEDULER if (!T.Object->shedule_Needed()) { -#ifdef DEBUG_SCHEDULER - Msg("SCHEDULER: process unregister [%s][%x][%s]", *T.Object->shedule_Name(), T.Object, "false"); -#endif // DEBUG_SCHEDULER T.dwTimeOfLastExecute = dwTime; continue; } u32 Elapsed = dwTime - T.dwTimeOfLastExecute; #ifdef DEBUG - VERIFY(T.Object->dbg_startframe != Device.dwFrame); - T.Object->dbg_startframe = Device.dwFrame; + VERIFY(T.Object->dbg_startframe != Device.dwFrame); + T.Object->dbg_startframe = Device.dwFrame; #endif T.Object->shedule_Update(Elapsed); T.dwTimeOfLastExecute = dwTime; } + m_processing_nowRT = false; +} + +void CSheduler::UpdateDeferred() +{ + PROF_EVENT(); + + cycles_start = CPU::QPC(); + cycles_limit = CPU::qpc_freq * u64(iCeil(psShedulerCurrent)) / 1000ull + cycles_start; // Normal (sheduled) + m_processing_now = true; ProcessStep(); m_processing_now = false; -#ifdef DEBUG_SCHEDULER - Msg("SCHEDULER: PROCESS STEP FINISHED %d", Device.dwFrame); -#endif // DEBUG_SCHEDULER +} + +void CSheduler::UpdateFinalize() +{ + PROF_EVENT(); + clamp(psShedulerTarget, 3.f, 66.f); psShedulerCurrent = 0.9f * psShedulerCurrent + 0.1f * psShedulerTarget; Device.Statistic->fShedulerLoad = psShedulerCurrent; // Finalize - g_bSheduleInProgress = FALSE; internal_Registration(); Device.Statistic->Sheduler.End(); } + +void CSheduler::Update() +{ + PROF_EVENT(); + + UpdateInit(); + UpdateRT(); + UpdateDeferred(); + UpdateFinalize(); +} diff --git a/src/xrEngine/xrSheduler.h b/src/xrEngine/xrSheduler.h index 14520515a8..caf677213f 100644 --- a/src/xrEngine/xrSheduler.h +++ b/src/xrEngine/xrSheduler.h @@ -1,5 +1,4 @@ -#ifndef XRSHEDULER_H_INCLUDED -#define XRSHEDULER_H_INCLUDED +#pragma once #include "ISheduled.h" @@ -8,11 +7,10 @@ class ENGINE_API CSheduler private: struct Item { + shared_str scheduled_name; u32 dwTimeForExecute; u32 dwTimeOfLastExecute; - shared_str scheduled_name; ISheduled* Object; - u32 dwPadding; // for align-issues IC bool operator <(Item& I) { @@ -30,13 +28,21 @@ class ENGINE_API CSheduler private: xr_vector ItemsRT; xr_vector Items; - xr_vector ItemsProcessed; xr_vector Registration; - ISheduled* m_current_step_obj; + + xrSRWLock ItemsLock; + + volatile ISheduled* m_current_step_obj; + bool m_processing_now; + bool m_processing_nowRT; + IC void PushImpl(Item& I); + IC void PushImpl(Item&& I); IC void Push(Item& I); + IC void Push(Item&& I); IC void Pop(); + IC void PopImpl(); IC Item& Top() { return Items.front(); @@ -48,9 +54,15 @@ class ENGINE_API CSheduler public: u64 cycles_start; u64 cycles_limit; + volatile bool m_bTerminating; public: void ProcessStep(); void Process(); + + void UpdateInit(); + void UpdateRT(); + void UpdateDeferred(); + void UpdateFinalize(); void Update(); #ifdef DEBUG @@ -63,5 +75,3 @@ class ENGINE_API CSheduler void Initialize(); void Destroy(); }; - -#endif // XRSHEDULER_H_INCLUDED diff --git a/src/xrEngine/xr_collide_form.cpp b/src/xrEngine/xr_collide_form.cpp index cf65f1ae38..d954401059 100644 --- a/src/xrEngine/xr_collide_form.cpp +++ b/src/xrEngine/xr_collide_form.cpp @@ -65,8 +65,9 @@ bool pred_find_elem(const CCF_Skeleton::SElement& E, u16 elem) bool CCF_Skeleton::_ElementCenter(u16 elem_id, Fvector& e_center) { + xrSRWLockGuard guard(&build_lock, true); ElementVecIt it = std::lower_bound(elements.begin(), elements.end(), elem_id, pred_find_elem); - if (it->elem_id == elem_id) + if ((it != elements.end()) && (it->elem_id == elem_id)) { it->center(e_center); return true; @@ -127,12 +128,13 @@ CCF_Skeleton::CCF_Skeleton(CObject* O) : ICollisionForm(O, cftObject) void CCF_Skeleton::BuildState() { - dwFrame = Device.dwFrame; IRenderVisual* pVisual = owner->Visual(); IKinematics* K = PKinematics(pVisual); - K->CalculateBones(); + //K->CalculateBones(); const Fmatrix& L2W = owner->XFORM(); + xrSRWLockGuard guard(&build_lock, false); + dwFrame = Device.dwFrame; if (vis_mask != K->LL_GetBonesVisible()) { vis_mask = K->LL_GetBonesVisible(); @@ -149,6 +151,11 @@ void CCF_Skeleton::BuildState() } } + // Non-blocking: BuildState runs inside the IK callback from CalculateBones, which already + // holds the current skeleton's UCalc_Mutex; a blocking acquire of this neighbour skeleton's + // lock could cross-lock two objects in opposite order on two threads (AB-BA deadlock). If + // it's mid-recalc elsewhere, read its 1-frame-stale transforms instead of blocking. + xrCriticalSectionTryGuard g(K->UCalc_Mutex); for (ElementVecIt I = elements.begin(); I != elements.end(); I++) { if (!I->valid()) continue; @@ -212,9 +219,11 @@ void CCF_Skeleton::BuildState() void CCF_Skeleton::BuildTopLevel() { - dwFrameTL = Device.dwFrame; IRenderVisual* K = owner->Visual(); vis_data& vis = K->getVisData(); + + xrSRWLockGuard guard(&build_lock, false); + dwFrameTL = Device.dwFrame; Fbox& B = vis.box; bv_box.min.average(B.min); bv_box.max.average(B.max); @@ -227,12 +236,16 @@ void CCF_Skeleton::BuildTopLevel() BOOL CCF_Skeleton::_RayQuery(const collide::ray_defs& Q, collide::rq_results& R) { + PROF_EVENT("CCF_Skeleton::_RayQuery"); if (dwFrameTL != Device.dwFrame) BuildTopLevel(); Fsphere w_bv_sphere; - owner->XFORM().transform_tiny(w_bv_sphere.P, bv_sphere.P); - w_bv_sphere.R = bv_sphere.R; + { + xrSRWLockGuard guard(&build_lock, true); + owner->XFORM().transform_tiny(w_bv_sphere.P, bv_sphere.P); + w_bv_sphere.R = bv_sphere.R; + } // float tgt_dist = Q.range; @@ -254,6 +267,7 @@ BOOL CCF_Skeleton::_RayQuery(const collide::ray_defs& Q, collide::rq_results& R) } BOOL bHIT = FALSE; + xrSRWLockGuard guard(&build_lock, true); for (ElementVecIt I = elements.begin(); I != elements.end(); I++) { if (!I->valid())continue; @@ -415,14 +429,14 @@ void CCF_Shape::_BoxQuery(const Fbox& B, const Fmatrix& M, u32 flags) */ void CCF_Shape::add_sphere(Fsphere& S) { - shapes.push_back(shape_def()); + shapes.emplace_back(); shapes.back().type = 0; shapes.back().data.sphere.set(S); } void CCF_Shape::add_box(Fmatrix& B) { - shapes.push_back(shape_def()); + shapes.emplace_back(); shapes.back().type = 1; shapes.back().data.box.set(B); shapes.back().data.ibox.invert(B); diff --git a/src/xrEngine/xr_collide_form.h b/src/xrEngine/xr_collide_form.h index 052a8f06a5..d934040225 100644 --- a/src/xrEngine/xr_collide_form.h +++ b/src/xrEngine/xr_collide_form.h @@ -157,6 +157,8 @@ class ENGINE_API CCF_Skeleton : public ICollisionForm u32 dwFrame; // The model itself u32 dwFrameTL; // Top level + xrSRWLock build_lock; + void BuildState(); void BuildTopLevel(); public: diff --git a/src/xrEngine/xr_efflensflare.cpp b/src/xrEngine/xr_efflensflare.cpp index 29b7b1715f..4231284119 100644 --- a/src/xrEngine/xr_efflensflare.cpp +++ b/src/xrEngine/xr_efflensflare.cpp @@ -269,6 +269,7 @@ static Fvector2 RayDeltas[CLensFlare::MAX_RAYS] = void CLensFlare::OnFrame(shared_str id) { + PROF_EVENT("CLensFlare::OnFrame"); if (dwFrame == Device.dwFrame)return; #ifndef _EDITOR if (!g_pGameLevel) return; diff --git a/src/xrEngine/xr_ioc_cmd.cpp b/src/xrEngine/xr_ioc_cmd.cpp index 9b939fa1cc..1f256fb95c 100644 --- a/src/xrEngine/xr_ioc_cmd.cpp +++ b/src/xrEngine/xr_ioc_cmd.cpp @@ -33,6 +33,10 @@ xr_token vid_bpp_token[] = {"32", 32}, {0, 0} }; + +extern float r_wallmarks_ssa_k; +extern BOOL r_wallmarks_static; +extern BOOL r_wallmarks_dynamic; //----------------------------------------------------------------------- void IConsole_Command::add_to_LRU(shared_str const& arg) @@ -775,7 +779,7 @@ class CCC_r2 : public CCC_Token { //fill_render_mode_list (); tokens = vid_quality_token; - if (!strstr(Core.Params, "-r2")) + if (!Core.ParamsData.test(ECoreParams::r2)) { inherited::Save(F); } @@ -1038,6 +1042,8 @@ void CCC_Register() CMD1(CCC_LoadCFG, "cfg_load"); CMD1(CCC_DumpCVars, "dump_cvar"); + CMD3(CCC_Mask, "mt_particles", &psDeviceFlags, mtParticles); + #ifdef DEBUG CMD1(CCC_MotionsStat, "stat_motions"); CMD1(CCC_TexturesStat, "stat_textures"); @@ -1049,7 +1055,6 @@ void CCC_Register() #endif // DEBUG_MEMORY_MANAGER #ifdef DEBUG - CMD3(CCC_Mask, "mt_particles", &psDeviceFlags, mtParticles); CMD1(CCC_DbgStrCheck, "dbg_str_check"); CMD1(CCC_DbgStrDump, "dbg_str_dump"); @@ -1074,6 +1079,8 @@ void CCC_Register() CMD3(CCC_Mask, "rs_render_dynamics", &psDeviceFlags, rsDrawDynamic); #endif + CMD3(CCC_Mask, "rs_render_portals", &psDeviceFlags, rsDrawPortals); + // bone damage modifier CMD4(CCC_Float, "g_hit_pwr_modif", &hit_modifier, .5f, 3.f); @@ -1084,6 +1091,10 @@ void CCC_Register() // Render device states CMD4(CCC_Integer, "r__supersample", &ps_r__Supersample, 1, 4); + CMD4(CCC_Integer, "r_wallmarks_static", &r_wallmarks_static, 0, 1); + CMD4(CCC_Integer, "r_wallmarks_dynamic", &r_wallmarks_dynamic, 0, 1); + CMD4(CCC_Float, "r_wallmarks_ssa_k", &r_wallmarks_ssa_k, 0.25f, 10.f); + CMD4(CCC_Float, "r2_sunshafts_min", &ps_r2_sun_shafts_min, 0.0, 0.5); CMD4(CCC_Float, "r2_sunshafts_value", &ps_r2_sun_shafts_value, 0.5, 2.0); @@ -1228,7 +1239,7 @@ void CCC_Register() CMD2(CCC_Color, "g_crosshair_color", &g_crosshair_color); CMD4(CCC_Float, "mouse_sens_aim", &g_AimLookFactor, 0.01f, 5.0f); - if (strstr(Core.Params, "-dbgdev")) + if (Core.ParamsData.test(ECoreParams::dbgdev)) CMD4(CCC_Float, "g_freelook_z_offset_factor", &g_freelook_z_offset, -3.f, 3.f); CMD4(CCC_Float, "g_ironsights_zoom_factor", &g_ironsights_factor, 1.f, 2.f); diff --git a/src/xrEngine/xr_ioc_cmd.h b/src/xrEngine/xr_ioc_cmd.h index 897818cf3a..4befbdd7dd 100644 --- a/src/xrEngine/xr_ioc_cmd.h +++ b/src/xrEngine/xr_ioc_cmd.h @@ -124,6 +124,47 @@ class ENGINE_API CCC_Mask : public IConsole_Command } }; +class ENGINE_API CCC_Mask64 : public IConsole_Command +{ +protected: + Flags64* value; + u64 mask; +public: + CCC_Mask64(LPCSTR N, Flags64* V, u64 M) : + IConsole_Command(N), + value(V), + mask(M) + { + }; + const BOOL GetValue() const { return value->test(mask); } + + virtual void Execute(LPCSTR args) + { + if (EQ(args, "on")) value->set(mask, TRUE); + else if (EQ(args, "off")) value->set(mask, FALSE); + else if (EQ(args, "1")) value->set(mask, TRUE); + else if (EQ(args, "0")) value->set(mask, FALSE); + else InvalidSyntax(); + } + + virtual void Status(TStatus& S) + { + xr_strcpy(S, value->test(mask) ? "on" : "off"); + } + + virtual void Info(TInfo& I) + { + xr_strcpy(I, "'on/off' or '1/0'"); + } + + virtual void fill_tips(vecTips& tips, u32 mode) + { + TStatus str; + xr_sprintf(str, sizeof(str), "%s (current) [on/off]", value->test(mask) ? "on" : "off"); + tips.push_back(str); + } +}; + class ENGINE_API CCC_ToggleMask : public IConsole_Command { protected: diff --git a/src/xrEngine/xr_object.cpp b/src/xrEngine/xr_object.cpp index e8f6286e32..859c369ddc 100644 --- a/src/xrEngine/xr_object.cpp +++ b/src/xrEngine/xr_object.cpp @@ -93,7 +93,7 @@ void CObject::cNameVisual_set(shared_str N) #ifdef OPTIMIZE_CALCULATE_BONES if (new_k) - new_k->spatialParent = this; + new_k->spatialParent = SpatialComponent; if (old_k) old_k->spatialParent = nullptr; @@ -105,6 +105,7 @@ void CObject::cNameVisual_set(shared_str N) new_k->SetUpdateCallbackParam(old_k->GetUpdateCallbackParam()); } + OnChangeVisual(); ::Render->model_Delete(old_v); } else @@ -119,10 +120,13 @@ void CObject::cNameVisual_set(shared_str N) } #endif - ::Render->model_Delete(renderable.visual); - NameVisual = 0; + // The children classes will see that renderable.visual is gone, but actual deletion will happen after the callback to prevent nasty stuff + IRenderVisual* old_v = renderable.visual; + renderable.visual = nullptr; + NameVisual = 0; + OnChangeVisual(); + ::Render->model_Delete(old_v); } - OnChangeVisual(); } // flagging @@ -142,30 +146,33 @@ void CObject::processing_deactivate() void CObject::setEnabled(BOOL _enabled) { + if (Props.bDestroy || !SpatialComponent.get()) return; if (_enabled) { Props.bEnabled = 1; - if (collidable.model) spatial.type |= STYPE_COLLIDEABLE; + if (collidable.model) + SpatialComponent->spatial.type |= STYPE_COLLIDEABLE; } else { Props.bEnabled = 0; - spatial.type &= ~STYPE_COLLIDEABLE; + SpatialComponent->spatial.type &= ~STYPE_COLLIDEABLE; } } void CObject::setVisible(BOOL _visible) { + if (Props.bDestroy) return; if (_visible) - { - // Parent should control object visibility itself (??????) + { // Parent should control object visibility itself (??????) Props.bVisible = 1; - if (renderable.visual) spatial.type |= STYPE_RENDERABLE; + if (renderable.visual) + SpatialComponent->spatial.type |= STYPE_RENDERABLE; } else { Props.bVisible = 0; - spatial.type &= ~STYPE_RENDERABLE; + SpatialComponent->spatial.type &= ~STYPE_RENDERABLE; } } @@ -197,8 +204,7 @@ const Fbox& CObject::BoundingBox() const // Purpose : //---------------------------------------------------------------------- CObject::CObject() : - ISpatial(g_SpatialSpace), - dwFrame_AsCrow(u32(-1)) + dwFrame_AsCrow (u32(-1)) { // Transform Props.storage = 0; @@ -270,8 +276,9 @@ BOOL CObject::net_Spawn(CSE_Abstract* data) } } - R_ASSERT(spatial.space); - spatial_register(); + VERIFY(SpatialComponent->spatial.space); + + spatial_register (); if (register_schedule()) shedule_register(); @@ -304,6 +311,7 @@ const float base_spu_epsR = 0.05f; void CObject::spatial_update(float eps_P, float eps_R) { + if (Props.bDestroy) return; // BOOL bUpdate = FALSE; if (PositionStack.empty()) @@ -346,15 +354,17 @@ void CObject::spatial_update(float eps_P, float eps_R) } else { - if (spatial.node_ptr) + if (SpatialComponent->spatial.node_ptr) { // Object registered! - if (!fsimilar(Radius(), spatial.sphere.R, eps_R)) spatial_move(); + if (!fsimilar(Radius(), SpatialComponent->spatial.sphere.R,eps_R)) + spatial_move(); else { Fvector C; Center(C); - if (!C.similar(spatial.sphere.P, eps_P)) spatial_move(); + if (!C.similar(SpatialComponent->spatial.sphere.P,eps_P)) + spatial_move(); } // else nothing to do :_) } @@ -371,9 +381,11 @@ void CObject::UpdateCL() if (Device.dwFrame == dbg_update_cl) Debug.fatal(DEBUG_INFO, "'UpdateCL' called twice per frame for %s", *cName()); dbg_update_cl = Device.dwFrame; - if (Parent && spatial.node_ptr) Debug.fatal(DEBUG_INFO, "Object %s has parent but is still registered inside spatial DB", *cName()); + if (Parent && SpatialComponent->spatial.node_ptr) + Debug.fatal (DEBUG_INFO,"Object %s has parent but is still registered inside spatial DB",*cName()); - if ((0 == collidable.model) && (spatial.type&STYPE_COLLIDEABLE)) Debug.fatal(DEBUG_INFO, "Object %s registered as 'collidable' but has no collidable model", *cName()); + if ((0==collidable.model)&&(SpatialComponent->spatial.type&STYPE_COLLIDEABLE)) + Debug.fatal (DEBUG_INFO,"Object %s registered as 'collidable' but has no collidable model",*cName()); #endif spatial_update(base_spu_epsP * 5, base_spu_epsR * 5); @@ -412,21 +424,22 @@ void CObject::shedule_Update(u32 T) void CObject::spatial_register() { - Center(spatial.sphere.P); - spatial.sphere.R = Radius(); - ISpatial::spatial_register(); + Center(SpatialComponent->spatial.sphere.P); + SpatialComponent->spatial.sphere.R = Radius(); + ISpatialOwner::spatial_register(); } void CObject::spatial_unregister() { - ISpatial::spatial_unregister(); + ISpatialOwner::spatial_unregister(); } void CObject::spatial_move() { - Center(spatial.sphere.P); - spatial.sphere.R = Radius(); - ISpatial::spatial_move(); + if (Props.bDestroy) return; + Center(SpatialComponent->spatial.sphere.P); + SpatialComponent->spatial.sphere.R = Radius(); + ISpatialOwner::spatial_move(); } CObject::SavedPosition CObject::ps_Element(u32 ID) const @@ -435,7 +448,7 @@ CObject::SavedPosition CObject::ps_Element(u32 ID) const return PositionStack[ID]; } -void CObject::renderable_Render() +void CObject::renderable_Render(IDSGraphManager* DM) { MakeMeCrow(); } @@ -484,6 +497,9 @@ void CObject::setDestroy(BOOL _destroy) if (_destroy == (BOOL)Props.bDestroy) return; + if (_destroy) + setVisible(false); + Props.bDestroy = _destroy ? 1 : 0; if (_destroy) { @@ -534,3 +550,9 @@ Fvector CObject::get_last_local_point_on_mesh(Fvector const& local_point, u16 co return result; } + +void CObject::OnChangeVisual() +{ + if (g_pGameLevel) + g_pGameLevel->Objects.relcase_visual_invoke(this); +} diff --git a/src/xrEngine/xr_object.h b/src/xrEngine/xr_object.h index 7c2b8c8994..4d85cfbb9b 100644 --- a/src/xrEngine/xr_object.h +++ b/src/xrEngine/xr_object.h @@ -15,6 +15,58 @@ class ENGINE_API IRender_ObjectSpecific; class ENGINE_API CCustomHUD; class NET_Packet; class CSE_Abstract; +class CGameObject; +class CActor; +class CInventoryItem; +class CEntity; +class CEntityAlive; +class CInventoryOwner; +class CMissile; +class CPhysicsShellHolder; +class CWeapon; +class CWeaponBM16; +class CWeaponRPG7; +class CWeaponRG6; +class CWeaponMagazined; +class CWeaponMagazinedWGrenade; +class CWeaponKnife; +class CWeaponBinoculars; +class CHudItem; +class CWeaponAmmo; +class CTorch; +class CCustomDetector; +class CCustomDevice; +class CArtefact; +class CCustomOutfit; +class CHelmet; +class CAI_Stalker; +class CBolt; +class CPda; +class CInventoryBox; +class CCustomZone; +class CSpaceRestrictor; +class CSpectator; +class CSilencer; +class CScope; +class CGrenadeLauncher; +class CAttachmentOwner; +class CProjector; +class CLevelChanger; +class CPhysicItem; +class CEatableItem; +class CScriptZone; +class CHelicopter; +class CHangingLamp; +class CHolderCustom; +class CCar; +class CBaseMonster; +class CGrenade; +class CCustomMonster; +class CPhraseDialogManager; +class CBackpack; +class CClimableObject; +class CPhysicObject; +class CTeamBaseZone; //----------------------------------------------------------------------------------------------------------- #define CROW_RADIUS (30.f) @@ -27,7 +79,6 @@ xr_pure_interface IObjectPhysicsCollision; #pragma pack(push,4) class ENGINE_API CObject : public DLL_Pure, - public ISpatial, public ISheduled, public IRenderable, public ICollidable @@ -66,6 +117,8 @@ class ENGINE_API CObject : shared_str NameObject; shared_str NameSection; shared_str NameVisual; + + bool m_ForceDestroy; protected: // Parentness CObject* Parent; @@ -131,7 +184,7 @@ class ENGINE_API CObject : virtual float Radius() const; virtual const Fbox& BoundingBox() const; - IC IRender_Sector* Sector() { return H_Root()->spatial.sector; } + IC IRender_Sector* Sector() { return H_Root()->SpatialComponent->spatial.sector; } IC IRender_ObjectSpecific* ROS() { return renderable_ROS(); } virtual BOOL renderable_ShadowGenerate() { return TRUE; } virtual BOOL renderable_ShadowReceive() { return TRUE; } @@ -139,16 +192,67 @@ class ENGINE_API CObject : // Accessors and converters ICF IRenderVisual* Visual() const { return renderable.visual; } ICF ICollisionForm* CFORM() const { return collidable.model; } - virtual CObject* dcast_CObject() { return this; } - virtual IRenderable* dcast_Renderable() { return this; } + virtual CObject* dcast_CObject() override { return this; } + virtual IRenderable* dcast_Renderable() override { return this; } + virtual Feel::Sound* dcast_FeelSound() override { return nullptr; } - virtual void OnChangeVisual() - { - } + virtual void OnChangeVisual(); virtual IPhysicsShell* physics_shell() { return 0; } virtual const IObjectPhysicsCollision* physics_collision() { return 0; } + virtual CGameObject* cast_game_object() { return nullptr; } + virtual CActor* cast_actor() { return nullptr; } + virtual CInventoryOwner* cast_inventory_owner() { return nullptr; } + virtual CInventoryItem* cast_inventory_item() { return nullptr; } + virtual CEntity* cast_entity() { return nullptr; } + virtual CEntityAlive* cast_entity_alive() { return nullptr; } + virtual CMissile* cast_missile() { return nullptr; } + virtual CPhysicsShellHolder* cast_physics_shell_holder() { return nullptr; } + virtual CWeapon* cast_weapon() { return nullptr; } + virtual CHudItem* cast_hud_item() { return nullptr; } + virtual CWeaponRPG7* cast_weapon_rpg7() { return nullptr; } + virtual CWeaponRG6* cast_weapon_rg6() { return nullptr; } + virtual CTorch* cast_torch() { return nullptr; } + virtual CCustomDetector* cast_custom_detector() { return nullptr; } + virtual CCustomDevice* cast_custom_device() { return nullptr; } + virtual CWeaponBinoculars* cast_weapon_binoculars() { return nullptr; } + virtual CWeaponKnife* cast_weapon_knife() { return nullptr; } + virtual CWeaponMagazined* cast_weapon_magazined() { return nullptr; } + virtual CWeaponMagazinedWGrenade* cast_weapon_magazined_w_grenade() { return nullptr; } + virtual CWeaponBM16* cast_weapon_bm16() { return nullptr; } + virtual CArtefact* cast_artefact() { return nullptr; } + virtual CCustomOutfit* cast_outfit() { return nullptr; } + virtual CHelmet* cast_helmet() { return nullptr; } + virtual CWeaponAmmo* cast_weapon_ammo() { return nullptr; } + virtual CAI_Stalker* cast_stalker() { return nullptr; } + virtual CBolt* cast_bolt() { return nullptr; } + virtual CPda* cast_pda() { return nullptr; } + virtual CInventoryBox* cast_inventory_box() { return nullptr; } + virtual CCustomZone* cast_custom_zone() { return nullptr; } + virtual CSpaceRestrictor* cast_restrictor() { return nullptr; } + virtual CSpectator* cast_spectator() { return nullptr; } + virtual CSilencer* cast_addon_silencer() { return nullptr; } + virtual CScope* cast_addon_scope() { return nullptr; } + virtual CGrenadeLauncher* cast_addon_grenade_launcher() { return nullptr; } + virtual CAttachmentOwner* cast_attachment_owner() { return nullptr; } + virtual CProjector* cast_projector() { return nullptr; } + virtual CLevelChanger* cast_level_changer() { return nullptr; } + virtual CPhysicItem* cast_physics_item() { return nullptr; } + virtual CEatableItem* cast_eatable_item() { return nullptr; } + virtual CScriptZone* cast_script_zone() { return nullptr; } + virtual CHelicopter* cast_helicopter() { return nullptr; } + virtual CHangingLamp* cast_hanging_lamp() { return nullptr; } + virtual CHolderCustom* cast_holder_custom() { return nullptr; } + virtual CCar* cast_car() { return nullptr; } + virtual CBaseMonster* cast_base_monster() { return nullptr; } + virtual CGrenade* cast_grenade() { return nullptr; } + virtual CCustomMonster* cast_custom_monster() { return nullptr; } + virtual CPhraseDialogManager* cast_phrase_dialog_manager() { return nullptr; } + virtual CBackpack* cast_backpack() { return nullptr; } + virtual CClimableObject* cast_climable_object() { return nullptr; } + virtual CPhysicObject* cast_physics_object() { return nullptr; } + virtual CTeamBaseZone* cast_team_base_zone() { return nullptr; } // Name management ICF shared_str cName() const { return NameObject; } void cName_set(shared_str N); @@ -177,6 +281,9 @@ class ENGINE_API CObject : ICF void setReady(BOOL _ready) { Props.net_Ready = _ready ? 1 : 0; } ICF BOOL getReady() const { return Props.net_Ready; } + ICF bool getForceDestroy() { return m_ForceDestroy; } + ICF void setForceDestroy() { m_ForceDestroy = true; } + //--------------------------------------------------------------------- CObject(); virtual ~CObject(); @@ -185,7 +292,7 @@ class ENGINE_API CObject : // Update virtual void shedule_Update(u32 dt); // Called by sheduler - virtual void renderable_Render(); + virtual void renderable_Render(IDSGraphManager* DM); // Called by renderer virtual void UpdateCL(); // Called each frame, so no need for dt virtual BOOL net_Spawn(CSE_Abstract* data); @@ -217,7 +324,7 @@ class ENGINE_API CObject : }; // HUD - virtual void OnHUDDraw(CCustomHUD* hud) + virtual void OnHUDDraw(CCustomHUD* hud, IDSGraphManager* DM) { }; diff --git a/src/xrEngine/xr_object_list.cpp b/src/xrEngine/xr_object_list.cpp index 78149d4b70..e8faa73e31 100644 --- a/src/xrEngine/xr_object_list.cpp +++ b/src/xrEngine/xr_object_list.cpp @@ -34,8 +34,13 @@ CObjectList::~CObjectList() { R_ASSERT(objects_active.empty()); R_ASSERT(objects_sleeping.empty()); - R_ASSERT(destroy_queue.empty()); + ProcessDestroyQueueImpl(force_destroy_queue); + ProcessDestroyQueueImpl(destroy_queue); + R_ASSERT(destroy_queue.empty()); + R_ASSERT(force_destroy_queue.empty()); //. R_ASSERT ( map_NETID.empty() ); + + ClearProcessDestroyQueueFromDevice(); } CObject* CObjectList::FindObjectByName(shared_str name) @@ -130,53 +135,53 @@ void CObjectList::SingleUpdate(CObject* O) VERIFY3(O->dbg_update_cl == Device.dwFrame, "Broken sequence of calls to 'UpdateCL'", *O->cName()); #endif #if 0//ndef DEBUG - __try - { -#endif - if (O->H_Parent() && (O->H_Parent()->getDestroy() || O->H_Root()->getDestroy())) + __try { - // Push to destroy-queue if it isn't here already - Msg("! ERROR: incorrect destroy sequence for object[%d:%s], section[%s], parent[%d:%s]", O->ID(), *O->cName(), - *O->cNameSect(), O->H_Parent()->ID(), *O->H_Parent()->cName()); - } +#endif + if (O->H_Parent() && (O->H_Parent()->getDestroy() || O->H_Root()->getDestroy())) + { + // Push to destroy-queue if it isn't here already + Msg("! ERROR: incorrect destroy sequence for object[%d:%s], section[%s], parent[%d:%s]", O->ID(), *O->cName(), + *O->cNameSect(), O->H_Parent()->ID(), *O->H_Parent()->cName()); + } #if 0//ndef DEBUG - } - __except (EXCEPTION_EXECUTE_HANDLER) - { - CObject* parent_obj = O->H_Parent(); - CObject* root_obj = O->H_Root(); - Msg ("! ERROR: going to crush: [%d:%s], section[%s], parent_obj_addr[0x%08x], root_obj_addr[0x%08x]",O->ID(),*O->cName(),*O->cNameSect(), *((u32*)&parent_obj), *((u32*)&root_obj)); - if (parent_obj) - { - __try - { - Msg("! Parent object: [%d:%s], section[%s]", - parent_obj->ID(), - parent_obj->cName().c_str(), - parent_obj->cNameSect().c_str()); + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + CObject* parent_obj = O->H_Parent(); + CObject* root_obj = O->H_Root(); + Msg("! ERROR: going to crush: [%d:%s], section[%s], parent_obj_addr[0x%08x], root_obj_addr[0x%08x]", O->ID(), *O->cName(), *O->cNameSect(), *((u32*)&parent_obj), *((u32*)&root_obj)); + if (parent_obj) + { + __try + { + Msg("! Parent object: [%d:%s], section[%s]", + parent_obj->ID(), + parent_obj->cName().c_str(), + parent_obj->cNameSect().c_str()); - } - __except (EXCEPTION_EXECUTE_HANDLER) - { - Msg("! Failed to get parent object info."); - } - } - if (root_obj) - { - __try - { - Msg("! Root object: [%d:%s], section[%s]", - root_obj->ID(), - root_obj->cName().c_str(), - root_obj->cNameSect().c_str()); - } - __except (EXCEPTION_EXECUTE_HANDLER) - { - Msg("! Failed to get root object info."); - } - } - R_ASSERT(false); - } //end of __except + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + Msg("! Failed to get parent object info."); + } + } + if (root_obj) + { + __try + { + Msg("! Root object: [%d:%s], section[%s]", + root_obj->ID(), + root_obj->cName().c_str(), + root_obj->cNameSect().c_str()); + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + Msg("! Failed to get root object info."); + } + } + R_ASSERT(false); + } //end of __except #endif #ifdef DEBUG @@ -195,8 +200,10 @@ void CObjectList::clear_crow_vec(Objects& o) o.clear_not_free(); } +extern BOOL mt_Scheduler; void CObjectList::Update(bool bForce) { + PROF_EVENT("CObjectList::Update"); if (!Device.Paused() || bForce) { // Clients @@ -204,113 +211,113 @@ void CObjectList::Update(bool bForce) { // Select Crow-Mode Device.Statistic->UpdateClient_updated = 0; + Objects workload; + workload.reserve(objects_active.capacity()); - Objects& crows = m_crows[0]; - - { - Objects& crows1 = m_crows[1]; - crows.insert(crows.end(), crows1.begin(), crows1.end()); - crows1.clear_not_free(); - } - -#if 0 - std::sort (crows.begin(), crows.end()); - crows.erase ( - std::unique( - crows.begin(), - crows.end() - ), - crows.end() - ); -#else -# ifdef DEBUG - std::sort(crows.begin(), crows.end()); - VERIFY( - std::unique( - crows.begin(), - crows.end() - ) == crows.end() - ); -# endif // ifdef DEBUG -#endif - - Device.Statistic->UpdateClient_crows = crows.size(); - Objects* workload = 0; - if (!psDeviceFlags.test(rsDisableObjectsAsCrows)) - workload = &crows; - else { - workload = &objects_active; - clear_crow_vec(crows); + PROF_EVENT("CObjectList::Update/Crows"); + Objects& crows = m_crows[0]; + { + Objects& crows1 = m_crows[1]; + crows.insert(crows.end(), crows1.begin(), crows1.end()); + crows1.clear_not_free(); + } + + Device.Statistic->UpdateClient_crows = crows.size(); + Objects* required_workload; + if (!psDeviceFlags.test(rsDisableObjectsAsCrows)) + required_workload = &crows; + else + { + required_workload = &objects_active; + clear_crow_vec(crows); + } + + Device.Statistic->UpdateClient.Begin(); + Device.Statistic->UpdateClient_active = objects_active.size(); + Device.Statistic->UpdateClient_total = objects_active.size() + objects_sleeping.size(); + + { + PROF_EVENT("CObjectList::Update/CopyWorkload"); + workload = *required_workload; + } + + crows.clear_not_free(); + + for (const auto obj : workload) + { + obj->IAmNotACrowAnyMore(); + obj->dwFrame_AsCrow = u32(-1); + } } - Device.Statistic->UpdateClient.Begin(); - Device.Statistic->UpdateClient_active = objects_active.size(); - Device.Statistic->UpdateClient_total = objects_active.size() + objects_sleeping.size(); - - u32 const objects_count = workload->size(); - CObject** objects = (CObject**)_alloca(objects_count * sizeof(CObject*)); - std::copy(workload->begin(), workload->end(), objects); - - crows.clear_not_free(); - - CObject** b = objects; - CObject** e = objects + objects_count; - for (CObject** i = b; i != e; ++i) { - (*i)->IAmNotACrowAnyMore(); - (*i)->dwFrame_AsCrow = u32(-1); + PROF_EVENT("CObjectList::Update/SingleUpdate"); + for (const auto obj : workload) + { + SingleUpdate(obj); + } } - for (CObject** i = b; i != e; ++i) - SingleUpdate(*i); - Device.Statistic->UpdateClient.End(); } } // Destroy - if (!destroy_queue.empty()) - { - // Info - for (Objects::iterator oit = objects_active.begin(); oit != objects_active.end(); oit++) - for (int it = destroy_queue.size() - 1; it >= 0; it--) - { - (*oit)->net_Relcase(destroy_queue[it]); - } - for (Objects::iterator oit = objects_sleeping.begin(); oit != objects_sleeping.end(); oit++) - for (int it = destroy_queue.size() - 1; it >= 0; it--) (*oit)->net_Relcase(destroy_queue[it]); + ProcessDestroyQueueImpl(force_destroy_queue); + if (mt_Scheduler) + { + xrCriticalSectionGuard guard(&Device.seqParallelBeforRenderCS); + Device.seqParallelBeforRender.push_back(xr_make_delegate(this, &CObjectList::ProcessDestroyQueue)); + } + else + ProcessDestroyQueue(); +} - for (int it = destroy_queue.size() - 1; it >= 0; it--) Sound->object_relcase(destroy_queue[it]); +void CObjectList::ProcessDestroyQueue() +{ + ProcessDestroyQueueImpl(destroy_queue); +} - RELCASE_CALLBACK_VEC::iterator It = m_relcase_callbacks.begin(); - RELCASE_CALLBACK_VEC::iterator Ite = m_relcase_callbacks.end(); - for (; It != Ite; ++It) - { - VERIFY(*(*It).m_ID == (It - m_relcase_callbacks.begin())); - Objects::iterator dIt = destroy_queue.begin(); - Objects::iterator dIte = destroy_queue.end(); - for (; dIt != dIte; ++dIt) - { - (*It).m_Callback(*dIt); - g_hud->net_Relcase(*dIt); - } - } +void CObjectList::ProcessDestroyQueueImpl(Objects& queue) +{ + if (!queue.empty()) + { + PROF_EVENT("CObjectList::Update/destroy_queue"); + for (int it = queue.size() - 1; it >= 0; it--) + { + auto obj = queue[it]; + for (const auto oit : objects_active) + oit->net_Relcase(obj); + + for (const auto oit : objects_sleeping) + oit->net_Relcase(obj); + + if (Sound) + Sound->object_relcase(obj); + + auto It = m_relcase_callbacks.begin(); + auto Ite = m_relcase_callbacks.end(); + for (; It != Ite; ++It) + { + VERIFY(*(*It).m_ID == (It - m_relcase_callbacks.begin())); + (*It).m_Callback(obj); + } + + if (g_hud) + g_hud->net_Relcase(obj); - // Destroy - for (int it = destroy_queue.size() - 1; it >= 0; it--) - { - CObject* O = destroy_queue[it]; - // Msg ("Object [%x]", O); #ifdef DEBUG if (debug_destroy) - Msg("Destroying object[%x][%x] [%d][%s] frame[%d]", fast_dynamic_cast(O), O, O->ID(), *O->cName(), Device.dwFrame); + Msg("Destroying object[%x][%x] [%d][%s] frame[%d]", fast_dynamic_cast(obj), obj, obj->ID(), *obj->cName(), Device.dwFrame); #endif // DEBUG - O->net_Destroy(); - Destroy(O); - } - destroy_queue.clear(); - } + + obj->net_Destroy(); + Destroy(obj); + } + + queue.clear(); + } } void CObjectList::net_Register(CObject* O) @@ -420,11 +427,28 @@ return (it==map_NETID.end())?0:it->second; */ void CObjectList::Load() { - R_ASSERT(/*map_NETID.empty() &&*/ objects_active.empty() && destroy_queue.empty() && objects_sleeping.empty()); + R_ASSERT(/*map_NETID.empty() &&*/ objects_active.empty() && force_destroy_queue.empty() && destroy_queue.empty() && objects_sleeping.empty()); +} + +void CObjectList::ClearProcessDestroyQueueFromDevice() +{ + auto Callback = xr_make_delegate(this, &CObjectList::ProcessDestroyQueue); + xrCriticalSectionGuard guard(&Device.seqParallelBeforRenderCS); + Device.seqParallelBeforRender.erase( + std::remove( + Device.seqParallelBeforRender.begin(), + Device.seqParallelBeforRender.end(), + Callback + ), Device.seqParallelBeforRender.end() + ); } void CObjectList::Unload() { + ClearProcessDestroyQueueFromDevice(); + ProcessDestroyQueueImpl(force_destroy_queue); + ProcessDestroyQueueImpl(destroy_queue); + if (objects_sleeping.size() || objects_active.size()) Msg("! objects-leaked: %d", objects_sleeping.size() + objects_active.size()); @@ -455,13 +479,20 @@ void CObjectList::Unload() O->net_Destroy(); Destroy(O); } + + // Clear the destroy_queues from dangling pointers + force_destroy_queue.clear(); + destroy_queue.clear(); } CObject* CObjectList::Create(LPCSTR name) { CObject* O = g_pGamePersistent->ObjectPool.create(name); // Msg("CObjectList::Create [%x]%s", O, name); - objects_sleeping.push_back(O); + + if (O) + objects_sleeping.push_back(O); + return O; } @@ -470,36 +501,18 @@ void CObjectList::Destroy(CObject* O) if (0 == O) return; net_Unregister(O); - if (!Device.Paused()) - { - if (!m_crows[1].empty()) - { - Msg("assertion !m_crows[1].empty() failed: %d", m_crows[1].size()); - - Objects::const_iterator i = m_crows[1].begin(); - Objects::const_iterator const e = m_crows[1].end(); - for (u32 j = 0; i != e; ++i, ++j) - Msg("%d %s", j, (*i)->cName().c_str()); - VERIFY(Device.Paused() || m_crows[1].empty()); - m_crows[1].clear_not_free(); - } - } - else - { - Objects& crows = m_crows[1]; - Objects::iterator const i = std::find(crows.begin(), crows.end(), O); - if (i != crows.end()) - { - crows.erase(i); - VERIFY(std::find(crows.begin(), crows.end(), O) == crows.end()); - } - } + Objects& crows1 = m_crows[1]; + Objects::iterator _i1 = std::find(crows1.begin(), crows1.end(), O); + if (_i1 != crows1.end()) + { + crows1.erase_fast(_i1); + } Objects& crows = m_crows[0]; Objects::iterator _i0 = std::find(crows.begin(), crows.end(), O); if (_i0 != crows.end()) { - crows.erase(_i0); + crows.erase_fast(_i0); VERIFY(std::find(crows.begin(), crows.end(), O) == crows.end()); } @@ -552,6 +565,31 @@ void CObjectList::relcase_unregister(int* ID) m_relcase_callbacks.pop_back(); } +void CObjectList::relcase_visual_register(RELCASE_CALLBACK cb, int* ID) +{ + *ID = m_relcase_visual_callbacks.size(); + m_relcase_visual_callbacks.push_back(SRelcasePair(ID, cb)); +} + +void CObjectList::relcase_visual_unregister(int* ID) +{ + VERIFY(m_relcase_visual_callbacks[*ID].m_ID == ID); + m_relcase_visual_callbacks[*ID] = m_relcase_visual_callbacks.back(); + *m_relcase_visual_callbacks.back().m_ID = *ID; + m_relcase_visual_callbacks.pop_back(); +} + +void CObjectList::relcase_visual_invoke(CObject* obj) +{ + auto It = m_relcase_visual_callbacks.begin(); + auto Ite = m_relcase_visual_callbacks.end(); + for (; It != Ite; ++It) + { + VERIFY(*(*It).m_ID == (It - m_relcase_visual_callbacks.begin())); + (*It).m_Callback(obj); + } +} + void CObjectList::dump_list(Objects& v, LPCSTR reason) { Objects::iterator it = v.begin(); @@ -570,7 +608,8 @@ void CObjectList::dump_list(Objects& v, LPCSTR reason) bool CObjectList::dump_all_objects() { - dump_list(destroy_queue, "destroy_queue"); + dump_list(force_destroy_queue, "force_destroy_queue"); + dump_list(destroy_queue, "destroy_queue"); dump_list(objects_active, "objects_active"); dump_list(objects_sleeping, "objects_sleeping"); dump_list(m_crows[0], "m_crows[0]"); @@ -583,7 +622,11 @@ void CObjectList::register_object_to_destroy(CObject* object_to_destroy) #ifdef DEBUG VERIFY(!registered_object_to_destroy(object_to_destroy)); #endif - destroy_queue.push_back(object_to_destroy); + + if (object_to_destroy->getForceDestroy()) + force_destroy_queue.push_back(object_to_destroy); + else + destroy_queue.push_back(object_to_destroy); Objects::iterator it = objects_active.begin(); Objects::iterator it_e = objects_active.end(); diff --git a/src/xrEngine/xr_object_list.h b/src/xrEngine/xr_object_list.h index 15e39a7da6..b8a7ee71ff 100644 --- a/src/xrEngine/xr_object_list.h +++ b/src/xrEngine/xr_object_list.h @@ -16,6 +16,7 @@ class ENGINE_API CObjectList typedef xr_vector Objects; private: + Objects force_destroy_queue; Objects destroy_queue; Objects objects_active; Objects objects_sleeping; @@ -23,7 +24,7 @@ class ENGINE_API CObjectList u32 m_owner_thread_id; public: - typedef fastdelegate::FastDelegate1 RELCASE_CALLBACK; + typedef xr_delegate RELCASE_CALLBACK; struct SRelcasePair { @@ -43,6 +44,11 @@ class ENGINE_API CObjectList void relcase_register(RELCASE_CALLBACK, int*); void relcase_unregister(int*); + RELCASE_CALLBACK_VEC m_relcase_visual_callbacks; + void relcase_visual_register(RELCASE_CALLBACK, int*); + void relcase_visual_unregister(int*); + void relcase_visual_invoke(CObject* obj); + public: // methods CObjectList(); @@ -60,6 +66,9 @@ class ENGINE_API CObjectList void SingleUpdate(CObject* O); void Update(bool bForce); + void ProcessDestroyQueue(); + void ProcessDestroyQueueImpl(Objects& queue); + void ClearProcessDestroyQueueFromDevice(); void net_Register(CObject* O); void net_Unregister(CObject* O); diff --git a/src/xrGame/AI_PhraseDialogManager.h b/src/xrGame/AI_PhraseDialogManager.h index e747d6d4b2..5698c39e4e 100644 --- a/src/xrGame/AI_PhraseDialogManager.h +++ b/src/xrGame/AI_PhraseDialogManager.h @@ -27,6 +27,9 @@ class CAI_PhraseDialogManager : public CPhraseDialogManager virtual void SetDefaultStartDialog(shared_str phrase_dialog); virtual shared_str GetStartDialog() { return m_sStartDialog; } virtual void RestoreDefaultStartDialog(); + + virtual CPhraseDialogManager* cast_phrase_dialog_manager() { return this; } + virtual CAI_PhraseDialogManager* cast_ai_phrase_dialog_manager() { return this; } protected: //диалог, если не NULL, то его персонаж запустит //при встрече с актером diff --git a/src/xrGame/Actor.cpp b/src/xrGame/Actor.cpp index 41791b0f2b..da8e3dc311 100644 --- a/src/xrGame/Actor.cpp +++ b/src/xrGame/Actor.cpp @@ -126,7 +126,7 @@ CActor::CActor() : CEntityAlive(), current_ik_cam_shift(0) //Alundaio -psp always /* - if (strstr(Core.Params, "-psp")) + if (Core.ParamsData.test(ECoreParams::psp)) psActorFlags.set(AF_PSP, TRUE); else psActorFlags.set(AF_PSP, FALSE); @@ -154,7 +154,7 @@ CActor::CActor() : CEntityAlive(), current_ik_cam_shift(0) fCurAVelocity = 0.0f; fFPCamYawMagnitude = 0.0f; //--#SM+#-- fFPCamPitchMagnitude = 0.0f; //--#SM+#-- - // ýôôåêòîðû + // Эффекторы (Effectors) pCamBobbing = 0; cam_freelook = eflDisabled; @@ -192,7 +192,7 @@ CActor::CActor() : CEntityAlive(), current_ik_cam_shift(0) Device.seqRender.Add (this,REG_PRIORITY_LOW); #endif - //ðàçðåøèòü èñïîëüçîâàíèå ïîÿñà â inventory + // Разрешить использование пояса в inventory (Allow use of belt in inventory) inventory().SetBeltUseful(true); m_pPersonWeLookingAt = NULL; @@ -363,12 +363,10 @@ void CActor::Load(LPCSTR section) if (GameID() == eGameIDSingle) OnDifficultyChanged(); ////////////////////////////////////////////////////////////////////////// - ISpatial* self = smart_cast(this); - if (self) - { - self->spatial.type |= STYPE_VISIBLEFORAI; - self->spatial.type &= ~STYPE_REACTTOSOUND; - } + + SpatialComponent->spatial.type |= STYPE_VISIBLEFORAI; + SpatialComponent->spatial.type &= ~STYPE_REACTTOSOUND; + ////////////////////////////////////////////////////////////////////////// // m_PhysicMovementControl: General @@ -496,7 +494,7 @@ void CActor::Load(LPCSTR section) // sheduler shedule.t_min = shedule.t_max = 1; - // íàñòðîéêè äèñïåðñèè ñòðåëüáû + // Настройки дисперсии стрельбы (Dispersion settings for shooting) m_fDispBase = pSettings->r_float(section, "disp_base"); m_fDispBase = deg2rad(m_fDispBase); @@ -585,21 +583,21 @@ void CActor::Hit(SHit* pHDS) if (Device.dwFrame != last_hit_frame && HDS.bone() != BI_NONE) { - // âû÷èñëèòü ïîçèöèþ è íàïðàâëåííîñòü ïàðòèêëà + // вычислить позицию и направленность партикла (Calculate position and direction of particle) Fmatrix pos; CParticlesPlayer::MakeXFORM(this, HDS.bone(), HDS.dir, HDS.p_in_bone_space, pos); - // óñòàíîâèòü particles - CParticlesObject* ps = NULL; + // установить particles (Set particles) + intrusive_ptr ps_ = nullptr; if (eacFirstEye == cam_active && this == Level().CurrentEntity()) - ps = CParticlesObject::Create(invincibility_fire_shield_1st, TRUE); + ps_ = Particles::Details::Create(invincibility_fire_shield_1st,TRUE); else - ps = CParticlesObject::Create(invincibility_fire_shield_3rd, TRUE); + ps_ = Particles::Details::Create(invincibility_fire_shield_3rd,TRUE); - ps->UpdateParent(pos, Fvector().set(0.f, 0.f, 0.f)); - GamePersistent().ps_needtoplay.push_back(ps); + ps_->UpdateParent(pos, Fvector().set(0.f, 0.f, 0.f)); + GamePersistent().ps_needtoplay.push_back(ps_); }; }; @@ -917,7 +915,7 @@ void CActor::Die(CObject* who) }; - ///!!! ÷èñòêà ïîÿñà + ///!!! чистка пояса (Belt cleanup) TIItemContainer& l_blist = inventory().m_belt; while (!l_blist.empty()) inventory().Ruck(l_blist.front()); @@ -1127,6 +1125,7 @@ float CActor::currentFOV() void CActor::UpdateCL() { + PROF_EVENT("CActor UpdateCL"); if (g_Alive() && Level().CurrentViewEntity() == this) { if (CurrentGameUI() && (!CurrentGameUI()->TopInputReceiver() || (CurrentGameUI()->TopInputReceiver() && !CurrentGameUI()->TopInputReceiver()->StopAnyMove())) && !m_holder) @@ -1272,7 +1271,7 @@ void CActor::UpdateCL() if (g_Alive()) CStepManager::update(this == Level().CurrentViewEntity()); - spatial.type |= STYPE_REACTTOSOUND; + SpatialComponent->spatial.type |= STYPE_REACTTOSOUND; if (m_sndShockEffector) { @@ -1772,6 +1771,7 @@ void CActor::set_state_box(u32 mstate) void CActor::shedule_Update(u32 DT) { + PROF_EVENT("CActor shedule_Update"); setSVU(OnServer()); //. UpdateInventoryOwner (DT); @@ -1928,7 +1928,7 @@ void CActor::shedule_Update(u32 DT) inherited::shedule_Update(DT); - //ýôôåêòîð âêëþ÷àåìûé ïðè õîäüáå + // Эффектор, включаемый при ходьбе (Effector enabled while walking) if (!pCamBobbing) { pCamBobbing = xr_new(); @@ -1936,7 +1936,7 @@ void CActor::shedule_Update(u32 DT) } pCamBobbing->SetState(mstate_real, conditions().IsLimping(), IsZoomAimingMode()); - //çâóê òÿæåëîãî äûõàíèÿ ïðè óòàëîñòè è õðîìàíèè + // Звук тяжелого дыхания при усталости и хромании (Heavy breathing sound when tired or limping) if (this == Level().CurrentControlEntity() && !g_dedicated_server) { if (conditions().IsLimping() && g_Alive() && !psActorFlags.test(AF_GODMODE_RT)) @@ -2004,11 +2004,11 @@ void CActor::shedule_Update(u32 DT) m_DangerSnd.stop(); } - //åñëè â ðåæèìå HUD, òî ñàìà ìîäåëü àêòåðà íå ðèñóåòñÿ + // если в режиме HUD, то сама модель актера не рисуется (If in HUD mode, the actor model is not drawn) if (!character_physics_support()->IsRemoved()) setVisible(TRUE); - //÷òî àêòåð âèäèò ïåðåä ñîáîé + // что актер видит перед собой (What the actor sees in front of him) collide::rq_result& RQ = HUD().GetRQ(); @@ -2016,7 +2016,7 @@ void CActor::shedule_Update(u32 DT) { m_pObjectWeLookingAt = smart_cast(RQ.O); - CGameObject* game_object = smart_cast(RQ.O); + CGameObject* game_object = m_pObjectWeLookingAt; m_pUsableObject = smart_cast(game_object); m_pInvBoxWeLookingAt = smart_cast(game_object); m_pPersonWeLookingAt = smart_cast(game_object); @@ -2083,9 +2083,7 @@ void CActor::shedule_Update(u32 DT) m_pInvBoxWeLookingAt = NULL; } - // UpdateSleep (); - - //äëÿ ñâîéñò àðòåôàêòîâ, íàõîäÿùèõñÿ íà ïîÿñå + // для свойств артефактов, находящихся на поясе (For properties of artefacts on the belt) UpdateArtefactsOnBeltAndOutfit(); m_pPhysics_support->in_shedule_Update(DT); Check_for_AutoPickUp(); @@ -2181,15 +2179,15 @@ void CActor::SetVisibilityFromObject(u16 who_id, float value) m_visibility_changed = true; } -void CActor::RenderCamAttached() +void CActor::RenderCamAttached(IDSGraphManager* DM) { if (cam_active == eacFirstEye && ::Render->active_phase() == 0) { if (GetAttachments()->size()) { - ::Render->set_HUD(TRUE); - ::Render->set_CamAttached(TRUE); - ::Render->set_Object(this); + DM->set_HUD(TRUE); + DM->set_CamAttached(TRUE); + DM->set_Object(this); Fmatrix cam = Fidentity; Cameras().camera_Matrix(cam); @@ -2199,11 +2197,11 @@ void CActor::RenderCamAttached() script_attachment* att = pair.second; if (att->GetType() == eSA_CamAttached) - att->Render(nullptr, &cam); + att->Render(nullptr, &cam, DM); } - ::Render->set_CamAttached(FALSE); - ::Render->set_HUD(FALSE); + DM->set_CamAttached(FALSE); + DM->set_HUD(FALSE); } } } @@ -2243,7 +2241,7 @@ bool canRenderLegs(CActor* actor, CHolderCustom* m_holder) noexcept && !actor->m_FPCam; }; -void CActor::renderable_Render() +void CActor::renderable_Render(IDSGraphManager* DM) { VERIFY(_valid(XFORM())); @@ -2256,21 +2254,21 @@ void CActor::renderable_Render() { if (canRenderLegs(this, m_holder)) { - m_legs_controller.render(); + m_legs_controller.render(DM); } if (showActorBody == 1 || showActorBody == 2) { - inherited::renderable_Render(); + inherited::renderable_Render(DM); if (showActorBody == 2) { - CInventoryOwner::renderable_Render(); + CInventoryOwner::renderable_Render(DM); } } - //if (fpBody) - // inherited::renderable_Render(); + //if (fpBody) + // inherited::renderable_Render(DM); } else if (AllowActorShadow()) // render actor shadow { @@ -2294,7 +2292,7 @@ void CActor::renderable_Render() // Render full body from legs controller without hiding bones for shadow correctness // Solves potential issues with manipulating actor's XFORM m_legs_controller.update(this, true); - m_legs_controller.render(); + m_legs_controller.render(DM); // Ideally the active item also should be duplicated but leave this for now // Move active item @@ -2304,7 +2302,7 @@ void CActor::renderable_Render() auto& v = pItem->object(); if (needAdjust) v.XFORM().c.mad(diff, m); - v.renderable_Render(); + v.renderable_Render(DM); } // Move torch @@ -2315,7 +2313,7 @@ void CActor::renderable_Render() auto& v = I->object(); if (needAdjust) v.XFORM().c.mad(diff, m); - v.renderable_Render(); + v.renderable_Render(DM); } } @@ -2333,14 +2331,14 @@ void CActor::renderable_Render() } else { - inherited::renderable_Render(); - CInventoryOwner::renderable_Render(); + inherited::renderable_Render(DM); + CInventoryOwner::renderable_Render(DM); } } else { - inherited::renderable_Render(); - CInventoryOwner::renderable_Render(); + inherited::renderable_Render(DM); + CInventoryOwner::renderable_Render(DM); } } } @@ -2348,8 +2346,8 @@ void CActor::renderable_Render() // Third Person Body and Weapon/Item else { - inherited::renderable_Render(); - CInventoryOwner::renderable_Render(); + inherited::renderable_Render(DM); + CInventoryOwner::renderable_Render(DM); } } @@ -2398,12 +2396,12 @@ extern BOOL g_ShowAnimationInfo ; #endif // DEBUG // HUD -void CActor::OnHUDDraw(CCustomHUD*) +void CActor::OnHUDDraw(CCustomHUD* Z, IDSGraphManager* DM) { R_ASSERT(IsFocused()); //demonized: disable hud when FPCam is on if (!((mstate_real & mcLookout) && !IsGameTypeSingle()) && (!m_FPCam || m_FPCam->hudEnabled)) - g_player_hud->render_hud(); + g_player_hud->render_hud(DM); #if 0//ndef NDEBUG @@ -2671,6 +2669,7 @@ void CActor::OnItemBelt(CInventoryItem* inventory_item, const SInvItemPlace& pre void CActor::UpdateArtefactsOnBeltAndOutfit() { + PROF_EVENT(); static float update_time = 0; float f_update_time = 0; @@ -2860,12 +2859,12 @@ bool CActor::can_attach(const CInventoryItem* inventory_item) const if (!item || /*!item->enabled() ||*/ !item->can_be_attached()) return (false); - //ìîæíî ëè ïðèñîåäèíÿòü îáúåêòû òàêîãî òèïà + // можно ли присоединять объекты такого типа (Can objects of this type be attached) if (m_attach_item_sections.end() == std::find(m_attach_item_sections.begin(), m_attach_item_sections.end(), inventory_item->object().cNameSect())) return false; - //åñëè óæå åñòü ïðèñîåäèííåíûé îáúåò òàêîãî òèïà + // если уже есть присоединенный объект такого типа (If there is already an attached object of this type) if (attached(inventory_item->object().cNameSect())) return false; diff --git a/src/xrGame/Actor.h b/src/xrGame/Actor.h index db61f6d744..45ece1c68b 100644 --- a/src/xrGame/Actor.h +++ b/src/xrGame/Actor.h @@ -105,6 +105,9 @@ class CActor : virtual CActor* cast_actor() { return this; } virtual CGameObject* cast_game_object() { return this; } virtual IInputReceiver* cast_input_receiver() { return this; } + virtual CEntityAlive* cast_entity_alive() { return this; } + virtual CEntity* cast_entity() { return this; } + virtual CPhraseDialogManager* cast_phrase_dialog_manager() { return this; } virtual CCharacterPhysicsSupport* character_physics_support() { return m_pPhysics_support; } virtual CCharacterPhysicsSupport* character_physics_support() const { return m_pPhysics_support; } virtual CPHDestroyable* ph_destroyable(); @@ -117,7 +120,7 @@ class CActor : public: virtual void Load(LPCSTR section); - virtual void RenderCamAttached(); + virtual void RenderCamAttached(IDSGraphManager* DM); virtual void shedule_Update(u32 T); virtual void UpdateCL(); @@ -125,7 +128,7 @@ class CActor : virtual void OnEvent(NET_Packet& P, u16 type); // Render - virtual void renderable_Render(); + virtual void renderable_Render(IDSGraphManager* DM); virtual BOOL renderable_ShadowGenerate(); virtual bool AllowActorShadow(); virtual void feel_sound_new(CObject* who, int type, CSound_UserDataPtr user_data, const Fvector& Position, @@ -334,7 +337,7 @@ class CActor : void g_SetAnimation(u32 mstate_rl); void g_SetSprintAnimation(u32 mstate_rl, MotionID& head, MotionID& torso, MotionID& legs); public: - virtual void OnHUDDraw(CCustomHUD* hud); + virtual void OnHUDDraw(CCustomHUD* hud, IDSGraphManager* DM); BOOL HUDview() const; //visiblity @@ -795,7 +798,7 @@ class CActor : private: collide::rq_results RQR; BOOL CanPickItem(const CFrustum& frustum, const Fvector& from, CObject* item); - xr_vector ISpatialResult; + xr_vector ISpatialResult; private: CLocationManager* m_location_manager; diff --git a/src/xrGame/ActorCondition.cpp b/src/xrGame/ActorCondition.cpp index 9a9c3d2827..1d31546d39 100644 --- a/src/xrGame/ActorCondition.cpp +++ b/src/xrGame/ActorCondition.cpp @@ -380,15 +380,13 @@ void CActorCondition::AffectDamage_InjuriousMaterialAndMonstersInfluence() // Add Radiation and Psy Level from Monsters CPda* const pda = m_object->GetPDA(); - if (pda) + if (m_object && m_object->g_Alive()) { typedef xr_vector monsters; - for (monsters::const_iterator it = pda->feel_touch.begin(); - it != pda->feel_touch.end(); - ++it) + for (const auto Object : m_object->feel_touch) { - CBaseMonster* const monster = smart_cast(*it); + CBaseMonster* const monster = smart_cast(Object); if (!monster || !monster->g_Alive()) continue; psy_influence += monster->get_psy_influence(); diff --git a/src/xrGame/ActorEffector.h b/src/xrGame/ActorEffector.h index 5a0176d112..3399406795 100644 --- a/src/xrGame/ActorEffector.h +++ b/src/xrGame/ActorEffector.h @@ -33,7 +33,7 @@ class CActorCameraManager : public CCameraManager } }; -typedef fastdelegate::FastDelegate0 GET_KOEFF_FUNC; +typedef xr_delegate GET_KOEFF_FUNC; void AddEffector(CActor* A, int type, const shared_str& sect_name); void AddEffector(CActor* A, int type, const shared_str& sect_name, float factor); diff --git a/src/xrGame/ActorHelmet.cpp b/src/xrGame/ActorHelmet.cpp index 76dc3e0427..3be55cbce3 100644 --- a/src/xrGame/ActorHelmet.cpp +++ b/src/xrGame/ActorHelmet.cpp @@ -233,7 +233,7 @@ float CHelmet::get_HitFracActor() const float CHelmet::HitThroughArmor(float hit_power, s16 element, float ap, bool& add_wound, ALife::EHitType hit_type) { - if (strstr(Core.Params, "-dbgbullet")) + if (Core.ParamsData.test(ECoreParams::dbgbullet)) Msg("CHelmet::HitThroughArmor hit_type=%d | unmodified hit_power=%f", (u32)hit_type, hit_power); float NewHitPower = hit_power; @@ -260,7 +260,7 @@ float CHelmet::HitThroughArmor(float hit_power, s16 element, float ap, bool& add NewHitPower *= d_hit_power; - if (strstr(Core.Params, "-dbgbullet")) + if (Core.ParamsData.test(ECoreParams::dbgbullet)) Msg("CHelmet::HitThroughArmor AP(%f) <= bone_armor(%f) [HitFracActor=%f] modified hit_power=%f", ap, BoneArmor, m_boneProtection->m_fHitFracActor, NewHitPower); } @@ -276,7 +276,7 @@ float CHelmet::HitThroughArmor(float hit_power, s16 element, float ap, bool& add NewHitPower *= d_hit_power; - if (strstr(Core.Params, "-dbgbullet")) + if (Core.ParamsData.test(ECoreParams::dbgbullet)) Msg("CHelmet::HitThroughArmor AP(%f) > bone_armor(%f) [HitFracActor=%f] modified hit_power=%f", ap, BoneArmor, m_boneProtection->m_fHitFracActor, NewHitPower); } @@ -293,9 +293,10 @@ float CHelmet::HitThroughArmor(float hit_power, s16 element, float ap, bool& add //пуля НЕ пробила бронь NewHitPower *= m_boneProtection->m_fHitFracActor; //add_wound = false; //раны нет - if (strstr(Core.Params, "-dbgbullet")) - Msg("CHelmet::HitThroughArmor AP(%f) <= bone_armor(%f) [HitFracActor=%f] modified hit_power=%f", ap, - BoneArmor, m_boneProtection->m_fHitFracActor, NewHitPower); + + if (Core.ParamsData.test(ECoreParams::dbgbullet)) + Msg("CCustomOutfit::HitThroughArmor AP(%f) <= bone_armor(%f) [HitFracActor=%f] modified hit_power=%f", + ap, BoneArmor, m_boneProtection->m_fHitFracActor, NewHitPower); } else { @@ -304,9 +305,9 @@ float CHelmet::HitThroughArmor(float hit_power, s16 element, float ap, bool& add NewHitPower *= d_hit_power; - if (strstr(Core.Params, "-dbgbullet")) - Msg("CHelmet::HitThroughArmor AP(%f) > bone_armor(%f) [HitFracActor=%f] modified hit_power=%f", ap, - BoneArmor, m_boneProtection->m_fHitFracActor, NewHitPower); + if (Core.ParamsData.test(ECoreParams::dbgbullet)) + Msg("CCustomOutfit::HitThroughArmor AP(%f) > bone_armor(%f) [HitFracActor=%f] modified hit_power=%f", + ap, BoneArmor, m_boneProtection->m_fHitFracActor, NewHitPower); } } } @@ -326,18 +327,18 @@ float CHelmet::HitThroughArmor(float hit_power, s16 element, float ap, bool& add if (NewHitPower < 0.f) NewHitPower = 0.f; - if (strstr(Core.Params, "-dbgbullet")) + if (Core.ParamsData.test(ECoreParams::dbgbullet)) Msg("CHelmet::HitThroughArmor hit_type=%d | After HitTypeProtection(%f) hit_power=%f", (u32)hit_type, protect * one, NewHitPower); } - if (strstr(Core.Params, "-dbgbullet")) + if (Core.ParamsData.test(ECoreParams::dbgbullet)) Msg("CHelmet::HitThroughArmor hit_type=%d | After HitFractionActor hit_power=%f", (u32)hit_type, NewHitPower); //увеличить изношенность шлема Hit(hit_power, hit_type); - if (strstr(Core.Params, "-dbgbullet")) + if (Core.ParamsData.test(ECoreParams::dbgbullet)) Msg("CCustomOutfit::HitThroughArmor hit_type=%d | After immunities hit_power=%f", (u32)hit_type, NewHitPower); return NewHitPower; diff --git a/src/xrGame/ActorHelmet.h b/src/xrGame/ActorHelmet.h index 79ad700f62..7e29682088 100644 --- a/src/xrGame/ActorHelmet.h +++ b/src/xrGame/ActorHelmet.h @@ -54,6 +54,8 @@ class CHelmet : public CInventoryItemObject void ReloadBonesProtection(); void AddBonesProtection(LPCSTR bones_section); + virtual CHelmet* cast_helmet() { return this; } + protected: virtual bool install_upgrade_impl(LPCSTR section, bool test); diff --git a/src/xrGame/Actor_Feel.cpp b/src/xrGame/Actor_Feel.cpp index 41213924df..fe8a4015d9 100644 --- a/src/xrGame/Actor_Feel.cpp +++ b/src/xrGame/Actor_Feel.cpp @@ -79,7 +79,7 @@ ICF static BOOL info_trace_callback(collide::rq_result& result, LPVOID params) else { //check obstacle flag - if (result.O->spatial.type & STYPE_OBSTACLE) + if (result.O->SpatialComponent->spatial.type & STYPE_OBSTACLE) bOverlaped = TRUE; return TRUE; @@ -189,7 +189,7 @@ void CActor::PickupModeUpdate_COD(pickup_result_t pickup_result) for (u32 o_it = 0; o_it < ISpatialResult.size(); o_it++) { - ISpatial* spatial = ISpatialResult[o_it]; + ISpatialShared spatial = ISpatialResult[o_it]; CInventoryItem* pIItem = smart_cast(spatial->dcast_CObject()); if (0 == pIItem) continue; @@ -276,6 +276,7 @@ void CActor::PickupModeUpdate_COD(pickup_result_t pickup_result) void CActor::Check_for_AutoPickUp() { + PROF_EVENT(); // mp only if (!psActorFlags.test(AF_AUTOPICKUP)) return; if (IsGameTypeSingle()) return; @@ -287,13 +288,13 @@ void CActor::Check_for_AutoPickUp() Fbox APU_Box; APU_Box.set(Fvector().sub(bc, m_AutoPickUp_AABB), Fvector().add(bc, m_AutoPickUp_AABB)); - xr_vector ISpatialResult; + xr_vector ISpatialResult; g_SpatialSpace->q_box(ISpatialResult, 0, STYPE_COLLIDEABLE, bc, m_AutoPickUp_AABB); // Determine visibility for dynamic part of scene for (u32 o_it = 0; o_it < ISpatialResult.size(); o_it++) { - ISpatial* spatial = ISpatialResult[o_it]; + ISpatialShared spatial = ISpatialResult[o_it]; CInventoryItem* pIItem = smart_cast(spatial->dcast_CObject()); if (0 == pIItem) continue; diff --git a/src/xrGame/Actor_Network.cpp b/src/xrGame/Actor_Network.cpp index 1d185f81e8..688d5a0c35 100644 --- a/src/xrGame/Actor_Network.cpp +++ b/src/xrGame/Actor_Network.cpp @@ -699,7 +699,7 @@ BOOL CActor::net_Spawn(CSE_Abstract* DC) } - spatial.type |= STYPE_REACTTOSOUND; + SpatialComponent->spatial.type |= STYPE_REACTTOSOUND; psHUD_Flags.set(HUD_WEAPON_RT,TRUE); psHUD_Flags.set(HUD_WEAPON_RT2,TRUE); @@ -1229,6 +1229,7 @@ int actInterpType = 0; void CActor::make_Interpolation() { + PROF_EVENT(); m_dwILastUpdateTime = Level().timeServer(); if (g_Alive() && m_bInInterpolation) @@ -1934,9 +1935,7 @@ void CActor::OnPlayHeadShotParticle(NET_Packet P) Fmatrix pos; CParticlesPlayer::MakeXFORM(this, element, HitDir, HitPos, pos); // particles - CParticlesObject* ps = NULL; - - ps = CParticlesObject::Create(m_sHeadShotParticle.c_str(),TRUE); + intrusive_ptr ps = Particles::Details::Create(m_sHeadShotParticle.c_str(),TRUE); ps->UpdateParent(pos, Fvector().set(0.f, 0.f, 0.f)); GamePersistent().ps_needtoplay.push_back(ps); diff --git a/src/xrGame/Artefact.cpp b/src/xrGame/Artefact.cpp index 411c58ad80..fd96be18c1 100644 --- a/src/xrGame/Artefact.cpp +++ b/src/xrGame/Artefact.cpp @@ -219,6 +219,7 @@ void CArtefact::UpdateWorkload(u32 dt) void CArtefact::shedule_Update(u32 dt) { + PROF_EVENT("CArtefact::shedule_Update"); inherited::shedule_Update(dt); ////////////////////////////////////////////////////////////////////////// @@ -350,52 +351,56 @@ void CArtefact::MoveTo(Fvector const& position) void CArtefact::UpdateXForm() { - if (Device.dwFrame != dwXF_Frame) + if (Device.dwFrame == dwXF_Frame) return; + dwXF_Frame = Device.dwFrame; + + if (0==H_Parent()) return; + + // Get access to entity and its visual + CEntityAlive* E = H_Parent()->cast_entity_alive(); + + if(!E) return; + + CInventoryOwner *parent = E->cast_inventory_owner(); + if (parent && parent->use_simplified_visual()) + return; + + VERIFY (E); + IKinematics* V = PKinematics(E->Visual()); + VERIFY (V); + if(CAttachableItem::enabled()) + return; + + // Get matrices + int boneL = -1, boneR = -1, boneR2 = -1; + E->g_WeaponBones (boneL,boneR,boneR2); + if (boneR == -1) return; + + boneL = boneR2; + + //V->CalculateBones (); + Fmatrix mL, mR; + if (E->cast_actor()) + { + V->Bone_GetAnimPos(mL, boneL, u8(-1), false); + V->Bone_GetAnimPos(mR, boneR, u8(-1), false); + } + else { - dwXF_Frame = Device.dwFrame; - - if (0 == H_Parent()) return; - - // Get access to entity and its visual - CEntityAlive* E = smart_cast(H_Parent()); - - if (!E) return; - - const CInventoryOwner* parent = smart_cast(E); - if (parent && parent->use_simplified_visual()) - return; - - VERIFY(E); - IKinematics* V = smart_cast(E->Visual()); - VERIFY(V); - if (CAttachableItem::enabled()) - return; - - // Get matrices - int boneL = -1, boneR = -1, boneR2 = -1; - E->g_WeaponBones(boneL, boneR, boneR2); - if (boneR == -1) return; - - boneL = boneR2; - - V->CalculateBones(); - Fmatrix& mL = V->LL_GetTransform(u16(boneL)); - Fmatrix& mR = V->LL_GetTransform(u16(boneR)); - - // Calculate - Fmatrix mRes; - Fvector R, D,N; - D.sub(mL.c, mR.c); - D.normalize_safe(); - R.crossproduct(mR.j, D); - R.normalize_safe(); - N.crossproduct(D, R); - N.normalize_safe(); - mRes.set(R,N, D, mR.c); - mRes.mulA_43(E->XFORM()); - // UpdatePosition (mRes); - XFORM().mul(mRes, offset()); + // V->CalculateBones(); + mL = V->LL_GetTransform(boneL); + mR = V->LL_GetTransform(boneR); } + // Calculate + Fmatrix mRes; + Fvector R,D,N; + D.sub (mL.c,mR.c); D.normalize_safe(); + R.crossproduct (mR.j,D); R.normalize_safe(); + N.crossproduct (D,R); N.normalize_safe(); + mRes.set (R,N,D,mR.c); + mRes.mulA_43 (E->XFORM()); + + XFORM().mul (mRes,offset()); } #include "xr_level_controller.h" diff --git a/src/xrGame/BastArtifact.cpp b/src/xrGame/BastArtifact.cpp index 2748dcd463..c96a59ef11 100644 --- a/src/xrGame/BastArtifact.cpp +++ b/src/xrGame/BastArtifact.cpp @@ -7,8 +7,6 @@ #include "BastArtifact.h" #include "../xrphysics/PhysicsShell.h" #include "../xrphysics/extendedgeom.h" -#include "ParticlesObject.h" - CBastArtefact::CBastArtefact(void) { @@ -187,8 +185,7 @@ void CBastArtefact::UpdateCLChild() if (m_fEnergy > 0 && ::Random.randF(0.f, 1.0f) < (m_fEnergy / (m_fStrikeImpulse * 100.f))) { - CParticlesObject* pStaticPG; - pStaticPG = CParticlesObject::Create(*m_sParticleName,TRUE); + intrusive_ptr pStaticPG = Particles::Details::Create(*m_sParticleName,TRUE); Fmatrix pos; pos.set(XFORM()); Fvector vel; @@ -199,7 +196,7 @@ void CBastArtefact::UpdateCLChild() pStaticPG->Play(false); } } - else if (H_Parent()) XFORM().set(H_Parent()->XFORM()); + else if (H_Parent() && IsHidden()) XFORM().set(H_Parent()->XFORM()); } diff --git a/src/xrGame/BlackGraviArtifact.cpp b/src/xrGame/BlackGraviArtifact.cpp index f1195afbf0..bac4484886 100644 --- a/src/xrGame/BlackGraviArtifact.cpp +++ b/src/xrGame/BlackGraviArtifact.cpp @@ -8,7 +8,6 @@ #include "BlackGraviArtifact.h" #include "../xrphysics/PhysicsShell.h" #include "entity_alive.h" -#include "ParticlesObject.h" #include "phmovementcontrol.h" #include "xrmessages.h" #include "physicsshellholder.h" @@ -46,8 +45,7 @@ BOOL CBlackGraviArtefact::net_Spawn(CSE_Abstract* DC) if (!inherited::net_Spawn(DC)) return FALSE; - CParticlesObject* pStaticPG; - pStaticPG = CParticlesObject::Create("anomaly\\galantine",FALSE); + intrusive_ptr pStaticPG = Particles::Details::Create("anomaly\\galantine",FALSE); Fmatrix pos; //pos.rotateY(1.57); //pos.mulA(pos); @@ -104,8 +102,7 @@ void CBlackGraviArtefact::UpdateCLChild() GraviStrike(); - CParticlesObject* pStaticPG; - pStaticPG = CParticlesObject::Create(*m_sParticleName,TRUE); + intrusive_ptr pStaticPG = Particles::Details::Create(*m_sParticleName,TRUE); Fmatrix pos; pos.set(XFORM()); Fvector vel; @@ -118,7 +115,7 @@ void CBlackGraviArtefact::UpdateCLChild() m_bStrike = false; } } - else if (H_Parent()) XFORM().set(H_Parent()->XFORM()); + else if (H_Parent() && IsHidden()) XFORM().set(H_Parent()->XFORM()); } //void CBlackGraviArtefact::Hit(float P, Fvector &dir, diff --git a/src/xrGame/Bolt.cpp b/src/xrGame/Bolt.cpp index a3672e3356..57bac990fc 100644 --- a/src/xrGame/Bolt.cpp +++ b/src/xrGame/Bolt.cpp @@ -1,6 +1,5 @@ #include "stdafx.h" #include "bolt.h" -#include "ParticlesObject.h" #include "../xrphysics/PhysicsShell.h" #include "xr_level_controller.h" #include "script_game_object.h" diff --git a/src/xrGame/Bolt.h b/src/xrGame/Bolt.h index 700f05c632..c2d9e69de8 100644 --- a/src/xrGame/Bolt.h +++ b/src/xrGame/Bolt.h @@ -28,6 +28,8 @@ class CBolt : virtual BOOL UsedAI_Locations() { return FALSE; } virtual IDamageSource* cast_IDamageSource() { return this; } + virtual CBolt* cast_bolt() { return this; } + private: bool m_thrown; }; diff --git a/src/xrGame/BottleItem.cpp b/src/xrGame/BottleItem.cpp index a3bb221827..f9fbf06b01 100644 --- a/src/xrGame/BottleItem.cpp +++ b/src/xrGame/BottleItem.cpp @@ -53,8 +53,7 @@ void CBottleItem::BreakToPieces() if (*m_sBreakParticles) { //показываем эффекты - CParticlesObject* pStaticPG; - pStaticPG = CParticlesObject::Create(*m_sBreakParticles,TRUE); + intrusive_ptr pStaticPG = Particles::Details::Create(*m_sBreakParticles,TRUE); pStaticPG->play_at_pos(Position()); } diff --git a/src/xrGame/Car.cpp b/src/xrGame/Car.cpp index 23df2056a8..b358658ac1 100644 --- a/src/xrGame/Car.cpp +++ b/src/xrGame/Car.cpp @@ -1,9 +1,5 @@ #include "stdafx.h" #include "car.h" -//#if 0 - -#include "ParticlesObject.h" -//#include "Physics.h" #ifdef DEBUG # include "../xrEngine/StatGraph.h" @@ -185,8 +181,7 @@ void CCar::Load(LPCSTR section) { inherited::Load(section); //CPHSkeleton::Load(section); - ISpatial* self = smart_cast(this); - if (self) self->spatial.type |= STYPE_VISIBLEFORAI; + SpatialComponent->spatial.type |= STYPE_VISIBLEFORAI; #ifdef CAR_NEW m_on_before_hit_callback = READ_IF_EXISTS(pSettings, r_string, section, "on_before_hit", nullptr); @@ -250,17 +245,7 @@ BOOL CCar::net_Spawn(CSE_Abstract* DC) m_memory->reload(pUserData->r_string("visual_memory_definition", "section")); } - renderable.visual->flags.set(IRenderVisualFlags::eIgnoreOptimization, TRUE); - - xr_vector* children = renderable.visual->get_children(); - - if (children) - { - for (auto* child : *children) - { - child->flags.set(IRenderVisualFlags::eIgnoreOptimization, TRUE); - } - } + renderable.visual->MarkIgnoreOptimization(TRUE); #ifdef CAR_NEW CInifile *ini = Visual()->dcast_PKinematics()->LL_UserData(); @@ -630,9 +615,9 @@ void CCar::VisualUpdate(float fov) m_lights.Update(); } -void CCar::renderable_Render() +void CCar::renderable_Render(IDSGraphManager* DM) { - inherited::renderable_Render(); + inherited::renderable_Render(DM); if (m_car_weapon) m_car_weapon->Render_internal(); } @@ -653,7 +638,7 @@ void CCar::net_Import(NET_Packet& P) // P.w_u32 (NumItems); } -void CCar::OnHUDDraw(CCustomHUD* /**hud*/) +void CCar::OnHUDDraw(CCustomHUD* hud, IDSGraphManager* DM) { #ifdef DEBUG Fvector velocity; @@ -2015,7 +2000,7 @@ void CCar::PhDataUpdate(float step) SDoor* D = m_doors_update[k]; if (!D->update) { - m_doors_update.erase(m_doors_update.begin() + k); + m_doors_update.erase_fast(m_doors_update.begin() + k); --k; } else @@ -2166,6 +2151,7 @@ IC void CCar::fill_exhaust_vector(LPCSTR S, xr_vector& exhausts) IKinematics* pKinematics = smart_cast(Visual()); string64 S1; int count = _GetItemCount(S); + exhausts.reserve(count); for (int i = 0; i < count; ++i) { _GetItem(S, i, S1); @@ -2439,4 +2425,4 @@ Fvector CCar::ExitPosition() if (!m_doors.empty())m_doors.begin()->second.GetExitPosition(m_exit_position); else m_exit_position.set(Position()); return m_exit_position; -} \ No newline at end of file +} diff --git a/src/xrGame/Car.h b/src/xrGame/Car.h index 04c0d704a6..fe1905e11e 100644 --- a/src/xrGame/Car.h +++ b/src/xrGame/Car.h @@ -265,7 +265,7 @@ class CCar : u16 bone_id; Fmatrix transform; //Fvector velocity; - CParticlesObject* p_pgobject; + intrusive_ptr p_pgobject; CPhysicsElement* pelement; CCar* pcar; void Init(); @@ -618,7 +618,7 @@ class CCar : virtual void UpdateEx(float fov); //called by owner virtual void shedule_Update(u32 dt); - virtual void renderable_Render(); + virtual void renderable_Render(IDSGraphManager* DM); virtual bool bfAssignMovement(CScriptEntityAction* tpEntityAction); virtual bool bfAssignObject(CScriptEntityAction* tpEntityAction); @@ -680,7 +680,7 @@ class CCar : }; virtual u16 Initiator(); // HUD - virtual void OnHUDDraw(CCustomHUD* hud); + virtual void OnHUDDraw(CCustomHUD* hud, IDSGraphManager* DM); CCameraBase* Camera() { return active_camera; } void SetExplodeTime(u32 et); @@ -706,6 +706,14 @@ class CCar : public: virtual CEntity* cast_entity() { return this; } + virtual CGameObject* cast_game_object() { return this; } + virtual CExplosive* cast_explosive() { return this; } + virtual CPhysicsShellHolder* cast_physics_shell_holder() { return this; } + virtual CParticlesPlayer* cast_particles_player() { return this; } + virtual CScriptEntity* cast_script_entity() { return this; } + virtual IDamageSource* cast_IDamageSource() { return this; } + virtual CHolderCustom* cast_holder_custom() { return this; } + virtual CCar* cast_car() { return this; } private: template IC void fill_wheel_vector(LPCSTR S, xr_vector& type_wheels); @@ -717,13 +725,6 @@ class CCar : virtual void reinit(); virtual void reload(LPCSTR section); - virtual CGameObject* cast_game_object() { return this; } - virtual CExplosive* cast_explosive() { return this; } - virtual CPhysicsShellHolder* cast_physics_shell_holder() { return this; } - virtual CParticlesPlayer* cast_particles_player() { return this; } - virtual CScriptEntity* cast_script_entity() { return this; } - virtual IDamageSource* cast_IDamageSource() { return this; } - virtual CHolderCustom* cast_holder_custom() { return this; } private: car_memory* m_memory; diff --git a/src/xrGame/CarExhaust.cpp b/src/xrGame/CarExhaust.cpp index 6b88e9561b..5fcedf92e2 100644 --- a/src/xrGame/CarExhaust.cpp +++ b/src/xrGame/CarExhaust.cpp @@ -15,7 +15,7 @@ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// CCar::SExhaust::~SExhaust() { - CParticlesObject::Destroy(p_pgobject); + Particles::Details::Destroy(p_pgobject); } void CCar::SExhaust::Init() @@ -30,7 +30,7 @@ void CCar::SExhaust::Init() //pelement->InterpolateGlobalTransform(&element_transform); //element_transform.invert(); //transform.mulA(element_transform); - p_pgobject = CParticlesObject::Create(*pcar->m_exhaust_particles,FALSE); + p_pgobject = Particles::Details::Create(*pcar->m_exhaust_particles,FALSE); Fvector zero_vector; zero_vector.set(0.f, 0.f, 0.f); p_pgobject->UpdateParent(pcar->XFORM(), zero_vector); @@ -57,7 +57,7 @@ void CCar::SExhaust::Update() void CCar::SExhaust::Clear() { - CParticlesObject::Destroy(p_pgobject); + Particles::Details::Destroy(p_pgobject); } void CCar::SExhaust::Play() diff --git a/src/xrGame/CharacterPhysicsSupport.cpp b/src/xrGame/CharacterPhysicsSupport.cpp index 30100925b5..f1737fb5d8 100644 --- a/src/xrGame/CharacterPhysicsSupport.cpp +++ b/src/xrGame/CharacterPhysicsSupport.cpp @@ -389,6 +389,7 @@ void CCharacterPhysicsSupport::UpdateCollisionActivatingDellay() void CCharacterPhysicsSupport::in_shedule_Update(u32 DT) { + PROF_EVENT(); ///VERIFY( 0 ); //CPHSkeleton::Update(DT); @@ -657,10 +658,10 @@ void CCharacterPhysicsSupport::in_UpdateCL() // demonized: use screen space area to check if need update float perceived_dist = Device.GetPerceivedDist(p); - float ssa = Device.CalcSSADynamic(m_EntityAlife.spatial.sphere.P, m_EntityAlife.spatial.sphere.R); + float ssa = Device.CalcSSADynamic(m_EntityAlife.SpatialComponent->spatial.sphere.P, m_EntityAlife.SpatialComponent->spatial.sphere.R); if (ssa > IK_CALC_SSA) { - if (view_frust.testSphere_dirty(m_EntityAlife.spatial.sphere.P, m_EntityAlife.spatial.sphere.R) || perceived_dist < IK_ALWAYS_CALC_DIST) + if (view_frust.testSphere_dirty(m_EntityAlife.SpatialComponent->spatial.sphere.P, m_EntityAlife.SpatialComponent->spatial.sphere.R) || perceived_dist < IK_ALWAYS_CALC_DIST) { update_interactive_anims(); ik_controller()->Update(); diff --git a/src/xrGame/ClimableObject.cpp b/src/xrGame/ClimableObject.cpp index 4038fd37a8..d247e1b83e 100644 --- a/src/xrGame/ClimableObject.cpp +++ b/src/xrGame/ClimableObject.cpp @@ -75,7 +75,7 @@ BOOL CClimableObject::net_Spawn(CSE_Abstract* DC) //m_box.m_halfsize.set(1.f,1.f,1.f); BOOL ret = inherited::net_Spawn(DC); - spatial.type &= ~STYPE_VISIBLEFORAI; + SpatialComponent->spatial.type &= ~STYPE_VISIBLEFORAI; const float f_min_width = 0.2f; Fvector shift; @@ -363,8 +363,10 @@ void CClimableObject::ObjectContactCallback(bool& do_colide, bool bo1, dContact& VERIFY(ch); VERIFY(usr_data_lad); this_object = static_cast(usr_data_lad->ph_ref_object); - VERIFY(this_object); - if (!this_object->BeforeLadder(ch, -0.1f)) do_colide = false; + if (this_object) + { + if (!this_object->BeforeLadder(ch, -0.1f)) do_colide = false; + } } #ifdef DEBUG extern Flags32 dbg_net_Draw_Flags; diff --git a/src/xrGame/ClimableObject.h b/src/xrGame/ClimableObject.h index b6c41de12a..6f291c4bd4 100644 --- a/src/xrGame/ClimableObject.h +++ b/src/xrGame/ClimableObject.h @@ -34,6 +34,8 @@ class CClimableObject : virtual float Radius() const; //////////////////////////////////////////////////////////////////// virtual IPhysicsShellHolder* cast_IPhysicsShellHolder() { return this; } + virtual CPhysicsShellHolder* cast_physics_shell_holder() { return this; } + virtual CClimableObject* cast_climable_object() { return this; } #ifdef DEBUG virtual void OnRender (); diff --git a/src/xrGame/CustomDetector.cpp b/src/xrGame/CustomDetector.cpp index 80487e4a04..4e2190e004 100644 --- a/src/xrGame/CustomDetector.cpp +++ b/src/xrGame/CustomDetector.cpp @@ -22,7 +22,7 @@ ITEM_INFO::ITEM_INFO() ITEM_INFO::~ITEM_INFO() { if (pParticle) - CParticlesObject::Destroy(pParticle); + Particles::Details::Destroy(pParticle); } CCustomDetector::CCustomDetector(){} @@ -43,6 +43,7 @@ void CCustomDetector::Load(LPCSTR section) void CCustomDetector::shedule_Update(u32 dt) { + PROF_EVENT("CCustomDetector::shedule_Update"); inherited::shedule_Update(dt); if (!IsWorking()) diff --git a/src/xrGame/CustomDetector.h b/src/xrGame/CustomDetector.h index 70a48452af..c41c5ac171 100644 --- a/src/xrGame/CustomDetector.h +++ b/src/xrGame/CustomDetector.h @@ -134,6 +134,9 @@ class CCustomDetector : public CCustomDevice float m_fAfDetectRadius; virtual u32 ef_detector_type() const { return 1; }; + + virtual CCustomDetector* cast_custom_detector() { return this; } + protected: virtual void UpdateWork(); virtual void UpdateAf(){}; diff --git a/src/xrGame/CustomDevice.h b/src/xrGame/CustomDevice.h index 7bca57f2ef..0f983f047f 100644 --- a/src/xrGame/CustomDevice.h +++ b/src/xrGame/CustomDevice.h @@ -25,6 +25,8 @@ class CCustomDevice : public CHudItemObject virtual void shedule_Update(u32 dt); virtual void UpdateCL(); + virtual CCustomDevice* cast_custom_device() { return this; } + enum EDeviceStates { eIdleZoom = 5, diff --git a/src/xrGame/CustomMonster.cpp b/src/xrGame/CustomMonster.cpp index d1429c8851..9ab61cf603 100644 --- a/src/xrGame/CustomMonster.cpp +++ b/src/xrGame/CustomMonster.cpp @@ -323,6 +323,7 @@ void CCustomMonster::net_Import(NET_Packet& P) void CCustomMonster::shedule_Update(u32 DT) { + PROF_EVENT("CCustomMonster::shedule_Update"); VERIFY(!g_Alive() || processing_enabled()); // Queue shrink VERIFY(_valid(Position())); @@ -331,22 +332,13 @@ void CCustomMonster::shedule_Update(u32 DT) while ((NET.size() > 2) && (NET[1].dwTimeStamp < dwTimeCL)) NET.pop_front(); float dt = float(DT) / 1000.f; + + CScriptEntity::process_sound_callbacks(); + // *** general stuff if (g_Alive()) { - if (false && g_mt_config.test(mtAiVision)) -#ifndef DEBUG - Device.seqParallel.push_back(fastdelegate::FastDelegate0<>(this, &CCustomMonster::Exec_Visibility)); -#else // DEBUG - { - if (!psAI_Flags.test(aiStalker) || !!smart_cast(Level().CurrentEntity())) - Device.seqParallel.push_back(fastdelegate::FastDelegate0<>(this,&CCustomMonster::Exec_Visibility)); - else - Exec_Visibility (); - } -#endif // DEBUG - else - Exec_Visibility(); + Exec_Visibility(); memory().update(dt); } inherited::shedule_Update(DT); @@ -430,6 +422,7 @@ void CCustomMonster::net_update::lerp(CCustomMonster::net_update& A, CCustomMons void CCustomMonster::update_sound_player() { + PROF_EVENT("AI: [Monsters] Update sounds"); sound().update(client_update_fdelta()); } @@ -453,8 +446,6 @@ void CCustomMonster::UpdateCL() animation_movement()->DBG_verify_position_not_chaged(); #endif - CScriptEntity::process_sound_callbacks(); - /* //. hack just to skip 'CalculateBones' if (sound().need_bone_data()) { // we do this because we know here would be virtual function call @@ -465,7 +456,7 @@ void CCustomMonster::UpdateCL() */ if (g_mt_config.test(mtSoundPlayer)) - Device.seqParallel.push_back(fastdelegate::FastDelegate0<>(this, &CCustomMonster::update_sound_player)); + Device.seqParallel.push_back(xr_make_delegate(this, &CCustomMonster::update_sound_player)); else { START_PROFILE("CustomMonster/client_update/sound_player") @@ -586,6 +577,8 @@ void CCustomMonster::UpdatePositionAnimation() if (!bfScriptAnimation()) SelectAnimation(XFORM().k, movement().detail().direction(), movement().speed()); STOP_PROFILE + + eye_pp_s0(); } BOOL CCustomMonster::feel_visible_isRelevant(CObject* O) @@ -600,7 +593,7 @@ void CCustomMonster::eye_pp_s0() { // Eye matrix IKinematics* V = smart_cast(Visual()); - V->CalculateBones(); + //V->CalculateBones(); Fmatrix& mEye = V->LL_GetTransform(u16(eye_bone)); Fmatrix X; X.mul_43(XFORM(), mEye); @@ -632,7 +625,8 @@ void CCustomMonster::update_range_fov(float& new_range, float& new_fov, float st float current_fog_density = GamePersistent().Environment().CurrentEnv->fog_density; // 0=no_fog, 1=full_fog, >1 = super-fog - float current_far_plane = GamePersistent().Environment().CurrentEnv->far_plane; +#pragma todo("v2v3v4: Let's see, maybe it will stay like this because it's much cheaper and more logical.") + float current_far_plane = ai().get_alife() ? ai().alife().online_distance() : GamePersistent().Environment().CurrentEnv->far_plane; // 300=standart, 50=super-fog #ifdef HOLDERCUSTOM_NEW @@ -686,7 +680,7 @@ void CCustomMonster::eye_pp_s1() VERIFY(_valid(eye_matrix)); mProject.build_projection(deg2rad(new_fov), 1, 0.1f, new_range); mFull.mul(mProject, mView); - feel_vision_query(mFull, eye_matrix.c); + feel_vision_query(mFull); Device.Statistic->AI_Vis_Query.End(); } @@ -697,20 +691,29 @@ void CCustomMonster::eye_pp_s2() u32 dwTime = Level().timeServer(); u32 dwDT = dwTime - eye_pp_timestamp; eye_pp_timestamp = dwTime; - feel_vision_update(this, eye_matrix.c, float(dwDT) / 1000.f, memory().visual().transparency_threshold()); + static DWORD this_thread_id = 0; + this_thread_id = GetCurrentThreadId(); + Device.secondary_tasks.run([=]() + { + if (this_thread_id != GetCurrentThreadId()) { PROF_THREAD("X-Ray PPL Thread") } + feel_vision_update(eye_matrix.c,float(dwDT)/1000.f,memory().visual().transparency_threshold()); + + }); Device.Statistic->AI_Vis_RayTests.End(); } void CCustomMonster::Exec_Visibility() { + PROF_EVENT("AI: Exec_Visibility"); //if (0==Sector()) return; if (!g_Alive()) return; + PROF_EVENT("stalker/schedule_update/vision/Exec_Visibility") + Device.Statistic->AI_Vis.Begin(); switch (eye_pp_stage % 2) { case 0: - eye_pp_s0(); eye_pp_s1(); break; case 1: eye_pp_s2(); @@ -748,14 +751,9 @@ BOOL CCustomMonster::net_Spawn(CSE_Abstract* DC) if (!movement().net_Spawn(DC) || !inherited::net_Spawn(DC) || !CScriptEntity::net_Spawn(DC)) return (FALSE); - ISpatial* self = smart_cast(this); - if (self) - { - self->spatial.type |= STYPE_VISIBLEFORAI; - // enable react to sound only if alive - if (g_Alive()) - self->spatial.type |= STYPE_REACTTOSOUND; - } + SpatialComponent->spatial.type |= STYPE_VISIBLEFORAI; + if (g_Alive()) + SpatialComponent->spatial.type |= STYPE_REACTTOSOUND; CSE_Abstract* e = (CSE_Abstract*)(DC); CSE_ALifeMonsterAbstract* E = smart_cast(e); @@ -836,7 +834,7 @@ BOOL CCustomMonster::net_Spawn(CSE_Abstract* DC) } #ifdef DEBUG -void CCustomMonster::OnHUDDraw(CCustomHUD *hud) +void CCustomMonster::OnHUDDraw(CCustomHUD *hud, IDSGraphManager* DM) { } #endif @@ -865,18 +863,11 @@ void CCustomMonster::net_Destroy() movement().net_Destroy(); Device.remove_from_seq_parallel( - fastdelegate::FastDelegate0<>( + xr_make_delegate( this, &CCustomMonster::update_sound_player ) ); - Device.remove_from_seq_parallel( - fastdelegate::FastDelegate0<>( - this, - &CCustomMonster::Exec_Visibility - ) - ); - #ifdef DEBUG DBG().on_destroy_object(this); #endif @@ -1434,20 +1425,5 @@ void CCustomMonster::ForceTransform(const Fmatrix& m) Fvector CCustomMonster::spatial_sector_point() { - //if ( g_Alive() ) - // return inherited::spatial_sector_point( ); - - //if ( !animation_movement() ) - return inherited::spatial_sector_point().add(Fvector().set(0.f, Radius() * .5f, 0.f)); - - //IKinematics* const kinematics = smart_cast(Visual()); - //VERIFY (kinematics); - //u16 const root_bone_id = kinematics->LL_BoneID("bip01_spine"); - - //Fmatrix local; - //kinematics->Bone_GetAnimPos ( local, root_bone_id, u8(-1), false ); - - //Fmatrix result; - //result.mul_43 ( XFORM(), local ); - //return result.c; + return ISpatialOwner::spatial_sector_point().add(Fvector().set(0.f, Radius() * .5f, 0.f)); } diff --git a/src/xrGame/CustomMonster.h b/src/xrGame/CustomMonster.h index 5b07433ebe..f6175e664d 100644 --- a/src/xrGame/CustomMonster.h +++ b/src/xrGame/CustomMonster.h @@ -169,7 +169,7 @@ class CCustomMonster : // debug #ifdef DEBUG virtual void OnRender ( ); - virtual void OnHUDDraw (CCustomHUD* hud); + virtual void OnHUDDraw (CCustomHUD* hud, IDSGraphManager* DM); #endif virtual bool bfExecMovement() { return (false); }; @@ -228,6 +228,7 @@ class CCustomMonster : bool is_special_killer(CObject* obj); IC CMemoryManager& memory() const; + IC CMemoryManager* memoryPtr() const { return m_memory_manager; } virtual float feel_vision_mtl_transp(CObject* O, u32 element); virtual void feel_sound_new(CObject* who, int type, CSound_UserDataPtr user_data, const Fvector& Position, float power); diff --git a/src/xrGame/CustomOutfit.cpp b/src/xrGame/CustomOutfit.cpp index 587fbf902b..72631d2ee4 100644 --- a/src/xrGame/CustomOutfit.cpp +++ b/src/xrGame/CustomOutfit.cpp @@ -159,7 +159,7 @@ float CCustomOutfit::GetBoneArmor(s16 element) #pragma optimize( "", off ) float CCustomOutfit::HitThroughArmor(float hit_power, s16 element, float ap, bool& add_wound, ALife::EHitType hit_type) { - if (strstr(Core.Params, "-dbgbullet")) + if (Core.ParamsData.test(ECoreParams::dbgbullet)) Msg("CCustomOutfit::HitThroughArmor hit_type=%d | unmodified hit_power=%f", (u32)hit_type, hit_power); float NewHitPower = hit_power; @@ -186,7 +186,7 @@ float CCustomOutfit::HitThroughArmor(float hit_power, s16 element, float ap, boo NewHitPower *= d_hit_power; - if (strstr(Core.Params, "-dbgbullet")) + if (Core.ParamsData.test(ECoreParams::dbgbullet)) Msg("CHelmet::HitThroughArmor AP(%f) <= bone_armor(%f) [HitFracActor=%f] modified hit_power=%f", ap, BoneArmor, m_boneProtection->m_fHitFracActor, NewHitPower); } @@ -202,7 +202,7 @@ float CCustomOutfit::HitThroughArmor(float hit_power, s16 element, float ap, boo NewHitPower *= d_hit_power; - if (strstr(Core.Params, "-dbgbullet")) + if (Core.ParamsData.test(ECoreParams::dbgbullet)) Msg("CHelmet::HitThroughArmor AP(%f) > bone_armor(%f) [HitFracActor=%f] modified hit_power=%f", ap, BoneArmor, m_boneProtection->m_fHitFracActor, NewHitPower); } @@ -219,9 +219,10 @@ float CCustomOutfit::HitThroughArmor(float hit_power, s16 element, float ap, boo //пуля НЕ пробила бронь NewHitPower *= m_boneProtection->m_fHitFracActor; //add_wound = false; //раны нет - if (strstr(Core.Params, "-dbgbullet")) - Msg("CHelmet::HitThroughArmor AP(%f) <= bone_armor(%f) [HitFracActor=%f] modified hit_power=%f", ap, - BoneArmor, m_boneProtection->m_fHitFracActor, NewHitPower); + + if (Core.ParamsData.test(ECoreParams::dbgbullet)) + Msg("CCustomOutfit::HitThroughArmor AP(%f) <= bone_armor(%f) [HitFracActor=%f] modified hit_power=%f", + ap, BoneArmor, m_boneProtection->m_fHitFracActor, NewHitPower); } else { @@ -230,9 +231,9 @@ float CCustomOutfit::HitThroughArmor(float hit_power, s16 element, float ap, boo NewHitPower *= d_hit_power; - if (strstr(Core.Params, "-dbgbullet")) - Msg("CHelmet::HitThroughArmor AP(%f) > bone_armor(%f) [HitFracActor=%f] modified hit_power=%f", ap, - BoneArmor, m_boneProtection->m_fHitFracActor, NewHitPower); + if (Core.ParamsData.test(ECoreParams::dbgbullet)) + Msg("CCustomOutfit::HitThroughArmor AP(%f) > bone_armor(%f) [HitFracActor=%f] modified hit_power=%f", + ap, BoneArmor, m_boneProtection->m_fHitFracActor, NewHitPower); } } } @@ -252,14 +253,14 @@ float CCustomOutfit::HitThroughArmor(float hit_power, s16 element, float ap, boo if (NewHitPower < 0.f) NewHitPower = 0.f; - if (strstr(Core.Params, "-dbgbullet")) + if (Core.ParamsData.test(ECoreParams::dbgbullet)) Msg("CCustomOutfit::HitThroughArmor hit_type=%d | After HitTypeProtection(%f) hit_power=%f", (u32)hit_type, protect * one, NewHitPower); } //увеличить изношенность костюма Hit(hit_power, hit_type); - if (strstr(Core.Params, "-dbgbullet")) + if (Core.ParamsData.test(ECoreParams::dbgbullet)) Msg("CCustomOutfit::HitThroughArmor hit_type=%d | After Immunities hit_power=%f", (u32)hit_type, NewHitPower); return NewHitPower; @@ -440,4 +441,4 @@ void CCustomOutfit::AddBonesProtection(LPCSTR bones_section) float CCustomOutfit::get_HitFracActor() const { return m_boneProtection->m_fHitFracActor; -} \ No newline at end of file +} diff --git a/src/xrGame/CustomOutfit.h b/src/xrGame/CustomOutfit.h index 600cbd4dcd..3c47d7aa7e 100644 --- a/src/xrGame/CustomOutfit.h +++ b/src/xrGame/CustomOutfit.h @@ -32,6 +32,8 @@ class CCustomOutfit : public CInventoryItemObject virtual void OnH_A_Chield(); virtual float GetControlInertionFactor() const { return m_fControlInertionFactor; }; + virtual CCustomOutfit* cast_outfit() { return this; } + protected: HitImmunity::HitTypeSVec m_HitTypeProtection; diff --git a/src/xrGame/CustomRocket.cpp b/src/xrGame/CustomRocket.cpp index bf476d4517..0875a301e1 100644 --- a/src/xrGame/CustomRocket.cpp +++ b/src/xrGame/CustomRocket.cpp @@ -598,7 +598,7 @@ void CCustomRocket::StartEngineParticles() { VERIFY(m_pEngineParticles == NULL); if (!m_sEngineParticles) return; - m_pEngineParticles = CParticlesObject::Create(*m_sEngineParticles,FALSE); + m_pEngineParticles = Particles::Details::Create(*m_sEngineParticles,FALSE); UpdateParticles(); m_pEngineParticles->Play(false); @@ -622,7 +622,7 @@ void CCustomRocket::StartFlyParticles() VERIFY(m_pFlyParticles == NULL); if (!m_sFlyParticles) return; - m_pFlyParticles = CParticlesObject::Create(*m_sFlyParticles,FALSE); + m_pFlyParticles = Particles::Details::Create(*m_sFlyParticles,FALSE); UpdateParticles(); m_pFlyParticles->Play(false); diff --git a/src/xrGame/CustomRocket.h b/src/xrGame/CustomRocket.h index cf9aca165f..538a15e33b 100644 --- a/src/xrGame/CustomRocket.h +++ b/src/xrGame/CustomRocket.h @@ -55,7 +55,7 @@ class CCustomRocket : public CPhysicItem, virtual BOOL UsedAI_Locations() { return (FALSE); } virtual bool Useful() const { return (m_eState == eInactive); } - virtual void renderable_Render() { inherited::renderable_Render(); } + virtual void renderable_Render(IDSGraphManager* DM) { inherited::renderable_Render(DM); } //создание физической оболочки virtual void activate_physic_shell(); @@ -153,10 +153,10 @@ class CCustomRocket : public CPhysicItem, protected: //имя партиклов двигателя shared_str m_sEngineParticles; - CParticlesObject* m_pEngineParticles; + intrusive_ptr m_pEngineParticles; //имя партиклов полета shared_str m_sFlyParticles; - CParticlesObject* m_pFlyParticles; + intrusive_ptr m_pFlyParticles; Fvector m_vPrevVel; float m_time_to_explode; diff --git a/src/xrGame/CustomZone.cpp b/src/xrGame/CustomZone.cpp index 2b637a4c1b..c6d2fe2886 100644 --- a/src/xrGame/CustomZone.cpp +++ b/src/xrGame/CustomZone.cpp @@ -4,7 +4,6 @@ #include "hit.h" #include "PHDestroyable.h" #include "actor.h" -#include "ParticlesObject.h" #include "xrserver_objects_alife_monsters.h" #include "../xrEngine/LightAnimLibrary.h" #include "level.h" @@ -93,8 +92,7 @@ void CCustomZone::Load(LPCSTR section) m_StateTime[eZoneStateAccumulate] = pSettings->r_s32(section, "accamulate_time"); ////////////////////////////////////////////////////////////////////////// - ISpatial* self = smart_cast(this); - if (self) self->spatial.type |= (STYPE_COLLIDEABLE | STYPE_SHAPE); + SpatialComponent->spatial.type |= (STYPE_COLLIDEABLE | STYPE_SHAPE); ////////////////////////////////////////////////////////////////////////// LPCSTR sound_str = NULL; @@ -420,7 +418,8 @@ BOOL CCustomZone::net_Spawn(CSE_Abstract* DC) setEnabled(TRUE); - PlayIdleParticles(); + if (IsEnabled()) + PlayIdleParticles(); m_iPreviousStateTime = m_iStateTime = 0; @@ -446,7 +445,7 @@ void CCustomZone::net_Destroy() m_pLight.destroy(); m_pIdleLight.destroy(); - CParticlesObject::Destroy(m_pIdleParticles); + Particles::Details::Destroy(m_pIdleParticles); if (m_actor_effector) m_actor_effector->Stop(); @@ -588,6 +587,7 @@ void CCustomZone::UpdateCL() // called as usual void CCustomZone::shedule_Update(u32 dt) { + PROF_EVENT("CCustomZone::shedule_Update"); m_zone_flags.set(eZoneIsActive, FALSE); if (IsEnabled()) @@ -744,7 +744,7 @@ void CCustomZone::feel_touch_delete(CObject* O) if (it != m_ObjectInfoMap.end()) { exit_Zone(*it); - m_ObjectInfoMap.erase(it); + m_ObjectInfoMap.erase_fast(it); } } @@ -803,9 +803,7 @@ void CCustomZone::PlayIdleParticles(bool bIdleLight) { if (!m_pIdleParticles) { - m_pIdleParticles = CParticlesObject::Create(m_sIdleParticles.c_str(),FALSE); - m_pIdleParticles->UpdateParent(XFORM(), zero_vel); - + m_pIdleParticles = Particles::Details::Create(m_sIdleParticles.c_str(),FALSE); m_pIdleParticles->UpdateParent(XFORM(), zero_vel); m_pIdleParticles->Play(false); } @@ -821,7 +819,7 @@ void CCustomZone::StopIdleParticles(bool bIdleLight) if (m_pIdleParticles) { m_pIdleParticles->Stop(FALSE); - CParticlesObject::Destroy(m_pIdleParticles); + Particles::Details::Destroy(m_pIdleParticles); } if (bIdleLight) @@ -877,8 +875,7 @@ void CCustomZone::PlayBlowoutParticles() if (!m_sBlowoutParticles) return; if (!m_zone_flags.test(eFastMode)) return; - CParticlesObject* pParticles; - pParticles = CParticlesObject::Create(*m_sBlowoutParticles,TRUE); + intrusive_ptr pParticles = Particles::Details::Create(*m_sBlowoutParticles,TRUE); pParticles->UpdateParent(XFORM(), zero_vel); pParticles->Play(false); @@ -954,7 +951,7 @@ void CCustomZone::PlayEntranceParticles(CGameObject* pObject) if (play_bone != BI_NONE) { - CParticlesObject* pParticles = CParticlesObject::Create(particle_str, TRUE); + intrusive_ptr pParticles = Particles::Details::Create(particle_str, TRUE); Fmatrix xform; Fvector dir; if (fis_zero(vel.magnitude())) @@ -983,8 +980,7 @@ void CCustomZone::PlayBoltEntranceParticles() xr_vector& Shapes = Sh->Shapes(); Fvector sP0, sP1, vel; - CParticlesObject* pParticles = NULL; - + intrusive_ptr pParticles; xr_vector::iterator it = Shapes.begin(); xr_vector::iterator it_e = Shapes.end(); @@ -1021,7 +1017,7 @@ void CCustomZone::PlayBoltEntranceParticles() PXF.c = sP1; - pParticles = CParticlesObject::Create(m_sBoltEntranceParticles.c_str(), TRUE); + pParticles = Particles::Details::Create(m_sBoltEntranceParticles.c_str(), TRUE); pParticles->UpdateParent(PXF, vel); pParticles->Play(false); } @@ -1040,8 +1036,7 @@ void CCustomZone::PlayBulletParticles(Fvector& pos) if (!m_sEntranceParticlesSmall) return; - CParticlesObject* pParticles; - pParticles = CParticlesObject::Create(*m_sEntranceParticlesSmall,TRUE); + intrusive_ptr pParticles = Particles::Details::Create(*m_sEntranceParticlesSmall,TRUE); Fmatrix M; M = XFORM(); @@ -1457,7 +1452,7 @@ void CCustomZone::net_Relcase(CObject* O) if (it != m_ObjectInfoMap.end()) { exit_Zone(*it); - m_ObjectInfoMap.erase(it); + m_ObjectInfoMap.erase_fast(it); } if (GO->ID() == m_owner_id) m_owner_id = u32(-1); @@ -1492,8 +1487,7 @@ void CCustomZone::PlayAccumParticles() if (!m_zone_flags.test(eFastMode)) return; if (m_sAccumParticles.size()) { - CParticlesObject* pParticles; - pParticles = CParticlesObject::Create(*m_sAccumParticles,TRUE); + intrusive_ptr pParticles = Particles::Details::Create(*m_sAccumParticles,TRUE); pParticles->UpdateParent(XFORM(), zero_vel); pParticles->Play(false); } @@ -1507,8 +1501,7 @@ void CCustomZone::PlayAwakingParticles() if (!m_zone_flags.test(eFastMode)) return; if (m_sAwakingParticles.size()) { - CParticlesObject* pParticles; - pParticles = CParticlesObject::Create(*m_sAwakingParticles,TRUE); + intrusive_ptr pParticles = Particles::Details::Create(*m_sAwakingParticles,TRUE); pParticles->UpdateParent(XFORM(), zero_vel); pParticles->Play(false); } @@ -1576,7 +1569,7 @@ void CCustomZone::GoEnabledState() bool CCustomZone::feel_touch_on_contact(CObject* O) { - if ((spatial.type | STYPE_VISIBLEFORAI) != spatial.type) + if ((SpatialComponent->spatial.type | STYPE_VISIBLEFORAI) != SpatialComponent->spatial.type) return (false); return (inherited::feel_touch_on_contact(O)); diff --git a/src/xrGame/CustomZone.h b/src/xrGame/CustomZone.h index 97fd93697f..bb0d9af79d 100644 --- a/src/xrGame/CustomZone.h +++ b/src/xrGame/CustomZone.h @@ -83,7 +83,9 @@ class CCustomZone : public CSpaceRestrictor, //абсолютный размер float Power(float dist, float nearest_shape_radius); - virtual CCustomZone* cast_custom_zone() { return this; } + virtual CCustomZone* cast_custom_zone() {return this;} + virtual CSpaceRestrictor* cast_restrictor() {return this;} + virtual CGameObject* cast_game_object() { return this; } //различные состояния в которых может находиться зона typedef enum @@ -284,7 +286,7 @@ class CCustomZone : public CSpaceRestrictor, ref_sound m_entrance_sound; //объект партиклов обычного состояния зоны - CParticlesObject* m_pIdleParticles; + intrusive_ptr m_pIdleParticles; ////////////////////////////// //подсветка аномалии diff --git a/src/xrGame/DamagableItem.h b/src/xrGame/DamagableItem.h index 3a54e51443..872350caa2 100644 --- a/src/xrGame/DamagableItem.h +++ b/src/xrGame/DamagableItem.h @@ -1,3 +1,5 @@ +#pragma once + class CDamagableItem { protected: diff --git a/src/xrGame/DemoPlay_Control.h b/src/xrGame/DemoPlay_Control.h index 7ce63e2c1c..897b85cebc 100644 --- a/src/xrGame/DemoPlay_Control.h +++ b/src/xrGame/DemoPlay_Control.h @@ -11,7 +11,7 @@ class demoplay_control demoplay_control(); ~demoplay_control(); - typedef fastdelegate::FastDelegate0 user_callback_t; + typedef xr_delegate user_callback_t; enum EAction { diff --git a/src/xrGame/DestroyablePhysicsObject.cpp b/src/xrGame/DestroyablePhysicsObject.cpp index a62c312792..524996094f 100644 --- a/src/xrGame/DestroyablePhysicsObject.cpp +++ b/src/xrGame/DestroyablePhysicsObject.cpp @@ -158,6 +158,7 @@ void CDestroyablePhysicsObject::InitServerObject(CSE_Abstract* D) void CDestroyablePhysicsObject::shedule_Update(u32 dt) { + PROF_EVENT("CDestroyablePhysicsObject::shedule_Update"); inherited::shedule_Update(dt); CPHDestroyable::SheduleUpdate(dt); } diff --git a/src/xrGame/ElectricBall.cpp b/src/xrGame/ElectricBall.cpp index a412aeb036..794499d35f 100644 --- a/src/xrGame/ElectricBall.cpp +++ b/src/xrGame/ElectricBall.cpp @@ -25,5 +25,5 @@ void CElectricBall::UpdateCLChild() { inherited::UpdateCLChild(); - if (H_Parent()) XFORM().set(H_Parent()->XFORM()); + if (H_Parent() && IsHidden()) XFORM().set(H_Parent()->XFORM()); }; diff --git a/src/xrGame/EliteDetector.cpp b/src/xrGame/EliteDetector.cpp index 4fe249e93e..b22c174bdd 100644 --- a/src/xrGame/EliteDetector.cpp +++ b/src/xrGame/EliteDetector.cpp @@ -80,6 +80,7 @@ void fix_ws_wnd_size(CUIWindow* w, float kx) p.x /= kx; w->SetWndPos(p); + xrCriticalSectionGuard guard(w->csUi); CUIWindow::WINDOW_LIST::iterator it = w->GetChildWndList().begin(); CUIWindow::WINDOW_LIST::iterator it_e = w->GetChildWndList().end(); diff --git a/src/xrGame/Entity.cpp b/src/xrGame/Entity.cpp index 3f1be3a17f..dc51fa1812 100644 --- a/src/xrGame/Entity.cpp +++ b/src/xrGame/Entity.cpp @@ -361,6 +361,7 @@ const u32 FORGET_KILLER_TIME = 180000; void CEntity::shedule_Update(u32 dt) { + PROF_EVENT(); inherited::shedule_Update(dt); if (!getDestroy() && !g_Alive() && (m_killer_id != u16(-1))) { diff --git a/src/xrGame/Entity.h b/src/xrGame/Entity.h index 0488a3c252..e92c41ef9c 100644 --- a/src/xrGame/Entity.h +++ b/src/xrGame/Entity.h @@ -13,6 +13,11 @@ class ENGINE_API CBoneInstance; class CWeaponList; class CPHMovementControl; class CHudItem; +class CActor; +class CAI_Stalker; +class CEntityAlive; +class CInventoryOwner; +class CPhantom; class CEntity : public CPhysicsShellHolder, @@ -62,6 +67,12 @@ class CEntity : virtual ~CEntity(); virtual DLL_Pure* _construct(); virtual CEntity* cast_entity() { return this; } + virtual CActor* cast_actor() { return nullptr; } + virtual CAI_Stalker* cast_stalker() { return nullptr; } + virtual CEntityAlive* cast_entity_alive() { return nullptr; } + virtual CInventoryOwner* cast_inventory_owner() { return nullptr; } + virtual CGameObject* cast_game_object() { return this; } + virtual CPhantom* cast_phantom() { return nullptr; } public: // Core events diff --git a/src/xrGame/Explosive.cpp b/src/xrGame/Explosive.cpp index 82f320166c..017987f9cf 100644 --- a/src/xrGame/Explosive.cpp +++ b/src/xrGame/Explosive.cpp @@ -390,9 +390,8 @@ void CExplosive::Explode() Fvector::generate_orthonormal_basis(explode_matrix.j, explode_matrix.i, explode_matrix.k); explode_matrix.c.set(pos); - CParticlesObject* pStaticPG; - pStaticPG = CParticlesObject::Create(*m_sExplodeParticles, !m_bDynamicParticles); - if (m_bDynamicParticles) m_pExpParticle = pStaticPG; + intrusive_ptr pStaticPG = Particles::Details::Create(*m_sExplodeParticles,!m_bDynamicParticles); + if (m_bDynamicParticles) m_pExpParticle = pStaticPG.get(); pStaticPG->UpdateParent(explode_matrix, vel); pStaticPG->Play(false); @@ -443,13 +442,13 @@ void CExplosive::Explode() //взрывная волна //////////////////////////////// //--------------------------------------------------------------------- - xr_vector ISpatialResult; + xr_vector ISpatialResult; g_SpatialSpace->q_sphere(ISpatialResult, 0, STYPE_COLLIDEABLE, pos, m_fBlastRadius); m_blasted_objects.clear(); for (u32 o_it = 0; o_it < ISpatialResult.size(); o_it++) { - ISpatial* spatial = ISpatialResult[o_it]; + ISpatialShared spatial = ISpatialResult[o_it]; // feel_touch_new(spatial->dcast_CObject()); CPhysicsShellHolder* pGameObject = smart_cast(spatial->dcast_CObject()); @@ -571,7 +570,7 @@ void CExplosive::OnAfterExplosion() if (m_pExpParticle) { m_pExpParticle->Stop(); - CParticlesObject::Destroy(m_pExpParticle); + Particles::Details::Destroy(m_pExpParticle); m_pExpParticle = NULL; } //ликвидировать сам объект @@ -624,6 +623,9 @@ void CExplosive::OnEvent(NET_Packet& P, u16 type) { case GE_GRENADE_EXPLODE: { + if (m_explosion_flags.test(flExploding)) + break; + Fvector pos, normal; u16 parent_id; P.r_u16(parent_id); @@ -877,4 +879,4 @@ void CExplosive::LoadExplosiveSection(CInifile *ini, LPCSTR section) { CExplosive::Load(ini, section); } -#endif \ No newline at end of file +#endif diff --git a/src/xrGame/ExplosiveItem.cpp b/src/xrGame/ExplosiveItem.cpp index 3d644744ec..629acc4ee0 100644 --- a/src/xrGame/ExplosiveItem.cpp +++ b/src/xrGame/ExplosiveItem.cpp @@ -99,9 +99,9 @@ bool CExplosiveItem::shedule_Needed() return (inherited::shedule_Needed() || CDelayedActionFuse::isActive()); } -void CExplosiveItem::renderable_Render() +void CExplosiveItem::renderable_Render(IDSGraphManager* DM) { - inherited::renderable_Render(); + inherited::renderable_Render(DM); } void CExplosiveItem::net_Relcase(CObject* O) diff --git a/src/xrGame/ExplosiveItem.h b/src/xrGame/ExplosiveItem.h index 4baca709cf..d2fda0ed99 100644 --- a/src/xrGame/ExplosiveItem.h +++ b/src/xrGame/ExplosiveItem.h @@ -39,7 +39,7 @@ class CExplosiveItem : virtual bool shedule_Needed(); virtual void UpdateCL(); - virtual void renderable_Render(); + virtual void renderable_Render(IDSGraphManager* DM); virtual void ChangeCondition(float fDeltaCondition) { CInventoryItem::ChangeCondition(fDeltaCondition); }; virtual void StartTimerEffects(); }; diff --git a/src/xrGame/ExplosiveRocket.h b/src/xrGame/ExplosiveRocket.h index ec86fb07df..a286517eb2 100644 --- a/src/xrGame/ExplosiveRocket.h +++ b/src/xrGame/ExplosiveRocket.h @@ -28,6 +28,7 @@ class CExplosiveRocket : virtual CWeapon* cast_weapon() { return NULL; } virtual CGameObject* cast_game_object() { return this; } virtual IDamageSource* cast_IDamageSource() { return CExplosive::cast_IDamageSource(); } + virtual CExplosiveRocket* cast_explosive_rocket() { return this; } virtual void on_activate_physic_shell(); public: @@ -59,7 +60,7 @@ class CExplosiveRocket : virtual void OnH_A_Chield() { inherited::OnH_A_Chield(); } virtual void OnH_B_Chield() { inherited::OnH_B_Chield(); } - virtual void renderable_Render() { inherited::renderable_Render(); } + virtual void renderable_Render(IDSGraphManager* DM) { inherited::renderable_Render(DM); } virtual void make_Interpolation(); virtual void PH_B_CrPr(); // actions & operations before physic correction-prediction steps virtual void PH_I_CrPr(); // actions & operations after correction before prediction steps diff --git a/src/xrGame/Flashlight.cpp b/src/xrGame/Flashlight.cpp index 9cc1aead1e..cb75ca8acc 100644 --- a/src/xrGame/Flashlight.cpp +++ b/src/xrGame/Flashlight.cpp @@ -85,6 +85,9 @@ BOOL CFlashlight::net_Spawn(CSE_Abstract* DC) light_render->set_type((IRender_Light::LT)(READ_IF_EXISTS(pSettings, r_u8, m_light_section, "type", 2))); light_omni->set_type((IRender_Light::LT)(READ_IF_EXISTS(pSettings, r_u8, m_light_section, "omni_type", 1))); + light_render->set_shadow(true); + light_omni->set_shadow(false); + light_render->set_is_playerlight(true); // SSS23: Is a player light return TRUE; diff --git a/src/xrGame/FoodItem.h b/src/xrGame/FoodItem.h index 76a727ccd3..f9c2bcada1 100644 --- a/src/xrGame/FoodItem.h +++ b/src/xrGame/FoodItem.h @@ -8,6 +8,8 @@ class CFoodItem : public CEatableItemObject public: CFoodItem(); virtual ~CFoodItem(); - + + virtual CFoodItem* cast_food_item() { return this; } + DECLARE_SCRIPT_REGISTER_FUNCTION }; diff --git a/src/xrGame/GameObject.cpp b/src/xrGame/GameObject.cpp index 2c01f4156b..22fadc316c 100644 --- a/src/xrGame/GameObject.cpp +++ b/src/xrGame/GameObject.cpp @@ -87,13 +87,7 @@ void CGameObject::init() void CGameObject::Load(LPCSTR section) { inherited::Load(section); - ISpatial* self = smart_cast(this); - if (self) - { - // #pragma todo("to Dima: All objects are visible for AI ???") - // self->spatial.type |= STYPE_VISIBLEFORAI; - self->spatial.type &= ~STYPE_REACTTOSOUND; - } + SpatialComponent->spatial.type &= ~STYPE_REACTTOSOUND; } void CGameObject::reinit() @@ -132,8 +126,12 @@ void CGameObject::net_Destroy() xr_delete(m_ini_file); m_script_clsid = -1; - if (Visual() && smart_cast(Visual())) - smart_cast(Visual())->Callback(0, 0); + if (Visual() && Visual()->dcast_PKinematics()) + { + IKinematics* K = Visual()->dcast_PKinematics(); + K->Callback(0, 0); + ::Render->remove_SkeletonWallmarksFromObject(K); + } inherited::net_Destroy(); setReady(FALSE); @@ -292,8 +290,7 @@ BOOL CGameObject::net_Spawn(CSE_Abstract* DC) if (visual->flags.test(CSE_Visual::flObstacle)) { - ISpatial* self = smart_cast(this); - self->spatial.type |= STYPE_OBSTACLE; + SpatialComponent->spatial.type |= STYPE_OBSTACLE; } } @@ -379,9 +376,9 @@ BOOL CGameObject::net_Spawn(CSE_Abstract* DC) { m_server_flags = O->m_flags; if (O->m_flags.is(CSE_ALifeObject::flVisibleForAI)) - spatial.type |= STYPE_VISIBLEFORAI; + SpatialComponent->spatial.type |= STYPE_VISIBLEFORAI; else - spatial.type = (spatial.type | STYPE_VISIBLEFORAI) ^ STYPE_VISIBLEFORAI; + SpatialComponent->spatial.type = (SpatialComponent->spatial.type | STYPE_VISIBLEFORAI) ^ STYPE_VISIBLEFORAI; } reload(*cNameSect()); @@ -427,6 +424,16 @@ BOOL CGameObject::net_Spawn(CSE_Abstract* DC) if (l_tpALifeObject && ai().game_graph().valid_vertex_id(l_tpALifeObject->m_tGraphID)) ai_location().game_vertex(l_tpALifeObject->m_tGraphID); + if (!_valid(Position())) + { + Fvector vertex_pos = ai().level_graph().vertex_position(ai_location().level_vertex_id()); + Msg("! [%s]: %s has invalid Position[%f,%f,%f] level_vertex_id[%u][%f,%f,%f]", __FUNCTION__, cName().c_str(), Position().x, Position().y, Position().z, ai_location().level_vertex_id(), vertex_pos.x, vertex_pos.y, vertex_pos.z); + Position().set(vertex_pos); + CSE_ALifeObject* const se_obj = smart_cast(E); + if (se_obj != nullptr) + se_obj->o_Position.set(Position()); + } + validate_ai_locations(false); // validating position @@ -624,7 +631,7 @@ void CGameObject::setup_parent_ai_locations(bool assign_position) { // CGameObject *l_tpGameObject = static_cast(H_Root()); VERIFY(H_Parent()); - CGameObject* l_tpGameObject = static_cast(H_Parent()); + CGameObject* l_tpGameObject = H_Parent()->cast_game_object(); VERIFY(l_tpGameObject); // get parent's position @@ -700,7 +707,7 @@ void CGameObject::validate_ai_locations(bool decrement_reference) void CGameObject::spatial_move() { - if (H_Parent()) + if (H_Parent() && !getVisible() && !getEnabled()) setup_parent_ai_locations(); else if (Visual()) validate_ai_locations(); @@ -745,16 +752,15 @@ void CGameObject::dbg_DrawSkeleton () } #endif -void CGameObject::renderable_Render() +void CGameObject::renderable_Render(IDSGraphManager* DM) { - inherited::renderable_Render(); - ::Render->set_Transform(&XFORM()); - ::Render->add_Visual(Visual()); + inherited::renderable_Render(DM); + DM->add_Dynamic(Visual(), &XFORM()); Visual()->getVisData().hom_frame = Device.dwFrame; - RenderAttachments(); + RenderAttachments(DM); } -void CGameObject::RenderAttachments() +void CGameObject::RenderAttachments(IDSGraphManager* DM) { if (m_script_attachments.size()) { @@ -763,7 +769,7 @@ void CGameObject::RenderAttachments() script_attachment* att = pair.second; if (att->GetType() == eSA_World) { - att->Render(Visual()->dcast_PKinematics(), &XFORM()); + att->Render(Visual()->dcast_PKinematics(), &XFORM(), DM); if (::Render->get_generation() == ::Render->GENERATION_R1) g_pGamePersistent->AttachmentUIsToRender.push_back(att); @@ -1076,6 +1082,7 @@ void CGameObject::DestroyObject() void CGameObject::shedule_Update(u32 dt) { + PROF_EVENT(); //уничтожить if (NeedToDestroyObject()) { diff --git a/src/xrGame/GameObject.h b/src/xrGame/GameObject.h index 0a44bdbe37..7b2e3d862b 100644 --- a/src/xrGame/GameObject.h +++ b/src/xrGame/GameObject.h @@ -46,6 +46,44 @@ class CFlashlight; class IKinematics; class script_attachment; class CMissile; +class CExplosiveRocket; +class CGrenade; +class CUsableScriptObject; +class CBreakableObject; +class CHudItem; +class CCustomOutfit; +class CHelmet; +class CCustomDetector; +class CWeaponAmmo; +class CWeaponBinoculars; +class CWeaponKnife; +class CWeaponMagazined; +class CWeaponMagazinedWGrenade; +class CWeaponBM16; +class CWeaponRPG7; +class CWeaponRG6; +class CTorch; +class CBolt; +class CPda; +class CInventoryBox; +class CSpectator; +class CSilencer; +class CScope; +class CGrenadeLauncher; +class CProjector; +class CLevelChanger; +class CPhysicItem; +class CEatableItem; +class CScriptZone; +class CHelicopter; +class CHangingLamp; +class CPhraseDialogManager; +class CBackpack; +class CClimableObject; +class CPhysicObject; +class CTeamBaseZone; +class CPhantom; +class CAI_Trader; template class CScriptCallbackEx; @@ -70,29 +108,67 @@ class CGameObject : virtual ~CGameObject(); public: //functions used for avoiding most of the smart_cast - virtual CAttachmentOwner* cast_attachment_owner() { return NULL; } - virtual CInventoryOwner* cast_inventory_owner() { return NULL; } - virtual CInventoryItem* cast_inventory_item() { return NULL; } - virtual CEntity* cast_entity() { return NULL; } - virtual CEntityAlive* cast_entity_alive() { return NULL; } - virtual CActor* cast_actor() { return NULL; } virtual CGameObject* cast_game_object() { return this; } - virtual CCustomZone* cast_custom_zone() { return NULL; } - virtual CPhysicsShellHolder* cast_physics_shell_holder() { return NULL; } - virtual IInputReceiver* cast_input_receiver() { return NULL; } - virtual CParticlesPlayer* cast_particles_player() { return NULL; } - virtual CArtefact* cast_artefact() { return NULL; } - virtual CCustomMonster* cast_custom_monster() { return NULL; } - virtual CAI_Stalker* cast_stalker() { return NULL; } - virtual CScriptEntity* cast_script_entity() { return NULL; } - virtual CWeapon* cast_weapon() { return NULL; } - virtual CMissile* cast_missile() { return NULL; } - virtual CFlashlight* cast_flashlight() { return NULL; } - virtual CExplosive* cast_explosive() { return NULL; } - virtual CSpaceRestrictor* cast_restrictor() { return NULL; } - virtual CAttachableItem* cast_attachable_item() { return NULL; } - virtual CHolderCustom* cast_holder_custom() { return NULL; } - virtual CBaseMonster* cast_base_monster() { return NULL; } + virtual CAttachmentOwner* cast_attachment_owner() { return nullptr; } + virtual CInventoryOwner* cast_inventory_owner() { return nullptr; } + virtual CInventoryItem* cast_inventory_item() { return nullptr; } + virtual CEntity* cast_entity() { return nullptr; } + virtual CEntityAlive* cast_entity_alive() { return nullptr; } + virtual CActor* cast_actor() { return nullptr; } + virtual CCustomZone* cast_custom_zone() { return nullptr; } + virtual CPhysicsShellHolder* cast_physics_shell_holder() { return nullptr; } + virtual IInputReceiver* cast_input_receiver() { return nullptr; } + virtual CParticlesPlayer* cast_particles_player() { return nullptr; } + virtual CArtefact* cast_artefact() { return nullptr; } + virtual CCustomMonster* cast_custom_monster() { return nullptr; } + virtual CAI_Stalker* cast_stalker() { return nullptr; } + virtual CScriptEntity* cast_script_entity() { return nullptr; } + virtual CWeapon* cast_weapon() { return nullptr; } + virtual CExplosive* cast_explosive() { return nullptr; } + virtual CSpaceRestrictor* cast_restrictor() { return nullptr; } + virtual CAttachableItem* cast_attachable_item() { return nullptr; } + virtual CHolderCustom* cast_holder_custom() { return nullptr; } + virtual CBaseMonster* cast_base_monster() { return nullptr; } + virtual CCar* cast_car() { return nullptr; } + virtual CMissile* cast_missile() { return nullptr; } + virtual CExplosiveRocket* cast_explosive_rocket() { return nullptr; } + virtual CGrenade* cast_grenade() { return nullptr; } + virtual CUsableScriptObject* cast_usable_script_object() { return this; } + virtual CBreakableObject* cast_breakable_object() { return nullptr; } + virtual CHudItem* cast_hud_item() { return nullptr; } + virtual CCustomOutfit* cast_outfit() { return nullptr; } + virtual CHelmet* cast_helmet() { return nullptr; } + virtual CCustomDetector* cast_custom_detector() { return nullptr; } + virtual CWeaponAmmo* cast_weapon_ammo() { return nullptr; } + virtual CWeaponBinoculars* cast_weapon_binoculars() { return nullptr; } + virtual CWeaponKnife* cast_weapon_knife() { return nullptr; } + virtual CWeaponMagazined* cast_weapon_magazined() { return nullptr; } + virtual CWeaponMagazinedWGrenade* cast_weapon_magazined_w_grenade() { return nullptr; } + virtual CWeaponBM16* cast_weapon_bm16() { return nullptr; } + virtual CWeaponRPG7* cast_weapon_rpg7() { return nullptr; } + virtual CWeaponRG6* cast_weapon_rg6() { return nullptr; } + virtual CTorch* cast_torch() { return nullptr; } + virtual CBolt* cast_bolt() { return nullptr; } + virtual CPda* cast_pda() { return nullptr; } + virtual CInventoryBox* cast_inventory_box() { return nullptr; } + virtual CSpectator* cast_spectator() { return nullptr; } + virtual CSilencer* cast_addon_silencer() { return nullptr; } + virtual CScope* cast_addon_scope() { return nullptr; } + virtual CGrenadeLauncher* cast_addon_grenade_launcher() { return nullptr; } + virtual CProjector* cast_projector() { return nullptr; } + virtual CLevelChanger* cast_level_changer() { return nullptr; } + virtual CPhysicItem* cast_physics_item() { return nullptr; } + virtual CEatableItem* cast_eatable_item() { return nullptr; } + virtual CScriptZone* cast_script_zone() { return nullptr; } + virtual CHelicopter* cast_helicopter() { return nullptr; } + virtual CHangingLamp* cast_hanging_lamp() { return nullptr; } + virtual CPhraseDialogManager* cast_phrase_dialog_manager() { return nullptr; } + virtual CBackpack* cast_backpack() { return nullptr; } + virtual CClimableObject* cast_climable_object() { return nullptr; } + virtual CPhysicObject* cast_physics_object() { return nullptr; } + virtual CTeamBaseZone* cast_team_base_zone() { return nullptr; } + virtual CPhantom* cast_phantom() { return nullptr; } + virtual CAI_Trader* cast_trader() { return nullptr; } public: virtual bool feel_touch_on_contact(CObject*) { return TRUE; } @@ -127,8 +203,8 @@ class CGameObject : virtual void shedule_Update(u32 dt); virtual bool shedule_Needed(); - virtual void renderable_Render(); - virtual void RenderAttachments(); + virtual void renderable_Render(IDSGraphManager* DM); + virtual void RenderAttachments(IDSGraphManager* DM); virtual void OnEvent(NET_Packet& P, u16 type); virtual void Hit(SHit* pHDS) diff --git a/src/xrGame/GamePersistent.cpp b/src/xrGame/GamePersistent.cpp index 19a8afb755..ae8b99a2f5 100644 --- a/src/xrGame/GamePersistent.cpp +++ b/src/xrGame/GamePersistent.cpp @@ -10,8 +10,6 @@ #include "UICursor.h" #include "game_base_space.h" #include "level.h" -#include "ParticlesObject.h" -#include "game_base_space.h" #include "stalker_animation_data_storage.h" #include "stalker_velocity_holder.h" @@ -42,6 +40,9 @@ #endif // _EDITOR #include "gametype_chooser.h" +extern BOOL mt_Scheduler; +extern BOOL mt_SchedulerRT; + //#ifdef DEBUG_MEMORY_MANAGER // static void * ode_alloc (size_t size) { return Memory.mem_alloc(size,"ODE"); } // static void * ode_realloc (void *ptr, size_t oldsize, size_t newsize) { return Memory.mem_realloc(ptr,newsize,"ODE"); } @@ -66,8 +67,7 @@ CGamePersistent::CGamePersistent(void) ambient_effect_wind_out_time = 0.f; ambient_effect_wind_on = false; - ZeroMemory(ambient_sound_next_time, sizeof(ambient_sound_next_time)); - + ambient_sound_next_time.assign(32, 0); m_pUI_core = NULL; m_pMainMenu = NULL; @@ -83,7 +83,7 @@ CGamePersistent::CGamePersistent(void) //dSetFreeHandler (ode_free ); // - BOOL bDemoMode = (0 != strstr(Core.Params, "-demomode ")); + BOOL bDemoMode = Core.ParamsData.test(ECoreParams::demomode); if (bDemoMode) { string256 fname; @@ -158,7 +158,7 @@ void CGamePersistent::OnAppStart() // load game materials GMLib.Load(); init_game_globals(); - __super::OnAppStart(); + inherited::OnAppStart(); m_pUI_core = xr_new(); m_pMainMenu = xr_new(); m_pWallmarksManager = xr_new(); @@ -174,7 +174,7 @@ void CGamePersistent::OnAppEnd() xr_delete(m_pUI_core); xr_delete(m_pWallmarksManager); - __super::OnAppEnd(); + inherited::OnAppEnd(); clean_game_globals(); @@ -183,15 +183,15 @@ void CGamePersistent::OnAppEnd() void CGamePersistent::Start(LPCSTR op) { - __super::Start(op); + inherited::Start(op); } void CGamePersistent::Disconnect() { // destroy ambient particles - CParticlesObject::Destroy(ambient_particles); + Particles::Details::Destroy(ambient_particles); - __super::Disconnect(); + inherited::Disconnect(); // stop all played emitters ::Sound->stop_emitters(); m_game_params.m_e_game_type = eGameIDNoGame; @@ -201,7 +201,7 @@ void CGamePersistent::Disconnect() void CGamePersistent::OnGameStart() { - __super::OnGameStart(); + inherited::OnGameStart(); UpdateGameType(); } @@ -257,7 +257,7 @@ EGameIDs ParseStringToGameType(LPCSTR str) void CGamePersistent::UpdateGameType() { - __super::UpdateGameType(); + inherited::UpdateGameType(); m_game_params.m_e_game_type = ParseStringToGameType(m_game_params.m_game_type); @@ -270,7 +270,7 @@ void CGamePersistent::UpdateGameType() void CGamePersistent::OnGameEnd() { - __super::OnGameEnd(); + inherited::OnGameEnd(); xr_delete(g_stalker_animation_data_storage); xr_delete(g_stalker_velocity_holder); @@ -278,6 +278,7 @@ void CGamePersistent::OnGameEnd() void CGamePersistent::WeathersUpdate() { + PROF_EVENT("CGamePersistent WeathersUpdate"); if (g_pGameLevel && !g_dedicated_server) { CActor* actor = smart_cast(Level().CurrentViewEntity()); @@ -293,14 +294,14 @@ void CGamePersistent::WeathersUpdate() if (env_amb) { CEnvAmbient::SSndChannelVec& vec = env_amb->get_snd_channels(); - CEnvAmbient::SSndChannelVecIt I = vec.begin(); - CEnvAmbient::SSndChannelVecIt E = vec.end(); - for (u32 idx = 0; I != E; ++I, ++idx) + auto I = vec.cbegin(); + const auto E = vec.cend(); + + for (size_t idx = 0; I != E; ++I, ++idx) { CEnvAmbient::SSndChannel& ch = **I; - R_ASSERT(idx<32); - if (ambient_sound_next_time[idx] == 0) //first + if (ambient_sound_next_time[idx] == 0) { ambient_sound_next_time[idx] = Device.dwTimeGlobal + ch.get_rnd_sound_first_time(); } @@ -317,35 +318,15 @@ void CGamePersistent::WeathersUpdate() pos.y += 10.f; snd.play_at_pos(0, pos); -#ifdef DEBUG - if (!snd._handle() && strstr(Core.Params, "-nosound")) - continue; -#endif // DEBUG + if (!snd._handle() || Core.ParamsData.test(ECoreParams::nosound)) + continue; VERIFY(snd._handle()); u32 _length_ms = iFloor(snd.get_length_sec() * 1000.0f); ambient_sound_next_time[idx] = Device.dwTimeGlobal + _length_ms + ch.get_rnd_sound_time(); - // Msg("- Playing ambient sound channel [%s] file[%s]",ch.m_load_section.c_str(),snd._handle()->file_name()); } } - /* - if (Device.dwTimeGlobal > ambient_sound_next_time) - { - ref_sound* snd = env_amb->get_rnd_sound(); - ambient_sound_next_time = Device.dwTimeGlobal + env_amb->get_rnd_sound_time(); - if (snd) - { - Fvector pos; - float angle = ::Random.randF(PI_MUL_2); - pos.x = _cos(angle); - pos.y = 0; - pos.z = _sin(angle); - pos.normalize ().mul(env_amb->get_rnd_sound_dist()).add(Device.vCameraPosition); - pos.y += 10.f; - snd->play_at_pos (0,pos); - } - } - */ + // start effect if ((FALSE == bIndoor) && (0 == ambient_particles) && Device.dwTimeGlobal > ambient_effect_next_time) { @@ -362,7 +343,7 @@ void CGamePersistent::WeathersUpdate() wind_blast_out_time; ambient_effect_wind_on = true; - ambient_particles = CParticlesObject::Create(eff->particles.c_str(), FALSE, false); + ambient_particles = Particles::Details::Create(eff->particles.c_str(),FALSE,false); Fvector pos; Fvector offset = eff->offset; offset.x += Random.randF(0.5f, 5.f) * (Random.randF(0.f, 1.f) < 0.5f ? -1.f : 1.f); @@ -455,7 +436,7 @@ void CGamePersistent::WeathersUpdate() // if particles not playing - destroy if (ambient_particles && !ambient_particles->IsPlaying()) - CParticlesObject::Destroy(ambient_particles); + Particles::Details::Destroy(ambient_particles); } } @@ -464,7 +445,7 @@ bool allow_intro() #ifdef MASTER_GOLD if (g_SASH.IsRunning()) #else // #ifdef MASTER_GOLD - if ((0 != strstr(Core.Params, "-nointro")) || g_SASH.IsRunning()) + if (Core.ParamsData.test(ECoreParams::nointro) || g_SASH.IsRunning()) #endif // #ifdef MASTER_GOLD { return false; @@ -475,14 +456,7 @@ bool allow_intro() bool allow_logo() // AVO: skip NVIDIA and other logos at load time { - if (0 != strstr(Core.Params, "-skiplogo")) - { - return false; - } - else - { - return true; - } + return !Core.ParamsData.test(ECoreParams::skiplogo); } void CGamePersistent::start_logo_intro() @@ -586,7 +560,7 @@ void CGamePersistent::game_loaded() void CGamePersistent::update_game_loaded() { xr_delete(m_intro); - Msg("intro_delete ::update_game_loaded"); + load_screen_renderer.stop(); start_game_intro(); // demonized @@ -641,6 +615,7 @@ extern CUISequencer* g_tutorial2; void CGamePersistent::OnFrame() { + PROF_EVENT("CGamePersistent OnFrame"); if (Device.dwPrecacheFrame == 5 && m_intro_event.empty()) { m_intro_event.bind(this, &CGamePersistent::game_loaded); @@ -753,14 +728,28 @@ void CGamePersistent::OnFrame() } #endif // MASTER_GOLD } - __super::OnFrame(); + inherited::OnFrame(); if (!Device.Paused()) - Engine.Sheduler.Update(); + { + if (!mt_Scheduler) + { + PROF_EVENT("Sheduler"); + ::Engine.Sheduler.Update(); + } + else + { + if (!mt_SchedulerRT) + { + PROF_EVENT("Sheduler RT"); + ::Engine.Sheduler.UpdateInit(); + ::Engine.Sheduler.UpdateRT(); + } + } - // update weathers ambient - if (!Device.Paused()) + // update weathers ambient WeathersUpdate(); + } if (0 != pDemoFile) { @@ -812,6 +801,7 @@ void CGamePersistent::OnEvent(EVENT E, u64 P1, u64 P2) { if (E == eQuickLoad) { + PROF_EVENT("eQuickLoad"); if (Device.Paused()) Device.Pause(FALSE, TRUE, TRUE, "eQuickLoad"); @@ -929,7 +919,10 @@ void CGamePersistent::OnRenderPPUI_PP() void CGamePersistent::LoadTitle(bool change_tip, shared_str map_name) { - pApp->LoadStage(); + { + xrCriticalSectionGuard g(loadTitleCs); + pApp->LoadStage(); + } if (change_tip) { string512 buff; @@ -1003,6 +996,8 @@ void CGamePersistent::RestoreEffectorDOF() // m_dof [4]; // 0-dest 1-current 2-from 3-original void CGamePersistent::UpdateDof() { + PROF_EVENT("CGamePersistent UpdateDof"); + static float diff_far = pSettings->r_float("zone_pick_dof", "far"); //70.0f; static float diff_near = pSettings->r_float("zone_pick_dof", "near"); //-70.0f; diff --git a/src/xrGame/GamePersistent.h b/src/xrGame/GamePersistent.h index c6d6b09351..710d573f42 100644 --- a/src/xrGame/GamePersistent.h +++ b/src/xrGame/GamePersistent.h @@ -13,9 +13,11 @@ class CGamePersistent : public IGame_Persistent, public IEventReceiver { + using inherited = IGame_Persistent; + // ambient particles - CParticlesObject* ambient_particles; - u32 ambient_sound_next_time [32]; //max snd channels + intrusive_ptr ambient_particles; + xr_vector ambient_sound_next_time; //max snd channels u32 ambient_effect_next_time; u32 ambient_effect_stop_time; @@ -31,7 +33,9 @@ class CGamePersistent : EVENT eQuickLoad; Fvector m_dof [4]; // 0-dest 1-current 2-from 3-original - fastdelegate::FastDelegate0<> m_intro_event; + xr_delegate m_intro_event; + + xrCriticalSection loadTitleCs; void xr_stdcall start_logo_intro(); void xr_stdcall update_logo_intro(); diff --git a/src/xrGame/GameTask.cpp b/src/xrGame/GameTask.cpp index d4a30a2cbb..bf3ffd6b8d 100644 --- a/src/xrGame/GameTask.cpp +++ b/src/xrGame/GameTask.cpp @@ -20,11 +20,9 @@ #include "ui/uitexturemaster.h" -CGameTask::CGameTask() +CGameTask::CGameTask() : + m_map_object_id(0), m_TimeToComplete(0), m_priority(0) { - m_map_object_id = 0; - m_TimeToComplete = 0; - m_priority = 0; m_ReceiveTime = 0; m_FinishTime = 0; m_timer_finish = 0; @@ -141,6 +139,7 @@ void CGameTask::ChangeStateCallback() ETaskState CGameTask::UpdateState() { + PROF_EVENT("CGameTask::UpdateState"); if ((m_ReceiveTime != m_TimeToComplete)) { if (Level().GetGameTime() > m_TimeToComplete) @@ -148,24 +147,26 @@ ETaskState CGameTask::UpdateState() return eTaskStateFail; } } - //check fail infos - if (CheckInfo(m_failInfos)) - return eTaskStateFail; - - //check fail functor - if (CheckFunctions(m_fail_lua_functions)) - return eTaskStateFail; - - //check complete infos - if (CheckInfo(m_completeInfos)) - return eTaskStateCompleted; - - - //check complete functor - if (CheckFunctions(m_complete_lua_functions)) - return eTaskStateCompleted; - - + { + PROF_EVENT("check fail infos"); + if (CheckInfo(m_failInfos)) + return eTaskStateFail; + } + { + PROF_EVENT("check fail functor"); + if (CheckFunctions(m_fail_lua_functions)) + return eTaskStateFail; + } + { + PROF_EVENT("check complete infos"); + if (CheckInfo(m_completeInfos)) + return eTaskStateCompleted; + } + { + PROF_EVENT("check complete functor"); + if (CheckFunctions(m_complete_lua_functions)) + return eTaskStateCompleted; + } return GetTaskState(); } diff --git a/src/xrGame/GametaskManager.cpp b/src/xrGame/GametaskManager.cpp index 4c01bfcd9e..7528529a82 100644 --- a/src/xrGame/GametaskManager.cpp +++ b/src/xrGame/GametaskManager.cpp @@ -133,6 +133,7 @@ CGameTask* CGameTaskManager::GiveGameTaskToActor(CGameTask* t, u32 timeToComplet void CGameTaskManager::SetTaskState(CGameTask* t, ETaskState state) { + PROF_EVENT("CGameTaskManager::SetTaskState"); m_flags.set(eChanged, TRUE); t->SetTaskState(state); @@ -160,6 +161,7 @@ void CGameTaskManager::SetTaskState(const shared_str& id, ETaskState state) void CGameTaskManager::UpdateTasks() { + PROF_EVENT("CGameTaskManager::UpdateTasks"); if (Device.Paused()) return; Level().MapManager().DisableAllPointers(); diff --git a/src/xrGame/GraviArtifact.cpp b/src/xrGame/GraviArtifact.cpp index 0225ad8748..abb5dffe3a 100644 --- a/src/xrGame/GraviArtifact.cpp +++ b/src/xrGame/GraviArtifact.cpp @@ -65,7 +65,7 @@ void CGraviArtefact::UpdateCLChild() } } } - else if (H_Parent()) + else if(H_Parent() && IsHidden()) { XFORM().set(H_Parent()->XFORM()); diff --git a/src/xrGame/Grenade.cpp b/src/xrGame/Grenade.cpp index 2224b9c617..daf66b4a09 100644 --- a/src/xrGame/Grenade.cpp +++ b/src/xrGame/Grenade.cpp @@ -3,7 +3,6 @@ #include "../xrphysics/PhysicsShell.h" //.#include "WeaponHUD.h" #include "entity.h" -#include "ParticlesObject.h" #include "actor.h" #include "inventory.h" #include "level.h" @@ -297,6 +296,7 @@ void CGrenade::OnAnimationEnd(u32 state) void CGrenade::UpdateCL() { + PROF_EVENT(); inherited::UpdateCL(); CExplosive::UpdateCL(); diff --git a/src/xrGame/Grenade.h b/src/xrGame/Grenade.h index 081c702144..98de6e3d22 100644 --- a/src/xrGame/Grenade.h +++ b/src/xrGame/Grenade.h @@ -90,9 +90,10 @@ class CGrenade : virtual CMissile* cast_missile() { return this; } virtual CHudItem* cast_hud_item() { return this; } virtual CGameObject* cast_game_object() { return this; } + virtual CGrenade* cast_grenade() { return this; } virtual IDamageSource* cast_IDamageSource() { return CExplosive::cast_IDamageSource(); } - typedef fastdelegate::FastDelegate destroy_callback; + typedef xr_delegate destroy_callback; void set_destroy_callback(destroy_callback callback) { diff --git a/src/xrGame/GrenadeLauncher.cpp b/src/xrGame/GrenadeLauncher.cpp index 3878567b21..381f305285 100644 --- a/src/xrGame/GrenadeLauncher.cpp +++ b/src/xrGame/GrenadeLauncher.cpp @@ -49,7 +49,7 @@ void CGrenadeLauncher::OnH_B_Independent(bool just_before_destroy) inherited::OnH_B_Independent(just_before_destroy); } -void CGrenadeLauncher::renderable_Render() +void CGrenadeLauncher::renderable_Render(IDSGraphManager* DM) { - inherited::renderable_Render(); + inherited::renderable_Render(DM); } diff --git a/src/xrGame/GrenadeLauncher.h b/src/xrGame/GrenadeLauncher.h index 0807fd380c..c6e3488d4f 100644 --- a/src/xrGame/GrenadeLauncher.h +++ b/src/xrGame/GrenadeLauncher.h @@ -22,10 +22,12 @@ class CGrenadeLauncher : public CInventoryItemObject virtual void OnH_B_Independent(bool just_before_destroy); virtual void UpdateCL(); - virtual void renderable_Render(); + virtual void renderable_Render(IDSGraphManager* DM); float GetGrenadeVel() { return m_fGrenadeVel; } + virtual CGrenadeLauncher* cast_addon_grenade_launcher() {return this;} + protected: //стартовая скорость вылета подствольной гранаты float m_fGrenadeVel; diff --git a/src/xrGame/HUDCrosshair.cpp b/src/xrGame/HUDCrosshair.cpp index a1cd77f855..43e97803b3 100644 --- a/src/xrGame/HUDCrosshair.cpp +++ b/src/xrGame/HUDCrosshair.cpp @@ -63,7 +63,7 @@ void CHUDCrosshair::SetDispersion(float d) dispersionRadius = d; } -extern ENGINE_API BOOL g_bRendering; +extern ENGINE_API xr_atomic_bool g_bRendering; static float lerp(float a, float b, float t) { diff --git a/src/xrGame/HUDManager.cpp b/src/xrGame/HUDManager.cpp index 1910d5a846..b402212aeb 100644 --- a/src/xrGame/HUDManager.cpp +++ b/src/xrGame/HUDManager.cpp @@ -23,6 +23,8 @@ #include "player_hud.h" #include "script_attachment_manager.h" +#include "GametaskManager.h" + extern CUIGameCustom* CurrentGameUI() { return g_hud ? HUD().GetGameUI() : nullptr; @@ -125,24 +127,53 @@ CHUDManager::~CHUDManager() } //-------------------------------------------------------------------- +BOOL mt_ui = FALSE; void CHUDManager::OnFrame() { + PROF_EVENT("CHUDManager::OnFrame"); if (!psHUD_Flags.is(HUD_DRAW_RT2)) return; if (!b_online) return; - if (pUIGame) - pUIGame->OnFrame(); + if (!mt_ui) + { + if (pUIGame) + pUIGame->OnFrame(); + } PP.CameraPick(); g_player_hud->OnFrame(); DoPick(PP); } +xrCriticalSection ui_lock; +extern BOOL mt_TaskManager; +void CHUDManager::OnFrameMT() +{ + if (!b_online) + return; + + PROF_EVENT("CHUDManager::OnFrameMT"); + + if (mt_TaskManager && Device.dwPrecacheFrame == 0) + Level().GameTaskManager().UpdateTasks(); + + if (!psHUD_Flags.is(HUD_DRAW_RT2)) + return; + + if (mt_ui) + { + xrCriticalSectionGuard guard(&ui_lock); + if (pUIGame) + pUIGame->OnFrame(); + } +} + //-------------------------------------------------------------------- -void CHUDManager::Render_First() +//R1 Actor Shadow +void CHUDManager::Render_First(IDSGraphManager* DM) { if (!psHUD_Flags.is(HUD_WEAPON | HUD_WEAPON_RT | HUD_WEAPON_RT2 | HUD_DRAW_RT2))return; if (0 == pUIGame) return; @@ -153,10 +184,12 @@ void CHUDManager::Render_First() if (A && !A->HUDview()) return; // only shadow - ::Render->set_Invisible(TRUE); - ::Render->set_Object(O->H_Root()); - O->renderable_Render(); - ::Render->set_Invisible(FALSE); + DM->set_Invisible(true); + DM->set_Object(O->H_Root()); + + O->renderable_Render(DM); + + DM->set_Invisible(); } bool need_render_hud() @@ -175,19 +208,19 @@ bool need_render_hud() return true; } -void CHUDManager::Render_Last() +void CHUDManager::Render_Last(IDSGraphManager* DM) { if (0 == pUIGame) return; - if (g_actor) g_actor->RenderCamAttached(); + if (g_actor) g_actor->RenderCamAttached(DM); if (!psHUD_Flags.is(HUD_WEAPON | HUD_WEAPON_RT | HUD_WEAPON_RT2 | HUD_DRAW_RT2))return; if (!need_render_hud()) return; CObject* O = g_pGameLevel->CurrentViewEntity(); // hud itself - ::Render->set_HUD(TRUE); - ::Render->set_Object(O->H_Root()); - O->OnHUDDraw(this); - ::Render->set_HUD(FALSE); + DM->set_HUD(true); + DM->set_Object(O->H_Root()); + O->OnHUDDraw(this, DM); + DM->set_HUD(); } void CHUDManager::Render_R1_Attachment_UI() @@ -246,6 +279,7 @@ extern ENGINE_API BOOL bShowPauseString; //отрисовка элементов интерфейса void CHUDManager::RenderUI() { + PROF_EVENT("CHUDManager::RenderUI"); if (!psHUD_Flags.is(HUD_DRAW_RT2)) return; @@ -255,7 +289,10 @@ void CHUDManager::RenderUI() { HitMarker.Render(); if (pUIGame) + { + xrCriticalSectionGuard guard(&ui_lock); pUIGame->Render(); + } UI().RenderFont(); } @@ -454,19 +491,22 @@ void CHUDManager::OnScreenResolutionChanged() funct(); } +BOOL hud_frequent_updates = TRUE; void CHUDManager::OnDisconnected() { b_online = false; - if (pUIGame) - Device.seqFrame.Remove(pUIGame); + if (hud_frequent_updates) + if (pUIGame) + Device.seqFrame.Remove(pUIGame); } void CHUDManager::OnConnected() { if (b_online) return; b_online = true; - if (pUIGame) - Device.seqFrame.Add(pUIGame, REG_PRIORITY_LOW - 1000); + if (hud_frequent_updates) + if (pUIGame) + Device.seqFrame.Add(pUIGame, REG_PRIORITY_LOW - 1000); } void CHUDManager::net_Relcase(CObject* obj) @@ -476,8 +516,8 @@ void CHUDManager::net_Relcase(CObject* obj) HitMarker.net_Relcase(obj); - VERIFY(g_player_hud); - g_player_hud->net_Relcase(obj); + if (g_player_hud) + g_player_hud->net_Relcase(obj); #ifdef DEBUG DBG_PH_NetRelcase( obj ); diff --git a/src/xrGame/HUDManager.h b/src/xrGame/HUDManager.h index f7a31730cd..40eec3ed8a 100644 --- a/src/xrGame/HUDManager.h +++ b/src/xrGame/HUDManager.h @@ -66,10 +66,11 @@ class CHUDManager : CHUDManager(); virtual ~CHUDManager(); virtual void OnFrame(); + virtual void OnFrameMT(); virtual void OnEvent(EVENT E, u64 P1, u64 P2); - virtual void Render_First(); - virtual void Render_Last(); + virtual void Render_First(IDSGraphManager* DM); + virtual void Render_Last(IDSGraphManager* DM); virtual void RenderUI(); diff --git a/src/xrGame/HUDTarget.cpp b/src/xrGame/HUDTarget.cpp index 98dafbbfd0..34024da150 100644 --- a/src/xrGame/HUDTarget.cpp +++ b/src/xrGame/HUDTarget.cpp @@ -9,7 +9,7 @@ Flags32 psCrosshair_Flags = {}; -extern ENGINE_API BOOL g_bRendering; +extern ENGINE_API xr_atomic_bool g_bRendering; u32 g_crosshair_color = C_WHITE; CrosshairSettings g_crosshair_camera_far = CrosshairSettings( @@ -377,6 +377,9 @@ void CHUDTarget::Render() if (!m_bShowCrosshair) return; + if (load_screen_renderer.IsActive()) + return; + CHUDManager& hud = HUD(); bool firepos_active = hud.FireposActive(); bool aimpos_active = hud.AimposActive(); diff --git a/src/xrGame/HangingLamp.cpp b/src/xrGame/HangingLamp.cpp index 6814409f35..a167315c79 100644 --- a/src/xrGame/HangingLamp.cpp +++ b/src/xrGame/HangingLamp.cpp @@ -249,27 +249,30 @@ void CHangingLamp::UpdateCL() if (m_pPhysicsShell) m_pPhysicsShell->InterpolateGlobalTransform(&XFORM()); - if (Alive() && light_render->get_active()) + if (Alive()) { - if (Visual()) PKinematics(Visual())->CalculateBones(); - if (NeedUpdate) { // update T&R from light (main) bone Fmatrix xf; if (light_bone != BI_NONE) { - Fmatrix& M = smart_cast(Visual())->LL_GetTransform(light_bone); + Fmatrix& M = smart_cast(Visual())->LL_GetTransform_safed(light_bone); xf.mul(XFORM(), M); - VERIFY(!fis_zero(DET(xf))); + if (fis_zero(DET(xf))) + xf = XFORM(); } else { xf.set(XFORM()); } - light_render->set_rotation(xf.k, xf.i); + if(light_render->get_type()!=IRender_Light::POINT) + light_render->set_rotation(xf.k, xf.i); + light_render->set_position(xf.c); - if (glow_render)glow_render->set_position(xf.c); + + if (glow_render) + glow_render->set_position(xf.c); // update T&R from ambient bone if (light_ambient) @@ -278,7 +281,7 @@ void CHangingLamp::UpdateCL() { if (ambient_bone != BI_NONE) { - Fmatrix& M = smart_cast(Visual())->LL_GetTransform(ambient_bone); + Fmatrix& M = smart_cast(Visual())->LL_GetTransform_safed(ambient_bone); xf.mul(XFORM(), M); VERIFY(!fis_zero(DET(xf))); } @@ -500,7 +503,7 @@ void CHangingLamp::CreateBody(CSE_ALifeObjectHangingLamp* lamp) string64 fixed_bone; _GetItem(fixed_bones, i, fixed_bone); u16 fixed_bone_id = pKinematics->LL_BoneID(fixed_bone); - R_ASSERT2(BI_NONE!=fixed_bone_id, "wrong fixed bone") ; + R_ASSERT2(BI_NONE != fixed_bone_id, make_string("wrong fixed bone [%s] for object with visual [%s]", fixed_bone, pKinematics->getDebugName().c_str()).c_str()); bone_map.insert(mk_pair(fixed_bone_id, physicsBone())); } } diff --git a/src/xrGame/HangingLamp.h b/src/xrGame/HangingLamp.h index c9fa536d87..e466970bd1 100644 --- a/src/xrGame/HangingLamp.h +++ b/src/xrGame/HangingLamp.h @@ -80,6 +80,8 @@ class CHangingLamp : virtual void net_Import(NET_Packet& P); virtual BOOL UsedAI_Locations(); + virtual CHangingLamp* cast_hanging_lamp() { return this; } + virtual void Center(Fvector& C) const; virtual float Radius() const; DECLARE_SCRIPT_REGISTER_FUNCTION diff --git a/src/xrGame/Helicopter.cpp b/src/xrGame/Helicopter.cpp index 306c768be9..36263d23f4 100644 --- a/src/xrGame/Helicopter.cpp +++ b/src/xrGame/Helicopter.cpp @@ -21,8 +21,10 @@ CHelicopter::CHelicopter() m_light_render = NULL; m_lanim = NULL; - ISpatial* self = smart_cast(this); - if (self) self->spatial.type |= STYPE_VISIBLEFORAI; + SpatialComponent->spatial.type |= STYPE_VISIBLEFORAI; + + // demonized: check if object is eligible for bone calc optimization + SpatialComponent->canOptimizeCalculateBones = false; m_movement.parent = this; m_body.parent = this; @@ -244,17 +246,7 @@ BOOL CHelicopter::net_Spawn(CSE_Abstract* DC) Device.seqRender.Add(this,REG_PRIORITY_LOW-1); #endif - renderable.visual->flags.set(IRenderVisualFlags::eIgnoreOptimization, TRUE); - - xr_vector* children = renderable.visual->get_children(); - - if (children) - { - for (auto* child : *children) - { - child->flags.set(IRenderVisualFlags::eIgnoreOptimization, TRUE); - } - } + renderable.visual->MarkIgnoreOptimization(TRUE); return TRUE; } @@ -269,7 +261,7 @@ void CHelicopter::net_Destroy() CPHDestroyable::RespawnInit(); m_engineSound.stop(); m_brokenSound.stop(); - CParticlesObject::Destroy(m_pParticle); + Particles::Details::Destroy(m_pParticle); m_light_render.destroy(); m_movement.net_Destroy(); #ifdef DEBUG diff --git a/src/xrGame/Helicopter2.cpp b/src/xrGame/Helicopter2.cpp index 62f45a4d6e..6a7beef184 100644 --- a/src/xrGame/Helicopter2.cpp +++ b/src/xrGame/Helicopter2.cpp @@ -50,7 +50,7 @@ void CHelicopter::TurnEngineSound(bool bOn) void CHelicopter::StartFlame() { if (m_pParticle)return; - m_pParticle = CParticlesObject::Create(*m_smoke_particle,FALSE); + m_pParticle = Particles::Details::Create(*m_smoke_particle,FALSE).get(); Fvector zero_vector; zero_vector.set(0.f, 0.f, 0.f); @@ -105,7 +105,7 @@ void CHelicopter::ExplodeHelicopter() if (m_pParticle) { m_pParticle->Stop(); - CParticlesObject::Destroy(m_pParticle); + Particles::Details::Destroy(m_pParticle); } if (CPHDestroyable::CanDestroy()) CPHDestroyable::Destroy(ID(), "physic_destroyable_object"); diff --git a/src/xrGame/HelicopterMovementManager.cpp b/src/xrGame/HelicopterMovementManager.cpp index 064c0584a1..f217e56c7f 100644 --- a/src/xrGame/HelicopterMovementManager.cpp +++ b/src/xrGame/HelicopterMovementManager.cpp @@ -228,7 +228,7 @@ void SHeliMovementState::goPatrolByPatrolPath(LPCSTR path_name, int start_idx) patrol_begin_idx = start_idx; patrol_path_name = path_name; - currPatrolPath = ai().patrol_paths().path(patrol_path_name); + currPatrolPath = ai().patrol_paths().safe_path(patrol_path_name, false, true); need_to_del_path = false; currPatrolVertex = currPatrolPath->vertex(patrol_begin_idx); @@ -307,7 +307,7 @@ void SHeliMovementState::load(IReader& input_packet) if (type == eMovPatrolPath) { - currPatrolPath = ai().patrol_paths().path(patrol_path_name); + currPatrolPath = ai().patrol_paths().safe_path(patrol_path_name, false, true); int idx = input_packet.r_s32(); currPatrolVertex = currPatrolPath->vertex(idx); } diff --git a/src/xrGame/HolderEntityObject.cpp b/src/xrGame/HolderEntityObject.cpp index cbc8db2b45..fde50a6807 100644 --- a/src/xrGame/HolderEntityObject.cpp +++ b/src/xrGame/HolderEntityObject.cpp @@ -131,9 +131,9 @@ void CHolderEntityObject::cam_Update(float dt, float fov) Level().Cameras().UpdateFromCamera(Camera()); } -void CHolderEntityObject::renderable_Render() +void CHolderEntityObject::renderable_Render(IDSGraphManager* DM) { - inheritedPH::renderable_Render(); + inheritedPH::renderable_Render(DM); } void CHolderEntityObject::Action(u16 id, u32 flags) diff --git a/src/xrGame/HolderEntityObject.h b/src/xrGame/HolderEntityObject.h index 1be41124f4..5ae3d51f78 100644 --- a/src/xrGame/HolderEntityObject.h +++ b/src/xrGame/HolderEntityObject.h @@ -60,7 +60,7 @@ class CHolderEntityObject : public CPhysicsShellHolder, virtual CInventory* GetInventory() { return NULL; }; virtual void cam_Update(float dt, float fov = 90.0f); - virtual void renderable_Render(); + virtual void renderable_Render(IDSGraphManager* DM); virtual void attach_actor_script(bool bForce = false); virtual void detach_actor_script(bool bForce = false); diff --git a/src/xrGame/HudItem.cpp b/src/xrGame/HudItem.cpp index a11a4eaf87..c4d51092b2 100644 --- a/src/xrGame/HudItem.cpp +++ b/src/xrGame/HudItem.cpp @@ -116,10 +116,10 @@ void CHudItem::PlaySound(LPCSTR alias, const Fvector& position, u8 index) //-Alundaio -void CHudItem::renderable_Render() +void CHudItem::renderable_Render(IDSGraphManager* DM) { UpdateXForm(); - BOOL _hud_render = ::Render->get_HUD() && GetHUDmode(); + BOOL _hud_render = DM->get_HUD() && GetHUDmode(); if (_hud_render && !IsHidden()) { @@ -128,16 +128,18 @@ void CHudItem::renderable_Render() { if (!object().H_Parent() || (!_hud_render && !IsHidden())) { - on_renderable_Render(); + on_renderable_Render(DM); debug_draw_firedeps(); } else if (object().H_Parent()) { CInventoryOwner* owner = smart_cast(object().H_Parent()); - VERIFY(owner); - CInventoryItem* self = smart_cast(this); - if (owner->attached(self)) - on_renderable_Render(); + if (owner) + { + CInventoryItem* self = smart_cast(this); + if (owner->attached(self)) + on_renderable_Render(DM); + } } } } @@ -1227,7 +1229,7 @@ CAnonHudItem::~CAnonHudItem() { } void CAnonHudItem::UpdateXForm() { } -void CAnonHudItem::on_renderable_Render() { } +void CAnonHudItem::on_renderable_Render(IDSGraphManager* DM) { } #ifdef ATTACHMENT_HUD_VISBOX void VisualCallbackHud(IKinematics* tpKinematics) diff --git a/src/xrGame/HudItem.h b/src/xrGame/HudItem.h index a1d97315be..525bf297c5 100644 --- a/src/xrGame/HudItem.h +++ b/src/xrGame/HudItem.h @@ -5,6 +5,19 @@ class CPhysicItem; class NET_Packet; class CInventoryItem; class CMotionDef; +class CCustomDetector; +class CWeaponMagazined; +class CWeaponMagazinedWGrenade; +class CWeaponBinoculars; +class CWeaponKnife; +class CWeaponBM16; +class CWeaponRPG7; +class CWeaponRG6; +class CWeapon; +class CMissile; +class CBolt; +class CGrenade; +class CPhysicsShellHolder; class CUIWindow; #include "actor_defs.h" @@ -187,7 +200,7 @@ class CHudItem : public CHUDState virtual void PlayAnimIdleSprint(); virtual void UpdateCL(); - virtual void renderable_Render(); + virtual void renderable_Render(IDSGraphManager* DM); virtual void UpdateHudAdditional(Fmatrix& trans); @@ -270,7 +283,7 @@ class CHudItem : public CHUDState IC u32 animation_slot() { return m_animation_slot; } - virtual void on_renderable_Render() = 0; + virtual void on_renderable_Render(IDSGraphManager* DM) = 0; virtual void debug_draw_firedeps() { @@ -287,6 +300,21 @@ class CHudItem : public CHUDState float m_nearwall_ofs; virtual CHudItem* cast_hud_item() { return this; } + virtual CCustomDetector* cast_custom_detector() { return nullptr; } + virtual CWeaponBinoculars* cast_weapon_binoculars() { return nullptr; } + virtual CWeaponKnife* cast_weapon_knife() { return nullptr; } + virtual CWeaponMagazined* cast_weapon_magazined() { return nullptr; } + virtual CWeaponMagazinedWGrenade* cast_weapon_magazined_w_grenade() { return nullptr; } + virtual CWeaponBM16* cast_weapon_bm16() { return nullptr; } + virtual CWeapon* cast_weapon() { return nullptr; } + virtual CWeaponRPG7* cast_weapon_rpg7() { return nullptr; } + virtual CWeaponRG6* cast_weapon_rg6() { return nullptr; } + virtual CGrenade* cast_grenade() { return nullptr; } + virtual CMissile* cast_missile() { return nullptr; } + virtual CBolt* cast_bolt() { return nullptr; } + virtual CInventoryItem* cast_inventory_item() { return nullptr; } + virtual CPhysicsShellHolder* cast_physics_shell_holder() { return nullptr; } + virtual CPhysicItem* cast_physics_item() { return nullptr; } virtual bool PlayAnimCrouchIdleMoving(); //AVO: new crouch idle animation bool HudAnimationExist(LPCSTR anim_name); @@ -332,8 +360,8 @@ class CAnonHudItem : public CHudItem CAnonHudItem(); virtual ~CAnonHudItem(); virtual void UpdateXForm(); - virtual void on_renderable_Render(); + virtual void on_renderable_Render(IDSGraphManager* DM); virtual bool TryPlayAnimIdle() { return false; } virtual void UpdateHudAdditional(Fmatrix& trans) { } DECLARE_SCRIPT_REGISTER_FUNCTION -}; \ No newline at end of file +}; diff --git a/src/xrGame/IKLimbsController.cpp b/src/xrGame/IKLimbsController.cpp index bfc1b50f4d..067cd163e6 100644 --- a/src/xrGame/IKLimbsController.cpp +++ b/src/xrGame/IKLimbsController.cpp @@ -346,12 +346,50 @@ void _stdcall CIKLimbsController::IKVisualCallback(IKinematics* K) return; #endif - CGameObject* O = ((CGameObject*)K->GetUpdateCallbackParam()); - CPhysicsShellHolder* Sh = smart_cast(O); - VERIFY(Sh); - CIKLimbsController* ik = Sh->character_ik_controller(); - VERIFY(ik); - ik->Calculate(); + if(CGameObject* O = (CGameObject*)K->GetUpdateCallbackParam()) + { + if(CPhysicsShellHolder* Sh = O->cast_physics_shell_holder()) + { + if(CIKLimbsController* ik = Sh->character_ik_controller()) + { + if(!Sh->m_pPhysicsShell) + { + Fvector ce; + O->Center(ce); + if (Render->ViewBase.testSphere_dirty(ce, O->Radius())) + { + if (Device.vCameraPosition.distance_to_sqr(O->Position()) > 3000.f) + { + //if (Device.dwFrame < ik->optimize_frame) + IKinematics* K = O->Visual()->dcast_PKinematics(); + u16 root = K->LL_GetBoneRoot(); + CBoneInstance& root_bi = K->LL_GetBoneInstance(root); + root_bi.reset_callback(); + return; + //ik->optimize_frame = Device.dwFrame + Random.randI(8); + } + + { + PROF_EVENT("IK_UPDATE_CALCULATE"); + ik->_pose_extrapolation.update(O->XFORM()); + for (CIKLimb& limb : ik->_bone_chains) + ik->LimbUpdate(limb); + + ik->Calculate(); + } + + } + else + { + IKinematics* K = O->Visual()->dcast_PKinematics(); + u16 root = K->LL_GetBoneRoot(); + CBoneInstance& root_bi = K->LL_GetBoneInstance(root); + root_bi.reset_callback(); + } + } + } + } + } } void CIKLimbsController::PlayLegs(CBlend* b) @@ -381,11 +419,6 @@ void CIKLimbsController::Update() skeleton_animated->UpdateTracks(); update_blend(m_legs_blend); - _pose_extrapolation.update(m_object->XFORM()); - xr_vector::iterator i = _bone_chains.begin(), e = _bone_chains.end(); - for (; e != i; ++i) - LimbUpdate(*i); - /* Fmatrix predict; _pose_extrapolation.extrapolate( predict, Device.fTimeGlobal ); diff --git a/src/xrGame/InfoDocument.cpp b/src/xrGame/InfoDocument.cpp index 85f3cff50b..c29e358025 100644 --- a/src/xrGame/InfoDocument.cpp +++ b/src/xrGame/InfoDocument.cpp @@ -79,7 +79,7 @@ void CInfoDocument::OnH_B_Independent(bool just_before_destroy) inherited::OnH_B_Independent(just_before_destroy); } -void CInfoDocument::renderable_Render() +void CInfoDocument::renderable_Render(IDSGraphManager* DM) { - inherited::renderable_Render(); + inherited::renderable_Render(DM); } diff --git a/src/xrGame/InfoDocument.h b/src/xrGame/InfoDocument.h index 55c5e416d2..120ada90dc 100644 --- a/src/xrGame/InfoDocument.h +++ b/src/xrGame/InfoDocument.h @@ -22,7 +22,7 @@ class CInfoDocument : public CInventoryItemObject virtual void net_Destroy(); virtual void shedule_Update(u32 dt); virtual void UpdateCL(); - virtual void renderable_Render(); + virtual void renderable_Render(IDSGraphManager* DM); virtual void OnH_A_Chield(); virtual void OnH_B_Independent(bool just_before_destroy); diff --git a/src/xrGame/Inventory.cpp b/src/xrGame/Inventory.cpp index 69b99098ba..78ff05be53 100644 --- a/src/xrGame/Inventory.cpp +++ b/src/xrGame/Inventory.cpp @@ -625,7 +625,8 @@ void CInventory::Activate(u16 slot, bool bForce) CHudItem* tempItem = active_item->cast_hud_item(); R_ASSERT2(tempItem, active_item->object().cNameSect().c_str()); - tempItem->SendDeactivateItem(); + if (tempItem) + tempItem->SendDeactivateItem(); #ifdef DEBUG // Msg("--- Inventory owner [%s]: send deactivate item [%s]", m_pOwner->Name(), active_item->NameItem()); #endif // #ifdef DEBUG @@ -874,8 +875,8 @@ void CInventory::Update() funct(m_iActiveSlot, obj, prev_slot, prev_obj); } } - else if ((GetNextActiveSlot() != NO_ACTIVE_SLOT) && ActiveItem() && ActiveItem()->cast_hud_item()->IsHidden()) - ActiveItem()->ActivateItem(); + else if ((GetNextActiveSlot() != NO_ACTIVE_SLOT) && ActiveItem() && ActiveItem()->cast_hud_item() && ActiveItem()->cast_hud_item()->IsHidden()) + ActiveItem()->ActivateItem(); } UpdateDropTasks(); } @@ -1276,14 +1277,9 @@ CInventoryItem* CInventory::GetItemFromInventory(LPCSTR caItemName) { TIItemContainer& l_list = m_all; - u32 crc = crc32(caItemName, xr_strlen(caItemName)); - for (TIItemContainer::iterator l_it = l_list.begin(); l_list.end() != l_it; ++l_it) - if ((*l_it)->object().cNameSect()._get()->dwCRC == crc) - { - VERIFY(0 == xr_strcmp( (*l_it)->object().cNameSect().c_str(), caItemName)); + if (xr_strcmp((*l_it)->object().cNameSect().c_str(), caItemName) == 0) return (*l_it); - } return (0); } @@ -1547,7 +1543,9 @@ void CInventory::UnblockSlot(u16 slot_id) bool CInventory::IsSlotBlocked(u16 slot_id) const { - //VERIFY(slot_id <= LAST_SLOT); + if (m_blocked_slots.size() <= slot_id) + return false; + return m_blocked_slots[slot_id] > 0; } diff --git a/src/xrGame/Inventory.h b/src/xrGame/Inventory.h index 53db2fbee6..c847aadec7 100644 --- a/src/xrGame/Inventory.h +++ b/src/xrGame/Inventory.h @@ -196,7 +196,7 @@ class CInventory except_next_items_t m_next_items_exceptions; u32 m_next_item_iteration_time; - std::vector m_blocked_slots; + xr_vector m_blocked_slots; bool IsSlotBlocked(u16 slot_id) const; void TryActivatePrevSlot(); void TryDeactivateActiveSlot(); diff --git a/src/xrGame/InventoryBox.h b/src/xrGame/InventoryBox.h index c2b724e7fc..a6081b9512 100644 --- a/src/xrGame/InventoryBox.h +++ b/src/xrGame/InventoryBox.h @@ -36,6 +36,9 @@ class CInventoryBox : public CGameObject void set_closed(bool status, LPCSTR reason); IC bool closed() const { return m_closed; } + virtual CInventoryBox* cast_inventory_box() { return this; } + virtual CGameObject* cast_game_object() { return this; } + protected: void SE_update_status(); diff --git a/src/xrGame/InventoryOwner.cpp b/src/xrGame/InventoryOwner.cpp index 1a210aebd7..b1468ac03a 100644 --- a/src/xrGame/InventoryOwner.cpp +++ b/src/xrGame/InventoryOwner.cpp @@ -27,6 +27,7 @@ #include "CustomOutfit.h" #include "Bolt.h" #include "string_table.h" +#include "map_manager.h" CInventoryOwner::CInventoryOwner() { @@ -172,6 +173,8 @@ void CInventoryOwner::net_Destroy() inventory().Clear(); inventory().SetActiveSlot(NO_ACTIVE_SLOT); + + Level().MapManager().RemoveRelationLocation(this); } void CInventoryOwner::save(NET_Packet& output_packet) @@ -323,12 +326,12 @@ bool CInventoryOwner::IsTrading() } //============== -void CInventoryOwner::renderable_Render() +void CInventoryOwner::renderable_Render (IDSGraphManager* DM) { if (inventory().ActiveItem()) - inventory().ActiveItem()->renderable_Render(); + inventory().ActiveItem()->renderable_Render(DM); - CAttachmentOwner::renderable_Render(); + CAttachmentOwner::renderable_Render(DM); } void CInventoryOwner::OnItemTake(CInventoryItem* inventory_item) diff --git a/src/xrGame/InventoryOwner.h b/src/xrGame/InventoryOwner.h index 16ee2982e3..9afef0a2f0 100644 --- a/src/xrGame/InventoryOwner.h +++ b/src/xrGame/InventoryOwner.h @@ -30,6 +30,15 @@ class CTradeParameters; class CPurchaseList; class CWeapon; class CCustomOutfit; +class CHelmet; +class CActor; +class CAI_Stalker; +class CEntity; +class CBaseMonster; +class CCar; +class CAI_Trader; +class CPhraseDialogManager; +class CAI_PhraseDialogManager; class CInventoryOwner : public CAttachmentOwner { @@ -39,6 +48,18 @@ class CInventoryOwner : public CAttachmentOwner public: virtual CInventoryOwner* cast_inventory_owner() { return this; } + virtual CAttachmentOwner* cast_attachment_owner() { return this; } + virtual CActor* cast_actor() { return nullptr; } + virtual CEntityAlive* cast_entity_alive() { return nullptr; } + virtual CEntity* cast_entity() { return nullptr; } + virtual CAI_Stalker* cast_stalker() { return nullptr; } + virtual CGameObject* cast_game_object() { return nullptr; } + virtual CBaseMonster* cast_base_monster() { return nullptr; } + virtual CCar* cast_car() { return nullptr; } + virtual CAI_Trader* cast_trader() { return nullptr; } + virtual CPhraseDialogManager* cast_phrase_dialog_manager() { return nullptr; } + virtual CAI_PhraseDialogManager* cast_ai_phrase_dialog_manager() { return nullptr; } + public: virtual DLL_Pure* _construct(); @@ -214,7 +235,7 @@ class CInventoryOwner : public CAttachmentOwner xr_string m_game_name_str; public: - virtual void renderable_Render(); + virtual void renderable_Render(IDSGraphManager* DM); virtual void OnItemTake(CInventoryItem* inventory_item); virtual void OnItemBelt(CInventoryItem* inventory_item, const SInvItemPlace& previous_place); diff --git a/src/xrGame/Level.cpp b/src/xrGame/Level.cpp index a5b12349c5..44450ed445 100644 --- a/src/xrGame/Level.cpp +++ b/src/xrGame/Level.cpp @@ -173,42 +173,47 @@ namespace crash_saving { NET_Packet& net_packet = data->P; net_packet.w_begin(M_SAVE_GAME); - std::string path = "fatal_ctd_save_"; - std::string path_mask(path); - std::string path_ext = ".scop"; - path_mask.append("*").append(path_ext); + xr_string path = "fatal_ctd_save_"; + xr_string path_mask(path); + xr_string path_ext = ".scop"; + path_mask.append("*").append(path_ext); FS_FileSet fset_temp; FS.file_list(fset_temp, "$game_saves$", FS_ListFiles | FS_RootOnly, path_mask.c_str()); - std::vector fset(fset_temp.begin(), fset_temp.end()); - struct { - bool operator()(FS_File& a, FS_File& b) { - return a.time_write > b.time_write; - } - } sortFilesDesc; - std::sort(fset.begin(), fset.end(), sortFilesDesc); + xr_vector fset; + for (auto& file : fset_temp) + { + fset.push_back(file); + } + struct { + bool operator()(FS_File& a, FS_File& b) { + return a.time_write > b.time_write; + } + } sortFilesDesc; + std::sort(fset.begin(), fset.end(), sortFilesDesc); //Msg("save mask %s", path_mask.c_str()); - for (auto &file : fset) - { - string128 name; - xr_strcpy(name, sizeof(name), file.name.c_str()); - std::string name_string(name); - name_string.erase(name_string.length() - path_ext.length()); + for (auto& file : fset) + { + string128 name; + xr_strcpy(name, sizeof(name), file.name.c_str()); + xr_string name_string(name); + name_string.erase(name_string.length() - path_ext.length()); //Msg("found save file %s, save_name %s", name, name_string.c_str()); - try { - //Msg("save number %s", name_string.substr(path.length()).c_str()); - int name_count = std::stoi(name_string.substr(path.length())); - saveCount = name_count; - break; - } catch (...) { - Msg("!error getting save number from %s", name); - } - } + try { + //Msg("save number %s", name_string.substr(path.length()).c_str()); + int name_count = std::stoi(name_string.substr(path.length()).c_str()); + saveCount = name_count; + break; + } + catch (...) { + Msg("!error getting save number from %s", name); + } + } saveCount++; if (saveCount >= saveCountMax) { @@ -233,8 +238,9 @@ CLevel::CLevel() : , DemoCS(MUTEX_PROFILE_ID(DemoCS)) #endif { - g_bDebugEvents = strstr(Core.Params, "-debug_ge") != nullptr; - game_events = xr_new(); + PROF_EVENT("CLevel::CLevel"); + g_bDebugEvents = Core.ParamsData.test(ECoreParams::debug_ge); + game_events = xr_new(); eChangeRP = Engine.Event.Handler_Attach("LEVEL:ChangeRP", this); eDemoPlay = Engine.Event.Handler_Attach("LEVEL:PlayDEMO", this); @@ -286,41 +292,42 @@ extern CAI_Space* g_ai_space; CLevel::~CLevel() { - //crash_saving::save_impl = nullptr; // CLevel not available, disable crash save - xr_delete(g_player_hud); - delete_data(m_script_attachments); - delete_data(hud_zones_list); - hud_zones_list = nullptr; - Msg("- Destroying level"); - Engine.Event.Handler_Detach(eEntitySpawn, this); - Engine.Event.Handler_Detach(eEnvironment, this); - Engine.Event.Handler_Detach(eChangeTrack, this); - Engine.Event.Handler_Detach(eDemoPlay, this); - Engine.Event.Handler_Detach(eChangeRP, this); - if (physics_world()) - { - destroy_physics_world(); - xr_delete(m_ph_commander_physics_worldstep); - } - // destroy PSs - for (POIt p_it = m_StaticParticles.begin(); m_StaticParticles.end() != p_it; ++p_it) - CParticlesObject::Destroy(*p_it); - m_StaticParticles.clear(); - // Unload sounds - // unload prefetched sounds - sound_registry.clear(); - // unload static sounds - for (u32 i = 0; i < static_Sounds.size(); ++i) - { - static_Sounds[i]->destroy(); - xr_delete(static_Sounds[i]); - } - static_Sounds.clear(); - xr_delete(m_level_sound_manager); - xr_delete(m_space_restriction_manager); - xr_delete(m_seniority_hierarchy_holder); - xr_delete(m_client_spawn_manager); - xr_delete(m_autosave_manager); + PROF_EVENT("CLevel::~CLevel"); + //crash_saving::save_impl = nullptr; // CLevel not available, disable crash save + xr_delete(g_player_hud); + delete_data(m_script_attachments); + delete_data(hud_zones_list); + hud_zones_list = nullptr; + Msg("- Destroying level"); + Engine.Event.Handler_Detach(eEntitySpawn, this); + Engine.Event.Handler_Detach(eEnvironment, this); + Engine.Event.Handler_Detach(eChangeTrack, this); + Engine.Event.Handler_Detach(eDemoPlay, this); + Engine.Event.Handler_Detach(eChangeRP, this); + if (physics_world()) + { + destroy_physics_world(); + xr_delete(m_ph_commander_physics_worldstep); + } + // destroy PSs + for (POIt p_it = m_StaticParticles.begin(); m_StaticParticles.end() != p_it; ++p_it) + Particles::Details::Destroy(*p_it); + m_StaticParticles.clear(); + // Unload sounds + // unload prefetched sounds + sound_registry.clear(); + // unload static sounds + for (u32 i = 0; i < static_Sounds.size(); ++i) + { + static_Sounds[i]->destroy(); + xr_delete(static_Sounds[i]); + } + static_Sounds.clear(); + xr_delete(m_level_sound_manager); + xr_delete(m_space_restriction_manager); + xr_delete(m_seniority_hierarchy_holder); + xr_delete(m_client_spawn_manager); + xr_delete(m_autosave_manager); xr_delete(m_debug_renderer); delete_data(m_debug_render_queue); if (!g_dedicated_server) @@ -973,10 +980,15 @@ void CLevel::MakeReconnect() } } +BOOL mt_ph_commander = FALSE; +BOOL mt_TaskManager = FALSE; void CLevel::OnFrame() { PROF_EVENT("CLevel::OnFrame()"); + // demonized: update wallmarks before rendering + ::Render->update_Wallmarks(); + #ifdef DEBUG_MEMORY_MANAGER debug_memory_guard __guard__; #endif @@ -1034,21 +1046,14 @@ void CLevel::OnFrame() if (!g_dedicated_server) { if (g_mt_config.test(mtMap)) - Device.seqParallel.push_back(fastdelegate::FastDelegate0<>(m_map_manager, &CMapManager::Update)); + Device.seqParallel.push_back(xr_make_delegate(m_map_manager, &CMapManager::Update)); else MapManager().Update(); - if (IsGameTypeSingle() && Device.dwPrecacheFrame == 0) - { - // XXX nitrocaster: was enabled in x-ray 1.5; to be restored or removed - //if (g_mt_config.test(mtMap)) - //{ - // Device.seqParallel.push_back(fastdelegate::FastDelegate0<>( - // m_game_task_manager,&CGameTaskManager::UpdateTasks)); - //} - //else - GameTaskManager().UpdateTasks(); - } + + if (!mt_TaskManager && Device.dwPrecacheFrame == 0) + GameTaskManager().UpdateTasks(); } + // Inherited update inherited::OnFrame(); // Draw client/server stats @@ -1138,19 +1143,21 @@ void CLevel::OnFrame() #endif g_pGamePersistent->Environment().SetGameTime(GetEnvironmentGameDayTimeSec(), game->GetEnvironmentGameTimeFactor()); - if (!g_dedicated_server) + if (!mt_ph_commander) + { + PROF_EVENT("m_ph_commander"); ai().script_engine().script_process(ScriptEngine::eScriptProcessorLevel)->update(); - m_ph_commander->update(); - m_ph_commander_scripts->update(); - Device.Statistic->TEST0.Begin(); - BulletManager().CommitRenderSet(); - Device.Statistic->TEST0.End(); + + m_ph_commander->update(); + m_ph_commander_scripts->update(); + } + // update static sounds if (!g_dedicated_server) { if (g_mt_config.test(mtLevelSounds)) { - Device.seqParallel.push_back(fastdelegate::FastDelegate0<>( + Device.seqParallel.push_back(xr_make_delegate( m_level_sound_manager, &CLevelSoundManager::Update)); } else @@ -1161,7 +1168,7 @@ void CLevel::OnFrame() if (!g_dedicated_server) { if (g_mt_config.test(mtLUA_GC)) - Device.seqParallel.push_back(fastdelegate::FastDelegate0<>(this, &CLevel::script_gc)); + Device.seqParallel.push_back(xr_make_delegate(this, &CLevel::script_gc)); else script_gc(); } @@ -1184,11 +1191,20 @@ extern BOOL psLua_ParallelGC_debug; void CLevel::script_gc() { + if (mt_ph_commander) + { + PROF_EVENT("m_ph_commander"); + ai().script_engine().script_process(ScriptEngine::eScriptProcessorLevel)->update(); + + m_ph_commander->update(); + m_ph_commander_scripts->update(); + } if (!(psLua_ParallelGC && Device.LuaGC)) - { - PROF_EVENT(); + { + PROF_EVENT("CLevel::script_gc"); lua_gc(ai().script_engine().lua(), LUA_GCSTEP, psLUA_GCSTEP); } + } // demonized: bind LuaGC call to be available in device.cpp @@ -1196,8 +1212,8 @@ bool CLevel::Load(u32 dwNum) { inherited::Load(dwNum); Msg("Device.LuaGC bind"); - Device.LuaGC = fastdelegate::FastDelegate0(&CLevel::LuaGC); - Device.LuaGCDebug = fastdelegate::FastDelegate0(&CLevel::LuaGCDebug); + Device.LuaGC.bind(&CLevel::LuaGC); + Device.LuaGCDebug.bind(&CLevel::LuaGCDebug); return true; } @@ -1654,26 +1670,6 @@ bool CLevel::InterpolationDisabled() return g_cl_lvInterp < 0; } -void CLevel::PhisStepsCallback(u32 Time0, u32 Time1) -{ - if (!Level().game) - return; - if (GameID() == eGameIDSingle) - return; - //#pragma todo("Oles to all: highly inefficient and slow!!!") - //fixed (Andy) - /* - for (xr_vector::iterator O=Level().Objects.objects.begin(); O!=Level().Objects.objects.end(); ++O) - { - if( smart_cast((*O)){ - CActor* pActor = smart_cast(*O); - if (!pActor || pActor->Remote()) continue; - pActor->UpdatePosStack(Time0, Time1); - } - }; - */ -} - void CLevel::SetNumCrSteps(u32 NumSteps) { m_bNeed_CrPr = true; diff --git a/src/xrGame/Level.h b/src/xrGame/Level.h index 75df8013d0..88740cc051 100644 --- a/src/xrGame/Level.h +++ b/src/xrGame/Level.h @@ -110,7 +110,7 @@ class CLevel : void ReculcInterpolationSteps(); u32 GetNumCrSteps() const { return m_dwNumSteps; } void SetNumCrSteps(u32 NumSteps); - static void PhisStepsCallback(u32 Time0, u32 Time1); + bool In_NetCorrectionPrediction() { return m_bIn_CrPr; } virtual void OnMessage(void* data, u32 size); virtual void OnInvalidHost(); @@ -161,7 +161,8 @@ class CLevel : void OnBuildVersionChallenge(); void OnConnectResult(NET_Packet* P); // Static particles - DEFINE_VECTOR(CParticlesObject*, POVec, POIt); + using POVec = xr_vector>; + using POIt = POVec::iterator; POVec m_StaticParticles; game_cl_GameState* game = nullptr; bool m_bGameConfigStarted = false; @@ -317,6 +318,7 @@ class CLevel : CLevel(); virtual ~CLevel(); // названияе текущего уровня + void set_name(const shared_str& level_name){ map_data.m_name = level_name;} virtual shared_str name() const; // this method can be used ONLY from CCC_ChangeGameType // XXX nitrocaster: why c_str? diff --git a/src/xrGame/Level_Bullet_Manager.cpp b/src/xrGame/Level_Bullet_Manager.cpp index 8a5544638d..0648bf9a10 100644 --- a/src/xrGame/Level_Bullet_Manager.cpp +++ b/src/xrGame/Level_Bullet_Manager.cpp @@ -160,15 +160,15 @@ void populateBulletTable ( } -CBulletManager::CBulletManager() +CBulletManager::CBulletManager() : pure_relcase(&CBulletManager::net_Relcase) #if 0//def PROFILE_CRITICAL_SECTIONS - : m_Lock(MUTEX_PROFILE_ID(CBulletManager)) + ,m_Lock(MUTEX_PROFILE_ID(CBulletManager)) # ifdef DEBUG ,m_thread_id(GetCurrentThreadId()) # endif // #ifdef DEBUG #else // #ifdef PROFILE_CRITICAL_SECTIONS # ifdef DEBUG - : m_thread_id(GetCurrentThreadId()) + ,m_thread_id(GetCurrentThreadId()) # endif // #ifdef DEBUG #endif // #ifdef PROFILE_CRITICAL_SECTIONS { @@ -230,7 +230,7 @@ void CBulletManager::PlayExplodePS(const Fmatrix& xf) return; shared_str const& ps_name = m_ExplodeParticles[Random.randI(0, m_ExplodeParticles.size())]; - CParticlesObject* const ps = CParticlesObject::Create(*ps_name,TRUE); + intrusive_ptr const ps = Particles::Details::Create(*ps_name,TRUE); ps->UpdateParent(xf, zero_vel); GamePersistent().ps_needtoplay.push_back(ps); } @@ -247,6 +247,7 @@ void CBulletManager::PlayWhineSound(SBullet* bullet, CObject* object, const Fvec void CBulletManager::Clear() { + xrCriticalSectionGuard guard(&m_Lock); m_Bullets.clear(); m_Events.clear(); } @@ -267,15 +268,11 @@ void CBulletManager::AddBullet(const Fvector& position, bool AimBullet, int iShotNum) { -#ifdef DEBUG - VERIFY(m_thread_id == GetCurrentThreadId()); -#endif - VERIFY(u16(-1)!=cartridge.bullet_material_idx); // u32 CurID = Level().CurrentControlEntity()->ID(); // u32 OwnerID = sender_id; - m_Bullets.push_back(SBullet()); - SBullet& bullet = m_Bullets.back(); + xrCriticalSectionGuard guard(&m_Lock); + SBullet& bullet = m_Bullets.emplace_back(); bullet.Init(position, direction, starting_speed, power, /*power_critical,*/ impulse, sender_id, sendersweapon_id, e_hit_type, maximum_distance, cartridge, air_resistance_factor, SendHit, iShotNum); // bullet.frame_num = Device.dwFrame; @@ -315,8 +312,10 @@ void CBulletManager::AddBullet(const Fvector& position, void CBulletManager::UpdateWorkload() { + PROF_EVENT("CBulletManager::UpdateWorkload"); // VERIFY ( m_thread_id == GetCurrentThreadId() ); + xrCriticalSectionGuard guard(&m_Lock); rq_storage.r_clear(); u32 const time_delta = Device.dwTimeDelta; @@ -1113,6 +1112,7 @@ float SqrDistancePointToSegment(const Fvector& pt, const Fvector& orig, const Fv BOOL g_render_short_tracers = 1; void CBulletManager::Render() { + PROF_EVENT("CBulletManager::Render"); #ifdef DEBUG if (g_bDrawBulletHit && !m_bullet_points.empty()) { VERIFY (!(m_bullet_points.size() % 2)); @@ -1152,29 +1152,26 @@ void CBulletManager::Render() } #endif - if (m_BulletsRendered.empty()) return; - - //u32 vOffset = 0 ; - u32 bullet_num = m_BulletsRendered.size(); + if (m_Bullets.empty()) return; + xrCriticalSectionGuard guard(&m_Lock); + u32 bullet_num = m_Bullets.size(); - UIRender->StartPrimitive((u32)bullet_num * 12, IUIRender::ptTriList, IUIRender::pttLIT); + UIRender->StartPrimitive(bullet_num * 12, IUIRender::ptTriList, IUIRender::pttLIT); - for (BulletVecIt it = m_BulletsRendered.begin(); it != m_BulletsRendered.end(); it++) + for (SBullet& bullet : m_Bullets) { - SBullet* bullet = &(*it); - if (!bullet->flags.allow_tracer) + if (!bullet.flags.allow_tracer) continue; + if (!psActorFlags.test(AF_USE_TRACERS)) continue; - if (!bullet->CanBeRenderedNow()) + if (!bullet.CanBeRenderedNow()) continue; - Fvector const tracer = Fvector().sub(bullet->bullet_pos, bullet->tracer_start_position); + Fvector const tracer = Fvector().sub(bullet.bullet_pos, bullet.tracer_start_position); float length = tracer.magnitude(); - Fvector const tracer_direction = length >= EPS_L - ? Fvector(tracer).mul(1.f / length) - : Fvector().set(0.f, 0.f, 1.f); + Fvector const tracer_direction = length >= EPS_L ? Fvector(tracer).mul(1.f / length) : Fvector().set(0.f, 0.f, 1.f); if (length < m_fTracerLengthMin) { @@ -1189,7 +1186,7 @@ void CBulletManager::Render() length = m_fTracerLengthMax; float width = m_fTracerWidth; - float dist2segSqr = SqrDistancePointToSegment(Device.vCameraPosition, bullet->bullet_pos, tracer); + float dist2segSqr = SqrDistancePointToSegment(Device.vCameraPosition, bullet.bullet_pos, tracer); //--------------------------------------------- float MaxDistSqr = 1.0f; float MinDistSqr = 0.09f; @@ -1199,20 +1196,19 @@ void CBulletManager::Render() width *= _sqrt(dist2segSqr / MaxDistSqr); } - if (Device.vCameraPosition.distance_to_sqr(bullet->bullet_pos) < (length * length)) + if (Device.vCameraPosition.distance_to_sqr(bullet.bullet_pos) < (length * length)) { - length = Device.vCameraPosition.distance_to(bullet->bullet_pos) - 0.3f; + length = Device.vCameraPosition.distance_to(bullet.bullet_pos) - 0.3f; } Fvector center; - center.mad(bullet->bullet_pos, tracer_direction, -length * .5f); + center.mad(bullet.bullet_pos, tracer_direction, -length * .5f); bool bActor = false; if (Level().CurrentViewEntity()) { - bActor = (bullet->parent_id == Level().CurrentViewEntity()->ID()); + bActor = (bullet.parent_id == Level().CurrentViewEntity()->ID()); } - tracers.Render(bullet->bullet_pos, center, tracer_direction, length, width, bullet->m_u8ColorID, bullet->speed, - bActor); + tracers.Render(bullet.bullet_pos, center, tracer_direction, length, width, bullet.m_u8ColorID, bullet.speed, bActor); } UIRender->CacheSetCullMode(IUIRender::cmNONE); @@ -1222,21 +1218,26 @@ void CBulletManager::Render() UIRender->CacheSetCullMode(IUIRender::cmCCW); } -void CBulletManager::CommitRenderSet() // @ the end of frame +// demonized: net_Relcase for mt_scheduler 1 +void __stdcall CBulletManager::net_Relcase(CObject* object) { - m_BulletsRendered = m_Bullets; - if (g_mt_config.test(mtBullets)) - { - Device.seqParallel.push_back(fastdelegate::FastDelegate0<>(this, &CBulletManager::UpdateWorkload)); - } - else - { - UpdateWorkload(); - } + // Clean up pending events + m_Events.erase( + std::remove_if( + m_Events.begin(), + m_Events.end(), + [object](const _event& E) + { + return (E.dynamic && E.R.O == object); + } + ), + m_Events.end() + ); } void CBulletManager::CommitEvents() // @ the start of frame { + PROF_EVENT("CBulletManager::CommitEvents"); if (m_Events.size() > 1000) Msg("! too many bullets during single frame: %d", m_Events.size()); @@ -1251,25 +1252,28 @@ void CBulletManager::CommitEvents() // @ the start of frame case EVENT_HIT: { // demonized: bullet on impact callback - ::luabind::functor funct; - if (ai().script_engine().functor("_G.CBulletOnImpact", funct)) { - ::luabind::object table = ::luabind::newtable(ai().script_engine().lua()); - populateBulletTable( - table, - !fis_zero(end_point.x) && !fis_zero(end_point.y) && !fis_zero(end_point.z) ? end_point : bullet->bullet_pos, - bullet->dir, - bullet->speed, - bullet->fly_dist + E.R.range, - bullet->catridgeSection, - bullet->bulletId, - bullet->weapon_id, - bullet->parent_id, - E.dynamic && E.R.O ? E.R.O->ID() : 65535, - mt ? mt->m_Name.c_str() : NULL, - bullet->life_time, - E.R.element - ); - funct(table); + { + xrCriticalSectionGuard guard(&m_Lock); + ::luabind::functor funct; + if (ai().script_engine().functor("_G.CBulletOnImpact", funct)) { + ::luabind::object table = ::luabind::newtable(ai().script_engine().lua()); + populateBulletTable( + table, + !fis_zero(end_point.x) && !fis_zero(end_point.y) && !fis_zero(end_point.z) ? end_point : bullet->bullet_pos, + bullet->dir, + bullet->speed, + bullet->fly_dist + E.R.range, + bullet->catridgeSection, + bullet->bulletId, + bullet->weapon_id, + bullet->parent_id, + E.dynamic && E.R.O ? E.R.O->ID() : 65535, + mt ? mt->m_Name.c_str() : NULL, + bullet->life_time, + E.R.element + ); + funct(table); + } } if (E.dynamic) DynamicObjectHit(E); @@ -1280,6 +1284,7 @@ void CBulletManager::CommitEvents() // @ the start of frame case EVENT_REMOVE: { // demonized: bullet on remove callback + xrCriticalSectionGuard guard(&m_Lock); ::luabind::functor funct; if (ai().script_engine().functor("_G.CBulletOnRemove", funct)) { ::luabind::object table = ::luabind::newtable(ai().script_engine().lua()); @@ -1310,6 +1315,14 @@ void CBulletManager::CommitEvents() // @ the start of frame } } m_Events.clear_and_reserve(); + + if (g_mt_config.test(mtBullets)) { + Device.seqParallel.push_back(xr_make_delegate(this, &CBulletManager::UpdateWorkload)); + } + else + { + UpdateWorkload(); + } } void CBulletManager::RegisterEvent(EventType Type, BOOL _dynamic, SBullet* bullet, const Fvector& end_point, diff --git a/src/xrGame/Level_Bullet_Manager.h b/src/xrGame/Level_Bullet_Manager.h index 8baee9347e..b3a1ec68bf 100644 --- a/src/xrGame/Level_Bullet_Manager.h +++ b/src/xrGame/Level_Bullet_Manager.h @@ -108,7 +108,7 @@ struct SBullet class CLevel; -class CBulletManager +class CBulletManager : private pure_relcase { private: static float const parent_ignore_distance; @@ -149,10 +149,9 @@ class CBulletManager RStringVec m_ExplodeParticles; //список пуль находящихся в данный момент на уровне - //. xrCriticalSection m_Lock ; + xrCriticalSection m_Lock ; BulletVec m_Bullets; // working set, locked - BulletVec m_BulletsRendered; // copy for rendering xr_vector<_event> m_Events; #ifdef DEBUG @@ -251,11 +250,11 @@ class CBulletManager bool SendHit, bool AimBullet = false, int iShotNum = 0); void CommitEvents(); // @ the start of frame - void CommitRenderSet(); // @ the end of frame void Render(); + void __stdcall net_Relcase(CObject* obj); #ifdef CBULLETMANAGER_EX - bool ValidateHitDynamicVisualMesh(SBullet& B, collide::rq_result& R, Fvector& collide_position, float range); + bool ValidateHitDynamicVisualMesh(SBullet& B, collide::rq_result& R, Fvector& collide_position, float range); #endif }; diff --git a/src/xrGame/Level_bullet_manager_firetrace.cpp b/src/xrGame/Level_bullet_manager_firetrace.cpp index b59b228144..fab7b4e267 100644 --- a/src/xrGame/Level_bullet_manager_firetrace.cpp +++ b/src/xrGame/Level_bullet_manager_firetrace.cpp @@ -241,7 +241,7 @@ void CBulletManager::FireShotmark(SBullet* bullet, const Fvector& vDir, const Fv if (ps_name && ShowMark) { //отыграть партиклы попадания в материал - CParticlesObject* ps = CParticlesObject::Create(ps_name,TRUE); + intrusive_ptr ps = Particles::Details::Create(ps_name,TRUE); ps->UpdateParent(pos, zero_vel); GamePersistent().ps_needtoplay.push_back(ps); diff --git a/src/xrGame/Level_input.cpp b/src/xrGame/Level_input.cpp index 3f85153afb..111de39156 100644 --- a/src/xrGame/Level_input.cpp +++ b/src/xrGame/Level_input.cpp @@ -266,16 +266,23 @@ void CLevel::IR_OnKeyboardPress(int key) case kQUIT: { - if (b_ui_exist && CurrentGameUI()->TopInputReceiver()) - { - if (CurrentGameUI()->IR_UIOnKeyboardPress(key)) return; //special case for mp and main_menu - CurrentGameUI()->TopInputReceiver()->HideDialog(); - } - else + if (b_ui_exist && CurrentGameUI()->TopInputReceiver()) + { + if(Device.Paused()) { - Console->Execute("main_menu"); + // Снимаем паузу, через Esc + Device.Pause(FALSE, TRUE, TRUE, "kQUIT"); + return; } - return; + + if (CurrentGameUI()->IR_UIOnKeyboardPress(key)) return; //special case for mp and main_menu + CurrentGameUI()->TopInputReceiver()->HideDialog(); + } + else + { + Console->Execute("main_menu"); + } + return; } break; }; diff --git a/src/xrGame/Level_load.cpp b/src/xrGame/Level_load.cpp index f21cb8ad94..aecfd2f934 100644 --- a/src/xrGame/Level_load.cpp +++ b/src/xrGame/Level_load.cpp @@ -1,7 +1,6 @@ #include "stdafx.h" #include "LevelGameDef.h" #include "ai_space.h" -#include "ParticlesObject.h" #include "script_process.h" #include "script_engine.h" #include "script_engine_space.h" @@ -55,7 +54,7 @@ bool CLevel::Load_GameSpecific_After() if (FS.exist(fn_game, "$level$", "level.ps_static")) { IReader* F = FS.r_open(fn_game); - CParticlesObject* pStaticParticles; + u32 chunk = 0; string256 ref_name; Fmatrix transform; @@ -86,7 +85,7 @@ bool CLevel::Load_GameSpecific_After() if ((g_pGamePersistent->m_game_params.m_e_game_type & EGameIDs(gametype_usage)) || (ver == 0)) { - pStaticParticles = CParticlesObject::Create(ref_name,FALSE, false); + auto pStaticParticles = Particles::Details::Create(ref_name,FALSE,false); pStaticParticles->UpdateParent(transform, zero_vel); pStaticParticles->Play(false); m_StaticParticles.push_back(pStaticParticles); diff --git a/src/xrGame/Level_network.cpp b/src/xrGame/Level_network.cpp index 6f4aaeb41a..e5914b4dee 100644 --- a/src/xrGame/Level_network.cpp +++ b/src/xrGame/Level_network.cpp @@ -30,6 +30,7 @@ extern bool g_b_ClearGameCaptions; void CLevel::remove_objects() { + PROF_EVENT("remove_objects"); if (!IsGameTypeSingle()) Msg("CLevel::remove_objects - Start"); BOOL b_stored = psDeviceFlags.test(rsDisableObjectsAsCrows); @@ -56,6 +57,7 @@ void CLevel::remove_objects() ClientReceive(); ProcessGameEvents(); Objects.Update(false); + Objects.ProcessDestroyQueue(); #ifdef DEBUG Msg ("Update objects list..."); #endif // #ifdef DEBUG @@ -321,6 +323,7 @@ void CLevel::Send(NET_Packet& P, u32 dwFlags, u32 dwTimeout) void CLevel::net_Update() { + PROF_EVENT("net_Update"); if (game_configured) { // If we have enought bandwidth - replicate client data on to server diff --git a/src/xrGame/Level_network_messages.cpp b/src/xrGame/Level_network_messages.cpp index 40bf3c1965..b28dcb1183 100644 --- a/src/xrGame/Level_network_messages.cpp +++ b/src/xrGame/Level_network_messages.cpp @@ -58,6 +58,7 @@ static bool SimmulateNetworkLag() void CLevel::ClientReceive() { + PROF_EVENT("CLevel::ClientReceive"); m_dwRPC = 0; m_dwRPS = 0; diff --git a/src/xrGame/Level_network_spawn.cpp b/src/xrGame/Level_network_spawn.cpp index 9217732ed1..e961fc488a 100644 --- a/src/xrGame/Level_network_spawn.cpp +++ b/src/xrGame/Level_network_spawn.cpp @@ -15,6 +15,7 @@ void CLevel::cl_Process_Spawn(NET_Packet& P) // Begin analysis shared_str s_name; P.r_stringZ(s_name); + PROF_EVENT("CLevel::cl_Process_Spawn"); //Msg("cl_Process_Spawn spawning %s", s_name.c_str()); @@ -115,22 +116,34 @@ void CLevel::g_sv_Spawn(CSE_Abstract* E) #ifdef DEBUG_MEMORY_MANAGER mem_alloc_gather_stats (false); #endif // DEBUG_MEMORY_MANAGER - if (0 == O || (!O->net_Spawn(E))) + + if (0 == O) + { + Msg("! Failed to spawn entity '%s', O is nullptr", *E->s_name); + return; + } + + if (!O->net_Spawn(E)) { + Msg("! Failed to spawn entity '%s', net_Spawn failed", *E->s_name); O->net_Destroy(); if (!g_dedicated_server) client_spawn_manager().clear(O->ID()); Objects.Destroy(O); Msg("! Failed to spawn entity '%s'", *E->s_name); + #ifdef DEBUG_MEMORY_MANAGER mem_alloc_gather_stats (!!psAI_Flags.test(aiDebugOnFrameAllocs)); #endif // DEBUG_MEMORY_MANAGER + } else { + #ifdef DEBUG_MEMORY_MANAGER mem_alloc_gather_stats (!!psAI_Flags.test(aiDebugOnFrameAllocs)); #endif // DEBUG_MEMORY_MANAGER + if (!g_dedicated_server) client_spawn_manager().callback(O); //Msg ("--spawn--SPAWN: %f ms",1000.f*T.GetAsync()); @@ -201,6 +214,7 @@ void CLevel::g_sv_Spawn(CSE_Abstract* E) //--------------------------------------------------------- Game().OnSpawn(O); //--------------------------------------------------------- + #ifdef DEBUG_MEMORY_MANAGER if (g_bMEMO) { lua_gc (ai().script_engine().lua(),LUA_GCCOLLECT,0); @@ -208,6 +222,7 @@ void CLevel::g_sv_Spawn(CSE_Abstract* E) Msg ("* %20s : %lld bytes, %d ops", *E->s_name,Memory.mem_usage()-E_mem, Memory.stat_calls ); } #endif // DEBUG_MEMORY_MANAGER + } CSE_Abstract* CLevel::spawn_item(LPCSTR section, const Fvector& position, u32 level_vertex_id, u16 parent_id, diff --git a/src/xrGame/Level_network_start_client.cpp b/src/xrGame/Level_network_start_client.cpp index 297f92a302..458445be7c 100644 --- a/src/xrGame/Level_network_start_client.cpp +++ b/src/xrGame/Level_network_start_client.cpp @@ -27,6 +27,7 @@ bool CLevel::net_Start_client(const char* options) bool CLevel::net_start_client1() { + PROF_EVENT("CLevel::net_start_client1"); pApp->LoadBegin(); // name_of_server string64 name_of_server = ""; @@ -52,6 +53,7 @@ bool CLevel::net_start_client1() bool CLevel::net_start_client2() { + PROF_EVENT("CLevel::net_start_client2"); if (psNET_direct_connect) { Server->create_direct_client(); @@ -79,6 +81,7 @@ void rescan_mp_archives() bool CLevel::net_start_client3() { + PROF_EVENT("CLevel::net_start_client3"); if (connected_to_server) { LPCSTR level_name = NULL; @@ -133,6 +136,7 @@ bool CLevel::net_start_client3() bool CLevel::net_start_client4() { + PROF_EVENT("CLevel::net_start_client4"); if (connected_to_server) { // Begin spawn @@ -152,9 +156,6 @@ bool CLevel::net_start_client4() physics_world()->set_default_contact_shotmark(ContactShotMark); physics_world()->set_default_character_contact_shotmark(CharacterContactShotMark); - VERIFY(physics_world()); - physics_world()->set_step_time_callback((PhysicsStepTimeCallback*)&PhisStepsCallback); - // Send network to single or multithreaded mode // *note: release version always has "mt_*" enabled @@ -212,6 +213,7 @@ void CLevel::ClientSendProfileData() bool CLevel::net_start_client5() { + PROF_EVENT("CLevel::net_start_client5"); if (connected_to_server) { // HUD @@ -235,6 +237,7 @@ bool CLevel::net_start_client5() bool CLevel::net_start_client6() { + PROF_EVENT("CLevel::net_start_client6"); if (connected_to_server) { // Sync diff --git a/src/xrGame/Level_start.cpp b/src/xrGame/Level_start.cpp index 25e2b2044a..32a0f21728 100644 --- a/src/xrGame/Level_start.cpp +++ b/src/xrGame/Level_start.cpp @@ -30,6 +30,7 @@ void CLevel::net_StartPlayDemo() bool CLevel::net_Start(const char* op_server, const char* op_client) { + PROF_EVENT("CLevel::net_Start"); net_start_result_total = TRUE; pApp->LoadBegin(); @@ -106,6 +107,7 @@ shared_str level_name(const shared_str& server_options); bool CLevel::net_start1() { + PROF_EVENT("CLevel::net_start1"); // Start client and server if need it if (m_caServerOptions.size()) { @@ -152,6 +154,7 @@ bool CLevel::net_start1() bool CLevel::net_start2() { + PROF_EVENT("CLevel::net_start2"); if (net_start_result_total && m_caServerOptions.size()) { GameDescriptionData game_descr; @@ -171,6 +174,7 @@ bool CLevel::net_start2() bool CLevel::net_start3() { + PROF_EVENT("CLevel::net_start3"); if (!net_start_result_total) return true; //add server port if don't have one in options if (!strstr(m_caClientOptions.c_str(), "port=") && Server) @@ -216,6 +220,7 @@ bool CLevel::net_start3() bool CLevel::net_start4() { + PROF_EVENT("CLevel::net_start4"); if (!net_start_result_total) return true; g_loading_events.pop_front(); @@ -232,6 +237,7 @@ bool CLevel::net_start4() bool CLevel::net_start5() { + PROF_EVENT("CLevel::net_start5"); if (net_start_result_total) { NET_Packet NP; @@ -249,6 +255,7 @@ bool CLevel::net_start5() bool CLevel::net_start6() { + PROF_EVENT("CLevel::net_start6"); //init bullet manager BulletManager().Clear(); BulletManager().Load(); @@ -339,6 +346,7 @@ bool CLevel::net_start6() void CLevel::InitializeClientGame(NET_Packet& P) { + PROF_EVENT("CLevel::InitializeClientGame"); string256 game_type_name; P.r_stringZ(game_type_name); if (game && !xr_strcmp(game_type_name, game->type_name())) diff --git a/src/xrGame/MainMenu.cpp b/src/xrGame/MainMenu.cpp index 2467fe93f0..db1b119f7d 100644 --- a/src/xrGame/MainMenu.cpp +++ b/src/xrGame/MainMenu.cpp @@ -226,10 +226,12 @@ void CMainMenu::Activate(bool bActivate) } Device.seqRender.Remove(g_pGameLevel); CCameraManager::ResetPP(); - }; + } + else + Console->Execute("stat_memory"); + Device.seqRender.Add(this, 4); // 1-console 2-cursor 3-tutorial - Console->Execute("stat_memory"); } else { diff --git a/src/xrGame/MercuryBall.cpp b/src/xrGame/MercuryBall.cpp index a5d2f5036f..fe6073811b 100644 --- a/src/xrGame/MercuryBall.cpp +++ b/src/xrGame/MercuryBall.cpp @@ -50,5 +50,5 @@ void CMercuryBall::UpdateCLChild() } } } - else if (H_Parent()) XFORM().set(H_Parent()->XFORM()); + else if (H_Parent() && IsHidden()) XFORM().set(H_Parent()->XFORM()); } diff --git a/src/xrGame/Message_Filter.h b/src/xrGame/Message_Filter.h index bde1c2236d..be9ae52133 100644 --- a/src/xrGame/Message_Filter.h +++ b/src/xrGame/Message_Filter.h @@ -1,7 +1,7 @@ #ifndef DEMO_MESSAGE_FILER #define DEMO_MESSAGE_FILER -#include +#include "../xrCore/xr_delegate.h" #include "../xrCore/net_utils.h" #include "associative_vector.h" @@ -10,7 +10,7 @@ class message_filter { public: - typedef fastdelegate::FastDelegate3 msg_type_subtype_func_t; + typedef xr_delegate msg_type_subtype_func_t; message_filter(); ~message_filter(); void filter(u16 const& msg_type, diff --git a/src/xrGame/Missile.cpp b/src/xrGame/Missile.cpp index 7f5218d297..7b8b228541 100644 --- a/src/xrGame/Missile.cpp +++ b/src/xrGame/Missile.cpp @@ -1,4 +1,4 @@ -#include "stdafx.h" +#include "stdafx.h" #include "missile.h" //.#include "WeaponHUD.h" #include "../xrphysics/PhysicsShell.h" @@ -103,6 +103,18 @@ void CMissile::Load(LPCSTR section) if (pSettings->line_exist(section, "snd_checkout")) m_sounds.LoadSound(section, "snd_checkout", "sndCheckout", false, SOUND_TYPE_WEAPON_RECHARGING); + + if (pSettings->line_exist(section, "checkout_bones")) + { + m_sCheckoutBones.clear(); + LPCSTR lineStr = pSettings->r_string(section, "checkout_bones"); + for (int j = 0, cnt = _GetItemCount(lineStr); j < cnt; ++j) + { + string128 bone_name; + _GetItem(lineStr, j, bone_name); + m_sCheckoutBones.push_back(bone_name); + } + } } BOOL CMissile::net_Spawn(CSE_Abstract* DC) @@ -601,6 +613,7 @@ void CMissile::OnEvent(NET_Packet& P, u16 type) { m_fake_missile = NULL; IsFakeMissile = true; + setForceDestroy(); } CMissile* missile = smart_cast(Level().Objects.net_Find(id)); @@ -758,9 +771,19 @@ void CMissile::activate_physic_shell() m_pPhysicsShell->SetAirResistance(0.f, 0.f); m_pPhysicsShell->set_DynamicScales(1.f, 1.f); - IKinematics* kinematics = smart_cast(Visual()); + IKinematics* kinematics = PKinematics(Visual()); VERIFY(kinematics); kinematics->CalculateBones_Invalidate(); + if (m_fThrowForce != 0.f && !m_sCheckoutBones.empty()) + { + u16 bone_id; + for (const auto& boneName : m_sCheckoutBones) + { + bone_id = kinematics->LL_BoneID(boneName); + if (bone_id != BI_NONE && kinematics->LL_GetBoneVisible(bone_id)) + kinematics->LL_SetBoneVisible(bone_id, FALSE, TRUE); + } + } kinematics->CalculateBones(TRUE); } @@ -788,7 +811,7 @@ void CMissile::setup_physic_shell() R_ASSERT(!m_pPhysicsShell); create_physic_shell(); m_pPhysicsShell->Activate(XFORM(), 0, XFORM()); //,true - IKinematics* kinematics = smart_cast(Visual()); + IKinematics *kinematics = PKinematics(Visual()); R_ASSERT(kinematics); kinematics->CalculateBones_Invalidate(); kinematics->CalculateBones(TRUE); diff --git a/src/xrGame/Missile.h b/src/xrGame/Missile.h index 6d11bcde32..3c34ed102d 100644 --- a/src/xrGame/Missile.h +++ b/src/xrGame/Missile.h @@ -4,6 +4,8 @@ struct dContact; struct SGameMtl; +class CBolt; +class CGrenade; class CMissile : public CHudItemObject { @@ -27,6 +29,9 @@ class CMissile : public CHudItemObject virtual void reinit(); virtual CMissile* cast_missile() { return this; } + virtual CBolt* cast_bolt() { return nullptr; } + virtual CGrenade* cast_grenade() { return nullptr; } + virtual void Load(LPCSTR section); virtual BOOL net_Spawn(CSE_Abstract* DC); virtual void net_Destroy(); @@ -78,6 +83,8 @@ class CMissile : public CHudItemObject CMissile* m_fake_missile; + xr_vector m_sCheckoutBones; + u32 dwUpdateSounds_Frame = 0; //параметры броска diff --git a/src/xrGame/MosquitoBald.cpp b/src/xrGame/MosquitoBald.cpp index 1e935d3beb..dc9a8534e0 100644 --- a/src/xrGame/MosquitoBald.cpp +++ b/src/xrGame/MosquitoBald.cpp @@ -1,6 +1,5 @@ #include "stdafx.h" #include "mosquitobald.h" -#include "ParticlesObject.h" #include "level.h" #include "physicsshellholder.h" #include "../xrengine/xr_collide_form.h" diff --git a/src/xrGame/PDA.cpp b/src/xrGame/PDA.cpp index cb2f011295..eb03351705 100644 --- a/src/xrGame/PDA.cpp +++ b/src/xrGame/PDA.cpp @@ -400,7 +400,9 @@ void CPda::shedule_Update(u32 dt) inherited::shedule_Update(dt); if (!H_Parent()) return; - Position().set(H_Parent()->Position()); + + if(!CAttachableItem::enabled()) + Position().set(H_Parent()->Position()); if (IsOn() && Level().CurrentEntity() && Level().CurrentEntity()->ID() == H_Parent()->ID()) { diff --git a/src/xrGame/PDA.h b/src/xrGame/PDA.h index 9c77223717..88c923d74e 100644 --- a/src/xrGame/PDA.h +++ b/src/xrGame/PDA.h @@ -70,6 +70,8 @@ class CPda : virtual void save(NET_Packet& output_packet); virtual void load(IReader& input_packet); + virtual CPda* cast_pda() { return this; } + protected: void UpdateActiveContacts(); diff --git a/src/xrGame/PHCommander.cpp b/src/xrGame/PHCommander.cpp index a21a571f5a..52ec7291d7 100644 --- a/src/xrGame/PHCommander.cpp +++ b/src/xrGame/PHCommander.cpp @@ -27,7 +27,10 @@ bool CPHCall::obsolete() void CPHCall::check() { - if (m_condition && m_condition->is_true() && m_action) m_action->run(); + if(!m_condition) return; + if(!m_condition->is_true()) return; + if(!m_action) return; + m_action->run(); } bool CPHCall::equal(CPHReqComparerV* cmp_condition, CPHReqComparerV* cmp_action) @@ -60,6 +63,7 @@ CPHCommander::~CPHCommander() void CPHCommander::clear() { + xrCriticalSectionGuard guard(&lock); while (m_calls.size()) { remove_call(m_calls.end() - 1); @@ -76,6 +80,8 @@ void CPHCommander::clear() void CPHCommander::update() { + xrCriticalSectionGuard guard(&lock); + PROF_EVENT("CPHCommander::update"); for (u32 i = 0; i < m_calls.size(); i++) { try @@ -98,22 +104,12 @@ void CPHCommander::update() } } -void CPHCommander::update_threadsafety() -{ - lock.Enter(); - update(); - lock.Leave(); -} -void CPHCommander::add_call_threadsafety(CPHCondition* condition, CPHAction* action) -{ - lock.Enter(); - add_call(condition, action); - lock.Leave(); -} + void CPHCommander::add_call(CPHCondition* condition, CPHAction* action, PHCALL_STORAGE& cs) { + xrCriticalSectionGuard guard(&lock); cs.push_back(xr_new(condition, action)); } @@ -124,6 +120,7 @@ void CPHCommander::add_call(CPHCondition* condition, CPHAction* action) void CPHCommander::remove_call(PHCALL_I i, PHCALL_STORAGE& cs) { + xrCriticalSectionGuard guard(&lock); #ifdef DEBUG const CPHCallOnStepCondition * esc = smart_cast((*i)->condition()); const CPHConstForceAction * cfa = smart_cast((*i)->action()); @@ -185,6 +182,7 @@ struct SFRemovePred2 PHCALL_I CPHCommander::find_call(CPHReqComparerV* cmp_condition, CPHReqComparerV* cmp_action, PHCALL_STORAGE& cs) { + xrCriticalSectionGuard guard(&lock); return std::find_if(cs.begin(), cs.end(), SFEqualPred(cmp_condition, cmp_action)); } @@ -200,6 +198,7 @@ bool CPHCommander::has_call(CPHReqComparerV* cmp_condition, CPHReqComparerV* cmp void CPHCommander::remove_call(CPHReqComparerV* cmp_condition, CPHReqComparerV* cmp_action, PHCALL_STORAGE& cs) { + xrCriticalSectionGuard guard(&lock); cs.erase( std::remove_if( cs.begin(), @@ -258,6 +257,7 @@ struct SRemoveRped void CPHCommander::remove_calls(CPHReqComparerV* cmp_object, PHCALL_STORAGE& cs) { + xrCriticalSectionGuard guard(&lock); cs.erase( std::remove_if( cs.begin(), @@ -268,12 +268,6 @@ void CPHCommander::remove_calls(CPHReqComparerV* cmp_object, PHCALL_STORAGE& cs) ); } -void CPHCommander::remove_calls_threadsafety(CPHReqComparerV* cmp_object) -{ - lock.Enter(); - remove_calls(cmp_object); - lock.Leave(); -} void CPHCommander::remove_calls(CPHReqComparerV* cmp_object) { @@ -314,5 +308,5 @@ void CPHCommander::update_as() void CPHCommander::phys_shell_relcase(CPhysicsShell* sh) { CPHReqComparerHasShell c(sh); - remove_calls_threadsafety(&c); + remove_calls(&c); } diff --git a/src/xrGame/PHCommander.h b/src/xrGame/PHCommander.h index 1b5d178f69..e5b17b9323 100644 --- a/src/xrGame/PHCommander.h +++ b/src/xrGame/PHCommander.h @@ -1,8 +1,8 @@ -#ifndef PH_COMMANDER_H -#define PH_COMMANDER_H +#pragma once +#include "../xrPhysics/IPHWorld.h" + class CPHReqBase; class CPHReqComparerV; -#include "../xrphysics/iphworld.h" class CPhysicsShell; class CPHReqBase @@ -16,7 +16,6 @@ class CPHReqBase virtual bool compare(const CPHReqComparerV* v) const { return false; } ; }; - class CPHCondition : public CPHReqBase { @@ -88,17 +87,16 @@ class CPHCommander : bool add_call_unique(CPHCondition* condition, CPHReqComparerV* cmp_condition, CPHAction* action, CPHReqComparerV* cmp_action); void add_call(CPHCondition* condition, CPHAction* action); - void add_call_threadsafety(CPHCondition* condition, CPHAction* action); + void remove_call(PHCALL_I i); bool has_call(CPHReqComparerV* cmp_condition, CPHReqComparerV* cmp_action); PHCALL_I find_call(CPHReqComparerV* cmp_condition, CPHReqComparerV* cmp_action); void remove_call(CPHReqComparerV* cmp_condition, CPHReqComparerV* cmp_action); void remove_calls(CPHReqComparerV* cmp_object); - void remove_calls_threadsafety(CPHReqComparerV* cmp_object); + void update(); - void update_threadsafety(); ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void add_call_unique_as(CPHCondition* condition, CPHReqComparerV* cmp_condition, CPHAction* action, CPHReqComparerV* cmp_action); @@ -123,7 +121,6 @@ class CPHCommander : IC void remove_call(CPHReqComparerV* cmp_condition, CPHReqComparerV* cmp_action, PHCALL_STORAGE& cs); IC void remove_calls(CPHReqComparerV* cmp_object, PHCALL_STORAGE& cs); private: - virtual void update_step() { update_threadsafety(); } + virtual void update_step() { update(); } virtual void phys_shell_relcase(CPhysicsShell* sh); }; -#endif diff --git a/src/xrGame/PHDebug.cpp b/src/xrGame/PHDebug.cpp index 85f775c72b..ad23387f56 100644 --- a/src/xrGame/PHDebug.cpp +++ b/src/xrGame/PHDebug.cpp @@ -68,7 +68,7 @@ struct SPHObjDBGDraw:public SPHDBGDrawAbsract SPHObjDBGDraw(const CPHObject* obj) { AABB.set(obj->AABB); - AABB_center.set(obj->spatial.sphere.P); + AABB_center.set(obj->SpatialComponent->spatial.sphere.P); } void render ( ) { diff --git a/src/xrGame/PHDebug.h b/src/xrGame/PHDebug.h index b60c662b90..bacc253d04 100644 --- a/src/xrGame/PHDebug.h +++ b/src/xrGame/PHDebug.h @@ -85,7 +85,7 @@ void DBG_PH_NetRelcase( CObject* obj ); struct CFunctionGraph { public: - typedef fastdelegate::FastDelegate1 type_function; + typedef xr_delegate type_function; private: CStatGraph *m_stat_graph ; type_function m_function ; diff --git a/src/xrGame/PHMovementControl.cpp b/src/xrGame/PHMovementControl.cpp index b4bd65d844..6c0c4c188c 100644 --- a/src/xrGame/PHMovementControl.cpp +++ b/src/xrGame/PHMovementControl.cpp @@ -163,8 +163,9 @@ void CPHMovementControl::Calculate(Fvector& vAccel, const Fvector& camDir, float UpdateCollisionDamage(); ICollisionDamageInfo* cdi = CollisionDamageInfo(); - if (cdi->HitCallback()) - cdi->HitCallback()->call(gcontact_Initiator, fMinCrashSpeed, fMaxCrashSpeed, fContactSpeed, gcontact_HealthLost, cdi); + ICollisionHitCallback* hit_callback = cdi ? cdi->HitCallback() : nullptr; + if (hit_callback) + hit_callback->call(gcontact_Initiator, fMinCrashSpeed, fMaxCrashSpeed, fContactSpeed, gcontact_HealthLost, cdi); TraceBorder(previous_position); CheckEnvironment(vPosition); @@ -1276,7 +1277,7 @@ void CPHMovementControl::UpdateObjectBox(CPHCharacter* ach) return; Fvector cbox; - PKinematics(pObject->Visual())->CalculateBones(); + //PKinematics(pObject->Visual())->CalculateBones(); pObject->BoundingBox().getradius(cbox); const Fvector& pa = ach->BodyPosition(); diff --git a/src/xrGame/PHMovementDynamicActivate.cpp b/src/xrGame/PHMovementDynamicActivate.cpp index eb88f78ffe..e707463182 100644 --- a/src/xrGame/PHMovementDynamicActivate.cpp +++ b/src/xrGame/PHMovementDynamicActivate.cpp @@ -27,7 +27,7 @@ bool CPHMovementControl::ActivateBoxDynamic(DWORD id, int num_it/*=8*/, int num_ if (Device.dwTimeGlobal - trying_times[id] < 500 && dif.magnitude() < 0.05f) return false; } - if (!m_character || m_character->PhysicsRefObject()->ObjectPPhysicsShell()) + if (!m_character || (m_character->PhysicsRefObject() && m_character->PhysicsRefObject()->ObjectPPhysicsShell())) return false; DWORD old_id = BoxID(); diff --git a/src/xrGame/PHShellCreator.cpp b/src/xrGame/PHShellCreator.cpp index 9821012003..1f17ae15a1 100644 --- a/src/xrGame/PHShellCreator.cpp +++ b/src/xrGame/PHShellCreator.cpp @@ -24,6 +24,15 @@ void CPHShellSimpleCreator::CreatePhysicsShell() #endif owner->m_pPhysicsShell->build_FromKinematics(pKinematics, 0); + if (owner->m_pPhysicsShell->get_ElementsNumber() == 0) + { + Msg(" ! Error: world item visual [%s] has no elements!", pKinematics->getDebugName().c_str()); + } + else if (!owner->m_pPhysicsShell->get_ElementByStoreOrder(0)->has_geoms()) + { + Msg(" ! Error: world item visual [%s] has no shape!", pKinematics->getDebugName().c_str()); + } + owner->PPhysicsShell()->set_PhysicsRefObject(owner); //m_pPhysicsShell->SmoothElementsInertia(0.3f); owner->PPhysicsShell()->mXFORM.set(owner->XFORM()); diff --git a/src/xrGame/ParticlesObject.cpp b/src/xrGame/ParticlesObject.cpp index 7f2ecd6b98..0e76fdd421 100644 --- a/src/xrGame/ParticlesObject.cpp +++ b/src/xrGame/ParticlesObject.cpp @@ -2,15 +2,17 @@ // file: PSObject.cpp //---------------------------------------------------- #include "stdafx.h" -#pragma hdrstop - #include "ParticlesObject.h" +#include "../xrParticles/ParticlesAsyncManager.h" #include "../xrEngine/defines.h" #include "../Include/xrRender/RenderVisual.h" #include "../Include/xrRender/ParticleCustom.h" #include "../xrEngine/render.h" #include "../xrEngine/IGame_Persistent.h" #include "../xrEngine/environment.h" +#include "_thread_types.h" + +#include "../xrCore/profiler.h" const Fvector zero_vel = {0.f, 0.f, 0.f}; @@ -32,7 +34,7 @@ void CParticlesObject::Init(LPCSTR p_name, IRender_Sector* S, BOOL bAutoRemove) // create visual renderable.visual = Render->model_CreateParticles(p_name); VERIFY(renderable.visual); - IParticleCustom* V = smart_cast(renderable.visual); + IParticleCustom* V = renderable.visual ? renderable.visual->dcast_ParticleCustom() : NULL; VERIFY(V); time_limit = V->GetTimeLimit(); } @@ -60,24 +62,17 @@ void CParticlesObject::Init(LPCSTR p_name, IRender_Sector* S, BOOL bAutoRemove) // spatial - spatial.type = 0; - spatial.sector = S; + SpatialComponent->spatial.type = 0; + SpatialComponent->spatial.sector = S; - // sheduled - shedule.t_min = 20; - shedule.t_max = 50; - shedule_register(); + NeedUpdate = CParticlesAsync::NeedForceUpdate(); dwLastTime = Device.dwTimeGlobal; - mt_dt = 0; } +//---------------------------------------------------- CParticlesObject::~CParticlesObject() { - VERIFY(0==mt_dt); - - // we do not need this since CPS_Instance does it - // shedule_unregister (); } void CParticlesObject::UpdateSpatial() @@ -92,21 +87,21 @@ void CParticlesObject::UpdateSpatial() float R; renderable.xform.transform_tiny(P, vis.sphere.P); R = vis.sphere.R; - if (0 == spatial.type) + if (0 == SpatialComponent->spatial.type) { // First 'valid' update - register - spatial.type = STYPE_RENDERABLE; - spatial.sphere.set(P, R); + SpatialComponent->spatial.type = STYPE_PARTICLE; + SpatialComponent->spatial.sphere.set(P, R); spatial_register(); } else { - BOOL bMove = FALSE; - if (!P.similar(spatial.sphere.P, EPS_L * 10.f)) bMove = TRUE; - if (!fsimilar(R, spatial.sphere.R, 0.15f)) bMove = TRUE; + bool bMove = false; + if (!P.similar(SpatialComponent->spatial.sphere.P, EPS_L * 10.f)) bMove = true; + if (!fsimilar(R, SpatialComponent->spatial.sphere.R, 0.15f)) bMove = true; if (bMove) { - spatial.sphere.set(P, R); + SpatialComponent->spatial.sphere.set(P, R); spatial_move(); } } @@ -117,115 +112,99 @@ const shared_str CParticlesObject::Name() { if (g_dedicated_server) return ""; - IParticleCustom* V = smart_cast(renderable.visual); + IParticleCustom* V = renderable.visual ? renderable.visual->dcast_ParticleCustom() : NULL; VERIFY(V); return (V) ? V->Name() : ""; } +intrusive_ptr Particles::Details::Create(LPCSTR p_name, BOOL bAutoRemove, bool remove_on_game_load) +{ + intrusive_ptr Particle = xr_new(p_name, bAutoRemove, remove_on_game_load); + g_pGamePersistent->ps_active_deffer.push_back(Particle); + + return Particle; +} + void CParticlesObject::Play(bool bHudMode) { if (g_dedicated_server) return; - IParticleCustom* V = smart_cast(renderable.visual); + IParticleCustom* V = renderable.visual ? renderable.visual->dcast_ParticleCustom() : NULL; VERIFY(V); if (bHudMode) V->SetHudMode(bHudMode); V->Play(); dwLastTime = Device.dwTimeGlobal - 33ul; - mt_dt = 0; - PerformAllTheWork(0); + + PerformAllTheWork(); m_bStopping = false; + + if (NeedUpdate) + { + CParticlesAsync::ForceUpdate(this); + NeedUpdate = false; + } } void CParticlesObject::play_at_pos(const Fvector& pos, BOOL xform) { if (g_dedicated_server) return; - IParticleCustom* V = smart_cast(renderable.visual); + IParticleCustom* V = renderable.visual ? renderable.visual->dcast_ParticleCustom() : NULL; VERIFY(V); Fmatrix m; m.translate(pos); V->UpdateParent(m, zero_vel, xform); V->Play(); dwLastTime = Device.dwTimeGlobal - 33ul; - mt_dt = 0; - PerformAllTheWork(0); + + PerformAllTheWork(); m_bStopping = false; + + if (NeedUpdate) + { + CParticlesAsync::ForceUpdate(this); + NeedUpdate = false; + } } void CParticlesObject::Stop(BOOL bDefferedStop) { if (g_dedicated_server) return; - IParticleCustom* V = smart_cast(renderable.visual); + IParticleCustom* V = renderable.visual ? renderable.visual->dcast_ParticleCustom() : NULL; VERIFY(V); V->Stop(bDefferedStop); m_bStopping = true; } -void CParticlesObject::shedule_Update(u32 _dt) +void CParticlesObject::Update(u32 _dt) { inherited::shedule_Update(_dt); - if (g_dedicated_server) return; + if (g_dedicated_server) + return; + + if (m_bDead) + return; - // Update - if (m_bDead) return; - u32 dt = Device.dwTimeGlobal - dwLastTime; - if (dt) - { - if (0) - { - //.psDeviceFlags.test(mtParticles)) { //. AlexMX comment this line// NO UNCOMMENT - DON'T WORK PROPERLY - mt_dt = dt; - fastdelegate::FastDelegate0<> delegate(this, &CParticlesObject::PerformAllTheWork_mt); - Device.seqParallel.push_back(delegate); - } - else - { - mt_dt = 0; - IParticleCustom* V = smart_cast(renderable.visual); - VERIFY(V); - V->OnFrame(dt); - } - dwLastTime = Device.dwTimeGlobal; - } UpdateSpatial(); } -void CParticlesObject::PerformAllTheWork(u32 _dt) +void CParticlesObject::PerformAllTheWork() { if (g_dedicated_server) return; // Update - u32 dt = Device.dwTimeGlobal - dwLastTime; - if (dt) - { - IParticleCustom* V = smart_cast(renderable.visual); - VERIFY(V); - V->OnFrame(dt); - dwLastTime = Device.dwTimeGlobal; - } UpdateSpatial(); } -void CParticlesObject::PerformAllTheWork_mt() -{ - if (g_dedicated_server) return; - - if (0 == mt_dt) return; //??? - IParticleCustom* V = smart_cast(renderable.visual); - VERIFY(V); - V->OnFrame(mt_dt); - mt_dt = 0; -} - void CParticlesObject::SetXFORM(const Fmatrix& m) { if (g_dedicated_server) return; - IParticleCustom* V = smart_cast(renderable.visual); + IParticleCustom* V = renderable.visual ? renderable.visual->dcast_ParticleCustom() : NULL; VERIFY(V); V->UpdateParent(m, zero_vel,TRUE); renderable.xform.set(m); @@ -236,7 +215,7 @@ void CParticlesObject::UpdateParent(const Fmatrix& m, const Fvector& vel) { if (g_dedicated_server) return; - IParticleCustom* V = smart_cast(renderable.visual); + IParticleCustom* V = renderable.visual ? renderable.visual->dcast_ParticleCustom() : NULL; VERIFY(V); V->UpdateParent(m, vel,FALSE); UpdateSpatial(); @@ -260,20 +239,13 @@ float CParticlesObject::shedule_Scale() return Device.vCameraPosition.distance_to(Position()) / 200.f; } -void CParticlesObject::renderable_Render() +void CParticlesObject::renderable_Render(IDSGraphManager* DM) { - VERIFY(renderable.visual); - u32 dt = Device.dwTimeGlobal - dwLastTime; - if (dt) - { - IParticleCustom* V = smart_cast(renderable.visual); - VERIFY(V); - V->OnFrame(dt); - dwLastTime = Device.dwTimeGlobal; - } + if (!renderable.visual) + return; - ::Render->set_Transform(&renderable.xform); - ::Render->add_Visual(renderable.visual); + DM->add_Dynamic(renderable.visual, &renderable.xform); + renderable.visual->getVisData().hom_frame = Device.dwFrame; } bool CParticlesObject::IsAutoRemove() @@ -292,18 +264,36 @@ void CParticlesObject::SetHudMode(bool bHudMode) { if (g_dedicated_server) return; - IParticleCustom* V = smart_cast(renderable.visual); + IParticleCustom* V = renderable.visual ? renderable.visual->dcast_ParticleCustom() : NULL; VERIFY(V); V->SetHudMode(bHudMode); } +void CParticlesObject::SetLiveUpdate(BOOL b) +{ + if(g_dedicated_server) return; + + IParticleCustom* V = renderable.visual ? renderable.visual->dcast_ParticleCustom() : NULL; + VERIFY(V); + V->SetLiveUpdate(b); +} + +BOOL CParticlesObject::GetLiveUpdate() +{ + if(g_dedicated_server) return FALSE; + + IParticleCustom* V = renderable.visual ? renderable.visual->dcast_ParticleCustom() : NULL; + VERIFY(V); + return V->GetLiveUpdate(); +} + //играются ли партиклы, отличается от PSI_Alive, тем что после //остановки Stop партиклы могут еще доигрывать анимацию IsPlaying = true bool CParticlesObject::IsPlaying() { if (g_dedicated_server) return false; - IParticleCustom* V = smart_cast(renderable.visual); + IParticleCustom* V = renderable.visual ? renderable.visual->dcast_ParticleCustom() : NULL; VERIFY(V); return !!V->IsPlaying(); } diff --git a/src/xrGame/ParticlesObject.h b/src/xrGame/ParticlesObject.h index 033d85bbed..acbb848ba1 100644 --- a/src/xrGame/ParticlesObject.h +++ b/src/xrGame/ParticlesObject.h @@ -7,9 +7,9 @@ extern const Fvector zero_vel; class CParticlesObject : public CPS_Instance { - typedef CPS_Instance inherited; + friend class CParticlesAsync; + using inherited = CPS_Instance; - u32 dwLastTime; void Init(LPCSTR p_name, IRender_Sector* S, BOOL bAutoRemove); void UpdateSpatial(); @@ -17,21 +17,17 @@ class CParticlesObject : public CPS_Instance bool m_bLooped; //флаг, что система зациклена bool m_bStopping; //вызвана функция Stop() -protected: - u32 mt_dt; - -protected: - virtual ~CParticlesObject(); - + bool NeedUpdate = false; + public: + virtual ~CParticlesObject(); CParticlesObject(LPCSTR p_name, BOOL bAutoRemove, bool destroy_on_game_load); virtual bool shedule_Needed() { return true; }; virtual float shedule_Scale(); - virtual void shedule_Update(u32 dt); - virtual void renderable_Render(); - void PerformAllTheWork(u32 dt); - void __stdcall PerformAllTheWork_mt(); + virtual void Update(u32 dt) override; + virtual void renderable_Render(IDSGraphManager* DM); + void PerformAllTheWork(); Fvector& Position(); void SetXFORM(const Fmatrix& m); @@ -41,7 +37,7 @@ class CParticlesObject : public CPS_Instance void play_at_pos(const Fvector& pos, BOOL xform = FALSE); virtual void Play(bool bHudMode); void Stop(BOOL bDefferedStop = TRUE); - virtual BOOL Locked() { return mt_dt; } + // virtual BOOL Locked() { return mt_dt; } bool IsLooped() { return m_bLooped; } bool IsAutoRemove(); @@ -50,13 +46,17 @@ class CParticlesObject : public CPS_Instance void SetHudMode(bool bHudMode); const shared_str Name(); -public: - static CParticlesObject* Create(LPCSTR p_name, BOOL bAutoRemove = TRUE, bool remove_on_game_load = true) - { - return xr_new(p_name, bAutoRemove, remove_on_game_load); - } + void SetLiveUpdate(BOOL b); + BOOL GetLiveUpdate(); + +}; - static void Destroy(CParticlesObject*& p) +namespace Particles::Details +{ + intrusive_ptr Create(LPCSTR p_name, BOOL bAutoRemove = TRUE, bool remove_on_game_load = true); + + template + static void Destroy(T& p) { if (p) { @@ -64,6 +64,6 @@ class CParticlesObject : public CPS_Instance p = 0; } } -}; +} #endif /*ParticlesObjectH*/ diff --git a/src/xrGame/ParticlesPlayer.cpp b/src/xrGame/ParticlesPlayer.cpp index 7aadd735e6..6932001db9 100644 --- a/src/xrGame/ParticlesPlayer.cpp +++ b/src/xrGame/ParticlesPlayer.cpp @@ -28,7 +28,7 @@ CParticlesPlayer::SParticlesInfo* CParticlesPlayer::SBoneInfo::AppendParticles( if (pi) return pi; particles.push_back(SParticlesInfo()); pi = &particles.back(); - pi->ps = CParticlesObject::Create(*ps_name,FALSE); + pi->ps = Particles::Details::Create(*ps_name,FALSE); return pi; } @@ -40,7 +40,7 @@ void CParticlesPlayer::SBoneInfo::StopParticles(const shared_str& ps_name, bool if (!bDestroy) pi->ps->Stop(); else - CParticlesObject::Destroy(pi->ps); + Particles::Details::Destroy(pi->ps); } } @@ -52,7 +52,7 @@ void CParticlesPlayer::SBoneInfo::StopParticles(u16 sender_id, bool bDestroy) if (!bDestroy) it->ps->Stop(); else - CParticlesObject::Destroy(it->ps); + Particles::Details::Destroy(it->ps); } } @@ -122,7 +122,7 @@ void CParticlesPlayer::net_DestroyParticles() for (ParticlesInfoListIt p_it = b_info.particles.begin(); p_it != b_info.particles.end(); p_it++) { SParticlesInfo& p_info = *p_it; - CParticlesObject::Destroy(p_info.ps); + Particles::Details::Destroy(p_info.ps); } b_info.particles.clear(); } @@ -298,7 +298,7 @@ void CParticlesPlayer::UpdateParticles() } if (!p_info.ps->IsPlaying()) { - CParticlesObject::Destroy(p_info.ps); + Particles::Details::Destroy(p_info.ps); } else m_bActiveBones = true; diff --git a/src/xrGame/ParticlesPlayer.h b/src/xrGame/ParticlesPlayer.h index 04c58309ee..aaf13b44a8 100644 --- a/src/xrGame/ParticlesPlayer.h +++ b/src/xrGame/ParticlesPlayer.h @@ -20,7 +20,7 @@ class CParticlesPlayer //структура с внутренней информацией о партикле struct SParticlesInfo { - CParticlesObject* ps; + intrusive_ptr ps; Fvector angles; u16 sender_id; //id - объекта, который запустил партиклы u32 life_time; //время жизни партикла (-1) - бесконечно diff --git a/src/xrGame/PhraseDialogManager.h b/src/xrGame/PhraseDialogManager.h index 9ce5f269ab..42d89bb4ad 100644 --- a/src/xrGame/PhraseDialogManager.h +++ b/src/xrGame/PhraseDialogManager.h @@ -2,6 +2,9 @@ #include "PhraseDialogDefs.h" +class CInventoryOwner; +class CAI_PhraseDialogManager; + class CPhraseDialogManager { public: @@ -26,6 +29,10 @@ class CPhraseDialogManager const DIALOG_SHARED_PTR& GetDialogByID(const shared_str& dialog_id) const; bool HaveAvailableDialog(const shared_str& dialog_id) const; + virtual CPhraseDialogManager* cast_phrase_dialog_manager() { return this; } + virtual CAI_PhraseDialogManager* cast_ai_phrase_dialog_manager() { return nullptr; } + virtual CInventoryOwner* cast_inventory_owner() { return nullptr; } + protected: virtual bool AddAvailableDialog(shared_str dialog_id, CPhraseDialogManager* partner); diff --git a/src/xrGame/PhysicObject.cpp b/src/xrGame/PhysicObject.cpp index 88165adb7b..d9d1f9ad52 100644 --- a/src/xrGame/PhysicObject.cpp +++ b/src/xrGame/PhysicObject.cpp @@ -391,7 +391,7 @@ void CPhysicObject::UpdateCL() //двигаем объект за анимацией if (m_pPhysicsShell->PPhysicsShellAnimator()) { - m_pPhysicsShell->AnimatorOnFrame(); + m_pPhysicsShell->AnimatorOnFrame(!!Render->ViewBase.testSphere_dirty(SpatialComponent->spatial.sphere.P, SpatialComponent->spatial.sphere.R)); } if (!IsGameTypeSingle()) diff --git a/src/xrGame/PhysicObject.h b/src/xrGame/PhysicObject.h index 07f3b3cece..605ab034ca 100644 --- a/src/xrGame/PhysicObject.h +++ b/src/xrGame/PhysicObject.h @@ -95,6 +95,10 @@ class CPhysicObject : void unset_door_ignore_dynamics(); public: bool get_door_vectors(Fvector& closed, Fvector& open) const; + + virtual CPhysicsShellHolder* cast_physics_shell_holder() { return this; } + virtual CPhysicObject* cast_physics_object() { return this; } + public: CPhysicObject(void); virtual ~CPhysicObject(void); diff --git a/src/xrGame/PhysicsShellHolder.cpp b/src/xrGame/PhysicsShellHolder.cpp index 1aa767aa15..8315b40661 100644 --- a/src/xrGame/PhysicsShellHolder.cpp +++ b/src/xrGame/PhysicsShellHolder.cpp @@ -80,10 +80,11 @@ void CPhysicsShellHolder::net_Destroy() CCharacterPhysicsSupport* char_support = character_physics_support(); if (char_support) char_support->destroy_imotion(); + deactivate_physics_shell(); + inherited::net_Destroy(); b_sheduled = false; - deactivate_physics_shell(); xr_delete(m_pPhysicsShell); } @@ -388,6 +389,7 @@ void CPhysicsShellHolder::OnChangeVisual() void CPhysicsShellHolder::UpdateCL() { + PROF_EVENT(); inherited::UpdateCL(); //обновить присоединенные партиклы UpdateParticles(); diff --git a/src/xrGame/PhysicsShellHolder.h b/src/xrGame/PhysicsShellHolder.h index 403ab67375..b3106f47c2 100644 --- a/src/xrGame/PhysicsShellHolder.h +++ b/src/xrGame/PhysicsShellHolder.h @@ -71,19 +71,21 @@ class CPhysicsShellHolder : public CGameObject, virtual const IPhysicsShell* physics_shell() const; virtual IPhysicsShell* physics_shell(); virtual const IPhysicsElement* physics_character() const; - virtual CPHDestroyable* ph_destroyable() { return NULL; } - virtual ICollisionDamageReceiver* PHCollisionDamageReceiver() { return NULL; } - virtual CPHSkeleton* PHSkeleton() { return NULL; } + virtual CPHDestroyable* ph_destroyable() { return nullptr; } + virtual ICollisionDamageReceiver* PHCollisionDamageReceiver() { return nullptr; } + virtual CPHSkeleton* PHSkeleton() { return nullptr; } virtual CPhysicsShellHolder* cast_physics_shell_holder() { return this; } + virtual CPhysicItem* cast_physics_item() { return nullptr; } virtual CParticlesPlayer* cast_particles_player() { return this; } - virtual IDamageSource* cast_IDamageSource() { return NULL; } - virtual CPHSoundPlayer* ph_sound_player() { return NULL; } - virtual CCharacterPhysicsSupport* character_physics_support() { return NULL; } - virtual const CCharacterPhysicsSupport* character_physics_support() const { return NULL; } - virtual CIKLimbsController* character_ik_controller() { return NULL; } - virtual ICollisionHitCallback* get_collision_hit_callback() { return NULL; } - virtual void set_collision_hit_callback(ICollisionHitCallback* cc) { ; } - virtual void _BCL enable_notificate() { ; } + virtual CGameObject* cast_game_object() { return this; } + virtual IDamageSource* cast_IDamageSource() { return nullptr; } + virtual CPHSoundPlayer* ph_sound_player() { return nullptr; } + virtual CCharacterPhysicsSupport* character_physics_support() { return nullptr; } + virtual const CCharacterPhysicsSupport* character_physics_support() const { return nullptr; } + virtual CIKLimbsController* character_ik_controller() { return nullptr; } + virtual ICollisionHitCallback* get_collision_hit_callback() { return nullptr; } + virtual void set_collision_hit_callback(ICollisionHitCallback* cc) {} + virtual void _BCL enable_notificate() {} public: virtual void PHGetLinearVell(Fvector& velocity); diff --git a/src/xrGame/PostprocessAnimator.cpp b/src/xrGame/PostprocessAnimator.cpp index d84f254b04..14ab0263d4 100644 --- a/src/xrGame/PostprocessAnimator.cpp +++ b/src/xrGame/PostprocessAnimator.cpp @@ -491,7 +491,7 @@ CPostprocessAnimatorControlled::CPostprocessAnimatorControlled(CEffectorControll : m_controller(c) { m_controller->SetPP(this); - SetFactorFunc(fastdelegate::FastDelegate0(m_controller, &CEffectorController::GetFactor)); + SetFactorFunc(xr_make_delegate(m_controller, &CEffectorController::GetFactor)); } CPostprocessAnimatorControlled::~CPostprocessAnimatorControlled() diff --git a/src/xrGame/PostprocessAnimator.h b/src/xrGame/PostprocessAnimator.h index cb29fb92d4..b123265d53 100644 --- a/src/xrGame/PostprocessAnimator.h +++ b/src/xrGame/PostprocessAnimator.h @@ -197,9 +197,9 @@ virtual BOOL Process (float dt, SPPInfo &PPInfo); class CPostprocessAnimatorLerp : public CPostprocessAnimator { protected: - fastdelegate::FastDelegate0 m_get_factor_func; + xr_delegate m_get_factor_func; public: - void SetFactorFunc(fastdelegate::FastDelegate0 f) { m_get_factor_func = f; } + void SetFactorFunc(xr_delegate f) { m_get_factor_func = f; } virtual BOOL Process(SPPInfo& PPInfo); }; diff --git a/src/xrGame/Scope.h b/src/xrGame/Scope.h index 78130eda32..d897f2ad91 100644 --- a/src/xrGame/Scope.h +++ b/src/xrGame/Scope.h @@ -16,5 +16,8 @@ class CScope : public CInventoryItemObject public: CScope(); virtual ~CScope(); + + virtual CScope* cast_addon_scope() {return this;} + DECLARE_SCRIPT_REGISTER_FUNCTION }; diff --git a/src/xrGame/ShootingObject.cpp b/src/xrGame/ShootingObject.cpp index e018fe90c2..38b8e50c03 100644 --- a/src/xrGame/ShootingObject.cpp +++ b/src/xrGame/ShootingObject.cpp @@ -7,7 +7,6 @@ #include "ShootingObject.h" -#include "ParticlesObject.h" #include "WeaponAmmo.h" #include "actor.h" @@ -239,7 +238,8 @@ void CShootingObject::StartParticles(CParticlesObject*& pParticles, LPCSTR parti return; } - pParticles = CParticlesObject::Create(particles_name, (BOOL)auto_remove_flag); + pParticles = Particles::Details::Create(particles_name, (BOOL)auto_remove_flag).get(); + pParticles->SetLiveUpdate(TRUE); UpdateParticles(pParticles, pos, vel); @@ -258,7 +258,7 @@ void CShootingObject::StopParticles(CParticlesObject*& pParticles) if (pParticles == NULL) return; pParticles->Stop(); - CParticlesObject::Destroy(pParticles); + Particles::Details::Destroy(pParticles); } void CShootingObject::UpdateParticles(CParticlesObject*& pParticles, @@ -276,7 +276,7 @@ void CShootingObject::UpdateParticles(CParticlesObject*& pParticles, && !pParticles->PSI_alive()) { pParticles->Stop(); - CParticlesObject::Destroy(pParticles); + Particles::Details::Destroy(pParticles); } } @@ -324,7 +324,8 @@ void CShootingObject::OnShellDrop(const Fvector& play_pos, if (!m_sShellParticles) return; if (Device.vCameraPosition.distance_to_sqr(play_pos) > 2 * 2) return; - CParticlesObject* pShellParticles = CParticlesObject::Create(*m_sShellParticles,TRUE); + intrusive_ptr pShellParticles = Particles::Details::Create(*m_sShellParticles,TRUE); + pShellParticles->SetLiveUpdate(TRUE); Fmatrix particles_pos; particles_pos.set(get_ParticlesXFORM()); @@ -364,7 +365,8 @@ void CShootingObject::StartFlameParticles() } StopFlameParticles(); - m_pFlameParticles = CParticlesObject::Create(*m_sFlameParticlesCurrent,FALSE); + m_pFlameParticles = Particles::Details::Create(*m_sFlameParticlesCurrent,FALSE); + m_pFlameParticles->SetLiveUpdate(TRUE); UpdateFlameParticles(); @@ -375,7 +377,8 @@ void CShootingObject::StartFlameParticles() { in_hud_mode = false; } - m_pFlameParticles->Play(in_hud_mode); + if(m_pFlameParticles) + m_pFlameParticles->Play(in_hud_mode); } void CShootingObject::StopFlameParticles() @@ -406,7 +409,7 @@ void CShootingObject::UpdateFlameParticles() !m_pFlameParticles->PSI_alive()) { m_pFlameParticles->Stop(); - CParticlesObject::Destroy(m_pFlameParticles); + Particles::Details::Destroy(m_pFlameParticles); } } @@ -562,4 +565,4 @@ void CShootingObject::StartShotParticles() CParticlesObject* pSmokeParticles = NULL; StartParticles(pSmokeParticles, *m_sShotParticles, m_vCurrentShootPos, m_vCurrentShootDir, true); -} \ No newline at end of file +} diff --git a/src/xrGame/ShootingObject.h b/src/xrGame/ShootingObject.h index 916c8d8b32..a12bc420be 100644 --- a/src/xrGame/ShootingObject.h +++ b/src/xrGame/ShootingObject.h @@ -10,6 +10,9 @@ #include "../xrEngine/render.h" #include "anticheat_dumpable_object.h" +#include "../xrParticles/psystem.h" +#include "ParticlesObject.h" + class CCartridge; class CParticlesObject; class IRender_Sector; @@ -263,7 +266,7 @@ class CShootingObject : public IAnticheatDumpable //для выстрела 1м и 2м видом стрельбы shared_str m_sFlameParticles; //объект партиклов огня - CParticlesObject* m_pFlameParticles; + intrusive_ptr m_pFlameParticles; //имя пратиклов для дыма shared_str m_sSmokeParticlesCurrent; diff --git a/src/xrGame/Silencer.cpp b/src/xrGame/Silencer.cpp index 3c6335b5db..2822522056 100644 --- a/src/xrGame/Silencer.cpp +++ b/src/xrGame/Silencer.cpp @@ -46,7 +46,7 @@ void CSilencer::OnH_B_Independent(bool just_before_destroy) inherited::OnH_B_Independent(just_before_destroy); } -void CSilencer::renderable_Render() +void CSilencer::renderable_Render(IDSGraphManager* DM) { - inherited::renderable_Render(); + inherited::renderable_Render(DM); } diff --git a/src/xrGame/Silencer.h b/src/xrGame/Silencer.h index 43c747f7af..3de2c4a80a 100644 --- a/src/xrGame/Silencer.h +++ b/src/xrGame/Silencer.h @@ -22,5 +22,7 @@ class CSilencer : public CInventoryItemObject virtual void OnH_B_Independent(bool just_before_destroy); virtual void UpdateCL(); - virtual void renderable_Render(); + virtual void renderable_Render(IDSGraphManager* DM); + + virtual CSilencer* cast_addon_silencer() {return this;} }; diff --git a/src/xrGame/Spectator.h b/src/xrGame/Spectator.h index 9e6ee89d9d..a7eeeb94d1 100644 --- a/src/xrGame/Spectator.h +++ b/src/xrGame/Spectator.h @@ -71,6 +71,8 @@ class CSpectator : virtual CGameObject* cast_game_object() { return this; } virtual IInputReceiver* cast_input_receiver() { return this; } + virtual CSpectator* cast_spectator() { return this; } + virtual void net_Relcase(CObject* O); void GetSpectatorString(string1024& pStr); diff --git a/src/xrGame/TeleWhirlwind.cpp b/src/xrGame/TeleWhirlwind.cpp index 74c76f1c81..95571b979e 100644 --- a/src/xrGame/TeleWhirlwind.cpp +++ b/src/xrGame/TeleWhirlwind.cpp @@ -215,8 +215,7 @@ bool CTeleWhirlwindObject::destroy_object(const Fvector dir, float val) CEntityAlive* pEntity = smart_cast(object); if (pEntity) { - CParticlesObject* pParticles = CParticlesObject::Create( - m_pTelekinesis->GetTearingParticles(), true, true); + intrusive_ptr pParticles = Particles::Details::Create(m_pTelekinesis->GetTearingParticles(), true, true); Fmatrix xform, m; Fvector angles; @@ -578,8 +577,7 @@ bool CTeleTrampolinObject::destroy_object(const Fvector dir, float val) CEntityAlive* pEntity = smart_cast(object); if (pEntity) { - CParticlesObject* pParticles = CParticlesObject::Create( - m_pTelekinesis->GetTearingParticles(), true, true); + intrusive_ptr pParticles = Particles::Details::Create(m_pTelekinesis->GetTearingParticles(), true, true); Fmatrix xform, m; Fvector angles; diff --git a/src/xrGame/Torch.cpp b/src/xrGame/Torch.cpp index 4b8e00cb36..31ec0caa23 100644 --- a/src/xrGame/Torch.cpp +++ b/src/xrGame/Torch.cpp @@ -155,8 +155,11 @@ void CTorch::Switch(bool light_on) { light_render->set_active(light_on); - // CActor *pA = smart_cast(H_Parent()); - //if(!pA) + if(light_on && H_Parent() && H_Parent()->cast_actor()) + { + m_prev_hp.x = -H_Parent()->cast_actor()->cam_Active()->yaw; + m_prev_hp.y = -H_Parent()->cast_actor()->cam_Active()->pitch; + } light_omni->set_active(light_on); } glow_render->set_active(light_on); @@ -305,10 +308,9 @@ void CTorch::SwitchLightOnly() } extern BOOL r_optimize_torch = TRUE; -void CTorch::UpdateCL() +void CTorch::Update() { - inherited::UpdateCL(); - + PROF_EVENT("CTorch::Update") if (!m_switched_on) return; if (isFlickering) @@ -324,20 +326,28 @@ void CTorch::UpdateCL() } } - CBoneInstance& BI = smart_cast(Visual())->LL_GetBoneInstance(guid_bone); - Fmatrix M; + Fmatrix M = PKinematics(Visual())->LL_GetTransform(guid_bone); if (H_Parent()) { - CActor* actor = smart_cast(H_Parent()); - if (actor) smart_cast(H_Parent()->Visual())->CalculateBones_Invalidate(); + if (!AlwaysTheCrow()) + MakeMeCrow(); + + CActor* actor = H_Parent()->cast_actor(); + //if (actor) PKinematics(H_Parent()->Visual())->CalculateBones_Invalidate(); - if (H_Parent()->XFORM().c.distance_to_sqr(Device.vCameraPosition) < _sqr(OPTIMIZATION_DISTANCE) || GameID() != - eGameIDSingle) + if ((H_Parent()->XFORM().c.distance_to_sqr(Device.vCameraPosition) < _sqr(OPTIMIZATION_DISTANCE) || GameID() != eGameIDSingle)) { // near camera - smart_cast(H_Parent()->Visual())->CalculateBones(); - M.mul_43(XFORM(), BI.mTransform); + //PKinematics(H_Parent()->Visual())->CalculateBones + //( + // !!Render->ViewBase.testSphere_dirty(H_Parent()->SpatialComponent->spatial.sphere.P, + // H_Parent()->SpatialComponent->spatial.sphere.R + SpatialComponent->spatial.sphere.R + light_render->get_homdata().sphere.R) + //); + if(actor && actor->HUDview()) + PKinematics(H_Parent()->Visual())->CalculateBones(TRUE); + + M.mulA_43(XFORM()); } else { @@ -369,7 +379,7 @@ void CTorch::UpdateCL() dir.setHP(m_prev_hp.x + m_delta_h, m_prev_hp.y); Fvector::generate_orthonormal_basis_normalized(dir, up, right); - if (!m_bUseInertion && actor->active_cam() == eacFirstEye) + if (!m_bUseInertion && actor->HUDview()) { CCameraBase* actorcam = actor->cam_FirstEye(); Fvector offset = actorcam->vPosition; @@ -423,13 +433,13 @@ void CTorch::UpdateCL() { if (getVisible() && m_pPhysicsShell) { - M.mul(XFORM(), BI.mTransform); + M.mulA_43(XFORM()); m_switched_on = false; light_render->set_active(false); light_omni->set_active(false); glow_render->set_active(false); - } //if (getVisible() && m_pPhysicsShell) + } } if (!m_switched_on) return; @@ -452,6 +462,25 @@ void CTorch::UpdateCL() glow_render->set_color(fclr); } +void CTorch::shedule_Update(u32 dt) +{ + inherited::shedule_Update(dt); + //Update(); + + if (H_Parent() && m_switched_on && !AlwaysTheCrow() && enabled()) + { + MakeMeCrow(); + } +} + +void CTorch::UpdateCL() +{ + PROF_EVENT("CTorch::UpdateCL") + inherited::UpdateCL (); + + Update(); +} + void CTorch::SetLanim(LPCSTR name, bool bFlicker, int flickerChance, float flickerDelay, float framerate) { lanim = LALib.FindItem(name); @@ -547,9 +576,9 @@ void CTorch::afterDetach() Switch(false); } -void CTorch::renderable_Render() +void CTorch::renderable_Render(IDSGraphManager* DM) { - inherited::renderable_Render(); + inherited::renderable_Render(DM); } void CTorch::enable(bool value) diff --git a/src/xrGame/Torch.h b/src/xrGame/Torch.h index b361ec886f..82f873b48f 100644 --- a/src/xrGame/Torch.h +++ b/src/xrGame/Torch.h @@ -58,6 +58,9 @@ class CTorch : public CInventoryItemObject virtual void OnMoveToSlot(const SInvItemPlace& prev); virtual void OnMoveToRuck(const SInvItemPlace& prev); virtual void UpdateCL(); + virtual void shedule_Update (u32 dt); + + void Update (); void Switch(); void Switch(bool light_on); @@ -94,7 +97,9 @@ class CTorch : public CInventoryItemObject virtual void afterAttach(); virtual void afterDetach(); - virtual void renderable_Render(); + virtual void renderable_Render (IDSGraphManager* DM); + + virtual CTorch* cast_torch() { return this; } DECLARE_SCRIPT_REGISTER_FUNCTION }; diff --git a/src/xrGame/TorridZone.cpp b/src/xrGame/TorridZone.cpp index 78693b00d2..fbe6ecfeb3 100644 --- a/src/xrGame/TorridZone.cpp +++ b/src/xrGame/TorridZone.cpp @@ -25,9 +25,18 @@ BOOL CTorridZone::net_Spawn(CSE_Abstract* DC) m_animator->Load(zone->get_motion()); m_animator->Play(true); + shedule.t_min = shedule.t_max = 1; + Engine.Sheduler.Register(this, TRUE); + return (TRUE); } +void CTorridZone::net_Destroy() +{ + inherited::net_Destroy(); + Engine.Sheduler.Unregister(this); +} + void CTorridZone::UpdateWorkload(u32 dt) { inherited::UpdateWorkload(dt); @@ -69,7 +78,7 @@ bool CTorridZone::Disable() // Lain: added bool CTorridZone::light_in_slow_mode() { - return false; + return true; } BOOL CTorridZone::AlwaysTheCrow() diff --git a/src/xrGame/TorridZone.h b/src/xrGame/TorridZone.h index 800a042073..f6350dfc48 100644 --- a/src/xrGame/TorridZone.h +++ b/src/xrGame/TorridZone.h @@ -14,10 +14,12 @@ class CTorridZone : public CMosquitoBald virtual void UpdateWorkload(u32 dt); virtual void shedule_Update(u32 dt); BOOL net_Spawn(CSE_Abstract* DC); + virtual void net_Destroy(); virtual bool IsVisibleForZones() { return true; } virtual bool Enable(); virtual bool Disable(); + virtual bool register_schedule() const { return false; } // Lain: added virtual bool light_in_slow_mode(); diff --git a/src/xrGame/UIDialogHolder.cpp b/src/xrGame/UIDialogHolder.cpp index 2d9aa49256..2af54d0f39 100644 --- a/src/xrGame/UIDialogHolder.cpp +++ b/src/xrGame/UIDialogHolder.cpp @@ -16,6 +16,10 @@ dlgItem::dlgItem(CUIWindow* pWnd) bool dlgItem::operator <(const dlgItem& itm) const { + if (!wnd) + return false; + if (!itm.wnd) + return true; return (int)enabled > (int)itm.enabled; } @@ -38,6 +42,9 @@ bool operator ==(const recvItem& i1, const recvItem& i2) CDialogHolder::CDialogHolder() { m_b_in_update = false; + m_b_in_render = false; + m_dialogsToRender.reserve(64); + m_dialogsToRender_new.reserve(64); } CDialogHolder::~CDialogHolder() @@ -127,7 +134,7 @@ void CDialogHolder::AddDialogToRender(CUIWindow* pDialog) bAdd = (m_dialogsToRender.end() == std::find(m_dialogsToRender.begin(), m_dialogsToRender.end(), itm)); if (!bAdd) return; - if (m_b_in_update) + if (m_b_in_update || m_b_in_render) m_dialogsToRender_new.push_back(itm); else m_dialogsToRender.push_back(itm); @@ -140,37 +147,46 @@ void CDialogHolder::RemoveDialogToRender(CUIWindow* pDialog) if (TopInputReceiver() == pDialog) SetMainInputReceiver(NULL, false); - dlgItem itm(pDialog); - itm.enabled = true; - xr_vector::iterator it = std::find(m_dialogsToRender.begin(), m_dialogsToRender.end(), itm); - - if (it != m_dialogsToRender.end()) - { - (*it).wnd->Show(false); - (*it).wnd->Enable(false); - (*it).enabled = false; - return; - } - - it = std::find(m_dialogsToRender_new.begin(), m_dialogsToRender_new.end(), itm); - - if (it != m_dialogsToRender_new.end()) - { - (*it).wnd->Show(false); - (*it).wnd->Enable(false); - (*it).enabled = false; - } + auto remove_from_list = [&](xr_vector& list) + { + dlgItem itm(pDialog); + auto it = std::find(list.begin(), list.end(), itm); + + if (it != list.end()) + { + (*it).wnd->Show(false); + (*it).wnd->Enable(false); + (*it).enabled = false; + + // NEW: If we aren't currently updating, we can safely erase it now. + // Otherwise, we MUST nullify the pointer to prevent dangling access. + if (m_b_in_update || m_b_in_render) + (*it).wnd = nullptr; // Crucial: stop OnFrame from touching this memory + else + list.erase(it); + + return true; + } + return false; + }; + + if (!remove_from_list(m_dialogsToRender)) + { + remove_from_list(m_dialogsToRender_new); + } } void CDialogHolder::DoRenderDialogs() { + m_b_in_render = true; xr_vector::iterator it = m_dialogsToRender.begin(); for (; it != m_dialogsToRender.end(); ++it) { - if ((*it).enabled && (*it).wnd->IsShown()) + if ((*it).enabled && (*it).wnd && (*it).wnd->IsShown()) (*it).wnd->Draw(); } + m_b_in_render = false; } void CDialogHolder::OnExternalHideIndicators() @@ -193,7 +209,7 @@ CUIDialogWnd* CDialogHolder::TopInputReceiver() void CDialogHolder::SetMainInputReceiver(CUIDialogWnd* ir, bool _find_remove) { - if (TopInputReceiver() == ir) return; + if (!_find_remove && TopInputReceiver() == ir) return; if (!ir || _find_remove) { @@ -205,19 +221,21 @@ void CDialogHolder::SetMainInputReceiver(CUIDialogWnd* ir, bool _find_remove) { VERIFY(ir && _find_remove); - u32 cnt = m_input_receivers.size(); - for (; cnt > 0; --cnt) - if (m_input_receivers[cnt - 1].m_item == ir) + for (int currentIndex = m_input_receivers.size() - 1; currentIndex >= 0; --currentIndex) + { + if (m_input_receivers[currentIndex].m_item != ir) + continue; + + const u32 nextIndex = currentIndex + 1; + if (nextIndex < m_input_receivers.size()) { - m_input_receivers[cnt].m_flags.set(recvItem::eCrosshair, - m_input_receivers[cnt - 1].m_flags.test(recvItem::eCrosshair)); - m_input_receivers[cnt].m_flags.set(recvItem::eIndicators, - m_input_receivers[cnt - 1].m_flags.test(recvItem::eIndicators)); - xr_vector::iterator it = m_input_receivers.begin(); - std::advance(it, cnt - 1); - m_input_receivers.erase(it); - break; + m_input_receivers[nextIndex].m_flags.set(recvItem::eCrosshair, m_input_receivers[currentIndex].m_flags.test(recvItem::eCrosshair)); + m_input_receivers[nextIndex].m_flags.set(recvItem::eIndicators, m_input_receivers[currentIndex].m_flags.test(recvItem::eIndicators)); } + + m_input_receivers.erase(m_input_receivers.begin() + currentIndex); + break; + } } } else @@ -242,6 +260,7 @@ void CDialogHolder::StopDialog(CUIDialogWnd* pDialog) void CDialogHolder::OnFrame() { + PROF_EVENT("CDialogHolder::OnFrame"); m_b_in_update = true; CUIDialogWnd* wnd = TopInputReceiver(); if (wnd && wnd->IsEnabled()) @@ -263,9 +282,18 @@ void CDialogHolder::OnFrame() m_dialogsToRender_new.clear(); } - std::sort(m_dialogsToRender.begin(), m_dialogsToRender.end()); - while (!m_dialogsToRender.empty() && (!m_dialogsToRender[m_dialogsToRender.size() - 1].enabled)) - m_dialogsToRender.pop_back(); + static auto eraseFunc = [](const dlgItem& item) + { + return !item.enabled || !item.wnd; + }; + m_dialogsToRender.erase( + std::remove_if( + m_dialogsToRender.begin(), + m_dialogsToRender.end(), + eraseFunc + ), + m_dialogsToRender.end() + ); } void CDialogHolder::CleanInternals() diff --git a/src/xrGame/UIDialogHolder.h b/src/xrGame/UIDialogHolder.h index 605691bced..8be9e08c21 100644 --- a/src/xrGame/UIDialogHolder.h +++ b/src/xrGame/UIDialogHolder.h @@ -34,11 +34,11 @@ class PROTECT_API CDialogHolder : public pureFrame xr_vector m_input_receivers; xr_vector m_dialogsToRender; xr_vector m_dialogsToRender_new; - bool m_b_in_update; + volatile bool m_b_in_update; + volatile bool m_b_in_render; void StartMenu(CUIDialogWnd* pDialog, bool bDoHideIndicators); void StopMenu(CUIDialogWnd* pDialog); - void SetMainInputReceiver(CUIDialogWnd* ir, bool _find_remove); protected: void DoRenderDialogs(); void CleanInternals(); @@ -51,6 +51,7 @@ class PROTECT_API CDialogHolder : public pureFrame CUIDialogWnd* TopInputReceiver(); void AddDialogToRender(CUIWindow* pDialog); void RemoveDialogToRender(CUIWindow* pDialog); + void SetMainInputReceiver(CUIDialogWnd* ir, bool _find_remove); virtual void _BCL OnFrame(); virtual bool UseIndicators() { return true; } diff --git a/src/xrGame/UIGameCustom.cpp b/src/xrGame/UIGameCustom.cpp index cda19a3a30..7f383f9501 100644 --- a/src/xrGame/UIGameCustom.cpp +++ b/src/xrGame/UIGameCustom.cpp @@ -44,6 +44,7 @@ CUIGameCustom::CUIGameCustom() m_pMessagesWnd = nullptr; ShowGameIndicators(true); ShowCrosshair(true); + CustomStatics.reserve(64); } bool g_b_ClearGameCaptions = false; @@ -56,6 +57,7 @@ CUIGameCustom::~CUIGameCustom() void CUIGameCustom::OnFrame() { + PROF_EVENT("CUIGameCustom::OnFrame"); CDialogHolder::OnFrame(); for (auto item : CustomStatics) item->Update(); @@ -83,6 +85,7 @@ void CUIGameCustom::OnFrame() void CUIGameCustom::Render() { + PROF_EVENT("CUIGameCustom::Render"); for (StaticDrawableWrapper* item : CustomStatics) item->Draw(); Window->Draw(); diff --git a/src/xrGame/UIGameCustom_script.cpp b/src/xrGame/UIGameCustom_script.cpp index bdff0f98af..49c08099ea 100644 --- a/src/xrGame/UIGameCustom_script.cpp +++ b/src/xrGame/UIGameCustom_script.cpp @@ -19,7 +19,7 @@ void CUIGameCustom::script_register(lua_State* L) .def_readwrite("m_endTime", &StaticDrawableWrapper::m_endTime) .def("wnd", &StaticDrawableWrapper::wnd), - class_("CUIGameCustom") + class_("CUIGameCustom") .def("AddDialogToRender", &CUIGameCustom::AddDialogToRender) .def("RemoveDialogToRender", &CUIGameCustom::RemoveDialogToRender) .def("AddCustomStatic", &CUIGameCustom::AddCustomStatic) diff --git a/src/xrGame/UIPlayerItem.h b/src/xrGame/UIPlayerItem.h index 2a9c3ccbea..78c5fe1383 100644 --- a/src/xrGame/UIPlayerItem.h +++ b/src/xrGame/UIPlayerItem.h @@ -54,6 +54,8 @@ class UIPlayerItem : public CUIWindow void Init(CUIXml& uiXml, LPCSTR playerNode, int index); s32 GetPlayerCheckPoints() const; virtual void Update(); + + virtual CUIWindow* ui_cast_window() { return this; } }; #endif diff --git a/src/xrGame/UITeamHeader.h b/src/xrGame/UITeamHeader.h index 6c9356d3b5..62b7d01a18 100644 --- a/src/xrGame/UITeamHeader.h +++ b/src/xrGame/UITeamHeader.h @@ -38,6 +38,8 @@ class UITeamHeader : public CUIWindow void Init(CUIXml& uiXml, LPCSTR path); virtual void Update(); + virtual CUIWindow* ui_cast_window() { return this; } + protected: private: }; //UITeamHeader diff --git a/src/xrGame/UITeamPanels.h b/src/xrGame/UITeamPanels.h index 663c973a3c..40949ee71b 100644 --- a/src/xrGame/UITeamPanels.h +++ b/src/xrGame/UITeamPanels.h @@ -38,6 +38,9 @@ class UITeamPanels : public CUIWindow void NeedUpdatePanels(); void SetArtefactsCount(s32 greenTeamArtC, s32 blueTeamArtC); + + virtual CUIWindow* ui_cast_window() { return this; } + }; #endif diff --git a/src/xrGame/UITeamState.h b/src/xrGame/UITeamState.h index bc7eae5949..2e98a4dc41 100644 --- a/src/xrGame/UITeamState.h +++ b/src/xrGame/UITeamState.h @@ -83,6 +83,8 @@ class UITeamState : public CUIWindow virtual void Update(); virtual void Draw(); + + virtual CUIWindow* ui_cast_window() { return this; } }; #endif diff --git a/src/xrGame/UsableScriptObject.h b/src/xrGame/UsableScriptObject.h index cb99c388a8..ec3ce473e7 100644 --- a/src/xrGame/UsableScriptObject.h +++ b/src/xrGame/UsableScriptObject.h @@ -19,6 +19,9 @@ class CUsableScriptObject //можно ли использовать объект стандартным (не скриптовым) образом bool nonscript_usable(); void set_nonscript_usable(bool usable); + + virtual CUsableScriptObject* cast_usable_script_object() {return this;} + virtual CGameObject* cast_game_object() { return nullptr; } private: shared_str m_sTipText; bool m_bNonscriptUsable; diff --git a/src/xrGame/Weapon.cpp b/src/xrGame/Weapon.cpp index 7c271b4d8c..f837ef3aa3 100644 --- a/src/xrGame/Weapon.cpp +++ b/src/xrGame/Weapon.cpp @@ -5,7 +5,6 @@ #include "stdafx.h" #include "Weapon.h" -#include "ParticlesObject.h" #include "entity_alive.h" #include "inventory_item_impl.h" #include "inventory.h" @@ -218,10 +217,10 @@ void CWeapon::UpdateXForm() boneL = boneR2; V->CalculateBones_Invalidate(); - V->CalculateBones(TRUE); + // V->CalculateBones(TRUE); - Fmatrix& mL = V->LL_GetTransform(u16(boneL)); - Fmatrix& mR = V->LL_GetTransform(u16(boneR)); + Fmatrix& mL = V->LL_GetTransform_safed(u16(boneL)); + Fmatrix& mR = V->LL_GetTransform_safed(u16(boneR)); // Calculate Fmatrix mRes; Fvector R, D, N; @@ -1203,6 +1202,7 @@ void CWeapon::OnEvent(NET_Packet& P, u16 type) void CWeapon::shedule_Update(u32 dT) { + PROF_EVENT("CWeapon::shedule_Update"); // Queue shrink // u32 dwTimeCL = Level().timeServer()-NET_Latency; // while ((NET.size()>2) && (NET[1].dwTimeStampActiveItem() == this); bool res = b_is_active_item && IsZoomed() && ZoomHideCrosshair() && ZoomTexture() && !IsRotatingToZoom(); return res; diff --git a/src/xrGame/Weapon.h b/src/xrGame/Weapon.h index 418e6d5919..bca657fd49 100644 --- a/src/xrGame/Weapon.h +++ b/src/xrGame/Weapon.h @@ -21,6 +21,12 @@ class ENGINE_API CMotionDef; class CSE_ALifeItemWeapon; class CSE_ALifeItemWeaponAmmo; class CWeaponMagazined; +class CWeaponMagazinedWGrenade; +class CWeaponBinoculars; +class CWeaponKnife; +class CWeaponBM16; +class CWeaponRPG7; +class CWeaponRG6; class CParticlesObject; class CUIWindow; class CBinocularsVision; @@ -65,15 +71,14 @@ class CWeapon : public CHudItemObject, virtual void net_Import(NET_Packet& P); virtual void net_Relcase(CObject* object) override; - virtual CWeapon* cast_weapon() - { - return this; - } - - virtual CWeaponMagazined* cast_weapon_magazined() - { - return 0; - } + virtual CWeapon* cast_weapon() { return this; } + virtual CWeaponBinoculars* cast_weapon_binoculars() { return nullptr; } + virtual CWeaponKnife* cast_weapon_knife() { return nullptr; } + virtual CWeaponMagazined* cast_weapon_magazined() { return nullptr; } + virtual CWeaponMagazinedWGrenade* cast_weapon_magazined_w_grenade() { return nullptr; } + virtual CWeaponBM16* cast_weapon_bm16() { return nullptr; } + virtual CWeaponRPG7* cast_weapon_rpg7() { return nullptr; } + virtual CWeaponRG6* cast_weapon_rg6() { return nullptr; } //serialization virtual void save(NET_Packet& output_packet); @@ -117,7 +122,7 @@ class CWeapon : public CHudItemObject, virtual void UpdateCL(); virtual void shedule_Update(u32 dt); - virtual void renderable_Render(); + virtual void renderable_Render(IDSGraphManager* DM); virtual void render_hud_mode(); virtual bool need_renderable(); diff --git a/src/xrGame/WeaponAmmo.cpp b/src/xrGame/WeaponAmmo.cpp index a105e93854..bd3cf1666d 100644 --- a/src/xrGame/WeaponAmmo.cpp +++ b/src/xrGame/WeaponAmmo.cpp @@ -211,14 +211,15 @@ bool CWeaponAmmo::Get(CCartridge& cartridge) return true; } -void CWeaponAmmo::renderable_Render() +void CWeaponAmmo::renderable_Render(IDSGraphManager* DM) { if (!m_ready_to_destroy) - inherited::renderable_Render(); + inherited::renderable_Render(DM); } void CWeaponAmmo::UpdateCL() { + PROF_EVENT(); VERIFY2(_valid(renderable.xform), *cName()); inherited::UpdateCL(); VERIFY2(_valid(renderable.xform), *cName()); diff --git a/src/xrGame/WeaponAmmo.h b/src/xrGame/WeaponAmmo.h index 3277941c37..6fd7746966 100644 --- a/src/xrGame/WeaponAmmo.h +++ b/src/xrGame/WeaponAmmo.h @@ -76,7 +76,7 @@ class CWeaponAmmo : virtual void OnH_B_Chield(); virtual void OnH_B_Independent(bool just_before_destroy); virtual void UpdateCL(); - virtual void renderable_Render(); + virtual void renderable_Render(IDSGraphManager* DM); virtual bool Useful() const; virtual float Weight() const; diff --git a/src/xrGame/WeaponAutomaticShotgun.cpp b/src/xrGame/WeaponAutomaticShotgun.cpp index f2277af1e0..7ccd838a03 100644 --- a/src/xrGame/WeaponAutomaticShotgun.cpp +++ b/src/xrGame/WeaponAutomaticShotgun.cpp @@ -1,7 +1,6 @@ #include "stdafx.h" #include "WeaponAutomaticShotgun.h" #include "entity.h" -#include "ParticlesObject.h" #include "xr_level_controller.h" #include "inventory.h" #include "level.h" diff --git a/src/xrGame/WeaponBinoculars.h b/src/xrGame/WeaponBinoculars.h index 2bcb65718e..81bbe386b5 100644 --- a/src/xrGame/WeaponBinoculars.h +++ b/src/xrGame/WeaponBinoculars.h @@ -39,6 +39,7 @@ class CWeaponBinoculars : public CWeaponCustomPistol virtual void render_item_ui(); virtual bool render_item_ui_query(); virtual bool use_crosshair() const { return false; } + virtual CWeaponBinoculars* cast_weapon_binoculars() { return this; } virtual bool GetBriefInfo(II_BriefInfo& info); virtual void net_Relcase(CObject* object); protected: diff --git a/src/xrGame/WeaponDispersion.cpp b/src/xrGame/WeaponDispersion.cpp index fad660de55..7643de6403 100644 --- a/src/xrGame/WeaponDispersion.cpp +++ b/src/xrGame/WeaponDispersion.cpp @@ -42,8 +42,11 @@ float CWeapon::GetFireDispersion(float cartridge_k, bool for_crosshair) if (H_Parent()) { const CInventoryOwner* pOwner = smart_cast(H_Parent()); - float parent_disp = pOwner->GetWeaponAccuracy(); - fire_disp += parent_disp; + if (pOwner) + { + float parent_disp = pOwner->GetWeaponAccuracy(); + fire_disp += parent_disp; + } } return fire_disp; diff --git a/src/xrGame/WeaponFire.cpp b/src/xrGame/WeaponFire.cpp index 7f598dc66f..acd85f6f4d 100644 --- a/src/xrGame/WeaponFire.cpp +++ b/src/xrGame/WeaponFire.cpp @@ -4,7 +4,6 @@ #include "stdafx.h" #include "Weapon.h" -#include "ParticlesObject.h" #include "entity.h" #include "actor.h" diff --git a/src/xrGame/WeaponKnife.h b/src/xrGame/WeaponKnife.h index 40689ee0b7..55734f8bbc 100644 --- a/src/xrGame/WeaponKnife.h +++ b/src/xrGame/WeaponKnife.h @@ -82,6 +82,8 @@ class CWeaponKnife : public CWeapon virtual bool GetBriefInfo(II_BriefInfo& info); + virtual CWeaponKnife* cast_weapon_knife() { return this; } + #ifdef DEBUG virtual void OnRender (); #endif @@ -140,7 +142,7 @@ class CWeaponKnife : public CWeapon u16 m_except_id; CObject* m_last_picked_obj; - typedef xr_vector spartial_base_t; + typedef xr_vector spartial_base_t; typedef buffer_vector victims_list_t; struct victim_bone_data diff --git a/src/xrGame/WeaponMagazined.cpp b/src/xrGame/WeaponMagazined.cpp index 5bb6d53eb1..667b6dabc1 100644 --- a/src/xrGame/WeaponMagazined.cpp +++ b/src/xrGame/WeaponMagazined.cpp @@ -2,7 +2,6 @@ #include "WeaponMagazined.h" #include "actor.h" -#include "ParticlesObject.h" #include "Scope.h" #include "Silencer.h" #include "GrenadeLauncher.h" @@ -71,7 +70,7 @@ CWeaponMagazined::~CWeaponMagazined() } // sounds - Device.remove_from_seq_parallel(fastdelegate::FastDelegate0<>(this, &CWeaponMagazined::UpdateSoundsPositions)); + Device.remove_from_seq_parallel(xr_make_delegate(this, &CWeaponMagazined::UpdateSoundsPositions)); } void CWeaponMagazined::net_Destroy() @@ -658,6 +657,7 @@ void CWeaponMagazined::on_b_hud_detach() extern ENGINE_API BOOL g_bootComplete; void CWeaponMagazined::UpdateCL() { + PROF_EVENT(); inherited::UpdateCL(); float dt = Device.fTimeDelta; @@ -711,7 +711,7 @@ void CWeaponMagazined::UpdateSounds() { // Force update of fire dependencies and then put into second thread, fixes flickering limbs get_LastFP(); - Device.seqParallel.push_back(fastdelegate::FastDelegate0<>(this, &CWeaponMagazined::UpdateSoundsPositions)); + Device.seqParallel.push_back(xr_make_delegate(this, &CWeaponMagazined::UpdateSoundsPositions)); } else { diff --git a/src/xrGame/WeaponMagazined.h b/src/xrGame/WeaponMagazined.h index f4e37fb3e5..e33abc8e42 100644 --- a/src/xrGame/WeaponMagazined.h +++ b/src/xrGame/WeaponMagazined.h @@ -7,6 +7,12 @@ class ENGINE_API CMotionDef; class CAnonHudItem; +class CWeaponBinoculars; +class CWeaponMagazinedWGrenade; +class CWeaponBM16; +class CWeaponRPG7; +class CWeaponRG6; + //размер очереди считается бесконечность //заканчиваем стрельбу, только, если кончились патроны #define WEAPON_ININITE_QUEUE -1 @@ -91,10 +97,12 @@ class CWeaponMagazined : public CWeapon void LoadSilencerKoeffs(); void LoadScopeKoeffs(); - virtual CWeaponMagazined* cast_weapon_magazined() - { - return this; - } + virtual CWeaponBinoculars* cast_weapon_binoculars() { return nullptr; } + virtual CWeaponMagazined* cast_weapon_magazined() { return this; } + virtual CWeaponMagazinedWGrenade* cast_weapon_magazined_w_grenade() { return nullptr; } + virtual CWeaponBM16* cast_weapon_bm16() { return nullptr; } + virtual CWeaponRPG7* cast_weapon_rpg7() { return nullptr; } + virtual CWeaponRG6* cast_weapon_rg6() { return nullptr; } virtual void SetDefaults(); virtual void FireStart(); diff --git a/src/xrGame/WeaponMagazinedWGrenade.cpp b/src/xrGame/WeaponMagazinedWGrenade.cpp index a60906c24a..a280f5caf8 100644 --- a/src/xrGame/WeaponMagazinedWGrenade.cpp +++ b/src/xrGame/WeaponMagazinedWGrenade.cpp @@ -1,7 +1,6 @@ #include "stdafx.h" #include "weaponmagazinedwgrenade.h" #include "entity.h" -#include "ParticlesObject.h" #include "GrenadeLauncher.h" #include "xrserver_objects_alife_items.h" #include "ExplosiveRocket.h" diff --git a/src/xrGame/WeaponMagazinedWGrenade.h b/src/xrGame/WeaponMagazinedWGrenade.h index 1e3a8f3068..dc21be4d42 100644 --- a/src/xrGame/WeaponMagazinedWGrenade.h +++ b/src/xrGame/WeaponMagazinedWGrenade.h @@ -71,6 +71,8 @@ class CWeaponMagazinedWGrenade : public CWeaponMagazined, virtual void PlayAnimFireModeSwitch(); virtual bool TryPlayAnimBore(); + virtual CWeaponMagazinedWGrenade* cast_weapon_magazined_w_grenade() { return this; } + //Script exports void SetAmmoElapsed2(int ammo_count); void AmmoTypeForEach2(const ::luabind::functor& funct); diff --git a/src/xrGame/WeaponPistol.cpp b/src/xrGame/WeaponPistol.cpp index efc27b3f29..d7adc5925c 100644 --- a/src/xrGame/WeaponPistol.cpp +++ b/src/xrGame/WeaponPistol.cpp @@ -1,6 +1,5 @@ #include "stdafx.h" #include "weaponpistol.h" -#include "ParticlesObject.h" #include "actor.h" CWeaponPistol::CWeaponPistol() diff --git a/src/xrGame/WeaponRG6.h b/src/xrGame/WeaponRG6.h index 715e6d18c7..54bfcdfac2 100644 --- a/src/xrGame/WeaponRG6.h +++ b/src/xrGame/WeaponRG6.h @@ -16,6 +16,8 @@ class CWeaponRG6 : public CRocketLauncher, virtual void Load(LPCSTR section); virtual void OnEvent(NET_Packet& P, u16 type); + virtual CWeaponRG6* cast_weapon_rg6() { return this; } + #ifdef CROCKETLAUNCHER_CHANGE virtual void UnloadRocket(); #endif diff --git a/src/xrGame/WeaponRPG7.h b/src/xrGame/WeaponRPG7.h index babacad492..0f94aea097 100644 --- a/src/xrGame/WeaponRPG7.h +++ b/src/xrGame/WeaponRPG7.h @@ -30,6 +30,9 @@ class CWeaponRPG7 : public CWeaponCustomPistol, virtual void UnloadMagazine(bool spawn_ammo = true); virtual void net_Import(NET_Packet& P); // import from server + + virtual CWeaponRPG7* cast_weapon_rpg7() { return this; } + protected: virtual bool AllowBore(); virtual void PlayAnimReload(); diff --git a/src/xrGame/WeaponShotgun.cpp b/src/xrGame/WeaponShotgun.cpp index ffee947fc8..b7c85eac4f 100644 --- a/src/xrGame/WeaponShotgun.cpp +++ b/src/xrGame/WeaponShotgun.cpp @@ -1,7 +1,6 @@ #include "stdafx.h" #include "weaponshotgun.h" #include "entity.h" -#include "ParticlesObject.h" #include "xr_level_controller.h" #include "inventory.h" #include "level.h" diff --git a/src/xrGame/WeaponStatMgun.cpp b/src/xrGame/WeaponStatMgun.cpp index 479fc3c338..56e73e9e04 100644 --- a/src/xrGame/WeaponStatMgun.cpp +++ b/src/xrGame/WeaponStatMgun.cpp @@ -260,6 +260,7 @@ void CWeaponStatMgun::Load(LPCSTR section) LPCSTR str = pSettings->r_string(cNameSect_str(), "barrels"); string128 sec; int n = _GetItemCount(str); + m_barrels.reserve(n); for (int i = 0; i < n; ++i) { _GetItem(str, i, sec); @@ -442,7 +443,7 @@ void CWeaponStatMgun::net_Destroy() { if (p_overheat->IsPlaying()) p_overheat->Stop(FALSE); - CParticlesObject::Destroy(p_overheat); + Particles::Details::Destroy(p_overheat); } #ifdef HOLDERCUSTOM_NEW @@ -800,9 +801,9 @@ void CWeaponStatMgun::cam_Update(float dt, float fov) #endif } -void CWeaponStatMgun::renderable_Render() +void CWeaponStatMgun::renderable_Render(IDSGraphManager* DM) { - inheritedPH::renderable_Render(); + inheritedPH::renderable_Render(DM); RenderLight(); @@ -1207,8 +1208,7 @@ void CWeaponStatMgun::UpdateSound() void CWeaponStatMgun::SetFeelVisionIgnore(bool enable) { #ifdef SPATIAL_CHANGE - ISpatial *IS = smart_cast(this); - R_ASSERT(IS); + ISpatialShared& IS = SpatialComponent; if (enable) IS->spatial.type |= STYPE_FEELVISIONIGNORE; else diff --git a/src/xrGame/WeaponStatMgun.h b/src/xrGame/WeaponStatMgun.h index 638c79ff15..f9b96d1a3e 100644 --- a/src/xrGame/WeaponStatMgun.h +++ b/src/xrGame/WeaponStatMgun.h @@ -52,7 +52,7 @@ struct SStmBarrel shared_str m_sShellParticles; shared_str m_sFlameParticles; - CParticlesObject *m_pFlameParticles; + intrusive_ptr m_pFlameParticles; shared_str m_sSmokeParticles; Fcolor light_base_color; @@ -135,6 +135,8 @@ class CWeaponStatMgun : public CPhysicsShellHolder, //casts public: virtual CHolderCustom* cast_holder_custom() { return this; } + virtual CGameObject* cast_game_object() { return this; } + virtual CWeaponStatMgun* cast_weapon_stat_mgun() { return this; } //general public: @@ -176,7 +178,7 @@ class CWeaponStatMgun : public CPhysicsShellHolder, float m_overheat_decr_quant; float m_overheat_threshold; shared_str m_overheat_particles; - CParticlesObject* p_overheat; + intrusive_ptr p_overheat; protected: void UpdateBarrelDir(); virtual const Fvector& get_CurrentFirePoint(); @@ -210,7 +212,7 @@ class CWeaponStatMgun : public CPhysicsShellHolder, #endif virtual void cam_Update(float dt, float fov = 90.0f); - virtual void renderable_Render(); + virtual void renderable_Render(IDSGraphManager* DM); virtual bool attach_Actor(CGameObject* actor); virtual void detach_Actor(); diff --git a/src/xrGame/WeaponStatMgunBarrel.cpp b/src/xrGame/WeaponStatMgunBarrel.cpp index 5f59bb0135..c3d98bd233 100644 --- a/src/xrGame/WeaponStatMgunBarrel.cpp +++ b/src/xrGame/WeaponStatMgunBarrel.cpp @@ -91,7 +91,7 @@ void SStmBarrel::StartParticles(CParticlesObject *&pParticles, LPCSTR particles_ UpdateParticles(pParticles, pos, vel); return; } - pParticles = CParticlesObject::Create(particles_name, (BOOL)auto_remove_flag); + pParticles = Particles::Details::Create(particles_name, (BOOL)auto_remove_flag).get(); UpdateParticles(pParticles, pos, vel); pParticles->Play(false); } @@ -101,7 +101,7 @@ void SStmBarrel::StopParticles(CParticlesObject *&pParticles) if (pParticles == nullptr) return; pParticles->Stop(); - CParticlesObject::Destroy(pParticles); + Particles::Details::Destroy(pParticles); } void SStmBarrel::UpdateParticles(CParticlesObject *&pParticles, const Fvector &pos, const Fvector &vel) @@ -112,7 +112,7 @@ void SStmBarrel::UpdateParticles(CParticlesObject *&pParticles, const Fvector &p if (!pParticles->IsAutoRemove() && !pParticles->IsLooped() && !pParticles->PSI_alive()) { pParticles->Stop(); - CParticlesObject::Destroy(pParticles); + Particles::Details::Destroy(pParticles); } } @@ -157,7 +157,7 @@ void SStmBarrel::StartFlameParticles() return; } StopFlameParticles(); - m_pFlameParticles = CParticlesObject::Create(m_sFlameParticles.c_str(), FALSE); + m_pFlameParticles = Particles::Details::Create(m_sFlameParticles.c_str(), FALSE); UpdateFlameParticles(); m_pFlameParticles->Play(false); } @@ -181,7 +181,7 @@ void SStmBarrel::UpdateFlameParticles() if (!m_pFlameParticles->IsLooped() && !m_pFlameParticles->IsPlaying() && !m_pFlameParticles->PSI_alive()) { m_pFlameParticles->Stop(); - CParticlesObject::Destroy(m_pFlameParticles); + Particles::Details::Destroy(m_pFlameParticles); } } @@ -279,7 +279,7 @@ void SStmBarrel::OnShellDrop(const Fvector &play_pos, const Fvector &parent_vel) { if (m_sShellParticles.size() == 0) return; - CParticlesObject *pShellParticles = CParticlesObject::Create(m_sShellParticles.c_str(), TRUE); + intrusive_ptr pShellParticles = Particles::Details::Create(m_sShellParticles.c_str(), TRUE); pShellParticles->UpdateParent(Fmatrix().set(m_fire_xfm).translate_over(play_pos), parent_vel); pShellParticles->Play(false); } diff --git a/src/xrGame/WeaponStatMgunFire.cpp b/src/xrGame/WeaponStatMgunFire.cpp index c09961580f..2dd1eab70c 100644 --- a/src/xrGame/WeaponStatMgunFire.cpp +++ b/src/xrGame/WeaponStatMgunFire.cpp @@ -84,7 +84,7 @@ void CWeaponStatMgun::UpdateFire() { if (p_overheat->IsPlaying()) p_overheat->Stop(FALSE); - CParticlesObject::Destroy(p_overheat); + Particles::Details::Destroy(p_overheat); } if (m_firing_disabled) m_firing_disabled = false; @@ -126,7 +126,7 @@ void CWeaponStatMgun::UpdateFire() { if (!p_overheat) { - p_overheat = CParticlesObject::Create(m_overheat_particles.c_str(),FALSE); + p_overheat = Particles::Details::Create(m_overheat_particles.c_str(),FALSE); Fmatrix pos; pos.set(get_ParticlesXFORM()); pos.c.set(get_CurrentFirePoint()); diff --git a/src/xrGame/ZoneCampfire.cpp b/src/xrGame/ZoneCampfire.cpp index fa6d198d07..cabfb1e81b 100644 --- a/src/xrGame/ZoneCampfire.cpp +++ b/src/xrGame/ZoneCampfire.cpp @@ -23,8 +23,8 @@ CZoneCampfire::CZoneCampfire() CZoneCampfire::~CZoneCampfire() { - CParticlesObject::Destroy(m_pDisabledParticles); - CParticlesObject::Destroy(m_pEnablingParticles); + Particles::Details::Destroy(m_pDisabledParticles); + Particles::Details::Destroy(m_pEnablingParticles); m_disabled_sound.destroy(); } @@ -40,14 +40,14 @@ void CZoneCampfire::GoEnabledState() if (m_pDisabledParticles) { m_pDisabledParticles->Stop(FALSE); - CParticlesObject::Destroy(m_pDisabledParticles); + Particles::Details::Destroy(m_pDisabledParticles); } m_disabled_sound.stop(); m_disabled_sound.destroy(); LPCSTR str = pSettings->r_string(cNameSect(), "enabling_particles"); - m_pEnablingParticles = CParticlesObject::Create(str,FALSE); + m_pEnablingParticles = Particles::Details::Create(str,FALSE); m_pEnablingParticles->UpdateParent(XFORM(), zero_vel); m_pEnablingParticles->Play(false); } @@ -58,7 +58,7 @@ void CZoneCampfire::GoDisabledState() R_ASSERT(NULL==m_pDisabledParticles); LPCSTR str = pSettings->r_string(cNameSect(), "disabled_particles"); - m_pDisabledParticles = CParticlesObject::Create(str,FALSE); + m_pDisabledParticles = Particles::Details::Create(str,FALSE); m_pDisabledParticles->UpdateParent(XFORM(), zero_vel); m_pDisabledParticles->Play(false); @@ -121,7 +121,7 @@ void CZoneCampfire::PlayIdleParticles(bool bIdleLight) if (m_pEnablingParticles) { m_pEnablingParticles->Stop(FALSE); - CParticlesObject::Destroy(m_pEnablingParticles); + Particles::Details::Destroy(m_pEnablingParticles); } } } diff --git a/src/xrGame/ZoneCampfire.h b/src/xrGame/ZoneCampfire.h index 1203420bb9..dfc05ccd57 100644 --- a/src/xrGame/ZoneCampfire.h +++ b/src/xrGame/ZoneCampfire.h @@ -6,8 +6,8 @@ class CZoneCampfire : public CMosquitoBald private: typedef CMosquitoBald inherited; protected: - CParticlesObject* m_pEnablingParticles; - CParticlesObject* m_pDisabledParticles; + intrusive_ptr m_pEnablingParticles; + intrusive_ptr m_pDisabledParticles; ref_sound m_disabled_sound; bool m_turned_on; u32 m_turn_time; diff --git a/src/xrGame/action_planner_inline.h b/src/xrGame/action_planner_inline.h index 480a820d1f..4826c1e3e5 100644 --- a/src/xrGame/action_planner_inline.h +++ b/src/xrGame/action_planner_inline.h @@ -83,7 +83,7 @@ void CPlanner::update() } #endif //Alundaio: debug action - bool bDbgAct = strstr(Core.Params, "-dbgact") != NULL; + bool bDbgAct = Core.ParamsData.test(ECoreParams::dbgact); #ifdef LOG_ACTION if (m_failed) diff --git a/src/xrGame/actor_communication.cpp b/src/xrGame/actor_communication.cpp index 6331bb60a6..142d642892 100644 --- a/src/xrGame/actor_communication.cpp +++ b/src/xrGame/actor_communication.cpp @@ -157,16 +157,7 @@ void CActor::NewPdaContact(CInventoryOwner* pInvOwner) void CActor::LostPdaContact(CInventoryOwner* pInvOwner) { - CGameObject* GO = smart_cast(pInvOwner); - if (GO) - { - for (int t = ALife::eRelationTypeFriend; t < ALife::eRelationTypeLast; ++t) - { - ALife::ERelationType tt = (ALife::ERelationType)t; - Level().MapManager().RemoveMapLocation(RELATION_REGISTRY().GetSpotName(tt), GO->ID()); - } - Level().MapManager().RemoveMapLocation("deadbody_location", GO->ID()); - }; + Level().MapManager().RemoveRelationLocation(pInvOwner); } void CActor::AddGameNews_deffered(GAME_NEWS_DATA& news_data, u32 delay) diff --git a/src/xrGame/agent_enemy_manager.cpp b/src/xrGame/agent_enemy_manager.cpp index eb13382afc..700c01bb84 100644 --- a/src/xrGame/agent_enemy_manager.cpp +++ b/src/xrGame/agent_enemy_manager.cpp @@ -102,6 +102,8 @@ void CAgentEnemyManager::fill_enemies() CAgentMemberManager::iterator E = object().member().combat_members().end(); for (; I != E; ++I) { + if (!(*I)) continue; + if ((*I)->object().getDestroy()) continue; (*I)->probability(1.f); (*I)->object().memory().fill_enemies(CEnemyFiller(&m_enemies, object().member().mask(&(*I)->object()))); } @@ -120,7 +122,7 @@ void CAgentEnemyManager::fill_enemies() if (I != m_enemies.end()) continue; - m_wounded.erase(m_wounded.begin() + i); + m_wounded.erase_fast(m_wounded.begin() + i); --i; --n; } @@ -196,21 +198,23 @@ void CAgentEnemyManager::exchange_enemies(CMemberOrder& member0, CMemberOrder& m void CAgentEnemyManager::compute_enemy_danger() { - ENEMIES::iterator I = m_enemies.begin(); - ENEMIES::iterator E = m_enemies.end(); - for (; I != E; ++I) - { - float best = -1.f; - CAgentMemberManager::const_iterator i = object().member().combat_members().begin(); - CAgentMemberManager::const_iterator e = object().member().combat_members().end(); - for (; i != e; ++i) - { - float value = evaluate((*I).m_object, &(*i)->object()); - if (value > best) - best = value; - } - (*I).m_probability = best; - } + { + ENEMIES::iterator I = m_enemies.begin(); + ENEMIES::iterator E = m_enemies.end(); + for (; I != E; ++I) + { + float best = -1.f; + CAgentMemberManager::const_iterator i = object().member().combat_members().begin(); + CAgentMemberManager::const_iterator e = object().member().combat_members().end(); + for (; i != e; ++i) + { + float value = evaluate((*I).m_object, &(*i)->object()); + if (value > best) + best = value; + } + (*I).m_probability = best; + } + } std::sort(m_enemies.begin(), m_enemies.end()); } @@ -266,39 +270,41 @@ void CAgentEnemyManager::assign_enemies() void CAgentEnemyManager::permutate_enemies() { // filling member enemies - CAgentMemberManager::iterator I = object().member().combat_members().begin(); - CAgentMemberManager::iterator E = object().member().combat_members().end(); - for (; I != E; ++I) - { - // clear enemies - (*I)->enemies().clear(); - // setup procesed flag - (*I)->processed(false); - // get member squad mask - squad_mask_type member_mask = object().member().mask(&(*I)->object()); - // setup if player has enemy - bool enemy_selected = false; - // iterate on enemies - ENEMIES::const_iterator i = m_enemies.begin(), b = i; - ENEMIES::const_iterator e = m_enemies.end(); - for (; i != e; ++i) - { - if ((*i).m_mask.is(member_mask)) - (*I)->enemies().push_back(u32(i - b)); - - if ((*i).m_distribute_mask.is(member_mask)) - { - (*I)->selected_enemy(u32(i - b)); - enemy_selected = true; - } - } - // if there is enemy - all is ok - if (enemy_selected) - continue; - - // otherwise temporary make the member processed - (*I)->processed(true); - } + { + CAgentMemberManager::iterator I = object().member().combat_members().begin(); + CAgentMemberManager::iterator E = object().member().combat_members().end(); + for (; I != E; ++I) + { + // clear enemies + (*I)->enemies().clear(); + // setup procesed flag + (*I)->processed(false); + // get member squad mask + squad_mask_type member_mask = object().member().mask(&(*I)->object()); + // setup if player has enemy + bool enemy_selected = false; + // iterate on enemies + ENEMIES::const_iterator i = m_enemies.begin(), b = i; + ENEMIES::const_iterator e = m_enemies.end(); + for (; i != e; ++i) + { + if ((*i).m_mask.is(member_mask)) + (*I)->enemies().push_back(u32(i - b)); + + if ((*i).m_distribute_mask.is(member_mask)) + { + (*I)->selected_enemy(u32(i - b)); + enemy_selected = true; + } + } + // if there is enemy - all is ok + if (enemy_selected) + continue; + + // otherwise temporary make the member processed + (*I)->processed(true); + } + } // perform permutations bool changed; @@ -509,7 +515,9 @@ void CAgentEnemyManager::assign_wounded() } u32 combat_member_count = population(object().member().combat_mask()); - VERIFY(combat_member_count == object().member().combat_members().size()); + { + VERIFY(combat_member_count == object().member().combat_members().size()); + } u32 population_level = 0; while (population(assigned) < combat_member_count) diff --git a/src/xrGame/agent_explosive_manager.cpp b/src/xrGame/agent_explosive_manager.cpp index b9aa0e6303..f19c837ca9 100644 --- a/src/xrGame/agent_explosive_manager.cpp +++ b/src/xrGame/agent_explosive_manager.cpp @@ -34,11 +34,11 @@ void CAgentExplosiveManager::remove_links(CObject* object) { TO_BE_DESTROYED::iterator I = std::find(m_explosives_to_remove.begin(), m_explosives_to_remove.end(), object->ID()); if (I != m_explosives_to_remove.end()) - m_explosives_to_remove.erase(I); + m_explosives_to_remove.erase_fast(I); EXPLOSIVES::iterator J = std::find(m_explosives.begin(), m_explosives.end(), object->ID()); if (J != m_explosives.end()) - m_explosives.erase(J); + m_explosives.erase_fast(J); } void CAgentExplosiveManager::register_explosive(const CExplosive* explosive, const CGameObject* game_object) diff --git a/src/xrGame/agent_manager.cpp b/src/xrGame/agent_manager.cpp index 5da21967b2..80b6dd889d 100644 --- a/src/xrGame/agent_manager.cpp +++ b/src/xrGame/agent_manager.cpp @@ -87,6 +87,7 @@ void CAgentManager::remove_links(CObject* object) void CAgentManager::update_impl() { + PROF_EVENT("CAgentManager::update_impl"); VERIFY(!member().members().empty()); memory().update(); diff --git a/src/xrGame/agent_manager_properties.cpp b/src/xrGame/agent_manager_properties.cpp index 1e92994864..3e544bbb80 100644 --- a/src/xrGame/agent_manager_properties.cpp +++ b/src/xrGame/agent_manager_properties.cpp @@ -45,7 +45,7 @@ CAgentManagerPropertyEvaluatorEnemy::_value_type CAgentManagerPropertyEvaluatorE for (; I != E; ++I) { VERIFY(*I); - if ((*I)->object().memory().enemy().selected()) + if ((*I) && (*I)->object().memoryPtr() && (*I)->object().memory().enemy().selected()) return (true); } return (false); diff --git a/src/xrGame/agent_member_manager.cpp b/src/xrGame/agent_member_manager.cpp index e7a10133ca..56eb7b7a25 100644 --- a/src/xrGame/agent_member_manager.cpp +++ b/src/xrGame/agent_member_manager.cpp @@ -69,6 +69,10 @@ void CAgentMemberManager::remove(CEntity* member) if (registered_in_combat(stalker)) unregister_in_combat(stalker); + // Force rebuild m_combat_members + m_actuality = false; + m_combat_members.clear(); + squad_mask_type m = mask(stalker); object().memory().update_memory_masks(m); object().memory().update_memory_mask(m, m_combat_mask); diff --git a/src/xrGame/ai/ai_monsters_misc.cpp b/src/xrGame/ai/ai_monsters_misc.cpp index f23a5c08bf..86b1fba771 100644 --- a/src/xrGame/ai/ai_monsters_misc.cpp +++ b/src/xrGame/ai/ai_monsters_misc.cpp @@ -127,14 +127,14 @@ u32 dwfChooseAction(u32 dwActionRefreshRate, float fMinProbability0, float fMinP if (!tpEntity) for (int k = 0; k < (int)Group.members().size(); ++k) { - if (Group.members()[k]->g_Alive() && ((Group.members()[k]->spatial.type & STYPE_VISIBLEFORAI) == + if (Group.members()[k]->g_Alive() && ((Group.members()[k]->SpatialComponent->spatial.type & STYPE_VISIBLEFORAI) == STYPE_VISIBLEFORAI)) Members.push_back(Group.members()[k]); } else for (int k = 0; k < (int)Group.members().size(); ++k) { - if (Group.members()[k]->g_Alive() && ((Group.members()[k]->spatial.type & STYPE_VISIBLEFORAI) == + if (Group.members()[k]->g_Alive() && ((Group.members()[k]->SpatialComponent->spatial.type & STYPE_VISIBLEFORAI) == STYPE_VISIBLEFORAI)) if (tpEntity->Position().distance_to(Group.members()[k]->Position()) < fGroupDistance) { diff --git a/src/xrGame/ai/crow/ai_crow.cpp b/src/xrGame/ai/crow/ai_crow.cpp index a4bdd86eee..5482a765a6 100644 --- a/src/xrGame/ai/crow/ai_crow.cpp +++ b/src/xrGame/ai/crow/ai_crow.cpp @@ -118,12 +118,8 @@ void CAI_Crow::Load(LPCSTR section) { inherited::Load(section); ////////////////////////////////////////////////////////////////////////// - ISpatial* self = smart_cast(this); - if (self) - { - self->spatial.type &= ~STYPE_VISIBLEFORAI; - self->spatial.type &= ~STYPE_REACTTOSOUND; - } + SpatialComponent->spatial.type &= ~STYPE_VISIBLEFORAI; + SpatialComponent->spatial.type &= ~STYPE_REACTTOSOUND; ////////////////////////////////////////////////////////////////////////// // sounds @@ -159,17 +155,7 @@ BOOL CAI_Crow::net_Spawn(CSE_Abstract* DC) m_Anims.m_fly.Load(M, "fly_fwd"); m_Anims.m_idle.Load(M, "fly_idle"); - renderable.visual->flags.set(IRenderVisualFlags::eIgnoreOptimization, TRUE); - - xr_vector* children = renderable.visual->get_children(); - - if (children) - { - for (auto* child : *children) - { - child->flags.set(IRenderVisualFlags::eIgnoreOptimization, TRUE); - } - } + renderable.visual->MarkIgnoreOptimization(TRUE); o_workload_frame = 0; o_workload_rframe = 0; @@ -220,8 +206,7 @@ void CAI_Crow::switch2_FlyIdle() void CAI_Crow::switch2_DeathDead() { // AI need to pickup this - ISpatial* self = smart_cast(this); - if (self) self->spatial.type |= STYPE_VISIBLEFORAI; + SpatialComponent->spatial.type |= STYPE_VISIBLEFORAI; // smart_cast(Visual())->PlayCycle(m_Anims.m_death_dead.GetRandom()); } @@ -353,10 +338,10 @@ void CAI_Crow::UpdateCL() } } -void CAI_Crow::renderable_Render() +void CAI_Crow::renderable_Render(IDSGraphManager* DM) { UpdateWorkload(Device.fTimeDelta); - inherited::renderable_Render(); + inherited::renderable_Render(DM); o_workload_rframe = Device.dwFrame; } @@ -364,7 +349,7 @@ collide::rq_result GetPickResult(Fvector pos, Fvector dir, float range, CObject* void CAI_Crow::shedule_Update(u32 DT) { float fDT = float(DT) / 1000.F; - spatial.type &= ~STYPE_VISIBLEFORAI; + SpatialComponent->spatial.type &= ~STYPE_VISIBLEFORAI; inherited::shedule_Update(DT); diff --git a/src/xrGame/ai/crow/ai_crow.h b/src/xrGame/ai/crow/ai_crow.h index 245df3f50d..b2a369379a 100644 --- a/src/xrGame/ai/crow/ai_crow.h +++ b/src/xrGame/ai/crow/ai_crow.h @@ -122,7 +122,7 @@ class CAI_Crow : public CEntity virtual void net_Destroy(); virtual BOOL renderable_ShadowGenerate() { return FALSE; } virtual BOOL renderable_ShadowReceive() { return FALSE; } - virtual void renderable_Render(); + virtual void renderable_Render(IDSGraphManager* DM); virtual void shedule_Update(u32 DT); virtual void UpdateCL(); diff --git a/src/xrGame/ai/monsters/ai_monster_defs.h b/src/xrGame/ai/monsters/ai_monster_defs.h index e4c9611f4c..7aa80b35c5 100644 --- a/src/xrGame/ai/monsters/ai_monster_defs.h +++ b/src/xrGame/ai/monsters/ai_monster_defs.h @@ -268,6 +268,15 @@ enum EPState PS_STAND_UPPER }; +enum EHitSide +{ + eSideFront = u32(0), + eSideBack, + eSideLeft, + eSideRight, + eSideCount +}; + typedef shared_str anim_string; #define DEFAULT_ANIM eAnimStandIdle @@ -275,6 +284,7 @@ typedef shared_str anim_string; struct SAnimItem { anim_string target_name; // "stand_idle_" + bool target_may_not_exist; int spec_id; // (-1) - any, (0 - ...) - идентификатор 3 u8 count; // количество анимаций : "idle_0", "idle_1", "idle_2" @@ -288,6 +298,7 @@ struct SAnimItem anim_string back; anim_string left; anim_string right; + std::bitset may_not_exist; } fxs; }; @@ -427,15 +438,6 @@ struct t_fx_index s8 back; }; -enum EHitSide -{ - eSideFront = u32(0), - eSideBack, - eSideLeft, - eSideRight -}; - - DEFINE_VECTOR(SAnimItem*, ANIM_ITEM_VECTOR, ANIM_ITEM_VECTOR_IT); DEFINE_VECTOR(STransition, TRANSITION_ANIM_VECTOR, TRANSITION_ANIM_VECTOR_IT); DEFINE_MAP(EAction, SMotionItem, MOTION_ITEM_MAP, MOTION_ITEM_MAP_IT); diff --git a/src/xrGame/ai/monsters/ai_monster_squad.cpp b/src/xrGame/ai/monsters/ai_monster_squad.cpp index f0ee806167..3429eff2eb 100644 --- a/src/xrGame/ai/monsters/ai_monster_squad.cpp +++ b/src/xrGame/ai/monsters/ai_monster_squad.cpp @@ -213,7 +213,7 @@ void CMonsterSquad::unlock_cover(u32 node) { NODES_VECTOR_IT it = std::find(m_locked_covers.begin(), m_locked_covers.end(), node); if (it != m_locked_covers.end()) - m_locked_covers.erase(it); + m_locked_covers.erase_fast(it); } u8 CMonsterSquad::get_index(CEntity* m_object) @@ -262,7 +262,7 @@ void CMonsterSquad::unlock_corpse(const CEntityAlive* corpse) { CORPSES_VECTOR_IT it = std::find(m_locked_corpses.begin(), m_locked_corpses.end(), corpse); if (it != m_locked_corpses.end()) - m_locked_corpses.erase(it); + m_locked_corpses.erase_fast(it); } ////////////////////////////////////////////////////////////////////////// diff --git a/src/xrGame/ai/monsters/anti_aim_ability.h b/src/xrGame/ai/monsters/anti_aim_ability.h index 08630410e5..0029f8221d 100644 --- a/src/xrGame/ai/monsters/anti_aim_ability.h +++ b/src/xrGame/ai/monsters/anti_aim_ability.h @@ -9,7 +9,7 @@ class CBaseMonster; class anti_aim_ability : public CControl_ComCustom<> { public: - typedef fastdelegate::FastDelegate hit_callback; + typedef xr_delegate hit_callback; private: typedef CControl_ComCustom<> inherited; diff --git a/src/xrGame/ai/monsters/basemonster/base_monster.cpp b/src/xrGame/ai/monsters/basemonster/base_monster.cpp index ca3a6021f8..d22678df1e 100644 --- a/src/xrGame/ai/monsters/basemonster/base_monster.cpp +++ b/src/xrGame/ai/monsters/basemonster/base_monster.cpp @@ -326,6 +326,7 @@ void CBaseMonster::update_enemy_accessible_and_at_home_info() void CBaseMonster::UpdateCL() { + PROF_EVENT("CBaseMonster::UpdateCL"); #ifdef DEBUG if ( Level().CurrentEntity() == this ) { @@ -360,6 +361,7 @@ void CBaseMonster::UpdateCL() void CBaseMonster::shedule_Update(u32 dt) { + PROF_EVENT("CBaseMonster::shedule_Update"); #ifdef DEBUG if ( is_paused () ) { @@ -833,7 +835,7 @@ void CBaseMonster::set_action(EAction action) CParticlesObject* CBaseMonster::PlayParticles(const shared_str& name, const Fvector& position, const Fvector& dir, BOOL auto_remove, BOOL xformed) { - CParticlesObject* ps = CParticlesObject::Create(name.c_str(), auto_remove); + CParticlesObject* ps = Particles::Details::Create(name.c_str(),auto_remove).get(); // вычислить позицию и направленность партикла Fmatrix matrix; diff --git a/src/xrGame/ai/monsters/basemonster/base_monster.h b/src/xrGame/ai/monsters/basemonster/base_monster.h index 334ce8ca63..08e13be9ed 100644 --- a/src/xrGame/ai/monsters/basemonster/base_monster.h +++ b/src/xrGame/ai/monsters/basemonster/base_monster.h @@ -133,7 +133,7 @@ class CBaseMonster : public CCustomMonster, public CStepManager virtual float evaluate(const CItemManager* manager, const CGameObject* object) const; virtual void OnEvent(NET_Packet& P, u16 type); - virtual void OnHUDDraw(CCustomHUD* hud) { return inherited::OnHUDDraw(hud); } + virtual void OnHUDDraw(CCustomHUD* hud, IDSGraphManager* DM) { return inherited::OnHUDDraw(hud, DM); } virtual u16 PHGetSyncItemsNumber() { return inherited::PHGetSyncItemsNumber(); } virtual CPHSynchronize* PHGetSyncItem(u16 item) { return inherited::PHGetSyncItem(item); } virtual void PHUnFreeze() { return inherited::PHUnFreeze(); } @@ -141,7 +141,7 @@ class CBaseMonster : public CCustomMonster, public CStepManager virtual BOOL UsedAI_Locations() { return inherited::UsedAI_Locations(); } virtual const SRotation Orientation() const { return inherited::Orientation(); } - virtual void renderable_Render() { return inherited::renderable_Render(); } + virtual void renderable_Render(IDSGraphManager* DM) { return inherited::renderable_Render(DM); } virtual void on_restrictions_change(); diff --git a/src/xrGame/ai/monsters/basemonster/base_monster_feel.cpp b/src/xrGame/ai/monsters/basemonster/base_monster_feel.cpp index 59264cb62e..2b3b5bba88 100644 --- a/src/xrGame/ai/monsters/basemonster/base_monster_feel.cpp +++ b/src/xrGame/ai/monsters/basemonster/base_monster_feel.cpp @@ -33,6 +33,7 @@ void CBaseMonster::feel_sound_new(CObject* who, int eType, CSound_UserDataPtr us // ignore my sounds if (this == who) return; + PROF_EVENT("CBaseMonster::feel_sound_new"); if (user_data) user_data->accept(sound_user_data_visitor()); @@ -216,7 +217,7 @@ bool CBaseMonster::feel_vision_isRelevant(CObject* O) if (!g_Alive()) return false; if (0 == smart_cast(O)) return false; - if ((O->spatial.type & STYPE_VISIBLEFORAI) != STYPE_VISIBLEFORAI) return false; + if ((O->SpatialComponent->spatial.type & STYPE_VISIBLEFORAI) != STYPE_VISIBLEFORAI) return false; // если спит, то ничего не видит if (m_bSleep) return false; diff --git a/src/xrGame/ai/monsters/bloodsucker/bloodsucker.cpp b/src/xrGame/ai/monsters/bloodsucker/bloodsucker.cpp index c8a9459037..96e785b692 100644 --- a/src/xrGame/ai/monsters/bloodsucker/bloodsucker.cpp +++ b/src/xrGame/ai/monsters/bloodsucker/bloodsucker.cpp @@ -65,6 +65,7 @@ CAI_Bloodsucker::CAI_Bloodsucker() m_runaway_invisible_time = 0; using namespace detail::bloodsucker; + m_critical_hit_chance = default_critical_hit_chance; } CAI_Bloodsucker::~CAI_Bloodsucker() @@ -119,7 +120,7 @@ void CAI_Bloodsucker::Load(LPCSTR section) anim().AddAnim(eAnimStandTurnLeft, "stand_turn_ls_", -1, &velocity_turn, PS_STAND); anim().AddAnim(eAnimStandTurnRight, "stand_turn_rs_", -1, &velocity_turn, PS_STAND); anim().AddAnim(eAnimSleep, "lie_sleep_", -1, &velocity_none, PS_LIE); - anim().AddAnim(eAnimSleepStanding, "stand_sleep_", -1, &velocity_none, PS_STAND); + anim().AddAnim(eAnimSleepStanding, { "stand_sleep_", true }, -1, &velocity_none, PS_STAND); anim().AddAnim(eAnimWalkFwd, "stand_walk_fwd_", -1, &velocity_walk, PS_STAND); anim().AddAnim(eAnimWalkDamaged, "stand_walk_fwd_dmg_", -1, &velocity_walk_dmg, PS_STAND); anim().AddAnim(eAnimRun, "stand_run_", -1, &velocity_run, PS_STAND); @@ -161,7 +162,7 @@ void CAI_Bloodsucker::Load(LPCSTR section) "fx_stand_l", "fx_stand_r"); anim().AddAnim(eAnimSleep, "lie_sleep_", -1, &velocity_none, PS_LIE, "fx_run_f", "fx_stand_b", "fx_stand_l", "fx_stand_r"); - anim().AddAnim(eAnimSleepStanding, "stand_sleep_", -1, &velocity_none, PS_STAND, "fx_run_f", "fx_stand_b", + anim().AddAnim(eAnimSleepStanding, {"stand_sleep_", true}, -1, &velocity_none, PS_STAND, "fx_run_f", "fx_stand_b", "fx_stand_l", "fx_stand_r"); anim().AddAnim(eAnimWalkFwd, "stand_walk_fwd_", -1, &velocity_walk, PS_STAND, "fx_run_f", "fx_stand_b", "fx_stand_l", "fx_stand_r"); @@ -258,9 +259,9 @@ void CAI_Bloodsucker::Load(LPCSTR section) m_vampire_want_speed = pSettings->r_float(section, "Vampire_Want_Speed"); m_vampire_wound = pSettings->r_float(section, "Vampire_Wound"); - m_vampire_gain_health = pSettings->r_float(section, "Vampire_GainHealth"); - m_vampire_distance = pSettings->r_float(section, "Vampire_Distance"); - m_sufficient_hits_before_vampire = pSettings->r_u32(section, "Vampire_Sufficient_Hits"); + m_vampire_gain_health = READ_IF_EXISTS(pSettings, r_float, section, "Vampire_GainHealth", 0.5f); + m_vampire_distance = READ_IF_EXISTS(pSettings, r_float, section, "Vampire_Distance", 1.0f); + m_sufficient_hits_before_vampire = READ_IF_EXISTS(pSettings, r_u32, section, "Vampire_Sufficient_Hits", 5); m_sufficient_hits_before_vampire_random = -1 + (rand() % 3); invisible_particle_name = pSettings->r_string(section, "Particle_Invisible"); @@ -269,6 +270,8 @@ void CAI_Bloodsucker::Load(LPCSTR section) READ_IF_EXISTS(pSettings, r_float, section, "separate_factor", 0.f); + m_critical_hit_chance = READ_IF_EXISTS(pSettings, r_float, section, "critical_hit_chance", + default_critical_hit_chance); m_visibility_state_change_min_delay = READ_IF_EXISTS(pSettings, r_u32, section, "visibility_state_change_min_delay", default_visibility_state_change_min_delay); @@ -879,7 +882,7 @@ void CAI_Bloodsucker::manual_deactivate() extern int ps_r2_heatvision; -void CAI_Bloodsucker::renderable_Render() +void CAI_Bloodsucker::renderable_Render(IDSGraphManager* DM) { //--DSR-- HeatVision_start @@ -889,7 +892,7 @@ void CAI_Bloodsucker::renderable_Render() //} if (m_visibility_state != no_visibility || ps_r2_heatvision > 0) - inherited::renderable_Render(); + inherited::renderable_Render(DM); //--DSR-- HeatVision_end } diff --git a/src/xrGame/ai/monsters/bloodsucker/bloodsucker.h b/src/xrGame/ai/monsters/bloodsucker/bloodsucker.h index 729cff54bf..7b08928b7d 100644 --- a/src/xrGame/ai/monsters/bloodsucker/bloodsucker.h +++ b/src/xrGame/ai/monsters/bloodsucker/bloodsucker.h @@ -182,7 +182,7 @@ class CAI_Bloodsucker : public CBaseMonster, virtual char* get_monster_class_name() { return "bloodsucker"; } - virtual void renderable_Render(); + virtual void renderable_Render(IDSGraphManager* DM); #ifdef DEBUG virtual CBaseMonster::SDebugInfo show_debug_info(); diff --git a/src/xrGame/ai/monsters/bloodsucker/bloodsucker_state_manager.cpp b/src/xrGame/ai/monsters/bloodsucker/bloodsucker_state_manager.cpp index d02c90d138..73f445da66 100644 --- a/src/xrGame/ai/monsters/bloodsucker/bloodsucker_state_manager.cpp +++ b/src/xrGame/ai/monsters/bloodsucker/bloodsucker_state_manager.cpp @@ -23,6 +23,7 @@ CStateManagerBloodsucker::CStateManagerBloodsucker(CAI_Bloodsucker* monster) : inherited(monster) { + add_state(eStateCustom, xr_new>(monster)); add_state(eStateRest, xr_new>(monster)); add_state(eStatePanic, xr_new>(monster)); @@ -93,57 +94,76 @@ void CStateManagerBloodsucker::execute() const CEntityAlive* enemy = object->EnemyMan.get_enemy(); - if (enemy) + if (!object->is_drag_anim_jump() && !object->is_animated()) { - if (check_vampire()) + if (enemy) { - state_id = eStateVampire_Execute; + if (check_vampire()) + { + state_id = eStateVampire_Execute; + } + else + { + switch (object->EnemyMan.get_danger_type()) + { + case eStrong: state_id = eStatePanic; + break; + case eWeak: state_id = eStateAttack; + break; + } + } + } + else if (object->HitMemory.is_hit()) + { + state_id = eStateHitted; + } + else if (object->hear_interesting_sound) + { + state_id = eStateHearInterestingSound; + } + else if (object->hear_dangerous_sound) + { + state_id = eStateHearDangerousSound; } else { - switch (object->EnemyMan.get_danger_type()) - { - case eStrong: state_id = eStatePanic; - break; - case eWeak: state_id = eStateAttack; - break; - } + if (can_eat()) state_id = eStateEat; + else state_id = eStateRest; } - } - else if (object->HitMemory.is_hit()) - { - state_id = eStateHitted; - } - else if (object->hear_interesting_sound) - { - state_id = eStateHearInterestingSound; - } - else if (object->hear_dangerous_sound) - { - state_id = eStateHearDangerousSound; + + // check if start interesting sound state + // if ( (prev_substate != eStateHearInterestingSound) && (state_id == eStateHearInterestingSound) ) + // { + // object->start_invisible_predator(); + // } + // else + // // check if stop interesting sound state + // if ( (prev_substate == eStateHearInterestingSound) && (state_id != eStateHearInterestingSound) ) + // { + // object->stop_invisible_predator(); + // } + + select_state(state_id); + + // выполнить текущее состояние + get_state_current()->execute(); + + prev_substate = current_substate; } else { - if (can_eat()) state_id = eStateEat; - else state_id = eStateRest; - } + state_id = eStateCustom; - // check if start interesting sound state - // if ( (prev_substate != eStateHearInterestingSound) && (state_id == eStateHearInterestingSound) ) - // { - // object->start_invisible_predator(); - // } - // else - // // check if stop interesting sound state - // if ( (prev_substate == eStateHearInterestingSound) && (state_id != eStateHearInterestingSound) ) - // { - // object->stop_invisible_predator(); - // } + if (object->is_drag_anim_jump()) + { + select_state(state_id); - select_state(state_id); + // выполнить текущее состояние + get_state_current()->execute(); - // выполнить текущее состояние - get_state_current()->execute(); + prev_substate = current_substate; - prev_substate = current_substate; + drag_object(); + } + } } diff --git a/src/xrGame/ai/monsters/burer/burer.cpp b/src/xrGame/ai/monsters/burer/burer.cpp index 1fcf9007af..09b93fecbb 100644 --- a/src/xrGame/ai/monsters/burer/burer.cpp +++ b/src/xrGame/ai/monsters/burer/burer.cpp @@ -367,7 +367,7 @@ void CBurer::UpdateGraviObject() // --------------------------------------------------------------------- // draw particle - CParticlesObject* ps = CParticlesObject::Create(particle_gravi_wave,TRUE); + intrusive_ptr ps = Particles::Details::Create(particle_gravi_wave,TRUE); // вычислить позицию и направленность партикла Fmatrix pos; @@ -466,7 +466,7 @@ void CBurer::Hit(SHit* pHDS) CParticlesPlayer::MakeXFORM(this, pHDS->bone(), pHDS->dir, pHDS->p_in_bone_space, pos); // установить particles - CParticlesObject* ps = CParticlesObject::Create(particle_fire_shield,TRUE); + intrusive_ptr ps = Particles::Details::Create(particle_fire_shield,TRUE); ps->UpdateParent(pos, Fvector().set(0.f, 0.f, 0.f)); GamePersistent().ps_needtoplay.push_back(ps); diff --git a/src/xrGame/ai/monsters/burer/burer_state_attack_tele.h b/src/xrGame/ai/monsters/burer/burer_state_attack_tele.h index 45251a204e..acf523d8fc 100644 --- a/src/xrGame/ai/monsters/burer/burer_state_attack_tele.h +++ b/src/xrGame/ai/monsters/burer/burer_state_attack_tele.h @@ -58,7 +58,19 @@ class CStateBurerAttackTele : public CState virtual void execute(); virtual void finalize(); virtual void critical_finalize(); - virtual void remove_links(CObject* object) { inherited::remove_links(object); } + virtual void remove_links(CObject* object) + { + inherited::remove_links(object); + + if (selected_object == smart_cast(object)) + { + selected_object = nullptr; + if (m_action == ACTION_TELE_FIRE) + { + m_action = ACTION_TELE_CONTINUE; + } + } + } virtual bool check_start_conditions(); virtual bool check_completion(); diff --git a/src/xrGame/ai/monsters/burer/burer_state_attack_tele_inline.h b/src/xrGame/ai/monsters/burer/burer_state_attack_tele_inline.h index 912f3c520c..b6ea972bae 100644 --- a/src/xrGame/ai/monsters/burer/burer_state_attack_tele_inline.h +++ b/src/xrGame/ai/monsters/burer/burer_state_attack_tele_inline.h @@ -350,6 +350,12 @@ void CStateBurerAttackTele::ExecuteTeleContinue() template void CStateBurerAttackTele::ExecuteTeleFire() { + if (!selected_object || (selected_object && selected_object->getDestroy())) + { + selected_object = nullptr; + return; + } + CEntityAlive* const enemy = const_cast(object->EnemyMan.get_enemy()); const Fvector enemy_pos = get_head_position(enemy); diff --git a/src/xrGame/ai/monsters/control_animation_base.cpp b/src/xrGame/ai/monsters/control_animation_base.cpp index 6b3fe48a7a..b53e7a0223 100644 --- a/src/xrGame/ai/monsters/control_animation_base.cpp +++ b/src/xrGame/ai/monsters/control_animation_base.cpp @@ -387,7 +387,13 @@ void CControlAnimationBase::FX_Play(EHitSide side, float amount) break; } - if (p_str && p_str->size()) smart_cast(m_object->Visual())->PlayFX(*(*p_str), amount); + if (p_str && p_str->size()) + { + if (anim_it->fxs.may_not_exist[side]) + smart_cast(m_object->Visual())->PlayFX_Safe(*(*p_str), amount); + else + smart_cast(m_object->Visual())->PlayFX(*(*p_str), amount); + } fx_time_last_play = m_object->m_dwCurrentTime; } @@ -526,6 +532,7 @@ void CControlAnimationBase::ValidateAnimation() void CControlAnimationBase::UpdateAnimCount() { IKinematicsAnimated* skel = smart_cast(m_object->Visual()); + xr_vector subjectsToDelete; for (ANIM_ITEM_VECTOR_IT it = m_anim_storage.begin(); it != m_anim_storage.end(); it++) { @@ -551,13 +558,34 @@ void CControlAnimationBase::UpdateAnimCount() else break; } - if (count != 0) (*it)->count = count; + if (count != 0) + { + (*it)->count = count; + } + else if ((*it)->target_may_not_exist) + { + subjectsToDelete.push_back(std::distance(m_anim_storage.begin(), it)); + } else { xr_sprintf(s, "Error! No animation: %s for monster %s", *((*it)->target_name), *m_object->cName()); R_ASSERT2(count != 0, s); } } + for (u32 idx : subjectsToDelete) + { + xr_delete(m_anim_storage[idx]); + while (true) + { + auto it = std::find_if(m_tReplacedAnims.begin(), m_tReplacedAnims.end(), [idx](const SReplacedAnim& ranim) + { + return ranim.cur_anim == idx || ranim.new_anim == idx; + }); + if (it == m_tReplacedAnims.end()) + break; + m_tReplacedAnims.erase_fast(it); + } + } } void CControlAnimationBase::SetCurAnim(EMotionAnim a) diff --git a/src/xrGame/ai/monsters/control_animation_base.h b/src/xrGame/ai/monsters/control_animation_base.h index 6a3338c595..3fd9dd6695 100644 --- a/src/xrGame/ai/monsters/control_animation_base.h +++ b/src/xrGame/ai/monsters/control_animation_base.h @@ -97,9 +97,23 @@ class CControlAnimationBase : public CControl_ComBase // создание карты анимаций (выполнять на Monster::Load) void AddAnim(EMotionAnim ma, LPCSTR tn, int s_id, SVelocityParam* vel, EPState p_s); + void AddAnim(EMotionAnim ma, std::pair target, int s_id, SVelocityParam* vel, EPState p_s); + void AddAnim(EMotionAnim ma, LPCSTR tn, int s_id, SVelocityParam* vel, EPState p_s, LPCSTR fx_front, LPCSTR fx_back, LPCSTR fx_left, LPCSTR fx_right); + void AddAnim(EMotionAnim ma, std::pair target, int s_id, SVelocityParam* vel, EPState p_s, + LPCSTR fx_front, LPCSTR fx_back, + LPCSTR fx_left, LPCSTR fx_right); + + void AddAnim(EMotionAnim ma, std::pair target, int s_id, SVelocityParam* vel, EPState p_s, + std::pair fx_front, std::pair fx_back, + std::pair fx_left, std::pair fx_right); + + void AddAnim(EMotionAnim ma, LPCSTR tn, int s_id, SVelocityParam* vel, EPState p_s, + std::pair fx_front, std::pair fx_back, + std::pair fx_left, std::pair fx_right); + // ------------------------------------- // добавить анимацию перехода (A - Animation, S - Position) diff --git a/src/xrGame/ai/monsters/control_animation_base_load.cpp b/src/xrGame/ai/monsters/control_animation_base_load.cpp index 4c9c9068b6..65acb1d692 100644 --- a/src/xrGame/ai/monsters/control_animation_base_load.cpp +++ b/src/xrGame/ai/monsters/control_animation_base_load.cpp @@ -1,38 +1,72 @@ #include "stdafx.h" #include "control_animation_base.h" -void CControlAnimationBase::AddAnim(EMotionAnim ma, LPCSTR tn, int s_id, SVelocityParam* vel, EPState p_s, - LPCSTR fx_front, LPCSTR fx_back, LPCSTR fx_left, LPCSTR fx_right) +void CControlAnimationBase::AddAnim(EMotionAnim ma, std::pair target, int s_id, SVelocityParam* vel, EPState p_s, + std::pair fx_front, std::pair fx_back, + std::pair fx_left, std::pair fx_right) { - SAnimItem* new_item = xr_new(); + SAnimItem* new_item = xr_new(); + + new_item->target_name = target.first; + new_item->target_may_not_exist = target.second; + new_item->spec_id = s_id; + new_item->velocity = *vel; + new_item->pos_state = p_s; - new_item->target_name = tn; - new_item->spec_id = s_id; - new_item->velocity = *vel; - new_item->pos_state = p_s; + new_item->fxs.front = fx_front.first; + new_item->fxs.back = fx_back.first; + new_item->fxs.left = fx_left.first; + new_item->fxs.right = fx_right.first; - new_item->fxs.front = fx_front; - new_item->fxs.back = fx_back; - new_item->fxs.left = fx_left; - new_item->fxs.right = fx_right; + new_item->fxs.may_not_exist[0] = fx_front.second; + new_item->fxs.may_not_exist[1] = fx_back.second; + new_item->fxs.may_not_exist[2] = fx_left.second; + new_item->fxs.may_not_exist[3] = fx_right.second; - new_item->count = 0; + new_item->count = 0; - m_anim_storage[ma] = new_item; + m_anim_storage[ma] = new_item; } -void CControlAnimationBase::AddAnim(EMotionAnim ma, LPCSTR tn, int s_id, SVelocityParam* vel, EPState p_s) +void CControlAnimationBase::AddAnim(EMotionAnim ma, LPCSTR tn, int s_id, SVelocityParam* vel, EPState p_s, + std::pair fx_front, std::pair fx_back, + std::pair fx_left, std::pair fx_right) +{ + AddAnim(ma, { tn, false }, s_id, vel, p_s, fx_front, fx_back, fx_left, fx_right); +} + +void CControlAnimationBase::AddAnim(EMotionAnim ma, LPCSTR tn, int s_id, SVelocityParam* vel, EPState p_s, + LPCSTR fx_front, LPCSTR fx_back, LPCSTR fx_left, LPCSTR fx_right) +{ + AddAnim(ma, { tn, false }, s_id, vel, p_s, { fx_front, false }, { fx_back, false }, { fx_left, false }, { fx_right, false }); + m_anim_storage[ma]->fxs.may_not_exist.reset(); +} + +void CControlAnimationBase::AddAnim(EMotionAnim ma, std::pair target, int s_id, SVelocityParam* vel, EPState p_s, + LPCSTR fx_front, LPCSTR fx_back, LPCSTR fx_left, LPCSTR fx_right) +{ + AddAnim(ma, target, s_id, vel, p_s, { fx_front, false }, { fx_back, false }, { fx_left, false }, { fx_right, false }); + m_anim_storage[ma]->fxs.may_not_exist.reset(); +} + +void CControlAnimationBase::AddAnim(EMotionAnim ma, std::pair target, int s_id, SVelocityParam* vel, EPState p_s) { - SAnimItem* new_item = xr_new(); + SAnimItem* new_item = xr_new(); - new_item->target_name = tn; - new_item->spec_id = s_id; - new_item->velocity = *vel; - new_item->pos_state = p_s; + new_item->target_name = target.first; + new_item->target_may_not_exist = target.second; + new_item->spec_id = s_id; + new_item->velocity = *vel; + new_item->pos_state = p_s; - new_item->count = 0; + new_item->count = 0; - m_anim_storage[ma] = new_item; + m_anim_storage[ma] = new_item; +} + +void CControlAnimationBase::AddAnim(EMotionAnim ma, LPCSTR tn, int s_id, SVelocityParam* vel, EPState p_s) +{ + AddAnim(ma, { tn, false }, s_id, vel, p_s); } void CControlAnimationBase::AddTransition(EMotionAnim from, EMotionAnim to, EMotionAnim trans, bool chain, diff --git a/src/xrGame/ai/monsters/controller/controller_psy_hit.cpp b/src/xrGame/ai/monsters/controller/controller_psy_hit.cpp index 9b0a62f37e..55fb5fc168 100644 --- a/src/xrGame/ai/monsters/controller/controller_psy_hit.cpp +++ b/src/xrGame/ai/monsters/controller/controller_psy_hit.cpp @@ -257,7 +257,7 @@ void CControllerPsyHit::death_glide_start() } Fmatrix m; - Fvector target_pos = k ? m.mul_43(m_object->XFORM(), k->LL_GetTransform(bone_id)).c : m_object->Position(); + Fvector target_pos = k ? m.mul_43(m_object->XFORM(), k->LL_GetTransform_safed(bone_id)).c : m_object->Position(); target_pos.y += k ? 0.f : 1.4f; Fvector dir; diff --git a/src/xrGame/ai/monsters/monster_event_manager.h b/src/xrGame/ai/monsters/monster_event_manager.h index dac077ba46..8560419bfd 100644 --- a/src/xrGame/ai/monsters/monster_event_manager.h +++ b/src/xrGame/ai/monsters/monster_event_manager.h @@ -1,7 +1,7 @@ #pragma once #include "monster_event_manager_defs.h" -typedef fastdelegate::FastDelegate1 typeEvent; +typedef xr_delegate typeEvent; class CMonsterEventManager { diff --git a/src/xrGame/ai/monsters/monster_home.cpp b/src/xrGame/ai/monsters/monster_home.cpp index bf7aee9edd..7edc3b290f 100644 --- a/src/xrGame/ai/monsters/monster_home.cpp +++ b/src/xrGame/ai/monsters/monster_home.cpp @@ -54,7 +54,7 @@ void CMonsterHome::load(LPCSTR line) if (m_object->spawn_ini() && m_object->spawn_ini()->section_exist(line)) { - m_path = ai().patrol_paths().path(m_object->spawn_ini()->r_string(line, "path")); + m_path = ai().patrol_paths().safe_path(m_object->spawn_ini()->r_string(line, "path"), false, true); check_path(m_object, m_path); if (m_object->spawn_ini()->line_exist(line, "radius_min")) m_radius_min = m_object->spawn_ini()->r_float(line, "radius_min"); @@ -96,7 +96,7 @@ void CMonsterHome::load(LPCSTR line) void CMonsterHome::setup(LPCSTR path_name, float min_radius, float max_radius, bool aggressive, float middle_radius) { - m_path = ai().patrol_paths().path(path_name); + m_path = ai().patrol_paths().safe_path(path_name, false, true); check_path(m_object, m_path); m_radius_min = min_radius; m_radius_max = max_radius; diff --git a/src/xrGame/ai/monsters/poltergeist/poltergeist.cpp b/src/xrGame/ai/monsters/poltergeist/poltergeist.cpp index b24a45ccae..314697424a 100644 --- a/src/xrGame/ai/monsters/poltergeist/poltergeist.cpp +++ b/src/xrGame/ai/monsters/poltergeist/poltergeist.cpp @@ -315,10 +315,10 @@ void CPoltergeist::Show() ability()->on_show(); } -void CPoltergeist::renderable_Render() +void CPoltergeist::renderable_Render(IDSGraphManager* DM) { Visual()->getVisData().hom_frame = Device.dwFrame; - inherited::renderable_Render(); + inherited::renderable_Render(DM); } void CPoltergeist::UpdateCL() diff --git a/src/xrGame/ai/monsters/poltergeist/poltergeist.h b/src/xrGame/ai/monsters/poltergeist/poltergeist.h index 732b628648..e52abf2d36 100644 --- a/src/xrGame/ai/monsters/poltergeist/poltergeist.h +++ b/src/xrGame/ai/monsters/poltergeist/poltergeist.h @@ -83,7 +83,7 @@ class CPoltergeist : public CBaseMonster, float get_fly_around_distance() const { return m_fly_around_distance; } float get_fly_around_change_direction_time() const { return m_fly_around_change_direction_time; } - virtual void renderable_Render(); + virtual void renderable_Render(IDSGraphManager* DM); IC CPolterSpecialAbility* ability() { return (m_flame ? m_flame : m_tele); } diff --git a/src/xrGame/ai/monsters/poltergeist/poltergeist_ability.cpp b/src/xrGame/ai/monsters/poltergeist/poltergeist_ability.cpp index 123e774c2d..1dc9e80a36 100644 --- a/src/xrGame/ai/monsters/poltergeist/poltergeist_ability.cpp +++ b/src/xrGame/ai/monsters/poltergeist/poltergeist_ability.cpp @@ -18,8 +18,8 @@ CPolterSpecialAbility::CPolterSpecialAbility(CPoltergeist* polter) CPolterSpecialAbility::~CPolterSpecialAbility() { - CParticlesObject::Destroy(m_particles_object); - CParticlesObject::Destroy(m_particles_object_electro); + Particles::Details::Destroy(m_particles_object); + Particles::Details::Destroy(m_particles_object_electro); } void CPolterSpecialAbility::load(LPCSTR section) @@ -57,8 +57,8 @@ void CPolterSpecialAbility::on_hide() void CPolterSpecialAbility::on_show() { - if (m_particles_object) CParticlesObject::Destroy(m_particles_object); - if (m_particles_object_electro) CParticlesObject::Destroy(m_particles_object_electro); + if (m_particles_object) Particles::Details::Destroy(m_particles_object); + if (m_particles_object_electro) Particles::Details::Destroy(m_particles_object_electro); } void CPolterSpecialAbility::update_frame() @@ -74,8 +74,8 @@ void CPolterSpecialAbility::on_die() m_object->PlayParticles(m_particles_death, particles_position, Fvector().set(0.0f, 1.0f, 0.0f), TRUE, FALSE); - CParticlesObject::Destroy(m_particles_object_electro); - CParticlesObject::Destroy(m_particles_object); + Particles::Details::Destroy(m_particles_object_electro); + Particles::Details::Destroy(m_particles_object); } void CPolterSpecialAbility::on_hit(SHit* pHDS) diff --git a/src/xrGame/ai/monsters/poltergeist/poltergeist_flame_thrower.cpp b/src/xrGame/ai/monsters/poltergeist/poltergeist_flame_thrower.cpp index 2afb3e2ec0..23886d3c03 100644 --- a/src/xrGame/ai/monsters/poltergeist/poltergeist_flame_thrower.cpp +++ b/src/xrGame/ai/monsters/poltergeist/poltergeist_flame_thrower.cpp @@ -125,7 +125,7 @@ void CPolterFlame::select_state(SFlameElement* elem, EFlameState state) break; case eStop: // stop fire particles - if (elem->particles_object) CParticlesObject::Destroy(elem->particles_object); + if (elem->particles_object) Particles::Details::Destroy(elem->particles_object); // start finish particles m_object->PlayParticles(m_particles_stop, elem->position, elem->target_dir,TRUE); @@ -251,7 +251,7 @@ void CPolterFlame::on_destroy() for (; I != E; ++I) { if ((*I)->sound._feedback()) (*I)->sound.stop(); - if ((*I)->particles_object) CParticlesObject::Destroy((*I)->particles_object); + if ((*I)->particles_object) Particles::Details::Destroy((*I)->particles_object); xr_delete((*I)); } diff --git a/src/xrGame/ai/monsters/pseudodog/psy_dog.cpp b/src/xrGame/ai/monsters/pseudodog/psy_dog.cpp index fb0c91912d..a17b79dfc5 100644 --- a/src/xrGame/ai/monsters/pseudodog/psy_dog.cpp +++ b/src/xrGame/ai/monsters/pseudodog/psy_dog.cpp @@ -34,17 +34,24 @@ CPsyDog::~CPsyDog() void CPsyDog::Load(LPCSTR section) { inherited::Load(section); - + m_aura->load(pSettings->r_string(section, "aura_effector")); - m_max_phantoms_count = pSettings->r_u8(section, "Phantoms_Count"); + m_min_phantoms_count = READ_IF_EXISTS(pSettings, r_u8, section, "Min_Phantoms_Count", 1); + if (pSettings->line_exist(section, "Phantoms_Count")) + m_max_phantoms_count = pSettings->r_u8(section, "Phantoms_Count"); + else + m_max_phantoms_count = pSettings->r_u8(section, "Max_Phantoms_Count"); + xr_free(m_phantoms_die_time); m_phantoms_die_time = xr_alloc(m_max_phantoms_count); for (int i = 0; i < m_max_phantoms_count; ++i) m_phantoms_die_time[i] = s_phantom_immediate_respawn_flag; - - m_time_phantom_respawn = pSettings->r_u32(section, "Time_Phantom_Respawn"); + if (pSettings->line_exist(section, "Time_Phantom_Respawn")) + m_time_phantom_respawn = pSettings->r_u32(section, "Time_Phantom_Respawn"); + else + m_time_phantom_respawn = pSettings->r_u32(section, "Time_Phantom_Appear"); } BOOL CPsyDog::net_Spawn(CSE_Abstract* dc) @@ -89,7 +96,7 @@ void CPsyDog::unregister_phantom(CPsyDogPhantom* phantom) } VERIFY(it != m_storage.end()); - m_storage.erase(it); + m_storage.erase_fast(it); } ////////////////////////////////////////////////////////////////////////// diff --git a/src/xrGame/ai/monsters/pseudodog/psy_dog.h b/src/xrGame/ai/monsters/pseudodog/psy_dog.h index f6894fb75f..2a2a592306 100644 --- a/src/xrGame/ai/monsters/pseudodog/psy_dog.h +++ b/src/xrGame/ai/monsters/pseudodog/psy_dog.h @@ -18,6 +18,7 @@ class CPsyDog : public CAI_PseudoDog CActor* m_enemy; // externals + u8 m_min_phantoms_count; u8 m_max_phantoms_count; u32 m_time_phantom_respawn; @@ -44,7 +45,7 @@ class CPsyDog : public CAI_PseudoDog virtual char* get_monster_class_name() { return "psydog"; } u8 get_phantoms_count(); - bool must_hide() { return get_phantoms_count() == 0; } + bool must_hide() { return get_phantoms_count() < m_min_phantoms_count; } private: bool spawn_phantom(); void delete_phantom(CPsyDogPhantom*); diff --git a/src/xrGame/ai/monsters/rats/ai_rat.h b/src/xrGame/ai/monsters/rats/ai_rat.h index 8f35c7b252..f68786e962 100644 --- a/src/xrGame/ai/monsters/rats/ai_rat.h +++ b/src/xrGame/ai/monsters/rats/ai_rat.h @@ -397,7 +397,7 @@ class CAI_Rat : public CCustomMonster, public CEatableItem ///////////////////////////////////// //rat as eatable item - virtual void OnHUDDraw(CCustomHUD* hud) { inherited::OnHUDDraw(hud); } + virtual void OnHUDDraw(CCustomHUD* hud, IDSGraphManager* DM) { inherited::OnHUDDraw(hud, DM); } virtual void OnH_B_Chield(); virtual void OnH_B_Independent(); virtual void OnH_A_Independent(); diff --git a/src/xrGame/ai/monsters/snork/snork.cpp b/src/xrGame/ai/monsters/snork/snork.cpp index a2530f06c0..afcab2b9ad 100644 --- a/src/xrGame/ai/monsters/snork/snork.cpp +++ b/src/xrGame/ai/monsters/snork/snork.cpp @@ -19,6 +19,12 @@ # include "../monster_cover_manager.h" #endif +#define STAND_FX_FRONT { "stand_fx_f", true } +#define STAND_FX_BACK { "stand_fx_b", true } +#define STAND_FX_LEFT { "stand_fx_l", true } +#define STAND_FX_RIGHT { "stand_fx_r", true } + +#define STAND_FX_ALL STAND_FX_FRONT, STAND_FX_BACK, STAND_FX_LEFT, STAND_FX_RIGHT CSnork::CSnork() { @@ -53,39 +59,23 @@ void CSnork::Load(LPCSTR section) SVelocityParam& velocity_steal = move().get_velocity(MonsterMovement::eVelocityParameterSteal); //SVelocityParam &velocity_drag = move().get_velocity(MonsterMovement::eVelocityParameterDrag); - anim().AddAnim(eAnimStandIdle, "stand_idle_", -1, &velocity_none, PS_STAND, "stand_fx_f", "stand_fx_b", - "stand_fx_l", "stand_fx_r"); - anim().AddAnim(eAnimStandDamaged, "stand_idle_damaged_", -1, &velocity_none, PS_STAND, "stand_fx_f", "stand_fx_b", - "stand_fx_l", "stand_fx_r"); - anim().AddAnim(eAnimWalkDamaged, "stand_walk_damaged_", -1, &velocity_walk_dmg, PS_STAND, "stand_fx_f", - "stand_fx_b", "stand_fx_l", "stand_fx_r"); - anim().AddAnim(eAnimRunDamaged, "stand_run_damaged_", -1, &velocity_run_dmg, PS_STAND, "stand_fx_f", "stand_fx_b", - "stand_fx_l", "stand_fx_r"); - anim().AddAnim(eAnimStandTurnLeft, "stand_turn_ls_", -1, &velocity_turn, PS_STAND, "stand_fx_f", "stand_fx_b", - "stand_fx_l", "stand_fx_r"); - anim().AddAnim(eAnimStandTurnRight, "stand_turn_rs_", -1, &velocity_turn, PS_STAND, "stand_fx_f", "stand_fx_b", - "stand_fx_l", "stand_fx_r"); - anim().AddAnim(eAnimWalkFwd, "stand_walk_fwd_", -1, &velocity_walk, PS_STAND, "stand_fx_f", "stand_fx_b", - "stand_fx_l", "stand_fx_r"); - anim().AddAnim(eAnimRun, "stand_run_", -1, &velocity_run, PS_STAND, "stand_fx_f", "stand_fx_b", "stand_fx_l", - "stand_fx_r"); - anim().AddAnim(eAnimAttack, "stand_attack_", -1, &velocity_turn, PS_STAND, "stand_fx_f", "stand_fx_b", "stand_fx_l", - "stand_fx_r"); - anim().AddAnim(eAnimDie, "stand_die_", 0, &velocity_none, PS_STAND, "stand_fx_f", "stand_fx_b", "stand_fx_l", - "stand_fx_r"); - anim().AddAnim(eAnimLookAround, "stand_look_around_", -1, &velocity_none, PS_STAND, "stand_fx_f", "stand_fx_b", - "stand_fx_l", "stand_fx_r"); - anim().AddAnim(eAnimSteal, "stand_steal_", -1, &velocity_steal, PS_STAND, "stand_fx_f", "stand_fx_b", "stand_fx_l", - "stand_fx_r"); - anim().AddAnim(eAnimEat, "stand_eat_", -1, &velocity_none, PS_STAND, "stand_fx_f", "stand_fx_b", "stand_fx_l", - "stand_fx_r"); - anim().AddAnim(eAnimCheckCorpse, "stand_check_corpse_", -1, &velocity_none, PS_STAND, "stand_fx_f", "stand_fx_b", - "stand_fx_l", "stand_fx_r"); - - anim().AddAnim(eAnimRunTurnLeft, "stand_run_look_left_", -1, &velocity_run, PS_STAND, "stand_fx_f", "stand_fx_b", - "stand_fx_l", "stand_fx_r"); - anim().AddAnim(eAnimRunTurnRight, "stand_run_look_right_", -1, &velocity_run, PS_STAND, "stand_fx_f", "stand_fx_b", - "stand_fx_l", "stand_fx_r"); + anim().AddAnim(eAnimStandIdle, "stand_idle_", -1, &velocity_none, PS_STAND, STAND_FX_ALL); + anim().AddAnim(eAnimStandDamaged, "stand_idle_damaged_", -1, &velocity_none, PS_STAND, STAND_FX_ALL); + anim().AddAnim(eAnimWalkDamaged, "stand_walk_damaged_", -1, &velocity_walk_dmg, PS_STAND, STAND_FX_ALL); + anim().AddAnim(eAnimRunDamaged, "stand_run_damaged_", -1, &velocity_run_dmg, PS_STAND, STAND_FX_ALL); + anim().AddAnim(eAnimStandTurnLeft, "stand_turn_ls_", -1, &velocity_turn, PS_STAND, STAND_FX_ALL); + anim().AddAnim(eAnimStandTurnRight, "stand_turn_rs_", -1, &velocity_turn, PS_STAND, STAND_FX_ALL); + anim().AddAnim(eAnimWalkFwd, "stand_walk_fwd_", -1, &velocity_walk, PS_STAND, STAND_FX_ALL); + anim().AddAnim(eAnimRun, "stand_run_", -1, &velocity_run, PS_STAND, STAND_FX_ALL); + anim().AddAnim(eAnimAttack, "stand_attack_", -1, &velocity_turn, PS_STAND, STAND_FX_ALL); + anim().AddAnim(eAnimDie, "stand_die_", 0, &velocity_none, PS_STAND, STAND_FX_ALL); + anim().AddAnim(eAnimLookAround, "stand_look_around_", -1, &velocity_none, PS_STAND, STAND_FX_ALL); + anim().AddAnim(eAnimSteal, "stand_steal_", -1, &velocity_steal, PS_STAND, STAND_FX_ALL); + anim().AddAnim(eAnimEat, "stand_eat_", -1, &velocity_none, PS_STAND, STAND_FX_ALL); + anim().AddAnim(eAnimCheckCorpse, "stand_check_corpse_", -1, &velocity_none, PS_STAND, STAND_FX_ALL); + + anim().AddAnim(eAnimRunTurnLeft, { "stand_run_look_left_", true }, -1, &velocity_run, PS_STAND, STAND_FX_ALL); + anim().AddAnim(eAnimRunTurnRight, { "stand_run_look_right_", true }, -1, &velocity_run, PS_STAND, STAND_FX_ALL); anim().LinkAction(ACT_STAND_IDLE, eAnimStandIdle); anim().LinkAction(ACT_SIT_IDLE, eAnimStandIdle); diff --git a/src/xrGame/ai/monsters/telekinesis.cpp b/src/xrGame/ai/monsters/telekinesis.cpp index 8711b4b513..c891402d73 100644 --- a/src/xrGame/ai/monsters/telekinesis.cpp +++ b/src/xrGame/ai/monsters/telekinesis.cpp @@ -126,7 +126,7 @@ void CTelekinesis::remove_object(TELE_OBJECTS_IT it) xr_delete(*it); // удалить - objects.erase(it); + objects.erase_fast(it); // проверить на полную деактивацию if (objects.empty()) diff --git a/src/xrGame/ai/phantom/phantom.cpp b/src/xrGame/ai/phantom/phantom.cpp index 1773fe2dd3..093ce336a3 100644 --- a/src/xrGame/ai/phantom/phantom.cpp +++ b/src/xrGame/ai/phantom/phantom.cpp @@ -27,12 +27,8 @@ void CPhantom::Load(LPCSTR section) { inherited::Load(section); ////////////////////////////////////////////////////////////////////////// - ISpatial* self = smart_cast(this); - if (self) - { - self->spatial.type &= ~STYPE_VISIBLEFORAI; - self->spatial.type &= ~STYPE_REACTTOSOUND; - } + SpatialComponent->spatial.type &= ~STYPE_VISIBLEFORAI; + SpatialComponent->spatial.type &= ~STYPE_REACTTOSOUND; ////////////////////////////////////////////////////////////////////////// fSpeed = pSettings->r_float(section, "speed"); fASpeed = pSettings->r_float(section, "angular_speed"); @@ -123,7 +119,7 @@ void CPhantom::net_Destroy() // stop looped SStateData& sdata = m_state_data[stFly]; sdata.sound.stop(); - CParticlesObject::Destroy(m_fly_particles); + Particles::Details::Destroy(m_fly_particles); } //--------------------------------------------------------------------- @@ -222,7 +218,7 @@ void CPhantom::SwitchToState_internal(EState new_state) UpdateEvent.bind(this, &CPhantom::OnIdleState); SStateData& sdata = m_state_data[m_CurState]; sdata.sound.stop(); - CParticlesObject::Destroy(m_fly_particles); + Particles::Details::Destroy(m_fly_particles); } break; } @@ -283,7 +279,7 @@ void CPhantom::UpdateFlyMedia() void CPhantom::shedule_Update(u32 DT) { - spatial.type &= ~STYPE_VISIBLEFORAI; + SpatialComponent->spatial.type &= ~STYPE_VISIBLEFORAI; inherited::shedule_Update(DT); @@ -323,7 +319,7 @@ Fmatrix CPhantom::XFORM_center() CParticlesObject* CPhantom::PlayParticles(const shared_str& name, BOOL bAutoRemove, const Fmatrix& xform) { - CParticlesObject* ps = CParticlesObject::Create(name.c_str(), bAutoRemove); + CParticlesObject* ps = Particles::Details::Create(name.c_str(), bAutoRemove).get(); ps->UpdateParent(xform, zero_vel); ps->Play(false); return bAutoRemove ? 0 : ps; diff --git a/src/xrGame/ai/phantom/phantom.h b/src/xrGame/ai/phantom/phantom.h index 34dd5c0c90..6f7fb7fcbd 100644 --- a/src/xrGame/ai/phantom/phantom.h +++ b/src/xrGame/ai/phantom/phantom.h @@ -31,7 +31,7 @@ class CPhantom : public CEntity void UpdateFlyMedia(); - fastdelegate::FastDelegate0<> UpdateEvent; + xr_delegate UpdateEvent; private: struct SStateData { @@ -93,6 +93,7 @@ class CPhantom : public CEntity virtual BOOL UsedAI_Locations() { return false; } virtual CEntity* cast_entity() { return this; } + virtual CPhantom* cast_phantom() { return this; } void SetEnemy(CObject* enemy) { m_enemy = enemy; } //Alundaio }; diff --git a/src/xrGame/ai/stalker/ai_stalker.cpp b/src/xrGame/ai/stalker/ai_stalker.cpp index b87e227d8a..64ab459b59 100644 --- a/src/xrGame/ai/stalker/ai_stalker.cpp +++ b/src/xrGame/ai/stalker/ai_stalker.cpp @@ -832,20 +832,6 @@ void CAI_Stalker::net_Destroy() CInventoryOwner::net_Destroy(); m_pPhysics_support->in_NetDestroy(); - Device.remove_from_seq_parallel( - fastdelegate::FastDelegate0<>( - this, - &CAI_Stalker::update_object_handler - ) - ); - -#ifdef DEBUG - fastdelegate::FastDelegate0<> f = fastdelegate::FastDelegate0<>(this,&CAI_Stalker::update_object_handler); - xr_vector >::const_iterator I; - I = std::find(Device.seqParallel.begin(),Device.seqParallel.end(),f); - VERIFY (I == Device.seqParallel.end()); -#endif // DEBUG - xr_delete(m_ce_close); xr_delete(m_ce_far); xr_delete(m_ce_best); @@ -964,6 +950,7 @@ void CAI_Stalker::net_Import(NET_Packet& P) void CAI_Stalker::update_object_handler() { + PROF_EVENT("AI: [Stalker] Update Handler"); if (!g_Alive()) return; @@ -1022,29 +1009,16 @@ void CAI_Stalker::destroy_anim_mov_ctrl() void CAI_Stalker::UpdateCL() { + PROF_EVENT("CAI_Stalker::UpdateCL"); START_PROFILE("stalker") START_PROFILE("stalker/client_update") VERIFY2(PPhysicsShell()||getEnabled(), *cName()); if (g_Alive()) { - if (g_mt_config.test(mtObjectHandler) && CObjectHandler::planner().initialized()) + if (CObjectHandler::planner().initialized()) { - fastdelegate::FastDelegate0<> f = fastdelegate::FastDelegate0<>( - this, &CAI_Stalker::update_object_handler); -#ifdef DEBUG - xr_vector >::const_iterator I; - I = std::find(Device.seqParallel.begin(),Device.seqParallel.end(),f); - VERIFY (I == Device.seqParallel.end()); -#endif - Device.seqParallel.push_back( - fastdelegate::FastDelegate0<>(this, &CAI_Stalker::update_object_handler)); - } - else - { - START_PROFILE("stalker/client_update/object_handler") - update_object_handler(); - STOP_PROFILE + update_object_handler(); } if ( @@ -1127,6 +1101,7 @@ BOOL NPCsLookAtActor = TRUE; float NPCsLookAtActorMinDistance = 3.5f; void CAI_Stalker::shedule_Update(u32 DT) { + PROF_EVENT("CAI_Stalker::shedule_Update"); // Optimization update // if (Device.dwFrame % 2) return; @@ -1153,6 +1128,8 @@ void CAI_Stalker::shedule_Update(u32 DT) // *** general stuff float dt = float(DT) / 1000.f; + CScriptEntity::process_sound_callbacks(); + if (g_Alive()) { animation().play_delayed_callbacks(); @@ -1173,14 +1150,9 @@ void CAI_Stalker::shedule_Update(u32 DT) #if 0//def DEBUG memory().visual().check_visibles(); #endif - if (false && g_mt_config.test(mtAiVision)) - Device.seqParallel.push_back(fastdelegate::FastDelegate0<>(this, &CCustomMonster::Exec_Visibility)); - else - { - START_PROFILE("stalker/schedule_update/vision") - Exec_Visibility(); - STOP_PROFILE - } + START_PROFILE("stalker/schedule_update/vision") + Exec_Visibility(); + STOP_PROFILE START_PROFILE("stalker/schedule_update/memory") START_PROFILE("stalker/schedule_update/memory/process") @@ -1294,32 +1266,22 @@ void CAI_Stalker::Think() u32 update_delta = Device.dwTimeGlobal - m_dwLastUpdateTime; START_PROFILE("stalker/schedule_update/think/brain") - // try { - // try { - brain().update(update_delta); - // } -#ifdef DEBUG - // catch (::luabind::cast_failed &message) { - // Msg ("! Expression \"%s\" from ::luabind::object to %s",message.what(),message.info()->name()); - //throw; - // } -#endif - // catch (std::exception &message) { - // Msg ("! Expression \"%s\"",message.what()); - // throw; - // } - // catch (...) { - // Msg ("! unknown exception occured"); - // throw; - // } - // } - // catch(...) { -#ifdef DEBUG - // Msg ("! Last action being executed : %s",brain().current_action().m_action_name); -#endif - // brain().setup (this); - // brain().update (update_delta); - // } + try + { + brain().update(update_delta); + } + /*catch (::luabind::cast_failed &message) + { + Msg ("! Expression \"%s\" from ::luabind::object to %s", message.what(), message.info()->name()); + } + catch (std::exception &message) + { + Msg ("! Expression \"%s\"",message.what()); + }*/ + catch (...) + { + //Msg ("! unknown exception occured"); + } STOP_PROFILE START_PROFILE("stalker/schedule_update/think/movement") @@ -1377,8 +1339,14 @@ void CAI_Stalker::net_Relcase(CObject* O) sight().remove_links(O); movement().remove_links(O); + if (O == m_throw_ignore_object) + m_throw_ignore_object = nullptr; + + if (m_best_item_to_kill && m_best_item_to_kill->object_id() == O->ID()) + m_best_item_to_kill = nullptr; + if (!g_Alive()) - return; + return; agent_manager().remove_links(O); m_pPhysics_support->in_NetRelcase(O); @@ -1535,25 +1503,17 @@ shared_str const& CAI_Stalker::aim_bone_id() const return (m_aim_bone_id); } -void aim_target(shared_str const& aim_bone_id, Fvector& result, const CGameObject* object) -{ - IKinematics* kinematics = smart_cast(object->Visual()); - VERIFY(kinematics); - - u16 bone_id = kinematics->LL_BoneID(aim_bone_id); - VERIFY2(bone_id != BI_NONE, make_string("Cannot find bone %s",bone_id)); - - Fmatrix const& bone_matrix = kinematics->LL_GetTransform(bone_id); - Fmatrix final; - final.mul_43(object->XFORM(), bone_matrix); - result = final.c; -} - void CAI_Stalker::aim_target(Fvector& result, const CGameObject* object) { VERIFY(m_aim_bone_id.size()); - ::aim_target(m_aim_bone_id, result, object); + IKinematics* kinematics = PKinematics(object->Visual()); + VERIFY(kinematics); + + u16 bone_id = kinematics->LL_BoneID(*m_aim_bone_id); + VERIFY2(bone_id != BI_NONE, make_string("Cannot find bone %s", bone_id)); + + kinematics->LL_GetBoneWorldPosition(bone_id, object->XFORM(), result); } BOOL CAI_Stalker::AlwaysTheCrow() diff --git a/src/xrGame/ai/stalker/ai_stalker.h b/src/xrGame/ai/stalker/ai_stalker.h index ef24bbbb53..e8fbc7c005 100644 --- a/src/xrGame/ai/stalker/ai_stalker.h +++ b/src/xrGame/ai/stalker/ai_stalker.h @@ -185,6 +185,8 @@ class CAI_Stalker : virtual CAI_Stalker* cast_stalker() { return this; } virtual CCustomMonster* cast_custom_monster() { return this; } virtual CScriptEntity* cast_script_entity() { return this; } + virtual CPhraseDialogManager* cast_phrase_dialog_manager() { return this; } + virtual CAI_PhraseDialogManager* cast_ai_phrase_dialog_manager() { return this; } public: void init(); @@ -223,7 +225,7 @@ class CAI_Stalker : virtual void feel_touch_new(CObject* O); virtual void feel_touch_delete(CObject* O); void on_ownership_reject(CObject* O, bool just_before_destroy); - virtual void renderable_Render(); + virtual void renderable_Render(IDSGraphManager* DM); virtual void Exec_Look(float dt); virtual void Hit(SHit* pHDS); virtual void PHHit(SHit& H); @@ -237,7 +239,7 @@ class CAI_Stalker : bool LookAtActorLuaResult = true; #ifdef DEBUG - virtual void OnHUDDraw (CCustomHUD* hud); + virtual void OnHUDDraw (CCustomHUD* hud, IDSGraphManager* DM); virtual void OnRender (); void debug_text (); bool m_dbg_hud_draw ; @@ -652,8 +654,8 @@ class CAI_Stalker : IC float auto_queue_fire_dist_med() const; IC float auto_queue_fire_dist_far() const; public: - typedef fastdelegate::FastDelegate on_best_cover_changed_delegate; - typedef fastdelegate::FastDelegate HitCallback; + typedef xr_delegate on_best_cover_changed_delegate; + typedef xr_delegate HitCallback; private: typedef xr_vector cover_delegates; @@ -867,7 +869,7 @@ class CAI_Stalker : bool use_smart_covers_only() const; public: - typedef fastdelegate::FastDelegate EyeMatrixCallback; + typedef xr_delegate EyeMatrixCallback; private: virtual BOOL AlwaysTheCrow(); diff --git a/src/xrGame/ai/stalker/ai_stalker_cover.cpp b/src/xrGame/ai/stalker/ai_stalker_cover.cpp index 511539a723..74b81237fb 100644 --- a/src/xrGame/ai/stalker/ai_stalker_cover.cpp +++ b/src/xrGame/ai/stalker/ai_stalker_cover.cpp @@ -51,7 +51,7 @@ void CAI_Stalker::unsubscribe_on_best_cover_changed(const on_best_cover_changed_ { cover_delegates::iterator I = std::find(m_cover_delegates.begin(), m_cover_delegates.end(), delegate); VERIFY(I != m_cover_delegates.end()); - m_cover_delegates.erase(I); + m_cover_delegates.erase_fast(I); } void CAI_Stalker::on_best_cover_changed(const CCoverPoint* new_cover, const CCoverPoint* old_cover) @@ -160,21 +160,8 @@ const CCoverPoint* CAI_Stalker::find_best_cover(const Fvector& position_to_cover float minimum_enemy_distance, maximum_enemy_distance; compute_enemy_distances(minimum_enemy_distance, maximum_enemy_distance); - if (!best_weapon()) - m_ce_best->can_use_smart_covers(false); - else - { - CWeapon* weapon = smart_cast(best_weapon()); - if (!weapon) - m_ce_best->can_use_smart_covers(false); - else - { - if (weapon->BaseSlot() != INV_SLOT_3) - m_ce_best->can_use_smart_covers(false); - else - m_ce_best->can_use_smart_covers(true); - } - } + CInventoryItem* best_wpn = best_weapon(); + m_ce_best->can_use_smart_covers(best_wpn && best_wpn->cast_weapon() && best_wpn->BaseSlot() == INV_SLOT_3); m_ce_best->setup(position_to_cover_from, minimum_enemy_distance, maximum_enemy_distance, minimum_enemy_distance); const CCoverPoint* point = ai().cover_manager().best_cover(Position(), g_ai_cover_search_near_radius, *m_ce_best, diff --git a/src/xrGame/ai/stalker/ai_stalker_debug.cpp b/src/xrGame/ai/stalker/ai_stalker_debug.cpp index 6092fcd02a..087c06dca2 100644 --- a/src/xrGame/ai/stalker/ai_stalker_debug.cpp +++ b/src/xrGame/ai/stalker/ai_stalker_debug.cpp @@ -68,7 +68,7 @@ void try_change_current_entity() CFrustum frustum; frustum.CreateFromMatrix (Device.mFullTransform,FRUSTUM_P_LRTB|FRUSTUM_P_FAR); - typedef xr_vector OBJECTS; + typedef xr_vector OBJECTS; OBJECTS ISpatialResult; g_SpatialSpace->q_frustum (ISpatialResult, 0, STYPE_COLLIDEABLE, frustum); @@ -78,7 +78,7 @@ void try_change_current_entity() OBJECTS::const_iterator I = ISpatialResult.begin(); OBJECTS::const_iterator E = ISpatialResult.end(); for ( ; I != E; ++I) { - CCustomMonster *current = smart_cast(*I); + CCustomMonster *current = smart_cast((*I)->dcast_CObject()); if (!current) continue; if (Level().CurrentEntity()==current) continue; @@ -929,9 +929,9 @@ void CAI_Stalker::debug_text () } -void CAI_Stalker::OnHUDDraw (CCustomHUD *hud) +void CAI_Stalker::OnHUDDraw (CCustomHUD *hud, IDSGraphManager* DM) { - inherited::OnHUDDraw (hud); + inherited::OnHUDDraw (hud, DM); m_dbg_hud_draw = true; } diff --git a/src/xrGame/ai/stalker/ai_stalker_events.cpp b/src/xrGame/ai/stalker/ai_stalker_events.cpp index 3fef0767d9..fb4abf8d0b 100644 --- a/src/xrGame/ai/stalker/ai_stalker_events.cpp +++ b/src/xrGame/ai/stalker/ai_stalker_events.cpp @@ -97,11 +97,11 @@ void CAI_Stalker::OnEvent(NET_Packet& P, u16 type) void CAI_Stalker::on_ownership_reject(CObject* O, bool just_before_destroy) { m_pPhysics_support->in_UpdateCL(); - IKinematics* const kinematics = smart_cast(Visual()); - kinematics->CalculateBones_Invalidate(); - kinematics->CalculateBones(true); + //IKinematics* kinematics = PKinematics(Visual()); + //kinematics->CalculateBones_Invalidate(); + //kinematics->CalculateBones(true); - CGameObject* const game_object = smart_cast(O); + CGameObject* game_object = O->cast_game_object(); VERIFY(game_object); if (!inventory().DropItem(game_object, just_before_destroy, just_before_destroy)) @@ -147,7 +147,7 @@ void CAI_Stalker::feel_touch_new(CObject* O) // Msg ("FEEL_TOUCH::NEW : %s",*O->cName()); if (!g_Alive()) return; if (Remote()) return; - if ((O->spatial.type | STYPE_VISIBLEFORAI) != O->spatial.type) return; + if ((O->SpatialComponent->spatial.type | STYPE_VISIBLEFORAI) != O->SpatialComponent->spatial.type) return; // demonized: add g_ai_die_in_anomaly == 0 check if (!(g_ai_die_in_anomaly || m_enable_anomalies_pathfinding)) { diff --git a/src/xrGame/ai/stalker/ai_stalker_feel.cpp b/src/xrGame/ai/stalker/ai_stalker_feel.cpp index cd81af1894..f60f346e5a 100644 --- a/src/xrGame/ai/stalker/ai_stalker_feel.cpp +++ b/src/xrGame/ai/stalker/ai_stalker_feel.cpp @@ -32,12 +32,12 @@ bool CAI_Stalker::feel_vision_isRelevant(CObject* O) return (true); } -void CAI_Stalker::renderable_Render() +void CAI_Stalker::renderable_Render(IDSGraphManager* DM) { - inherited::renderable_Render(); + inherited::renderable_Render(DM); if (!already_dead()) - CInventoryOwner::renderable_Render(); + CInventoryOwner::renderable_Render(DM); #ifdef DEBUG if (g_Alive()) { @@ -77,7 +77,7 @@ bool CAI_Stalker::feel_touch_contact(CObject* O) // when 0 - disable pathfinding around anomaly if (!(g_ai_die_in_anomaly || m_enable_anomalies_pathfinding)) { CCustomZone* sr = smart_cast(O); - if (sr && (sr->spatial.type & STYPE_VISIBLEFORAI)) { + if (sr && (sr->SpatialComponent->spatial.type & STYPE_VISIBLEFORAI)) { return false; } } @@ -89,7 +89,7 @@ bool CAI_Stalker::feel_touch_on_contact(CObject* O) { VERIFY(O != this); - if ((O->spatial.type | STYPE_VISIBLEFORAI) != O->spatial.type) + if ((O->SpatialComponent->spatial.type | STYPE_VISIBLEFORAI) != O->SpatialComponent->spatial.type) return (false); // demonized: add g_ai_die_in_anomaly == 0 and m_enable_anomalies_damage check @@ -111,5 +111,5 @@ void CAI_Stalker::feel_touch_delete(CObject* O) if (i == m_ignored_touched_objects.end()) return; - m_ignored_touched_objects.erase(i); + m_ignored_touched_objects.erase_fast(i); } diff --git a/src/xrGame/ai/stalker/ai_stalker_fire.cpp b/src/xrGame/ai/stalker/ai_stalker_fire.cpp index 0bd316aad4..80ecda2995 100644 --- a/src/xrGame/ai/stalker/ai_stalker_fire.cpp +++ b/src/xrGame/ai/stalker/ai_stalker_fire.cpp @@ -279,7 +279,7 @@ void CAI_Stalker::Hit(SHit* pHDS) float hit_power = HDS.power * m_fRankImmunity; - if (strstr(Core.Params, "-dbgbullet")) + if (Core.ParamsData.test(ECoreParams::dbgbullet)) Msg("CAI_Stalker::Hit hit_type=%d | hit_power(%f)*m_fRankImmunity(%f) = %f", (u32)HDS.hit_type, HDS.power, m_fRankImmunity, hit_power); @@ -297,7 +297,7 @@ void CAI_Stalker::Hit(SHit* pHDS) hit_power *= d_hit_power; VERIFY(hit_power>=0.0f); - if (strstr(Core.Params, "-dbgbullet")) + if (Core.ParamsData.test(ECoreParams::dbgbullet)) Msg("CAI_Stalker::Hit AP(%f) > BoneArmor(%f) [HitFracNpc=%f] modified hit_power=%f", ap, BoneArmor, m_boneHitProtection->m_fHitFracNpc, hit_power); } @@ -306,7 +306,7 @@ void CAI_Stalker::Hit(SHit* pHDS) hit_power *= m_boneHitProtection->m_fHitFracNpc; //HDS.add_wound = false; - if (strstr(Core.Params, "-dbgbullet")) + if (Core.ParamsData.test(ECoreParams::dbgbullet)) Msg("CAI_Stalker::Hit AP(%f) > BoneArmor(%f) [HitFracNpc=%f] modified hit_power=%f", ap, BoneArmor, m_boneHitProtection->m_fHitFracNpc, hit_power); } @@ -322,6 +322,25 @@ void CAI_Stalker::Hit(SHit* pHDS) if (g_Alive()) { + + { + const CEntityAlive *entity_alive = smart_cast(pHDS->initiator()); + if(entity_alive && entity_alive->g_Alive() && tfGetRelationType(entity_alive) == ALife::eRelationTypeEnemy) + { + movement().set_mental_state(eMentalStateDanger); + if (!memory().visual().visible_now(entity_alive)) + { + CNotYetVisibleObject new_object; + new_object.m_object = smart_cast(pHDS->initiator()); + new_object.m_value = 1.0f; + new_object.m_prev_time = Device.dwTimeGlobal-1; + new_object.m_update_time = Device.dwTimeGlobal; + memory().visual().add_not_yet_visible_object(new_object); + memory().visual().add_visible_object(pHDS->initiator(), Device.fTimeDelta); + } + } + } + bool already_critically_wounded = critically_wounded(); if (!already_critically_wounded) @@ -813,12 +832,16 @@ void CAI_Stalker::update_can_kill_info() if (m_pick_frame_id == Device.dwFrame) return; + if (!inventory().ActiveItem()) + return; + + PROF_EVENT("update_can_kill_info"); + m_pick_frame_id = Device.dwFrame; m_can_kill_member = false; m_can_kill_enemy = false; Fvector position, direction; - VERIFY(inventory().ActiveItem()); g_fireParams(0, position, direction); can_kill_entity_from(position, direction, start_pick_distance()); } diff --git a/src/xrGame/ai/stalker/ai_stalker_misc.cpp b/src/xrGame/ai/stalker/ai_stalker_misc.cpp index 7492f66f50..366732bdb7 100644 --- a/src/xrGame/ai/stalker/ai_stalker_misc.cpp +++ b/src/xrGame/ai/stalker/ai_stalker_misc.cpp @@ -60,16 +60,12 @@ bool CAI_Stalker::useful(const CItemManager* manager, const CGameObject* object) if (!memory().item().useful(object)) return (false); - const CInventoryItem* inventory_item = smart_cast(object); - if (!inventory_item || !inventory_item->useful_for_NPC()) - return (false); - const CBolt* bolt = smart_cast(object); if (bolt) return (false); CInventory* inventory_non_const = const_cast(&inventory()); - CInventoryItem* inventory_item_non_const = const_cast(inventory_item); + CInventoryItem* inventory_item_non_const = const_cast(smart_cast(object)); if (!inventory_non_const->CanTakeItem(inventory_item_non_const)) return (false); @@ -189,6 +185,9 @@ void CAI_Stalker::process_enemies() typedef MemorySpace::squad_mask_type squad_mask_type; typedef CVisualMemoryManager::VISIBLES VISIBLES; + if (!memory().visual().objectsPtr()) + return; + squad_mask_type mask = memory().visual().mask(); VISIBLES::const_iterator I = memory().visual().objects().begin(); VISIBLES::const_iterator E = memory().visual().objects().end(); diff --git a/src/xrGame/ai/trader/ai_trader.h b/src/xrGame/ai/trader/ai_trader.h index 3a554a58ca..bdce346862 100644 --- a/src/xrGame/ai/trader/ai_trader.h +++ b/src/xrGame/ai/trader/ai_trader.h @@ -45,6 +45,9 @@ class CAI_Trader : public CEntityAlive, virtual CPhysicsShellHolder* cast_physics_shell_holder() { return this; } virtual CParticlesPlayer* cast_particles_player() { return this; } virtual CScriptEntity* cast_script_entity() { return this; } + virtual CPhraseDialogManager* cast_phrase_dialog_manager() { return this; } + virtual CAI_PhraseDialogManager* cast_ai_phrase_dialog_manager() { return this; } + virtual CAI_Trader* cast_trader() { return this; } virtual DLL_Pure* _construct(); virtual void Load(LPCSTR section); diff --git a/src/xrGame/ai_space.h b/src/xrGame/ai_space.h index fc021d1f49..547b6775f7 100644 --- a/src/xrGame/ai_space.h +++ b/src/xrGame/ai_space.h @@ -72,6 +72,7 @@ class CAI_Space IC CScriptEngine& script_engine() const; IC moving_objects& moving_objects() const; IC doors::manager& doors() const; + IC CPatrolPathStorage& patrol_paths_raw(); #ifdef DEBUG void validate (const u32 level_id) const; diff --git a/src/xrGame/ai_space_inline.h b/src/xrGame/ai_space_inline.h index 52d6efbe19..3723f75611 100644 --- a/src/xrGame/ai_space_inline.h +++ b/src/xrGame/ai_space_inline.h @@ -92,3 +92,9 @@ IC CAI_Space& ai() } return (*g_ai_space); } + +IC CPatrolPathStorage& CAI_Space::patrol_paths_raw() +{ + VERIFY(m_patrol_path_storage); + return *m_patrol_path_storage; +} diff --git a/src/xrGame/aimers_base.cpp b/src/xrGame/aimers_base.cpp index 88d0a6a64d..d53222aad5 100644 --- a/src/xrGame/aimers_base.cpp +++ b/src/xrGame/aimers_base.cpp @@ -21,8 +21,8 @@ base::base( Fvector const& target ) : m_object(*object), - m_kinematics(smart_cast(*object->Visual())), - m_animated(smart_cast(*object->Visual())), + m_kinematics(*PKinematics(object->Visual())), + m_animated(*object->Visual()->dcast_PKinematicsAnimated()), m_target(target), m_animation_id(m_animated.LL_MotionID(animation_id)), m_animation_start(animation_start) diff --git a/src/xrGame/aimers_base_inline.h b/src/xrGame/aimers_base_inline.h index ed10f2cc01..f5259f595e 100644 --- a/src/xrGame/aimers_base_inline.h +++ b/src/xrGame/aimers_base_inline.h @@ -61,7 +61,8 @@ inline void aimers::base::fill_bones( for (; i != e; ++i) { VERIFY(*i < bone_count1); - m_kinematics.Bone_GetAnimPos(local_bones[*i], bones_ids[*i], channel_mask, false); + //m_kinematics.Bone_GetAnimPos(local_bones[*i], bones_ids[*i], channel_mask, false); + m_kinematics.LL_GetBoneLocalTransform(bones_ids[*i], local_bones[*i]); VERIFY(_valid(local_bones[*i])); VERIFY(_valid(m_start_transform)); diff --git a/src/xrGame/alife_graph_registry.cpp b/src/xrGame/alife_graph_registry.cpp index 7e5271d4e5..a3fdc79d7a 100644 --- a/src/xrGame/alife_graph_registry.cpp +++ b/src/xrGame/alife_graph_registry.cpp @@ -9,9 +9,11 @@ #include "stdafx.h" #include "alife_graph_registry.h" #include "../xrEngine/x_ray.h" +#include "level.h" using namespace ALife; +xr_task_group level_load; CALifeGraphRegistry::CALifeGraphRegistry() { m_level = 0; @@ -67,7 +69,20 @@ void CALifeGraphRegistry::update(CSE_ALifeDynamicObject* object) void CALifeGraphRegistry::setup_current_level() { - m_level = xr_new(ai().game_graph().vertex(actor()->m_tGraphID)->level_id()); + u8 level_id = ai().game_graph().vertex(actor()->m_tGraphID)->level_id(); + + GameGraph::LEVEL_MAP::const_iterator I = ai().game_graph().header().levels().find(level_id); + Level().set_name((*I).second.name()); + int levelid = pApp->Level_ID(*(*I).second.name(), "1.0", true); + static DWORD this_thread_id = 0; + this_thread_id = GetCurrentThreadId(); + level_load.run([=]() + { + if (this_thread_id != GetCurrentThreadId()) { PROF_THREAD("X-Ray PPL Thread") } + Level().Load(levelid); + }); + + m_level = xr_new(level_id); level().set_process_time(m_process_time); for (int i = 0, n = ai().game_graph().header().vertex_count(); i < n; ++i) if (ai().game_graph().vertex(i)->level_id() == level().level_id()) @@ -86,8 +101,6 @@ void CALifeGraphRegistry::setup_current_level() m_temp.clear(); } - GameGraph::LEVEL_MAP::const_iterator I = ai().game_graph().header().levels().find( - ai().game_graph().vertex(actor()->m_tGraphID)->level_id()); R_ASSERT2(ai().game_graph().header().levels().end() != I, "Graph point level ID not found!"); int id = pApp->Level_ID(*(*I).second.name(), "1.0", true); diff --git a/src/xrGame/alife_group_abstract.cpp b/src/xrGame/alife_group_abstract.cpp index 16ea80feb9..636164c272 100644 --- a/src/xrGame/alife_group_abstract.cpp +++ b/src/xrGame/alife_group_abstract.cpp @@ -175,7 +175,7 @@ void CSE_ALifeGroupAbstract::try_switch_offline() // detach object from the group tpGroupMember->set_health(0.f); tpGroupMember->m_bDirectControl = true; - m_tpMembers.erase(m_tpMembers.begin() + i); + m_tpMembers.erase_fast(m_tpMembers.begin() + i); tpGroupMember->m_bOnline = false; CSE_ALifeInventoryItem* item = smart_cast(tpGroupMember); if (item && item->attached()) diff --git a/src/xrGame/alife_monster_patrol_path_manager.cpp b/src/xrGame/alife_monster_patrol_path_manager.cpp index 665f006df1..856d831fb7 100644 --- a/src/xrGame/alife_monster_patrol_path_manager.cpp +++ b/src/xrGame/alife_monster_patrol_path_manager.cpp @@ -37,7 +37,7 @@ CALifeMonsterPatrolPathManager::CALifeMonsterPatrolPathManager(object_type* obje void CALifeMonsterPatrolPathManager::path(const shared_str& path_name) { - path(ai().patrol_paths().path(path_name)); + path(ai().patrol_paths().safe_path(path_name)); } const CALifeMonsterPatrolPathManager::_GRAPH_ID& CALifeMonsterPatrolPathManager::target_game_vertex_id() const diff --git a/src/xrGame/alife_simulator.cpp b/src/xrGame/alife_simulator.cpp index 935a0d4bfd..f24b9efbc7 100644 --- a/src/xrGame/alife_simulator.cpp +++ b/src/xrGame/alife_simulator.cpp @@ -27,7 +27,8 @@ extern void destroy_lua_wpn_params(); void restart_all() { - if (strstr(Core.Params, "-keep_lua")) + PROF_EVENT("restart_all"); + if (Core.ParamsData.test(ECoreParams::keep_lua)) return; destroy_lua_wpn_params(); @@ -45,6 +46,7 @@ CALifeSimulator::CALifeSimulator(xrServer* server, shared_str* command_line) : CALifeInteractionManager(server, alife_section), CALifeSimulatorBase(server, alife_section) { + PROF_EVENT("CALifeSimulator::CALifeSimulator"); restart_all(); ai().set_alife(this); diff --git a/src/xrGame/alife_simulator_base2.cpp b/src/xrGame/alife_simulator_base2.cpp index 814b967242..3c547dfcb2 100644 --- a/src/xrGame/alife_simulator_base2.cpp +++ b/src/xrGame/alife_simulator_base2.cpp @@ -64,6 +64,9 @@ void CALifeSimulatorBase::unregister_object(CSE_ALifeDynamicObject* object, bool graph().detach(*objects().object(item->base()->ID_Parent), item, objects().object(item->base()->ID_Parent)->m_tGraphID, alife_query); + // Do not rely on m_bOnline to reflect schedule registry membership during destruction. + scheduled().remove(object, true); + objects().remove(object->ID); story_objects().remove(object->m_story_id); smart_terrains().remove(object); @@ -72,7 +75,6 @@ void CALifeSimulatorBase::unregister_object(CSE_ALifeDynamicObject* object, bool if (!object->m_bOnline) { graph().remove(object, object->m_tGraphID); - scheduled().remove(object); } else if (object->ID_Parent == 0xffff) { diff --git a/src/xrGame/alife_simulator_script.cpp b/src/xrGame/alife_simulator_script.cpp index 3ed58269ce..c143c14228 100644 --- a/src/xrGame/alife_simulator_script.cpp +++ b/src/xrGame/alife_simulator_script.cpp @@ -43,6 +43,7 @@ CSE_ALifeDynamicObject* alife_object(const CALifeSimulator* self, ALife::_OBJECT if (object_id == 0xffff) { Msg("alife():object(id) ! invalid id specified"); + ai().script_engine().print_stack(); return (0); } return (self->objects().object(object_id, true)); @@ -340,7 +341,10 @@ bool has_info(const CALifeSimulator* self, const ALife::_OBJECT_ID& id, LPCSTR i if (!known_info) return (false); - if (std::find_if(known_info->begin(), known_info->end(), CFindByIDPred(info_id)) == known_info->end()) + static shared_str has_info; + has_info = info_id; + + if (std::find_if(known_info->begin(), known_info->end(), CFindByIDPred(has_info)) == known_info->end()) return (false); return (true); @@ -359,7 +363,10 @@ void AlifeGiveInfo(const CALifeSimulator *alife, const ALife::_OBJECT_ID &id, LP if (!known_info) return; - if (std::find_if(known_info->begin(), known_info->end(), CFindByIDPred(info_id)) == known_info->end()) + static shared_str AlifeGiveInfo; + AlifeGiveInfo = info_id; + + if (std::find_if(known_info->begin(), known_info->end(), CFindByIDPred(AlifeGiveInfo)) == known_info->end()) { known_info->push_back(info_id); } @@ -372,7 +379,11 @@ void AlifeRemoveInfo(const CALifeSimulator *alife, const ALife::_OBJECT_ID &id, KNOWN_INFO_VECTOR *known_info = alife->registry().get().object(id, true); if (!known_info) return; - known_info->erase(std::find_if(known_info->begin(), known_info->end(), CFindByIDPred(info_id)),known_info->end()); + + static shared_str AlifeRemoveInfo; + AlifeRemoveInfo = info_id; + + known_info->erase(std::find_if(known_info->begin(), known_info->end(), CFindByIDPred(AlifeRemoveInfo)),known_info->end()); } //Alundaio: teleport object @@ -641,7 +652,7 @@ void CALifeSimulator::script_register(lua_State* L) .def("set_switch_distance", &CALifeSimulator::set_switch_distance) //Alundaio: renamed to set_switch_distance from switch_distance //Alundaio: extend alife simulator exports - .def("teleport_object", &teleport_object) + .def("teleport_object", &::teleport_object) .def("iterate_info", &IterateInfo) .def("clone_weapon", &try_to_clone_object) .def("register", &reprocess_spawn) diff --git a/src/xrGame/alife_spawn_registry.cpp b/src/xrGame/alife_spawn_registry.cpp index 80a3eb65d6..c8260a03ef 100644 --- a/src/xrGame/alife_spawn_registry.cpp +++ b/src/xrGame/alife_spawn_registry.cpp @@ -99,7 +99,7 @@ struct dummy static bool ignore_save_incompatibility() { - return (!!strstr(Core.Params, "-ignore_save_incompatibility")); + return Core.ParamsData.test(ECoreParams::ignore_save_incompatibility); } void CALifeSpawnRegistry::load(IReader& file_stream, xrGUID* save_guid) diff --git a/src/xrGame/alife_spawn_registry_spawn.cpp b/src/xrGame/alife_spawn_registry_spawn.cpp index efef52cf26..f0b5977cd7 100644 --- a/src/xrGame/alife_spawn_registry_spawn.cpp +++ b/src/xrGame/alife_spawn_registry_spawn.cpp @@ -122,7 +122,9 @@ void CALifeSpawnRegistry::fill_new_spawns(SPAWN_GRAPH::CVertex* vertex, SPAWN_ID if (vertex->edges().empty()) { // vertex->data()->object().m_spawn_count++; - spawns.push_back(vertex->data()->object().m_tSpawnID); + const ALife::_SPAWN_ID sid = vertex->data()->object().m_tSpawnID; + if (sid != ALife::_SPAWN_ID(-1)) + spawns.push_back(sid); return; } diff --git a/src/xrGame/alife_surge_manager.cpp b/src/xrGame/alife_surge_manager.cpp index 17bffbe91a..b76febb42a 100644 --- a/src/xrGame/alife_surge_manager.cpp +++ b/src/xrGame/alife_surge_manager.cpp @@ -33,10 +33,13 @@ void CALifeSurgeManager::spawn_new_spawns() xr_vector::const_iterator E = m_temp_spawns.end(); for (; I != E; ++I) { + const CALifeSpawnRegistry::SPAWN_GRAPH::CVertex* const vertex_ptr = spawns().spawns().vertex(*I); + if (!vertex_ptr) + continue; CSE_ALifeDynamicObject *object, *spawn = smart_cast( - &spawns().spawns().vertex(*I)->data()->object()); - VERIFY3(spawn, spawns().spawns().vertex(*I)->data()->object().name(), - spawns().spawns().vertex(*I)->data()->object().name_replace()); + &vertex_ptr->data()->object()); + VERIFY3(spawn, vertex_ptr->data()->object().name(), + vertex_ptr->data()->object().name_replace()); #ifdef DEBUG CTimer timer; diff --git a/src/xrGame/alife_switch_manager.cpp b/src/xrGame/alife_switch_manager.cpp index 1308172153..39e761b9dd 100644 --- a/src/xrGame/alife_switch_manager.cpp +++ b/src/xrGame/alife_switch_manager.cpp @@ -61,7 +61,7 @@ void CALifeSwitchManager::add_online(CSE_ALifeDynamicObject* object, bool update object->s_flags.and(u16(-1) ^ M_SPAWN_UPDATE); //Alundaio: Knowing last object to spawn can be very useful to debugging - if (strstr(Core.Params, "-dbg")) + if (Core.isDebug()) Msg("[LSS] Spawning object [%s][%s][%d]", object->name_replace(), *object->s_name, object->ID); //Alundaio: Workaround for crash with corpses that end up outside AI map diff --git a/src/xrGame/alife_trader_abstract.cpp b/src/xrGame/alife_trader_abstract.cpp index 0e168dfef9..eb6800daea 100644 --- a/src/xrGame/alife_trader_abstract.cpp +++ b/src/xrGame/alife_trader_abstract.cpp @@ -147,7 +147,7 @@ void CSE_ALifeDynamicObject::detach(CSE_ALifeInventoryItem* tpALifeInventoryItem if (I) { - children.erase(*I); + children.erase_fast(*I); return; } @@ -156,7 +156,7 @@ void CSE_ALifeDynamicObject::detach(CSE_ALifeInventoryItem* tpALifeInventoryItem ALife::OBJECT_IT i = std::find(children.begin(), children.end(), tpALifeInventoryItem->base()->ID); R_ASSERT2(children.end() != i, "Can't detach an item which is not on my own"); - children.erase(i); + children.erase_fast(i); } void add_online_impl(CSE_ALifeDynamicObject* object, const bool& update_registries) diff --git a/src/xrGame/alife_update_manager.cpp b/src/xrGame/alife_update_manager.cpp index 4872b1effb..f2831b2b63 100644 --- a/src/xrGame/alife_update_manager.cpp +++ b/src/xrGame/alife_update_manager.cpp @@ -77,7 +77,7 @@ CALifeUpdateManager::~CALifeUpdateManager() { shedule_unregister(); Device.remove_from_seq_parallel( - fastdelegate::FastDelegate0<>( + xr_make_delegate( this, &CALifeUpdateManager::update ) @@ -112,6 +112,7 @@ void CALifeUpdateManager::update_scheduled(bool init_ef) void CALifeUpdateManager::update() { + PROF_EVENT("AI: A-Life Update"); update_switch(); update_scheduled(false); } @@ -126,7 +127,7 @@ void CALifeUpdateManager::shedule_Update(u32 dt) if (!m_first_time && g_mt_config.test(mtALife)) { Device.seqParallel.push_back( - fastdelegate::FastDelegate0<>( + xr_make_delegate( this, &CALifeUpdateManager::update ) @@ -274,8 +275,11 @@ void CALifeUpdateManager::new_game(LPCSTR save_name) Msg("* New game is successfully created!"); } +extern xr_task_group level_load; + void CALifeUpdateManager::load(LPCSTR game_name, bool no_assert, bool new_only) { + PROF_EVENT("Load Alife Simulator"); // g_pGamePersistent->LoadTitle ("st_loading_alife_simulator"); g_pGamePersistent->LoadTitle(); @@ -300,6 +304,7 @@ void CALifeUpdateManager::load(LPCSTR game_name, bool no_assert, bool new_only) #endif // g_pGamePersistent->LoadTitle ("st_server_connecting"); g_pGamePersistent->LoadTitle(true, g_pGameLevel->name()); + level_load.wait(); } void CALifeUpdateManager::reload(LPCSTR section) @@ -562,7 +567,7 @@ void CALifeUpdateManager::remove_restriction(ALife::_OBJECT_ID id, ALife::_OBJEC return; } - creature->m_dynamic_out_restrictions.erase(I); + creature->m_dynamic_out_restrictions.erase_fast(I); break; } @@ -579,7 +584,7 @@ void CALifeUpdateManager::remove_restriction(ALife::_OBJECT_ID id, ALife::_OBJEC return; } - creature->m_dynamic_in_restrictions.erase(I); + creature->m_dynamic_in_restrictions.erase_fast(I); break; } diff --git a/src/xrGame/atlas_submit_queue.h b/src/xrGame/atlas_submit_queue.h index 84fa32641e..dc1ce3cbc0 100644 --- a/src/xrGame/atlas_submit_queue.h +++ b/src/xrGame/atlas_submit_queue.h @@ -2,7 +2,7 @@ #define ATLAS_SUBMIT_QUEUE_INCLUDED -#include +#include "../xrCore/xr_delegate.h" #include "profile_data_types.h" namespace gamespy_profile diff --git a/src/xrGame/attachable_item.cpp b/src/xrGame/attachable_item.cpp index 30eb3c44f3..5c71c10ee1 100644 --- a/src/xrGame/attachable_item.cpp +++ b/src/xrGame/attachable_item.cpp @@ -13,6 +13,7 @@ #include "inventory.h" #include "../xrEngine/xr_input.h" #include "ui_base.h" +#include "../Include/xrRender/RenderVisual.h" #ifdef DEBUG CAttachableItem* CAttachableItem::m_dbgItem = NULL; @@ -65,10 +66,10 @@ void CAttachableItem::OnH_A_Chield() object().setVisible(true); } -void CAttachableItem::renderable_Render() +void CAttachableItem::renderable_Render(IDSGraphManager* DM) { - ::Render->set_Transform(&object().XFORM()); - ::Render->add_Visual(object().Visual()); + DM->add_Dynamic(object().Visual(), &object().XFORM()); + object().Visual()->getVisData().hom_frame = Device.dwFrame; } void CAttachableItem::OnH_A_Independent() diff --git a/src/xrGame/attachable_item.h b/src/xrGame/attachable_item.h index b36fb827ad..90bfa88997 100644 --- a/src/xrGame/attachable_item.h +++ b/src/xrGame/attachable_item.h @@ -10,6 +10,7 @@ class CPhysicsShellHolder; class CInventoryItem; +class CTorch; class CAttachableItem { @@ -29,10 +30,12 @@ class CAttachableItem virtual ~CAttachableItem(); virtual DLL_Pure* _construct(); virtual CAttachableItem* cast_attachable_item() { return this; } + virtual CInventoryItem* cast_inventory_item() { return nullptr; } + virtual CTorch* cast_torch() { return nullptr; } virtual void reload(LPCSTR section); virtual void OnH_A_Chield(); virtual void OnH_A_Independent(); - virtual void renderable_Render(); + virtual void renderable_Render(IDSGraphManager* DM); virtual bool can_be_attached() const; bool load_attach_position(LPCSTR section); virtual void afterAttach(); diff --git a/src/xrGame/attachment_owner.cpp b/src/xrGame/attachment_owner.cpp index 5f3ff359bc..90a18ef1aa 100644 --- a/src/xrGame/attachment_owner.cpp +++ b/src/xrGame/attachment_owner.cpp @@ -52,12 +52,10 @@ void CAttachmentOwner::net_Destroy() R_ASSERT(attached_objects().empty()); } -void CAttachmentOwner::renderable_Render() +void CAttachmentOwner::renderable_Render(IDSGraphManager* DM) { - xr_vector::iterator I = m_attached_objects.begin(); - xr_vector::iterator E = m_attached_objects.end(); - for (; I != E; ++I) - (*I)->renderable_Render(); + for (CAttachableItem* item : m_attached_objects) + item->renderable_Render(DM); } void __stdcall AttachmentCallback(IKinematics* tpKinematics) @@ -117,7 +115,7 @@ void CAttachmentOwner::detach(CInventoryItem* inventory_item) if ((*I)->item().object().ID() == inventory_item->object().ID()) { CAttachableItem* ai = *I; - m_attached_objects.erase(I); + m_attached_objects.erase_fast(I); ai->afterDetach(); if (m_attached_objects.empty()) { diff --git a/src/xrGame/attachment_owner.h b/src/xrGame/attachment_owner.h index 453946c3ef..8e03bb3b85 100644 --- a/src/xrGame/attachment_owner.h +++ b/src/xrGame/attachment_owner.h @@ -27,7 +27,7 @@ class CAttachmentOwner virtual void reinit(); virtual void reload(LPCSTR section); virtual void net_Destroy(); - virtual void renderable_Render(); + virtual void renderable_Render(IDSGraphManager* DM); virtual void attach(CInventoryItem* inventory_item); virtual void detach(CInventoryItem* inventory_item); virtual bool can_attach(const CInventoryItem* inventory_item) const; diff --git a/src/xrGame/autosave_manager.cpp b/src/xrGame/autosave_manager.cpp index c72e2ff5d4..0e8bc16bd7 100644 --- a/src/xrGame/autosave_manager.cpp +++ b/src/xrGame/autosave_manager.cpp @@ -49,6 +49,7 @@ float CAutosaveManager::shedule_Scale() void CAutosaveManager::shedule_Update(u32 dt) { + PROF_EVENT("CAutosaveManager::shedule_Update"); inherited::shedule_Update(dt); #pragma todo("Plecha to Plecha : AUTOSAVE (do not forgive to enable it in release version:-))))!!!!") if (true) return; diff --git a/src/xrGame/best_scores_store.h b/src/xrGame/best_scores_store.h index a38bcadbf9..4a419d2655 100644 --- a/src/xrGame/best_scores_store.h +++ b/src/xrGame/best_scores_store.h @@ -10,7 +10,7 @@ class CGameSpy_SAKE; namespace gamespy_profile { - typedef fastdelegate::FastDelegate bestscore_operation_cb; + typedef xr_delegate bestscore_operation_cb; class best_scores_store { diff --git a/src/xrGame/callback_info.h b/src/xrGame/callback_info.h index 981a5f6d46..0a57b7558f 100644 --- a/src/xrGame/callback_info.h +++ b/src/xrGame/callback_info.h @@ -7,7 +7,7 @@ class CUIWindow; struct SCallbackInfo { CScriptCallbackEx m_callback; - fastdelegate::FastDelegate2 m_cpp_callback; + xr_delegate m_cpp_callback; CUIWindow* m_control_ptr; shared_str m_control_name; s16 m_event; diff --git a/src/xrGame/cdkey_ban_list.cpp b/src/xrGame/cdkey_ban_list.cpp index 7e922faee0..3a3907149e 100644 --- a/src/xrGame/cdkey_ban_list.cpp +++ b/src/xrGame/cdkey_ban_list.cpp @@ -161,7 +161,7 @@ void cdkey_ban_list::unban_player_by_index(size_t const index) return; } xr_delete(m_ban_list[index]); - m_ban_list.erase(m_ban_list.begin() + index); + m_ban_list.erase_fast(m_ban_list.begin() + index); save(); } diff --git a/src/xrGame/client_spawn_manager.h b/src/xrGame/client_spawn_manager.h index 1d8972b8e6..17d42df93c 100644 --- a/src/xrGame/client_spawn_manager.h +++ b/src/xrGame/client_spawn_manager.h @@ -17,7 +17,7 @@ class CGameObject; class CClientSpawnManager { public: - typedef fastdelegate::FastDelegate1 CALLBACK_TYPE; + typedef xr_delegate CALLBACK_TYPE; public: struct CSpawnCallback diff --git a/src/xrGame/configs_dumper.h b/src/xrGame/configs_dumper.h index 359ed7d855..fde08f72d9 100644 --- a/src/xrGame/configs_dumper.h +++ b/src/xrGame/configs_dumper.h @@ -24,8 +24,8 @@ namespace mp_anticheat class configs_dumper : public ISheduled { public: - typedef fastdelegate::FastDelegate3 complete_callback_t; - typedef fastdelegate::FastDelegate1 yield_callback_t; + typedef xr_delegate complete_callback_t; + typedef xr_delegate yield_callback_t; configs_dumper(); virtual ~configs_dumper(); diff --git a/src/xrGame/console_commands.cpp b/src/xrGame/console_commands.cpp index 0eac01e435..5fe4ad7a39 100644 --- a/src/xrGame/console_commands.cpp +++ b/src/xrGame/console_commands.cpp @@ -177,6 +177,14 @@ extern float NPCsLookAtActorMinDistance; extern BOOL interruptFireOnAimToggle; extern BOOL mt_UpdateWeaponSounds; +extern BOOL mt_Scheduler; +extern BOOL mt_SchedulerRT; +extern BOOL mt_calc_bones; +extern BOOL mt_ph_commander; +extern BOOL mt_TaskManager; +extern BOOL mt_ui; +extern int SchedulerBatchSize; +extern BOOL SchedulerLog; extern BOOL alifeObjectHangingLampIgnoreMatchConfiguration; extern BOOL duplicate_story_id_crash; @@ -189,6 +197,9 @@ extern float IK_CALC_SSA; extern float IK_ALWAYS_CALC_DIST; extern BOOL r_optimize_calculate_bones; extern BOOL r_optimize_torch; +extern BOOL hud_frequent_updates; + +extern BOOL lua_use_functor_cache; extern BOOL g_legs_enabled; extern float legs_fwd_offset; @@ -218,6 +229,7 @@ extern u32 g_ai_aim_inertia_time; extern u32 g_ai_aim_queue_inertia_time; extern float g_ai_danger_ricochet_mult; BOOL g_ai_move_to_cover_run = FALSE; +BOOL g_ai_enhanced_vision = FALSE; extern CrosshairSettings g_crosshair_camera_near; extern CrosshairSettings g_crosshair_camera_far; @@ -351,20 +363,23 @@ CUIOptConCom g_OptConCom; extern u32 game_lua_memory_usage(); #endif // SEVERAL_ALLOCATORS -typedef void (*full_memory_stats_callback_type)(); +typedef void (*full_memory_stats_callback_type)(bool); extern XRCORE_API full_memory_stats_callback_type g_full_memory_stats_callback; +static xr_atomic_bool g_mem_stats_async_in_progress = false; -static void full_memory_stats() +static void full_memory_stats(bool assert = true) { + PROF_EVENT("full_memory_stats"); Msg("* [x-ray]: Full Memory Stats"); Memory.mem_compact(); - size_t _process_heap = ::Memory.mem_usage(); + size_t _process_heap = ::Memory.mem_usage(assert); #ifdef SEVERAL_ALLOCATORS u32 _game_lua = game_lua_memory_usage(); u32 _render = ::Render->memory_usage(); #endif // SEVERAL_ALLOCATORS - u32 _eco_strings_count = 0; - int _eco_strings = (int)g_pStringContainer->stat_economy(_eco_strings_count); + u32 _eco_strings_count = 0; + u32 _eco_strings_unique_count = 0; + int _eco_strings = (int)g_pStringContainer->stat_economy(_eco_strings_count, _eco_strings_unique_count); int _eco_smem = (int)g_pSharedMemoryContainer->stat_economy(); u32 m_base = 0, c_base = 0, m_lmaps = 0, c_lmaps = 0; @@ -382,7 +397,10 @@ static void full_memory_stats() Msg("* [x-ray]: process heap[%u K], game lua[%d K], render[%d K]", _process_heap / 1024, _game_lua / 1024, _render / 1024); #endif // SEVERAL_ALLOCATORS - Msg("* [x-ray]: shared strings: memory[%ld K], count[%lu]", _eco_strings / 1024, _eco_strings_count); + Msg("* [x-ray]: shared strings: memory[%ld K], count[%lu], unique[%lu]", _eco_strings / 1024, _eco_strings_count, _eco_strings_unique_count); + if (_eco_strings_count != _eco_strings_unique_count) + Msg("! [x-ray]: shared strings, count != unique"); + Msg("* [x-ray]: shared memory: memory[%ld K]", _eco_smem); u64 DLTX_total_bytes = 0; @@ -390,9 +408,11 @@ static void full_memory_stats() u64 DLTX_files_cached = 0; CInifile::GetCacheStats(DLTX_files_cached, DLTX_total_bytes, DLTX_section_count); Msg("* [x-ray]: DLTX Cache: Files Cached: %zu, Sections Total %zu, Usage: %.2f MB", DLTX_files_cached, DLTX_section_count, (double)DLTX_total_bytes / 1024 / 1024); - - size_t lua_mem = lua_gc(ai().script_engine().lua(), LUA_GCCOUNT, 0); - Msg("* [Lua]: Memory usage: %u K", lua_mem); + + /*if (Console) + { + Console->DumpHistoryToLog(); + }*/ #ifdef FS_DEBUG Msg("* [x-ray]: file mapping: memory[%d K], count[%d]", g_file_mapped_memory / 1024, g_file_mapped_count); @@ -411,9 +431,71 @@ class CCC_MemStats : public IConsole_Command virtual void Execute(LPCSTR args) { + if (g_mem_stats_async_in_progress.load(std::memory_order_acquire)) + { + Msg("* [x-ray]: stat_memory_async is already running"); + return; + } + full_memory_stats(); } }; + +static void mem_stats_async_thread(void*) +{ + try + { + PROF_EVENT("mem_stats_async_thread"); + full_memory_stats(false); + } + catch (...) + { + // do nothing + } + g_mem_stats_async_in_progress.store(false, std::memory_order_release); +} + +class CCC_MemStatsAsync : public IConsole_Command +{ +public: + CCC_MemStatsAsync(LPCSTR N) : IConsole_Command(N) + { + g_full_memory_stats_callback = &full_memory_stats; + bEmptyArgsHandled = TRUE; + }; + + virtual void Execute(LPCSTR args) + { + if (g_mem_stats_async_in_progress.exchange(true, std::memory_order_acq_rel)) + { + Msg("* [x-ray]: stat_memory_async is already running"); + return; + } + + thread_spawn(&mem_stats_async_thread, "stat_memory_async", 0, nullptr); + Msg("* [x-ray]: stat_memory_async started"); + } +}; + +static void shared_string_dump() { + g_pStringContainer->dump_console(); +} + + +class CCC_SharedStringDump : public IConsole_Command +{ +public: + CCC_SharedStringDump(LPCSTR N) : IConsole_Command(N) + { + bEmptyArgsHandled = TRUE; + }; + + virtual void Execute(LPCSTR args) + { + shared_string_dump(); + } +}; + #ifdef DEBUG class CCC_MemCheckpoint : public IConsole_Command { @@ -1024,7 +1106,7 @@ class CCC_ALifeSave : public IConsole_Command return; } - Console->Execute("stat_memory"); + // Console->Execute("stat_memory"); string_path S, S1; S[0] = 0; @@ -1146,7 +1228,7 @@ class CCC_ALifeLoadFrom : public IConsole_Command if (MainMenu()->IsActive()) MainMenu()->Activate(false); - Console->Execute("stat_memory"); + // Console->Execute("stat_memory"); if (Device.Paused()) Device.Pause(FALSE, TRUE, TRUE, "CCC_ALifeLoadFrom"); @@ -1237,7 +1319,7 @@ class CCC_FlushLog : public IConsole_Command virtual void Execute(LPCSTR /**args/**/) { - FlushLog(); + xrLogger::FlushLog(); Msg("* Log file has been saved successfully!"); } }; @@ -1249,8 +1331,8 @@ class CCC_ClearLog : public IConsole_Command virtual void Execute(LPCSTR) { - LogFile.clear_not_free(); - FlushLog(); + Console->ClearLog(); + xrLogger::FlushLog(); Msg("* Log file has been cleaned successfully!"); } }; @@ -1917,7 +1999,7 @@ class CCC_TimeFactor : public IConsole_Command float time_factor = (float)atof(args); clamp(time_factor, EPS, 1000.f); Device.time_factor(time_factor); - if (!strstr(Core.Params, "-sound_constant_speed")) + if (!Core.ParamsData.test(ECoreParams::sound_constant_speed)) psSpeedOfSound = time_factor; } @@ -2465,12 +2547,61 @@ class CCC_MovePathQueryPosThreshold : public CCC_Float } }; +// Add after other includes, before command classes +#include "../Include/xrRender/particles_systems_library_interface.hpp" +#include "../Layers/xrRender/PSLibrary.h" +#include "GamePersistent.h" + +class CCC_Particle_TEST : public IConsole_Command +{ +public: + CCC_Particle_TEST(LPCSTR N) + : IConsole_Command(N) { bEmptyArgsHandled = TRUE; }; + virtual void Execute(LPCSTR args) + { + if (!g_pGameLevel) + return; + if (!Level().CurrentControlEntity()) + return; + + collide::rq_result l_rq; + if (Level().ObjectSpace.RayPick(Device.vCameraPosition, Device.vCameraDirection, 1000.f, collide::rqtBoth, l_rq, Level().CurrentControlEntity())) + { + int count = 1; + string256 string; + string[0] = 0; + sscanf(args, "%s %d", &string, &count); + for (int i = 0; i < count; ++i) + { + auto pParticle = Particles::Details::Create(string, FALSE); + + // Set up matrix and position + Fmatrix pos; + pos.identity(); + pos.k.set(Level().CurrentControlEntity()->XFORM().k); + Fvector::generate_orthonormal_basis_normalized(pos.k, pos.j, pos.i); + pos.c.set(Fvector(Device.vCameraPosition).add(Fvector(Device.vCameraDirection).mul(l_rq.range))); + pParticle->UpdateParent(pos, zero_vel); + GamePersistent().ps_needtoplay.push_back(pParticle); + } + } + } + virtual void fill_tips(vecTips& tips, u32 mode) + { + particles_systems::library_interface const& library = GamePersistent().Environment().m_pRender->particles_systems_library(); + for (auto pi = library.vec_all_particles().begin(); pi != library.vec_all_particles().end(); ++pi) + tips.push_back(pi->c_str()); + } +}; + void CCC_RegisterCommands() { //Not needed for a singleplayer-only mod //g_OptConCom.Init(); CMD1(CCC_MemStats, "stat_memory"); + CMD1(CCC_MemStatsAsync, "stat_memory_async"); + CMD1(CCC_SharedStringDump, "stat_shared_string_dump"); #ifdef DEBUG CMD1(CCC_MemCheckpoint, "stat_memory_checkpoint"); #endif //#ifdef DEBUG @@ -2547,6 +2678,8 @@ void CCC_RegisterCommands() CMD1(CCC_DemoRecordSetDir, "demo_set_cam_direction"); //#endif // #ifndef MASTER_GOLD + CMD3(CCC_Mask, "mt_bullets", &g_mt_config, mtBullets); + #ifndef MASTER_GOLD // ai CMD3(CCC_Mask, "mt_ai_vision", &g_mt_config, mtAiVision); @@ -2554,7 +2687,6 @@ void CCC_RegisterCommands() CMD3(CCC_Mask, "mt_detail_path", &g_mt_config, mtDetailPath); CMD3(CCC_Mask, "mt_object_handler", &g_mt_config, mtObjectHandler); CMD3(CCC_Mask, "mt_sound_player", &g_mt_config, mtSoundPlayer); - CMD3(CCC_Mask, "mt_bullets", &g_mt_config, mtBullets); CMD3(CCC_Mask, "mt_script_gc", &g_mt_config, mtLUA_GC); CMD3(CCC_Mask, "mt_level_sounds", &g_mt_config, mtLevelSounds); CMD3(CCC_Mask, "mt_alife", &g_mt_config, mtALife); @@ -2580,6 +2712,7 @@ void CCC_RegisterCommands() CMD4(CCC_Integer, "lua_parallel_gc", &psLua_ParallelGC, 0, 1); CMD4(CCC_Integer, "lua_debug", &lua_debug, 0, 1); + CMD4(CCC_Integer, "lua_use_functor_cache", &lua_use_functor_cache, 0, 1); CMD4(CCC_Integer, "lua_busy_hands_debug", &lua_busy_hands_debug, 0, 1); #ifdef DEBUG @@ -2693,7 +2826,7 @@ void CCC_RegisterCommands() /* AVO: changing restriction to -dbg key instead of DEBUG */ //#ifndef MASTER_GOLD #ifdef MASTER_GOLD - if (0 != strstr(Core.Params, "-dbg")) + if (0 != Core.isDebug()) { CMD1(CCC_JumpToLevel, "jump_to_level"); CMD3(CCC_Mask, "g_god", &psActorFlags, AF_GODMODE); @@ -2733,8 +2866,6 @@ void CCC_RegisterCommands() CMD4(CCC_Integer, "ai_grenade_throw_delay_base", &g_ai_grenade_throw_delay_base, 0, 10000); CMD4(CCC_Integer, "ai_grenade_throw_delay_step", &g_ai_grenade_throw_delay_step, 0, 10000); - extern u32 g_ai_aim_inertia_time; - extern u32 g_ai_aim_queue_inertia_time; CMD4(CCC_Integer, "ai_aim_inertia_time", (int*)&g_ai_aim_inertia_time, 0, 10000); CMD4(CCC_Integer, "ai_aim_queue_inertia_time", (int*)&g_ai_aim_queue_inertia_time, 0, 10000); // Danger perception multipliers: 1.0 = original engine behaviour, 0.0 = disabled, 5.0 = 5x urgency @@ -2755,8 +2886,8 @@ void CCC_RegisterCommands() CMD4(CCC_Float, "ai_danger_grenade_mult", &g_ai_danger_grenade_mult, 0.f, 5.f); CMD4(CCC_Float, "ai_danger_enemy_sound_mult", &g_ai_danger_enemy_sound_mult, 0.f, 5.f); - extern BOOL g_ai_move_to_cover_run; - CMD4(CCC_Integer, "ai_move_to_cover_run", &g_ai_move_to_cover_run, 0, 1); + CMD4(CCC_Integer, "ai_move_to_cover_run", &g_ai_move_to_cover_run, 0, 1); + CMD4(CCC_Integer, "ai_enhanced_vision", &g_ai_enhanced_vision, 0, 1); CMD4(CCC_Float, "ai_vision_speed_boost", &g_ai_vision_speed_boost, 0.1f, 10.0f); CMD4(CCC_Float, "ai_reload_threshold", &g_ai_reload_threshold, 0.01f, 1.0f); @@ -3098,6 +3229,15 @@ void CCC_RegisterCommands() CMD3(CCC_Mask, "blend_move_anims", &psDeviceFlags2, rsBlendMoveAnims); CMD4(CCC_Integer, "mt_update_weapon_sounds", &mt_UpdateWeaponSounds, 0, 1); + CMD4(CCC_Integer, "mt_scheduler", &mt_Scheduler, 0, 1); + CMD4(CCC_Integer, "mt_schedulerRT", &mt_SchedulerRT, 0, 1); + CMD4(CCC_Integer, "mt_level_call", &mt_ph_commander, 0, 1); + CMD4(CCC_Integer, "mt_calc_bones", &mt_calc_bones, 0, 1); + CMD4(CCC_Integer, "mt_task_manager", &mt_TaskManager, 0, 1); + CMD4(CCC_Integer, "mt_ui", &mt_ui, 0, 1); + + CMD4(CCC_Integer, "scheduler_batch_size", &SchedulerBatchSize, 32, 65536); + CMD4(CCC_Integer, "scheduler_log", &SchedulerLog, 0, 1); CMD4(CCC_Integer, "spawn_antifreeze", &spawn_antifreeze, 0, 1); CMD4(CCC_Integer, "spawn_antifreeze_debug", &spawn_antifreeze_debug, 0, 1); @@ -3105,8 +3245,9 @@ void CCC_RegisterCommands() CMD4(CCC_Float, "ik_calc_dist", &IK_CALC_DIST, 50, 150); CMD4(CCC_Float, "ik_calc_ssa", &IK_CALC_SSA, 0.001f, 0.02f); CMD4(CCC_Float, "ik_always_calc_dist", &IK_ALWAYS_CALC_DIST, 10, 50); - CMD4(CCC_Integer, "r__optimize_calculate_bones", &r_optimize_calculate_bones, 0, 1); - CMD4(CCC_Integer, "r__optimize_torch", &r_optimize_torch, 0, 1); + CMD4(CCC_Integer, "r__optimize_calculate_bones", &r_optimize_calculate_bones, 0, 1); + CMD4(CCC_Integer, "r__optimize_torch", &r_optimize_torch, 0, 1); + CMD4(CCC_Integer, "hud_frequent_updates", &hud_frequent_updates, 0, 1); CMD4(CCC_Integer, "g_progressive_stamina_cost", &progressiveStaminaCost, 0, 1); CMD4(CCC_Integer, "g_npcs_look_at_actor", &NPCsLookAtActor, 0, 1); @@ -3236,7 +3377,7 @@ void CCC_RegisterCommands() // New zoom delta algorithm CMD4(CCC_Integer, "new_zoom_delta_algorithm", &useNewZoomDeltaAlgorithm, 0, 1); - if (strstr(Core.Params, "-dbgdev")) + if (Core.ParamsData.test(ECoreParams::dbgdev)) CMD4(CCC_Float, "g_streff", &streff, -10.f, 10.f); //No need for server commands in a singleplayer-only mod //register_mp_console_commands(); @@ -3266,10 +3407,12 @@ void CCC_RegisterCommands() CMD4(CCC_Integer, "g_draw_pickup_item_names", &drawPickupItemNames, 0, 1); // Wallmark distances - CMD4(CCC_Float, "g_wallmark_range_static", &wallmark_range_static, 0.f, 1000.f); - CMD4(CCC_Float, "g_wallmark_range_skeleton", &wallmark_range_skeleton, 0.f, 1000.f); + //CMD4(CCC_Float, "g_wallmark_range_static", &wallmark_range_static, 0.f, 1000.f); + //CMD4(CCC_Float, "g_wallmark_range_skeleton", &wallmark_range_skeleton, 0.f, 1000.f); + + CMD1(CCC_MovePathQueryPosThreshold, "movement_manager_move_along_path_query_pos_threshold"); - CMD1(CCC_MovePathQueryPosThreshold, "movement_manager_move_along_path_query_pos_threshold"); + CMD1(CCC_Particle_TEST, "g_ps_test"); CMD4(CCC_Integer, "show_actor_body", &showActorBody, 0, 2); CMD4(CCC_Integer, "disable_actor_body_rotation_delay", &disableActorBodyRotationDelay, 0, 1); } diff --git a/src/xrGame/cover_manager.cpp b/src/xrGame/cover_manager.cpp index 7798dbb95a..efad681303 100644 --- a/src/xrGame/cover_manager.cpp +++ b/src/xrGame/cover_manager.cpp @@ -33,7 +33,7 @@ CCoverManager::~CCoverManager() xr_delete(m_smart_covers_storage); } -IC bool CCoverManager::edge_vertex(u32 index) +IC bool CCoverManager::edge_vertex(u32 index) const { CLevelGraph::CVertex* v = ai().level_graph().vertex(index); return ( @@ -48,7 +48,7 @@ IC bool CCoverManager::edge_vertex(u32 index) ); } -IC bool CCoverManager::cover(CLevelGraph::CVertex* v, u32 index0, u32 index1) +IC bool CCoverManager::cover(CLevelGraph::CVertex* v, u32 index0, u32 index1) const { return ( ai().level_graph().valid_vertex_id(v->link(index0)) && @@ -57,7 +57,7 @@ IC bool CCoverManager::cover(CLevelGraph::CVertex* v, u32 index0, u32 index1) ); } -IC bool CCoverManager::critical_point(CLevelGraph::CVertex* v, u32 index, u32 index0, u32 index1) +IC bool CCoverManager::critical_point(CLevelGraph::CVertex* v, u32 index, u32 index0, u32 index1) const { return ( !ai().level_graph().valid_vertex_id(v->link(index)) && @@ -70,7 +70,7 @@ IC bool CCoverManager::critical_point(CLevelGraph::CVertex* v, u32 index, u32 in ); } -IC bool CCoverManager::critical_cover(u32 index) +IC bool CCoverManager::critical_cover(u32 index) const { CLevelGraph::CVertex* v = ai().level_graph().vertex(index); return ( @@ -83,38 +83,39 @@ IC bool CCoverManager::critical_cover(u32 index) void CCoverManager::compute_static_cover() { + PROF_EVENT(); clear(); xr_delete(m_covers); - m_covers = xr_new(ai().level_graph().header().box(), ai().level_graph().header().cell_size() * .5f, - 8 * 65536, 4 * 65536); + m_covers = xr_new(ai().level_graph().header().box(), ai().level_graph().header().cell_size() * .5f, 8 * 65536, 4 * 65536); m_temp.resize(ai().level_graph().header().vertex_count()); - CLevelGraph const& graph = ai().level_graph(); - u32 n = ai().level_graph().header().vertex_count(); - for (u32 i = 0; i < n; ++i) + const CLevelGraph& Graph = ai().level_graph(); + const u32 LevelVertexCount = ai().level_graph().header().vertex_count(); + + xr_parallel_for(0u, LevelVertexCount, [&](u32 range) { - CLevelGraph::CVertex const& vertex = *graph.vertex(i); + const CLevelGraph::CVertex& vertex = *Graph.vertex(range); if (vertex.high_cover(0) + vertex.high_cover(1) + vertex.high_cover(2) + vertex.high_cover(3)) { - m_temp[i] = edge_vertex(i); - continue; + m_temp[range] = edge_vertex(range); + return; } if (vertex.low_cover(0) + vertex.low_cover(1) + vertex.low_cover(2) + vertex.low_cover(3)) { - m_temp[i] = edge_vertex(i); - continue; + m_temp[range] = edge_vertex(range); + return; } - m_temp[i] = false; - } + m_temp[range] = false; + }); - for (u32 i = 0; i < n; ++i) + for (u32 i = 0; i < LevelVertexCount; ++i) if (m_temp[i] && critical_cover(i)) - m_covers->insert(xr_new(ai().level_graph().vertex_position(ai().level_graph().vertex(i)), i)); + m_covers->insert(xr_new(ai().level_graph().vertex_position(ai().level_graph().vertex(i)),i)); - VERIFY(!m_smart_covers_storage); - m_smart_covers_storage = xr_new(); + VERIFY (!m_smart_covers_storage); + m_smart_covers_storage = xr_new(); } void CCoverManager::clear_covers(PointVector& covers) diff --git a/src/xrGame/cover_manager.h b/src/xrGame/cover_manager.h index 7b02004297..3222f61fee 100644 --- a/src/xrGame/cover_manager.h +++ b/src/xrGame/cover_manager.h @@ -51,10 +51,10 @@ class CCoverManager protected: - IC bool edge_vertex(u32 index); - IC bool cover(LevelGraph::CVertex* v, u32 index0, u32 index1); - IC bool critical_point(LevelGraph::CVertex* v, u32 index, u32 index0, u32 index1); - IC bool critical_cover(u32 index); + IC bool edge_vertex(u32 index) const; + IC bool cover(LevelGraph::CVertex* v, u32 index0, u32 index1) const; + IC bool critical_point(LevelGraph::CVertex* v, u32 index, u32 index0, u32 index1) const; + IC bool critical_cover(u32 index) const; private: template diff --git a/src/xrGame/cta_game_artefact.cpp b/src/xrGame/cta_game_artefact.cpp index 0dc9bed76d..38210351e9 100644 --- a/src/xrGame/cta_game_artefact.cpp +++ b/src/xrGame/cta_game_artefact.cpp @@ -90,7 +90,7 @@ void CtaGameArtefact::OnAnimationEnd(u32 state) void CtaGameArtefact::UpdateCLChild() { inherited::UpdateCLChild(); - if (H_Parent()) + if (H_Parent() && IsHidden()) XFORM().set(H_Parent()->XFORM()); if (!m_artefact_rpoint) @@ -139,7 +139,7 @@ void CtaGameArtefact::CreateArtefactActivation() CGameObject::u_EventGen(P, GE_OWNERSHIP_REJECT, H_Parent()->ID()); P.w_u16(ID()); P.w_u8(0); - P.w_vec3(*m_artefact_rpoint); + P.w_vec3(m_artefact_rpoint ? *m_artefact_rpoint : Position()); CGameObject::u_EventSend(P); MoveTo(*m_artefact_rpoint); //for server net_Import } diff --git a/src/xrGame/danger_manager.cpp b/src/xrGame/danger_manager.cpp index ce4e8ed7da..08299df03a 100644 --- a/src/xrGame/danger_manager.cpp +++ b/src/xrGame/danger_manager.cpp @@ -178,7 +178,7 @@ void CDangerManager::remove_links(const CObject* object) IGNORED::iterator I = std::find(m_ignored.begin(), m_ignored.end(), object->ID()); if (I != m_ignored.end()) - m_ignored.erase(I); + m_ignored.erase_fast(I); } bool CDangerManager::useful(const CDangerObject& object) const diff --git a/src/xrGame/date_time.cpp b/src/xrGame/date_time.cpp index 14da6e75cb..9566edf646 100644 --- a/src/xrGame/date_time.cpp +++ b/src/xrGame/date_time.cpp @@ -1,76 +1,50 @@ -//////////////////////////////////////////////////////////////////////////// -// Module : date_time.h -// Created : 08.05.2004 -// Modified : 08.05.2004 -// Author : Dmitriy Iassenev -// Description : Date and time routines -//////////////////////////////////////////////////////////////////////////// - #include "stdafx.h" +#include "date_time.h" -#if 0 -#define CHECK_YEAR(year) \ - do {\ - generate_time ( year - 1, 12, 31, 0, 0, 0, 0);\ - generate_time ( year, 1, 1, 0, 0, 0, 0);\ - generate_time ( year, 2, 28, 0, 0, 0, 0);\ - if ((year % 400 == 0) || ((year % 4 == 0) && (year % 100 != 0)) )\ - generate_time ( year, 2, 29, 0, 0, 0, 0);\ - } while (0) - - generate_time ( 1, 1, 1, 0, 0, 0, 0); - generate_time ( 1, 2, 28, 0, 0, 0, 0); - CHECK_YEAR ( 2); - CHECK_YEAR ( 3); - CHECK_YEAR ( 4); - CHECK_YEAR ( 5); - CHECK_YEAR (1600); - CHECK_YEAR (1700); - CHECK_YEAR (1800); - CHECK_YEAR (1900); - CHECK_YEAR (2000); - CHECK_YEAR (2010); - CHECK_YEAR (2011); - CHECK_YEAR (2012); - CHECK_YEAR (2013); +u32 extra_day_count(u32 years) +{ + return ((years % 400 == 0) || ((years % 4 == 0) && (years % 100 != 0))) ? 1 : 0; +} -#undef CHECK_YEAR -#endif // #if 0 +static u32 days_in_month[12] = { 31u, 28u, 31u, 30u, 31u, 30u, 31u, 31u, 30u, 31u, 30u, 31u }; -static u64 generate_time_impl(u32 years, u32 months, u32 days, u32 hours, u32 minutes, u32 seconds, u32 milliseconds) +u64 generate_time(u32 years, u32 months, u32 days, u32 hours, u32 minutes, u32 seconds, u32 milliseconds) { - u64 const extra_day_count = ((years % 400 == 0) || ((years % 4 == 0) && (years % 100 != 0))) ? 1 : 0; u64 const years_minus_1 = u64(years - 1); - u64 result = years_minus_1 * 365 + years_minus_1 / 4 - years_minus_1 / 100 + years_minus_1 / 400; - if (months > 1) result += u64(31); - if (months > 2) result += u64(28 + extra_day_count); - if (months > 3) result += u64(31); - if (months > 4) result += u64(30); - if (months > 5) result += u64(31); - if (months > 6) result += u64(30); - if (months > 7) result += u64(31); - if (months > 8) result += u64(31); - if (months > 9) result += u64(30); - if (months > 10) result += u64(31); - if (months > 11) result += u64(30); + u64 result = years_minus_1 * 365 + years_minus_1 / 4 - years_minus_1 / 100 + years_minus_1 / 400; + for (u32 it = 0; it < months; it++) + { + if (months > it + 1) + { + result += days_in_month[it]; + if (it == 1) + { + result += extra_day_count(years); + } + } + } + result += u64(days - 1); - result = result * u64(24) + u64(hours); - result = result * u64(60) + u64(minutes); - result = result * u64(60) + u64(seconds); - result = result * u64(1000) + u64(milliseconds); - return (result); + result *= 24ul; + result += u64(hours); + result *= 60ul; + result += u64(minutes); + result *= 60ul; + result += u64(seconds); + result *= 1000ul; + result += u64(milliseconds); + return result; } -static void split_time_impl(u64 time, u32& years, u32& months, u32& days, u32& hours, u32& minutes, u32& seconds, - u32& milliseconds) +void split_time(u64 time, u32& years, u32& months, u32& days, u32& hours, u32& minutes, u32& seconds, u32& milliseconds) { - milliseconds = u32(time % 1000); + milliseconds = u32(time % 1000u); time /= 1000; - seconds = u32(time % 60); + seconds = u32(time % 60u); time /= 60; - minutes = u32(time % 60); + minutes = u32(time % 60u); time /= 60; - hours = u32(time % 24); + hours = u32(time % 24u); time /= 24; u64 const p0 = time / (400 * 365 + 100 - 4 + 1); @@ -79,110 +53,24 @@ static void split_time_impl(u64 time, u32& years, u32& months, u32& days, u32& h time -= p1 * (100 * 365 + 25 - 1); u64 const p2 = time / (4 * 365 + 1); time -= p2 * (4 * 365 + 1); - u64 const p3 = _min(u32(time) / 365, 3); + u64 const p3 = std::min(time / 365u, 3ui64); time -= p3 * 365; years = u32(400 * p0 + 100 * p1 + 4 * p2 + p3 + 1); ++time; - u64 const extra_day_count = ((years % 400 == 0) || ((years % 4 == 0) && (years % 100 != 0))) ? 1 : 0; - VERIFY(time - extra_day_count < 366); - months = 1; - if (time > 31) + for (u32 it = 0; it < months; it++) { - ++months; - time -= 31; - if (time > 28 + extra_day_count) + if ((it == 1) && days_in_month[it] + extra_day_count(years) < time) { ++months; - time -= 28 + extra_day_count; - if (time > 31) - { - ++months; - time -= 31; - if (time > 30) - { - ++months; - time -= 30; - if (time > 31) - { - ++months; - time -= 31; - if (time > 30) - { - ++months; - time -= 30; - if (time > 31) - { - ++months; - time -= 31; - if (time > 31) - { - ++months; - time -= 31; - if (time > 30) - { - ++months; - time -= 30; - if (time > 31) - { - ++months; - time -= 31; - if (time > 30) - { - ++months; - time -= 30; - } - } - } - } - } - } - } - } - } + time -= days_in_month[it] + extra_day_count(years); + } + else if (days_in_month[it] < time) + { + ++months; + time -= days_in_month[it]; } } days = u32(time); } - -u64 generate_time(u32 years, u32 months, u32 days, u32 hours, u32 minutes, u32 seconds, u32 milliseconds) -{ - u64 const result = generate_time_impl(years, months, days, hours, minutes, seconds, milliseconds); - -#ifdef DEBUG -# if 0 - { - u64 const milliseconds_in_day = 24*60*60*1000; - u32 l_years, l_months, l_days, l_hours, l_minutes, l_seconds, l_milliseconds; - if (years > 1 || months > 1 || days > 1) - split_time_impl (result - milliseconds_in_day, l_years, l_months, l_days, l_hours, l_minutes, l_seconds, l_milliseconds); - split_time_impl (result, l_years, l_months, l_days, l_hours, l_minutes, l_seconds, l_milliseconds); - split_time_impl (result + milliseconds_in_day, l_years, l_months, l_days, l_hours, l_minutes, l_seconds, l_milliseconds); - split_time_impl (result, l_years, l_months, l_days, l_hours, l_minutes, l_seconds, l_milliseconds); - } -# endif // #if 0 - u32 l_years, l_months, l_days, l_hours, l_minutes, l_seconds, l_milliseconds; - split_time_impl (result, l_years, l_months, l_days, l_hours, l_minutes, l_seconds, l_milliseconds); - u64 const new_result = generate_time_impl(l_years, l_months, l_days, l_hours, l_minutes, l_seconds, l_milliseconds); - VERIFY (result == new_result); - split_time_impl (result, years, months, days, hours, minutes, seconds, milliseconds); - VERIFY (years == l_years); - VERIFY (months == l_months); - VERIFY (days == l_days); - VERIFY (hours == l_hours); - VERIFY (minutes == l_minutes); - VERIFY (seconds == l_seconds); - VERIFY (milliseconds == l_milliseconds); -#endif // #ifdef DEBUG - return (result); -} - -void split_time(u64 time, u32& years, u32& months, u32& days, u32& hours, u32& minutes, u32& seconds, u32& milliseconds) -{ - split_time_impl(time, years, months, days, hours, minutes, seconds, milliseconds); -#ifdef DEBUG - u64 const test_time = generate_time_impl(years, months, days, hours, minutes, seconds, milliseconds); - VERIFY (test_time == time); -#endif // #ifdef DEBUG -} diff --git a/src/xrGame/detail_path_builder.h b/src/xrGame/detail_path_builder.h index f5b354c52f..dd1f27e299 100644 --- a/src/xrGame/detail_path_builder.h +++ b/src/xrGame/detail_path_builder.h @@ -39,11 +39,12 @@ class CDetailPathBuilder void register_to_process() { m_object->m_wait_for_distributed_computation = true; - Device.seqParallel.push_back(fastdelegate::FastDelegate0<>(this, &CDetailPathBuilder::process)); + Device.seqParallel.push_back(xr_make_delegate(this, &CDetailPathBuilder::process)); } void process_impl(bool separate_computing = true) { + PROF_EVENT("CDetailPathBuilder::process_impl"); if (separate_computing) m_object->m_wait_for_distributed_computation = false; @@ -68,7 +69,7 @@ class CDetailPathBuilder m_object->m_wait_for_distributed_computation = false; Device.remove_from_seq_parallel( - fastdelegate::FastDelegate0<>( + xr_make_delegate( this, &CDetailPathBuilder::process ) diff --git a/src/xrGame/doors_actor.cpp b/src/xrGame/doors_actor.cpp index efbb514c12..52149b75fc 100644 --- a/src/xrGame/doors_actor.cpp +++ b/src/xrGame/doors_actor.cpp @@ -35,7 +35,7 @@ static void on_door_destroy(doors_type& doors, door& door) { doors_type::iterator const found = std::find(doors.begin(), doors.end(), &door); if (found != doors.end()) - doors.erase(found); + doors.erase_fast(found); } void actor::on_door_destroy(door& door) @@ -79,7 +79,9 @@ Fvector const& actor::get_position() const bool actor::need_update() const { - return !m_open_doors.empty() && !m_closed_doors.empty(); + // Continue door state maintenance while at least one pending queue exists. + // Using && can leave a single queue "orphaned", preventing initiator release. + return !m_open_doors.empty() || !m_closed_doors.empty(); } class passed_doors_predicate @@ -199,7 +201,7 @@ bool actor::add_new_door( } VERIFY(std::find( processed_doors.begin(), processed_doors.end(), door ) == processed_doors.end()); - locked_doors.erase(i); + locked_doors.erase_fast(i); door->change_state(this, state); if (door->is_blocked(state)) { diff --git a/src/xrGame/doors_door.cpp b/src/xrGame/doors_door.cpp index 6aeedba442..68fd8413a1 100644 --- a/src/xrGame/doors_door.cpp +++ b/src/xrGame/doors_door.cpp @@ -44,12 +44,12 @@ door::door(CPhysicObject* object) : m_open_vector.mul(length); m_closed_vector.mul(length); - m_object.spatial.type |= STYPE_VISIBLEFORAI; + m_object.SpatialComponent->spatial.type |= STYPE_VISIBLEFORAI; } door::~door() { - m_object.spatial.type &= ~STYPE_VISIBLEFORAI; + m_object.SpatialComponent->spatial.type &= ~STYPE_VISIBLEFORAI; if (m_initiators.empty()) return; @@ -221,7 +221,7 @@ void door::change_state(actor* const initiator, door_state const start_state, do // if ( !xr_strcmp( "sim_default_duty_28212", initiator->get_name()) ) { // int i=0; (void)i; // } - m_initiators.erase(found); + m_initiators.erase_fast(found); } if (!m_initiators.empty()) diff --git a/src/xrGame/eatable_item.h b/src/xrGame/eatable_item.h index 7470173919..4c50e6fb2a 100644 --- a/src/xrGame/eatable_item.h +++ b/src/xrGame/eatable_item.h @@ -30,6 +30,7 @@ class CEatableItem : public CInventoryItem virtual ~CEatableItem(); virtual DLL_Pure* _construct(); virtual CEatableItem* cast_eatable_item() { return this; } + virtual CInventoryItem* cast_inventory_item() { return this; } virtual void Load(LPCSTR section); virtual void load(IReader& packet); diff --git a/src/xrGame/eatable_item_object.cpp b/src/xrGame/eatable_item_object.cpp index dc27c96342..b7035e7e9c 100644 --- a/src/xrGame/eatable_item_object.cpp +++ b/src/xrGame/eatable_item_object.cpp @@ -133,10 +133,10 @@ void CEatableItemObject::load(IReader& packet) CEatableItem::load(packet); } -void CEatableItemObject::renderable_Render() +void CEatableItemObject::renderable_Render(IDSGraphManager* DM) { - CPhysicItem::renderable_Render(); - CEatableItem::renderable_Render(); + CPhysicItem::renderable_Render(DM); + CEatableItem::renderable_Render(DM); } void CEatableItemObject::reload(LPCSTR section) diff --git a/src/xrGame/eatable_item_object.h b/src/xrGame/eatable_item_object.h index c21aad12a3..afa8ed2884 100644 --- a/src/xrGame/eatable_item_object.h +++ b/src/xrGame/eatable_item_object.h @@ -24,13 +24,10 @@ class CEatableItemObject : virtual CPhysicsShellHolder* cast_physics_shell_holder() { return this; } virtual CInventoryItem* cast_inventory_item() { return this; } virtual CAttachableItem* cast_attachable_item() { return this; } - virtual CWeapon* cast_weapon() { return 0; } - virtual CFoodItem* cast_food_item() { return 0; } - virtual CMissile* cast_missile() { return 0; } - virtual CFlashlight* cast_flashlight() { return 0; } - virtual CHudItem* cast_hud_item() { return 0; } - virtual CWeaponAmmo* cast_weapon_ammo() { return 0; } - virtual CGameObject* cast_game_object() { return this; }; + virtual CFoodItem* cast_food_item() { return nullptr; } + virtual CFlashlight* cast_flashlight() { return nullptr; } + virtual CGameObject* cast_game_object() { return this; } + virtual CEatableItem* cast_eatable_item() { return this; } public: virtual void Load(LPCSTR section); @@ -49,7 +46,7 @@ class CEatableItemObject : virtual void save(NET_Packet& output_packet); virtual void load(IReader& input_packet); virtual BOOL net_SaveRelevant() { return TRUE; } - virtual void renderable_Render(); + virtual void renderable_Render(IDSGraphManager* DM); virtual void reload(LPCSTR section); virtual void reinit(); virtual void activate_physic_shell(); diff --git a/src/xrGame/enemy_manager.cpp b/src/xrGame/enemy_manager.cpp index d023928f33..a77f7c8cf5 100644 --- a/src/xrGame/enemy_manager.cpp +++ b/src/xrGame/enemy_manager.cpp @@ -75,10 +75,11 @@ bool CEnemyManager::is_useful(const CEntityAlive* entity_alive) const int enemy_manager_useful_cache_time = 200; bool CEnemyManager::useful(const CEntityAlive* entity_alive) const { + PROF_EVENT("CEnemyManager::useful"); if (!entity_alive->g_Alive()) return (false); - if ((entity_alive->spatial.type & STYPE_VISIBLEFORAI) != STYPE_VISIBLEFORAI) + if ((entity_alive->SpatialComponent->spatial.type & STYPE_VISIBLEFORAI) != STYPE_VISIBLEFORAI) return (false); if ((m_object->ID() == entity_alive->ID()) || !m_object->is_relation_enemy(entity_alive)) @@ -243,7 +244,7 @@ void CEnemyManager::remove_links(CObject* object) // we just use the pinter itself, we can just statically cast object OBJECTS::iterator I = std::find(m_objects.begin(), m_objects.end(), (CEntityAlive*)object); if (I != m_objects.end()) - m_objects.erase(I); + m_objects.erase_fast(I); if (m_last_enemy == object) m_last_enemy = 0; diff --git a/src/xrGame/entity_alive.cpp b/src/xrGame/entity_alive.cpp index 41815981d5..1f066ffb42 100644 --- a/src/xrGame/entity_alive.cpp +++ b/src/xrGame/entity_alive.cpp @@ -210,6 +210,7 @@ void CEntityAlive::reload(LPCSTR section) void CEntityAlive::shedule_Update(u32 dt) { + PROF_EVENT(); inherited::shedule_Update(dt); //condition update with the game time pass @@ -336,8 +337,7 @@ void CEntityAlive::Die(CObject* who) } // disable react to sound - ISpatial* self = smart_cast(this); - if (self) self->spatial.type &= ~STYPE_REACTTOSOUND; + SpatialComponent->spatial.type &= ~STYPE_REACTTOSOUND; if (character_physics_support()) character_physics_support()->in_Die(); } @@ -410,47 +410,51 @@ void CEntityAlive::BloodyWallmarks(float P, const Fvector& dir, s16 element, wallmark_size, &**m_pBloodMarksVector); } -void CEntityAlive::PlaceBloodWallmark(const Fvector& dir, const Fvector& start_pos, - float trace_dist, float wallmark_size, - IWallMarkArray* pwallmarks_vector) +extern BOOL r_blood_decals_on_objects; +void CEntityAlive::PlaceBloodWallmark(const Fvector& dir, const Fvector& start_pos, float trace_dist, float wallmark_size, IWallMarkArray* pwallmarks_vector) { collide::rq_result result; - BOOL reach_wall = - Level().ObjectSpace.RayPick( - start_pos, - dir, - trace_dist, - collide::rqtBoth, - result, - this - ) - && - !result.O; + bool bSurfaceReached = Level().ObjectSpace.RayPick(start_pos, dir, trace_dist, collide::rqtBoth, result, r_blood_decals_on_objects ? nullptr : this); + if (!r_blood_decals_on_objects) + bSurfaceReached = bSurfaceReached && !result.O; - //если кровь долетела до статического объекта - if (reach_wall) + if (!bSurfaceReached) + return; + + // Calculate hit pos + Fvector end_point; + end_point.set(0, 0, 0); + end_point.mad(start_pos, dir, result.range); + + if (r_blood_decals_on_objects && result.O) { - CDB::TRI* pTri = Level().ObjectSpace.GetStaticTris() + result.element; - SGameMtl* pMaterial = GMLib.GetMaterialByIdx(pTri->material); + // Dynamic object + IKinematics* const pK = smart_cast(result.O->Visual()); + if (!pK) + return; + + CBoneData const& bone_data = pK->LL_GetData((u16)result.element); + SGameMtl* pMaterial = GMLib.GetMaterialByIdx(bone_data.game_mtl_idx); if (pMaterial->Flags.is(SGameMtl::flBloodmark)) - { - //вычислить нормаль к пораженной поверхности - Fvector* pVerts = Level().ObjectSpace.GetStaticVerts(); + ::Render->add_SkeletonWallmark(&result.O->renderable.xform, pK, pwallmarks_vector, end_point, dir, wallmark_size); + } - //вычислить точку попадания - Fvector end_point; - end_point.set(0, 0, 0); - end_point.mad(start_pos, dir, result.range); + //если кровь долетела до статического объекта + CDB::TRI* pTri = Level().ObjectSpace.GetStaticTris() + result.element; + SGameMtl* pMaterial = GMLib.GetMaterialByIdx(pTri->material); + if (pMaterial->Flags.is(SGameMtl::flBloodmark)) + { + //вычислить нормаль к пораженной поверхности + Fvector* pVerts = Level().ObjectSpace.GetStaticVerts(); - //ref_shader wallmarkShader = wallmarks_vector[::Random.randI(wallmarks_vector.size())]; - VERIFY(!pwallmarks_vector->empty()); - { - //добавить отметку на материале - //::Render->add_StaticWallmark(wallmarkShader, end_point, wallmark_size, pTri, pVerts); - ::Render->add_StaticWallmark(pwallmarks_vector, end_point, wallmark_size, pTri, pVerts); - } + //ref_shader wallmarkShader = wallmarks_vector[::Random.randI(wallmarks_vector.size())]; + VERIFY(!pwallmarks_vector->empty()); + { + //добавить отметку на материале + //::Render->add_StaticWallmark(wallmarkShader, end_point, wallmark_size, pTri, pVerts); + ::Render->add_StaticWallmark(pwallmarks_vector, end_point, wallmark_size, pTri, pVerts); } } } @@ -797,8 +801,8 @@ void CEntityAlive::OnChangeVisual() void CEntityAlive::fill_hit_bone_surface_areas() const { + xrSRWLockGuard guard(&m_hit_bone_lock, false); VERIFY(!m_hit_bone_surface_areas_actual); - m_hit_bone_surface_areas_actual = true; IKinematics* const kinematics = smart_cast(Visual()); VERIFY(kinematics); @@ -841,6 +845,7 @@ void CEntityAlive::fill_hit_bone_surface_areas() const } std::sort(m_hit_bone_surface_areas.begin(), m_hit_bone_surface_areas.end(), sort_surface_area_predicate()); + m_hit_bone_surface_areas_actual = true; } BOOL g_ai_use_old_vision = 0; @@ -856,10 +861,11 @@ Fvector CEntityAlive::get_new_local_point_on_mesh(u16& bone_id) const if (!kinematics->LL_BoneCount()) return inherited::get_new_local_point_on_mesh(bone_id); - + if (!m_hit_bone_surface_areas_actual) fill_hit_bone_surface_areas(); + xrSRWLockGuard guard(&m_hit_bone_lock, true); if (m_hit_bone_surface_areas.empty()) return inherited::get_new_local_point_on_mesh(bone_id); @@ -983,8 +989,7 @@ Fvector CEntityAlive::get_last_local_point_on_mesh(Fvector const& last_point, u1 IKinematics* const kinematics = smart_cast(Visual()); VERIFY(kinematics); - Fmatrix transform; - kinematics->Bone_GetAnimPos(transform, bone_id, u8(-1), false); + Fmatrix transform = kinematics->LL_GetTransform(bone_id); Fvector result; transform.transform_tiny(result, last_point); diff --git a/src/xrGame/entity_alive.h b/src/xrGame/entity_alive.h index bf7072c94c..d10ce5766f 100644 --- a/src/xrGame/entity_alive.h +++ b/src/xrGame/entity_alive.h @@ -14,6 +14,9 @@ class CCharacterPhysicsSupport; class CMaterialManager; class CVisualMemoryManager; class CBlend; +class CActor; +class CAI_Stalker; +class CInventoryOwner; class CEntityAlive : public CEntity { @@ -22,6 +25,11 @@ class CEntityAlive : public CEntity u32 m_used_time; public: virtual CEntityAlive* cast_entity_alive() { return this; } + virtual CActor* cast_actor() { return nullptr; } + virtual CAI_Stalker* cast_stalker() { return nullptr; } + virtual CEntity* cast_entity() { return this; } + virtual CInventoryOwner* cast_inventory_owner() { return nullptr; } + virtual CGameObject* cast_game_object() { return this; } public: bool m_bMobility; @@ -211,9 +219,10 @@ class CEntityAlive : public CEntity typedef xr_vector> hit_bone_surface_areas_type; private: + mutable xrSRWLock m_hit_bone_lock; mutable hit_bone_surface_areas_type m_hit_bone_surface_areas; mutable CRandom m_hit_bones_random; - mutable bool m_hit_bone_surface_areas_actual; + mutable xr_atomic_bool m_hit_bone_surface_areas_actual; }; #include "entity_alive_inline.h" diff --git a/src/xrGame/event_conditions_collection.h b/src/xrGame/event_conditions_collection.h index 3330d7a5f4..a6d8efd0c8 100644 --- a/src/xrGame/event_conditions_collection.h +++ b/src/xrGame/event_conditions_collection.h @@ -67,7 +67,7 @@ namespace award_system event_condition_t* m_root_condition; }; //event_root_condition_t - typedef fastdelegate::FastDelegate event_action_delegate_t; + typedef xr_delegate event_action_delegate_t; class event_conditions_collection { diff --git a/src/xrGame/filetransfer_common.h b/src/xrGame/filetransfer_common.h index 58f92f85dc..59aea00544 100644 --- a/src/xrGame/filetransfer_common.h +++ b/src/xrGame/filetransfer_common.h @@ -32,8 +32,8 @@ namespace file_transfer receive_rejected = 0x02 //this command send by dest site, if he doesn't want file.. }; - typedef fastdelegate::FastDelegate3 sending_state_callback_t; - typedef fastdelegate::FastDelegate3 receiving_state_callback_t; + typedef xr_delegate sending_state_callback_t; + typedef xr_delegate receiving_state_callback_t; typedef std::pair mutable_buffer_t; typedef std::pair const_buffer_t; diff --git a/src/xrGame/flare.cpp b/src/xrGame/flare.cpp index b39bc592f3..7f1ff4c4ab 100644 --- a/src/xrGame/flare.cpp +++ b/src/xrGame/flare.cpp @@ -112,7 +112,7 @@ void CFlare::SwitchOn() light_render->set_active(true); - m_pFlareParticles = CParticlesObject::Create(pSettings->r_string(cNameSect(), "working_particles"), FALSE); + m_pFlareParticles = Particles::Details::Create(pSettings->r_string(cNameSect(), "working_particles"), FALSE); m_pFlareParticles->Play(true); } @@ -120,7 +120,7 @@ void CFlare::SwitchOff() { SetCondition(0.0f); light_render.destroy(); - CParticlesObject::Destroy(m_pFlareParticles); + Particles::Details::Destroy(m_pFlareParticles); processing_deactivate(); } diff --git a/src/xrGame/flare.h b/src/xrGame/flare.h index 322661676c..05443ed861 100644 --- a/src/xrGame/flare.h +++ b/src/xrGame/flare.h @@ -14,7 +14,7 @@ class CFlare : public CHudItemObject CLAItem* light_lanim; ref_light light_render; - CParticlesObject* m_pFlareParticles; + intrusive_ptr m_pFlareParticles; float m_work_time_sec; void SwitchOn(); void SwitchOff(); @@ -34,4 +34,6 @@ class CFlare : public CHudItemObject void ActivateFlare(); void DropFlare(); bool IsFlareActive(); + + virtual CFlare* cast_flare() { return this; } }; diff --git a/src/xrGame/game_cl_artefacthunt.cpp b/src/xrGame/game_cl_artefacthunt.cpp index b3dff211fa..5b4a7f9e0f 100644 --- a/src/xrGame/game_cl_artefacthunt.cpp +++ b/src/xrGame/game_cl_artefacthunt.cpp @@ -103,7 +103,7 @@ void game_cl_ArtefactHunt::Init() transform.identity(); transform.setXYZ(R.A); transform.translate_over(R.P); - CParticlesObject* pStaticParticles = CParticlesObject::Create(pSettings->r_string("artefacthunt_gamedata", ParticleStr),FALSE,false); + CParticlesObject* pStaticParticles = Particles::Details::Create(pSettings->r_string("artefacthunt_gamedata", ParticleStr),FALSE,false).get(); pStaticParticles->UpdateParent (transform,zero_vel); pStaticParticles->Play (); Level().m_StaticParticles.push_back (pStaticParticles); diff --git a/src/xrGame/game_cl_deathmatch.cpp b/src/xrGame/game_cl_deathmatch.cpp index 0d3566869f..fdc6c73c7a 100644 --- a/src/xrGame/game_cl_deathmatch.cpp +++ b/src/xrGame/game_cl_deathmatch.cpp @@ -998,9 +998,7 @@ void game_cl_Deathmatch::PlayParticleEffect(LPCSTR EffName, Fvector& pos) // CParticlesPlayer::MakeXFORM(pObj,0,Fvector().set(0.f,1.f,0.f),Fvector().set(0.f,0.f,0.f),pos); // установить particles - CParticlesObject* ps = NULL; - - ps = CParticlesObject::Create(EffName,TRUE); + intrusive_ptr ps = Particles::Details::Create(EffName,TRUE); ps->UpdateParent(M, Fvector().set(0.f, 0.f, 0.f)); GamePersistent().ps_needtoplay.push_back(ps); diff --git a/src/xrGame/game_cl_mp.h b/src/xrGame/game_cl_mp.h index 7222e34eaf..e20a96fc31 100644 --- a/src/xrGame/game_cl_mp.h +++ b/src/xrGame/game_cl_mp.h @@ -8,7 +8,7 @@ #include "configs_dumper.h" #include "configs_dump_verifyer.h" #include "screenshot_server.h" -#include +#include "../xrCore/xr_delegate.h" class CUIWindow; class CUISpeechMenu; @@ -323,7 +323,7 @@ class game_cl_mp : public game_cl_GameState void AddSoundMessage(LPCSTR sound_name, u32 const sound_priority, u32 const soundID); void PlaySndMessage(u32 ID); - typedef fastdelegate::FastDelegate player_info_reply_cb_t; + typedef xr_delegate player_info_reply_cb_t; bool RequestPlayersInfo(player_info_reply_cb_t const pinfo_repl_cb); private: u8* buffer_for_compress; diff --git a/src/xrGame/game_sv_base.cpp b/src/xrGame/game_sv_base.cpp index f4cb9ba13c..669ff341e0 100644 --- a/src/xrGame/game_sv_base.cpp +++ b/src/xrGame/game_sv_base.cpp @@ -316,9 +316,9 @@ void game_sv_GameState::net_Export_State(NET_Packet& P, ClientID to) game_PlayerState* tmp_ps = tmp_client->ps; player_exporter tmp_functor(to, tmp_ps, &P); - fastdelegate::FastDelegate1 pcounter; + xr_delegate pcounter; pcounter.bind(&tmp_functor, &player_exporter::count_players); - fastdelegate::FastDelegate1 exporter; + xr_delegate exporter; exporter.bind(&tmp_functor, &player_exporter::export_players); m_server->ForEachClientDo(pcounter); diff --git a/src/xrGame/game_sv_capture_the_artefact.cpp b/src/xrGame/game_sv_capture_the_artefact.cpp index 4b3875c7a3..a4af03b081 100644 --- a/src/xrGame/game_sv_capture_the_artefact.cpp +++ b/src/xrGame/game_sv_capture_the_artefact.cpp @@ -2288,7 +2288,7 @@ void game_sv_CaptureTheArtefact::ActorDeliverArtefactOnBase(CSE_ActorMP* actor, void game_sv_CaptureTheArtefact::StartNewRound() { - fastdelegate::FastDelegate1 tmp_functor; + xr_delegate tmp_functor; tmp_functor.bind(this, &game_sv_CaptureTheArtefact::PrepareClientForNewRound); m_server->ForEachClientDoSender(tmp_functor); MoveLifeActors(); diff --git a/src/xrGame/game_sv_deathmatch.cpp b/src/xrGame/game_sv_deathmatch.cpp index 3720c9d24e..2b7411fdc0 100644 --- a/src/xrGame/game_sv_deathmatch.cpp +++ b/src/xrGame/game_sv_deathmatch.cpp @@ -166,7 +166,7 @@ void game_sv_Deathmatch::OnRoundStart() m_dwLastRPoints[i] = u32(-1); } //------------------------------------- - fastdelegate::FastDelegate1 tmp_delegate; + xr_delegate tmp_delegate; tmp_delegate.bind(this, &game_sv_Deathmatch::RespawnPlayerAsSpectator); m_server->ForEachClientDoSender(tmp_delegate); m_item_respawner.respawn_all_items(); diff --git a/src/xrGame/game_sv_event_queue.h b/src/xrGame/game_sv_event_queue.h index 73c0c18402..e64d2eca64 100644 --- a/src/xrGame/game_sv_event_queue.h +++ b/src/xrGame/game_sv_event_queue.h @@ -15,7 +15,7 @@ class GameEventQueue xr_vector unused; xr_set m_blocked_clients; public: - typedef fastdelegate::FastDelegate1 event_predicate; + typedef xr_delegate event_predicate; GameEventQueue(); ~GameEventQueue(); diff --git a/src/xrGame/game_sv_mp.cpp b/src/xrGame/game_sv_mp.cpp index ed5217eb17..b3419bc592 100644 --- a/src/xrGame/game_sv_mp.cpp +++ b/src/xrGame/game_sv_mp.cpp @@ -463,7 +463,6 @@ void game_sv_mp::ReconnectPlayer(ClientID const& clientID) bool g_bConsoleCommandsCreated = false; extern float g_fTimeFactor; -#define SAVE_SCREENSHOTS_KEY "-savescreenshots" void game_sv_mp::Create(shared_str& options) { @@ -480,7 +479,7 @@ void game_sv_mp::Create(shared_str& options) //------------------------------------------------------------------ Set_RankUp_Allowed(false); m_cdkey_ban_list.load(); - if (strstr(Core.Params, SAVE_SCREENSHOTS_KEY)) + if (Core.ParamsData.test(ECoreParams::savescreenshots)) { g_sv_mp_save_proxy_screenshots = TRUE; } diff --git a/src/xrGame/game_sv_single.cpp b/src/xrGame/game_sv_single.cpp index e61f971abc..5239657f05 100644 --- a/src/xrGame/game_sv_single.cpp +++ b/src/xrGame/game_sv_single.cpp @@ -347,6 +347,7 @@ void game_sv_Single::on_death(CSE_Abstract* e_dest, CSE_Abstract* e_src) void game_sv_Single::restart_simulator(LPCSTR saved_game_name) { + PROF_EVENT("restart_simulator"); shared_str& options = *alife().server_command_line(); delete_data(m_alife_simulator); diff --git a/src/xrGame/gsc_dsigned_ltx.h b/src/xrGame/gsc_dsigned_ltx.h index d82f2c400e..90e0e10925 100644 --- a/src/xrGame/gsc_dsigned_ltx.h +++ b/src/xrGame/gsc_dsigned_ltx.h @@ -1,7 +1,7 @@ #ifndef GSC_DSINGNED_LTX_INCLUDED #define GSC_DSINGNED_LTX_INCLUDED -#include +#include "../xrCore/xr_delegate.h" #include "xr_dsa_signer.h" #include "xr_dsa_verifyer.h" diff --git a/src/xrGame/helicopter.h b/src/xrGame/helicopter.h index bb24a1a305..0295f1649e 100644 --- a/src/xrGame/helicopter.h +++ b/src/xrGame/helicopter.h @@ -306,13 +306,10 @@ class CHelicopter : public CEntity, return (inherited::net_SaveRelevant() && BOOL(PPhysicsShell() != NULL)) || m_exploded; }; - virtual void renderable_Render() { inherited::renderable_Render(); }; + virtual void renderable_Render(IDSGraphManager* DM) { inherited::renderable_Render(DM); }; virtual BOOL renderable_ShadowGenerate() { return FALSE; } virtual BOOL renderable_ShadowReceive() { return TRUE; } - // demonized: check if object is eligible for bone calc optimization - bool canOptimizeCalculateBones() override { return false; }; - virtual void OnEvent(NET_Packet& P, u16 type); virtual void UpdateCL(); virtual void shedule_Update(u32 time_delta); @@ -329,6 +326,7 @@ class CHelicopter : public CEntity, virtual CGameObject* cast_game_object() { return this; } virtual CExplosive* cast_explosive() { return this; } + virtual CHelicopter* cast_helicopter() { return this; } virtual CPHSkeleton* PHSkeleton() { return this; } public: diff --git a/src/xrGame/hit_memory_manager.cpp b/src/xrGame/hit_memory_manager.cpp index 3c6d6f7d96..211b795ee4 100644 --- a/src/xrGame/hit_memory_manager.cpp +++ b/src/xrGame/hit_memory_manager.cpp @@ -94,6 +94,7 @@ void CHitMemoryManager::reload(LPCSTR section) void CHitMemoryManager::add(float amount, const Fvector& vLocalDir, const CObject* who, s16 element) { + PROF_EVENT("HitMemory::add"); #ifndef MASTER_GOLD if (who && smart_cast(who) && psAI_Flags.test(aiIgnoreActor)) return; @@ -254,10 +255,12 @@ void CHitMemoryManager::remove_links(CObject* object) m_last_hit_time = 0; } - VERIFY(m_hits); - HITS::iterator I = std::find_if(m_hits->begin(), m_hits->end(), CHitObjectPredicate(object)); - if (I != m_hits->end()) - m_hits->erase(I); + if (m_hits) + { + HITS::iterator I = std::find_if(m_hits->begin(), m_hits->end(), CHitObjectPredicate(object)); + if (I != m_hits->end()) + m_hits->erase(I); + } #ifdef USE_SELECTED_HIT if (!m_selected_hit) diff --git a/src/xrGame/holder_custom.h b/src/xrGame/holder_custom.h index f1dc1d11a8..66ec9e1df9 100644 --- a/src/xrGame/holder_custom.h +++ b/src/xrGame/holder_custom.h @@ -9,6 +9,7 @@ class CGameObject; class CCameraBase; class CActor; class CScriptGameObject; +class CWeaponStatMgun; class CHolderCustom { @@ -34,7 +35,12 @@ class CHolderCustom virtual void UpdateEx(float fov) { }; //called by owner + virtual CHolderCustom* cast_holder_custom() { return this; } + virtual CCar* cast_car() { return nullptr; } + virtual CGameObject* cast_game_object() { return nullptr; } + virtual CWeaponStatMgun* cast_weapon_stat_mgun() { return nullptr; } + bool Engaged() { return m_owner != NULL; } virtual void OnMouseMove(int x, int y) = 0; virtual void OnKeyboardPress(int dik) = 0; diff --git a/src/xrGame/hud_item_object.cpp b/src/xrGame/hud_item_object.cpp index bf64789322..cb901c5e46 100644 --- a/src/xrGame/hud_item_object.cpp +++ b/src/xrGame/hud_item_object.cpp @@ -105,12 +105,12 @@ void CHudItemObject::UpdateCL() CHudItem::UpdateCL(); } -void CHudItemObject::renderable_Render() +void CHudItemObject::renderable_Render(IDSGraphManager* DM) { - CHudItem::renderable_Render(); + CHudItem::renderable_Render(DM); } -void CHudItemObject::on_renderable_Render() +void CHudItemObject::on_renderable_Render(IDSGraphManager* DM) { - CInventoryItemObject::renderable_Render(); + CInventoryItemObject::renderable_Render(DM); } diff --git a/src/xrGame/hud_item_object.h b/src/xrGame/hud_item_object.h index 374571a72b..70f3d7c5c0 100644 --- a/src/xrGame/hud_item_object.h +++ b/src/xrGame/hud_item_object.h @@ -3,6 +3,21 @@ #include "inventory_item_object.h" #include "huditem.h" +class CCustomDetector; +class CWeaponBinoculars; +class CWeaponKnife; +class CWeaponMagazined; +class CWeaponMagazinedWGrenade; +class CWeaponBM16; +class CWeapon; +class CWeaponRPG7; +class CWeaponRG6; +class CMissile; +class CBolt; +class CGrenade; +class CPhysicItem; +class CPhysicsShellHolder; + class CHudItemObject : public CInventoryItemObject, public CHudItem @@ -15,7 +30,22 @@ class CHudItemObject : virtual DLL_Pure* _construct(); public: + virtual CInventoryItem* cast_inventory_item() { return this; } + virtual CCustomDetector* cast_custom_detector() { return nullptr; } + virtual CWeaponBinoculars* cast_weapon_binoculars() { return nullptr; } + virtual CWeaponKnife* cast_weapon_knife() { return nullptr; } + virtual CWeaponMagazined* cast_weapon_magazined() { return nullptr; } + virtual CWeaponMagazinedWGrenade* cast_weapon_magazined_w_grenade() { return nullptr; } + virtual CWeaponBM16* cast_weapon_bm16() { return nullptr; } + virtual CWeapon* cast_weapon() { return nullptr; } + virtual CWeaponRPG7* cast_weapon_rpg7() { return nullptr; } + virtual CWeaponRG6* cast_weapon_rg6() { return nullptr; } virtual CHudItem* cast_hud_item() { return this; } + virtual CGrenade* cast_grenade() { return nullptr; } + virtual CMissile* cast_missile() { return nullptr; } + virtual CBolt* cast_bolt() { return nullptr; } + virtual CPhysicsShellHolder* cast_physics_shell_holder() { return this; } + virtual CPhysicItem* cast_physics_item() { return this; } public: virtual void Load(LPCSTR section); @@ -32,12 +62,12 @@ class CHudItemObject : virtual bool ActivateItem(); virtual void DeactivateItem(); virtual void UpdateCL(); - virtual void renderable_Render(); - virtual void on_renderable_Render(); + virtual void renderable_Render(IDSGraphManager* DM); + virtual void on_renderable_Render(IDSGraphManager* DM); virtual void OnMoveToRuck(const SInvItemPlace& prev); virtual bool use_parent_ai_locations() const { - return CInventoryItemObject::use_parent_ai_locations() && (Device.dwFrame != dwXF_Frame); + return CInventoryItemObject::use_parent_ai_locations()&&IsHidden(); } }; diff --git a/src/xrGame/inventory_item.cpp b/src/xrGame/inventory_item.cpp index 2897dbeb4f..8f686ea4f2 100644 --- a/src/xrGame/inventory_item.cpp +++ b/src/xrGame/inventory_item.cpp @@ -95,8 +95,10 @@ void CInventoryItem::Load(LPCSTR section) { CHitImmunity::LoadImmunities(pSettings->r_string(section, "immunities_sect"), pSettings); - ISpatial* self = smart_cast(this); - if (self) self->spatial.type |= STYPE_VISIBLEFORAI; + if (cast_game_object()) + { + cast_game_object()->SpatialComponent->spatial.type |= STYPE_VISIBLEFORAI; + } m_section_id._set(section); m_name = CStringTable().translate(pSettings->r_string(section, "inv_name")); @@ -232,6 +234,7 @@ extern Flags32 dbg_net_Draw_Flags; void CInventoryItem::UpdateCL() { + PROF_EVENT("CInventoryItem::UpdateCL") #ifdef DEBUG if(bDebug){ if (dbg_net_Draw_Flags.test(dbg_draw_invitem) ) diff --git a/src/xrGame/inventory_item.h b/src/xrGame/inventory_item.h index 0a49b60b6b..1658b5a008 100644 --- a/src/xrGame/inventory_item.h +++ b/src/xrGame/inventory_item.h @@ -41,6 +41,27 @@ class CFlashlight; class CInventoryOwner; +class CArtefact; +class CCustomOutfit; +class CHelmet; +class CCustomDetector; +class CCustomDevice; +class CWeaponMagazined; +class CWeaponMagazinedWGrenade; +class CWeaponBinoculars; +class CWeaponKnife; +class CWeaponBM16; +class CWeaponRPG7; +class CWeaponRG6; +class CTorch; +class CBolt; +class CPda; +class CGrenade; +class CSilencer; +class CScope; +class CGrenadeLauncher; +class CFlare; + struct SHit; class CSE_ALifeInventoryItem; @@ -299,15 +320,37 @@ class CInventoryItem : public: virtual CInventoryItem* cast_inventory_item() { return this; } virtual CAttachableItem* cast_attachable_item() { return this; } - virtual CPhysicsShellHolder* cast_physics_shell_holder() { return 0; } - virtual CEatableItem* cast_eatable_item() { return 0; } - virtual CWeapon* cast_weapon() { return 0; } - virtual CFoodItem* cast_food_item() { return 0; } - virtual CMissile* cast_missile() { return 0; } - virtual CFlashlight* cast_flashlight() { return 0; } - virtual CHudItem* cast_hud_item() { return 0; } - virtual CWeaponAmmo* cast_weapon_ammo() { return 0; } - virtual CGameObject* cast_game_object() { return 0; } + virtual CFlashlight* cast_flashlight() { return nullptr; } + virtual CPhysicsShellHolder* cast_physics_shell_holder() { return nullptr; } + virtual CEatableItem* cast_eatable_item() { return nullptr; } + virtual CWeapon* cast_weapon() { return nullptr; } + virtual CFoodItem* cast_food_item() { return nullptr; } + virtual CMissile* cast_missile() { return nullptr; } + virtual CHudItem* cast_hud_item() { return nullptr; } + virtual CWeaponAmmo* cast_weapon_ammo() { return nullptr; } + virtual CGameObject* cast_game_object() { return nullptr; } + virtual CArtefact* cast_artefact() { return nullptr; } + virtual CCustomOutfit* cast_outfit() { return nullptr; } + virtual CHelmet* cast_helmet() { return nullptr; } + virtual CCustomDetector* cast_custom_detector() { return nullptr; } + virtual CCustomDevice* cast_custom_device() { return nullptr; } + virtual CWeaponBinoculars* cast_weapon_binoculars() { return nullptr; } + virtual CWeaponKnife* cast_weapon_knife() { return nullptr; } + virtual CWeaponMagazined* cast_weapon_magazined() { return nullptr; } + virtual CWeaponMagazinedWGrenade* cast_weapon_magazined_w_grenade() { return nullptr; } + virtual CWeaponBM16* cast_weapon_bm16() { return nullptr; } + virtual CTorch* cast_torch() { return nullptr; } + virtual CWeaponRPG7* cast_weapon_rpg7() { return nullptr; } + virtual CWeaponRG6* cast_weapon_rg6() { return nullptr; } + virtual CBolt* cast_bolt() { return nullptr; } + virtual CPda* cast_pda() { return nullptr; } + virtual CGrenade* cast_grenade() { return nullptr; } + virtual CSilencer* cast_addon_silencer() { return nullptr; } + virtual CScope* cast_addon_scope() { return nullptr; } + virtual CGrenadeLauncher* cast_addon_grenade_launcher() { return nullptr; } + virtual CPhysicItem* cast_physics_item() { return nullptr; } + virtual CBackpack* cast_backpack() { return nullptr; } + virtual CFlare* cast_flare() { return nullptr; } ////////// upgrades ////////////////////////////////////////////////// public: diff --git a/src/xrGame/inventory_item_object.cpp b/src/xrGame/inventory_item_object.cpp index dc947e34bb..c8cd76c6ab 100644 --- a/src/xrGame/inventory_item_object.cpp +++ b/src/xrGame/inventory_item_object.cpp @@ -128,10 +128,10 @@ void CInventoryItemObject::load(IReader& packet) CInventoryItem::load(packet); } -void CInventoryItemObject::renderable_Render() +void CInventoryItemObject::renderable_Render(IDSGraphManager* DM) { - CPhysicItem::renderable_Render(); - CInventoryItem::renderable_Render(); + CPhysicItem::renderable_Render (DM); + CInventoryItem::renderable_Render (DM); } void CInventoryItemObject::reload(LPCSTR section) diff --git a/src/xrGame/inventory_item_object.h b/src/xrGame/inventory_item_object.h index 85b880ab60..f4006b4abb 100644 --- a/src/xrGame/inventory_item_object.h +++ b/src/xrGame/inventory_item_object.h @@ -11,6 +11,25 @@ #include "physic_item.h" #include "inventory_item.h" +class CCustomDetector; +class CWeaponBinoculars; +class CWeaponKnife; +class CWeaponMagazined; +class CWeaponMagazinedWGrenade; +class CWeaponBM16; +class CWeapon; +class CWeaponRPG7; +class CWeaponRG6; +class CHudItem; +class CTorch; +class CBolt; +class CPda; +class CGrenade; +class CMissile; +class CSilencer; +class CScope; +class CGrenadeLauncher; + class CInventoryItemObject : public CInventoryItem, public CPhysicItem @@ -24,13 +43,27 @@ class CInventoryItemObject : virtual CPhysicsShellHolder* cast_physics_shell_holder() { return this; } virtual CInventoryItem* cast_inventory_item() { return this; } virtual CAttachableItem* cast_attachable_item() { return this; } - virtual CWeapon* cast_weapon() { return 0; } - virtual CFoodItem* cast_food_item() { return 0; } - virtual CMissile* cast_missile() { return 0; } - virtual CFlashlight* cast_flashlight() { return 0; } - virtual CHudItem* cast_hud_item() { return 0; } - virtual CWeaponAmmo* cast_weapon_ammo() { return 0; } - virtual CGameObject* cast_game_object() { return this; }; + virtual CFlashlight* cast_flashlight() { return nullptr; } + virtual CHudItem* cast_hud_item() { return nullptr; } + virtual CGameObject* cast_game_object() { return this; } + virtual CCustomDetector* cast_custom_detector() { return nullptr; } + virtual CWeaponBinoculars* cast_weapon_binoculars() { return nullptr; } + virtual CWeaponKnife* cast_weapon_knife() { return nullptr; } + virtual CWeaponMagazined* cast_weapon_magazined() { return nullptr; } + virtual CWeaponMagazinedWGrenade* cast_weapon_magazined_w_grenade() { return nullptr; } + virtual CWeaponBM16* cast_weapon_bm16() { return nullptr; } + virtual CWeapon* cast_weapon() { return nullptr; } + virtual CTorch* cast_torch() { return nullptr; } + virtual CWeaponRPG7* cast_weapon_rpg7() { return nullptr; } + virtual CWeaponRG6* cast_weapon_rg6() { return nullptr; } + virtual CBolt* cast_bolt() { return nullptr; } + virtual CPda* cast_pda() { return nullptr; } + virtual CGrenade* cast_grenade() { return nullptr; } + virtual CMissile* cast_missile() { return nullptr; } + virtual CSilencer* cast_addon_silencer() { return nullptr; } + virtual CScope* cast_addon_scope() { return nullptr; } + virtual CGrenadeLauncher* cast_addon_grenade_launcher() { return nullptr; } + virtual CPhysicItem* cast_physics_item() { return this; } public: virtual void Load(LPCSTR section); @@ -51,7 +84,7 @@ class CInventoryItemObject : virtual void save(NET_Packet& output_packet); virtual void load(IReader& input_packet); virtual BOOL net_SaveRelevant() { return TRUE; } - virtual void renderable_Render(); + virtual void renderable_Render(IDSGraphManager* DM); virtual void reload(LPCSTR section); virtual void reinit(); virtual void activate_physic_shell(); diff --git a/src/xrGame/inventory_upgrade_manager.cpp b/src/xrGame/inventory_upgrade_manager.cpp index 97e448b6e2..a7f689a612 100644 --- a/src/xrGame/inventory_upgrade_manager.cpp +++ b/src/xrGame/inventory_upgrade_manager.cpp @@ -366,6 +366,10 @@ void Manager::test_all_upgrades( CInventoryItem& item ) bool Manager::upgrade_install(CInventoryItem& item, shared_str const& upgrade_id, bool loading) { Upgrade* upgrade = upgrade_verify(item.m_section_id, upgrade_id); + if (upgrade == nullptr) + { + return false; + } UpgradeStateResult res = upgrade->can_install(item, loading); if (res == result_ok) diff --git a/src/xrGame/item_manager.cpp b/src/xrGame/item_manager.cpp index 78700d55af..11d8d2d4ef 100644 --- a/src/xrGame/item_manager.cpp +++ b/src/xrGame/item_manager.cpp @@ -32,7 +32,8 @@ bool CItemManager::is_useful(const CGameObject* object) const { return (m_object->useful(this, object)); } - +#include "memory_manager.h" +#include "enemy_manager.h" bool CItemManager::useful(const CGameObject* object) const { if (object->getDestroy()) @@ -55,23 +56,24 @@ bool CItemManager::useful(const CGameObject* object) const return false; auto gameObject = const_cast(object); - if (gameObject == nullptr && gameObject->UsedAI_Locations()) + if (!gameObject->UsedAI_Locations()) return false; - if (!m_object->movement().restrictions().accessible(object->Position())) - return (false); + const CInventoryItem* inventory_item = gameObject ? gameObject->cast_inventory_item() : NULL; + if (!inventory_item || !inventory_item->useful_for_NPC()) + return (false); - if (!m_object->movement().restrictions().accessible(object->ai_location().level_vertex_id())) - return (false); + if (m_stalker && !m_stalker->can_take(inventory_item)) + return (false); - const CInventoryItem* inventory_item = smart_cast(object); - if (inventory_item && !inventory_item->useful_for_NPC()) - return (false); + if (m_stalker && !m_stalker->memory().enemy().selected()) + { + if (!m_object->movement().restrictions().accessible(object->Position())) + return (false); - if (m_stalker && (!m_stalker->can_take(inventory_item) || !m_stalker - ->movement().restrictions().accessible( - inventory_item->object().Position()))) - return (false); + if (!m_object->movement().restrictions().accessible(object->ai_location().level_vertex_id())) + return (false); + } if (!ai().get_level_graph()) return (false); diff --git a/src/xrGame/level_changer.cpp b/src/xrGame/level_changer.cpp index 80626e93fb..ef837625b1 100644 --- a/src/xrGame/level_changer.cpp +++ b/src/xrGame/level_changer.cpp @@ -157,7 +157,7 @@ bool CLevelChanger::get_reject_pos(Fvector& p, Fvector& r) if (m_ini_file && m_ini_file->section_exist("pt_move_if_reject")) { LPCSTR p_name = m_ini_file->r_string("pt_move_if_reject", "path"); - const CPatrolPath* patrol_path = ai().patrol_paths().path(p_name); + const CPatrolPath* patrol_path = ai().patrol_paths().safe_path(p_name, false, true); VERIFY(patrol_path); const CPatrolPoint* pt; diff --git a/src/xrGame/level_changer.h b/src/xrGame/level_changer.h index 65283bda03..e0fc1e0e47 100644 --- a/src/xrGame/level_changer.h +++ b/src/xrGame/level_changer.h @@ -48,4 +48,7 @@ class CLevelChanger : public CGameObject, public Feel::Touch virtual BOOL net_SaveRelevant(); virtual void save(NET_Packet& output_packet); virtual void load(IReader& input_packet); + + virtual CGameObject* cast_game_object() { return this; } + virtual CLevelChanger* cast_level_changer() { return this; } }; diff --git a/src/xrGame/level_graph.h b/src/xrGame/level_graph.h index a042d78d39..176fb04fb7 100644 --- a/src/xrGame/level_graph.h +++ b/src/xrGame/level_graph.h @@ -63,10 +63,10 @@ class CLevelGraph u32 m_max_z; private: - u32 vertex(const Fvector& position) const; u32 guess_vertex_id(u32 const& current_vertex_id, Fvector const& position) const; public: + u32 vertex(const Fvector& position) const; typedef u32 const_iterator; typedef u32 const_spawn_iterator; typedef u32 const_death_iterator; diff --git a/src/xrGame/level_graph_inline.h b/src/xrGame/level_graph_inline.h index 1f34262ec1..c26cd9055a 100644 --- a/src/xrGame/level_graph_inline.h +++ b/src/xrGame/level_graph_inline.h @@ -544,7 +544,7 @@ IC bool CLevelGraph::create_straight_path(u32 start_vertex_id, const Fvector2& s VPUSH(v3d(start_point)), VPUSH(v3d(finish_point)) ); - FlushLog (); + xrLogger::FlushLog (); R_ASSERT2 (false,"Loop became infinite :-( call Dima and SAVE YOUR LOG!"); } #endif diff --git a/src/xrGame/level_path_builder.h b/src/xrGame/level_path_builder.h index df2f00ee31..7f734d09fe 100644 --- a/src/xrGame/level_path_builder.h +++ b/src/xrGame/level_path_builder.h @@ -78,7 +78,7 @@ class CLevelPathBuilder : public CDetailPathBuilder return; m_object->m_wait_for_distributed_computation = true; - Device.seqParallel.push_back(fastdelegate::FastDelegate0<>(this, &CLevelPathBuilder::process)); + Device.seqParallel.push_back(xr_make_delegate(this, &CLevelPathBuilder::process)); } void process_impl(bool separate_compute = false) @@ -112,6 +112,7 @@ class CLevelPathBuilder : public CDetailPathBuilder void __stdcall process() { + PROF_EVENT("CLevelPathBuilder::process"); // demonized: disable the check since we already do it in register_to_process /*if (Device.dwTimeGlobal < m_next_retry_time) return;*/ @@ -125,7 +126,7 @@ class CLevelPathBuilder : public CDetailPathBuilder m_object->m_wait_for_distributed_computation = false; Device.remove_from_seq_parallel( - fastdelegate::FastDelegate0<>( + xr_make_delegate( this, &CLevelPathBuilder::process ) diff --git a/src/xrGame/level_script.cpp b/src/xrGame/level_script.cpp index 63dcf5466e..3b9433e718 100644 --- a/src/xrGame/level_script.cpp +++ b/src/xrGame/level_script.cpp @@ -531,6 +531,11 @@ void map_pan_to_level(LPCSTR level_name, bool zoom_in) mapWnd->SetTargetMap(shared_str(level_name), zoom_in); } +CMapManager* get_map_manager() +{ + return &Level().MapManager(); +} + bool patrol_path_exists(LPCSTR patrol_path) { return (!!ai().patrol_paths().path(patrol_path, true)); @@ -615,6 +620,11 @@ bool is_level_present() return (!!g_pGameLevel); } +void scheduler_flush(bool b) +{ + g_pGameLevel->schedulerFlush = b; +} + void add_call(const ::luabind::functor& condition, const ::luabind::functor& action) { ::luabind::functor _condition = condition; @@ -838,7 +848,7 @@ bool getCamEffectorTransformData(::luabind::object& t, LPCSTR animationFile) { COMotion M; if (M.LoadMotion(full_path)) { - std::map mapOrder; + xr_map mapOrder; mapOrder[EChannelType::ctPositionX] = "positionX"; mapOrder[EChannelType::ctPositionY] = "positionY"; mapOrder[EChannelType::ctPositionZ] = "positionZ"; @@ -1126,9 +1136,14 @@ void refresh_npc_names() if (g_pGameLevel) { CObject* obj = g_pGameLevel->Objects.net_Find(it->first); - CInventoryOwner* owner = smart_cast(obj); - if (owner) - owner->refresh_npc_name(); + if (obj) + { + CInventoryOwner* owner = smart_cast(obj); + if (owner) + { + owner->refresh_npc_name(); + } + } } } } @@ -1214,11 +1229,28 @@ void stop_tutorial() g_tutorial->Stop(); } +LPCSTR tutorial_name() +{ + if (g_tutorial) + return g_tutorial->m_name; + return "invalid"; +} + LPCSTR translate_string(LPCSTR str) { return *CStringTable().translate(str); } +void patrol_path_add(LPCSTR patrol_path, CPatrolPath* path) +{ + ai().patrol_paths_raw().add_path(shared_str(patrol_path), path); +} + +void patrol_path_remove(LPCSTR patrol_path) +{ + ai().patrol_paths_raw().remove_path(shared_str(patrol_path)); +} + bool has_active_tutotial() { return (g_tutorial != NULL); @@ -2536,6 +2568,7 @@ void CLevel::script_register(lua_State* L) def("map_remove_object_spot", map_remove_object_spot), def("map_has_object_spot", map_has_object_spot), def("map_change_spot_hint", map_change_spot_hint), + def("map_manager", get_map_manager), // demonized: remove all map object spots by id def("map_remove_all_object_spots", map_remove_all_object_spots), @@ -2568,6 +2601,8 @@ void CLevel::script_register(lua_State* L) def("enable_input", enable_input), def("spawn_phantom", spawn_phantom), + def("scheduler_flush", scheduler_flush), + def("get_bounding_volume", get_bounding_volume), def("iterate_sounds", &iterate_sounds1), @@ -2626,7 +2661,10 @@ void CLevel::script_register(lua_State* L) def("get_attachment", &GetAttachment), def("remove_attachment", (void (*)(LPCSTR)) &RemoveAttachment), def("remove_attachment", (void (*)(script_attachment*)) &RemoveAttachment), - def("iterate_attachments", &IterateAttachments) + def("iterate_attachments", &IterateAttachments), + + def("patrol_path_add", &patrol_path_add), + def("patrol_path_remove", &patrol_path_remove) ], module(L, "actor_stats") @@ -2775,6 +2813,7 @@ void CLevel::script_register(lua_State* L) def("start_tutorial", &start_tutorial), def("stop_tutorial", &stop_tutorial), def("has_active_tutorial", &has_active_tutotial), + def("active_tutorial_name", &tutorial_name), def("translate_string", &translate_string), def("reload_language", &reload_language), def("get_resolutions", &vid_modes_string), diff --git a/src/xrGame/level_sounds.cpp b/src/xrGame/level_sounds.cpp index 31baef11f7..8875c04ddf 100644 --- a/src/xrGame/level_sounds.cpp +++ b/src/xrGame/level_sounds.cpp @@ -219,6 +219,7 @@ void CLevelSoundManager::Unload() void CLevelSoundManager::Update() { + PROF_EVENT("CLevelSoundManager::Update"); if (Device.Paused()) return; if (Device.dwPrecacheFrame != 0) return; // static sounds diff --git a/src/xrGame/login_manager.h b/src/xrGame/login_manager.h index b30c0737d4..831782764e 100644 --- a/src/xrGame/login_manager.h +++ b/src/xrGame/login_manager.h @@ -46,7 +46,7 @@ namespace gamespy_gp DECLARE_SCRIPT_REGISTER_FUNCTION }; //struct profile - //typedef fastdelegate::FastDelegate login_operation_cb; + //typedef xr_delegate login_operation_cb; typedef mixed_delegate login_operation_cb; class login_manager : private xray::noncopyable diff --git a/src/xrGame/map_location.cpp b/src/xrGame/map_location.cpp index 8c3ba72112..6f2129cd7e 100644 --- a/src/xrGame/map_location.cpp +++ b/src/xrGame/map_location.cpp @@ -320,7 +320,8 @@ void CMapLocation::CalcLevelName() bool CMapLocation::Update() //returns actual { - R_ASSERT(m_cached.m_updatedFrame!=Device.dwFrame); + if (m_cached.m_updatedFrame == Device.dwFrame) + return true; if (m_flags.test(eTTL)) { @@ -437,6 +438,9 @@ void CMapLocation::UpdateSpot(CUICustomMap* map, CMapSpot* sp) } else if (Level().name() == map->MapName() && GetSpotPointer(sp)) { + if (!m_owner_se_object) + return; + GameGraph::_GRAPH_ID dest_graph_id; dest_graph_id = m_owner_se_object->m_tGraphID; diff --git a/src/xrGame/map_manager.cpp b/src/xrGame/map_manager.cpp index bc03d9c8e5..66a098b287 100644 --- a/src/xrGame/map_manager.cpp +++ b/src/xrGame/map_manager.cpp @@ -151,6 +151,16 @@ CMapLocation* CMapManager::AddRelationLocation(CInventoryOwner* pInvOwner) return l; } +void CMapManager::RemoveRelationLocation(CInventoryOwner* pInvOwner) +{ + for (int t = ALife::eRelationTypeFriend; t < ALife::eRelationTypeLast; ++t) + { + ALife::ERelationType tt = (ALife::ERelationType)t; + Level().MapManager().RemoveMapLocation(RELATION_REGISTRY().GetSpotName(tt), pInvOwner->object_id()); + } + Level().MapManager().RemoveMapLocation("deadbody_location", pInvOwner->object_id()); +} + void CMapManager::Destroy(CMapLocation* ml) { m_deffered_destroy_queue.push_back(ml); @@ -272,6 +282,7 @@ void CMapManager::GetMapLocations(u16 id, xr_vector& res) void CMapManager::Update() { + PROF_EVENT("Map: Update"); delete_data(m_deffered_destroy_queue); //from prev frame Locations_it it = Locations().begin(); diff --git a/src/xrGame/map_manager.h b/src/xrGame/map_manager.h index 6bd78dec9c..7ce6553448 100644 --- a/src/xrGame/map_manager.h +++ b/src/xrGame/map_manager.h @@ -1,6 +1,7 @@ #pragma once #include "object_interfaces.h" #include "map_location_defs.h" +#include "script_export_space.h" class CMapLocationWrapper; class CInventoryOwner; @@ -20,6 +21,7 @@ class CMapManager Locations& Locations(); //{return *m_locations;} CMapLocation* AddMapLocation(const shared_str& spot_type, u16 id); CMapLocation* AddRelationLocation(CInventoryOwner* pInvOwner); + void RemoveRelationLocation(CInventoryOwner* pInvOwner); void RemoveMapLocation(const shared_str& spot_type, u16 id); // demonized: remove all map object spots by id @@ -40,4 +42,6 @@ class CMapManager void Dump (); #endif void Destroy(CMapLocation*); + + DECLARE_SCRIPT_REGISTER_FUNCTION }; diff --git a/src/xrGame/map_manager_script.cpp b/src/xrGame/map_manager_script.cpp new file mode 100644 index 0000000000..15a8724f97 --- /dev/null +++ b/src/xrGame/map_manager_script.cpp @@ -0,0 +1,49 @@ +#include "pch_script.h" +#include "map_manager.h" +#include "map_location.h" + +using namespace luabind; + +#pragma optimize("s",on) +void CMapManager::script_register(lua_State* L) +{ + module(L) + [ + class_("CMapManager") + .def(constructor<>()) + //.def("AddMapLocation", &CMapManager::AddMapLocation_script) + //.def("AddUserLocation", &CMapManager::AddUserLocation_script) + //.def("RemoveMapLocation", &CMapManager::RemoveMapLocation_script) + //.def("HasMapLocation", &CMapManager::HasMapLocation_script) + //.def("GetMapLocation", &CMapManager::GetMapLocation_script) + .def("RemoveMapLocationByObjectID", &CMapManager::RemoveMapLocationByObjectID) + .def("RemoveMapLocation", (void (CMapManager::*)(CMapLocation*)) & CMapManager::RemoveMapLocation) + //.def("RemoveMapLocation", &CMapManager::RemoveMapLocation_script) + .def("DisableAllPointers", &CMapManager::DisableAllPointers), + //.def("MapLocationsForEach", &CMapManager::MapLocationsForEach) + //.def("AllLocationsForEach", &CMapManager::AllLocationsForEach), + + class_("CMapLocation") + //.def(constructor<>()) + .def("HintEnabled", &CMapLocation::HintEnabled) + .def("GetHint", &CMapLocation::GetHint) + .def("SetHint", &CMapLocation::SetHint) + .def("PointerEnabled", &CMapLocation::PointerEnabled) + .def("EnablePointer", &CMapLocation::EnablePointer) + .def("DisablePointer", &CMapLocation::DisablePointer) + //.def("GetType", &CMapLocation::GetType) + //.def("SpotSize", &CMapLocation::SpotSize) + //.def("IsUserDefined", &CMapLocation::IsUserDefined) + //.def("SetUserDefinedFlag", &CMapLocation::SetUserDefinedFlag) + //.def("HighlightSpot", &CMapLocation::HighlightSpot) + .def("Collidable", &CMapLocation::Collidable) + .def("SpotEnabled", &CMapLocation::SpotEnabled) + .def("EnableSpot", &CMapLocation::EnableSpot) + .def("DisableSpot", &CMapLocation::DisableSpot) + .def("GetLevelName", &CMapLocation::GetLevelName) + .def("GetPosition", &CMapLocation::GetPosition) + .def("ObjectID", &CMapLocation::ObjectID) + .def("GetLastPosition", &CMapLocation::GetLastPosition) + //.def("GetOwnerTaskID", &CMapLocation::GetOwnerTaskID) + ]; +} diff --git a/src/xrGame/map_spot.cpp b/src/xrGame/map_spot.cpp index 23554eb4ed..ed3d900f99 100644 --- a/src/xrGame/map_spot.cpp +++ b/src/xrGame/map_spot.cpp @@ -62,6 +62,14 @@ void CMapSpot::Load(CUIXml* xml, LPCSTR path) if (!Heading()) { m_border_static->SetWidth(m_border_static->GetWidth() * UI().get_current_kx()); + if (!UI().is_widescreen()) + { + m_border_static->SetHeight(m_border_static->GetHeight() * UI().get_current_kx()); + } + else + { + m_border_static->SetTextureOffset(1, 0); + } m_border_static->SetStretchTexture(true); } } @@ -331,6 +339,11 @@ void CComplexMapSpot::Load(CUIXml* xml, LPCSTR path) // complex_spot_template m_left_icon = CreateStaticOrig(*xml, "left_icon"); m_right_icon = CreateStaticOrig(*xml, "right_icon"); m_top_icon = CreateStaticOrig(*xml, "top_icon"); + m_top_icon->SetStretchTexture(true); + m_top_icon->SetWidth(m_top_icon->GetWidth() * UI().get_current_kx()); + if (!UI().is_widescreen()) { + m_top_icon->SetHeight(m_top_icon->GetHeight() * UI().get_current_kx()); + } m_timer = CreateStaticOrig(*xml, "timer"); xml->SetLocalRoot(stored_root); @@ -393,6 +406,7 @@ void CComplexMapSpot::SetWndSize(const Fvector2& size) return; } float k = size.x / m_originSize.x; + xrCriticalSectionGuard guard(csUi); for (WINDOW_LIST_it it = m_ChildWndList.begin(); m_ChildWndList.end() != it; ++it) { diff --git a/src/xrGame/memory_manager.cpp b/src/xrGame/memory_manager.cpp index a498fb511d..791ed19044 100644 --- a/src/xrGame/memory_manager.cpp +++ b/src/xrGame/memory_manager.cpp @@ -88,6 +88,7 @@ extern bool g_enemy_manager_second_update; void CMemoryManager::update_enemies(const bool& registered_in_combat) { + PROF_EVENT("CMemoryManager::update_enemies"); #ifdef _DEBUG g_enemy_manager_second_update = false; #endif // _DEBUG @@ -122,6 +123,7 @@ void CMemoryManager::update_enemies(const bool& registered_in_combat) void CMemoryManager::update(float time_delta) { + PROF_EVENT("CMemoryManager::update"); START_PROFILE("Memory Manager") visual().update(time_delta); sound().update(); @@ -158,6 +160,7 @@ void CMemoryManager::enable(const CObject* object, bool enable) template void CMemoryManager::update(const xr_vector& objects, bool add_enemies) { + PROF_EVENT("CMemoryManager::update"); squad_mask_type mask = m_stalker ? m_stalker->agent_manager().member().mask(m_stalker) : 0; xr_vector::const_iterator I = objects.begin(); xr_vector::const_iterator E = objects.end(); @@ -345,6 +348,9 @@ void CMemoryManager::on_restrictions_change() void CMemoryManager::make_object_visible_somewhen(const CEntityAlive* enemy) { + if (!enemy || enemy->getDestroy()) // safety check if enemy disappears (usual scenario for fast fight command) + return; + squad_mask_type mask = stalker().agent_manager().member().mask(&stalker()); MemorySpace::CVisibleObject* obj = visual().visible_object(enemy); // if (obj) { @@ -355,10 +361,15 @@ void CMemoryManager::make_object_visible_somewhen(const CEntityAlive* enemy) bool prev = obj ? obj->visible(mask) : false; visual().add_visible_object(enemy, .001f, true); MemorySpace::CVisibleObject* obj1 = object().memory().visual().visible_object(enemy); - VERIFY(obj1); - // if (obj1) - // Msg ("[%6d] make_object_visible_somewhen [%s] = %x",Device.dwTimeGlobal,*enemy->cName(),obj1->m_squad_mask.get()); - obj1->visible(mask, prev); + if (obj1) + { + // Msg ("[%6d] make_object_visible_somewhen [%s] = %x",Device.dwTimeGlobal,*enemy->cName(),obj1->m_squad_mask.get()); + obj1->visible(mask, prev); + } + else + { + Msg("![CMemoryManager::make_object_visible_somewhen] tried to make obj1 visible, but its nullptr"); + } } void CMemoryManager::save(NET_Packet& packet) const diff --git a/src/xrGame/memory_manager.h b/src/xrGame/memory_manager.h index e214f7d843..26a56fa471 100644 --- a/src/xrGame/memory_manager.h +++ b/src/xrGame/memory_manager.h @@ -67,7 +67,7 @@ class CMemoryManager public: template - IC void fill_enemies(const xr_vector& objects, const _predicate& predicate) const; + IC void fill_enemies(const xr_vector* objects, const _predicate& predicate) const; template IC void fill_enemies(const _predicate& predicate) const; diff --git a/src/xrGame/memory_manager_inline.h b/src/xrGame/memory_manager_inline.h index b685815886..7643406105 100644 --- a/src/xrGame/memory_manager_inline.h +++ b/src/xrGame/memory_manager_inline.h @@ -9,10 +9,15 @@ #pragma once template -IC void CMemoryManager::fill_enemies(const xr_vector& objects, const _predicate& predicate) const +IC void CMemoryManager::fill_enemies(const xr_vector* objects, const _predicate& predicate) const { - xr_vector::const_iterator I = objects.begin(); - xr_vector::const_iterator E = objects.end(); + if (objects == nullptr) + { + return; + } + + typename xr_vector::const_iterator I = objects->begin(); + typename xr_vector::const_iterator E = objects->end(); for (; I != E; ++I) { if (!(*I).m_enabled) @@ -28,7 +33,7 @@ IC void CMemoryManager::fill_enemies(const xr_vector& objects, const _predica template IC void CMemoryManager::fill_enemies(const _predicate& predicate) const { - fill_enemies(visual().objects(), predicate); + fill_enemies(visual().objectsPtr(), predicate); // fill_enemies (sound().objects(),predicate); // fill_enemies (hit().objects(),predicate); } diff --git a/src/xrGame/mixed_delegate.h b/src/xrGame/mixed_delegate.h index 45d171ae94..ee83589e67 100644 --- a/src/xrGame/mixed_delegate.h +++ b/src/xrGame/mixed_delegate.h @@ -1,7 +1,7 @@ #ifndef MIXED_DELEGATE_INCLUDED #define MIXED_DELEGATE_INCLUDED -#include +#include "../xrCore/xr_delegate.h" #include "pch_script.h" #include "script_export_space.h" #include "script_callback_ex.h" @@ -18,7 +18,7 @@ class mixed_delegate typedef Param1 param1_type; typedef Param2 param2_type; - typedef fastdelegate::FastDelegate fastdelegate_type; + typedef xr_delegate fastdelegate_type; typedef CScriptCallbackEx lua_delegate_type; typedef ::luabind::object lua_object_type; typedef ::luabind::functor lua_function_type; diff --git a/src/xrGame/movement_manager.cpp b/src/xrGame/movement_manager.cpp index 5db1f0d3a9..0a4758e775 100644 --- a/src/xrGame/movement_manager.cpp +++ b/src/xrGame/movement_manager.cpp @@ -141,6 +141,16 @@ GameGraph::_GRAPH_ID CMovementManager::game_dest_vertex_id() const void CMovementManager::set_level_dest_vertex(u32 const& level_vertex_id) { + if (!ai().level_graph().valid_vertex_id(level_vertex_id)) + { + Msg( + "! [CMovementManager::set_level_dest_vertex] ignoring invalid level vertex id [%u] for object [%s]", + level_vertex_id, + object().cName().c_str() + ); + return; + } + VERIFY2(restrictions().accessible(level_vertex_id), *object().cName()); level_path().set_dest_vertex(level_vertex_id); m_path_actuality = m_path_actuality && level_path().actual(); diff --git a/src/xrGame/moving_objects.h b/src/xrGame/moving_objects.h index 7999653b68..22c0d085f1 100644 --- a/src/xrGame/moving_objects.h +++ b/src/xrGame/moving_objects.h @@ -39,7 +39,7 @@ class moving_objects typedef xr_vector COLLISIONS; private: - typedef xr_vector Spatials; + typedef xr_vector Spatials; public: diff --git a/src/xrGame/object_manager_inline.h b/src/xrGame/object_manager_inline.h index 97f7754f36..6d10a486ec 100644 --- a/src/xrGame/object_manager_inline.h +++ b/src/xrGame/object_manager_inline.h @@ -69,14 +69,21 @@ float CAbstractObjectManager::do_evaluate(T* object) const TEMPLATE_SPECIALIZATION bool CAbstractObjectManager::is_useful(T* object) const { - const ISpatial* self = (const ISpatial*)(object); - if (!self) - return (false); + // 1. Check if the object exists + if (!object) return false; - if ((object->spatial.type & STYPE_VISIBLEFORAI) != STYPE_VISIBLEFORAI) - return (false); + // 2. Access the component via the intrusive_ptr + // We take a const reference to avoid atomic ref-count churn + const ISpatialShared spatial = object->SpatialComponent; - return (true); + // 3. Check if the component exists (is_useful requires a spatial presence) + if (!spatial) return false; + + // 4. Check the AI visibility flag + if (!(spatial->spatial.type & STYPE_VISIBLEFORAI)) + return false; + + return true; } TEMPLATE_SPECIALIZATION diff --git a/src/xrGame/patrol_path.cpp b/src/xrGame/patrol_path.cpp index 36c64fa1f0..dcd04b616f 100644 --- a/src/xrGame/patrol_path.cpp +++ b/src/xrGame/patrol_path.cpp @@ -46,11 +46,11 @@ CPatrolPath& CPatrolPath::load_raw(const CLevelGraph* level_graph, const CGameLe CPatrolPath& CPatrolPath::load_from_config(CInifile* ini_paths, LPCSTR patrol_name) { R_ASSERT3(ini_paths->line_exist(patrol_name, "points"), "Missing key 'points' in patrol path", patrol_name); - LPCSTR points_csv = ini_paths->r_string(patrol_name, "points"); - std::vector points = splitStringMulti(points_csv, ",", false, true); + xr_string points_csv = ini_paths->r_string(patrol_name, "points"); + xr_vector points = points_csv.SplitStringMulti(",", false, true); // Keep track of name <-> vertex_id association - std::map vertex_ids_by_name; + xr_map vertex_ids_by_name; // Add patrol points for (int idx = 0; idx < points.size(); idx++) @@ -76,13 +76,13 @@ CPatrolPath& CPatrolPath::load_from_config(CInifile* ini_paths, LPCSTR patrol_na } // Get list of vertices to link to - LPCSTR links_csv = ini_paths->r_string(patrol_name, links_csv_key.c_str()); - std::vector links = splitStringMulti(links_csv, ",", false, true); + xr_string links_csv = ini_paths->r_string(patrol_name, links_csv_key.c_str()); + xr_vector links = links_csv.SplitStringMulti(",", false, true); - for (std::string link : links) + for (xr_string link : links) { // Link current point to target points - std::pair link_info = parse_point_link(patrol_name, link, vertex_ids_by_name); + std::pair link_info = parse_point_link(patrol_name, link, vertex_ids_by_name); add_edge(idx, link_info.first, link_info.second); Msg("[PP] Linked %d to %d with a probability of %f", link_info.first, idx, link_info.second); } @@ -93,7 +93,7 @@ CPatrolPath& CPatrolPath::load_from_config(CInifile* ini_paths, LPCSTR patrol_na return (*this); } -std::pair CPatrolPath::parse_point_link(LPCSTR patrol_name, std::string link, std::map vertex_ids_by_name) +std::pair CPatrolPath::parse_point_link(LPCSTR patrol_name, xr_string link, xr_map vertex_ids_by_name) { Msg("[PP] Linking %s", link.c_str()); @@ -103,13 +103,13 @@ std::pair CPatrolPath::parse_point_link(LPCSTR patrol_name, std::str bool matched = std::regex_search(link, matches, pattern); R_ASSERT4(matched, "Bad format for patrol path link", patrol_name, link.c_str()); - std::string target = matches[1].str(); + xr_string target = matches[1].str().c_str(); float prob = std::stof(matches[2].str()); auto I = vertex_ids_by_name.find(target.c_str()); R_ASSERT4(I != vertex_ids_by_name.end(), "Patrol point link target does not exist", patrol_name, target.c_str()); - return std::make_pair((*I).second, prob); + return { (*I).second, prob }; } CPatrolPath::~CPatrolPath() diff --git a/src/xrGame/patrol_path.h b/src/xrGame/patrol_path.h index 1ce777e3c7..4c02dd1d90 100644 --- a/src/xrGame/patrol_path.h +++ b/src/xrGame/patrol_path.h @@ -42,7 +42,7 @@ class CPatrolPath : public CGraphAbstractSerialize IC const CVertex* point(const Fvector& position) const; private: - std::pair CPatrolPath::parse_point_link(LPCSTR patrol_name, std::string link, std::map vertex_ids_by_name); + std::pair CPatrolPath::parse_point_link(LPCSTR patrol_name, xr_string link, xr_map vertex_ids_by_name); #ifdef DEBUG public: diff --git a/src/xrGame/patrol_path_manager_inline.h b/src/xrGame/patrol_path_manager_inline.h index 68aa939adb..e3b9fc544c 100644 --- a/src/xrGame/patrol_path_manager_inline.h +++ b/src/xrGame/patrol_path_manager_inline.h @@ -96,13 +96,13 @@ IC void CPatrolPathManager::make_inactual() IC void CPatrolPathManager::set_path(shared_str path_name) { - set_path(ai().patrol_paths().path(path_name), path_name); + set_path(ai().patrol_paths().safe_path(path_name, false, true), path_name); } IC void CPatrolPathManager::set_path(shared_str path_name, const EPatrolStartType patrol_start_type, const EPatrolRouteType patrol_route_type, bool random) { - set_path(ai().patrol_paths().path(path_name), path_name); + set_path(ai().patrol_paths().safe_path(path_name, false, true), path_name); set_start_type(patrol_start_type); set_route_type(patrol_route_type); set_random(random); diff --git a/src/xrGame/patrol_path_params.cpp b/src/xrGame/patrol_path_params.cpp index ffb08b69e4..cf97815b09 100644 --- a/src/xrGame/patrol_path_params.cpp +++ b/src/xrGame/patrol_path_params.cpp @@ -16,8 +16,14 @@ CPatrolPathParams::CPatrolPathParams(LPCSTR caPatrolPathToGo, const PatrolPathManager::EPatrolRouteType tPatrolPathStop, bool bRandom, u32 index) { m_path_name = caPatrolPathToGo; - m_path = ai().patrol_paths().path(m_path_name, true); + m_path = ai().patrol_paths().safe_path(m_path_name, true); + if (m_path == nullptr) + { + Msg("! m_path is nullptr: [%s]", caPatrolPathToGo); + } + + // R_ASSERT3(m_path, "There is no patrol path", caPatrolPathToGo); THROW3(m_path, "There is no patrol path", caPatrolPathToGo); m_tPatrolPathStart = tPatrolPathStart; diff --git a/src/xrGame/patrol_path_storage.cpp b/src/xrGame/patrol_path_storage.cpp index ed9d0afe3c..887be00697 100644 --- a/src/xrGame/patrol_path_storage.cpp +++ b/src/xrGame/patrol_path_storage.cpp @@ -11,6 +11,9 @@ #include "patrol_path.h" #include "patrol_point.h" #include "levelgamedef.h" +#include "ai_space.h" +#include "level_graph.h" +#include "game_graph.h" CPatrolPathStorage::~CPatrolPathStorage() { @@ -150,3 +153,54 @@ void CPatrolPathStorage::save(IWriter& stream) stream.close_chunk(); } + +void CPatrolPathStorage::remove_path(shared_str patrol_name) +{ + m_registry.erase(patrol_name); +} + +void CPatrolPathStorage::add_path(shared_str patrol_name, CPatrolPath *path) +{ + remove_path(patrol_name); + m_registry.insert(std::make_pair(patrol_name, path)); +} + +const CPatrolPath* CPatrolPathStorage::safe_path(shared_str patrol_name, bool no_assert, bool on_level) const +{ + if (auto it = m_registry.find(patrol_name); it == m_registry.end()) + { + return path(patrol_name, no_assert); + } + else + { + for (auto&& [key, vertex] : it->second->vertices()) + { + auto& pp = vertex->data(); + + const u32 point_lvid = pp.level_vertex_id(); + const GameGraph::_GRAPH_ID point_gvid = pp.game_vertex_id(); + const Fvector& point_pos = pp.position(); + const shared_str& point_name = pp.name(); + + if (on_level || (ai().game_graph().valid_vertex_id(point_gvid) && + ai().game_graph().vertex(point_gvid)->level_id() == ai().level_graph().level_id())) + { + if (!ai().level_graph().valid_vertex_id(point_lvid)) + { + const u32 prev_vertex_id = pp.m_level_vertex_id; + pp.m_level_vertex_id = ai().level_graph().vertex(pp. + m_position); + Msg("! [%s]: path [%s] pp [%s] level_vertex_id [%u] -> %u", + __FUNCTION__, patrol_name.c_str(), pp.m_name.c_str(), + prev_vertex_id, pp.m_level_vertex_id); + } + } + else + { + return path(patrol_name, no_assert); + } + } + + return path(patrol_name, no_assert); + } +} diff --git a/src/xrGame/patrol_path_storage.h b/src/xrGame/patrol_path_storage.h index c94c44436a..030a0d558e 100644 --- a/src/xrGame/patrol_path_storage.h +++ b/src/xrGame/patrol_path_storage.h @@ -39,7 +39,11 @@ class CPatrolPathStorage : public IPureSerializeObject public: void load_raw(const CLevelGraph* level_graph, const CGameLevelCrossTable* cross, const CGameGraph* game_graph, IReader& stream); IC const CPatrolPath* path(shared_str patrol_name, bool no_assert = false) const; + const CPatrolPath* safe_path(shared_str patrol_name, bool no_assert = false, bool on_level = false) const; IC const PATROL_REGISTRY& patrol_paths() const; + + void add_path(shared_str, CPatrolPath*); + void remove_path(shared_str); }; #include "patrol_path_storage_inline.h" diff --git a/src/xrGame/patrol_point.h b/src/xrGame/patrol_point.h index 4e52c956a4..ab69a95831 100644 --- a/src/xrGame/patrol_point.h +++ b/src/xrGame/patrol_point.h @@ -18,6 +18,8 @@ class CGameGraph; class CPatrolPoint : public IPureSerializeObject { + friend class CPatrolPathStorage; + protected: shared_str m_name; Fvector m_position; diff --git a/src/xrGame/physic_item.cpp b/src/xrGame/physic_item.cpp index 97c208d9fc..8eccb34cf5 100644 --- a/src/xrGame/physic_item.cpp +++ b/src/xrGame/physic_item.cpp @@ -103,6 +103,7 @@ void CPhysicItem::net_Destroy() void CPhysicItem::UpdateCL() { + PROF_EVENT("CPhysicItem::UpdateCL") // if (!xr_strcmp("bolt",cName())) // Log ("--- B - CBolt",renderable.xform); if (!H_Parent() && m_pPhysicsShell && m_pPhysicsShell->isActive()) diff --git a/src/xrGame/physic_item.h b/src/xrGame/physic_item.h index 27fc35498d..4536a8dcc3 100644 --- a/src/xrGame/physic_item.h +++ b/src/xrGame/physic_item.h @@ -37,6 +37,8 @@ class CPhysicItem : virtual void create_box_physic_shell(); virtual void create_box2sphere_physic_shell(); virtual void create_physic_shell(); + virtual CPhysicItem* cast_physics_item() { return this; } + virtual CPhysicsShellHolder* cast_physics_shell_holder() { return this; } }; #include "physic_item_inline.h" diff --git a/src/xrGame/physics_game.cpp b/src/xrGame/physics_game.cpp index 7d13b65d1b..adb8b0644e 100644 --- a/src/xrGame/physics_game.cpp +++ b/src/xrGame/physics_game.cpp @@ -1,5 +1,4 @@ #include "stdafx.h" -#include "ParticlesObject.h" #include "../xrEngine/gamemtllib.h" #include "level.h" #include "gamepersistent.h" @@ -52,7 +51,7 @@ class CPHParticlesPlayCall : virtual void run() { - CParticlesObject* ps = CParticlesObject::Create(ps_name,TRUE); + intrusive_ptr ps = Particles::Details::Create(ps_name,TRUE); Fmatrix pos; Fvector zero_vel = {0.f, 0.f, 0.f}; @@ -175,24 +174,23 @@ static void play_object(dxGeomUserData* data, SGameMtlPair* mtl_pair, const dCon VERIFY(mtl_pair); VERIFY(c); - CPHSoundPlayer* sp = NULL; -#ifdef DEBUG - __try{ - sp=data->ph_ref_object->ObjectPhSoundPlayer(); - } - __except(EXCEPTION_EXECUTE_HANDLER){ - Msg( "data->ph_ref_object: %p ", data->ph_ref_object ); - Msg( "data: %p ", data ); - Msg( "materials: %s ", mtl_pair->dbg_Name() ); - FlushLog(); - FATAL( "bad data->ph_ref_object" ); - } -#else - if (data->ph_ref_object) - sp = data->ph_ref_object->ObjectPhSoundPlayer(); -#endif + CPHSoundPlayer* sp = nullptr; + + try + { + if (data->ph_ref_object) + sp = data->ph_ref_object->ObjectPhSoundPlayer(); + } + catch (...) + { + Msg("! Physics callbacks sound player play_object error"); + sp = nullptr; + } + if (sp) + { sp->Play(mtl_pair, *(Fvector*)c->pos); + } } template diff --git a/src/xrGame/physics_world_scripted.cpp b/src/xrGame/physics_world_scripted.cpp index 852f81b070..2fb7a698aa 100644 --- a/src/xrGame/physics_world_scripted.cpp +++ b/src/xrGame/physics_world_scripted.cpp @@ -11,7 +11,7 @@ using namespace luabind; void cphysics_world_scripted::AddCall(CPHCondition* c, CPHAction* a) { - Level().ph_commander_physics_worldstep().add_call_threadsafety(c, a); + Level().ph_commander_physics_worldstep().add_call(c, a); } diff --git a/src/xrGame/player_hud.cpp b/src/xrGame/player_hud.cpp index c2761ef9b8..fdf86ac082 100644 --- a/src/xrGame/player_hud.cpp +++ b/src/xrGame/player_hud.cpp @@ -314,6 +314,10 @@ void attachable_hud_item::setup_firedeps(firedeps& fd) if (m_measures.m_prop_flags.test(hud_item_measures::e_shell_point)) { + if (m_measures.m_shell_bone == BI_NONE) + { + return; + } Fmatrix& fire_mat = m_model->LL_GetTransform(m_measures.m_shell_bone); fire_mat.transform_tiny(fd.vLastSP, m_parent->m_adjust_mode ? m_parent->m_adjust_firepoint_shell[1][1] : m_measures.m_shell_point_offset); m_item_transform.transform_tiny(fd.vLastSP); @@ -326,11 +330,9 @@ bool attachable_hud_item::need_renderable() return m_parent_hud_item->need_renderable(); } -void attachable_hud_item::render() +void attachable_hud_item::render(IDSGraphManager* DM) { - ::Render->set_Transform(&m_item_transform); - ::Render->add_Visual(m_model->dcast_RenderVisual()); - + DM->add_Dynamic(m_model->dcast_RenderVisual(), &m_item_transform); m_parent_hud_item->render_hud_mode(); if (m_parent_hud_item->has_object() && m_parent_hud_item->object().GetAttachments()->size()) @@ -338,7 +340,7 @@ void attachable_hud_item::render() for (auto& pair : *m_parent_hud_item->object().GetAttachments()) { if (pair.second->GetType() == eSA_HUD) - pair.second->Render(m_model, &m_item_transform); + pair.second->Render(m_model, &m_item_transform, DM); } } } @@ -595,6 +597,12 @@ void attachable_hud_item::load(const shared_str& sect_name) ::Render->hud_loading = false; R_ASSERT2(visual, make_string("could not create model %s, section %s", visual_name, sect_name.c_str())); m_model = smart_cast(visual); + if (m_model) + { + IRenderVisual* pVisual = m_model->dcast_RenderVisual(); + if (pVisual) + pVisual->MarkIgnoreOptimization(TRUE); + } m_attach_place_idx = pSettings->r_u16(sect_name, "attach_place_idx"); m_measures.load(sect_name, m_model); @@ -832,6 +840,20 @@ void player_hud::load(const shared_str& player_hud_sect, bool force) ::Render->hud_loading = true; m_model = smart_cast(::Render->model_Create(model_name.c_str())); m_model_2 = smart_cast(::Render->model_Create(pSettings->line_exist(player_hud_sect, "visual_2") ? pSettings->r_string(player_hud_sect, "visual_2") : model_name.c_str())); + + if (m_model) + { + IRenderVisual* pVisual = m_model->dcast_RenderVisual(); + if (pVisual) + pVisual->MarkIgnoreOptimization(TRUE); + } + if (m_model_2) + { + IRenderVisual* pVisual = m_model_2->dcast_RenderVisual(); + if (pVisual) + pVisual->MarkIgnoreOptimization(TRUE); + } + bool b_reload = (m_attached_items[0] != nullptr || m_attached_items[1] != nullptr); ::Render->hud_loading = false; @@ -943,31 +965,28 @@ void player_hud::render_item_ui() } } -void player_hud::render_hud() +void player_hud::render_hud(IDSGraphManager* DM) { bool b_r0 = ((m_attached_items[0] && m_attached_items[0]->need_renderable()) || script_anim_part == 0 || script_anim_part == 2); bool b_r1 = ((m_attached_items[1] && m_attached_items[1]->need_renderable()) || script_anim_part == 1 || script_anim_part == 2); if (!b_r0 && !b_r1) return; - ::Render->set_Transform(&m_transform); - ::Render->add_Visual(m_model->dcast_RenderVisual()); - ::Render->set_Transform(&m_transform_2); - ::Render->add_Visual(m_model_2->dcast_RenderVisual()); + DM->add_Dynamic(m_model->dcast_RenderVisual(), &m_transform); + DM->add_Dynamic(m_model_2->dcast_RenderVisual(), &m_transform_2); if (m_attached_items[0]) - m_attached_items[0]->render(); + m_attached_items[0]->render(DM); if (m_attached_items[1]) - m_attached_items[1]->render(); + m_attached_items[1]->render(DM); if (m_attached_items[SCOPE_ATTACH_IDX]) - m_attached_items[SCOPE_ATTACH_IDX]->render(); + m_attached_items[SCOPE_ATTACH_IDX]->render(DM); if (script_anim_item_model) { - ::Render->set_Transform(&m_item_pos); - ::Render->add_Visual(script_anim_item_model->dcast_RenderVisual()); + DM->add_Dynamic(script_anim_item_model->dcast_RenderVisual(), &m_item_pos); } if (g_actor->GetAttachments()->size()) @@ -980,11 +999,11 @@ void player_hud::render_hud() { // Left arm if (att->GetParentBone() < 21) - att->Render(m_model_2->dcast_PKinematics(), &m_transform_2); + att->Render(m_model_2->dcast_PKinematics(), &m_transform_2, DM); // Right arm else - att->Render(m_model->dcast_PKinematics(), &m_transform); + att->Render(m_model->dcast_PKinematics(), &m_transform, DM); } } } @@ -1033,7 +1052,7 @@ u32 player_hud::motion_length(const MotionID& M, const CMotionDef*& md, float sp { md = m_model->LL_GetMotionDef(M); VERIFY(md); - if (md->flags & esmStopAtEnd) + if (md != nullptr && md->flags & esmStopAtEnd) { CMotion* motion = m_model->LL_GetRootMotion(M); return iFloor(0.5f + 1000.f * motion->GetLength() / (md->Dequantize(md->speed) * speed)); diff --git a/src/xrGame/player_hud.h b/src/xrGame/player_hud.h index 68f57b6c3d..84eda3a847 100644 --- a/src/xrGame/player_hud.h +++ b/src/xrGame/player_hud.h @@ -321,7 +321,7 @@ struct attachable_hud_item void load(const shared_str& sect_name); void update(bool bForce); void setup_firedeps(firedeps& fd); - void render(); + void render(IDSGraphManager* DM); void render_item_ui(); bool render_item_ui_query(); bool need_renderable(); @@ -370,7 +370,7 @@ class player_hud void StopBlendAnm(LPCSTR name, bool bForce = false); void StopAllBlendAnms(bool bForce); float SetBlendAnmTime(LPCSTR name, float time); - void render_hud(); + void render_hud(IDSGraphManager* DM); void render_item_ui(); bool render_item_ui_query(); u32 anim_play(u16 part, const MotionID& M, BOOL bMixIn, const CMotionDef*& md, float speed, u16 override_part = u16(-1)); diff --git a/src/xrGame/player_hud_legs.cpp b/src/xrGame/player_hud_legs.cpp index d24ca8f7ac..ccc1019784 100644 --- a/src/xrGame/player_hud_legs.cpp +++ b/src/xrGame/player_hud_legs.cpp @@ -250,7 +250,7 @@ void player_legs_controller::update(CActor* actor, bool isShadowPass) actor->XFORMShadow.translate_over(m_legs_transform.c); } -void player_legs_controller::render() +void player_legs_controller::render(IDSGraphManager* DM) { if (!m_model) return; @@ -267,6 +267,5 @@ void player_legs_controller::render() if (!visual) return; - ::Render->set_Transform(&m_legs_transform); - ::Render->add_Visual(visual); + DM->add_Dynamic(visual, &m_legs_transform); } diff --git a/src/xrGame/player_hud_legs.h b/src/xrGame/player_hud_legs.h index 9d9b7bf1f6..0876976fbe 100644 --- a/src/xrGame/player_hud_legs.h +++ b/src/xrGame/player_hud_legs.h @@ -9,7 +9,7 @@ class player_legs_controller { public: void update(CActor* actor, bool isShadowPass = false); - void render(); + void render(IDSGraphManager* DM); void destroy(); bool is_active() const { return m_model != nullptr; } diff --git a/src/xrGame/quadtree_inline.h b/src/xrGame/quadtree_inline.h index 960086eb31..be2d4af1e0 100644 --- a/src/xrGame/quadtree_inline.h +++ b/src/xrGame/quadtree_inline.h @@ -21,7 +21,7 @@ IC CSQuadTree::CQuadTree(const Fbox& box, float min_cell_size, u32 max_node_coun VERIFY(!fis_zero(min_cell_size)); VERIFY(m_radius > min_cell_size); - m_max_depth = iFloor(log(2.f * m_radius / min_cell_size) / log(2.f) + .5f); + m_max_depth = std::abs(iFloor(log(2.f * m_radius / min_cell_size) / log(2.f) + .5f)); m_nodes = xr_new(max_node_count); m_list_items = xr_new(max_list_item_count); diff --git a/src/xrGame/queued_async_method.h b/src/xrGame/queued_async_method.h index 21f6a9f920..7ab8e04a59 100644 --- a/src/xrGame/queued_async_method.h +++ b/src/xrGame/queued_async_method.h @@ -201,7 +201,7 @@ struct parameters_tuple3 parameters_tuple3(parameters_tuple3 const& copy) : m_t1(copy.m_t1), m_t2(copy.m_t2), - m_t3(copt.m_t3) + m_t3(copy.m_t3) { }; diff --git a/src/xrGame/relation_registry.cpp b/src/xrGame/relation_registry.cpp index 516330e75e..faa4264cb8 100644 --- a/src/xrGame/relation_registry.cpp +++ b/src/xrGame/relation_registry.cpp @@ -55,7 +55,6 @@ RELATION_REGISTRY::RELATION_MAP_SPOTS::RELATION_MAP_SPOTS() spot_names[ALife::eRelationTypeNeutral] = "neutral_location"; spot_names[ALife::eRelationTypeEnemy] = "enemy_location"; spot_names[ALife::eRelationTypeWorstEnemy] = "enemy_location"; - //spot_names[ALife::eRelationTypeWorstEnemy] = "enemy_location"; spot_names[ALife::eRelationTypeLast] = "neutral_location"; } diff --git a/src/xrGame/restricted_object.cpp b/src/xrGame/restricted_object.cpp index ca25833852..55a6e12751 100644 --- a/src/xrGame/restricted_object.cpp +++ b/src/xrGame/restricted_object.cpp @@ -132,39 +132,27 @@ u32 CRestrictedObject::accessible_nearest(const Fvector& position, Fvector& resu bool CRestrictedObject::accessible(const Fvector& position) const { - START_PROFILE("Restricted Object/Accessible") - ; - return (accessible(position, EPS_L)); - STOP_PROFILE; + return (accessible(position, EPS_L)); } bool CRestrictedObject::accessible(const Fvector& position, float radius) const { - START_PROFILE("Restricted Object/Accessible") - ; - Fsphere sphere; - sphere.P = position; - sphere.R = radius; - return (Level().space_restriction_manager().accessible(object().ID(), sphere)); - STOP_PROFILE; + Fsphere sphere; + sphere.P = position; + sphere.R = radius; + return (Level().space_restriction_manager().accessible(object().ID(), sphere)); } bool CRestrictedObject::accessible(u32 level_vertex_id) const { - START_PROFILE("Restricted Object/Accessible") - ; - VERIFY(ai().level_graph().valid_vertex_id(level_vertex_id)); - return (accessible(level_vertex_id, EPS_L)); - STOP_PROFILE; + VERIFY(ai().level_graph().valid_vertex_id(level_vertex_id)); + return (accessible(level_vertex_id, EPS_L)); } bool CRestrictedObject::accessible(u32 level_vertex_id, float radius) const { - START_PROFILE("Restricted Object/Accessible") - ; - VERIFY(ai().level_graph().valid_vertex_id(level_vertex_id)); - return (Level().space_restriction_manager().accessible(object().ID(), level_vertex_id, radius)); - STOP_PROFILE; + VERIFY(ai().level_graph().valid_vertex_id(level_vertex_id)); + return (Level().space_restriction_manager().accessible(object().ID(), level_vertex_id, radius)); } void CRestrictedObject::add_border(u32 start_vertex_id, float radius) const diff --git a/src/xrGame/screenshot_manager.h b/src/xrGame/screenshot_manager.h index f1a03cf8dc..c32c231841 100644 --- a/src/xrGame/screenshot_manager.h +++ b/src/xrGame/screenshot_manager.h @@ -13,7 +13,7 @@ class screenshot_manager : public ISheduled drawing_download_states = 0x02 }; - typedef fastdelegate::FastDelegate3 complete_callback_t; + typedef xr_delegate complete_callback_t; screenshot_manager(); virtual ~screenshot_manager(); diff --git a/src/xrGame/screenshot_server.cpp b/src/xrGame/screenshot_server.cpp index b0552c1834..4d66f179d4 100644 --- a/src/xrGame/screenshot_server.cpp +++ b/src/xrGame/screenshot_server.cpp @@ -5,7 +5,7 @@ #include "xrServer.h" #include "game_sv_base.h" #include "game_cl_mp.h" -#include +#include "../xrCore/xr_delegate.h" extern BOOL g_sv_mp_save_proxy_screenshots; extern BOOL g_sv_mp_save_proxy_configs; diff --git a/src/xrGame/script_attachment_manager.cpp b/src/xrGame/script_attachment_manager.cpp index ff3664391c..a02cae946b 100644 --- a/src/xrGame/script_attachment_manager.cpp +++ b/src/xrGame/script_attachment_manager.cpp @@ -52,7 +52,7 @@ static void update_visbox_attachment(IKinematics* k) #endif } -script_attachment::script_attachment(LPCSTR name, LPCSTR model_name): ISpatial(g_SpatialSpace) +script_attachment::script_attachment(LPCSTR name, LPCSTR model_name) { m_name = name; m_kinematics = nullptr; @@ -85,7 +85,7 @@ script_attachment::script_attachment(LPCSTR name, LPCSTR model_name): ISpatial(g m_current_motion = "idle"; m_model_name = ""; m_userdata = nullptr; - spatial.type |= STYPE_RENDERABLE; + SpatialComponent->spatial.type |= STYPE_RENDERABLE; LoadModel(model_name); PlayMotion("idle", false); } @@ -107,27 +107,27 @@ void script_attachment::RemoveAttachment(script_attachment* child) void script_attachment::spatial_register() { - renderable.xform.transform_tiny(spatial.sphere.P, renderable.visual ? renderable.visual->getVisData().sphere.P : Fvector{ 0,0,0 }); + renderable.xform.transform_tiny(SpatialComponent->spatial.sphere.P, renderable.visual ? renderable.visual->getVisData().sphere.P : Fvector{ 0,0,0 }); Fvector& scale = m_attachment_offset[2]; - spatial.sphere.R = renderable.visual ? renderable.visual->getVisData().sphere.R * std::max(scale.x, std::max(scale.y, scale.z)) : 0.f; - ISpatial::spatial_register(); + SpatialComponent->spatial.sphere.R = renderable.visual ? renderable.visual->getVisData().sphere.R * std::max(scale.x, std::max(scale.y, scale.z)) : 0.f; + ISpatialOwner::spatial_register(); } void script_attachment::spatial_unregister() { - ISpatial::spatial_unregister(); + ISpatialOwner::spatial_unregister(); } void script_attachment::spatial_move() { - if (!spatial.node_ptr) return; - renderable.xform.transform_tiny(spatial.sphere.P, renderable.visual->getVisData().sphere.P); + if (!SpatialComponent->spatial.node_ptr) return; + renderable.xform.transform_tiny(SpatialComponent->spatial.sphere.P, renderable.visual->getVisData().sphere.P); Fvector& scale = m_attachment_offset[2]; - spatial.sphere.R = renderable.visual->getVisData().sphere.R * std::max(scale.x, std::max(scale.y, scale.z)); - ISpatial::spatial_move(); + SpatialComponent->spatial.sphere.R = renderable.visual->getVisData().sphere.R * std::max(scale.x, std::max(scale.y, scale.z)); + ISpatialOwner::spatial_move(); } -void script_attachment::renderable_Render() +void script_attachment::renderable_Render(IDSGraphManager* DM) { if (GetType() != eSA_World) return; @@ -154,19 +154,18 @@ void script_attachment::renderable_Render() m_kinematics->CalculateBones_Invalidate(); m_kinematics->CalculateBones(TRUE); - ::Render->set_Transform(&renderable.xform); - ::Render->add_Visual(renderable.visual); + DM->add_Dynamic(renderable.visual, &renderable.xform); if (m_children.size()) { for (auto& pair : m_children) { - pair.second->Render(m_kinematics, &renderable.xform); + pair.second->Render(m_kinematics, &renderable.xform, DM); } } } -void script_attachment::Render(IKinematics* model, Fmatrix* mat) +void script_attachment::Render(IKinematics* model, Fmatrix* mat, IDSGraphManager* DM) { if (!model || (m_bone_callbacks[0] && m_bone_callbacks[0]->m_bone_id != BI_NONE)) renderable.xform = *mat; @@ -196,14 +195,13 @@ void script_attachment::Render(IKinematics* model, Fmatrix* mat) m_kinematics->CalculateBones(TRUE); } - ::Render->set_Transform(&renderable.xform); - ::Render->add_Visual(renderable.visual); + DM->add_Dynamic(renderable.visual, &renderable.xform); if (m_children.size()) { for (auto& pair : m_children) { - pair.second->Render(m_kinematics, &renderable.xform); + pair.second->Render(m_kinematics, &renderable.xform, DM); } } } @@ -671,7 +669,7 @@ extern BOOL print_bone_warnings; Fmatrix script_attachment::bone_transform(u16 bone_id) { if (bone_id == BI_NONE || bone_id >= m_kinematics->LL_BoneCount()) { - if (strstr(Core.Params, "-dbg") && print_bone_warnings) { + if (Core.isDebug() && print_bone_warnings) { Msg("![bone_position] Incorrect bone_id provided for %s (%s), fallback to root bone", GetName(), GetModelScript()); ai().script_engine().print_stack(); } @@ -723,6 +721,18 @@ ::luabind::object script_attachment::list_bones() return result; } +void script_attachment::SetType(u16 type) +{ + type = type < eSA_undefined ? type : eSA_World; + if (m_type == type) + return; + + m_type = type; + IRenderVisual* pVisual = renderable.visual->dcast_RenderVisual(); + if (pVisual) + pVisual->MarkIgnoreOptimization(m_type == eSA_HUD || m_type == eSA_CamAttached); +} + void script_attachment::LoadModel(LPCSTR model_name, bool keep_bc) { if (m_model_name == model_name) diff --git a/src/xrGame/script_attachment_manager.h b/src/xrGame/script_attachment_manager.h index a619ab7782..56c6abf785 100644 --- a/src/xrGame/script_attachment_manager.h +++ b/src/xrGame/script_attachment_manager.h @@ -46,8 +46,7 @@ struct script_attachment_bone_cb }; class script_attachment : - public IRenderable, - public ISpatial + public IRenderable { private: shared_str m_name; @@ -101,9 +100,9 @@ class script_attachment : virtual void spatial_move(); virtual IRenderable* dcast_Renderable() { return this; } - virtual void renderable_Render(); + virtual void renderable_Render(IDSGraphManager* DM); - void Render(IKinematics* model, Fmatrix* mat); + void Render(IKinematics* model, Fmatrix* mat, IDSGraphManager* DM); void Update(); void RenderUI(); @@ -185,7 +184,7 @@ class script_attachment : void RemoveChild(LPCSTR name, bool destroy = false); void IterateAttachments(::luabind::functor functor); - void SetType(u16 type) { m_type = type < eSA_undefined ? type : eSA_World; } + void SetType(u16 type); u16 GetType() { return m_type; } u32 PlayMotion(LPCSTR name, bool mixin = true, float speed = 1.f); diff --git a/src/xrGame/script_binder.cpp b/src/xrGame/script_binder.cpp index 3247759fc1..951d576c32 100644 --- a/src/xrGame/script_binder.cpp +++ b/src/xrGame/script_binder.cpp @@ -80,6 +80,7 @@ void CScriptBinder::Load(LPCSTR section) void CScriptBinder::reload(LPCSTR section) { + PROF_EVENT("CScriptBinder::reload"); #ifdef DEBUG_MEMORY_MANAGER size_t start = 0; if (g_bMEMO) @@ -133,6 +134,7 @@ void CScriptBinder::reload(LPCSTR section) BOOL CScriptBinder::net_Spawn(CSE_Abstract* DC) { + PROF_EVENT("CScriptBinder::net_Spawn"); #ifdef DEBUG_MEMORY_MANAGER size_t start = 0; if (g_bMEMO) @@ -165,6 +167,7 @@ BOOL CScriptBinder::net_Spawn(CSE_Abstract* DC) void CScriptBinder::net_Destroy() { + PROF_EVENT("CScriptBinder::net_Destroy"); if (m_object) { #ifdef _DEBUG @@ -200,6 +203,7 @@ void CScriptBinder::set_object(CScriptBinderObject* object) void CScriptBinder::shedule_Update(u32 time_delta) { + PROF_EVENT("CScriptBinder::shedule_Update"); if (m_object) { try @@ -215,6 +219,7 @@ void CScriptBinder::shedule_Update(u32 time_delta) void CScriptBinder::save(NET_Packet& output_packet) { + PROF_EVENT("CScriptBinder::save"); if (m_object) { try @@ -230,6 +235,7 @@ void CScriptBinder::save(NET_Packet& output_packet) void CScriptBinder::load(IReader& input_packet) { + PROF_EVENT("CScriptBinder::load"); if (m_object) { try @@ -261,6 +267,7 @@ BOOL CScriptBinder::net_SaveRelevant() void CScriptBinder::net_Relcase(CObject* object) { + PROF_EVENT("CScriptBinder::net_Relcase"); CGameObject* game_object = smart_cast(object); if (m_object && game_object) { diff --git a/src/xrGame/script_binder_object_wrapper.cpp b/src/xrGame/script_binder_object_wrapper.cpp index 8cc80cf7d3..22cb52583e 100644 --- a/src/xrGame/script_binder_object_wrapper.cpp +++ b/src/xrGame/script_binder_object_wrapper.cpp @@ -122,7 +122,7 @@ bool CScriptBinderObjectWrapper::net_SaveRelevant_static(CScriptBinderObject* sc void CScriptBinderObjectWrapper::net_Relcase(CScriptGameObject* object) { - ::luabind::call_member(this, "net_Relcase", object); + //::luabind::call_member(this, "net_Relcase", object); } void CScriptBinderObjectWrapper::net_Relcase_static(CScriptBinderObject* script_binder_object, diff --git a/src/xrGame/script_entity.cpp b/src/xrGame/script_entity.cpp index fba87dc1c3..20dc51a450 100644 --- a/src/xrGame/script_entity.cpp +++ b/src/xrGame/script_entity.cpp @@ -14,7 +14,6 @@ #include "../Include/xrRender/Kinematics.h" #include "script_entity_action.h" #include "weapon.h" -#include "ParticlesObject.h" #include "script_game_object.h" #include "script_engine.h" #include "movement_manager_space.h" @@ -205,6 +204,9 @@ void __stdcall ActionCallback(IKinematics* tpKinematics) if (!tpKinematics) return; + if (!tpKinematics->GetUpdateCallbackParam()) + return; + // sounds CScriptEntity* l_tpScriptMonster = smart_cast( (CGameObject*)(tpKinematics->GetUpdateCallbackParam())); @@ -224,7 +226,11 @@ void __stdcall ActionCallback(IKinematics* tpKinematics) l_tpScriptMonster->vfUpdateSounds(); l_tpScriptMonster->vfUpdateParticles(); } - catch(...) + catch (std::exception& e) + { + Msg("ActionCallback error: %s", e.what()); + } + catch (...) { } @@ -233,10 +239,12 @@ void __stdcall ActionCallback(IKinematics* tpKinematics) void CScriptEntity::vfUpdateParticles() { + if (!GetCurrentAction()) + return; CScriptParticleAction& l_tParticleAction = GetCurrentAction()->m_tParticleAction; if (xr_strlen(l_tParticleAction.m_caBoneName)) { - CParticlesObject* l_tpParticlesObject = l_tParticleAction.m_tpParticleSystem; + intrusive_ptr l_tpParticlesObject = l_tParticleAction.m_tpParticleSystem; l_tpParticlesObject->UpdateParent( GetUpdatedMatrix(l_tParticleAction.m_caBoneName, l_tParticleAction.m_tParticlePosition, l_tParticleAction.m_tParticleAngles), l_tParticleAction.m_tParticleVelocity); @@ -260,7 +268,7 @@ void CScriptEntity::vfFinishAction(CScriptEntityAction* tpEntityAction) xr_delete(m_current_sound); } if (!tpEntityAction->m_tParticleAction.m_bAutoRemove) - CParticlesObject::Destroy(tpEntityAction->m_tParticleAction.m_tpParticleSystem); + Particles::Details::Destroy(tpEntityAction->m_tParticleAction.m_tpParticleSystem); } void CScriptEntity::ProcessScripts() @@ -631,7 +639,10 @@ BOOL CScriptEntity::net_Spawn(CSE_Abstract* DC) void CScriptEntity::shedule_Update(u32 DT) { if (m_bScriptControl) + { + PROF_EVENT("CScriptEntity::shedule_Update"); ProcessScripts(); + } } void ScriptCallBack(CBlend* B) @@ -704,6 +715,7 @@ bool CScriptEntity::bfScriptAnimation() void CScriptEntity::UpdateCL() { + PROF_EVENT("CScriptEntity::UpdateCL"); bfScriptAnimation(); } @@ -719,6 +731,7 @@ const CScriptEntityAction* CScriptEntity::GetActionByIndex(u32 action_index) con void CScriptEntity::sound_callback(const CObject* object, int sound_type, const Fvector& position, float sound_power) { + PROF_EVENT("IGame_Level::SoundEvent_Dispatch"); if (!smart_cast(object)) return; @@ -752,10 +765,12 @@ int CScriptEntity::get_enemy_strength() void CScriptEntity::process_sound_callbacks() { + PROF_EVENT("CScriptEntity::process_sound_callbacks"); xr_vector::const_iterator I = m_saved_sounds.begin(); xr_vector::const_iterator E = m_saved_sounds.end(); for (; I != E; ++I) { + PROF_EVENT("suund_lua_call"); object().callback(GameObject::eSound)( object().lua_game_object(), (*I).m_game_object_id, diff --git a/src/xrGame/script_game_object.cpp b/src/xrGame/script_game_object.cpp index 67535c355d..43c7ac9645 100644 --- a/src/xrGame/script_game_object.cpp +++ b/src/xrGame/script_game_object.cpp @@ -184,7 +184,7 @@ void CScriptGameObject::ResetActionQueue() CScriptEntity* l_tpScriptMonster = smart_cast(&object()); if (!l_tpScriptMonster) ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CSciptEntity : cannot access class member ResetActionQueue!"); + make_string("CSciptEntity [%s]: cannot access class member ResetActionQueue!", object().cNameSect().c_str()).c_str()); else l_tpScriptMonster->ClearActionQueue(); } @@ -194,7 +194,7 @@ CScriptEntityAction* CScriptGameObject::GetCurrentAction() const CScriptEntity* l_tpScriptMonster = smart_cast(&object()); if (!l_tpScriptMonster) ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CSciptEntity : cannot access class member GetCurrentAction!"); + make_string("CSciptEntity [%s]: cannot access class member GetCurrentAction!", object().cNameSect().c_str()).c_str()); else if (l_tpScriptMonster->GetCurrentAction()) return (xr_new(l_tpScriptMonster->GetCurrentAction())); return (0); @@ -205,7 +205,7 @@ void CScriptGameObject::AddAction(const CScriptEntityAction* tpEntityAction, boo CScriptEntity* l_tpScriptMonster = smart_cast(&object()); if (!l_tpScriptMonster) ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CSciptEntity : cannot access class member AddAction!"); + make_string("CSciptEntity [%s]: cannot access class member AddAction!", object().cNameSect().c_str()).c_str()); else l_tpScriptMonster->AddAction(tpEntityAction, bHighPriority); } @@ -216,7 +216,7 @@ const CScriptEntityAction* CScriptGameObject::GetActionByIndex(u32 action_index) if (!l_tpScriptMonster) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CScriptEntity : cannot access class member GetActionByIndex!"); + make_string("CScriptEntity [%s]: cannot access class member GetActionByIndex!", object().cNameSect().c_str()).c_str()); return (0); } else @@ -247,7 +247,7 @@ CHelicopter* CScriptGameObject::get_helicopter() if (!helicopter) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CGameObject : cannot access class member get_helicopter!"); + make_string("CGameObject [%s]: cannot access class member get_helicopter!", object().cNameSect().c_str()).c_str()); NODEFAULT; } return helicopter; @@ -288,7 +288,7 @@ LPCSTR CScriptGameObject::WhoHitName() else { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CScriptGameObject : cannot access class member WhoHitName()"); + make_string("CScriptGameObject [%s]: cannot access class member WhoHitName()", object().cNameSect().c_str()).c_str()); return NULL; } } @@ -303,7 +303,7 @@ LPCSTR CScriptGameObject::WhoHitSectionName() else { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CScriptGameObject : cannot access class member WhoHitName()"); + make_string("CScriptGameObject [%s]: cannot access class member WhoHitName()", object().cNameSect().c_str()).c_str()); return NULL; } } @@ -325,7 +325,7 @@ bool CScriptGameObject::CheckObjectVisibility(const CScriptGameObject* tpLuaGame if (!actor) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CScriptGameObject : cannot access class member CheckObjectVisibility!"); + make_string("CScriptGameObject [%s]: cannot access class member CheckObjectVisibility!", object().cNameSect().c_str()).c_str()); return (false); } return (actor->memory().visual().visible_now(&tpLuaGameObject->object())); @@ -353,7 +353,7 @@ void CScriptGameObject::set_previous_point(int point_index) CCustomMonster* monster = smart_cast(&object()); if (!monster) ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CGameObject : cannot access class member set_previous_point!"); + make_string("CGameObject [%s]: cannot access class member set_previous_point!", object().cNameSect().c_str()).c_str()); else monster->movement().patrol().set_previous_point(point_index); } @@ -363,7 +363,7 @@ void CScriptGameObject::set_start_point(int point_index) CCustomMonster* monster = smart_cast(&object()); if (!monster) ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CGameObject : cannot access class member set_start_point!"); + make_string("CGameObject [%s]: cannot access class member set_start_point!", object().cNameSect().c_str()).c_str()); else monster->movement().patrol().set_start_point(point_index); } @@ -608,7 +608,7 @@ Fmatrix CScriptGameObject::bone_transform(u16 bone_id, bool bHud) // demonized: backwards compatibility with scripts, get root bone if bone_id is BI_NONE if (bone_id == BI_NONE) { - if (strstr(Core.Params, "-dbg") && print_bone_warnings) { + if (Core.isDebug() && print_bone_warnings) { Msg("![bone_position] Incorrect bone_id provided for %s (%d), fallback to root bone", object().cNameSect_str(), object().ID()); ai().script_engine().print_stack(); } @@ -931,7 +931,7 @@ void CScriptGameObject::SetQueueSize(u32 queue_size) if (!weapon) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CWeaponMagazined : cannot access class member SetQueueSize!"); + make_string("CWeaponMagazined [%s]: cannot access class member SetQueueSize!", object().cNameSect().c_str()).c_str()); return; } weapon->SetQueueSize(queue_size); @@ -947,7 +947,7 @@ u32 CScriptGameObject::Cost() const if (!inventory_item) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CSciptEntity : cannot access class member Cost!"); + make_string("CSciptEntity [%s]: cannot access class member Cost!", object().cNameSect().c_str()).c_str()); return (false); } return (inventory_item->Cost()); @@ -959,7 +959,7 @@ float CScriptGameObject::GetCondition() const if (!inventory_item) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CSciptEntity : cannot access class member GetCondition!"); + make_string("CSciptEntity [%s]: cannot access class member GetCondition!", object().cNameSect().c_str()).c_str()); return (false); } return (inventory_item->GetCondition()); @@ -971,7 +971,7 @@ void CScriptGameObject::SetCondition(float val) if (!inventory_item) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CSciptEntity : cannot access class member SetCondition!"); + make_string("CSciptEntity [%s]: cannot access class member SetCondition!", object().cNameSect().c_str()).c_str()); return; } val -= inventory_item->GetCondition(); @@ -984,7 +984,7 @@ float CScriptGameObject::GetPowerCritical() const if (!inventory_item) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CSciptEntity : cannot access class member GetPowerCritical!"); + make_string("CSciptEntity [%s]: cannot access class member GetPowerCritical!", object().cNameSect().c_str()).c_str()); return 0.f; } return (inventory_item->GetLowestBatteryCharge()); @@ -996,7 +996,7 @@ float CScriptGameObject::GetPsyFactor() const if (!pda) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CSciptEntity : cannot access class member GetPsyFactor!"); + make_string("CSciptEntity [%s]: cannot access class member GetPsyFactor!", object().cNameSect().c_str()).c_str()); return 0.f; } return (pda->m_psy_factor); @@ -1008,7 +1008,7 @@ void CScriptGameObject::SetPsyFactor(float val) if (!pda) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CSciptEntity : cannot access class member SetPsyFactor!"); + make_string("CSciptEntity [%s]: cannot access class member SetPsyFactor!", object().cNameSect().c_str()).c_str()); return; } pda->m_psy_factor = val; @@ -1051,7 +1051,7 @@ void CScriptGameObject::eat(CScriptGameObject* item) if (!item) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CSciptEntity : cannot access class member eat!"); + make_string("CSciptEntity [%s]: cannot access class member eat!", object().cNameSect().c_str()).c_str()); return; } @@ -1059,7 +1059,7 @@ void CScriptGameObject::eat(CScriptGameObject* item) if (!inventory_item) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CSciptEntity : cannot access class member eat!"); + make_string("CSciptEntity [%s]: cannot access class member eat!", object().cNameSect().c_str()).c_str()); return; } @@ -1067,7 +1067,7 @@ void CScriptGameObject::eat(CScriptGameObject* item) if (!inventory_owner) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CSciptEntity : cannot access class member eat!"); + make_string("CSciptEntity [%s]: cannot access class member eat!", object().cNameSect().c_str()).c_str()); return; } @@ -1080,7 +1080,7 @@ bool CScriptGameObject::inside(const Fvector& position, float epsilon) const if (!space_restrictor) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CSpaceRestrictor : cannot access class member inside!"); + make_string("CSpaceRestrictor [%s]: cannot access class member inside!", object().cNameSect().c_str()).c_str()); return (false); } Fsphere sphere; @@ -1100,7 +1100,7 @@ void CScriptGameObject::set_patrol_extrapolate_callback(const ::luabind::functor if (!monster) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CCustomMonster : cannot access class member set_patrol_extrapolate_callback!"); + make_string("CCustomMonster [%s]: cannot access class member set_patrol_extrapolate_callback!", object().cNameSect().c_str()).c_str()); return; } monster->movement().patrol().extrapolate_callback().set(functor); @@ -1113,7 +1113,7 @@ void CScriptGameObject::set_patrol_extrapolate_callback(const ::luabind::functor if (!monster) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CCustomMonster : cannot access class member set_patrol_extrapolate_callback!"); + make_string("CCustomMonster [%s]: cannot access class member set_patrol_extrapolate_callback!", this->object().cNameSect().c_str()).c_str()); return; } monster->movement().patrol().extrapolate_callback().set(functor, object); @@ -1125,7 +1125,7 @@ void CScriptGameObject::set_patrol_extrapolate_callback() if (!monster) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CCustomMonster : cannot access class member set_patrol_extrapolate_callback!"); + make_string("CCustomMonster [%s]: cannot access class member set_patrol_extrapolate_callback!", object().cNameSect().c_str()).c_str()); return; } monster->movement().patrol().extrapolate_callback().clear(); @@ -1137,7 +1137,7 @@ void CScriptGameObject::extrapolate_length(float extrapolate_length) if (!monster) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CCustomMonster : cannot access class member extrapolate_length!"); + make_string("CCustomMonster [%s]: cannot access class member extrapolate_length!", object().cNameSect().c_str()).c_str()); return; } monster->movement().detail().extrapolate_length(extrapolate_length); @@ -1149,7 +1149,7 @@ float CScriptGameObject::extrapolate_length() const if (!monster) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CCustomMonster : cannot access class member extrapolate_length!"); + make_string("CCustomMonster [%s]: cannot access class member extrapolate_length!", object().cNameSect().c_str()).c_str()); return (0.f); } return (monster->movement().detail().extrapolate_length()); @@ -1161,7 +1161,7 @@ void CScriptGameObject::set_fov(float new_fov) if (!monster) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CCustomMonster : cannot access class member set_fov!"); + make_string("CCustomMonster [%s]: cannot access class member set_fov!", object().cNameSect().c_str()).c_str()); return; } monster->set_fov(new_fov); @@ -1173,7 +1173,7 @@ void CScriptGameObject::set_range(float new_range) if (!monster) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CCustomMonster : cannot access class member set_range!"); + make_string("CCustomMonster [%s]: cannot access class member set_range!", object().cNameSect().c_str()).c_str()); return; } monster->set_range(new_range); @@ -1185,7 +1185,7 @@ u32 CScriptGameObject::vertex_in_direction(u32 level_vertex_id, Fvector directio if (!monster) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CCustomMonster : cannot access class member vertex_in_direction!"); + make_string("CCustomMonster [%s]: cannot access class member vertex_in_direction!", object().cNameSect().c_str()).c_str()); return (u32(-1)); } @@ -1213,7 +1213,7 @@ bool CScriptGameObject::invulnerable() const if (!monster) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CCustomMonster : cannot access class member invulnerable!"); + make_string("CCustomMonster [%s]: cannot access class member invulnerable!", object().cNameSect().c_str()).c_str()); return (false); } @@ -1226,7 +1226,7 @@ void CScriptGameObject::invulnerable(bool invulnerable) if (!monster) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CCustomMonster : cannot access class member invulnerable!"); + make_string("CCustomMonster [%s]: cannot access class member invulnerable!", object().cNameSect().c_str()).c_str()); return; } @@ -1583,7 +1583,7 @@ void CScriptGameObject::SetShaderTexture(int id, LPCSTR shader, LPCSTR texture, } } - if (!k) + if (!k && object().Visual()) k = object().Visual()->dcast_PKinematics(); if (!k) return; diff --git a/src/xrGame/script_game_object2.cpp b/src/xrGame/script_game_object2.cpp index 4c368fc512..f78633461f 100644 --- a/src/xrGame/script_game_object2.cpp +++ b/src/xrGame/script_game_object2.cpp @@ -57,7 +57,7 @@ void CScriptGameObject::explode(u32 level_time) if (!explosive) ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CExplosive : cannot access class member explode!"); + make_string("CExplosive [%s]: cannot access class member explode!", object().cNameSect().c_str()).c_str()); else { Fvector normal; @@ -73,7 +73,7 @@ bool CScriptGameObject::active_zone_contact(u16 id) if (!script_zone) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CScriptZone : cannot access class member active_zone_contact!"); + make_string("CScriptZone [%s]: cannot access class member active_zone_contact!", object().cNameSect().c_str()).c_str()); return (false); } return (script_zone->active_contact(id)); @@ -81,11 +81,11 @@ bool CScriptGameObject::active_zone_contact(u16 id) CScriptGameObject* CScriptGameObject::best_weapon() { - CObjectHandler* object_handler = smart_cast(&object()); + CObjectHandler* object_handler = smart_cast(&object()); if (!object_handler) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CScriptEntity : cannot access class member best_weapon!"); + make_string("CScriptEntity [%s]: cannot access class member best_weapon!", object().cNameSect().c_str()).c_str()); return (0); } else @@ -104,20 +104,20 @@ CScriptGameObject* CScriptGameObject::best_weapon() void CScriptGameObject::set_item(MonsterSpace::EObjectAction object_action) { - CObjectHandler* object_handler = smart_cast(&object()); + CObjectHandler* object_handler = smart_cast(&object()); if (!object_handler) ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CObjectHandler : cannot access class member set_item!"); + make_string("CObjectHandler [%s]: cannot access class member set_item!", object().cNameSect().c_str()).c_str()); else object_handler->set_goal(object_action); } void CScriptGameObject::set_item(MonsterSpace::EObjectAction object_action, CScriptGameObject* lua_game_object) { - CObjectHandler* object_handler = smart_cast(&object()); + CObjectHandler* object_handler = smart_cast(&object()); if (!object_handler) ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CObjectHandler : cannot access class member set_item!"); + make_string("CObjectHandler [%s]: cannot access class member set_item!", object().cNameSect().c_str()).c_str()); else object_handler->set_goal(object_action, lua_game_object ? &lua_game_object->object() : 0); } @@ -125,10 +125,10 @@ void CScriptGameObject::set_item(MonsterSpace::EObjectAction object_action, CScr void CScriptGameObject::set_item(MonsterSpace::EObjectAction object_action, CScriptGameObject* lua_game_object, u32 queue_size) { - CObjectHandler* object_handler = smart_cast(&object()); + CObjectHandler* object_handler = smart_cast(&object()); if (!object_handler) ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CObjectHandler : cannot access class member set_item!"); + make_string("CObjectHandler [%s]: cannot access class member set_item!", object().cNameSect().c_str()).c_str()); else object_handler->set_goal(object_action, lua_game_object ? &lua_game_object->object() : 0, queue_size, queue_size); @@ -137,10 +137,10 @@ void CScriptGameObject::set_item(MonsterSpace::EObjectAction object_action, CScr void CScriptGameObject::set_item(MonsterSpace::EObjectAction object_action, CScriptGameObject* lua_game_object, u32 queue_size, u32 queue_interval) { - CObjectHandler* object_handler = smart_cast(&object()); + CObjectHandler* object_handler = smart_cast(&object()); if (!object_handler) ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CObjectHandler : cannot access class member set_item!"); + make_string("CObjectHandler [%s]: cannot access class member set_item!", object().cNameSect().c_str()).c_str()); else object_handler->set_goal(object_action, lua_game_object ? &lua_game_object->object() : 0, queue_size, queue_size, queue_interval, queue_interval); @@ -237,7 +237,7 @@ u32 CScriptGameObject::memory_time(const CScriptGameObject& lua_game_object) if (!monster) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CScriptEntity : cannot access class member memory!"); + make_string("CScriptEntity [%s]: cannot access class member memory!", object().cNameSect().c_str()).c_str()); return (0); } else @@ -250,7 +250,7 @@ Fvector CScriptGameObject::memory_position(const CScriptGameObject& lua_game_obj if (!monster) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CScriptEntity : cannot access class member memory!"); + make_string("CScriptEntity [%s]: cannot access class member memory!", object().cNameSect().c_str()).c_str()); return (Fvector().set(0.f, 0.f, 0.f)); } else @@ -262,7 +262,7 @@ void CScriptGameObject::enable_memory_object(CScriptGameObject* game_object, boo CCustomMonster* monster = smart_cast(&object()); if (!monster) ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CGameObject : cannot access class member enable_memory_object!"); + make_string("CGameObject [%s]: cannot access class member enable_memory_object!", object().cNameSect().c_str()).c_str()); else monster->memory().enable(&game_object->object(), enable); } @@ -273,7 +273,7 @@ const xr_vector& CScriptGameObject::not_yet_visible_object if (!monster) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CGameObject : cannot access class member not_yet_visible_objects!"); + make_string("CGameObject [%s]: cannot access class member not_yet_visible_objects!", object().cNameSect().c_str()).c_str()); NODEFAULT; } return (monster->memory().visual().not_yet_visible_objects()); @@ -285,7 +285,7 @@ float CScriptGameObject::visibility_threshold() const if (!monster) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CGameObject : cannot access class member visibility_threshold!"); + make_string("CGameObject [%s]: cannot access class member visibility_threshold!", object().cNameSect().c_str()).c_str()); NODEFAULT; } return (monster->memory().visual().visibility_threshold()); @@ -297,7 +297,7 @@ void CScriptGameObject::enable_vision(bool value) if (!monster) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CVisualMemoryManager : cannot access class member enable_vision!"); + make_string("CVisualMemoryManager [%s]: cannot access class member enable_vision!", object().cNameSect().c_str()).c_str()); return; } monster->memory().visual().enable(value); @@ -309,7 +309,7 @@ bool CScriptGameObject::vision_enabled() const if (!monster) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CVisualMemoryManager : cannot access class member vision_enabled!"); + make_string("CVisualMemoryManager [%s]: cannot access class member vision_enabled!", object().cNameSect().c_str()).c_str()); return (false); } return (monster->memory().visual().enabled()); @@ -321,7 +321,7 @@ void CScriptGameObject::set_sound_threshold(float value) if (!monster) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CSoundMemoryManager : cannot access class member set_sound_threshold!"); + make_string("CSoundMemoryManager [%s]: cannot access class member set_sound_threshold!", object().cNameSect().c_str()).c_str()); return; } monster->memory().sound().set_threshold(value); @@ -333,7 +333,7 @@ void CScriptGameObject::restore_sound_threshold() if (!monster) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CSoundMemoryManager : cannot access class member restore_sound_threshold!"); + make_string("CSoundMemoryManager [%s]: cannot access class member restore_sound_threshold!", object().cNameSect().c_str()).c_str()); return; } monster->memory().sound().restore_threshold(); @@ -509,7 +509,7 @@ void CScriptGameObject::set_ignore_monster_threshold(float ignore_monster_thresh if (!stalker) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CAI_Stalker : cannot access class member set_ignore_monster_threshold!"); + make_string("CAI_Stalker [%s]: cannot access class member set_ignore_monster_threshold!", object().cNameSect().c_str()).c_str()); return; } clamp(ignore_monster_threshold, 0.f, 1.f); @@ -522,7 +522,7 @@ void CScriptGameObject::restore_ignore_monster_threshold() if (!stalker) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CAI_Stalker : cannot access class member restore_ignore_monster_threshold!"); + make_string("CAI_Stalker [%s]: cannot access class member restore_ignore_monster_threshold!", object().cNameSect().c_str()).c_str()); return; } stalker->memory().enemy().restore_ignore_monster_threshold(); @@ -534,7 +534,7 @@ float CScriptGameObject::ignore_monster_threshold() const if (!stalker) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CAI_Stalker : cannot access class member ignore_monster_threshold!"); + make_string("CAI_Stalker [%s]: cannot access class member ignore_monster_threshold!", object().cNameSect().c_str()).c_str()); return (0.f); } return (stalker->memory().enemy().ignore_monster_threshold()); @@ -546,7 +546,7 @@ void CScriptGameObject::set_max_ignore_monster_distance(const float& max_ignore_ if (!stalker) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CAI_Stalker : cannot access class member set_max_ignore_monster_distance!"); + make_string("CAI_Stalker [%s]: cannot access class member set_max_ignore_monster_distance!", object().cNameSect().c_str()).c_str()); return; } stalker->memory().enemy().max_ignore_monster_distance(max_ignore_monster_distance); @@ -558,7 +558,7 @@ void CScriptGameObject::restore_max_ignore_monster_distance() if (!stalker) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CAI_Stalker : cannot access class member restore_max_ignore_monster_distance!"); + make_string("CAI_Stalker [%s]: cannot access class member restore_max_ignore_monster_distance!", object().cNameSect().c_str()).c_str()); return; } stalker->memory().enemy().restore_max_ignore_monster_distance(); @@ -570,7 +570,7 @@ float CScriptGameObject::max_ignore_monster_distance() const if (!stalker) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CAI_Stalker : cannot access class member max_ignore_monster_distance!"); + make_string("CAI_Stalker [%s]: cannot access class member max_ignore_monster_distance!", object().cNameSect().c_str()).c_str()); return (0.f); } return (stalker->memory().enemy().max_ignore_monster_distance()); @@ -582,7 +582,7 @@ CCar* CScriptGameObject::get_car() if (!car) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CGameObject : cannot access class member get_car!"); + make_string("CGameObject [%s]: cannot access class member get_car!", object().cNameSect().c_str()).c_str()); NODEFAULT; } return car; @@ -613,7 +613,7 @@ void CScriptGameObject::debug_planner (const script_planner *planner) { CAI_Stalker *stalker = smart_cast(&object()); if (!stalker) { - ai().script_engine().script_log (ScriptStorage::eLuaMessageTypeError,"CAI_Stalker : cannot access class member debug_planner!"); + ai().script_engine().script_log (ScriptStorage::eLuaMessageTypeError,make_string("CAI_Stalker [%s]: cannot access class member debug_planner!", object().cNameSect().c_str()).c_str()); return; } @@ -634,7 +634,7 @@ u32 CScriptGameObject::location_on_path(float distance, Fvector* location) if (!monster) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CAI_Stalker : cannot access class member location_on_path!"); + make_string("CAI_Stalker [%s]: cannot access class member location_on_path!", object().cNameSect().c_str()).c_str()); return (u32(-1)); } @@ -648,7 +648,7 @@ bool CScriptGameObject::is_there_items_to_pickup() const if (!stalker) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CAI_Stalker : cannot access class member is_there_items_to_pickup!"); + make_string("CAI_Stalker [%s]: cannot access class member is_there_items_to_pickup!", object().cNameSect().c_str()).c_str()); return false; } return (!!stalker->memory().item().selected()); diff --git a/src/xrGame/script_game_object3.cpp b/src/xrGame/script_game_object3.cpp index 1a6011629f..85348a908a 100644 --- a/src/xrGame/script_game_object3.cpp +++ b/src/xrGame/script_game_object3.cpp @@ -74,7 +74,7 @@ const CCoverPoint* CScriptGameObject::best_cover(const Fvector& position, const if (!stalker) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CGameObject : cannot access class member best_cover!"); + make_string("CGameObject [%s]: cannot access class member best_cover!", object().cNameSect().c_str()).c_str()); return (0); } stalker->m_ce_best->setup(enemy_position, min_enemy_distance, max_enemy_distance, 0.f); @@ -88,7 +88,7 @@ const CCoverPoint* CScriptGameObject::safe_cover(const Fvector& position, float if (!stalker) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CGameObject : cannot access class member best_cover!"); + make_string("CGameObject [%s]: cannot access class member best_cover!", object().cNameSect().c_str()).c_str()); return (0); } stalker->m_ce_safe->setup(min_distance); @@ -102,7 +102,7 @@ const xr_vector& CScriptGameObject::memory_visible_ if (!monster) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CGameObject : cannot access class member memory_visible_objects!"); + make_string("CGameObject [%s]: cannot access class member memory_visible_objects!", object().cNameSect().c_str()).c_str()); NODEFAULT; } return (monster->memory().visual().objects()); @@ -114,7 +114,7 @@ const xr_vector& CScriptGameObject::memory_sound_obje if (!monster) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CGameObject : cannot access class member memory_sound_objects!"); + make_string("CGameObject [%s]: cannot access class member memory_sound_objects!", object().cNameSect().c_str()).c_str()); NODEFAULT; } return (monster->memory().sound().objects()); @@ -126,7 +126,7 @@ const xr_vector& CScriptGameObject::memory_hit_objects( if (!monster) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CGameObject : cannot access class member memory_hit_objects!"); + make_string("CGameObject [%s]: cannot access class member memory_hit_objects!", object().cNameSect().c_str()).c_str()); NODEFAULT; } return (monster->memory().hit().objects()); @@ -137,7 +137,7 @@ void CScriptGameObject::ChangeTeam(u8 team, u8 squad, u8 group) CCustomMonster* custom_monster = smart_cast(&object()); if (!custom_monster) ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CCustomMonster: cannot access class member ChangeTeam!"); + make_string("CCustomMonster[%s]: cannot access class member ChangeTeam!", object().cNameSect().c_str()).c_str()); else custom_monster->ChangeTeam(team, squad, group); } @@ -147,7 +147,7 @@ void CScriptGameObject::SetVisualMemoryEnabled(bool enabled) CCustomMonster* custom_monster = smart_cast(&object()); if (!custom_monster) ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CCustomMonster: cannot access class member ChangeTeam!"); + make_string("CCustomMonster[%s]: cannot access class member ChangeTeam!", object().cNameSect().c_str()).c_str()); else custom_monster->memory().visual().enable(enabled); } @@ -244,7 +244,7 @@ CScriptGameObject* CScriptGameObject::GetEnemy() const else { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CScriptGameObject : cannot access class member GetEnemy!"); + make_string("CScriptGameObject [%s]: cannot access class member GetEnemy!", object().cNameSect().c_str()).c_str()); return (0); } } @@ -260,7 +260,7 @@ CScriptGameObject* CScriptGameObject::GetCorpse() const else { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CScriptGameObject : cannot access class member GetCorpse!"); + make_string("CScriptGameObject [%s]: cannot access class member GetCorpse!", object().cNameSect().c_str()).c_str()); return (0); } } @@ -273,7 +273,7 @@ bool CScriptGameObject::CheckTypeVisibility(const char* section_name) else { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CScriptGameObject : cannot access class member CheckTypeVisibility!"); + make_string("CScriptGameObject [%s]: cannot access class member CheckTypeVisibility!", object().cNameSect().c_str()).c_str()); return (false); } } @@ -284,7 +284,7 @@ CScriptGameObject* CScriptGameObject::GetCurrentWeapon() const if (!l_tpStalker) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CAI_Stalker : cannot access class member GetCurrentWeapon!"); + make_string("CAI_Stalker [%s]: cannot access class member GetCurrentWeapon!", object().cNameSect().c_str()).c_str()); return (0); } CGameObject* current_weapon = l_tpStalker->GetCurrentWeapon(); @@ -297,7 +297,7 @@ void CScriptGameObject::deadbody_closed(bool status) if (!inventoryOwner) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CInventoryOwner : cannot access class member deadbody_closed!"); + make_string("CInventoryOwner [%s]: cannot access class member deadbody_closed!", object().cNameSect().c_str()).c_str()); return; } inventoryOwner->deadbody_closed(status); @@ -309,7 +309,7 @@ bool CScriptGameObject::deadbody_closed_status() if (!inventoryOwner) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CInventoryOwner : cannot access class member deadbody_closed_status!"); + make_string("CInventoryOwner [%s]: cannot access class member deadbody_closed_status!", object().cNameSect().c_str()).c_str()); return (0); } return inventoryOwner->deadbody_closed_status(); @@ -321,7 +321,7 @@ void CScriptGameObject::can_select_weapon(bool status) if (!stalker) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CAI_Stalker : cannot access class member can_select_weapon!"); + make_string("CAI_Stalker [%s]: cannot access class member can_select_weapon!", object().cNameSect().c_str()).c_str()); return; } stalker->can_select_weapon(status); @@ -333,7 +333,7 @@ bool CScriptGameObject::can_select_weapon() const if (!stalker) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CAI_Stalker : cannot access class member can_select_weapon!"); + make_string("CAI_Stalker [%s]: cannot access class member can_select_weapon!", object().cNameSect().c_str()).c_str()); return (0); } return stalker->can_select_weapon(); @@ -345,7 +345,7 @@ void CScriptGameObject::deadbody_can_take(bool status) if (!inventoryOwner) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CInventoryOwner : cannot access class member deadbody_can_take!"); + make_string("CInventoryOwner [%s]: cannot access class member deadbody_can_take!", object().cNameSect().c_str()).c_str()); return; } inventoryOwner->deadbody_can_take(status); @@ -357,7 +357,7 @@ bool CScriptGameObject::deadbody_can_take_status() if (!inventoryOwner) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CInventoryOwner : cannot access class member deadbody_can_take_status!"); + make_string("CInventoryOwner [%s]: cannot access class member deadbody_can_take_status!", object().cNameSect().c_str()).c_str()); return (0); } return inventoryOwner->deadbody_can_take_status(); @@ -371,7 +371,7 @@ CScriptGameObject* CScriptGameObject::GetCurrentOutfit() const if (!inventoryOwner) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CInventoryOwner : cannot access class member GetCurrentOutfit!"); + make_string("CInventoryOwner [%s]: cannot access class member GetCurrentOutfit!", object().cNameSect().c_str()).c_str()); return (0); } CGameObject* current_equipment = inventoryOwner->GetOutfit(); @@ -385,7 +385,7 @@ float CScriptGameObject::GetCurrentOutfitProtection(int hit_type) if (!inventoryOwner) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CInventoryOwner : cannot access class member GetCurrentOutfitProtection!"); + make_string("CInventoryOwner [%s]: cannot access class member GetCurrentOutfitProtection!", object().cNameSect().c_str()).c_str()); return (0); } CGameObject* current_equipment = inventoryOwner->GetOutfit(); @@ -401,7 +401,7 @@ CScriptGameObject* CScriptGameObject::GetFood() const if (!l_tpStalker) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CAI_Stalker : cannot access class member GetFood!"); + make_string("CAI_Stalker [%s]: cannot access class member GetFood!", object().cNameSect().c_str()).c_str()); return (0); } CGameObject* food = l_tpStalker->GetFood() ? &l_tpStalker->GetFood()->object() : 0; @@ -414,7 +414,7 @@ CScriptGameObject* CScriptGameObject::GetMedikit() const if (!l_tpStalker) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CAI_Stalker : cannot access class member GetCurrentWeapon!"); + make_string("CAI_Stalker [%s]: cannot access class member GetCurrentWeapon!", object().cNameSect().c_str()).c_str()); return (0); } CGameObject* medikit = l_tpStalker->GetMedikit() ? &l_tpStalker->GetMedikit()->object() : 0; @@ -430,7 +430,7 @@ LPCSTR CScriptGameObject::GetPatrolPathName() if (!script_monster) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CGameObject : cannot access class member GetPatrolPathName!"); + make_string("CGameObject [%s]: cannot access class member GetPatrolPathName!", object().cNameSect().c_str()).c_str()); return (""); } else @@ -446,7 +446,7 @@ void CScriptGameObject::add_animation(LPCSTR animation, bool hand_usage, bool us if (!stalker) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CGameObject : cannot access class member add_animation!"); + make_string("CGameObject [%s]: cannot access class member add_animation!", object().cNameSect().c_str()).c_str()); return; } @@ -479,7 +479,7 @@ void CScriptGameObject::add_animation(LPCSTR animation, bool hand_usage, Fvector if (!stalker) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CGameObject : cannot access class member add_animation!"); + make_string("CGameObject [%s]: cannot access class member add_animation!", object().cNameSect().c_str()).c_str()); return; } @@ -511,7 +511,7 @@ void CScriptGameObject::clear_animations() if (!stalker) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CGameObject : cannot access class member clear_animations!"); + make_string("CGameObject [%s]: cannot access class member clear_animations!", object().cNameSect().c_str()).c_str()); return; } stalker->animation().clear_script_animations(); @@ -523,7 +523,7 @@ int CScriptGameObject::animation_count() const if (!stalker) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CGameObject : cannot access class member clear_animations!"); + make_string("CGameObject [%s]: cannot access class member clear_animations!", object().cNameSect().c_str()).c_str()); return (-1); } return ((int)stalker->animation().script_animations().size()); @@ -550,7 +550,7 @@ void CScriptGameObject::set_patrol_path(LPCSTR path_name, const PatrolPathManage CAI_Stalker* stalker = smart_cast(&object()); if (!stalker) ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CAI_Stalker : cannot access class member movement!"); + make_string("CAI_Stalker [%s]: cannot access class member movement!", object().cNameSect().c_str()).c_str()); else stalker->movement().patrol().set_path(path_name, patrol_start_type, patrol_route_type, random); } @@ -560,7 +560,7 @@ void CScriptGameObject::inactualize_patrol_path() CAI_Stalker* stalker = smart_cast(&object()); if (!stalker) ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CAI_Stalker : cannot access class member movement!"); + make_string("CAI_Stalker [%s]: cannot access class member movement!", object().cNameSect().c_str()).c_str()); else stalker->movement().patrol().make_inactual(); } @@ -570,7 +570,7 @@ void CScriptGameObject::set_dest_level_vertex_id(u32 level_vertex_id) CAI_Stalker* stalker = smart_cast(&object()); if (!stalker) ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CAI_Stalker : cannot access class member set_dest_level_vertex_id!"); + make_string("CAI_Stalker [%s]: cannot access class member set_dest_level_vertex_id!", object().cNameSect().c_str()).c_str()); else { if (!ai().level_graph().valid_vertex_id(level_vertex_id)) @@ -600,7 +600,7 @@ void CScriptGameObject::set_dest_game_vertex_id(GameGraph::_GRAPH_ID game_vertex CAI_Stalker* stalker = smart_cast(&object()); if (!stalker) ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CAI_Stalker : cannot access class member set_dest_game_vertex_id!"); + make_string("CAI_Stalker [%s]: cannot access class member set_dest_game_vertex_id!", object().cNameSect().c_str()).c_str()); else { if (!ai().game_graph().valid_vertex_id(game_vertex_id)) @@ -619,7 +619,7 @@ void CScriptGameObject::set_movement_selection_type(ESelectionType selection_typ CAI_Stalker* stalker = smart_cast(&object()); if (!stalker) ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CAI_Stalker : cannot access class member set_movement_selection_type!"); + make_string("CAI_Stalker [%s]: cannot access class member set_movement_selection_type!", object().cNameSect().c_str()).c_str()); stalker->movement().game_selector().set_selection_type(selection_type); } @@ -629,7 +629,7 @@ CHARACTER_RANK_VALUE CScriptGameObject::GetRank() if (!stalker) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CAI_Stalker : cannot access class member GetRank!"); + make_string("CAI_Stalker [%s]: cannot access class member GetRank!", object().cNameSect().c_str()).c_str()); return (CHARACTER_RANK_VALUE(0)); } else @@ -712,7 +712,7 @@ void CScriptGameObject::set_desired_position() CAI_Stalker* stalker = smart_cast(&object()); if (!stalker) ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CAI_Stalker : cannot access class member movement!"); + make_string("CAI_Stalker [%s]: cannot access class member movement!", object().cNameSect().c_str()).c_str()); else stalker->movement().set_desired_position(0); } @@ -722,7 +722,7 @@ void CScriptGameObject::set_desired_position(const Fvector* desired_position) CAI_Stalker* stalker = smart_cast(&object()); if (!stalker) ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CAI_Stalker : cannot access class member movement!"); + make_string("CAI_Stalker [%s]: cannot access class member movement!", object().cNameSect().c_str()).c_str()); else { THROW2(desired_position || stalker->movement().restrictions().accessible(*desired_position), *stalker->cName()); @@ -735,7 +735,7 @@ void CScriptGameObject::set_desired_direction() CAI_Stalker* stalker = smart_cast(&object()); if (!stalker) ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CAI_Stalker : cannot access class member movement!"); + make_string("CAI_Stalker [%s]: cannot access class member movement!", object().cNameSect().c_str()).c_str()); else stalker->movement().set_desired_direction(0); } @@ -745,7 +745,7 @@ void CScriptGameObject::set_desired_direction(const Fvector* desired_direction) CAI_Stalker* stalker = smart_cast(&object()); if (!stalker) ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CAI_Stalker : cannot access class member movement!"); + make_string("CAI_Stalker [%s]: cannot access class member movement!", object().cNameSect().c_str()).c_str()); else { if (fsimilar(desired_direction->magnitude(), 0.f)) @@ -772,7 +772,7 @@ void CScriptGameObject::set_body_state(EBodyState body_state) CAI_Stalker* stalker = smart_cast(&object()); if (!stalker) ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CAI_Stalker : cannot access class member movement!"); + make_string("CAI_Stalker [%s]: cannot access class member movement!", object().cNameSect().c_str()).c_str()); else stalker->movement().set_body_state(body_state); } @@ -782,7 +782,7 @@ void CScriptGameObject::set_movement_type(EMovementType movement_type) CAI_Stalker* stalker = smart_cast(&object()); if (!stalker) ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CAI_Stalker : cannot access class member movement!"); + make_string("CAI_Stalker [%s]: cannot access class member movement!", object().cNameSect().c_str()).c_str()); else stalker->movement().set_movement_type(movement_type); } @@ -792,7 +792,7 @@ void CScriptGameObject::set_mental_state(EMentalState mental_state) CAI_Stalker* stalker = smart_cast(&object()); if (!stalker) ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CAI_Stalker : cannot access class member movement!"); + make_string("CAI_Stalker [%s]: cannot access class member movement!", object().cNameSect().c_str()).c_str()); else { #if 0//def DEBUG @@ -814,7 +814,7 @@ void CScriptGameObject::set_path_type(MovementManager::EPathType path_type) CAI_Stalker* stalker = smart_cast(&object()); if (!stalker) ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CAI_Stalker : cannot access class member movement!"); + make_string("CAI_Stalker [%s]: cannot access class member movement!", object().cNameSect().c_str()).c_str()); else stalker->movement().set_path_type(path_type); } @@ -824,7 +824,7 @@ void CScriptGameObject::set_detail_path_type(DetailPathManager::EDetailPathType CAI_Stalker* stalker = smart_cast(&object()); if (!stalker) ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CAI_Stalker : cannot access class member movement!"); + make_string("CAI_Stalker [%s]: cannot access class member movement!", object().cNameSect().c_str()).c_str()); else stalker->movement().set_detail_path_type(detail_path_type); } @@ -835,7 +835,7 @@ MonsterSpace::EBodyState CScriptGameObject::body_state() const if (!stalker) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CAI_Stalker : cannot access class member body_state!"); + make_string("CAI_Stalker [%s]: cannot access class member body_state!", object().cNameSect().c_str()).c_str()); return (MonsterSpace::eBodyStateStand); } return (stalker->movement().body_state()); @@ -847,7 +847,7 @@ MonsterSpace::EBodyState CScriptGameObject::target_body_state() const if (!stalker) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CAI_Stalker : cannot access class member body_state!"); + make_string("CAI_Stalker [%s]: cannot access class member body_state!", object().cNameSect().c_str()).c_str()); return (MonsterSpace::eBodyStateStand); } return (stalker->movement().target_body_state()); @@ -859,7 +859,7 @@ MonsterSpace::EMovementType CScriptGameObject::movement_type() const if (!stalker) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CAI_Stalker : cannot access class member movement_type!"); + make_string("CAI_Stalker [%s]: cannot access class member movement_type!", object().cNameSect().c_str()).c_str()); return (MonsterSpace::eMovementTypeStand); } return (stalker->movement().movement_type()); @@ -871,7 +871,7 @@ MonsterSpace::EMovementType CScriptGameObject::target_movement_type() const if (!stalker) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CAI_Stalker : cannot access class member target_movement_type!"); + make_string("CAI_Stalker [%s]: cannot access class member target_movement_type!", object().cNameSect().c_str()).c_str()); return (MonsterSpace::eMovementTypeStand); } return (stalker->movement().target_movement_type()); @@ -883,7 +883,7 @@ MonsterSpace::EMentalState CScriptGameObject::mental_state() const if (!stalker) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CAI_Stalker : cannot access class member mental_state!"); + make_string("CAI_Stalker [%s]: cannot access class member mental_state!", object().cNameSect().c_str()).c_str()); return (MonsterSpace::eMentalStateDanger); } return (stalker->movement().mental_state()); @@ -895,7 +895,7 @@ MonsterSpace::EMentalState CScriptGameObject::target_mental_state() const if (!stalker) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CAI_Stalker : cannot access class member mental_state!"); + make_string("CAI_Stalker [%s]: cannot access class member mental_state!", object().cNameSect().c_str()).c_str()); return (MonsterSpace::eMentalStateDanger); } return (stalker->movement().target_mental_state()); @@ -907,7 +907,7 @@ MovementManager::EPathType CScriptGameObject::path_type() const if (!stalker) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CAI_Stalker : cannot access class member path_type!"); + make_string("CAI_Stalker [%s]: cannot access class member path_type!", object().cNameSect().c_str()).c_str()); return (MovementManager::ePathTypeNoPath); } return (stalker->movement().path_type()); @@ -919,7 +919,7 @@ DetailPathManager::EDetailPathType CScriptGameObject::detail_path_type() const if (!stalker) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CAI_Stalker : cannot access class member detail_path_type!"); + make_string("CAI_Stalker [%s]: cannot access class member detail_path_type!", object().cNameSect().c_str()).c_str()); return (DetailPathManager::eDetailPathTypeSmooth); } return (DetailPathManager::eDetailPathTypeSmooth); @@ -930,7 +930,7 @@ void CScriptGameObject::set_sight(SightManager::ESightType sight_type, Fvector* CAI_Stalker* stalker = smart_cast(&object()); if (!stalker) ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CSightManager : cannot access class member set_sight!"); + make_string("CSightManager [%s]: cannot access class member set_sight!", object().cNameSect().c_str()).c_str()); else { if ((sight_type == SightManager::eSightTypeDirection) && vector3d && (_abs(vector3d->magnitude() - 1.f) > .01f)) @@ -948,7 +948,7 @@ void CScriptGameObject::set_sight(SightManager::ESightType sight_type, bool tors CAI_Stalker* stalker = smart_cast(&object()); if (!stalker) ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CSightManager : cannot access class member set_sight!"); + make_string("CSightManager [%s]: cannot access class member set_sight!", object().cNameSect().c_str()).c_str()); else stalker->sight().setup(sight_type, torso_look, path); } @@ -958,7 +958,7 @@ void CScriptGameObject::set_sight(SightManager::ESightType sight_type, Fvector& CAI_Stalker* stalker = smart_cast(&object()); if (!stalker) ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CSightManager : cannot access class member set_sight!"); + make_string("CSightManager [%s]: cannot access class member set_sight!", object().cNameSect().c_str()).c_str()); else { if ((sight_type == SightManager::eSightTypeDirection) && (_abs(vector3d.magnitude() - 1.f) > .01f)) @@ -976,7 +976,7 @@ void CScriptGameObject::set_sight(SightManager::ESightType sight_type, Fvector* CAI_Stalker* stalker = smart_cast(&object()); if (!stalker) ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CSightManager : cannot access class member set_sight!"); + make_string("CSightManager [%s]: cannot access class member set_sight!", object().cNameSect().c_str()).c_str()); else { if ((sight_type == SightManager::eSightTypeDirection) && vector3d && (_abs(vector3d->magnitude() - 1.f) > .01f)) @@ -994,7 +994,7 @@ void CScriptGameObject::set_sight(CScriptGameObject* object_to_look) CAI_Stalker* stalker = smart_cast(&object()); if (!stalker) ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CSightManager : cannot access class member set_sight!"); + make_string("CSightManager [%s]: cannot access class member set_sight!", object().cNameSect().c_str()).c_str()); else stalker->sight().setup(&object_to_look->object()); } @@ -1004,7 +1004,7 @@ void CScriptGameObject::set_sight(CScriptGameObject* object_to_look, bool torso_ CAI_Stalker* stalker = smart_cast(&object()); if (!stalker) ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CSightManager : cannot access class member set_sight!"); + make_string("CSightManager [%s]: cannot access class member set_sight!", object().cNameSect().c_str()).c_str()); else stalker->sight().setup(&object_to_look->object(), torso_look); } @@ -1014,7 +1014,7 @@ void CScriptGameObject::set_sight(CScriptGameObject* object_to_look, bool torso_ CAI_Stalker* stalker = smart_cast(&object()); if (!stalker) ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CSightManager : cannot access class member set_sight!"); + make_string("CSightManager [%s]: cannot access class member set_sight!", object().cNameSect().c_str()).c_str()); else stalker->sight().setup(&object_to_look->object(), torso_look, fire_object); } @@ -1024,7 +1024,7 @@ void CScriptGameObject::set_sight(CScriptGameObject* object_to_look, bool torso_ CAI_Stalker* stalker = smart_cast(&object()); if (!stalker) ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CSightManager : cannot access class member set_sight!"); + make_string("CSightManager [%s]: cannot access class member set_sight!", object().cNameSect().c_str()).c_str()); else stalker->sight().setup(CSightAction(&object_to_look->object(), torso_look, fire_object, no_pitch)); } @@ -1034,7 +1034,7 @@ void CScriptGameObject::set_sight(const CMemoryInfo* memory_object, bool torso_l CAI_Stalker* stalker = smart_cast(&object()); if (!stalker) ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CSightManager : cannot access class member set_sight!"); + make_string("CSightManager [%s]: cannot access class member set_sight!", object().cNameSect().c_str()).c_str()); else stalker->sight().setup(memory_object, torso_look); } @@ -1052,7 +1052,7 @@ u32 CScriptGameObject::GetInventoryObjectCount() const else { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CScriptGameObject : cannot access class member obj_count!"); + make_string("CScriptGameObject [%s]: cannot access class member obj_count!", object().cNameSect().c_str()).c_str()); return (0); } } @@ -1068,7 +1068,7 @@ CScriptGameObject* CScriptGameObject::GetActiveItem() else { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CScriptGameObject : cannot access class member activge_item!"); + make_string("CScriptGameObject [%s]: cannot access class member activge_item!", object().cNameSect().c_str()).c_str()); return (0); } } @@ -1102,7 +1102,7 @@ CScriptGameObject* CScriptGameObject::GetObjectByName(LPCSTR caObjectName) const else { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CScriptGameObject : cannot access class member object!"); + make_string("CScriptGameObject [%s]: cannot access class member object!", object().cNameSect().c_str()).c_str()); return (0); } } @@ -1122,7 +1122,7 @@ CScriptGameObject* CScriptGameObject::GetObjectByIndex(int iIndex) const else { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CScriptGameObject : cannot access class member object!"); + make_string("CScriptGameObject [%s]: cannot access class member object!", object().cNameSect().c_str()).c_str()); return (0); } } @@ -1158,7 +1158,7 @@ CScriptGameObject* CScriptGameObject::GetObjectById(u16 id) const else { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CScriptGameObject : cannot access class member object_id!"); + make_string("CScriptGameObject [%s]: cannot access class member object_id!", object().cNameSect().c_str()).c_str()); return (0); } } @@ -1261,7 +1261,7 @@ bool CScriptGameObject::weapon_strapped() const if (!stalker) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CScriptGameObject : cannot access class member weapon_strapped!"); + make_string("CScriptGameObject [%s]: cannot access class member weapon_strapped!", object().cNameSect().c_str()).c_str()); return (false); } @@ -1276,7 +1276,7 @@ bool CScriptGameObject::weapon_unstrapped() const if (!stalker) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CScriptGameObject : cannot access class member weapon_unstrapped!"); + make_string("CScriptGameObject [%s]: cannot access class member weapon_unstrapped!", object().cNameSect().c_str()).c_str()); return (false); } bool const result = stalker->weapon_unstrapped(); @@ -1290,7 +1290,7 @@ bool CScriptGameObject::path_completed() const if (!monster) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CScriptGameObject : cannot access class member path_completed!"); + make_string("CScriptGameObject [%s]: cannot access class member path_completed!", object().cNameSect().c_str()).c_str()); return (false); } return (monster->movement().path_completed()); @@ -1302,7 +1302,7 @@ void CScriptGameObject::patrol_path_make_inactual() if (!monster) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CScriptGameObject : cannot access class member patrol_path_make_inactual!"); + make_string("CScriptGameObject [%s]: cannot access class member patrol_path_make_inactual!", object().cNameSect().c_str()).c_str()); return; } monster->movement().patrol().make_inactual(); @@ -1315,7 +1315,7 @@ Fvector CScriptGameObject::head_orientation() const if (!stalker) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CScriptGameObject : cannot access class member head_orientation!"); + make_string("CScriptGameObject [%s]: cannot access class member head_orientation!", object().cNameSect().c_str()).c_str()); return (Fvector().set(flt_max,flt_max,flt_max)); } const SRotation& r = stalker->movement().head_orientation().current; @@ -1356,7 +1356,7 @@ void CScriptGameObject::make_object_visible_somewhen(CScriptGameObject* object) if (!stalker) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CAI_Stalker : cannot access class member make_object_visible_somewhen!"); + make_string("CAI_Stalker [%s]: cannot access class member make_object_visible_somewhen!", this->object().cNameSect().c_str()).c_str()); return; } @@ -1364,7 +1364,7 @@ void CScriptGameObject::make_object_visible_somewhen(CScriptGameObject* object) if (!entity_alive) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CEntityAlive : cannot access class member make_object_visible_somewhen!"); + make_string("CEntityAlive [%s]: cannot access class member make_object_visible_somewhen!", this->object().cNameSect().c_str()).c_str()); return; } @@ -1377,7 +1377,7 @@ void CScriptGameObject::sell_condition(CScriptIniFile* ini_file, LPCSTR section) if (!inventory_owner) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CInventoryOwner : cannot access class member sell_condition!"); + make_string("CInventoryOwner [%s]: cannot access class member sell_condition!", object().cNameSect().c_str()).c_str()); return; } @@ -1390,7 +1390,7 @@ void CScriptGameObject::sell_condition(float friend_factor, float enemy_factor) if (!inventory_owner) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CInventoryOwner : cannot access class member sell_condition!"); + make_string("CInventoryOwner [%s]: cannot access class member sell_condition!", object().cNameSect().c_str()).c_str()); return; } @@ -1409,7 +1409,7 @@ void CScriptGameObject::buy_condition(CScriptIniFile* ini_file, LPCSTR section) if (!inventory_owner) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CInventoryOwner : cannot access class member buy_condition!"); + make_string("CInventoryOwner [%s]: cannot access class member buy_condition!", object().cNameSect().c_str()).c_str()); return; } @@ -1422,7 +1422,7 @@ void CScriptGameObject::buy_condition(float friend_factor, float enemy_factor) if (!inventory_owner) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CInventoryOwner : cannot access class member buy_condition!"); + make_string("CInventoryOwner [%s]: cannot access class member buy_condition!", object().cNameSect().c_str()).c_str()); return; } @@ -1441,7 +1441,7 @@ void CScriptGameObject::show_condition(CScriptIniFile* ini_file, LPCSTR section) if (!inventory_owner) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CInventoryOwner : cannot access class member show_condition!"); + make_string("CInventoryOwner [%s]: cannot access class member show_condition!", object().cNameSect().c_str()).c_str()); return; } @@ -1458,7 +1458,7 @@ void CScriptGameObject::buy_supplies(CScriptIniFile* ini_file, LPCSTR section) if (!inventory_owner) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CInventoryOwner : cannot access class member buy_condition!"); + make_string("CInventoryOwner [%s]: cannot access class member buy_condition!", object().cNameSect().c_str()).c_str()); return; } @@ -1474,7 +1474,7 @@ void CScriptGameObject::buy_item_condition_factor(float factor) if (!inventory_owner) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CInventoryOwner : cannot access class member buy_item_condition_factor!"); + make_string("CInventoryOwner [%s]: cannot access class member buy_item_condition_factor!", object().cNameSect().c_str()).c_str()); return; } @@ -1487,7 +1487,7 @@ void CScriptGameObject::buy_item_exponent(float factor) if (!inventory_owner) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CInventoryOwner : cannot access class member buy_item_exponent!"); + make_string("CInventoryOwner [%s]: cannot access class member buy_item_exponent!", object().cNameSect().c_str()).c_str()); return; } @@ -1500,7 +1500,7 @@ void CScriptGameObject::sell_item_exponent(float factor) if (!inventory_owner) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CInventoryOwner : cannot access class member sell_item_exponent!"); + make_string("CInventoryOwner [%s]: cannot access class member sell_item_exponent!", object().cNameSect().c_str()).c_str()); return; } @@ -1550,7 +1550,7 @@ LPCSTR CScriptGameObject::sound_prefix() const if (!custom_monster) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CCustomMonster : cannot access class member sound_prefix!"); + make_string("CCustomMonster [%s]: cannot access class member sound_prefix!", object().cNameSect().c_str()).c_str()); return (0); } @@ -1563,7 +1563,7 @@ void CScriptGameObject::sound_prefix(LPCSTR sound_prefix) if (!custom_monster) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CCustomMonster : cannot access class member sound_prefix!"); + make_string("CCustomMonster [%s]: cannot access class member sound_prefix!", object().cNameSect().c_str()).c_str()); return; } @@ -1575,7 +1575,7 @@ bool CScriptGameObject::is_weapon_going_to_be_strapped(CScriptGameObject const* if (!object) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CGameObject : cannot access class member is_weapon_going_to_be_strapped (object passed is null)!"); + make_string("CGameObject [%s]: cannot access class member is_weapon_going_to_be_strapped (object passed is null)!", this->object().cNameSect().c_str()).c_str()); return false; } @@ -1583,7 +1583,7 @@ bool CScriptGameObject::is_weapon_going_to_be_strapped(CScriptGameObject const* if (!stalker) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CGameObject : cannot access class member is_weapon_going_to_be_strapped!"); + make_string("CGameObject [%s]: cannot access class member is_weapon_going_to_be_strapped!", this->object().cNameSect().c_str()).c_str()); return false; } @@ -2089,12 +2089,12 @@ void CScriptGameObject::IterateFeelTouch(::luabind::functor functor) void CScriptGameObject::SetSpatialType(u32 sptype) { - object().spatial.type = sptype; + object().SpatialComponent->spatial.type = sptype; } u32 CScriptGameObject::GetSpatialType() { - return object().spatial.type; + return object().SpatialComponent->spatial.type; } void CScriptGameObject::DestroyObject() @@ -2176,7 +2176,7 @@ bool CScriptGameObject::get_enable_anomalies_pathfinding() if (!stalker) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CGameObject : cannot access class member m_enable_anomalies_pathfinding!"); + make_string("CGameObject [%s]: cannot access class member m_enable_anomalies_pathfinding!", object().cNameSect().c_str()).c_str()); return false; } return stalker->m_enable_anomalies_pathfinding; @@ -2187,7 +2187,7 @@ void CScriptGameObject::set_enable_anomalies_pathfinding(bool v) if (!stalker) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CGameObject : cannot access class member m_enable_anomalies_pathfinding!"); + make_string("CGameObject [%s]: cannot access class member m_enable_anomalies_pathfinding!", object().cNameSect().c_str()).c_str()); return; } stalker->m_enable_anomalies_pathfinding = v; @@ -2198,7 +2198,7 @@ bool CScriptGameObject::get_enable_anomalies_damage() if (!stalker) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CGameObject : cannot access class member m_enable_anomalies_damage!"); + make_string("CGameObject [%s]: cannot access class member m_enable_anomalies_damage!", object().cNameSect().c_str()).c_str()); return false; } return stalker->m_enable_anomalies_damage; @@ -2209,7 +2209,7 @@ void CScriptGameObject::set_enable_anomalies_damage(bool v) if (!stalker) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CGameObject : cannot access class member m_enable_anomalies_damage!"); + make_string("CGameObject [%s]: cannot access class member m_enable_anomalies_damage!", object().cNameSect().c_str()).c_str()); return; } stalker->m_enable_anomalies_damage = v; diff --git a/src/xrGame/script_game_object4.cpp b/src/xrGame/script_game_object4.cpp index 23ddd872ea..8caf15c9f4 100644 --- a/src/xrGame/script_game_object4.cpp +++ b/src/xrGame/script_game_object4.cpp @@ -64,7 +64,7 @@ bool CScriptGameObject::is_body_turning() const if (!monster) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CGameObject : cannot access class member is_turning!"); + make_string("CGameObject [%s]: cannot access class member is_turning!", object().cNameSect().c_str()).c_str()); return (false); } @@ -90,7 +90,7 @@ u32 CScriptGameObject::add_sound(LPCSTR prefix, u32 max_count, ESoundTypes type, if (!monster) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CSoundPlayer : cannot access class member add!"); + make_string("CSoundPlayer [%s]: cannot access class member add!", object().cNameSect().c_str()).c_str()); return (0); } else @@ -104,7 +104,7 @@ u32 CScriptGameObject::add_combat_sound(LPCSTR prefix, u32 max_count, ESoundType if (!stalker) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CSoundPlayer : cannot access class member add!"); + make_string("CSoundPlayer [%s]: cannot access class member add!", object().cNameSect().c_str()).c_str()); return (0); } else @@ -123,7 +123,7 @@ void CScriptGameObject::remove_sound(u32 internal_type) CCustomMonster* monster = smart_cast(&object()); if (!monster) ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CSoundPlayer : cannot access class member add!"); + make_string("CSoundPlayer [%s]: cannot access class member add!", object().cNameSect().c_str()).c_str()); else monster->sound().remove(internal_type); } @@ -133,7 +133,7 @@ void CScriptGameObject::set_sound_mask(u32 sound_mask) CCustomMonster* monster = smart_cast(&object()); if (!monster) ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CSoundPlayer : cannot access class member set_sound_mask!"); + make_string("CSoundPlayer [%s]: cannot access class member set_sound_mask!", object().cNameSect().c_str()).c_str()); else { CEntityAlive* entity_alive = smart_cast(monster); @@ -150,7 +150,7 @@ void CScriptGameObject::play_sound(u32 internal_type) CCustomMonster* monster = smart_cast(&object()); if (!monster) ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CSoundPlayer : cannot access class member play!"); + make_string("CSoundPlayer [%s]: cannot access class member play!", object().cNameSect().c_str()).c_str()); else monster->sound().play(internal_type); } @@ -160,7 +160,7 @@ void CScriptGameObject::play_sound(u32 internal_type, u32 max_start_time) CCustomMonster* monster = smart_cast(&object()); if (!monster) ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CSoundPlayer : cannot access class member play!"); + make_string("CSoundPlayer [%s]: cannot access class member play!", object().cNameSect().c_str()).c_str()); else monster->sound().play(internal_type, max_start_time); } @@ -170,7 +170,7 @@ void CScriptGameObject::play_sound(u32 internal_type, u32 max_start_time, u32 mi CCustomMonster* monster = smart_cast(&object()); if (!monster) ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CSoundPlayer : cannot access class member play!"); + make_string("CSoundPlayer [%s]: cannot access class member play!", object().cNameSect().c_str()).c_str()); else monster->sound().play(internal_type, max_start_time, min_start_time); } @@ -180,7 +180,7 @@ void CScriptGameObject::play_sound(u32 internal_type, u32 max_start_time, u32 mi CCustomMonster* monster = smart_cast(&object()); if (!monster) ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CSoundPlayer : cannot access class member play!"); + make_string("CSoundPlayer [%s]: cannot access class member play!", object().cNameSect().c_str()).c_str()); else monster->sound().play(internal_type, max_start_time, min_start_time, max_stop_time); } @@ -191,7 +191,7 @@ void CScriptGameObject::play_sound(u32 internal_type, u32 max_start_time, u32 mi CCustomMonster* monster = smart_cast(&object()); if (!monster) ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CSoundPlayer : cannot access class member play!"); + make_string("CSoundPlayer [%s]: cannot access class member play!", object().cNameSect().c_str()).c_str()); else monster->sound().play(internal_type, max_start_time, min_start_time, max_stop_time, min_stop_time); } @@ -202,7 +202,7 @@ void CScriptGameObject::play_sound(u32 internal_type, u32 max_start_time, u32 mi CCustomMonster* monster = smart_cast(&object()); if (!monster) ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CSoundPlayer : cannot access class member play!"); + make_string("CSoundPlayer [%s]: cannot access class member play!", object().cNameSect().c_str()).c_str()); else monster->sound().play(internal_type, max_start_time, min_start_time, max_stop_time, min_stop_time, id); } @@ -213,7 +213,7 @@ int CScriptGameObject::active_sound_count(bool only_playing) if (!monster) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CGameObject : cannot access class member active_sound_count!"); + make_string("CGameObject [%s]: cannot access class member active_sound_count!", object().cNameSect().c_str()).c_str()); return (-1); } else @@ -231,7 +231,7 @@ bool CScriptGameObject::wounded() const if (!stalker) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CAI_Stalker : cannot access class member wounded!"); + make_string("CAI_Stalker [%s]: cannot access class member wounded!", object().cNameSect().c_str()).c_str()); return (false); } @@ -244,7 +244,7 @@ void CScriptGameObject::wounded(bool value) if (!stalker) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CAI_Stalker : cannot access class member wounded!"); + make_string("CAI_Stalker [%s]: cannot access class member wounded!", object().cNameSect().c_str()).c_str()); return; } @@ -271,7 +271,7 @@ CSightParams CScriptGameObject::sight_params() if (!stalker) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CAI_Stalker : cannot access class member sight_params!"); + make_string("CAI_Stalker [%s]: cannot access class member sight_params!", object().cNameSect().c_str()).c_str()); CSightParams result; result.m_object = 0; @@ -294,7 +294,7 @@ bool CScriptGameObject::critically_wounded() if (!custom_monster) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CCustomMonster : cannot access class member critically_wounded!"); + make_string("CCustomMonster [%s]: cannot access class member critically_wounded!", object().cNameSect().c_str()).c_str()); return (false); } @@ -575,7 +575,7 @@ void CScriptGameObject::memory_remove_links(const CScriptGameObject* tpLuaGameOb else { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CGameObject : cannot access class member memory_remove_links!"); + make_string("CGameObject [%s]: cannot access class member memory_remove_links!", object().cNameSect().c_str()).c_str()); } } diff --git a/src/xrGame/script_game_object_inventory_owner.cpp b/src/xrGame/script_game_object_inventory_owner.cpp index 6d5834d28e..eaa93ec98b 100644 --- a/src/xrGame/script_game_object_inventory_owner.cpp +++ b/src/xrGame/script_game_object_inventory_owner.cpp @@ -422,7 +422,7 @@ void CScriptGameObject::SetCanBeHarmed(bool state) if (!ent) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CEntityAlive : cannot access class member set_can_be_harmed!"); + make_string("CEntityAlive [%s]: cannot access class member set_can_be_harmed!", object().cNameSect().c_str()).c_str()); return; } @@ -435,7 +435,7 @@ bool CScriptGameObject::CanBeHarmed() if (!ent) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CEntityAlive : cannot access class member can_be_harmed!"); + make_string("CEntityAlive [%s]: cannot access class member can_be_harmed!", object().cNameSect().c_str()).c_str()); return false; } @@ -1202,7 +1202,7 @@ void CScriptGameObject::add_restrictions(LPCSTR out, LPCSTR in) if (!monster) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CRestrictedObject : cannot access class member add_restrictions!"); + make_string("CRestrictedObject [%s]: cannot access class member add_restrictions!", object().cNameSect().c_str()).c_str()); return; } @@ -1216,7 +1216,7 @@ void CScriptGameObject::remove_restrictions(LPCSTR out, LPCSTR in) if (!monster) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CRestrictedObject : cannot access class member remove_restrictions!"); + make_string("CRestrictedObject [%s]: cannot access class member remove_restrictions!", object().cNameSect().c_str()).c_str()); return; } @@ -1230,7 +1230,7 @@ void CScriptGameObject::remove_all_restrictions() if (!monster) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CRestrictedObject : cannot access class member remove_all_restrictions!"); + make_string("CRestrictedObject [%s]: cannot access class member remove_all_restrictions!", object().cNameSect().c_str()).c_str()); return; } @@ -1244,7 +1244,7 @@ LPCSTR CScriptGameObject::in_restrictions() if (!monster) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CRestrictedObject : cannot access class member in_restrictions!"); + make_string("CRestrictedObject [%s]: cannot access class member in_restrictions!", object().cNameSect().c_str()).c_str()); return (""); } return (*monster->movement().restrictions().in_restrictions()); @@ -1256,7 +1256,7 @@ LPCSTR CScriptGameObject::out_restrictions() if (!monster) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CRestrictedObject : cannot access class member out_restrictions!"); + make_string("CRestrictedObject [%s]: cannot access class member out_restrictions!", object().cNameSect().c_str()).c_str()); return (""); } return (*monster->movement().restrictions().out_restrictions()); @@ -1268,7 +1268,7 @@ LPCSTR CScriptGameObject::base_in_restrictions() if (!monster) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CRestrictedObject : cannot access class member base_in_restrictions!"); + make_string("CRestrictedObject [%s]: cannot access class member base_in_restrictions!", object().cNameSect().c_str()).c_str()); return (""); } return (*monster->movement().restrictions().base_in_restrictions()); @@ -1280,7 +1280,7 @@ LPCSTR CScriptGameObject::base_out_restrictions() if (!monster) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CRestrictedObject : cannot access class member base_out_restrictions!"); + make_string("CRestrictedObject [%s]: cannot access class member base_out_restrictions!", object().cNameSect().c_str()).c_str()); return (""); } return (*monster->movement().restrictions().base_out_restrictions()); @@ -1292,7 +1292,7 @@ bool CScriptGameObject::accessible_position(const Fvector& position) if (!monster) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CRestrictedObject : cannot access class member accessible!"); + make_string("CRestrictedObject [%s]: cannot access class member accessible!", object().cNameSect().c_str()).c_str()); return (false); } return (monster->movement().restrictions().accessible(position)); @@ -1304,7 +1304,7 @@ bool CScriptGameObject::accessible_vertex_id(u32 level_vertex_id) if (!monster) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CRestrictedObject : cannot access class member accessible!"); + make_string("CRestrictedObject [%s]: cannot access class member accessible!", object().cNameSect().c_str()).c_str()); return (false); } if (!ai().level_graph().valid_vertex_id(level_vertex_id)) @@ -1320,7 +1320,7 @@ u32 CScriptGameObject::accessible_nearest(const Fvector& position, Fvector& resu if (!monster) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CRestrictedObject : cannot access class member accessible!"); + make_string("CRestrictedObject [%s]: cannot access class member accessible!", object().cNameSect().c_str()).c_str()); return (u32(-1)); } if (monster->movement().restrictions().accessible(position)) @@ -1338,7 +1338,7 @@ void CScriptGameObject::enable_attachable_item(bool value) if (!attachable_item) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CAttachableItem : cannot access class member enable_attachable_item!"); + make_string("CAttachableItem [%s]: cannot access class member enable_attachable_item!", object().cNameSect().c_str()).c_str()); return; } attachable_item->enable(value); @@ -1350,7 +1350,7 @@ bool CScriptGameObject::attachable_item_enabled() const if (!attachable_item) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CAttachableItem : cannot access class member attachable_item_enabled!"); + make_string("CAttachableItem [%s]: cannot access class member attachable_item_enabled!", object().cNameSect().c_str()).c_str()); return (false); } return (attachable_item->enabled()); @@ -1362,7 +1362,7 @@ void CScriptGameObject::night_vision_allowed(bool value) if (!pActor) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CActor : cannot access class member enable_night_vision!"); + make_string("CActor [%s]: cannot access class member enable_night_vision!", object().cNameSect().c_str()).c_str()); return; } pActor->SetNightVisionAllowed(value); @@ -1374,7 +1374,7 @@ void CScriptGameObject::enable_night_vision(bool value) if (!pActor) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CActor : cannot access class member enable_night_vision!"); + make_string("CActor [%s]: cannot access class member enable_night_vision!", object().cNameSect().c_str()).c_str()); return; } pActor->SwitchNightVision(value); @@ -1386,7 +1386,7 @@ bool CScriptGameObject::night_vision_enabled() const if (!pActor) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CActor : cannot access class member enable_night_vision!"); + make_string("CActor [%s]: cannot access class member enable_night_vision!", object().cNameSect().c_str()).c_str()); return (false); } return (pActor->GetNightVisionStatus()); @@ -1398,7 +1398,7 @@ void CScriptGameObject::enable_torch(bool value) if (!torch) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CTorch : cannot access class member enable_torch!"); + make_string("CTorch [%s]: cannot access class member enable_torch!", object().cNameSect().c_str()).c_str()); return; } torch->Switch(value); @@ -1410,7 +1410,7 @@ bool CScriptGameObject::torch_enabled() const if (!torch) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CTorch : cannot access class member torch_enabled!"); + make_string("CTorch [%s]: cannot access class member torch_enabled!", object().cNameSect().c_str()).c_str()); return (false); } return (torch->torch_active()); @@ -1423,7 +1423,7 @@ void CScriptGameObject::update_torch() if (!torch) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CTorch : cannot access class member enable_torch!"); + make_string("CTorch [%s]: cannot access class member enable_torch!", object().cNameSect().c_str()).c_str()); return; } torch->UpdateCL(); @@ -1435,7 +1435,7 @@ void CScriptGameObject::attachable_item_load_attach(LPCSTR section) if (!attachable_item) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CAttachableItem : cannot access class member attachable_item_load_attach!"); + make_string("CAttachableItem [%s]: cannot access class member attachable_item_load_attach!", object().cNameSect().c_str()).c_str()); return; } attachable_item->load_attach_position(section); @@ -1473,7 +1473,7 @@ int CScriptGameObject::Weapon_GrenadeLauncher_Status() if (!weapon) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CWeapon : cannot access class member Weapon_GrenadeLauncher_Status!"); + make_string("CWeapon [%s]: cannot access class member Weapon_GrenadeLauncher_Status!", object().cNameSect().c_str()).c_str()); return (false); } return (int)weapon->get_GrenadeLauncherStatus(); @@ -1485,7 +1485,7 @@ int CScriptGameObject::Weapon_Scope_Status() if (!weapon) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CWeapon : cannot access class member Weapon_Scope_Status!"); + make_string("CWeapon [%s]: cannot access class member Weapon_Scope_Status!", object().cNameSect().c_str()).c_str()); return (false); } return (int)weapon->get_ScopeStatus(); @@ -1497,7 +1497,7 @@ int CScriptGameObject::Weapon_Silencer_Status() if (!weapon) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CWeapon : cannot access class member Weapon_Silencer_Status!"); + make_string("CWeapon [%s]: cannot access class member Weapon_Silencer_Status!", object().cNameSect().c_str()).c_str()); return (false); } return (int)weapon->get_SilencerStatus(); @@ -1509,7 +1509,7 @@ bool CScriptGameObject::Weapon_IsGrenadeLauncherAttached() if (!weapon) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CWeapon : cannot access class member Weapon_IsGrenadeLauncherAttached!"); + make_string("CWeapon [%s]: cannot access class member Weapon_IsGrenadeLauncherAttached!", object().cNameSect().c_str()).c_str()); return (false); } return weapon->IsGrenadeLauncherAttached(); @@ -1521,7 +1521,7 @@ bool CScriptGameObject::Weapon_IsScopeAttached() if (!weapon) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CWeapon : cannot access class member Weapon_IsScopeAttached!"); + make_string("CWeapon [%s]: cannot access class member Weapon_IsScopeAttached!", object().cNameSect().c_str()).c_str()); return (false); } return weapon->IsScopeAttached(); @@ -1533,7 +1533,7 @@ bool CScriptGameObject::Weapon_IsSilencerAttached() if (!weapon) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CWeapon : cannot access class member Weapon_IsSilencerAttached!"); + make_string("CWeapon [%s]: cannot access class member Weapon_IsSilencerAttached!", object().cNameSect().c_str()).c_str()); return (false); } return weapon->IsSilencerAttached(); @@ -1550,7 +1550,7 @@ int CScriptGameObject::animation_slot() const if (!hud_item) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CHudItem : cannot access class member animation_slot!"); + make_string("CHudItem [%s]: cannot access class member animation_slot!", object().cNameSect().c_str()).c_str()); return (u32(-1)); } return (hud_item->animation_slot()); @@ -1562,7 +1562,7 @@ CScriptGameObject* CScriptGameObject::active_device() const if (!inventory_owner) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CInventoryOwner : cannot access class member active_detector!"); + make_string("CInventoryOwner [%s]: cannot access class member active_detector!", object().cNameSect().c_str()).c_str()); return (0); } @@ -1583,7 +1583,7 @@ void CScriptGameObject::show_device(bool bFast) if (!inventory_owner) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CInventoryOwner : cannot access class member show_device!"); + make_string("CInventoryOwner [%s]: cannot access class member show_device!", object().cNameSect().c_str()).c_str()); return; } @@ -1602,7 +1602,7 @@ void CScriptGameObject::hide_device(bool bFast) if (!inventory_owner) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CInventoryOwner : cannot access class member hide_device!"); + make_string("CInventoryOwner [%s]: cannot access class member hide_device!", object().cNameSect().c_str()).c_str()); return; } @@ -1621,7 +1621,7 @@ void CScriptGameObject::force_hide_device() if (!inventory_owner) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CInventoryOwner : cannot access class member force_hide_device!"); + make_string("CInventoryOwner [%s]: cannot access class member force_hide_device!", object().cNameSect().c_str()).c_str()); return; } @@ -1640,7 +1640,7 @@ CScriptGameObject* CScriptGameObject::item_in_slot(u32 slot_id) const if (!inventory_owner) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CInventoryOwner : cannot access class member item_in_slot!"); + make_string("CInventoryOwner [%s]: cannot access class member item_in_slot!", object().cNameSect().c_str()).c_str()); return (0); } @@ -1676,7 +1676,7 @@ u32 CScriptGameObject::active_slot() if (!inventory_owner) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CInventoryOwner : cannot access class member active_slot!"); + make_string("CInventoryOwner [%s]: cannot access class member active_slot!", object().cNameSect().c_str()).c_str()); return (0); } return inventory_owner->inventory().GetActiveSlot(); @@ -1688,7 +1688,7 @@ void CScriptGameObject::activate_slot(u32 slot_id) if (!inventory_owner) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CInventoryOwner : cannot access class member activate_slot!"); + make_string("CInventoryOwner [%s]: cannot access class member activate_slot!", object().cNameSect().c_str()).c_str()); return; } inventory_owner->inventory().Activate((u16)slot_id); @@ -1700,7 +1700,7 @@ void CScriptGameObject::enable_movement(bool enable) if (!monster) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CCustomMonster : cannot access class member movement_enabled!"); + make_string("CCustomMonster [%s]: cannot access class member movement_enabled!", object().cNameSect().c_str()).c_str()); return; } @@ -1713,7 +1713,7 @@ bool CScriptGameObject::movement_enabled() if (!monster) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CCustomMonster : cannot access class member movement_enabled!"); + make_string("CCustomMonster [%s]: cannot access class member movement_enabled!", object().cNameSect().c_str()).c_str()); return (false); } @@ -1726,7 +1726,7 @@ bool CScriptGameObject::can_throw_grenades() const if (!stalker) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CAI_Stalker : cannot access class member can_throw_grenades!"); + make_string("CAI_Stalker [%s]: cannot access class member can_throw_grenades!", object().cNameSect().c_str()).c_str()); return (false); } @@ -1739,7 +1739,7 @@ void CScriptGameObject::can_throw_grenades(bool can_throw_grenades) if (!stalker) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CAI_Stalker : cannot access class member can_throw_grenades!"); + make_string("CAI_Stalker [%s]: cannot access class member can_throw_grenades!", object().cNameSect().c_str()).c_str()); return; } @@ -1752,7 +1752,7 @@ u32 CScriptGameObject::throw_time_interval() const if (!stalker) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CAI_Stalker : cannot access class member throw_time_interval!"); + make_string("CAI_Stalker [%s]: cannot access class member throw_time_interval!", object().cNameSect().c_str()).c_str()); return (0); } @@ -1765,7 +1765,7 @@ void CScriptGameObject::throw_time_interval(u32 throw_time_interval) if (!stalker) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CAI_Stalker : cannot access class member throw_time_interval!"); + make_string("CAI_Stalker [%s]: cannot access class member throw_time_interval!", object().cNameSect().c_str()).c_str()); return; } @@ -1778,7 +1778,7 @@ u32 CScriptGameObject::group_throw_time_interval() const if (!stalker) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CAI_Stalker : cannot access class member group_throw_time_interval!"); + make_string("CAI_Stalker [%s]: cannot access class member group_throw_time_interval!", object().cNameSect().c_str()).c_str()); return (0); } @@ -1791,7 +1791,7 @@ void CScriptGameObject::group_throw_time_interval(u32 throw_time_interval) if (!stalker) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CAI_Stalker : cannot access class member group_throw_time_interval!"); + make_string("CAI_Stalker [%s]: cannot access class member group_throw_time_interval!", object().cNameSect().c_str()).c_str()); return; } @@ -1804,7 +1804,7 @@ void CScriptGameObject::aim_time(CScriptGameObject* weapon, u32 aim_time) if (!stalker) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CAI_Stalker : cannot access class member aim_time!"); + make_string("CAI_Stalker [%s]: cannot access class member aim_time!", object().cNameSect().c_str()).c_str()); return; } @@ -1812,7 +1812,7 @@ void CScriptGameObject::aim_time(CScriptGameObject* weapon, u32 aim_time) if (!weapon_) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CAI_Stalker : cannot access class member aim_time (not a weapon passed)!"); + make_string("CAI_Stalker [%s]: cannot access class member aim_time (not a weapon passed)!", object().cNameSect().c_str()).c_str()); return; } @@ -1825,7 +1825,7 @@ u32 CScriptGameObject::aim_time(CScriptGameObject* weapon) if (!stalker) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CAI_Stalker : cannot access class member aim_time!"); + make_string("CAI_Stalker [%s]: cannot access class member aim_time!", object().cNameSect().c_str()).c_str()); return (u32(-1)); } @@ -1833,7 +1833,7 @@ u32 CScriptGameObject::aim_time(CScriptGameObject* weapon) if (!weapon_) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CAI_Stalker : cannot access class member aim_time (not a weapon passed)!"); + make_string("CAI_Stalker [%s]: cannot access class member aim_time (not a weapon passed)!", object().cNameSect().c_str()).c_str()); return (u32(-1)); } @@ -1846,7 +1846,7 @@ void CScriptGameObject::special_danger_move(bool value) if (!stalker) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CAI_Stalker : cannot access class member special_danger_move!"); + make_string("CAI_Stalker [%s]: cannot access class member special_danger_move!", object().cNameSect().c_str()).c_str()); return; } @@ -1859,7 +1859,7 @@ bool CScriptGameObject::special_danger_move() if (!stalker) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CAI_Stalker : cannot access class member special_danger_move!"); + make_string("CAI_Stalker [%s]: cannot access class member special_danger_move!", object().cNameSect().c_str()).c_str()); return (false); } @@ -1872,7 +1872,7 @@ void CScriptGameObject::sniper_update_rate(bool value) if (!stalker) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CAI_Stalker : cannot access class member sniper_update_rate!"); + make_string("CAI_Stalker [%s]: cannot access class member sniper_update_rate!", object().cNameSect().c_str()).c_str()); return; } @@ -1885,7 +1885,7 @@ bool CScriptGameObject::sniper_update_rate() const if (!stalker) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CAI_Stalker : cannot access class member sniper_update_rate!"); + make_string("CAI_Stalker [%s]: cannot access class member sniper_update_rate!", object().cNameSect().c_str()).c_str()); return (false); } @@ -1898,7 +1898,7 @@ void CScriptGameObject::sniper_fire_mode(bool value) if (!stalker) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CAI_Stalker : cannot access class member sniper_fire_mode!"); + make_string("CAI_Stalker [%s]: cannot access class member sniper_fire_mode!", object().cNameSect().c_str()).c_str()); return; } @@ -1911,7 +1911,7 @@ bool CScriptGameObject::sniper_fire_mode() const if (!stalker) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CAI_Stalker : cannot access class member sniper_fire_mode!"); + make_string("CAI_Stalker [%s]: cannot access class member sniper_fire_mode!", object().cNameSect().c_str()).c_str()); return (false); } @@ -2010,7 +2010,7 @@ void CScriptGameObject::aim_bone_id(LPCSTR bone_id) if (!stalker) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CAI_Stalker : cannot access class member aim_bone_id!"); + make_string("CAI_Stalker [%s]: cannot access class member aim_bone_id!", object().cNameSect().c_str()).c_str()); return; } @@ -2023,7 +2023,7 @@ LPCSTR CScriptGameObject::aim_bone_id() const if (!stalker) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CAI_Stalker : cannot access class member aim_bone_id!"); + make_string("CAI_Stalker [%s]: cannot access class member aim_bone_id!", object().cNameSect().c_str()).c_str()); return (false); } @@ -2036,7 +2036,7 @@ void CScriptGameObject::register_in_combat() if (!stalker) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CAI_Stalker : cannot access class member register_in_combat!"); + make_string("CAI_Stalker [%s]: cannot access class member register_in_combat!", object().cNameSect().c_str()).c_str()); return; } @@ -2049,7 +2049,7 @@ void CScriptGameObject::unregister_in_combat() if (!stalker) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CAI_Stalker : cannot access class member unregister_in_combat!"); + make_string("CAI_Stalker [%s]: cannot access class member unregister_in_combat!", object().cNameSect().c_str()).c_str()); return; } @@ -2095,7 +2095,7 @@ CCoverPoint const* CScriptGameObject::find_best_cover(Fvector position_to_cover_ if (!stalker) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CAI_Stalker : cannot access class member find_best_cover!"); + make_string("CAI_Stalker [%s]: cannot access class member find_best_cover!", object().cNameSect().c_str()).c_str()); return (0); } @@ -2115,9 +2115,9 @@ bool CScriptGameObject::suitable_smart_cover(CScriptGameObject* object) if (!stalker) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CAI_Stalker : cannot access class member suitable_smart_cover!"); + make_string("CAI_Stalker [%s]: cannot access class member suitable_smart_cover!", this->object().cNameSect().c_str()).c_str()); return (false); - } + } smart_cover::object const* const smart_object = smart_cast(&object->object()); if (!smart_object) @@ -2148,7 +2148,7 @@ void CScriptGameObject::take_items_enabled(bool const value) if (!stalker) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CAI_Stalker : cannot access class member take_items_enabled!"); + make_string("CAI_Stalker [%s]: cannot access class member take_items_enabled!", object().cNameSect().c_str()).c_str()); return; } @@ -2161,7 +2161,7 @@ bool CScriptGameObject::take_items_enabled() const if (!stalker) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CAI_Stalker : cannot access class member take_items_enabled!"); + make_string("CAI_Stalker [%s]: cannot access class member take_items_enabled!", object().cNameSect().c_str()).c_str()); return (false); } @@ -2174,7 +2174,7 @@ void CScriptGameObject::SetPlayShHdRldSounds(bool val) if (!owner) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CInventoryOwner : cannot access class member SetPlayShHdRldSounds!"); + make_string("CInventoryOwner [%s]: cannot access class member SetPlayShHdRldSounds!", object().cNameSect().c_str()).c_str()); return; } owner->SetPlayShHdRldSounds(val); @@ -2186,7 +2186,7 @@ void CScriptGameObject::death_sound_enabled(bool const value) if (!stalker) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CAI_Stalker : cannot access class member death_sound_enabled!"); + make_string("CAI_Stalker [%s]: cannot access class member death_sound_enabled!", object().cNameSect().c_str()).c_str()); return; } @@ -2199,7 +2199,7 @@ bool CScriptGameObject::death_sound_enabled() const if (!stalker) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CAI_Stalker : cannot access class member death_sound_enabled!"); + make_string("CAI_Stalker [%s]: cannot access class member death_sound_enabled!", object().cNameSect().c_str()).c_str()); return (false); } @@ -2277,7 +2277,7 @@ void CScriptGameObject::Weapon_AddonAttach(CScriptGameObject* item) if (!weapon) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CWeaponMagazined : cannot access class member Weapon_AddonAttach!"); + make_string("CWeaponMagazined [%s]: cannot access class member Weapon_AddonAttach!", object().cNameSect().c_str()).c_str()); return; } CInventoryItem* pItm = item->object().cast_inventory_item(); @@ -2299,7 +2299,7 @@ void CScriptGameObject::Weapon_AddonDetach(LPCSTR item_section, bool b_spawn_ite if (!weapon) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CWeaponMagazined : cannot access class member Weapon_AddonDetach!"); + make_string("CWeaponMagazined [%s]: cannot access class member Weapon_AddonDetach!", object().cNameSect().c_str()).c_str()); return; } @@ -2315,7 +2315,7 @@ void CScriptGameObject::Weapon_SetCurrentScope(u8 type) if (!weapon) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CWeaponMagazined : cannot access class member Weapon_SetCurrentScope!"); + make_string("CWeaponMagazined [%s]: cannot access class member Weapon_SetCurrentScope!", object().cNameSect().c_str()).c_str()); return; } @@ -2328,7 +2328,7 @@ u8 CScriptGameObject::Weapon_GetCurrentScope() if (!weapon) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CWeaponMagazined : cannot access class member Weapon_GetCurrentScope!"); + make_string("CWeaponMagazined [%s]: cannot access class member Weapon_GetCurrentScope!", object().cNameSect().c_str()).c_str()); return 255; } return weapon->m_cur_scope; @@ -2340,7 +2340,7 @@ bool CScriptGameObject::InstallUpgrade(LPCSTR upgrade) if (!item) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CInventoryItem : cannot access class member InstallUpgrade!"); + make_string("CInventoryItem [%s]: cannot access class member InstallUpgrade!", object().cNameSect().c_str()).c_str()); return false; } @@ -2356,7 +2356,7 @@ bool CScriptGameObject::HasUpgrade(LPCSTR upgrade) if (!item) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CInventoryItem : cannot access class member HasUpgrade!"); + make_string("CInventoryItem [%s]: cannot access class member HasUpgrade!", object().cNameSect().c_str()).c_str()); return false; } @@ -2389,7 +2389,7 @@ CScriptGameObject* CScriptGameObject::ItemOnBelt(u32 item_id) const if (!inventory_owner) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CInventoryOwner : cannot access class member item_on_belt!"); + make_string("CInventoryOwner [%s]: cannot access class member item_on_belt!", object().cNameSect().c_str()).c_str()); return (0); } @@ -2411,7 +2411,7 @@ bool CScriptGameObject::IsOnBelt(CScriptGameObject* obj) const if (!inventory_item) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CInventoryItem : cannot access class member is_on_belt!"); + make_string("CInventoryItem [%s]: cannot access class member is_on_belt!", object().cNameSect().c_str()).c_str()); return (0); } @@ -2419,7 +2419,7 @@ bool CScriptGameObject::IsOnBelt(CScriptGameObject* obj) const if (!inventory_owner) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CInventoryOwner : cannot access class member is_on_belt!"); + make_string("CInventoryOwner [%s]: cannot access class member is_on_belt!", object().cNameSect().c_str()).c_str()); return (0); } @@ -2432,7 +2432,7 @@ u32 CScriptGameObject::BeltSize() const if (!inventory_owner) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CInventoryOwner : cannot access class member move_to_belt!"); + make_string("CInventoryOwner [%s]: cannot access class member move_to_belt!", object().cNameSect().c_str()).c_str()); return (0); } @@ -2445,7 +2445,7 @@ float CScriptGameObject::GetActorMaxWeight() const if (!pActor) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CActor : cannot access class member GetActorMaxWeight!"); + make_string("CActor [%s]: cannot access class member GetActorMaxWeight!", object().cNameSect().c_str()).c_str()); return (false); } return (pActor->inventory().GetMaxWeight()); @@ -2457,7 +2457,7 @@ void CScriptGameObject::SetActorMaxWeight(float max_weight) if (!pActor) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CActor : cannot access class member SetActorMaxWeight!"); + make_string("CActor [%s]: cannot access class member SetActorMaxWeight!", object().cNameSect().c_str()).c_str()); return; } pActor->inventory().SetMaxWeight(max_weight); @@ -2470,7 +2470,7 @@ float CScriptGameObject::GetActorMaxWalkWeight() const if (!pActor) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CActor : cannot access class member GetActorMaxWalkWeight!"); + make_string("CActor [%s]: cannot access class member GetActorMaxWalkWeight!", object().cNameSect().c_str()).c_str()); return (false); } return (pActor->conditions().MaxWalkWeight()); @@ -2482,7 +2482,7 @@ void CScriptGameObject::SetActorMaxWalkWeight(float max_walk_weight) if (!pActor) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CActor : cannot access class member SetActorMaxWalkWeight!"); + make_string("CActor [%s]: cannot access class member SetActorMaxWalkWeight!", object().cNameSect().c_str()).c_str()); return; } pActor->conditions().SetMaxWalkWeight(max_walk_weight); @@ -2497,7 +2497,7 @@ float CScriptGameObject::GetAdditionalMaxWeight() const if (!outfit && !pBackpack) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CCustomOutfit : cannot access class member GetAdditionalMaxWeight!"); + make_string("CCustomOutfit [%s]: cannot access class member GetAdditionalMaxWeight!", object().cNameSect().c_str()).c_str()); return (false); } @@ -2514,7 +2514,7 @@ float CScriptGameObject::GetAdditionalMaxWalkWeight() const if (!outfit && !pBackpack) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CCustomOutfit : cannot access class member GetAdditionalMaxWalkWeight!"); + make_string("CCustomOutfit [%s]: cannot access class member GetAdditionalMaxWalkWeight!", object().cNameSect().c_str()).c_str()); return (false); } if (outfit) @@ -2530,7 +2530,7 @@ void CScriptGameObject::SetAdditionalMaxWeight(float add_max_weight) if (!outfit && !pBackpack) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CCustomOutfit : cannot access class member SetAdditionalMaxWeight!"); + make_string("CCustomOutfit [%s]: cannot access class member SetAdditionalMaxWeight!", object().cNameSect().c_str()).c_str()); return; } if (outfit) @@ -2547,7 +2547,7 @@ void CScriptGameObject::SetAdditionalMaxWalkWeight(float add_max_walk_weight) if (!outfit && !pBackpack) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CCustomOutfit : cannot access class member SetAdditionalMaxWalkWeight!"); + make_string("CCustomOutfit [%s]: cannot access class member SetAdditionalMaxWalkWeight!", object().cNameSect().c_str()).c_str()); return; } @@ -2566,7 +2566,7 @@ float CScriptGameObject::GetTotalWeight() const if (!inventory_owner) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CInventoryOwner : cannot access class member GetTotalWeight!"); + make_string("CInventoryOwner [%s]: cannot access class member GetTotalWeight!", object().cNameSect().c_str()).c_str()); return (false); } return (inventory_owner->inventory().TotalWeight()); @@ -2579,7 +2579,7 @@ void CScriptGameObject::UpdateWeight() const if (!inventory_owner) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CInventoryOwner : cannot access class member GetTotalWeightForceUpdate!"); + make_string("CInventoryOwner [%s]: cannot access class member GetTotalWeightForceUpdate!", object().cNameSect().c_str()).c_str()); return; } inventory_owner->inventory().CalcTotalWeight(); @@ -2591,7 +2591,7 @@ float CScriptGameObject::GetTotalWeightForceUpdate() const if (!inventory_owner) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CInventoryOwner : cannot access class member GetTotalWeightForceUpdate!"); + make_string("CInventoryOwner [%s]: cannot access class member GetTotalWeightForceUpdate!", object().cNameSect().c_str()).c_str()); return (false); } inventory_owner->inventory().CalcTotalWeight(); @@ -2605,7 +2605,7 @@ float CScriptGameObject::Weight() const if (!inventory_item) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CSciptEntity : cannot access class member Weight!"); + make_string("CSciptEntity [%s]: cannot access class member Weight!", object().cNameSect().c_str()).c_str()); return (false); } return (inventory_item->Weight()); @@ -2617,7 +2617,7 @@ void CScriptGameObject::SetWeight(float w) if (!inventory_item) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CSciptEntity : cannot access class member SetWeight!"); + make_string("CSciptEntity [%s]: cannot access class member SetWeight!", object().cNameSect().c_str()).c_str()); return; } inventory_item->SetWeight(w); @@ -2641,7 +2641,7 @@ float CScriptGameObject::GetActorJumpSpeed() const if (!pActor) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CActor : cannot access class member GetActorJumpSpeed!"); + make_string("CActor [%s]: cannot access class member GetActorJumpSpeed!", object().cNameSect().c_str()).c_str()); return (false); } return (pActor->m_fJumpSpeed); @@ -2653,7 +2653,7 @@ void CScriptGameObject::SetActorJumpSpeed(float jump_speed) if (!pActor) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CActor : cannot access class member SetActorJumpSpeed!"); + make_string("CActor [%s]: cannot access class member SetActorJumpSpeed!", object().cNameSect().c_str()).c_str()); return; } pActor->m_fJumpSpeed = jump_speed; @@ -2666,7 +2666,7 @@ float CScriptGameObject::GetActorSprintKoef() const if (!pActor) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CActor : cannot access class member GetActorJumpSpeed!"); + make_string("CActor [%s]: cannot access class member GetActorJumpSpeed!", object().cNameSect().c_str()).c_str()); return (false); } return (pActor->m_fSprintFactor); @@ -2678,7 +2678,7 @@ void CScriptGameObject::SetActorSprintKoef(float sprint_koef) if (!pActor) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CActor : cannot access class member SetActorJumpSpeed!"); + make_string("CActor [%s]: cannot access class member SetActorJumpSpeed!", object().cNameSect().c_str()).c_str()); return; } pActor->m_fSprintFactor = sprint_koef; @@ -2690,7 +2690,7 @@ float CScriptGameObject::GetActorRunCoef() const if (!pActor) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CActor : cannot access class member GetActorJumpSpeed!"); + make_string("CActor [%s]: cannot access class member GetActorJumpSpeed!", object().cNameSect().c_str()).c_str()); return (false); } return (pActor->m_fRunFactor); @@ -2702,7 +2702,7 @@ void CScriptGameObject::SetActorRunCoef(float run_coef) if (!pActor) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CActor : cannot access class member SetActorJumpSpeed!"); + make_string("CActor [%s]: cannot access class member SetActorJumpSpeed!", object().cNameSect().c_str()).c_str()); return; } pActor->m_fRunFactor = run_coef; @@ -2714,7 +2714,7 @@ float CScriptGameObject::GetActorRunBackCoef() const if (!pActor) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CActor : cannot access class member GetActorJumpSpeed!"); + make_string("CActor [%s]: cannot access class member GetActorJumpSpeed!", object().cNameSect().c_str()).c_str()); return (false); } return (pActor->m_fRunBackFactor); @@ -2726,7 +2726,7 @@ void CScriptGameObject::SetActorRunBackCoef(float run_back_coef) if (!pActor) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CActor : cannot access class member SetActorJumpSpeed!"); + make_string("CActor [%s]: cannot access class member SetActorJumpSpeed!", object().cNameSect().c_str()).c_str()); return; } pActor->m_fRunBackFactor = run_back_coef; @@ -2738,7 +2738,7 @@ void CScriptGameObject::SetActorCamBoxYOffset(u32 box_num, float offset) if (!pActor) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CActor : cannot access class member SetActorCamBoxYOffset!"); + make_string("CActor [%s]: cannot access class member SetActorCamBoxYOffset!", object().cNameSect().c_str()).c_str()); return; } pActor->set_actor_box_y_offset(box_num, offset); @@ -2751,7 +2751,7 @@ float CScriptGameObject::GetActorWalkAccel() const if (!pActor) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CActor : cannot access class member GetActorWalkAccel!"); + make_string("CActor [%s]: cannot access class member GetActorWalkAccel!", object().cNameSect().c_str()).c_str()); return (false); } return (pActor->m_fWalkAccel); @@ -2762,7 +2762,7 @@ void CScriptGameObject::SetActorWalkAccel(float val) if (!pActor) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CActor : cannot access class member SetActorWalkAccel!"); + make_string("CActor [%s]: cannot access class member SetActorWalkAccel!", object().cNameSect().c_str()).c_str()); return; } pActor->m_fWalkAccel = val; @@ -2775,7 +2775,7 @@ float CScriptGameObject::GetActorWalkBackCoef() const if (!pActor) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CActor : cannot access class member GetActorWalkBackCoef!"); + make_string("CActor [%s]: cannot access class member GetActorWalkBackCoef!", object().cNameSect().c_str()).c_str()); return (false); } return (pActor->m_fWalkBackFactor); @@ -2786,7 +2786,7 @@ void CScriptGameObject::SetActorWalkBackCoef(float val) if (!pActor) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CActor : cannot access class member SetActorWalkBackCoef!"); + make_string("CActor [%s]: cannot access class member SetActorWalkBackCoef!", object().cNameSect().c_str()).c_str()); return; } pActor->m_fWalkBackFactor = val; @@ -2813,7 +2813,7 @@ float CScriptGameObject::GetActorLookoutCoef() const if (!pActor) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CActor : cannot access class member GetActorLookoutCoef!"); + make_string("CActor [%s]: cannot access class member GetActorLookoutCoef!", object().cNameSect().c_str()).c_str()); return (false); } return (pActor->m_fLookoutFactor); @@ -2824,7 +2824,7 @@ void CScriptGameObject::SetActorLookoutCoef(float val) if (!pActor) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CActor : cannot access class member SetActorLookoutCoef!"); + make_string("CActor [%s]: cannot access class member SetActorLookoutCoef!", object().cNameSect().c_str()).c_str()); return; } pActor->m_fLookoutFactor = val; @@ -2837,7 +2837,7 @@ float CScriptGameObject::GetActorCrouchCoef() const if (!pActor) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CActor : cannot access class member GetActorCrouchCoef!"); + make_string("CActor [%s]: cannot access class member GetActorCrouchCoef!", object().cNameSect().c_str()).c_str()); return (false); } return (pActor->m_fCrouchFactor); @@ -2848,7 +2848,7 @@ void CScriptGameObject::SetActorCrouchCoef(float val) if (!pActor) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CActor : cannot access class member SetActorCrouchCoef!"); + make_string("CActor [%s]: cannot access class member SetActorCrouchCoef!", object().cNameSect().c_str()).c_str()); return; } pActor->m_fCrouchFactor = val; @@ -2859,7 +2859,7 @@ float CScriptGameObject::GetActorClimbCoef() const if (!pActor) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CActor : cannot access class member GetActorClimbCoef!"); + make_string("CActor [%s]: cannot access class member GetActorClimbCoef!", object().cNameSect().c_str()).c_str()); return (false); } return (pActor->m_fClimbFactor); @@ -2870,7 +2870,7 @@ void CScriptGameObject::SetActorClimbCoef(float val) if (!pActor) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CActor : cannot access class member SetActorClimbCoef!"); + make_string("CActor [%s]: cannot access class member SetActorClimbCoef!", object().cNameSect().c_str()).c_str()); return; } pActor->m_fClimbFactor = val; @@ -2881,7 +2881,7 @@ float CScriptGameObject::GetActorWalkStrafeCoef() const if (!pActor) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CActor : cannot access class member GetActorWalkStrafeCoef!"); + make_string("CActor [%s]: cannot access class member GetActorWalkStrafeCoef!", object().cNameSect().c_str()).c_str()); return (false); } return (pActor->m_fWalk_StrafeFactor); @@ -2892,7 +2892,7 @@ void CScriptGameObject::SetActorWalkStrafeCoef(float val) if (!pActor) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CActor : cannot access class member SetActorWalkStrafeCoef!"); + make_string("CActor [%s]: cannot access class member SetActorWalkStrafeCoef!", object().cNameSect().c_str()).c_str()); return; } pActor->m_fWalk_StrafeFactor = val; @@ -2903,7 +2903,7 @@ float CScriptGameObject::GetActorRunStrafeCoef() const if (!pActor) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CActor : cannot access class member GetActorRunStrafeCoef!"); + make_string("CActor [%s]: cannot access class member GetActorRunStrafeCoef!", object().cNameSect().c_str()).c_str()); return (false); } return (pActor->m_fRun_StrafeFactor); @@ -2914,7 +2914,7 @@ void CScriptGameObject::SetActorRunStrafeCoef(float val) if (!pActor) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CActor : cannot access class member SetActorRunStrafeCoef!"); + make_string("CActor [%s]: cannot access class member SetActorRunStrafeCoef!", object().cNameSect().c_str()).c_str()); return; } pActor->m_fRun_StrafeFactor = val; @@ -2925,7 +2925,7 @@ float CScriptGameObject::GetActorSprintStrafeCoef() const if (!pActor) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CActor : cannot access class member GetActorSprintStrafeCoef!"); + make_string("CActor [%s]: cannot access class member GetActorSprintStrafeCoef!", object().cNameSect().c_str()).c_str()); return (false); } return (pActor->m_fSprint_StrafeFactor); @@ -2936,7 +2936,7 @@ void CScriptGameObject::SetActorSprintStrafeCoef(float val) if (!pActor) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CActor : cannot access class member SetActorSprintStrafeCoef!"); + make_string("CActor [%s]: cannot access class member SetActorSprintStrafeCoef!", object().cNameSect().c_str()).c_str()); return; } pActor->m_fSprint_StrafeFactor = val; @@ -2948,7 +2948,7 @@ CScriptGameObject* CScriptGameObject::GetActorObjectLookingAt() if (!pActor) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CActor : cannot access class member GetActorObjectLookingAt!"); + make_string("CActor [%s]: cannot access class member GetActorObjectLookingAt!", object().cNameSect().c_str()).c_str()); return nullptr; } auto obj = pActor->ObjectWeLookingAt(); @@ -2964,7 +2964,7 @@ CScriptGameObject* CScriptGameObject::GetActorPersonLookingAt() if (!pActor) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CActor : cannot access class member GetActorPersonLookingAt!"); + make_string("CActor [%s]: cannot access class member GetActorPersonLookingAt!", object().cNameSect().c_str()).c_str()); return nullptr; } auto obj = pActor->PersonWeLookingAt(); @@ -2984,7 +2984,7 @@ LPCSTR CScriptGameObject::GetActorDefaultActionForObject() if (!pActor) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CActor : cannot access class member GetDefaultActionForObject!"); + make_string("CActor [%s]: cannot access class member GetDefaultActionForObject!", object().cNameSect().c_str()).c_str()); return nullptr; } return pActor->GetDefaultActionForObject(); diff --git a/src/xrGame/script_game_object_smart_covers.cpp b/src/xrGame/script_game_object_smart_covers.cpp index 783bc702c3..bc1fab57ff 100644 --- a/src/xrGame/script_game_object_smart_covers.cpp +++ b/src/xrGame/script_game_object_smart_covers.cpp @@ -20,7 +20,7 @@ bool CScriptGameObject::use_smart_covers_only() const if (!stalker) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CAI_Stalker : cannot access class member use_smart_covers_only!"); + make_string("CAI_Stalker [%s]: cannot access class member use_smart_covers_only!", object().cNameSect().c_str()).c_str()); return (false); } @@ -33,7 +33,7 @@ void CScriptGameObject::use_smart_covers_only(bool value) if (!stalker) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CAI_Stalker : cannot access class member use_smart_covers_only!"); + make_string("CAI_Stalker [%s]: cannot access class member use_smart_covers_only!", object().cNameSect().c_str()).c_str()); return; } @@ -46,7 +46,7 @@ void CScriptGameObject::set_smart_cover_target_selector() if (!stalker) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CAI_Stalker : cannot access class member set_smart_cover_target_selector!"); + make_string("CAI_Stalker [%s]: cannot access class member set_smart_cover_target_selector!", object().cNameSect().c_str()).c_str()); return; } @@ -59,7 +59,7 @@ void CScriptGameObject::set_smart_cover_target_selector(::luabind::functor if (!stalker) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CAI_Stalker : cannot access class member set_smart_cover_target_selector!"); + make_string("CAI_Stalker [%s]: cannot access class member set_smart_cover_target_selector!", object().cNameSect().c_str()).c_str()); return; } @@ -74,7 +74,7 @@ void CScriptGameObject::set_smart_cover_target_selector(::luabind::functor if (!stalker) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CAI_Stalker : cannot access class member set_smart_cover_target_selector!"); + make_string("CAI_Stalker [%s]: cannot access class member set_smart_cover_target_selector!", this->object().cNameSect().c_str()).c_str()); return; } @@ -89,7 +89,7 @@ void CScriptGameObject::set_smart_cover_target_idle() if (!stalker) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CAI_Stalker : cannot access class member smart_cover_setup_idle_target!"); + make_string("CAI_Stalker [%s]: cannot access class member smart_cover_setup_idle_target!", object().cNameSect().c_str()).c_str()); return; } @@ -109,7 +109,7 @@ void CScriptGameObject::set_smart_cover_target_lookout() if (!stalker) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CAI_Stalker : cannot access class member smart_cover_setup_lookout_target!"); + make_string("CAI_Stalker [%s]: cannot access class member smart_cover_setup_lookout_target!", object().cNameSect().c_str()).c_str()); return; } @@ -129,7 +129,7 @@ void CScriptGameObject::set_smart_cover_target_fire() if (!stalker) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CAI_Stalker : cannot access class member smart_cover_setup_fire_target!"); + make_string("CAI_Stalker [%s]: cannot access class member smart_cover_setup_fire_target!", object().cNameSect().c_str()).c_str()); return; } @@ -149,7 +149,7 @@ void CScriptGameObject::set_smart_cover_target_fire_no_lookout() if (!stalker) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CAI_Stalker : cannot access class member smart_cover_setup_fire_no_lookout_target!"); + make_string("CAI_Stalker [%s]: cannot access class member smart_cover_setup_fire_no_lookout_target!", object().cNameSect().c_str()).c_str()); return; } @@ -169,7 +169,7 @@ void CScriptGameObject::set_smart_cover_target_default(bool value) if (!stalker) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CAI_Stalker : cannot access class member set_smart_cover_target_default!"); + make_string("CAI_Stalker [%s]: cannot access class member set_smart_cover_target_default!", object().cNameSect().c_str()).c_str()); return; } @@ -189,7 +189,7 @@ bool CScriptGameObject::in_smart_cover() const if (!stalker) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CAI_Stalker : cannot access class member in_smart_cover_mode!"); + make_string("CAI_Stalker [%s]: cannot access class member in_smart_cover_mode!", object().cNameSect().c_str()).c_str()); return (""); } @@ -202,7 +202,7 @@ void CScriptGameObject::set_dest_smart_cover(LPCSTR cover_id) if (!stalker) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CAI_Stalker : cannot access class member set_dest_smart_cover!"); + make_string("CAI_Stalker [%s]: cannot access class member set_dest_smart_cover!", object().cNameSect().c_str()).c_str()); return; } @@ -215,7 +215,7 @@ void CScriptGameObject::set_dest_smart_cover() if (!stalker) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CAI_Stalker : cannot access class member set_dest_smart_cover!"); + make_string("CAI_Stalker [%s]: cannot access class member set_dest_smart_cover!", object().cNameSect().c_str()).c_str()); return; } @@ -228,7 +228,7 @@ CCoverPoint const* CScriptGameObject::get_dest_smart_cover() if (!stalker) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CAI_Stalker : cannot access class member get_dest_smart_cover!"); + make_string("CAI_Stalker [%s]: cannot access class member get_dest_smart_cover!", object().cNameSect().c_str()).c_str()); return (0); } @@ -241,7 +241,7 @@ LPCSTR CScriptGameObject::get_dest_smart_cover_name() if (!stalker) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CAI_Stalker : cannot access class member get_dest_smart_cover!"); + make_string("CAI_Stalker [%s]: cannot access class member get_dest_smart_cover!", object().cNameSect().c_str()).c_str()); return (0); } @@ -254,7 +254,7 @@ void CScriptGameObject::set_dest_loophole(LPCSTR loophole_id) if (!stalker) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CAI_Stalker : cannot access class member set_dest_loophole!"); + make_string("CAI_Stalker [%s]: cannot access class member set_dest_loophole!", object().cNameSect().c_str()).c_str()); return; } @@ -267,7 +267,7 @@ void CScriptGameObject::set_dest_loophole() if (!stalker) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CAI_Stalker : cannot access class member set_dest_loophole!"); + make_string("CAI_Stalker [%s]: cannot access class member set_dest_loophole!", object().cNameSect().c_str()).c_str()); return; } @@ -280,7 +280,7 @@ void CScriptGameObject::set_smart_cover_target(Fvector value) if (!stalker) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CAI_Stalker : cannot access class member set_smart_cover_target!"); + make_string("CAI_Stalker [%s]: cannot access class member set_smart_cover_target!", object().cNameSect().c_str()).c_str()); return; } @@ -293,7 +293,7 @@ void CScriptGameObject::set_smart_cover_target() if (!stalker) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CAI_Stalker : cannot access class member set_smart_cover_target!"); + make_string("CAI_Stalker [%s]: cannot access class member set_smart_cover_target!", object().cNameSect().c_str()).c_str()); return; } @@ -306,7 +306,7 @@ void CScriptGameObject::set_smart_cover_target(CScriptGameObject* enemy_object) if (!stalker) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CAI_Stalker : cannot access class member set_smart_cover_target!"); + make_string("CAI_Stalker [%s]: cannot access class member set_smart_cover_target!", object().cNameSect().c_str()).c_str()); return; } @@ -319,7 +319,7 @@ bool CScriptGameObject::in_loophole_fov(LPCSTR cover_id, LPCSTR loophole_id, Fve if (!stalker) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CAI_Stalker : cannot access class member object_in_loophole_fov!"); + make_string("CAI_Stalker [%s]: cannot access class member object_in_loophole_fov!", object().cNameSect().c_str()).c_str()); return (false); } @@ -332,7 +332,7 @@ bool CScriptGameObject::in_current_loophole_fov(Fvector object_position) const if (!stalker) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CAI_Stalker : cannot access class member object_in_loophole_fov!"); + make_string("CAI_Stalker [%s]: cannot access class member object_in_loophole_fov!", object().cNameSect().c_str()).c_str()); return (false); } @@ -345,7 +345,7 @@ bool CScriptGameObject::in_loophole_range(LPCSTR cover_id, LPCSTR loophole_id, F if (!stalker) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CAI_Stalker : cannot access class member object_in_loophole_range!"); + make_string("CAI_Stalker [%s]: cannot access class member object_in_loophole_range!", object().cNameSect().c_str()).c_str()); return (false); } @@ -358,7 +358,7 @@ bool CScriptGameObject::in_current_loophole_range(Fvector object_position) const if (!stalker) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CAI_Stalker : cannot access class member object_in_loophole_range!"); + make_string("CAI_Stalker [%s]: cannot access class member object_in_loophole_range!", object().cNameSect().c_str()).c_str()); return (false); } @@ -371,7 +371,7 @@ float const CScriptGameObject::idle_min_time() const if (!stalker) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CAI_Stalker : cannot access class member idle_min_time!"); + make_string("CAI_Stalker [%s]: cannot access class member idle_min_time!", object().cNameSect().c_str()).c_str()); return (flt_max); } @@ -384,7 +384,7 @@ void CScriptGameObject::idle_min_time(float value) if (!stalker) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CAI_Stalker : cannot access class member idle_min_time!"); + make_string("CAI_Stalker [%s]: cannot access class member idle_min_time!", object().cNameSect().c_str()).c_str()); return; } @@ -397,7 +397,7 @@ float const CScriptGameObject::idle_max_time() const if (!stalker) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CAI_Stalker : cannot access class member idle_max_time!"); + make_string("CAI_Stalker [%s]: cannot access class member idle_max_time!", object().cNameSect().c_str()).c_str()); return (flt_max); } @@ -410,7 +410,7 @@ void CScriptGameObject::idle_max_time(float value) if (!stalker) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CAI_Stalker : cannot access class member idle_max_time!"); + make_string("CAI_Stalker [%s]: cannot access class member idle_max_time!", object().cNameSect().c_str()).c_str()); return; } @@ -423,7 +423,7 @@ float const CScriptGameObject::lookout_min_time() const if (!stalker) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CAI_Stalker : cannot access class member lookout_min_time!"); + make_string("CAI_Stalker [%s]: cannot access class member lookout_min_time!", object().cNameSect().c_str()).c_str()); return (flt_max); } @@ -436,7 +436,7 @@ void CScriptGameObject::lookout_min_time(float value) if (!stalker) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CAI_Stalker : cannot access class member lookout_min_time!"); + make_string("CAI_Stalker [%s]: cannot access class member lookout_min_time!", object().cNameSect().c_str()).c_str()); return; } @@ -449,7 +449,7 @@ float const CScriptGameObject::lookout_max_time() const if (!stalker) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CAI_Stalker : cannot access class member lookout_max_time!"); + make_string("CAI_Stalker [%s]: cannot access class member lookout_max_time!", object().cNameSect().c_str()).c_str()); return (flt_max); } @@ -462,7 +462,7 @@ void CScriptGameObject::lookout_max_time(float value) if (!stalker) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CAI_Stalker : cannot access class member lookout_max_time!"); + make_string("CAI_Stalker [%s]: cannot access class member lookout_max_time!", object().cNameSect().c_str()).c_str()); return; } @@ -475,7 +475,7 @@ float CScriptGameObject::apply_loophole_direction_distance() const if (!stalker) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CAI_Stalker : cannot access class member smart_cover_enter_distance!"); + make_string("CAI_Stalker [%s]: cannot access class member smart_cover_enter_distance!", object().cNameSect().c_str()).c_str()); return (flt_max); } @@ -488,7 +488,7 @@ void CScriptGameObject::apply_loophole_direction_distance(float value) if (!stalker) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CAI_Stalker : cannot access class member smart_cover_enter_distance!"); + make_string("CAI_Stalker [%s]: cannot access class member smart_cover_enter_distance!", object().cNameSect().c_str()).c_str()); return; } @@ -501,7 +501,7 @@ bool CScriptGameObject::movement_target_reached() if (!stalker) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CAI_Stalker : cannot access class member movement_target_reached!"); + make_string("CAI_Stalker [%s]: cannot access class member movement_target_reached!", object().cNameSect().c_str()).c_str()); return (false); } diff --git a/src/xrGame/script_game_object_use.cpp b/src/xrGame/script_game_object_use.cpp index 011534a772..9e0b32f78c 100644 --- a/src/xrGame/script_game_object_use.cpp +++ b/src/xrGame/script_game_object_use.cpp @@ -128,7 +128,7 @@ bool CScriptGameObject::Alive() const if (!entity) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CSciptEntity : cannot access class member Alive!"); + make_string("CSciptEntity [%s]: cannot access class member Alive!", object().cNameSect().c_str()).c_str()); return (false); } return (!!entity->g_Alive()); @@ -163,7 +163,7 @@ IC T* CScriptGameObject::action_planner() if (!manager) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CAI_Stalker : cannot access class member action_planner!"); + make_string("CAI_Stalker [%s]: cannot access class member action_planner!", object().cNameSect().c_str()).c_str()); return (0); } return (&manager->brain()); @@ -180,7 +180,7 @@ void CScriptGameObject::set_enemy_callback(const ::luabind::functor& funct if (!monster) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CCustomMonster : cannot access class member set_enemy_callback!"); + make_string("CCustomMonster [%s]: cannot access class member set_enemy_callback!", object().cNameSect().c_str()).c_str()); return; } monster->memory().enemy().useful_callback().set(functor); @@ -192,7 +192,7 @@ void CScriptGameObject::set_enemy_callback(const ::luabind::functor& funct if (!monster) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CCustomMonster : cannot access class member set_enemy_callback!"); + make_string("CCustomMonster [%s]: cannot access class member set_enemy_callback!", this->object().cNameSect().c_str()).c_str()); return; } monster->memory().enemy().useful_callback().set(functor, object); @@ -204,7 +204,7 @@ void CScriptGameObject::set_enemy_callback() if (!monster) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CCustomMonster : cannot access class member set_enemy_callback!"); + make_string("CCustomMonster [%s]: cannot access class member set_enemy_callback!", object().cNameSect().c_str()).c_str()); return; } monster->memory().enemy().useful_callback().clear(); @@ -262,5 +262,5 @@ void CScriptGameObject::set_const_force(const Fvector& dir, float value, u32 tim CPHExpireOnStepCondition* cn = xr_new(); cn->set_time_interval(time_interval); //ph_world->AddCall(cn,a); - Level().ph_commander_physics_worldstep().add_call_threadsafety(cn, a); + Level().ph_commander_physics_worldstep().add_call(cn, a); } diff --git a/src/xrGame/script_game_object_use2.cpp b/src/xrGame/script_game_object_use2.cpp index db35433fac..627984470e 100644 --- a/src/xrGame/script_game_object_use2.cpp +++ b/src/xrGame/script_game_object_use2.cpp @@ -103,7 +103,7 @@ void CScriptGameObject::force_visibility_state(int state) if (!monster) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CAI_Bloodsucker : cannot access class member force_visibility_state!"); + make_string("CAI_Bloodsucker [%s]: cannot access class member force_visibility_state!", object().cNameSect().c_str()).c_str()); return; } @@ -116,7 +116,7 @@ int CScriptGameObject::get_visibility_state() if (!monster) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CAI_Bloodsucker : cannot access class member get_visibility_state!"); + make_string("CAI_Bloodsucker [%s]: cannot access class member get_visibility_state!", object().cNameSect().c_str()).c_str()); return CAI_Bloodsucker::full_visibility; } @@ -165,7 +165,7 @@ void CScriptGameObject::force_stand_sleep_animation(u32 index) if (!monster) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CAI_Bloodsucker : cannot access class member force_stand_sleep_animation!"); + make_string("CAI_Bloodsucker [%s]: cannot access class member force_stand_sleep_animation!", object().cNameSect().c_str()).c_str()); return; } @@ -178,7 +178,7 @@ void CScriptGameObject::release_stand_sleep_animation() if (!monster) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CAI_Bloodsucker : cannot access class member release_stand_sleep_animation!"); + make_string("CAI_Bloodsucker [%s]: cannot access class member release_stand_sleep_animation!", object().cNameSect().c_str()).c_str()); return; } @@ -191,7 +191,7 @@ void CScriptGameObject::set_invisible(bool val) if (!monster) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CAI_Bloodsucker : cannot access class member set_invisible!"); + make_string("CAI_Bloodsucker [%s]: cannot access class member set_invisible!", object().cNameSect().c_str()).c_str()); return; } @@ -204,7 +204,7 @@ void CScriptGameObject::set_manual_invisibility(bool val) if (!monster) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CAI_Bloodsucker : cannot access class member set_manual_invisible!"); + make_string("CAI_Bloodsucker [%s]: cannot access class member set_manual_invisible!", object().cNameSect().c_str()).c_str()); return; } val ? monster->set_manual_control(true) : monster->set_manual_control(false); @@ -234,7 +234,7 @@ void CScriptGameObject::set_enemy(CScriptGameObject* e) if (!monster) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CAI_Bloodsucker : cannot access class member set_enemy!"); + make_string("CAI_Bloodsucker [%s]: cannot access class member set_enemy!", object().cNameSect().c_str()).c_str()); return; } CGameObject* game_object = &e->object(); @@ -248,7 +248,7 @@ void CScriptGameObject::set_vis_state(float val) if (!monster) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CAI_Bloodsucker : cannot access class member set_vis_state!"); + make_string("CAI_Bloodsucker [%s]: cannot access class member set_vis_state!", object().cNameSect().c_str()).c_str()); return; } if (val == 1) @@ -267,7 +267,7 @@ void CScriptGameObject::off_collision(bool val) if (!monster) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CAI_Bloodsucker : cannot access class member set_vis_state!"); + make_string("CAI_Bloodsucker [%s]: cannot access class member set_vis_state!", object().cNameSect().c_str()).c_str()); return; } monster->set_collision_off(val); @@ -279,7 +279,7 @@ void CScriptGameObject::set_alien_control(bool val) if (!monster) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CAI_Bloodsucker : cannot access class member alien_control_activate!"); + make_string("CAI_Bloodsucker [%s]: cannot access class member alien_control_activate!", object().cNameSect().c_str()).c_str()); return; } @@ -307,7 +307,7 @@ CScriptSoundInfo CScriptGameObject::GetSoundInfo() else { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CScriptGameObject : cannot access class member GetSoundInfo!"); + make_string("CScriptGameObject [%s]: cannot access class member GetSoundInfo!", object().cNameSect().c_str()).c_str()); } return (ret_val); } @@ -329,7 +329,7 @@ CScriptMonsterHitInfo CScriptGameObject::GetMonsterHitInfo() else { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CScriptGameObject : cannot access class member GetMonsterHitInfo!"); + make_string("CScriptGameObject [%s]: cannot access class member GetMonsterHitInfo!", object().cNameSect().c_str()).c_str()); } return (ret_val); } @@ -366,7 +366,7 @@ bool CScriptGameObject::fake_death_fall_down() if (!monster) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CZombie : cannot access class member fake_death_fall_down!"); + make_string("CZombie [%s]: cannot access class member fake_death_fall_down!", object().cNameSect().c_str()).c_str()); return false; } @@ -379,7 +379,7 @@ void CScriptGameObject::fake_death_stand_up() if (!monster) { ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, - "CZombie : cannot access class member fake_death_fall_down!"); + make_string("CZombie [%s]: cannot access class member fake_death_fall_down!", object().cNameSect().c_str()).c_str()); return; } diff --git a/src/xrGame/script_particle_action.cpp b/src/xrGame/script_particle_action.cpp index 1c0a645316..fcaff8de05 100644 --- a/src/xrGame/script_particle_action.cpp +++ b/src/xrGame/script_particle_action.cpp @@ -19,7 +19,7 @@ void CScriptParticleAction::SetParticle(LPCSTR caParticleToRun, bool bAutoRemove { m_caParticleToRun = caParticleToRun; m_tGoalType = eGoalTypeParticleAttached; - m_tpParticleSystem = CParticlesObject::Create(*m_caParticleToRun, BOOL(m_bAutoRemove = bAutoRemove)); + m_tpParticleSystem = Particles::Details::Create(*m_caParticleToRun, BOOL(m_bAutoRemove = bAutoRemove)); m_bStartedToPlay = false; m_bCompleted = false; } diff --git a/src/xrGame/script_particle_action.h b/src/xrGame/script_particle_action.h index d26db99210..2ae276ed80 100644 --- a/src/xrGame/script_particle_action.h +++ b/src/xrGame/script_particle_action.h @@ -28,7 +28,7 @@ class CScriptParticleAction : public CScriptAbstractAction shared_str m_caParticleToRun; shared_str m_caBoneName; EGoalType m_tGoalType; - CParticlesObject* m_tpParticleSystem; + intrusive_ptr m_tpParticleSystem; bool m_bStartedToPlay; Fvector m_tParticlePosition; Fvector m_tParticleAngles; diff --git a/src/xrGame/script_particles.cpp b/src/xrGame/script_particles.cpp index 6a72bb63e1..1dda5652f7 100644 --- a/src/xrGame/script_particles.cpp +++ b/src/xrGame/script_particles.cpp @@ -9,6 +9,7 @@ #include "stdafx.h" #include "script_particles.h" #include "../xrEngine/objectanimator.h" +#include "../xrEngine/IGame_Persistent.h" CScriptParticlesCustom::CScriptParticlesCustom(CScriptParticles* owner, LPCSTR caParticlesName): CParticlesObject( caParticlesName,FALSE, true) @@ -25,14 +26,16 @@ CScriptParticlesCustom::~CScriptParticlesCustom() void CScriptParticlesCustom::PSI_internal_delete() { if (m_owner) - m_owner->m_particles = NULL; - CParticlesObject::PSI_internal_delete(); + m_owner->m_particles = nullptr; + + CParticlesObject::PSI_destroy(); } void CScriptParticlesCustom::PSI_destroy() { if (m_owner) - m_owner->m_particles = NULL; + m_owner->m_particles = nullptr; + CParticlesObject::PSI_destroy(); } @@ -88,6 +91,7 @@ CScriptParticles::CScriptParticles(LPCSTR caParticlesName) { m_particles = xr_new(this, caParticlesName); m_transform.identity(); + g_pGamePersistent->ps_active_deffer.push_back(m_particles); } CScriptParticles::~CScriptParticles() diff --git a/src/xrGame/script_particles.h b/src/xrGame/script_particles.h index df46d5cca9..6265f46ee5 100644 --- a/src/xrGame/script_particles.h +++ b/src/xrGame/script_particles.h @@ -18,10 +18,10 @@ class CScriptParticles; class CScriptParticlesCustom : public CParticlesObject { CObjectAnimator* m_animator; - virtual ~CScriptParticlesCustom(); CScriptParticles* m_owner; public: CScriptParticlesCustom(CScriptParticles* owner, LPCSTR caParticlesName); + virtual ~CScriptParticlesCustom(); virtual void shedule_Update(u32 dt); void LoadPath(LPCSTR caPathName); @@ -38,7 +38,7 @@ class CScriptParticles private: Fmatrix m_transform; public: - CScriptParticlesCustom* m_particles; + intrusive_ptr m_particles; CScriptParticles(LPCSTR caParticlesName); virtual ~CScriptParticles(); diff --git a/src/xrGame/script_zone.cpp b/src/xrGame/script_zone.cpp index 5dff46bf6d..713b425dbe 100644 --- a/src/xrGame/script_zone.cpp +++ b/src/xrGame/script_zone.cpp @@ -49,6 +49,7 @@ void CScriptZone::net_Destroy() void CScriptZone::shedule_Update(u32 dt) { + PROF_EVENT("CScriptZone::shedule_Update"); inherited::shedule_Update(dt); const Fsphere& s = CFORM()->getSphere(); diff --git a/src/xrGame/script_zone.h b/src/xrGame/script_zone.h index 7793751561..5b57af635b 100644 --- a/src/xrGame/script_zone.h +++ b/src/xrGame/script_zone.h @@ -33,6 +33,9 @@ class CScriptZone : public CSpaceRestrictor, public Feel::Touch bool active_contact(u16 id) const; virtual bool IsVisibleForZones() { return false; } virtual bool register_schedule() const { return true; } + virtual CSpaceRestrictor* cast_restrictor() { return this; } + virtual CScriptZone* cast_script_zone() { return this; } + virtual CGameObject* cast_game_object() { return this; } #ifdef DEBUG virtual void OnRender (); #endif diff --git a/src/xrGame/searchlight.cpp b/src/xrGame/searchlight.cpp index 56ce237462..e3a1ea385b 100644 --- a/src/xrGame/searchlight.cpp +++ b/src/xrGame/searchlight.cpp @@ -97,6 +97,7 @@ BOOL CProjector::net_Spawn(CSE_Abstract* DC) if (str && strlen(str)) { int num = _GetItemCount(str); + m_lights.reserve(num); for (int idx = 0; idx < num; idx++) { string64 sec; @@ -117,6 +118,7 @@ BOOL CProjector::net_Spawn(CSE_Abstract* DC) if (str && strlen(str)) { int num = _GetItemCount(str); + m_controls.reserve(num); for (int idx = 0; idx < num; idx++) { string64 sec; @@ -290,9 +292,9 @@ void CProjector::UpdateCL() } -void CProjector::renderable_Render() +void CProjector::renderable_Render(IDSGraphManager* DM) { - inherited::renderable_Render(); + inherited::renderable_Render(DM); } BOOL CProjector::UsedAI_Locations() diff --git a/src/xrGame/searchlight.h b/src/xrGame/searchlight.h index 6a8364ba84..9915db8229 100644 --- a/src/xrGame/searchlight.h +++ b/src/xrGame/searchlight.h @@ -62,15 +62,20 @@ class CProjector : public CScriptObject #endif virtual void shedule_Update(u32 dt); // Called by sheduler virtual void UpdateCL(); // Called each frame, so no need for dt - virtual void renderable_Render(); + virtual void renderable_Render(IDSGraphManager* DM); virtual BOOL UsedAI_Locations(); + virtual CProjector* cast_projector() { return this; } + #ifdef PROJECTOR_NEW /* Remove. */ #else virtual bool bfAssignWatch(CScriptEntityAction* tpEntityAction); virtual bool bfAssignObject(CScriptEntityAction* tpEntityAction); + + virtual CScriptEntity* cast_script_entity() { return this; } + virtual CGameObject* cast_game_object() { return this; } #endif Fvector GetCurrentDirection(); @@ -186,4 +191,4 @@ struct SProjectorControl static void _BCL BoneCallbackY(CBoneInstance *B); void SetParam(int id, Fvector val); }; -#endif \ No newline at end of file +#endif diff --git a/src/xrGame/sight_action.cpp b/src/xrGame/sight_action.cpp index abded4c126..1f4628e74e 100644 --- a/src/xrGame/sight_action.cpp +++ b/src/xrGame/sight_action.cpp @@ -13,6 +13,8 @@ #include "ai_object_location.h" #include "stalker_movement_manager_smart_cover.h" #include "inventory.h" +#include "../xrEngine/CameraBase.h" +#include "Actor.h" //#define SIGHT_TEST @@ -164,7 +166,33 @@ void CSightAction::execute_position(Fvector const& look_position) void CSightAction::execute_object() { Fvector look_pos; - m_object_to_look->Center(look_pos); + + // demonized: my edit, very ugly but it works + const CActor* cpActor = smart_cast(m_object_to_look); + if(cpActor) + { + CActor* pActor = const_cast(cpActor); + if(pActor->HUDview()) + { + look_pos = pActor->cam_FirstEye()->Position(); + look_pos.y -= 0.9f; + } + else + { + IKinematics* kinematics = PKinematics(pActor->Visual()); + VERIFY(kinematics); + + u16 bone_id = kinematics->LL_BoneID("bip01_head"); + VERIFY2(bone_id != BI_NONE, make_string("Cannot find bone %s", bone_id)); + Fvector pos; + kinematics->LL_GetBoneWorldPosition(bone_id, pActor->XFORM(), pos); + look_pos = pos; + look_pos.y -= 0.9f; + } + m_object->Visual()->dcast_PKinematics()->CalculateBBox(FALSE); + } + else + m_object_to_look->Center(look_pos); Fvector my_position = m_object->eye_matrix.c; diff --git a/src/xrGame/sight_manager.cpp b/src/xrGame/sight_manager.cpp index 96ca304404..aa6e67f63f 100644 --- a/src/xrGame/sight_manager.cpp +++ b/src/xrGame/sight_manager.cpp @@ -302,6 +302,10 @@ Fvector CSightManager::object_position() const { CGameObject const* object = ¤t_action().object(); Fvector look_pos; + + if (const_cast(object)->cast_actor()) + object->Visual()->dcast_PKinematics()->CalculateBBox(FALSE); + object->Center(look_pos); const CEntityAlive* entity_alive = smart_cast(object); diff --git a/src/xrGame/sight_manager_target.cpp b/src/xrGame/sight_manager_target.cpp index d2209ed373..86f17b2244 100644 --- a/src/xrGame/sight_manager_target.cpp +++ b/src/xrGame/sight_manager_target.cpp @@ -37,7 +37,7 @@ void CSightManager::SetPointLookAngles(const Fvector& tPosition, float& yaw, flo } #include "actor.h" -void aim_target(shared_str const& aim_bone_id, Fvector& result, const CGameObject* object); +#include "../xrEngine/CameraBase.h" bool CSightManager::aim_target(Fvector& my_position, Fvector& aim_target, const CGameObject* object) const { @@ -50,26 +50,27 @@ bool CSightManager::aim_target(Fvector& my_position, Fvector& aim_target, const return (true); } - extern CActor* g_actor; + CGameObject* GO = const_cast(object); - if (g_actor == object) + if (GO && GO->cast_entity() && GO->cast_entity()->g_Alive() && (GO->cast_actor() || GO->cast_stalker())) { - ::aim_target("bip01_head", aim_target, object); - return (true); - } - - if (CAI_Stalker const* stalker = smart_cast(object)) - { - if (stalker->g_Alive()) + if (GO->cast_actor() && GO->cast_actor()->HUDview()) + aim_target = GO->cast_actor()->cam_Active()->vPosition; + else { - ::aim_target("bip01_head", aim_target, object); - return (true); + IKinematics* kinematics = PKinematics(object->Visual()); + u16 bone_id = kinematics->LL_BoneID("bip01_head"); + kinematics->LL_GetBoneWorldPosition(bone_id, object->XFORM(), aim_target); } + return (true); } if (!object->use_center_to_aim()) return (false); + if (GO->cast_actor()) + m_object->Visual()->dcast_PKinematics()->CalculateBBox(FALSE); + m_object->Center(my_position); #if 1 //. hack is here, just because our actor model is animated with 20cm shift diff --git a/src/xrGame/smart_cover_object.cpp b/src/xrGame/smart_cover_object.cpp index 5db9863fab..a65ecf6137 100644 --- a/src/xrGame/smart_cover_object.cpp +++ b/src/xrGame/smart_cover_object.cpp @@ -56,7 +56,7 @@ BOOL object::net_Spawn(CSE_Abstract* server_entity) if (!inherited::net_Spawn(server_entity)) return (FALSE); - spatial.type &= ~STYPE_VISIBLEFORAI; + SpatialComponent->spatial.type &= ~STYPE_VISIBLEFORAI; m_enter_min_enemy_distance = smart_cover->m_enter_min_enemy_distance; m_exit_min_enemy_distance = smart_cover->m_exit_min_enemy_distance; diff --git a/src/xrGame/sound_memory_manager.cpp b/src/xrGame/sound_memory_manager.cpp index 6e62ae9f40..d3b7376f53 100644 --- a/src/xrGame/sound_memory_manager.cpp +++ b/src/xrGame/sound_memory_manager.cpp @@ -22,9 +22,13 @@ #include "ai/stalker/ai_stalker.h" #include "profiler.h" #include "client_spawn_manager.h" -#include "memory_manager.h" #include "../xrEngine/IGame_Persistent.h" +#include "stalker_movement_manager_smart_cover.h" +#include "movement_manager_space.h" +#include "stalker_planner.h" +#include "ai_sounds.h" + #ifndef MASTER_GOLD # include "actor.h" # include "ai_debug.h" @@ -33,9 +37,9 @@ #define SILENCE //#define SAVE_OWN_SOUNDS //#define SAVE_OWN_ITEM_SOUNDS -#define SAVE_NON_ALIVE_OBJECT_SOUNDS -#define SAVE_FRIEND_ITEM_SOUNDS -#define SAVE_FRIEND_SOUNDS +// #define SAVE_NON_ALIVE_OBJECT_SOUNDS +// #define SAVE_FRIEND_ITEM_SOUNDS +// #define SAVE_FRIEND_SOUNDS //#define SAVE_VISIBLE_OBJECT_SOUNDS const float COMBAT_SOUND_PERCEIVE_RADIUS_SQR = _sqr(5.f); @@ -128,6 +132,7 @@ IC bool is_sound_type(int s, const ESoundTypes& t) void CSoundMemoryManager::feel_sound_new(CObject* object, int sound_type, CSound_UserDataPtr user_data, const Fvector& position, float sound_power) { + PROF_EVENT("SoundMemory::feel_sound_new"); #ifndef MASTER_GOLD if (object && smart_cast(object) && psAI_Flags.test(aiIgnoreActor)) return; @@ -230,6 +235,7 @@ void CSoundMemoryManager::add(const CSoundObject& sound_object, bool check_for_e void CSoundMemoryManager::add(const CObject* object, int sound_type, const Fvector& position, float sound_power) { + PROF_EVENT("SoundMemory::add"); #ifndef SAVE_OWN_SOUNDS // we do not want to save our own sounds if (object && (m_object->ID() == object->ID())) @@ -248,33 +254,47 @@ void CSoundMemoryManager::add(const CObject* object, int sound_type, const Fvect return; #endif -#ifndef SAVE_FRIEND_ITEM_SOUNDS - // we do not want to save sounds from the teammates items - CEntityAlive *me = m_object; - if (object && object->H_Parent() && (me->tfGetRelationType(smart_cast(object->H_Parent())) == ALife::eRelationTypeFriend)) + // we do not want to save sounds from the teammates and neutrals items + CEntityAlive *me_entity_alive = m_object; + if (object && object->H_Parent() && smart_cast(object->H_Parent()) && (me_entity_alive->tfGetRelationType(smart_cast(object->H_Parent())) == ALife::eRelationTypeFriend || me_entity_alive->tfGetRelationType(smart_cast(object->H_Parent())) == ALife::eRelationTypeNeutral)) return; -#endif -#ifndef SAVE_FRIEND_SOUNDS - const CEntityAlive *entity_alive = smart_cast(object); - // we do not want to save sounds from the teammates - if (entity_alive && me && (me->tfGetRelationType(entity_alive) == ALife::eRelationTypeFriend)) + const CEntityAlive *who_entity_alive = smart_cast(object); + // we do not want to save sounds from the teammates and neutrals + if (who_entity_alive && me_entity_alive && (me_entity_alive->tfGetRelationType(who_entity_alive) == ALife::eRelationTypeFriend || me_entity_alive->tfGetRelationType(who_entity_alive) == ALife::eRelationTypeNeutral)) return; -#endif -#ifndef SAVE_VISIBLE_OBJECT_SOUNDS -# ifdef SAVE_FRIEND_SOUNDS - const CEntityAlive* entity_alive = smart_cast(object); -# endif - // we do not save sounds from the objects we see (?!) - if (m_object->memory().visual().visible_now(entity_alive)) + if(who_entity_alive && !m_object->memory().enemy().is_useful(who_entity_alive)) return; -#endif const CGameObject* game_object = smart_cast(object); if (!game_object && object) return; + bool heavy_sound = ((sound_type&SOUND_TYPE_WEAPON_SHOOTING) == SOUND_TYPE_WEAPON_SHOOTING || + (sound_type&SOUND_TYPE_WEAPON_BULLET_HIT) == SOUND_TYPE_WEAPON_BULLET_HIT || + (sound_type&SOUND_TYPE_WEAPON_EMPTY_CLICKING) == SOUND_TYPE_WEAPON_EMPTY_CLICKING || + (sound_type&SOUND_TYPE_STEP) == SOUND_TYPE_STEP); + + if(heavy_sound && sound_power >= 4.f) + { + if(CAI_Stalker *stalker = smart_cast(m_object)) + { + if(who_entity_alive && who_entity_alive->g_Alive() && !m_object->memory().visual().visible_now(who_entity_alive)) + { + stalker->movement().set_mental_state(eMentalStateDanger); + CNotYetVisibleObject new_object; + new_object.m_object = smart_cast(object); + new_object.m_value = 1.0f; + new_object.m_prev_time = Device.dwTimeGlobal-1; + new_object.m_update_time = Device.dwTimeGlobal; + m_object->memory().visual().add_not_yet_visible_object(new_object); + m_object->memory().visual().add_visible_object(object, Device.fTimeDelta); + //Msg("sound_power %f", sound_power); + } + } + } + const CGameObject* self = m_object; xr_vector::iterator J = std::find(m_sounds->begin(), m_sounds->end(), object_id(object)); @@ -321,15 +341,15 @@ void CSoundMemoryManager::update() START_PROFILE("Memory Manager/sounds::update") clear_delayed_objects(); - VERIFY(m_sounds); - m_sounds->erase( - std::remove_if( - m_sounds->begin(), - m_sounds->end(), - CRemoveOfflinePredicate() - ), - m_sounds->end() - ); + if (m_sounds) + m_sounds->erase( + std::remove_if( + m_sounds->begin(), + m_sounds->end(), + CRemoveOfflinePredicate() + ), + m_sounds->end() + ); #ifdef USE_SELECTED_SOUND xr_delete (m_selected_sound); @@ -371,10 +391,12 @@ struct CSoundObjectPredicate void CSoundMemoryManager::remove_links(CObject* object) { - VERIFY(m_sounds); - SOUNDS::iterator I = std::find_if(m_sounds->begin(), m_sounds->end(), CSoundObjectPredicate(object)); - if (I != m_sounds->end()) - m_sounds->erase(I); + if (m_sounds) + { + SOUNDS::iterator I = std::find_if(m_sounds->begin(), m_sounds->end(), CSoundObjectPredicate(object)); + if (I != m_sounds->end()) + m_sounds->erase(I); + } #ifdef USE_SELECTED_SOUND if (!m_selected_sound) diff --git a/src/xrGame/space_restriction_bridge.h b/src/xrGame/space_restriction_bridge.h index 42000ba737..bd917e2a8a 100644 --- a/src/xrGame/space_restriction_bridge.h +++ b/src/xrGame/space_restriction_bridge.h @@ -14,6 +14,7 @@ class CSpaceRestrictionBase; class CSpaceRestrictionBridge : public RestrictionSpace::CTimeIntrusiveBase { + friend class CSpaceRestrictionHolder; protected: CSpaceRestrictionBase* m_object; diff --git a/src/xrGame/space_restriction_composition.h b/src/xrGame/space_restriction_composition.h index f4a9d5d9f0..a4097b9b0a 100644 --- a/src/xrGame/space_restriction_composition.h +++ b/src/xrGame/space_restriction_composition.h @@ -16,6 +16,7 @@ extern int g_restriction_checker; class CSpaceRestrictionComposition : public CSpaceRestrictionBase { + friend class CSpaceRestrictionHolder; public: using CSpaceRestrictionBase::inside; diff --git a/src/xrGame/space_restriction_holder.cpp b/src/xrGame/space_restriction_holder.cpp index 5be990f006..ca69e0be03 100644 --- a/src/xrGame/space_restriction_holder.cpp +++ b/src/xrGame/space_restriction_holder.cpp @@ -29,7 +29,32 @@ CSpaceRestrictionHolder::~CSpaceRestrictionHolder() void CSpaceRestrictionHolder::clear() { - delete_data(m_restrictions); + // FX: Сначала нужно удалять групповые рестрикторы, + // т.к. они используют ref_counter. Если чистить простые, то в IntrusivePtr остаются битые указатели + // что приводит к порче памяти + + for (auto& [_, SharedPtr] : m_restrictions) + { + if (CSpaceRestrictionComposition* Obj = smart_cast(SharedPtr->m_object)) + { + if (Obj->m_restrictions.size() > 0) + { + xr_delete(SharedPtr); + } + } + continue; + } + + for (auto& [_, SharedPtr] : m_restrictions) + { + if (SharedPtr == nullptr) + continue; + + xr_delete(SharedPtr); + } + + m_restrictions.clear(); + m_default_out_restrictions = ""; m_default_in_restrictions = ""; } @@ -182,12 +207,20 @@ bool try_remove_string(shared_str& search_string, const shared_str& string_to_se void CSpaceRestrictionHolder::unregister_restrictor(CSpaceRestrictor* space_restrictor) { + if (m_restrictions.empty()) + return; + shared_str restrictor_id = space_restrictor->cName(); RESTRICTIONS::iterator I = m_restrictions.find(restrictor_id); - VERIFY(I != m_restrictions.end()); - + if (I == m_restrictions.end()) + { + return; + } + CSpaceRestrictionBridge* bridge = (*I).second; m_restrictions.erase(I); + if (!bridge) + return; if (try_remove_string(m_default_out_restrictions, restrictor_id)) on_default_restrictions_changed(); diff --git a/src/xrGame/space_restriction_manager.cpp b/src/xrGame/space_restriction_manager.cpp index 8ec25ebad3..cbdfa8669d 100644 --- a/src/xrGame/space_restriction_manager.cpp +++ b/src/xrGame/space_restriction_manager.cpp @@ -145,6 +145,9 @@ void CSpaceRestrictionManager::restrict(ALife::_OBJECT_ID id, shared_str out_res void CSpaceRestrictionManager::unrestrict(ALife::_OBJECT_ID id) { + if (m_clients->empty()) + return; + CLIENT_RESTRICTIONS::iterator I = m_clients->find(id); VERIFY(I != m_clients->end()); m_clients->erase(I); @@ -179,7 +182,7 @@ CSpaceRestrictionManager::CRestrictionPtr CSpaceRestrictionManager::restriction( out_restrictors = normalize_string(out_restrictors); in_restrictors = normalize_string(in_restrictors); - strconcat(sizeof(m_temp), m_temp, *out_restrictors, "\x01", *in_restrictors); + xr_strconcat(m_temp, *out_restrictors, "\x01", *in_restrictors); shared_str space_restrictions = m_temp; SPACE_RESTRICTIONS::const_iterator I = m_space_restrictions.find(space_restrictions); @@ -187,7 +190,7 @@ CSpaceRestrictionManager::CRestrictionPtr CSpaceRestrictionManager::restriction( return ((*I).second); CSpaceRestriction* client_restriction = xr_new(this, out_restrictors, in_restrictors); - m_space_restrictions.insert(std::make_pair(space_restrictions, client_restriction)); + m_space_restrictions[space_restrictions] = client_restriction; return (client_restriction); } diff --git a/src/xrGame/space_restrictor.cpp b/src/xrGame/space_restrictor.cpp index 3b50ea4087..a41ed7d77f 100644 --- a/src/xrGame/space_restrictor.cpp +++ b/src/xrGame/space_restrictor.cpp @@ -81,7 +81,7 @@ BOOL CSpaceRestrictor::net_Spawn(CSE_Abstract* data) CCustomZone* zone = smart_cast(this); //if (g_ai_die_in_anomaly == 0 || !zone || smart_cast(zone) || smart_cast(zone)) if (!zone || smart_cast(zone) || smart_cast(zone)) - spatial.type &= ~STYPE_VISIBLEFORAI; + SpatialComponent->spatial.type &= ~STYPE_VISIBLEFORAI; setEnabled(FALSE); setVisible(FALSE); @@ -330,3 +330,9 @@ void CSpaceRestrictor::OnRender () } #endif + +void CSpaceRestrictor::shedule_Update(u32 dt) +{ + PROF_EVENT("CSpaceRestrictor::shedule_Update"); + inherited::shedule_Update(dt); +} diff --git a/src/xrGame/space_restrictor.h b/src/xrGame/space_restrictor.h index 831de38a65..6eb9377189 100644 --- a/src/xrGame/space_restrictor.h +++ b/src/xrGame/space_restrictor.h @@ -12,6 +12,8 @@ #include "restriction_space.h" #include "script_export_space.h" +class CScriptZone; + class CSpaceRestrictor : public CGameObject { private: @@ -60,9 +62,14 @@ class CSpaceRestrictor : public CGameObject virtual BOOL UsedAI_Locations(); virtual void spatial_move(); IC bool actual() const; + virtual CCustomZone* cast_custom_zone() { return nullptr; } virtual CSpaceRestrictor* cast_restrictor() { return this; } + virtual CGameObject* cast_game_object() { return this; } + virtual CScriptZone* cast_script_zone() { return nullptr; } virtual bool register_schedule() const { return false; } + virtual void shedule_Update(u32 dt); + IC RestrictionSpace::ERestrictorTypes restrictor_type() const; public: diff --git a/src/xrGame/stalker_animation_manager.h b/src/xrGame/stalker_animation_manager.h index 4f4e7fcf97..ecb394ac6e 100644 --- a/src/xrGame/stalker_animation_manager.h +++ b/src/xrGame/stalker_animation_manager.h @@ -84,9 +84,9 @@ class CStalkerAnimationManager bool m_special_danger_move; public: - typedef fastdelegate::FastDelegate AnimationSelector; - typedef fastdelegate::FastDelegate AnimationCallback; - typedef fastdelegate::FastDelegate AnimationModifier; + typedef xr_delegate AnimationSelector; + typedef xr_delegate AnimationCallback; + typedef xr_delegate AnimationModifier; private: AnimationSelector m_global_selector; diff --git a/src/xrGame/stalker_animation_manager_update.cpp b/src/xrGame/stalker_animation_manager_update.cpp index e353f5bed4..5a02de2134 100644 --- a/src/xrGame/stalker_animation_manager_update.cpp +++ b/src/xrGame/stalker_animation_manager_update.cpp @@ -13,6 +13,7 @@ #include "script_callback_ex.h" #include "profiler.h" #include "stalker_movement_manager_smart_cover.h" +#include "Inventory.h" void CStalkerAnimationManager::play_delayed_callbacks() { @@ -251,7 +252,16 @@ void CStalkerAnimationManager::update() } catch (...) { - Msg("! error in stalker with visual %s", *object().cNameVisual()); + Msg("! error in stalker [%s], profile [%s] with visual [%s]", + object().cNameSect().c_str(), + object().cast_inventory_owner()->CharacterInfo().GetSpecificCharacterId().c_str(), + object().cNameVisual().c_str()); + + for (auto& invItem : m_object->cast_inventory_owner()->m_inventory->m_all) + { + Msg("# Inventory item: [%s] - %s", invItem->m_section_id.c_str(), invItem->m_name.c_str()); + } + /* avo: prevent game from crashing */ global().reset(); head().reset(); diff --git a/src/xrGame/stalker_animation_pair.h b/src/xrGame/stalker_animation_pair.h index cb237ecc28..fb00e96eb1 100644 --- a/src/xrGame/stalker_animation_pair.h +++ b/src/xrGame/stalker_animation_pair.h @@ -31,7 +31,7 @@ class CStalkerAnimationPair typedef std::pair BLEND_ID; public: - typedef fastdelegate::FastDelegate0<> CALLBACK_ID; + typedef xr_delegate CALLBACK_ID; typedef xr_vector CALLBACKS; private: diff --git a/src/xrGame/stalker_combat_action_base.cpp b/src/xrGame/stalker_combat_action_base.cpp index 11a789f289..49b96c1d4c 100644 --- a/src/xrGame/stalker_combat_action_base.cpp +++ b/src/xrGame/stalker_combat_action_base.cpp @@ -270,35 +270,40 @@ void CStalkerActionCombatBase::play_panic_sound(u32 max_start_time, u32 min_star } void CStalkerActionCombatBase::play_attack_sound(u32 max_start_time, u32 min_start_time, u32 max_stop_time, - u32 min_stop_time, u32 id) + u32 min_stop_time, u32 id) { - if (!object().memory().enemy().selected()->human_being()) - return; + if (!object().memory().enemy().selected()->human_being()) + return; - if (!object().agent_manager().member().can_cry_noninfo_phrase()) - return; + if (!object().agent_manager().member().can_cry_noninfo_phrase()) + return; - u32 sound_type = eStalkerSoundAttackNoAllies; + u32 sound_type = eStalkerSoundAttackNoAllies; #ifdef DEBUG - if (object().agent_manager().member().combat_members().empty()) - Msg ( - "! I am in combat, but there is no combat members at all (including me), npc[%s],team[%d],squad[%d],group[%d]", - *object().cName(), - object().g_Team(), - object().g_Squad(), - object().g_Group() - ); + { + if (object().agent_manager().member().combat_members().empty()) + Msg( + "! I am in combat, but there is no combat members at all (including me), npc[%s],team[%d],squad[%d],group[%d]", + *object().cName(), + object().g_Team(), + object().g_Squad(), + object().g_Group() + ); + } #endif // DEBUG - if (object().agent_manager().member().combat_members().size() > 1) - { - if (object().agent_manager().enemy().enemies().size() > 1) - sound_type = eStalkerSoundAttackAlliesSeveralEnemies; - else - sound_type = eStalkerSoundAttackAlliesSingleEnemy; - } - else - sound_type = eStalkerSoundAttackNoAllies; + { + + if (object().agent_manager().member().combat_members().size() > 1) + { + if (object().agent_manager().enemy().enemies().size() > 1) + sound_type = eStalkerSoundAttackAlliesSeveralEnemies; + else + sound_type = eStalkerSoundAttackAlliesSingleEnemy; + } + else + sound_type = eStalkerSoundAttackNoAllies; + } object().sound().play( sound_type, @@ -311,22 +316,29 @@ void CStalkerActionCombatBase::play_attack_sound(u32 max_start_time, u32 min_sta } void CStalkerActionCombatBase::play_start_search_sound(u32 max_start_time, u32 min_start_time, u32 max_stop_time, - u32 min_stop_time, u32 id) + u32 min_stop_time, u32 id) { - if (!object().agent_manager().member().can_cry_noninfo_phrase()) - return; + if (!object().agent_manager().member().can_cry_noninfo_phrase()) + return; #ifdef DEBUG - if (object().agent_manager().member().combat_members().empty()) - Msg ("! I am in combat, but there is no combat members at all (including me), npc[%s],team[%d],squad[%d],group[%d]", - *object().cName(), - object().g_Team(), - object().g_Squad(), - object().g_Group() - ); + { + + if (object().agent_manager().member().combat_members().empty()) + Msg("! I am in combat, but there is no combat members at all (including me), npc[%s],team[%d],squad[%d],group[%d]", + *object().cName(), + object().g_Team(), + object().g_Squad(), + object().g_Group() + ); + } #endif // DEBUG - bool search_with_allies = object().agent_manager().member().combat_members().size() > 1; + bool search_with_allies; + { + + search_with_allies = object().agent_manager().member().combat_members().size() > 1; + } object().sound().play( search_with_allies ? eStalkerSoundSearch1WithAllies : eStalkerSoundSearch1NoAllies, @@ -339,22 +351,29 @@ void CStalkerActionCombatBase::play_start_search_sound(u32 max_start_time, u32 m } void CStalkerActionCombatBase::play_enemy_lost_sound(u32 max_start_time, u32 min_start_time, u32 max_stop_time, - u32 min_stop_time, u32 id) + u32 min_stop_time, u32 id) { - if (!object().agent_manager().member().can_cry_noninfo_phrase()) - return; + if (!object().agent_manager().member().can_cry_noninfo_phrase()) + return; #ifdef DEBUG - if (object().agent_manager().member().combat_members().empty()) - Msg ("! I am in combat, but there is no combat members at all (including me), npc[%s],team[%d],squad[%d],group[%d]", - *object().cName(), - object().g_Team(), - object().g_Squad(), - object().g_Group() - ); + { + + if (object().agent_manager().member().combat_members().empty()) + Msg("! I am in combat, but there is no combat members at all (including me), npc[%s],team[%d],squad[%d],group[%d]", + *object().cName(), + object().g_Team(), + object().g_Squad(), + object().g_Group() + ); + } #endif // DEBUG - bool search_with_allies = object().agent_manager().member().combat_members().size() > 1; + bool search_with_allies; + { + + search_with_allies = object().agent_manager().member().combat_members().size() > 1; + } object().sound().play( search_with_allies ? eStalkerSoundEnemyLostWithAllies : eStalkerSoundEnemyLostNoAllies, diff --git a/src/xrGame/stalker_combat_planner.cpp b/src/xrGame/stalker_combat_planner.cpp index 2a0d055a8a..a43df89a87 100644 --- a/src/xrGame/stalker_combat_planner.cpp +++ b/src/xrGame/stalker_combat_planner.cpp @@ -178,8 +178,11 @@ void CStalkerCombatPlanner::initialize() m_loaded = false; - if (!object().agent_manager().member().combat_members().empty()) - CScriptActionPlanner::m_storage.set_property(eWorldPropertyUseSuddenness, false); + { + + if (!object().agent_manager().member().combat_members().empty()) + CScriptActionPlanner::m_storage.set_property(eWorldPropertyUseSuddenness, false); + } // this is possible when i enter combat when it is wait after combat stage // VERIFY (object().memory().enemy().selected()); diff --git a/src/xrGame/stalker_movement_manager_base.cpp b/src/xrGame/stalker_movement_manager_base.cpp index 1aa009a64f..74da92f946 100644 --- a/src/xrGame/stalker_movement_manager_base.cpp +++ b/src/xrGame/stalker_movement_manager_base.cpp @@ -22,11 +22,11 @@ #include "stalker_velocity_holder.h" #include "stalker_velocity_collection.h" #include "stalker_animation_manager.h" +#include "stalker_planner.h" #include "smart_cover_animation_selector.h" #ifdef DEBUG # include "stalker_decision_space.h" -# include "stalker_planner.h" # include "script_game_object.h" # include "stalker_combat_planner.h" #endif // DEBUG @@ -288,8 +288,22 @@ void stalker_movement_manager_base::setup_movement_params(stalker_movement_param if (!restrictions().accessible(*movement_params.desired_position())) { Fvector temp; - level_path().set_dest_vertex(restrictions().accessible_nearest(*movement_params.desired_position(), temp)); - detail().set_dest_position(temp); + const u32 nearest_vertex_id = + restrictions().accessible_nearest(*movement_params.desired_position(), temp); + if (!ai().level_graph().valid_vertex_id(nearest_vertex_id)) + { + Msg( + "! [stalker_movement_manager_base::setup_movement_params] cannot find an accessible " + "destination vertex for object [%s], forcing standstill", + object().cName().c_str() + ); + movement_params.m_movement_type = eMovementTypeStand; + } + else + { + level_path().set_dest_vertex(nearest_vertex_id); + detail().set_dest_position(temp); + } } else detail().set_dest_position(*movement_params.desired_position()); @@ -302,23 +316,73 @@ void stalker_movement_manager_base::setup_movement_params(stalker_movement_param (movement_params.m_path_type != MovementManager::ePathTypeNoPath) ) { - if (!restrictions().accessible(level_path().dest_vertex_id())) + u32 dest_vertex_id = level_path().dest_vertex_id(); + if (!ai().level_graph().valid_vertex_id(dest_vertex_id)) + { + LPCSTR action_name = ""; + if (object().brain().initialized()) + { + LPCSTR current_action_name = object().brain().current_action().m_action_name; + action_name = current_action_name ? current_action_name : ""; + } + + const u32 current_vertex_id = object().ai_location().level_vertex_id(); + Msg( + "! [stalker_movement_manager_base::setup_movement_params] invalid destination vertex [%u], " + "object [%s], action [%s], current vertex [%u]", + dest_vertex_id, + object().cName().c_str(), + action_name, + current_vertex_id + ); + + if (ai().level_graph().valid_vertex_id(current_vertex_id)) + { + set_nearest_accessible_position(object().Position(), current_vertex_id); + dest_vertex_id = level_path().dest_vertex_id(); + } + + if (!ai().level_graph().valid_vertex_id(dest_vertex_id)) + { + Msg( + "! [stalker_movement_manager_base::setup_movement_params] cannot recover destination " + "vertex for object [%s], forcing standstill", + object().cName().c_str() + ); + movement_params.m_movement_type = eMovementTypeStand; + return; + } + } + + if (!restrictions().accessible(dest_vertex_id)) { Fvector temp; - level_path().set_dest_vertex( - restrictions().accessible_nearest(ai().level_graph().vertex_position(level_path().dest_vertex_id()), - temp)); - detail().set_dest_position(temp); + const u32 nearest_vertex_id = + restrictions().accessible_nearest(ai().level_graph().vertex_position(dest_vertex_id), temp); + if (!ai().level_graph().valid_vertex_id(nearest_vertex_id)) + { + Msg( + "! [stalker_movement_manager_base::setup_movement_params] cannot find an accessible " + "vertex near destination [%u] for object [%s], forcing standstill", + dest_vertex_id, + object().cName().c_str() + ); + movement_params.m_movement_type = eMovementTypeStand; + } + else + { + level_path().set_dest_vertex(nearest_vertex_id); + detail().set_dest_position(temp); + } } else { - u32 vertex_id = level_path().dest_vertex_id(); - Fvector vertex_position = ai().level_graph().vertex_position(level_path().dest_vertex_id()); + Fvector vertex_position = ai().level_graph().vertex_position(dest_vertex_id); VERIFY2( restrictions().accessible(vertex_position) || show_restrictions(&restrictions()), make_string( "vertex_id[%d],position[%f][%f][%f],object[%s]", - vertex_id, + dest_vertex_id, VPUSH(vertex_position), *object().cName() ) @@ -589,6 +653,17 @@ void stalker_movement_manager_base::set_nearest_accessible_position() void stalker_movement_manager_base::set_nearest_accessible_position(Fvector desired_position, u32 level_vertex_id) { + if (!ai().level_graph().valid_vertex_id(level_vertex_id)) + { + Msg( + "! [stalker_movement_manager_base::set_nearest_accessible_position] invalid source vertex [%u] " + "for object [%s]", + level_vertex_id, + object().cName().c_str() + ); + return; + } + if (!ai().level_graph().inside(level_vertex_id, desired_position)) desired_position = ai().level_graph().vertex_position(level_vertex_id); else @@ -597,6 +672,16 @@ void stalker_movement_manager_base::set_nearest_accessible_position(Fvector desi if (!restrictions().accessible(desired_position)) { level_vertex_id = restrictions().accessible_nearest(Fvector().set(desired_position), desired_position); + if (!ai().level_graph().valid_vertex_id(level_vertex_id)) + { + Msg( + "! [stalker_movement_manager_base::set_nearest_accessible_position] cannot find an accessible " + "vertex for object [%s]", + object().cName().c_str() + ); + return; + } + VERIFY(restrictions().accessible(level_vertex_id)); VERIFY(restrictions().accessible(desired_position)); } @@ -606,6 +691,16 @@ void stalker_movement_manager_base::set_nearest_accessible_position(Fvector desi { level_vertex_id = restrictions().accessible_nearest(ai().level_graph().vertex_position(level_vertex_id), desired_position); + if (!ai().level_graph().valid_vertex_id(level_vertex_id)) + { + Msg( + "! [stalker_movement_manager_base::set_nearest_accessible_position] cannot find an " + "accessible replacement vertex for object [%s]", + object().cName().c_str() + ); + return; + } + VERIFY(restrictions().accessible(level_vertex_id)); VERIFY(restrictions().accessible(desired_position)); } diff --git a/src/xrGame/steering_behaviour.h b/src/xrGame/steering_behaviour.h index f10836e482..3bda29e496 100644 --- a/src/xrGame/steering_behaviour.h +++ b/src/xrGame/steering_behaviour.h @@ -266,7 +266,7 @@ namespace steering_behaviour float turn_factor; vec thrust_factor; - typedef std::vector Probes; + typedef xr_vector Probes; Probes probes; // obstacle-scanners (vectors in local (dir,up) space) params(float turn_factor, vec_arg thrust_factor, diff --git a/src/xrGame/step_manager.cpp b/src/xrGame/step_manager.cpp index c6bc69ab95..3f86cc48c5 100644 --- a/src/xrGame/step_manager.cpp +++ b/src/xrGame/step_manager.cpp @@ -226,7 +226,7 @@ void CStepManager::update(bool b_hud_view) LPCSTR ps_name = *mtl_pair->CollideParticles[::Random.randI(0, mtl_pair->CollideParticles.size())]; //отыграть партиклы столкновения материалов - CParticlesObject* ps = CParticlesObject::Create(ps_name,TRUE); + intrusive_ptr ps = Particles::Details::Create(ps_name,TRUE); // вычислить позицию и направленность партикла Fmatrix pos; diff --git a/src/xrGame/team_base_zone.h b/src/xrGame/team_base_zone.h index def163c3f4..6d8e0bf63c 100644 --- a/src/xrGame/team_base_zone.h +++ b/src/xrGame/team_base_zone.h @@ -33,6 +33,9 @@ class CTeamBaseZone : public CGameObject, public Feel::Touch virtual bool feel_touch_contact(CObject* O); virtual u8 GetZoneTeam() { return m_Team; }; + + virtual CTeamBaseZone* cast_team_base_zone() { return this; }; + #ifdef DEBUG virtual void OnRender (); #endif diff --git a/src/xrGame/ui/ArtefactDetectorUI.h b/src/xrGame/ui/ArtefactDetectorUI.h index e287531bcb..5299fa118f 100644 --- a/src/xrGame/ui/ArtefactDetectorUI.h +++ b/src/xrGame/ui/ArtefactDetectorUI.h @@ -35,6 +35,8 @@ class CUIDetectorWave : public CUIFrameLineWnd void InitFromXML(CUIXml& xml, LPCSTR path); void SetVelocity(float v); virtual void Update(); + + virtual CUIWindow* ui_cast_window() { return this; } }; class CUIArtefactDetectorSimple : public CUICustomDeviceBase @@ -90,6 +92,8 @@ class CUIArtefactDetectorElite : public CUICustomDeviceBase, public CUIWindow void construct(CEliteDetector* p); void Clear(); void RegisterItemToDraw(const Fvector& p, const shared_str& palette_idx); + + virtual CUIWindow* ui_cast_window() { return this; } }; diff --git a/src/xrGame/ui/ChangeWeatherDialog.hpp b/src/xrGame/ui/ChangeWeatherDialog.hpp index a006257dc2..b734264664 100644 --- a/src/xrGame/ui/ChangeWeatherDialog.hpp +++ b/src/xrGame/ui/ChangeWeatherDialog.hpp @@ -64,6 +64,8 @@ class ChangeWeatherDialog : public ButtonListDialog virtual void OnButtonClick(int i) override; // ~ButtonListDialog + virtual CUIWindow* ui_cast_window() { return this; } + private: void ParseWeather(); }; @@ -79,4 +81,6 @@ class ChangeGameTypeDialog : public ButtonListDialog // ButtonListDialog virtual void OnButtonClick(int i) override; // ~ButtonListDialog + + virtual CUIWindow* ui_cast_window() { return this; } }; diff --git a/src/xrGame/ui/UI3tButton.cpp b/src/xrGame/ui/UI3tButton.cpp index 2a202980a8..09e91b5416 100644 --- a/src/xrGame/ui/UI3tButton.cpp +++ b/src/xrGame/ui/UI3tButton.cpp @@ -17,7 +17,8 @@ CUI3tButton::CUI3tButton() m_background = NULL; m_back_frameline = NULL; - m_frameline_mode = false; + m_back_framewindow = NULL; + m_frameline_mode = Framemode_None; } @@ -73,7 +74,7 @@ void CUI3tButton::InitButton(Fvector2 pos, Fvector2 size) { // Custom draw: the background is painted by DrawTexture, so keep it out of the child list, which // runs after DrawTexture and would paint it a second time over anything layered on the face. - if (m_frameline_mode) + if (m_frameline_mode == Framemode_Line) { if (!m_back_frameline) { @@ -85,6 +86,17 @@ void CUI3tButton::InitButton(Fvector2 pos, Fvector2 size) m_back_frameline->SetWndPos(Fvector2().set(0, 0)); m_back_frameline->SetWndSize(size); } + else if (m_frameline_mode == Framemode_Window) + { + if (!m_back_framewindow) + { + m_back_framewindow = xr_new(); + m_back_framewindow->SetAutoDelete(true); + AttachChild(m_back_framewindow); + } + m_back_framewindow->SetWndPos(Fvector2().set(0, 0)); + m_back_framewindow->SetWndSize(size); + } else { if (!m_background) @@ -106,6 +118,7 @@ void CUI3tButton::SetWidth(float width) CUIButton::SetWidth(width); if (m_background) { m_background->SetWidth(width); } else if (m_back_frameline) { m_back_frameline->SetWidth(width); } + else if (m_back_framewindow) { m_back_framewindow->SetWidth(width); } } void CUI3tButton::SetHeight(float height) @@ -113,6 +126,7 @@ void CUI3tButton::SetHeight(float height) CUIButton::SetHeight(height); if (m_background) { m_background->SetHeight(height); } else if (m_back_frameline) { m_back_frameline->SetHeight(height); } + else if (m_back_framewindow) { m_back_framewindow->SetHeight(height); } } void CUI3tButton::InitTexture(LPCSTR tex_name) @@ -160,6 +174,13 @@ void CUI3tButton::InitTexture(LPCSTR tex_enabled, m_back_frameline->InitState(S_Touched, tex_touched); m_back_frameline->InitState(S_Highlighted, tex_highlighted); } + else if (m_back_framewindow) + { + m_back_framewindow->InitState(S_Enabled, tex_enabled); + m_back_framewindow->InitState(S_Disabled, tex_disabled); + m_back_framewindow->InitState(S_Touched, tex_touched); + m_back_framewindow->InitState(S_Highlighted, tex_highlighted); + } this->m_bTextureEnable = true; } @@ -190,6 +211,10 @@ void CUI3tButton::DrawTexture() { m_back_frameline->Draw(); } + else if (m_back_framewindow) + { + m_back_framewindow->Draw(); + } } } @@ -203,6 +228,7 @@ void CUI3tButton::Update() { if (m_background) { m_background->SetCurrentState(state); } else if (m_back_frameline) { m_back_frameline->SetCurrentState(state); } + else if (m_back_framewindow) { m_back_framewindow->SetCurrentState(state); } } TextItemControl()->SetTextColor(StateTextColor(state)); diff --git a/src/xrGame/ui/UI3tButton.h b/src/xrGame/ui/UI3tButton.h index 3d9df6d4f8..5b2418ac5b 100644 --- a/src/xrGame/ui/UI3tButton.h +++ b/src/xrGame/ui/UI3tButton.h @@ -55,11 +55,19 @@ class CUI3tButton : public CUIButton u32 m_dwTextColor[4]; bool m_bUseTextColor[4]; // note: 0 index will be ignored + virtual CUIWindow* ui_cast_window() { return this; } - bool m_frameline_mode; + enum EFrameMode + { + Framemode_None, + Framemode_Line, + Framemode_Window + }; + EFrameMode m_frameline_mode; bool vertical; CUI_IB_Static* m_background; CUI_IB_FrameLineWnd* m_back_frameline; + CUI_IB_FrameWindow* m_back_framewindow; private: void PlaySoundH(); void PlaySoundT(); diff --git a/src/xrGame/ui/UIAchievements.cpp b/src/xrGame/ui/UIAchievements.cpp index 67a8649ac3..3b8fa730f9 100644 --- a/src/xrGame/ui/UIAchievements.cpp +++ b/src/xrGame/ui/UIAchievements.cpp @@ -63,6 +63,8 @@ void CUIAchievements::Update() bool CUIAchievements::ParentHasMe() { + xrCriticalSectionGuard guard(m_parent->csUi); + WINDOW_LIST::const_iterator it = std::find(m_parent->Items().begin(), m_parent->Items().end(), this); return it != m_parent->Items().end(); } diff --git a/src/xrGame/ui/UIAchievements.h b/src/xrGame/ui/UIAchievements.h index 8113748411..ac45084be9 100644 --- a/src/xrGame/ui/UIAchievements.h +++ b/src/xrGame/ui/UIAchievements.h @@ -36,6 +36,8 @@ class CUIAchievements : public CUIWindow virtual void DrawHint(); virtual void Reset(); + virtual CUIWindow* ui_cast_window() { return this; } + protected: bool ParentHasMe(); }; diff --git a/src/xrGame/ui/UIActorMenu.h b/src/xrGame/ui/UIActorMenu.h index 5f4dc37419..8ab76947da 100644 --- a/src/xrGame/ui/UIActorMenu.h +++ b/src/xrGame/ui/UIActorMenu.h @@ -191,6 +191,9 @@ class CUIActorMenu : public CUIDialogWnd, CInventoryOwner* GetPartner() { return m_pPartnerInvOwner; }; void SetInvBox(CInventoryBox* box); CInventoryBox* GetInvBox() { return m_pInvBox; }; + + virtual CUIWindow* ui_cast_window() { return this; } + bool b_sort_hotkeys; void SelectInventoryTab(int tab); private: diff --git a/src/xrGame/ui/UIActorMenuInventory.cpp b/src/xrGame/ui/UIActorMenuInventory.cpp index d06899d758..42d5a6919a 100644 --- a/src/xrGame/ui/UIActorMenuInventory.cpp +++ b/src/xrGame/ui/UIActorMenuInventory.cpp @@ -648,6 +648,7 @@ bool CUIActorMenu::ToSlotScript(CScriptGameObject* GO, bool force_place, u16 slo CUIDragDropListEx* invlist = GetListByType(iActorBag); CUICellContainer* c = invlist->GetContainer(); + xrCriticalSectionGuard guard(c->csUi); CUIWindow::WINDOW_LIST child_list = c->GetChildWndList(); for (WINDOW_LIST_it it = child_list.begin(); child_list.end() != it; ++it) @@ -797,6 +798,7 @@ bool CUIActorMenu::ToSlot(CUICellItem* itm, bool force_place, u16 slot_id) { //Alundaio: Since the player's inventory is being used as a slot we need to search for cell with matching m_pData CUICellContainer* c = slot_list->GetContainer(); + xrCriticalSectionGuard guard(c->csUi); CUIWindow::WINDOW_LIST child_list = c->GetChildWndList(); for (WINDOW_LIST_it it = child_list.begin(); child_list.end() != it; ++it) @@ -914,6 +916,7 @@ bool CUIActorMenu::ToBeltScript(CScriptGameObject* GO, bool b_use_cursor_pos) CUIDragDropListEx* invlist = GetListByType(iActorBag); CUICellContainer* c = invlist->GetContainer(); + xrCriticalSectionGuard guard(c->csUi); CUIWindow::WINDOW_LIST child_list = c->GetChildWndList(); for (WINDOW_LIST_it it = child_list.begin(); child_list.end() != it; ++it) diff --git a/src/xrGame/ui/UIActorStateInfo.h b/src/xrGame/ui/UIActorStateInfo.h index 48a2748bfe..154fefcf60 100644 --- a/src/xrGame/ui/UIActorStateInfo.h +++ b/src/xrGame/ui/UIActorStateInfo.h @@ -59,6 +59,8 @@ class ui_actor_state_wnd : public CUIWindow virtual void Draw(); virtual void Show(bool status); + virtual CUIWindow* ui_cast_window() { return this; } + private: void update_round_states(CActor* actor, ALife::EHitType hit_type, EStateType stt_type); }; @@ -87,6 +89,8 @@ class ui_actor_state_item : public UIHintWindow void set_progress_shape(float value); // 0..1 void set_arrow(float value); // 0..1 void show_static(bool status, u8 number = 1); + + virtual CUIWindow* ui_cast_window() { return this; } }; // class ui_actor_state_item #endif // UI_ACTOR_STATE_INFO_H_INCLUDED diff --git a/src/xrGame/ui/UIAnimatedStatic.h b/src/xrGame/ui/UIAnimatedStatic.h index e9ba090e07..69ede3fd3f 100644 --- a/src/xrGame/ui/UIAnimatedStatic.h +++ b/src/xrGame/ui/UIAnimatedStatic.h @@ -83,6 +83,10 @@ class CUIAnimatedStatic : public CUIStatic bool m_bCyclic; virtual void Update(); + + virtual CUIWindow* ui_cast_window() { return this; } + virtual CUIStatic* ui_cast_static() { return this; } + }; class CUISleepStatic : public CUIStatic @@ -97,5 +101,8 @@ class CUISleepStatic : public CUIStatic virtual void Draw(); virtual void Update(); virtual void InitTextureEx(LPCSTR tex_name, LPCSTR sh_name = "hud\\default"); + + virtual CUIWindow* ui_cast_window() { return this; } + virtual CUIStatic* ui_cast_static() { return this; } }; #endif //UI_ANIMATED_STATIC_H_ diff --git a/src/xrGame/ui/UIBoosterInfo.h b/src/xrGame/ui/UIBoosterInfo.h index e11cd77321..8f1d7cd707 100644 --- a/src/xrGame/ui/UIBoosterInfo.h +++ b/src/xrGame/ui/UIBoosterInfo.h @@ -15,6 +15,8 @@ class CUIBoosterInfo : public CUIWindow void InitFromXml(CUIXml& xml); void SetInfo(const shared_str& section); + virtual CUIWindow* ui_cast_window() { return this; } + protected: UIBoosterInfoItem* m_booster_items[eBoostExplImmunity]; UIBoosterInfoItem* m_booster_satiety; @@ -36,6 +38,8 @@ class UIBoosterInfoItem : public CUIWindow void SetCaption(LPCSTR name); void SetValue(float value); + virtual CUIWindow* ui_cast_window() { return this; } + private: CUIStatic* m_caption; CUITextWnd* m_value; diff --git a/src/xrGame/ui/UIBtnHint.h b/src/xrGame/ui/UIBtnHint.h index 1e6d95446e..e602d4d6bb 100644 --- a/src/xrGame/ui/UIBtnHint.h +++ b/src/xrGame/ui/UIBtnHint.h @@ -17,6 +17,9 @@ class CUIButtonHint : public CUIFrameWindow void OnRender(); void Draw_() { m_enabledOnFrame = true; }; void SetHintText(CUIWindow* w, LPCSTR text); + + virtual CUIWindow* ui_cast_window() { return this; } + }; extern CUIButtonHint* g_btnHint; diff --git a/src/xrGame/ui/UIButton.h b/src/xrGame/ui/UIButton.h index 88040e601f..108c485e68 100644 --- a/src/xrGame/ui/UIButton.h +++ b/src/xrGame/ui/UIButton.h @@ -56,6 +56,10 @@ class CUIButton : public CUIStatic bool IsAccelerator(int iAccel) const; shared_str m_hint_text; + + virtual CUIWindow* ui_cast_window() { return this; } + virtual CUIStatic* ui_cast_static() { return this; } + protected: E_BUTTON_STATE m_eButtonState; diff --git a/src/xrGame/ui/UIBuyWeaponTab.h b/src/xrGame/ui/UIBuyWeaponTab.h index 5729d538ca..0e47c60726 100644 --- a/src/xrGame/ui/UIBuyWeaponTab.h +++ b/src/xrGame/ui/UIBuyWeaponTab.h @@ -12,6 +12,8 @@ class CUIBuyWeaponTab : public CUITabControl public: virtual void SendMessage(CUIWindow* pWnd, s16 msg, void* pData); + virtual CUIWindow* ui_cast_window() { return this; } + // public: // CUIBuyWeaponTab (); // virtual ~CUIBuyWeaponTab (); diff --git a/src/xrGame/ui/UIBuyWndBase.h b/src/xrGame/ui/UIBuyWndBase.h index 2867b3f640..f67a857e58 100644 --- a/src/xrGame/ui/UIBuyWndBase.h +++ b/src/xrGame/ui/UIBuyWndBase.h @@ -68,4 +68,6 @@ class IBuyWnd : public CUIDialogWnd virtual void ClearPreset(ETradePreset idx) =0; virtual void TryUsePreset(ETradePreset idx) =0; virtual bool IsIgnoreMoneyAndRank() =0; + + virtual CUIWindow* ui_cast_window() { return this; } }; diff --git a/src/xrGame/ui/UICDkey.h b/src/xrGame/ui/UICDkey.h index 51db1d604f..854a7d466f 100644 --- a/src/xrGame/ui/UICDkey.h +++ b/src/xrGame/ui/UICDkey.h @@ -30,6 +30,8 @@ class CUICDkey : public CUIEditBox virtual void Draw(); virtual void OnFocusLost(); + virtual CUIWindow* ui_cast_window() { return this; } + private: void xr_stdcall paste_from_clipboard(); @@ -59,6 +61,8 @@ class CUIMPPlayerName : public CUIEditBox // virtual bool IsChanged(); virtual void OnFocusLost(); + + virtual CUIWindow* ui_cast_window() { return this; } }; // class CUIMPPlayerName extern void GetCDKey_FromRegistry(char* cdkey); diff --git a/src/xrGame/ui/UICellCustomItems.h b/src/xrGame/ui/UICellCustomItems.h index 731b8e1afd..30e137c052 100644 --- a/src/xrGame/ui/UICellCustomItems.h +++ b/src/xrGame/ui/UICellCustomItems.h @@ -25,6 +25,11 @@ class CUIInventoryCellItem : public CUICellItem bool IsHelperOrHasHelperChild(); void Update(); CInventoryItem* object() { return (CInventoryItem*)m_pData; } + + virtual CUIWindow* ui_cast_window() { return this; } + virtual CUIStatic* ui_cast_static() { return this; } + virtual CUICellItem* ui_cast_cell_item() { return this; } + //Alundaio virtual void OnAfterChild(CUIDragDropListEx* parent_list); virtual void SetTextureColor(u32 color); @@ -48,6 +53,10 @@ class CUIAmmoCellItem : public CUIInventoryCellItem virtual bool EqualTo(CUICellItem* itm); virtual CUIDragItem* CreateDragItem(); CWeaponAmmo* object() { return (CWeaponAmmo*)m_pData; } + + virtual CUIWindow* ui_cast_window() { return this; } + virtual CUIStatic* ui_cast_static() { return this; } + virtual CUICellItem* ui_cast_cell_item() { return this; } }; class CUIWeaponCellItem : public CUIInventoryCellItem @@ -79,6 +88,10 @@ class CUIWeaponCellItem : public CUIInventoryCellItem virtual CUIDragItem* CreateDragItem(); virtual bool EqualTo(CUICellItem* itm); CUIStatic* get_addon_static(u32 idx) { return m_addons[idx]; } + + virtual CUIWindow* ui_cast_window() { return this; } + virtual CUIStatic* ui_cast_static() { return this; } + virtual CUICellItem* ui_cast_cell_item() { return this; } }; class CBuyItemCustomDrawCell : public ICustomDrawCellItem diff --git a/src/xrGame/ui/UICellItem.h b/src/xrGame/ui/UICellItem.h index 9a2fddf89c..8e1728f5c3 100644 --- a/src/xrGame/ui/UICellItem.h +++ b/src/xrGame/ui/UICellItem.h @@ -78,6 +78,10 @@ class CUICellItem : public CUIStatic virtual bool IsHelper() { return false; } virtual void SetIsHelper(bool is_helper) { ; } + virtual CUIWindow* ui_cast_window() { return this; } + virtual CUIStatic* ui_cast_static() { return this; } + virtual CUICellItem* ui_cast_cell_item() { return this; } + public: static CUICellItem* m_mouse_selected_item; void* m_pData; diff --git a/src/xrGame/ui/UIChangeMap.h b/src/xrGame/ui/UIChangeMap.h index 1bc206d83b..43d6151cd6 100644 --- a/src/xrGame/ui/UIChangeMap.h +++ b/src/xrGame/ui/UIChangeMap.h @@ -23,6 +23,8 @@ class CUIChangeMap : public CUIDialogWnd void OnBtnCancel(); void OnItemSelect(); + virtual CUIWindow* ui_cast_window() { return this; } + protected: void FillUpList(); diff --git a/src/xrGame/ui/UICharacterInfo.h b/src/xrGame/ui/UICharacterInfo.h index 9c20127e43..6e227c3c07 100644 --- a/src/xrGame/ui/UICharacterInfo.h +++ b/src/xrGame/ui/UICharacterInfo.h @@ -104,4 +104,6 @@ class CUICharacterInfo : public CUIWindow static bool get_actor_community(shared_str* our, shared_str* enemy); static bool ignore_community(shared_str const& check_community); + + virtual CUIWindow* ui_cast_window() { return this; } }; diff --git a/src/xrGame/ui/UIChatWnd.h b/src/xrGame/ui/UIChatWnd.h index 7976c446b4..a371c9a752 100644 --- a/src/xrGame/ui/UIChatWnd.h +++ b/src/xrGame/ui/UIChatWnd.h @@ -22,6 +22,7 @@ class CUIChatWnd : public CUIDialogWnd, public CUIWndCallback virtual bool NeedCursor() const { return false; } virtual void SendMessage(CUIWindow* pWnd, s16 msg, void* pData = NULL); + virtual CUIWindow* ui_cast_window() { return this; } protected: CUIEditBox* UIEditBox; diff --git a/src/xrGame/ui/UICheckButton.h b/src/xrGame/ui/UICheckButton.h index 19937a68b7..8da13b806a 100644 --- a/src/xrGame/ui/UICheckButton.h +++ b/src/xrGame/ui/UICheckButton.h @@ -39,6 +39,8 @@ class CUICheckButton : public CUI3tButton, public CUIOptionsItem void SetDependControl(CUIWindow* pWnd); + virtual CUIWindow* ui_cast_window() { return this; } + private: bool m_opt_backup_value; void InitTexture2(LPCSTR texture_name); diff --git a/src/xrGame/ui/UIComboBox.h b/src/xrGame/ui/UIComboBox.h index 8f23acb70f..e30dc5efb5 100644 --- a/src/xrGame/ui/UIComboBox.h +++ b/src/xrGame/ui/UIComboBox.h @@ -48,6 +48,9 @@ class CUIComboBox : public CUIWindow, public CUIOptionsItem, public pureRender int CurrentID() { return m_itoken_id; } void disable_id(int id); void enable_id(int id); + + virtual CUIWindow* ui_cast_window() { return this; } + protected: virtual bool OnMouseAction(float x, float y, EUIMessages mouse_action); virtual void OnBtnClicked(); diff --git a/src/xrGame/ui/UICustomEdit.h b/src/xrGame/ui/UICustomEdit.h index d3e1afd99a..57f00f0eeb 100644 --- a/src/xrGame/ui/UICustomEdit.h +++ b/src/xrGame/ui/UICustomEdit.h @@ -42,6 +42,9 @@ class CUICustomEdit : public CUIStatic void SetPasswordMode(bool mode = true); + virtual CUIWindow* ui_cast_window() { return this; } + virtual CUIStatic* ui_cast_static() { return this; } + protected: void Register_callbacks(); @@ -51,7 +54,7 @@ class CUICustomEdit : public CUIStatic void xr_stdcall press_tab(); protected: - typedef fastdelegate::FastDelegate0 Callback; + typedef xr_delegate Callback; enum { EDIT_BUF_SIZE = 256 }; diff --git a/src/xrGame/ui/UICustomSpin.h b/src/xrGame/ui/UICustomSpin.h index 04c4e47685..cf97449439 100644 --- a/src/xrGame/ui/UICustomSpin.h +++ b/src/xrGame/ui/UICustomSpin.h @@ -36,6 +36,8 @@ class CUICustomSpin : public CUIWindow, public CUIOptionsItem void SetTextColor(u32 color); void SetTextColorD(u32 color); + virtual CUIWindow* ui_cast_window() { return this; } + protected: virtual bool CanPressUp() = 0; virtual bool CanPressDown() = 0; diff --git a/src/xrGame/ui/UIDebugFonts.h b/src/xrGame/ui/UIDebugFonts.h index 22ca9a4389..c1ba8d6f0d 100644 --- a/src/xrGame/ui/UIDebugFonts.h +++ b/src/xrGame/ui/UIDebugFonts.h @@ -20,6 +20,9 @@ class CUIDebugFonts : public CUIDialogWnd void InitDebugFonts(Frect r); virtual bool OnKeyboardAction(int dik, EUIMessages keyboard_action); void FillUpList(); + + virtual CUIWindow* ui_cast_window() { return this; } + protected: CUIStatic m_background; }; diff --git a/src/xrGame/ui/UIDemoPlayControl.h b/src/xrGame/ui/UIDemoPlayControl.h index c42c68aa30..ce376dfefb 100644 --- a/src/xrGame/ui/UIDemoPlayControl.h +++ b/src/xrGame/ui/UIDemoPlayControl.h @@ -39,6 +39,9 @@ class CUIDemoPlayControl : void xr_stdcall OnRewindTypeSelected(CUIWindow* w, void* d); void xr_stdcall OnRewindPlayerSelected(CUIWindow* w, void* d); + + virtual CUIWindow* ui_cast_window() { return this; } + private: void StopRewind(); void UIStartRewind(); diff --git a/src/xrGame/ui/UIDialogWnd.cpp b/src/xrGame/ui/UIDialogWnd.cpp index 95af147723..7633c6ea3a 100644 --- a/src/xrGame/ui/UIDialogWnd.cpp +++ b/src/xrGame/ui/UIDialogWnd.cpp @@ -14,6 +14,10 @@ CUIDialogWnd::CUIDialogWnd() CUIDialogWnd::~CUIDialogWnd() { + if (m_pParentHolder) + { + m_pParentHolder->SetMainInputReceiver(this, true); + } } void CUIDialogWnd::Show(bool status) @@ -62,4 +66,4 @@ void CUIDialogWnd::HideDialog() //R_ASSERT2(IsShown(), "dialog already hidden"); if (IsShown() && GetHolder()) GetHolder()->StopDialog(this); -} \ No newline at end of file +} diff --git a/src/xrGame/ui/UIDialogWnd.h b/src/xrGame/ui/UIDialogWnd.h index ec62806ae5..c791121d8d 100644 --- a/src/xrGame/ui/UIDialogWnd.h +++ b/src/xrGame/ui/UIDialogWnd.h @@ -39,4 +39,6 @@ class CUIDialogWnd : public CUIWindow void HideDialog(); virtual bool IR_process(); + + virtual CUIWindow* ui_cast_window() { return this; } }; diff --git a/src/xrGame/ui/UIDoubleProgressBar.h b/src/xrGame/ui/UIDoubleProgressBar.h index a0adae8cec..4b113482a4 100644 --- a/src/xrGame/ui/UIDoubleProgressBar.h +++ b/src/xrGame/ui/UIDoubleProgressBar.h @@ -13,6 +13,8 @@ class CUIDoubleProgressBar : public CUIWindow void InitFromXml(CUIXml& xml_doc, LPCSTR path); void SetTwoPos(float cur_value, float compare_value); + virtual CUIWindow* ui_cast_window() { return this; } + protected: CUIProgressBar m_progress_one; CUIProgressBar m_progress_two; diff --git a/src/xrGame/ui/UIDragDropListEx.cpp b/src/xrGame/ui/UIDragDropListEx.cpp index 18942330ab..b9778bfba2 100644 --- a/src/xrGame/ui/UIDragDropListEx.cpp +++ b/src/xrGame/ui/UIDragDropListEx.cpp @@ -319,6 +319,7 @@ void CUIDragDropListEx::ClearAll(bool bDestroy) void CUIDragDropListEx::Compact() { + xrCriticalSectionGuard guard(m_container->csUi); CUIWindow::WINDOW_LIST wl = m_container->GetChildWndList(); ClearAll(false); @@ -504,6 +505,7 @@ CUICellItem* CUIDragDropListEx::RemoveItem(CUICellItem* itm, bool force_root) u32 CUIDragDropListEx::ItemsCount() { + xrCriticalSectionGuard guard(m_container->csUi); return m_container->GetChildWndList().size(); } @@ -515,6 +517,7 @@ bool CUIDragDropListEx::IsOwner(CUICellItem* itm) CUICellItem* CUIDragDropListEx::GetItemIdx(u32 idx) { R_ASSERT(idxcsUi); WINDOW_LIST_it it = m_container->GetChildWndList().begin(); std::advance(it, idx); return smart_cast(*it); @@ -607,6 +610,7 @@ bool CUICellContainer::AddSimilar(CUICellItem* itm) CUICellItem* CUICellContainer::FindSimilar(CUICellItem* itm) { + xrCriticalSectionGuard guard(csUi); for (WINDOW_LIST_it it = m_ChildWndList.begin(); m_ChildWndList.end() != it; ++it) { #ifdef DEBUG @@ -653,7 +657,7 @@ void CUICellContainer::PlaceItemAtPos(CUICellItem* itm, Ivector2& cell_pos) itm->SetWndSize(Fvector2().set((m_cellSize.x * cs.x), (m_cellSize.y * cs.y))); if (!m_pParentDragDropList->GetVirtualCells()) itm->SetWndPos(Fvector2().set(((m_cellSpacing.x + m_cellSize.x) * cell_pos.x), - ((m_cellSpacing.y + m_cellSize.y) * cell_pos.y))); + ((m_cellSpacing.y + m_cellSize.y) * cell_pos.y))); else { Ivector2 alignment_vec = m_pParentDragDropList->GetVirtualCellsAlignment(); @@ -677,6 +681,7 @@ void CUICellContainer::PlaceItemAtPos(CUICellItem* itm, Ivector2& cell_pos) CUICellItem* CUICellContainer::RemoveItem(CUICellItem* itm, bool force_root) { + xrCriticalSectionGuard guard(csUi); for (WINDOW_LIST_it it = m_ChildWndList.begin(); m_ChildWndList.end() != it; ++it) { CUICellItem* i = (CUICellItem*)(*it); @@ -684,7 +689,7 @@ CUICellItem* CUICellContainer::RemoveItem(CUICellItem* itm, bool force_root) if (i->HasChild(itm)) { CUICellItem* iii = i->PopChild(itm); - R_ASSERT(0==iii->ChildsCount()); + R_ASSERT(0 == iii->ChildsCount()); return iii; } } @@ -692,7 +697,7 @@ CUICellItem* CUICellContainer::RemoveItem(CUICellItem* itm, bool force_root) if (!force_root && itm->ChildsCount()) { CUICellItem* iii = itm->PopChild(NULL); - R_ASSERT(0==iii->ChildsCount()); + R_ASSERT(0 == iii->ChildsCount()); return iii; } @@ -889,6 +894,8 @@ void CUICellContainer::ClearAll(bool bDestroy) for (; it != it_e; ++it) (*it).Clear(); } + + xrCriticalSectionGuard guard(csUi); while (!m_ChildWndList.empty()) { CUIWindow* w = m_ChildWndList.back(); diff --git a/src/xrGame/ui/UIDragDropListEx.h b/src/xrGame/ui/UIDragDropListEx.h index f050b21123..0ee159146a 100644 --- a/src/xrGame/ui/UIDragDropListEx.h +++ b/src/xrGame/ui/UIDragDropListEx.h @@ -78,8 +78,8 @@ class CUIDragDropListEx : public CUIWindow, public CUIWndCallback virtual ~CUIDragDropListEx(); void InitDragDropList(Fvector2 pos, Fvector2 size); - typedef fastdelegate::FastDelegate1 DRAG_CELL_EVENT; - typedef fastdelegate::FastDelegate2 DRAG_ITEM_EVENT; + typedef xr_delegate DRAG_CELL_EVENT; + typedef xr_delegate DRAG_ITEM_EVENT; DRAG_CELL_EVENT m_f_item_drop; DRAG_CELL_EVENT m_f_item_start_drag; @@ -165,6 +165,8 @@ class CUIDragDropListEx : public CUIWindow, public CUIWndCallback virtual void SendMessage(CUIWindow* pWnd, s16 msg, void* pData = NULL); void OnDragEvent(CUIDragItem* drag_item, bool b_receive); + + virtual CUIWindow* ui_cast_window() { return this; } }; class CUICellContainer : public CUIWindow @@ -196,6 +198,8 @@ class CUICellContainer : public CUIWindow bool ValidCell(const Ivector2& pos) const; //Alundaio made public CUICell& GetCellAt(const Ivector2& pos); + virtual CUIWindow* ui_cast_window() { return this; } + protected: virtual void Draw(); diff --git a/src/xrGame/ui/UIDragDropReferenceList.h b/src/xrGame/ui/UIDragDropReferenceList.h index 09183e5910..48d19c540d 100644 --- a/src/xrGame/ui/UIDragDropReferenceList.h +++ b/src/xrGame/ui/UIDragDropReferenceList.h @@ -25,4 +25,6 @@ class CUIDragDropReferenceList : public CUIDragDropListEx virtual void __stdcall OnItemDBClick(CUIWindow* w, void* pData); virtual void __stdcall OnItemDrop(CUIWindow* w, void* pData); + + virtual CUIWindow* ui_cast_window() { return this; } }; diff --git a/src/xrGame/ui/UIEditBox.h b/src/xrGame/ui/UIEditBox.h index e6e085f96e..48f360a555 100644 --- a/src/xrGame/ui/UIEditBox.h +++ b/src/xrGame/ui/UIEditBox.h @@ -21,6 +21,10 @@ class CUIEditBox : public CUIOptionsItem, public CUICustomEdit // CUIMultiTextureOwner virtual void InitTexture(LPCSTR texture); virtual void InitTextureEx(LPCSTR texture, LPCSTR shader); + + virtual CUIWindow* ui_cast_window() { return this; } + virtual CUIStatic* ui_cast_static() { return this; } + protected: CUIFrameLineWnd* m_frameLine; shared_str m_opt_backup_value; diff --git a/src/xrGame/ui/UIEditBoxEx.h b/src/xrGame/ui/UIEditBoxEx.h index 3210984e4e..1b679e410f 100644 --- a/src/xrGame/ui/UIEditBoxEx.h +++ b/src/xrGame/ui/UIEditBoxEx.h @@ -15,6 +15,10 @@ class CUIEditBoxEx : /*public CUIMultiTextureOwner, */public CUICustomEdit // CUIMultiTextureOwner virtual void InitTexture(LPCSTR texture); virtual void InitTextureEx(LPCSTR texture, LPCSTR shader); + + virtual CUIWindow* ui_cast_window() { return this; } + virtual CUIStatic* ui_cast_static() { return this; } + protected: CUIFrameWindow* m_pFrameWindow; }; diff --git a/src/xrGame/ui/UIEditKeyBind.h b/src/xrGame/ui/UIEditKeyBind.h index 11cfacf597..0f63a435c9 100644 --- a/src/xrGame/ui/UIEditKeyBind.h +++ b/src/xrGame/ui/UIEditKeyBind.h @@ -41,6 +41,9 @@ class CUIEditKeyBind : public CUIFrameLineWnd, public CUIOptionsItem virtual void SetText(LPCSTR text); void SetEditMode(bool b); + + virtual CUIWindow* ui_cast_window() { return this; } + protected: void BindAction2Key(); diff --git a/src/xrGame/ui/UIFixedScrollBar.h b/src/xrGame/ui/UIFixedScrollBar.h index f05cbbb733..2b9dc4da59 100644 --- a/src/xrGame/ui/UIFixedScrollBar.h +++ b/src/xrGame/ui/UIFixedScrollBar.h @@ -36,4 +36,7 @@ class CUIFixedScrollBar : public CUIScrollBar virtual bool OnMouseDownEx(); virtual void OnMouseUp(int mouse_btn); virtual bool OnKeyboardHold(int dik); + + virtual CUIWindow* ui_cast_window() { return this; } + virtual CUIFixedScrollBar* ui_cast_fixed_scroll_bar() { return this; } }; diff --git a/src/xrGame/ui/UIFrameLineWnd.h b/src/xrGame/ui/UIFrameLineWnd.h index 5f83511a19..ed1b3082c0 100644 --- a/src/xrGame/ui/UIFrameLineWnd.h +++ b/src/xrGame/ui/UIFrameLineWnd.h @@ -17,6 +17,9 @@ class CUIFrameLineWnd : public CUIWindow void SetTextureColor(u32 cl) { m_texture_color = cl; } bool IsHorizontal() { return bHorizontal; } void SetHorizontal(bool horiz) { bHorizontal = horiz; } + + virtual CUIWindow* ui_cast_window() { return this; } + // When true, caps are scaled to fit the element -- texture->UI by height, then UI->screen for // resolution -- so the caps keep their authored shape. When false the cap width is the texture's own // pixel width used as-is on screen (never scaled) while its height stretches to fill the element, so diff --git a/src/xrGame/ui/UIFrameWindow.h b/src/xrGame/ui/UIFrameWindow.h index eec3891f04..9608131c40 100644 --- a/src/xrGame/ui/UIFrameWindow.h +++ b/src/xrGame/ui/UIFrameWindow.h @@ -29,6 +29,9 @@ class CUIFrameWindow : public CUIWindow, virtual void Draw(); + virtual CUIWindow* ui_cast_window() { return this; } + virtual ITextureOwner* ui_cast_texture_owner() { return this; } + protected: bool m_bTextureVisible; diff --git a/src/xrGame/ui/UIGameLog.cpp b/src/xrGame/ui/UIGameLog.cpp index be87a7973e..5a020f6a4c 100644 --- a/src/xrGame/ui/UIGameLog.cpp +++ b/src/xrGame/ui/UIGameLog.cpp @@ -80,6 +80,7 @@ void CUIGameLog::Update() CUIScrollView::Update(); toDelList.clear(); + xrCriticalSectionGuard guard(m_pad->csUi); WINDOW_LIST_it it = m_pad->GetChildWndList().begin(); WINDOW_LIST_it it_e = m_pad->GetChildWndList().end(); diff --git a/src/xrGame/ui/UIGameLog.h b/src/xrGame/ui/UIGameLog.h index b77ed9272d..42059cf3e4 100644 --- a/src/xrGame/ui/UIGameLog.h +++ b/src/xrGame/ui/UIGameLog.h @@ -30,6 +30,9 @@ class CUIGameLog : public CUIScrollView void SetTextAtrib(CGameFont* pFont, u32 color); u32 GetTextColor() { return txt_color; } + virtual CUIWindow* ui_cast_window() { return this; } + virtual CUIScrollView* ui_cast_scroll_view() { return this; } + private: WINDOW_LIST toDelList; float kill_msg_height; diff --git a/src/xrGame/ui/UIGameTutorial.cpp b/src/xrGame/ui/UIGameTutorial.cpp index e3d5ed6e46..46dfb9c299 100644 --- a/src/xrGame/ui/UIGameTutorial.cpp +++ b/src/xrGame/ui/UIGameTutorial.cpp @@ -96,6 +96,7 @@ bool CUISequenceItem::Stop(bool bForce) CUISequencer::CUISequencer() { m_flags.zero(); + m_name = "invalid"; } extern BOOL g_bootComplete; @@ -107,6 +108,8 @@ void CUISequencer::Start(LPCSTR tutor_name) m_UIWindow = xr_new(); + m_name = tutor_name; + static CUIXml uiXml; static bool uiXmlLoaded; if (uiXmlLoaded && g_bootComplete) @@ -120,6 +123,7 @@ void CUISequencer::Start(LPCSTR tutor_name) uiXml.Load(CONFIG_PATH, UI_PATH, "game_tutorials.xml"); uiXml.SetLocalRoot(uiXml.GetRoot()); } + int items_count = uiXml.GetNodesNum(tutor_name, 0, "item"); VERIFY(items_count>0); @@ -155,7 +159,7 @@ void CUISequencer::Start(LPCSTR tutor_name) if (snd_name && snd_name[0]) { m_global_sound.create(snd_name, st_Effect, sg_Undefined); - VERIFY(m_global_sound._handle() || strstr(Core.Params,"-nosound")); + VERIFY(m_global_sound._handle() || Core.ParamsData.test(ECoreParams::nosound)); } m_start_lua_function = uiXml.Read("function_on_start", 0, ""); m_stop_lua_function = uiXml.Read("function_on_stop", 0, ""); diff --git a/src/xrGame/ui/UIGameTutorial.h b/src/xrGame/ui/UIGameTutorial.h index 1dc21cb0ff..f941595e15 100644 --- a/src/xrGame/ui/UIGameTutorial.h +++ b/src/xrGame/ui/UIGameTutorial.h @@ -34,6 +34,7 @@ class CUISequencer : public pureFrame, public pureRender, public IInputReceiver bool IsActive() { return !!m_flags.test(etsActive); } + LPCSTR m_name; //IInputReceiver virtual void IR_OnMousePress(int btn); virtual void IR_OnMouseRelease(int btn); @@ -49,7 +50,7 @@ class CUISequencer : public pureFrame, public pureRender, public IInputReceiver virtual void IR_OnActivate(void); bool Persistent() { return !!m_flags.test(etsPersistent); } - fastdelegate::FastDelegate0<> m_on_destroy_event; + xr_delegate m_on_destroy_event; enum { diff --git a/src/xrGame/ui/UIGameTutorialSimpleItem.cpp b/src/xrGame/ui/UIGameTutorialSimpleItem.cpp index fa5965fe27..bb4ca22e90 100644 --- a/src/xrGame/ui/UIGameTutorialSimpleItem.cpp +++ b/src/xrGame/ui/UIGameTutorialSimpleItem.cpp @@ -37,6 +37,8 @@ bool CUISequenceSimpleItem::IsPlaying() CUIWindow* find_child_window(CUIWindow* parent, const shared_str& _name) { + xrCriticalSectionGuard guard(parent->csUi); + CUIWindow::WINDOW_LIST& wl = parent->GetChildWndList(); CUIWindow::WINDOW_LIST_it _I = wl.begin(); CUIWindow::WINDOW_LIST_it _E = wl.end(); @@ -55,7 +57,7 @@ void CUISequenceSimpleItem::Load(CUIXml* xml, int idx) if (m_snd_name && m_snd_name[0]) { m_sound.create(m_snd_name, st_Effect, sg_Undefined); - VERIFY(m_sound._handle() || strstr(Core.Params,"-nosound")); + VERIFY(m_sound._handle() || Core.ParamsData.test(ECoreParams::nosound)); } m_time_length = xml->ReadFlt("length_sec", 0, 0); m_desired_cursor_pos.x = xml->ReadAttribFlt("cursor_pos", 0, "x", 0); diff --git a/src/xrGame/ui/UIHint.h b/src/xrGame/ui/UIHint.h index 628d615a1b..ce707255b6 100644 --- a/src/xrGame/ui/UIHint.h +++ b/src/xrGame/ui/UIHint.h @@ -40,6 +40,8 @@ class UIHint : public CUIWindow // virtual void Update (); virtual void Draw(); + virtual CUIWindow* ui_cast_window() { return this; } + protected: CUIFrameWindow* m_background; CUITextWnd* m_text; @@ -79,6 +81,8 @@ class UIHintWindow : public CUIWindow void set_hint_text_ST(shared_str const& text); void update_hint_text(); + virtual CUIWindow* ui_cast_window() { return this; } + void set_hint_text_script(LPCSTR text) { set_hint_text(text); }; LPCSTR get_hint_text_script() { return m_hint_text.c_str(); } ; diff --git a/src/xrGame/ui/UIHudStatesWnd.h b/src/xrGame/ui/UIHudStatesWnd.h index 6d7e85b5c8..095b5c90ac 100644 --- a/src/xrGame/ui/UIHudStatesWnd.h +++ b/src/xrGame/ui/UIHudStatesWnd.h @@ -91,6 +91,9 @@ class CUIHudStatesWnd : public CUIWindow void DrawZoneIndicators(); void FakeUpdateIndicatorType(u8 t, float power); void EnableFakeIndicators(bool enable); + + virtual CUIWindow* ui_cast_window() { return this; } + protected: static ALife::EInfluenceType get_indik_type(ALife::EHitType hit_type); diff --git a/src/xrGame/ui/UIInteractiveBackground.h b/src/xrGame/ui/UIInteractiveBackground.h index 58d5f90270..8a74744f5a 100644 --- a/src/xrGame/ui/UIInteractiveBackground.h +++ b/src/xrGame/ui/UIInteractiveBackground.h @@ -50,6 +50,8 @@ class CUIInteractiveBackground : public CUIWindow virtual void SetWidth(float width); virtual void SetHeight(float heigth); + virtual CUIWindow* ui_cast_window() { return this; } + protected: T* m_states [S_Total]; }; @@ -130,3 +132,4 @@ void CUIInteractiveBackground::SetHeight(float height) } typedef CUIInteractiveBackground CUI_IB_FrameLineWnd; +typedef CUIInteractiveBackground CUI_IB_FrameWindow; diff --git a/src/xrGame/ui/UIInvUpgrade.h b/src/xrGame/ui/UIInvUpgrade.h index 5c9f658b45..e577a9b38c 100644 --- a/src/xrGame/ui/UIInvUpgrade.h +++ b/src/xrGame/ui/UIInvUpgrade.h @@ -127,6 +127,8 @@ class UIUpgrade : public CUIWindow CUIInventoryUpgradeWnd* get_upgrade_window() { return m_parent_wnd; } void attach_point(CUIUpgradePoint* point); + virtual CUIWindow* ui_cast_window() { return this; } + public: CUIUpgradePoint* m_point; }; @@ -144,6 +146,9 @@ class CUIUpgradePoint : public CUIStatic virtual bool OnMouseAction(float x, float y, EUIMessages mouse_action); virtual void OnFocusReceive(); virtual void OnFocusLost(); + + virtual CUIWindow* ui_cast_window() { return this; } + virtual CUIStatic* ui_cast_static() { return this; } }; #endif // UI_INVENTORY_UPGRADE_H_INCLUDED diff --git a/src/xrGame/ui/UIInvUpgradeInfo.h b/src/xrGame/ui/UIInvUpgradeInfo.h index cc01546011..d3d62253d5 100644 --- a/src/xrGame/ui/UIInvUpgradeInfo.h +++ b/src/xrGame/ui/UIInvUpgradeInfo.h @@ -43,6 +43,8 @@ class UIInvUpgradeInfo : public CUIWindow virtual void Draw(); + virtual CUIWindow* ui_cast_window() { return this; } + protected: Upgrade_type* m_upgrade; CUIFrameWindow* m_background; diff --git a/src/xrGame/ui/UIInvUpgradeProperty.cpp b/src/xrGame/ui/UIInvUpgradeProperty.cpp index c96dd0846b..f587eb9a7e 100644 --- a/src/xrGame/ui/UIInvUpgradeProperty.cpp +++ b/src/xrGame/ui/UIInvUpgradeProperty.cpp @@ -184,6 +184,7 @@ void UIInvUpgPropertiesWnd::init_from_xml(LPCSTR xml_name) if (!ui_property->init_property(property_id)) { Msg("! Invalid property <%s> in inventory upgrade manager!", property_id); + xr_delete(ui_property); continue; } diff --git a/src/xrGame/ui/UIInvUpgradeProperty.h b/src/xrGame/ui/UIInvUpgradeProperty.h index f7d636a67c..d8578e5b4c 100644 --- a/src/xrGame/ui/UIInvUpgradeProperty.h +++ b/src/xrGame/ui/UIInvUpgradeProperty.h @@ -48,6 +48,8 @@ class UIProperty : public CUIWindow bool read_value_from_section(LPCSTR section, LPCSTR param, float& result); bool compute_value(ItemUpgrades_type const& item_upgrades); bool show_result(LPCSTR values); + + virtual CUIWindow* ui_cast_window() { return this; } }; // class UIProperty // ========================================================================================= @@ -73,6 +75,8 @@ class UIInvUpgPropertiesWnd : public CUIWindow void set_upgrade_info(Upgrade_type& upgrade); void set_item_info(CInventoryItem& item); + virtual CUIWindow* ui_cast_window() { return this; } + protected: void set_info(ItemUpgrades_type const& item_upgrades); }; // class UIInvUpgPropertiesWnd diff --git a/src/xrGame/ui/UIInventoryUpgradeWnd.h b/src/xrGame/ui/UIInventoryUpgradeWnd.h index fa10ce090f..3356a5437b 100644 --- a/src/xrGame/ui/UIInventoryUpgradeWnd.h +++ b/src/xrGame/ui/UIInventoryUpgradeWnd.h @@ -80,6 +80,8 @@ class CUIInventoryUpgradeWnd : public CUIWindow void set_info_cur_upgrade(Upgrade_type* upgrade); UIUpgrade* FindUIUpgrade(Upgrade_type const* upgr); + virtual CUIWindow* ui_cast_window() { return this; } + private: void LoadCellsBacks(CUIXml& uiXml); void LoadCellStates(LPCSTR state_str, LPCSTR texture_name, LPCSTR texture_name2, u32 color); diff --git a/src/xrGame/ui/UIItemInfo.h b/src/xrGame/ui/UIItemInfo.h index b361576906..6f5f553945 100644 --- a/src/xrGame/ui/UIItemInfo.h +++ b/src/xrGame/ui/UIItemInfo.h @@ -49,6 +49,8 @@ class CUIItemInfo : public CUIWindow void TryAddUpgradeInfo(CInventoryItem& pInvItem); void TryAddBoosterInfo(CInventoryItem& pInvItem); + virtual CUIWindow* ui_cast_window() { return this; } + virtual void Draw(); bool m_b_FitToHeight; u32 delay; diff --git a/src/xrGame/ui/UIKeyBinding.h b/src/xrGame/ui/UIKeyBinding.h index 83210cc88e..4a3644689f 100644 --- a/src/xrGame/ui/UIKeyBinding.h +++ b/src/xrGame/ui/UIKeyBinding.h @@ -17,6 +17,9 @@ class CUIKeyBinding : public CUIWindow void CheckStructure (CUIXml& xml_doc); bool IsActionExist (LPCSTR action, CUIXml& xml_doc); #endif + + virtual CUIWindow* ui_cast_window() { return this; } + protected: void FillUpList(CUIXml& xml_doc, LPCSTR path); diff --git a/src/xrGame/ui/UIKickPlayer.h b/src/xrGame/ui/UIKickPlayer.h index eb28617490..d13e8abcab 100644 --- a/src/xrGame/ui/UIKickPlayer.h +++ b/src/xrGame/ui/UIKickPlayer.h @@ -25,6 +25,8 @@ class CUIKickPlayer : public CUIDialogWnd void OnBtnOk(); void OnBtnCancel(); + virtual CUIWindow* ui_cast_window() { return this; } + protected: typedef enum { MODE_KICK, MODE_BAN } E_MODE; diff --git a/src/xrGame/ui/UILanimController.cpp b/src/xrGame/ui/UILanimController.cpp index 4d2cc8d886..c6b9aebe8f 100644 --- a/src/xrGame/ui/UILanimController.cpp +++ b/src/xrGame/ui/UILanimController.cpp @@ -21,6 +21,7 @@ void CUIColorAnimConrollerContainer::Update() void CUIColorAnimConrollerContainer::ColorAnimationSetTextureColor(u32 color, bool only_alpha) { + xrCriticalSectionGuard guard(csUi); WINDOW_LIST::iterator it = m_ChildWndList.begin(); WINDOW_LIST::iterator it_e = m_ChildWndList.end(); for (; it != it_e; ++it) @@ -33,6 +34,7 @@ void CUIColorAnimConrollerContainer::ColorAnimationSetTextureColor(u32 color, bo void CUIColorAnimConrollerContainer::ColorAnimationSetTextColor(u32 color, bool only_alpha) { + xrCriticalSectionGuard guard(csUi); WINDOW_LIST::iterator it = m_ChildWndList.begin(); WINDOW_LIST::iterator it_e = m_ChildWndList.end(); for (; it != it_e; ++it) diff --git a/src/xrGame/ui/UILanimController.h b/src/xrGame/ui/UILanimController.h index 6d727f9049..fa2e217ad3 100644 --- a/src/xrGame/ui/UILanimController.h +++ b/src/xrGame/ui/UILanimController.h @@ -46,6 +46,9 @@ class CUILightAnimColorConrollerImpl : public CUILightAnimColorConroller { color_animation m_lanim_clr; public: + + virtual CUILightAnimColorConroller* ui_cast_light_anim_color_controller() { return this; } + void SetColorAnimation(LPCSTR lanim, u8 const& flags, float delay = 0.0f) { if (lanim && lanim[0] != 0) @@ -132,4 +135,7 @@ class CUIColorAnimConrollerContainer : public CUIWindow, virtual void Update(); virtual void ColorAnimationSetTextureColor(u32 color, bool only_alpha); virtual void ColorAnimationSetTextColor(u32 color, bool only_alpha); + + virtual CUIWindow* ui_cast_window() { return this; } + virtual CUILightAnimColorConroller* ui_cast_light_anim_color_controller() { return this; } }; diff --git a/src/xrGame/ui/UIListBox.cpp b/src/xrGame/ui/UIListBox.cpp index bb496466a8..6de138fcca 100644 --- a/src/xrGame/ui/UIListBox.cpp +++ b/src/xrGame/ui/UIListBox.cpp @@ -147,6 +147,7 @@ u32 CUIListBox::GetSelectedIDX() u32 _idx = 0; CUIWindow* w = GetSelected(); + xrCriticalSectionGuard guard(m_pad->csUi); for (WINDOW_LIST_it it = m_pad->GetChildWndList().begin(); m_pad->GetChildWndList().end() != it; ++it) { CUIListBoxItem* item = smart_cast(*it); @@ -174,6 +175,7 @@ void CUIListBox::MoveSelectedUp() CUIWindow* w = GetSelected(); if (!w) return; + xrCriticalSectionGuard guard(m_pad->csUi); WINDOW_LIST::reverse_iterator it = m_pad->GetChildWndList().rbegin(); WINDOW_LIST::reverse_iterator it_e = m_pad->GetChildWndList().rend(); WINDOW_LIST::reverse_iterator it_prev = it; @@ -198,6 +200,7 @@ void CUIListBox::MoveSelectedDown() CUIWindow* w = GetSelected(); if (!w) return; //. R_ASSERT(!m_flags.test(CUIScrollView::eMultiSelect)); + xrCriticalSectionGuard guard(m_pad->csUi); WINDOW_LIST_it it = m_pad->GetChildWndList().begin(); WINDOW_LIST_it it_e = m_pad->GetChildWndList().end(); WINDOW_LIST_it it_next; @@ -236,6 +239,7 @@ int CUIListBox::GetIdxByTAG(u32 tag_val) { int result = -1; + xrCriticalSectionGuard guard(m_pad->csUi); for (WINDOW_LIST_it it = m_pad->GetChildWndList().begin(); m_pad->GetChildWndList().end() != it; ++it) { CUIListBoxItem* item = smart_cast(*it); @@ -253,6 +257,7 @@ int CUIListBox::GetIdxByTAG(u32 tag_val) CUIListBoxItem* CUIListBox::GetItemByTAG(u32 tag_val) { + xrCriticalSectionGuard guard(m_pad->csUi); for (WINDOW_LIST_it it = m_pad->GetChildWndList().begin(); m_pad->GetChildWndList().end() != it; ++it) { CUIListBoxItem* item = smart_cast(*it); @@ -268,6 +273,7 @@ CUIListBoxItem* CUIListBox::GetItemByTAG(u32 tag_val) CUIListBoxItem* CUIListBox::GetItemByIDX(int idx) { int _idx = 0; + xrCriticalSectionGuard guard(m_pad->csUi); for (WINDOW_LIST_it it = m_pad->GetChildWndList().begin(); m_pad->GetChildWndList().end() != it; ++it) { CUIListBoxItem* item = smart_cast(*it); @@ -283,6 +289,7 @@ CUIListBoxItem* CUIListBox::GetItemByIDX(int idx) CUIListBoxItem* CUIListBox::GetItemByText(LPCSTR txt) { + xrCriticalSectionGuard guard(m_pad->csUi); for (WINDOW_LIST_it it = m_pad->GetChildWndList().begin(); m_pad->GetChildWndList().end() != it; ++it) { CUIListBoxItem* item = smart_cast(*it); @@ -330,6 +337,7 @@ CGameFont* CUIListBox::GetFont() float CUIListBox::GetLongestLength() { float len = 0; + xrCriticalSectionGuard guard(m_pad->csUi); for (WINDOW_LIST_it it = m_pad->GetChildWndList().begin(); m_pad->GetChildWndList().end() != it; ++it) { CUIListBoxItem* item = smart_cast(*it); diff --git a/src/xrGame/ui/UIListBox.h b/src/xrGame/ui/UIListBox.h index 341ca06086..06a298b9c9 100644 --- a/src/xrGame/ui/UIListBox.h +++ b/src/xrGame/ui/UIListBox.h @@ -42,6 +42,9 @@ class CUIListBox : public CUIScrollView void SetFont(CGameFont* pFont); CGameFont* GetFont(); + virtual CUIWindow* ui_cast_window() { return this; } + virtual CUIScrollView* ui_cast_scroll_view() { return this; } + public: bool bComplexMode; bool bLineWrap; diff --git a/src/xrGame/ui/UIListBoxItem.cpp b/src/xrGame/ui/UIListBoxItem.cpp index 7d7e428419..8aaba09867 100644 --- a/src/xrGame/ui/UIListBoxItem.cpp +++ b/src/xrGame/ui/UIListBoxItem.cpp @@ -79,6 +79,8 @@ u32 CUIListBoxItem::GetTextColor() float CUIListBoxItem::FieldsLength() const { + xrCriticalSectionGuard guard(const_cast(csUi)); + if (m_ChildWndList.empty()) return 0.0f; diff --git a/src/xrGame/ui/UIListBoxItem.h b/src/xrGame/ui/UIListBoxItem.h index 3e1cd15bfa..7d8be41c50 100644 --- a/src/xrGame/ui/UIListBoxItem.h +++ b/src/xrGame/ui/UIListBoxItem.h @@ -33,6 +33,10 @@ class CUIListBoxItem : public CUIFrameLineWnd, public CUISelectable void SetFont(CGameFont* F); CGameFont* GetFont(); + virtual CUIWindow* ui_cast_window() { return this; } + virtual CUIListBoxItem* ui_cast_list_box_item() { return this; } + virtual CUISelectable* ui_cast_selectable() { return this; } + protected: CUITextWnd* m_text; u32 tag; diff --git a/src/xrGame/ui/UIListBoxItemMsgChain.h b/src/xrGame/ui/UIListBoxItemMsgChain.h index 04a0680ccb..259da18345 100644 --- a/src/xrGame/ui/UIListBoxItemMsgChain.h +++ b/src/xrGame/ui/UIListBoxItemMsgChain.h @@ -16,6 +16,9 @@ class CUIListBoxItemMsgChain : public CUIListBoxItem }; virtual bool OnMouseDown(int mouse_btn); + + virtual CUIWindow* ui_cast_window() { return this; } + virtual CUIListBoxItem* ui_cast_list_box_item() { return this; } }; #endif //#ifndef UILISTBOXITEMMSGCHAIN_H_INCLUDED diff --git a/src/xrGame/ui/UIListItemServer.h b/src/xrGame/ui/UIListItemServer.h index 4a519b66de..6c67fb144a 100644 --- a/src/xrGame/ui/UIListItemServer.h +++ b/src/xrGame/ui/UIListItemServer.h @@ -59,6 +59,9 @@ class CUIListItemServer : public CUIListBoxItem int Get_gs_index() { return m_srv_info.info.Index; } LIST_SRV_ITEM* GetInfo() { return &m_srv_info; }; + virtual CUIWindow* ui_cast_window() { return this; } + virtual CUIListBoxItem* ui_cast_list_box_item() { return this; } + virtual CUIListItemServer* ui_cast_list_item_server() { return this; } protected: LIST_SRV_SIZES m_sizes; diff --git a/src/xrGame/ui/UILogsWnd.cpp b/src/xrGame/ui/UILogsWnd.cpp index 6d1fad1c10..7c0ea03c23 100644 --- a/src/xrGame/ui/UILogsWnd.cpp +++ b/src/xrGame/ui/UILogsWnd.cpp @@ -230,6 +230,7 @@ void CUILogsWnd::ReLoadNews() if (!m_list->Empty()) { + xrCriticalSectionGuard guard(m_list->csUi); m_items_cache.insert(m_items_cache.end(), m_list->Items().begin(), m_list->Items().end()); m_list->Items().clear(); diff --git a/src/xrGame/ui/UILogsWnd.h b/src/xrGame/ui/UILogsWnd.h index 5c63de57e9..d0a92a6819 100644 --- a/src/xrGame/ui/UILogsWnd.h +++ b/src/xrGame/ui/UILogsWnd.h @@ -83,6 +83,8 @@ class CUILogsWnd : public CUIWindow, public CUIWndCallback IC void UpdateNews() { m_need_reload = true; } void xr_stdcall PerformWork(); + virtual CUIWindow* ui_cast_window() { return this; } + protected: void ReLoadNews(); void AddNewsItem(GAME_NEWS_DATA& news_data); diff --git a/src/xrGame/ui/UIMMShniaga.h b/src/xrGame/ui/UIMMShniaga.h index a50bb91689..a56f87b930 100644 --- a/src/xrGame/ui/UIMMShniaga.h +++ b/src/xrGame/ui/UIMMShniaga.h @@ -26,6 +26,8 @@ class CUIMMShniaga : public CUIWindow, void SetVisibleMagnifier(bool f); virtual void OnDeviceReset(); + virtual CUIWindow* ui_cast_window() { return this; } + enum enum_page_id { epi_main = 0x00, diff --git a/src/xrGame/ui/UIMPAdminMenu.h b/src/xrGame/ui/UIMPAdminMenu.h index d4757e0581..ffb93d3e8b 100644 --- a/src/xrGame/ui/UIMPAdminMenu.h +++ b/src/xrGame/ui/UIMPAdminMenu.h @@ -41,4 +41,7 @@ class CUIMpAdminMenu : public CUIDialogWnd, public CUIWndCallback void SetActiveSubdialog(const shared_str& section); void xr_stdcall RemoteAdminLogin(CUIWindow*, void*); void ShowMessageBox(CUIMessageBox::E_MESSAGEBOX_STYLE style, LPCSTR reason = ""); + + virtual CUIWindow* ui_cast_window() { return this; } + }; diff --git a/src/xrGame/ui/UIMPChangeMapAdm.h b/src/xrGame/ui/UIMPChangeMapAdm.h index 2280b3c48b..0edc9b5c54 100644 --- a/src/xrGame/ui/UIMPChangeMapAdm.h +++ b/src/xrGame/ui/UIMPChangeMapAdm.h @@ -25,4 +25,7 @@ class CUIMpChangeMapAdm : public CUIWindow, public CUIWndCallback void OnBtnOk(); void OnItemSelect(); void FillUpList(); + + virtual CUIWindow* ui_cast_window() { return this; } + }; diff --git a/src/xrGame/ui/UIMPPlayersAdm.cpp b/src/xrGame/ui/UIMPPlayersAdm.cpp index 8530aa0ae1..ea82959abd 100644 --- a/src/xrGame/ui/UIMPPlayersAdm.cpp +++ b/src/xrGame/ui/UIMPPlayersAdm.cpp @@ -146,7 +146,7 @@ void CUIMpPlayersAdm::RefreshPlayersList() if (!tmp_game) return; - tmp_game->RequestPlayersInfo(fastdelegate::FastDelegate(this, &CUIMpPlayersAdm::FillPlayersList)); + tmp_game->RequestPlayersInfo(xr_delegate(this, &CUIMpPlayersAdm::FillPlayersList)); } void CUIMpPlayersAdm::SendMessage(CUIWindow* pWnd, s16 msg, void* pData) diff --git a/src/xrGame/ui/UIMPPlayersAdm.h b/src/xrGame/ui/UIMPPlayersAdm.h index 2ebe389c4b..e1e2b0269a 100644 --- a/src/xrGame/ui/UIMPPlayersAdm.h +++ b/src/xrGame/ui/UIMPPlayersAdm.h @@ -40,5 +40,8 @@ class CUIMpPlayersAdm : public CUIWindow, public CUIWndCallback void GetSelPlayerConfig(); void KickSelPlayer(); void BanSelPlayer(); + + virtual CUIWindow* ui_cast_window() { return this; } + // void SetBanSelPlayerText(); }; diff --git a/src/xrGame/ui/UIMPServerAdm.h b/src/xrGame/ui/UIMPServerAdm.h index 2b733c49b5..7d749bff20 100644 --- a/src/xrGame/ui/UIMPServerAdm.h +++ b/src/xrGame/ui/UIMPServerAdm.h @@ -73,4 +73,7 @@ class CUIMpServerAdm : public CUIWindow, public CUIWndCallback void ShowChangeGameLimitsBtns(); void OnBackBtn(); bool IsBackBtnShown() { return m_pBackBtn->IsShown(); }; + + virtual CUIWindow* ui_cast_window() { return this; } + }; diff --git a/src/xrGame/ui/UIMainIngameWnd.h b/src/xrGame/ui/UIMainIngameWnd.h index 456fbb0cde..5ca3db0c6c 100644 --- a/src/xrGame/ui/UIMainIngameWnd.h +++ b/src/xrGame/ui/UIMainIngameWnd.h @@ -25,6 +25,8 @@ class CUIMainIngameWnd : public CUIWindow virtual void Draw(); virtual void Update(); + virtual CUIWindow* ui_cast_window() { return this; } + public: CUIStatic* UIStaticDiskIO; CUITextWnd* UIStaticQuickHelp; diff --git a/src/xrGame/ui/UIMap.cpp b/src/xrGame/ui/UIMap.cpp index 3dec1225a1..dc10801acf 100644 --- a/src/xrGame/ui/UIMap.cpp +++ b/src/xrGame/ui/UIMap.cpp @@ -307,6 +307,7 @@ void CUIGlobalMap::Init_internal(const shared_str& name, CInifile& pLtx, const s void CUIGlobalMap::Update() { + xrCriticalSectionGuard guard(csUi); for (WINDOW_LIST_it it = m_ChildWndList.begin(); m_ChildWndList.end() != it; ++it) { CUICustomMap* m = smart_cast(*it); @@ -412,6 +413,7 @@ void CUILevelMap::Draw() if (MapWnd()) { float gmz = MapWnd()->GlobalMap()->GetCurrentZoom().x; + xrCriticalSectionGuard guard(csUi); if (m_label && m_label_scale_max > 0.0f) m_label->SetVisible(!!pda_show_map_labels && (gmz < m_label_scale_max)); diff --git a/src/xrGame/ui/UIMap.h b/src/xrGame/ui/UIMap.h index 0ba53e27bc..1e15805ccc 100644 --- a/src/xrGame/ui/UIMap.h +++ b/src/xrGame/ui/UIMap.h @@ -70,6 +70,9 @@ class CUICustomMap : public CUIStatic, public CUIWndCallback void SetRotate(bool b) { m_flags.set(eRotate, b); } void SetPointerDistance(float d) { m_pointer_dist = d; }; float GetPointerDistance() { return m_pointer_dist; }; + + virtual CUIWindow* ui_cast_window() { return this; } + virtual CUIStatic* ui_cast_static() { return this; } protected: virtual void Init_internal(const shared_str& name, CInifile& pLtx, const shared_str& sect_name, LPCSTR sh_name); diff --git a/src/xrGame/ui/UIMapDesc.h b/src/xrGame/ui/UIMapDesc.h index 5b82896e92..e3c7ff761d 100644 --- a/src/xrGame/ui/UIMapDesc.h +++ b/src/xrGame/ui/UIMapDesc.h @@ -17,6 +17,8 @@ class CUIMapDesc : public CUIDialogWnd virtual void SendMessage(CUIWindow* pWnd, s16 msg, void* pData = 0); virtual bool OnKeyboardAction(int dik, EUIMessages keyboard_action); + virtual CUIWindow* ui_cast_window() { return this; } + private: void Init(); diff --git a/src/xrGame/ui/UIMapInfo.h b/src/xrGame/ui/UIMapInfo.h index d25394e74e..2a6e7d97a6 100644 --- a/src/xrGame/ui/UIMapInfo.h +++ b/src/xrGame/ui/UIMapInfo.h @@ -14,6 +14,8 @@ class CUIMapInfo : public CUIWindow void InitMap(LPCSTR map_name, LPCSTR map_ver); LPCSTR GetLargeDesc(); + virtual CUIWindow* ui_cast_window() { return this; } + DECLARE_SCRIPT_REGISTER_FUNCTION protected: CUIScrollView* m_view; diff --git a/src/xrGame/ui/UIMapLegend.h b/src/xrGame/ui/UIMapLegend.h index ba71edcd2c..faac4bff64 100644 --- a/src/xrGame/ui/UIMapLegend.h +++ b/src/xrGame/ui/UIMapLegend.h @@ -33,6 +33,8 @@ class UIMapLegend : public CUIWindow virtual void Show(bool status); virtual void SendMessage(CUIWindow* pWnd, s16 msg, void* pData); + virtual CUIWindow* ui_cast_window() { return this; } + private: // m_ CUIFrameWindow* m_background; CUIScrollView* m_list; @@ -55,6 +57,8 @@ class UIMapLegendItem : public CUIWindow void init_from_xml(CUIXml& xml, int index); // virtual void Update (); + virtual CUIWindow* ui_cast_window() { return this; } + private: // m_ CUIStatic* m_image[4]; CUIStatic* m_text; diff --git a/src/xrGame/ui/UIMapList.h b/src/xrGame/ui/UIMapList.h index 7ae162f9a0..e6ea2a7151 100644 --- a/src/xrGame/ui/UIMapList.h +++ b/src/xrGame/ui/UIMapList.h @@ -26,6 +26,8 @@ class CUIMapList : public CUIWindow virtual void SendMessage(CUIWindow* pWnd, s16 msg, void* pData = NULL); void InitFromXml(CUIXml& xml_doc, const char* path); + virtual CUIWindow* ui_cast_window() { return this; } + void SetWeatherSelector(CUIComboBox* ws); void SetModeSelector(CUIWindow* ms); void SetMapPic(CUIStatic* map_pic); diff --git a/src/xrGame/ui/UIMapWnd.h b/src/xrGame/ui/UIMapWnd.h index 26c361ff90..12dbde0aaa 100644 --- a/src/xrGame/ui/UIMapWnd.h +++ b/src/xrGame/ui/UIMapWnd.h @@ -120,6 +120,8 @@ class CUIMapWnd : public CUIWindow, public CUIWndCallback // replayed at click time to rebuild their per-spot dispatch state (see SendMessage). CUIPropertiesBox* m_UIScratchBox; + virtual CUIWindow* ui_cast_window() { return this; } + public: CUICustomMap* m_tgtMap; Fvector2 m_tgtCenter; diff --git a/src/xrGame/ui/UIMessageBox.h b/src/xrGame/ui/UIMessageBox.h index 42d855ca47..7562a990f5 100644 --- a/src/xrGame/ui/UIMessageBox.h +++ b/src/xrGame/ui/UIMessageBox.h @@ -48,6 +48,10 @@ class CUIMessageBox : public CUIStatic virtual void SendMessage(CUIWindow* pWnd, s16 msg, void* pData); void OnYesOk(); + + virtual CUIWindow* ui_cast_window() { return this; } + virtual CUIStatic* ui_cast_static() { return this; } + protected: xr_string m_ret_val; CUI3tButton* m_UIButtonYesOk; diff --git a/src/xrGame/ui/UIMessageBoxEx.h b/src/xrGame/ui/UIMessageBoxEx.h index 11e4ef28be..3eccc6b61a 100644 --- a/src/xrGame/ui/UIMessageBoxEx.h +++ b/src/xrGame/ui/UIMessageBoxEx.h @@ -28,5 +28,7 @@ class CUIMessageBoxEx : public CUIDialogWnd, public CUIWndCallback virtual bool OnKeyboardAction(int dik, EUIMessages keyboard_action); virtual bool NeedCenterCursor() const { return false; } + virtual CUIWindow* ui_cast_window() { return this; } + CUIMessageBox* m_pMessageBox; }; diff --git a/src/xrGame/ui/UIMessagesWindow.h b/src/xrGame/ui/UIMessagesWindow.h index 8b0bd128ef..44c5ca24fa 100644 --- a/src/xrGame/ui/UIMessagesWindow.h +++ b/src/xrGame/ui/UIMessagesWindow.h @@ -30,6 +30,8 @@ class CUIMessagesWindow : public CUIWindow CUIChatWnd* GetChatWnd() { return m_pChatWnd; } virtual void Show(bool show); + virtual CUIWindow* ui_cast_window() { return this; } + protected: virtual void Init(float x, float y, float width, float height); diff --git a/src/xrGame/ui/UIMoneyIndicator.h b/src/xrGame/ui/UIMoneyIndicator.h index aff1c60b2d..9a8447b1c4 100644 --- a/src/xrGame/ui/UIMoneyIndicator.h +++ b/src/xrGame/ui/UIMoneyIndicator.h @@ -17,6 +17,8 @@ class CUIMoneyIndicator : public CUIWindow void SetMoneyChange(LPCSTR money); void AddBonusMoney(KillMessageStruct& msg); + virtual CUIWindow* ui_cast_window() { return this; } + protected: CUIStatic m_back; CUITextWnd m_money_amount; diff --git a/src/xrGame/ui/UIMotionIcon.h b/src/xrGame/ui/UIMotionIcon.h index 7cf36b698f..d7bf769946 100644 --- a/src/xrGame/ui/UIMotionIcon.h +++ b/src/xrGame/ui/UIMotionIcon.h @@ -18,4 +18,6 @@ class CUIMotionIcon : public CUIWindow virtual void Draw(); void Init(Frect const& rect); void SetNoise(float Pos); + + virtual CUIWindow* ui_cast_window() { return this; } }; diff --git a/src/xrGame/ui/UIMpTradeWnd.h b/src/xrGame/ui/UIMpTradeWnd.h index 06651e80d4..69ef562ea3 100644 --- a/src/xrGame/ui/UIMpTradeWnd.h +++ b/src/xrGame/ui/UIMpTradeWnd.h @@ -131,6 +131,8 @@ class CUIMpTradeWnd : public IBuyWnd, bool HasItemInGroup(shared_str const& section_name); CItemMgr const* GetItemMngr() const { return m_item_mngr; }; + virtual CUIWindow* ui_cast_window() { return this; } + private: //data shared_str m_sectionName; diff --git a/src/xrGame/ui/UINewsItemWnd.h b/src/xrGame/ui/UINewsItemWnd.h index e7f06426f3..6c4aa24e08 100644 --- a/src/xrGame/ui/UINewsItemWnd.h +++ b/src/xrGame/ui/UINewsItemWnd.h @@ -29,4 +29,6 @@ class CUINewsItemWnd : public CUIWindow virtual void Update() { }; + + virtual CUIWindow* ui_cast_window() { return this; } }; diff --git a/src/xrGame/ui/UIOutfitInfo.h b/src/xrGame/ui/UIOutfitInfo.h index d809a25f3e..2b46e39078 100644 --- a/src/xrGame/ui/UIOutfitInfo.h +++ b/src/xrGame/ui/UIOutfitInfo.h @@ -19,6 +19,8 @@ class CUIOutfitImmunity : public CUIWindow void InitFromXml(CUIXml& xml_doc, LPCSTR base_str, u32 hit_type); void SetProgressValue(float cur, float comp); + virtual CUIWindow* ui_cast_window() { return this; } + protected: CUIStatic m_name; // texture + name CUIDoubleProgressBar m_progress; @@ -37,6 +39,9 @@ class CUIOutfitInfo : public CUIWindow void InitFromXml(CUIXml& xml_doc); void UpdateInfo(CCustomOutfit* cur_outfit, CCustomOutfit* slot_outfit = NULL); void UpdateInfo(CHelmet* cur_helmet, CHelmet* slot_helmet = NULL); + + virtual CUIWindow* ui_cast_window() { return this; } + protected: enum { max_count = ALife::eHitTypeMax - 2 }; diff --git a/src/xrGame/ui/UIPdaKillMessage.h b/src/xrGame/ui/UIPdaKillMessage.h index 1e6201a362..28017a2787 100644 --- a/src/xrGame/ui/UIPdaKillMessage.h +++ b/src/xrGame/ui/UIPdaKillMessage.h @@ -10,6 +10,9 @@ class CUIPdaKillMessage : public CUIColorAnimConrollerContainer CUIPdaKillMessage(); void Init(KillMessageStruct& msg, CGameFont* F); + + virtual CUIWindow* ui_cast_window() { return this; } + protected: float InitText(CUITextWnd& refStatic, float x, PlayerInfo& info); float InitIcon(CUIStatic& refStatic, float x, IconInfo& info); diff --git a/src/xrGame/ui/UIPdaMsgListItem.h b/src/xrGame/ui/UIPdaMsgListItem.h index 53ecbe34c8..75bff41458 100644 --- a/src/xrGame/ui/UIPdaMsgListItem.h +++ b/src/xrGame/ui/UIPdaMsgListItem.h @@ -14,6 +14,8 @@ class CUIPdaMsgListItem : public CUIColorAnimConrollerContainer void InitPdaMsgListItem(const Fvector2& size); virtual void SetFont(CGameFont* pFont); + virtual CUIWindow* ui_cast_window() { return this; } + CUIStatic UIIcon; CUITextWnd UITimeText; CUITextWnd UICaptionText; diff --git a/src/xrGame/ui/UIPdaWnd.h b/src/xrGame/ui/UIPdaWnd.h index dd1a8bb6f9..db1062f5f5 100644 --- a/src/xrGame/ui/UIPdaWnd.h +++ b/src/xrGame/ui/UIPdaWnd.h @@ -62,6 +62,8 @@ class CUIPdaWnd : public CUIDialogWnd CMapSpot* pSelectedMapSpot; virtual void Reset(); + + virtual CUIWindow* ui_cast_window() { return this; } public: CUIPdaWnd(); virtual ~CUIPdaWnd(); diff --git a/src/xrGame/ui/UIProgressBar.h b/src/xrGame/ui/UIProgressBar.h index 5e4d34c63d..dfe90daf78 100644 --- a/src/xrGame/ui/UIProgressBar.h +++ b/src/xrGame/ui/UIProgressBar.h @@ -82,5 +82,7 @@ class CUIProgressBar : public CUIWindow virtual void Draw(); virtual void Update(); + virtual CUIWindow* ui_cast_window() { return this; } + DECLARE_SCRIPT_REGISTER_FUNCTION }; diff --git a/src/xrGame/ui/UIProgressShape.h b/src/xrGame/ui/UIProgressShape.h index 2e195dcf73..0bcec103b5 100644 --- a/src/xrGame/ui/UIProgressShape.h +++ b/src/xrGame/ui/UIProgressShape.h @@ -19,6 +19,9 @@ class CUIProgressShape : public CUIStatic public: float m_stage; + virtual CUIWindow* ui_cast_window() { return this; } + virtual CUIStatic* ui_cast_static() { return this; } + protected: bool m_bClockwise; u32 m_sectorCount; diff --git a/src/xrGame/ui/UIRadioButton.h b/src/xrGame/ui/UIRadioButton.h index fdff607d58..f692e1d3d4 100644 --- a/src/xrGame/ui/UIRadioButton.h +++ b/src/xrGame/ui/UIRadioButton.h @@ -14,4 +14,5 @@ class CUIRadioButton : public CUITabButton { /*do nothing*/ } + virtual CUIWindow* ui_cast_window() { return this; } }; diff --git a/src/xrGame/ui/UIRankIndicator.h b/src/xrGame/ui/UIRankIndicator.h index 36172e4578..fbe32d24ea 100644 --- a/src/xrGame/ui/UIRankIndicator.h +++ b/src/xrGame/ui/UIRankIndicator.h @@ -17,4 +17,6 @@ class CUIRankIndicator : public CUIWindow virtual ~CUIRankIndicator(); void InitFromXml(CUIXml& xml_doc); void SetRank(u8 team, u8 rank); + + virtual CUIWindow* ui_cast_window() { return this; } }; diff --git a/src/xrGame/ui/UIRankingWnd.h b/src/xrGame/ui/UIRankingWnd.h index 372864389a..0ce16c6c9e 100644 --- a/src/xrGame/ui/UIRankingWnd.h +++ b/src/xrGame/ui/UIRankingWnd.h @@ -69,6 +69,8 @@ class CUIRankingWnd : public CUIWindow, public CUIWndCallback void Init(); void update_info(); + virtual CUIWindow* ui_cast_window() { return this; } + protected: void add_achievement(CUIXml& xml, shared_str const& faction_id); void get_statistic(); diff --git a/src/xrGame/ui/UIRankingsCoC.h b/src/xrGame/ui/UIRankingsCoC.h index 82f42cb142..fa52a790ea 100644 --- a/src/xrGame/ui/UIRankingsCoC.h +++ b/src/xrGame/ui/UIRankingsCoC.h @@ -35,6 +35,8 @@ class CUIRankingsCoC : public CUIWindow virtual void DrawHint(); virtual void Reset(); + virtual CUIWindow* ui_cast_window() { return this; } + protected: bool ParentHasMe(); }; diff --git a/src/xrGame/ui/UIScriptWnd.h b/src/xrGame/ui/UIScriptWnd.h index d2b8d9de01..d85c9f920a 100644 --- a/src/xrGame/ui/UIScriptWnd.h +++ b/src/xrGame/ui/UIScriptWnd.h @@ -31,6 +31,9 @@ class CUIDialogWndEx : public CUIDialogWnd, public DLL_Pure virtual bool OnMouseAction(float x, float y, EUIMessages mouse_action); virtual bool OnKeyboardAction(int dik, EUIMessages keyboard_action); virtual bool Dispatch(int cmd, int param) { return true; } + + virtual CUIWindow* ui_cast_window() { return this; } + /* template IC T* GetControl(LPCSTR name); diff --git a/src/xrGame/ui/UIScrollBar.h b/src/xrGame/ui/UIScrollBar.h index 747f12bdb6..3332ebc209 100644 --- a/src/xrGame/ui/UIScrollBar.h +++ b/src/xrGame/ui/UIScrollBar.h @@ -102,4 +102,6 @@ class CUIScrollBar : public CUIWindow void TryScrollInc(bool by_scrollbox = false); void TryScrollDec(bool by_scrollbox = false); + + virtual CUIWindow* ui_cast_window() { return this; } }; diff --git a/src/xrGame/ui/UIScrollBox.h b/src/xrGame/ui/UIScrollBox.h index 9625649f4d..f115678f75 100644 --- a/src/xrGame/ui/UIScrollBox.h +++ b/src/xrGame/ui/UIScrollBox.h @@ -8,4 +8,6 @@ class CUIScrollBox : public CUIFrameLineWnd CUIScrollBox(); virtual bool OnMouseAction(float x, float y, EUIMessages mouse_action); + + virtual CUIWindow* ui_cast_window() { return this; } }; diff --git a/src/xrGame/ui/UIScrollView.cpp b/src/xrGame/ui/UIScrollView.cpp index ef9bc160a2..e0b383cd43 100644 --- a/src/xrGame/ui/UIScrollView.cpp +++ b/src/xrGame/ui/UIScrollView.cpp @@ -144,6 +144,7 @@ void CUIScrollView::RecalcSize() pad_size.y += m_upIndent; pad_size.y += m_downIndent; + xrCriticalSectionGuard guard(m_pad->csUi); if (m_sort_function) { //. m_pad->GetChildWndList().sort(m_sort_function); @@ -153,7 +154,7 @@ void CUIScrollView::RecalcSize() if (GetVertFlip()) { for (WINDOW_LIST::reverse_iterator it = m_pad->GetChildWndList().rbegin(); m_pad->GetChildWndList().rend() != it - ; ++it) + ; ++it) { (*it)->SetWndPos(item_pos); item_pos.y += (*it)->GetWndSize().y; @@ -184,7 +185,7 @@ void CUIScrollView::RecalcSize() UpdateScroll(); - m_flags.set(eNeedRecalc,FALSE); + m_flags.set(eNeedRecalc, FALSE); m_visible_rgn.set(-1, -1); } @@ -219,6 +220,7 @@ void CUIScrollView::Draw() visible_rect.bottom -= m_downIndent; UI().PushScissor(visible_rect); + xrCriticalSectionGuard guard(m_pad->csUi); WINDOW_LIST_it it = m_pad->GetChildWndList().begin(); // WINDOW_LIST_it it_e = m_pad->GetChildWndList().end(); @@ -228,7 +230,7 @@ void CUIScrollView::Draw() for (int idx = m_visible_rgn.x; idx <= m_visible_rgn.y; ++it, ++idx) { CUIScrollView* sw = smart_cast(*it); - VERIFY(sw==NULL); + VERIFY(sw == NULL); if ((*it)->GetVisible()) (*it)->Draw(); @@ -329,7 +331,7 @@ void CUIScrollView::SetScrollPos(int value) clamp(value, GetMinScrollPos(), GetMaxScrollPos()); m_VScrollBar->SetScrollPos(value); - OnScrollV(NULL,NULL); + OnScrollV(NULL, NULL); } void CUIScrollView::ScrollToBegin() @@ -338,7 +340,7 @@ void CUIScrollView::ScrollToBegin() RecalcSize(); m_VScrollBar->SetScrollPos(m_VScrollBar->GetMinRange()); - OnScrollV(NULL,NULL); + OnScrollV(NULL, NULL); } void CUIScrollView::ScrollToEnd() @@ -347,31 +349,31 @@ void CUIScrollView::ScrollToEnd() RecalcSize(); m_VScrollBar->SetScrollPos(m_VScrollBar->GetMaxRange()); - OnScrollV(NULL,NULL); + OnScrollV(NULL, NULL); } void CUIScrollView::SetRightIndention(float val) { m_rightIndent = val; - m_flags.set(eNeedRecalc,TRUE); + m_flags.set(eNeedRecalc, TRUE); } void CUIScrollView::SetLeftIndention(float val) { m_leftIndent = val; - m_flags.set(eNeedRecalc,TRUE); + m_flags.set(eNeedRecalc, TRUE); } void CUIScrollView::SetUpIndention(float val) { m_upIndent = val; - m_flags.set(eNeedRecalc,TRUE); + m_flags.set(eNeedRecalc, TRUE); } void CUIScrollView::SetDownIndention(float val) { m_downIndent = val; - m_flags.set(eNeedRecalc,TRUE); + m_flags.set(eNeedRecalc, TRUE); } u32 CUIScrollView::GetSize() @@ -381,9 +383,10 @@ u32 CUIScrollView::GetSize() CUIWindow* CUIScrollView::GetItem(u32 idx) { - if (m_pad->GetChildWndList().size() <= idx) - return NULL; + if (m_pad->GetChildNum() <= idx) + return nullptr; + xrCriticalSectionGuard guard(m_pad->csUi); WINDOW_LIST_it it = m_pad->GetChildWndList().begin(); std::advance(it, idx); return (*it); @@ -412,6 +415,7 @@ void CUIScrollView::SetSelected(CUIWindow* w) if (!m_flags.test(eItemsSelectabe)) return; + xrCriticalSectionGuard guard(m_pad->csUi); for (WINDOW_LIST_it it = m_pad->GetChildWndList().begin(); m_pad->GetChildWndList().end() != it; ++it) { smart_cast(*it)->SetSelected(*it == w); @@ -423,6 +427,7 @@ CUIWindow* CUIScrollView::GetSelected() if (!m_flags.test(eItemsSelectabe)) return NULL; + xrCriticalSectionGuard guard(m_pad->csUi); for (WINDOW_LIST_it it = m_pad->GetChildWndList().begin(); m_pad->GetChildWndList().end() != it; ++it) { if (smart_cast(*it)->GetSelected()) @@ -435,6 +440,7 @@ CUIWindow* CUIScrollView::GetSelected() void CUIScrollView::UpdateChildrenLenght() { float len = GetDesiredChildWidth(); + xrCriticalSectionGuard guard(m_pad->csUi); for (WINDOW_LIST_it it = m_pad->GetChildWndList().begin(); m_pad->GetChildWndList().end() != it; ++it) { (*it)->SetWidth(len); diff --git a/src/xrGame/ui/UIScrollView.h b/src/xrGame/ui/UIScrollView.h index 5cb9a5e4c8..9e7c725eb0 100644 --- a/src/xrGame/ui/UIScrollView.h +++ b/src/xrGame/ui/UIScrollView.h @@ -58,7 +58,11 @@ class CUIScrollView : public CUIWindow, public CUIWndCallback void ScrollToBegin(); void ScrollToEnd(); bool GetVertFlip() { return !!m_flags.test(eVertFlip); } - bool Empty() { return m_pad->GetChildWndList().empty(); } + bool Empty() + { + xrCriticalSectionGuard guard(m_pad->csUi); + return m_pad->GetChildWndList().empty(); + } u32 GetSize(); WINDOW_LIST& Items() { return m_pad->GetChildWndList(); } CUIWindow* GetItem(u32 idx); @@ -80,7 +84,10 @@ class CUIScrollView : public CUIWindow, public CUIWndCallback float Scroll2ViewV(); // calculate scale for scroll position CUIScrollBar* ScrollBar() { return m_VScrollBar; } - typedef fastdelegate::FastDelegate2 cmp_function; + virtual CUIWindow* ui_cast_window() { return this; } + virtual CUIScrollView* ui_cast_scroll_view() { return this; } + + typedef xr_delegate cmp_function; cmp_function m_sort_function; }; diff --git a/src/xrGame/ui/UISecondTaskWnd.h b/src/xrGame/ui/UISecondTaskWnd.h index 533220f849..9ab27e5958 100644 --- a/src/xrGame/ui/UISecondTaskWnd.h +++ b/src/xrGame/ui/UISecondTaskWnd.h @@ -44,6 +44,8 @@ class UITaskListWnd : public CUIWindow, public CUIWndCallback void UpdateList(); + virtual CUIWindow* ui_cast_window() { return this; } + protected: void xr_stdcall OnBtnClose(CUIWindow* w, void* d); bool xr_stdcall SortingLessFunction(CUIWindow* left, CUIWindow* right); @@ -84,6 +86,8 @@ class UITaskListWndItem : public CUIWindow virtual void SendMessage(CUIWindow* pWnd, s16 msg, void* pData); virtual bool OnMouseAction(float x, float y, EUIMessages mouse_action); + virtual CUIWindow* ui_cast_window() { return this; } + private: void hide_hint(); void update_view(); diff --git a/src/xrGame/ui/UIServerInfo.h b/src/xrGame/ui/UIServerInfo.h index adbe8532c2..0f33bcb48a 100644 --- a/src/xrGame/ui/UIServerInfo.h +++ b/src/xrGame/ui/UIServerInfo.h @@ -24,6 +24,8 @@ class CUIServerInfo : void SetServerRules(u8 const* data_ptr, u32 const data_size); bool HasInfo() { return m_dds_file_created; }; virtual bool OnKeyboardAction(int dik, EUIMessages keyboard_action); + + virtual CUIWindow* ui_cast_window() { return this; } private: void InitCallbacks(); diff --git a/src/xrGame/ui/UISkinSelector.h b/src/xrGame/ui/UISkinSelector.h index 5657e6a459..b86c5ead9c 100644 --- a/src/xrGame/ui/UISkinSelector.h +++ b/src/xrGame/ui/UISkinSelector.h @@ -36,6 +36,9 @@ class CUISkinSelectorWnd : public CUIDialogWnd int GetActiveIndex(); s16 GetTeam() { return m_team; }; virtual void Update(); + + virtual CUIWindow* ui_cast_window() { return this; } + protected: void OnBtnOK(); void OnBtnCancel(); diff --git a/src/xrGame/ui/UISpawnWnd.h b/src/xrGame/ui/UISpawnWnd.h index 8819184d6f..73917745e8 100644 --- a/src/xrGame/ui/UISpawnWnd.h +++ b/src/xrGame/ui/UISpawnWnd.h @@ -31,6 +31,8 @@ class CUISpawnWnd : public CUIDialogWnd void SetVisibleForBtn(ETEAMMENU_BTN btn, bool state); void SetCurTeam(int team); + virtual CUIWindow* ui_cast_window() { return this; } + protected: void InitTeamLogo(); diff --git a/src/xrGame/ui/UISpeechMenu.h b/src/xrGame/ui/UISpeechMenu.h index a6b195e84b..d2b6c9b737 100644 --- a/src/xrGame/ui/UISpeechMenu.h +++ b/src/xrGame/ui/UISpeechMenu.h @@ -13,6 +13,7 @@ class CUISpeechMenu : public CUIDialogWnd virtual bool NeedCursor() const { return false; } virtual bool OnKeyboardAction(int dik, EUIMessages keyboard_action); virtual bool StopAnyMove() { return false; } + virtual CUIWindow* ui_cast_window() { return this; } private: CUIScrollView* m_pList; u32 m_text_color; diff --git a/src/xrGame/ui/UIStatic.cpp b/src/xrGame/ui/UIStatic.cpp index 71154892a5..edbb0a0289 100644 --- a/src/xrGame/ui/UIStatic.cpp +++ b/src/xrGame/ui/UIStatic.cpp @@ -80,6 +80,7 @@ void CUIStatic::InitTextureEx(LPCSTR tex_name, LPCSTR sh_name) void CUIStatic::Draw() { + PROF_EVENT("CUIStatic::Draw"); DrawTexture(); inherited::Draw(); DrawText(); @@ -318,7 +319,7 @@ void CUITextWnd::Draw() void CUITextWnd::Update() { - R_ASSERT(GetChildWndList().size()==0); + R_ASSERT(GetChildNum() == 0); UpdateColorAnimation(); inherited::Update(); } diff --git a/src/xrGame/ui/UIStatic.h b/src/xrGame/ui/UIStatic.h index ed1edb851d..7725e8b2ca 100644 --- a/src/xrGame/ui/UIStatic.h +++ b/src/xrGame/ui/UIStatic.h @@ -118,7 +118,11 @@ class CUIStatic : public CUIWindow, public ITextureOwner, public CUILightAnimCol virtual void ColorAnimationSetTextureColor(u32 color, bool only_alpha); virtual void ColorAnimationSetTextColor(u32 color, bool only_alpha); - void SetNoShaderCache(bool v) { m_UIStaticItem.SetNoShaderCache(v); } + virtual CUIWindow* ui_cast_window() { return this; } + virtual CUIStatic* ui_cast_static() { return this; } + virtual ITextureOwner* ui_cast_texture_owner() { return this; } + virtual CUILightAnimColorConroller* ui_cast_light_anim_color_controller() { return this; } + void SetNoShaderCache(bool v) { m_UIStaticItem.SetNoShaderCache(v); } protected: CUILines* m_pTextControl; @@ -134,7 +138,7 @@ class CUIStatic : public CUIWindow, public ITextureOwner, public CUILightAnimCol Fvector2 m_TextureOffset; public: - std::string m_TextureName; + xr_string m_TextureName; CUILines* TextItemControl(); shared_str m_stat_hint_text; @@ -178,6 +182,9 @@ class CUITextWnd : public CUIWindow, public CUILightAnimColorConrollerImpl virtual void ColorAnimationSetTextColor(u32 color, bool only_alpha); + virtual CUIWindow* ui_cast_window() { return this; } + virtual CUILightAnimColorConroller* ui_cast_light_anim_color_controller() { return this; } + CUILines& TextItemControl() { return m_lines; } diff --git a/src/xrGame/ui/UIStats.h b/src/xrGame/ui/UIStats.h index cdb6eb51a6..cd123bae5a 100644 --- a/src/xrGame/ui/UIStats.h +++ b/src/xrGame/ui/UIStats.h @@ -12,4 +12,7 @@ class CUIStats : public CUIScrollView CUIStats(); virtual ~CUIStats(); CUIWindow* InitStats(CUIXml& xml_doc, LPCSTR path, int team); + + virtual CUIWindow* ui_cast_window() { return this; } + virtual CUIScrollView* ui_cast_scroll_view() { return this; } }; diff --git a/src/xrGame/ui/UIStatsIcon.h b/src/xrGame/ui/UIStatsIcon.h index f5bb606ffc..2f69182ffc 100644 --- a/src/xrGame/ui/UIStatsIcon.h +++ b/src/xrGame/ui/UIStatsIcon.h @@ -11,6 +11,8 @@ class CUIStatsIcon : public CUIStatic CUIStatsIcon(); void SetValue(LPCSTR str); + virtual CUIWindow* ui_cast_window() { return this; } + virtual CUIStatic* ui_cast_static() { return this; } protected: enum DEF_TEX diff --git a/src/xrGame/ui/UIStatsPlayerInfo.h b/src/xrGame/ui/UIStatsPlayerInfo.h index af33b318d7..4b34481b30 100644 --- a/src/xrGame/ui/UIStatsPlayerInfo.h +++ b/src/xrGame/ui/UIStatsPlayerInfo.h @@ -21,6 +21,8 @@ class CUIStatsPlayerInfo : public CUIWindow void InitPlayerInfo(Fvector2 pos, Fvector2 size); virtual void Update(); + virtual CUIWindow* ui_cast_window() { return this; } + protected: void AddField(float len, CGameFont* pF, u32 text_col, bool icon); const char* GetInfoByID(const char* id); diff --git a/src/xrGame/ui/UIStatsPlayerList.cpp b/src/xrGame/ui/UIStatsPlayerList.cpp index 210e33ad83..a41ab64ccf 100644 --- a/src/xrGame/ui/UIStatsPlayerList.cpp +++ b/src/xrGame/ui/UIStatsPlayerList.cpp @@ -273,14 +273,15 @@ void CUIStatsPlayerList::Update() std::sort(items.begin(), items.end(), DM_Compare_Players); int n = (int)items.size(); - n -= m_pad->GetChildWndList().size(); + n -= (int)m_pad->GetChildNum(); if (n < 0) { n = abs(n); + xrCriticalSectionGuard guard(m_pad->csUi); for (int i = 0; i < n; i++) m_pad->DetachChild(*(m_pad->GetChildWndList().begin())); - m_flags.set(eNeedRecalc,TRUE); + m_flags.set(eNeedRecalc, TRUE); } else { @@ -289,12 +290,13 @@ void CUIStatsPlayerList::Update() CUIStatsPlayerInfo* pi = xr_new(&m_field_info, m_i.f, m_i.c); pi->InitPlayerInfo(Fvector2().set(0, 0), Fvector2().set(this->GetDesiredChildWidth(), m_i.h)); CUIScrollView::AddWindow(pi, true); - m_flags.set(eNeedRecalc,TRUE); + m_flags.set(eNeedRecalc, TRUE); } } - R_ASSERT(items.size() == m_pad->GetChildWndList().size()); + R_ASSERT(items.size() == m_pad->GetChildNum()); + xrCriticalSectionGuard guard(m_pad->csUi); WINDOW_LIST_it it = m_pad->GetChildWndList().begin(); ItemIt itit = items.begin(); diff --git a/src/xrGame/ui/UIStatsPlayerList.h b/src/xrGame/ui/UIStatsPlayerList.h index 671c1904fd..f0fd8b94b7 100644 --- a/src/xrGame/ui/UIStatsPlayerList.h +++ b/src/xrGame/ui/UIStatsPlayerList.h @@ -25,6 +25,9 @@ class CUIStatsPlayerList : public CUIScrollView virtual void AddWindow(CUIWindow* pWnd, bool auto_delete = true); virtual void Update(); + virtual CUIWindow* ui_cast_window() { return this; } + virtual CUIScrollView* ui_cast_scroll_view() { return this; } + protected: void InitHeader(CUIXml& xml_doc, LPCSTR path); void InitTeamHeader(CUIXml& xml_doc, LPCSTR path); diff --git a/src/xrGame/ui/UITabButton.h b/src/xrGame/ui/UITabButton.h index e98ea77ce9..33ca7cf6ad 100644 --- a/src/xrGame/ui/UITabButton.h +++ b/src/xrGame/ui/UITabButton.h @@ -15,6 +15,8 @@ class CUITabButton : public CUI3tButton virtual bool OnMouseAction(float x, float y, EUIMessages mouse_action); virtual bool OnMouseDown(int mouse_btn); + virtual CUIWindow* ui_cast_window() { return this; } + float Overlap() const { return m_overlap; } void SetOverlap(float v) { m_overlap = v; } float Pitch() const { return GetWndSize().x - m_overlap; } diff --git a/src/xrGame/ui/UITabButtonMP.h b/src/xrGame/ui/UITabButtonMP.h index 65f4e8306c..71424830da 100644 --- a/src/xrGame/ui/UITabButtonMP.h +++ b/src/xrGame/ui/UITabButtonMP.h @@ -15,6 +15,8 @@ class CUITabButtonMP : public CUITabButton void SetOrientation(bool bVert) { m_orientationVertical = bVert; }; void CreateHint(); + virtual CUIWindow* ui_cast_window() { return this; } + shared_str m_temp_id; Fvector2 m_text_ident_normal; diff --git a/src/xrGame/ui/UITabControl.cpp b/src/xrGame/ui/UITabControl.cpp index b5b49dc632..1585613586 100644 --- a/src/xrGame/ui/UITabControl.cpp +++ b/src/xrGame/ui/UITabControl.cpp @@ -223,7 +223,8 @@ void CUITabControl::OnTabChange(const shared_str& sCur, const shared_str& sPrev) if (tb_prev) tb_prev->SendMessage(tb_cur, TAB_CHANGED, NULL); - tb_cur->SendMessage(tb_cur, TAB_CHANGED, NULL); + if (tb_cur) + tb_cur->SendMessage(tb_cur, TAB_CHANGED, NULL); if (GetAcceleratorsMode()) GetMessageTarget()->SendMessage(this, TAB_CHANGED, NULL); diff --git a/src/xrGame/ui/UITabControl.h b/src/xrGame/ui/UITabControl.h index a2d3f492fc..f08e9692a8 100644 --- a/src/xrGame/ui/UITabControl.h +++ b/src/xrGame/ui/UITabControl.h @@ -84,6 +84,9 @@ class CUITabControl : public CUIWindow, public CUIOptionsItem CUITabButton* GetButtonById_script(LPCSTR s) { return GetButtonById(s); } void ResetTab(); + + virtual CUIWindow* ui_cast_window() { return this; } + protected: // Список кнопок - переключателей закладок TABS_VECTOR m_TabsArr; diff --git a/src/xrGame/ui/UITalkDialogWnd.h b/src/xrGame/ui/UITalkDialogWnd.h index 90328c523b..e47977fb52 100644 --- a/src/xrGame/ui/UITalkDialogWnd.h +++ b/src/xrGame/ui/UITalkDialogWnd.h @@ -61,6 +61,8 @@ class CUITalkDialogWnd : public CUIWindow, public CUIWndCallback void SetTradeMode(); void UpdateButtonsLayout(bool b_disable_break, bool trade_enabled); + virtual CUIWindow* ui_cast_window() { return this; } + private: CUIScrollView* UIQuestionsList; CUIScrollView* UIAnswersList; @@ -91,6 +93,8 @@ class CUIQuestionItem : public CUIWindow, public CUIWndCallback virtual void SendMessage(CUIWindow* pWnd, s16 msg, void* pData = NULL); void __stdcall OnTextClicked(CUIWindow* w, void*); + + virtual CUIWindow* ui_cast_window() { return this; } }; class CUIAnswerItem : public CUIWindow @@ -104,6 +108,8 @@ class CUIAnswerItem : public CUIWindow public: CUIAnswerItem(CUIXml* xml_doc, LPCSTR path); void Init(LPCSTR text, LPCSTR name); + + virtual CUIWindow* ui_cast_window() { return this; } }; class CUIAnswerItemIconed : public CUIAnswerItem diff --git a/src/xrGame/ui/UITalkWnd.cpp b/src/xrGame/ui/UITalkWnd.cpp index 62d71e0a37..ec16463f69 100644 --- a/src/xrGame/ui/UITalkWnd.cpp +++ b/src/xrGame/ui/UITalkWnd.cpp @@ -177,6 +177,7 @@ void CUITalkWnd::SendMessage(CUIWindow* pWnd, s16 msg, void* pData) ////////////////////////////////////////////////////////////////////////// void UpdateCameraDirection(CGameObject* pTo) { + if (!pTo) return; if (Actor()->cam_freelook != eflDisabled) return; diff --git a/src/xrGame/ui/UITalkWnd.h b/src/xrGame/ui/UITalkWnd.h index d187adfff7..db81c32b94 100644 --- a/src/xrGame/ui/UITalkWnd.h +++ b/src/xrGame/ui/UITalkWnd.h @@ -57,6 +57,8 @@ class CUITalkWnd : public CUIDialogWnd void SwitchToUpgrade(); void AddIconedMessage(LPCSTR caption, LPCSTR text, LPCSTR texture_name, LPCSTR templ_name); + virtual CUIWindow* ui_cast_window() { return this; } + protected: //диалог void InitTalkDialog(); diff --git a/src/xrGame/ui/UITaskWnd.h b/src/xrGame/ui/UITaskWnd.h index 1ed051c024..2b3ba71d7a 100644 --- a/src/xrGame/ui/UITaskWnd.h +++ b/src/xrGame/ui/UITaskWnd.h @@ -100,6 +100,8 @@ class CUITaskWnd : public CUIWindow, void Show_TaskListWnd(bool status); + virtual CUIWindow* ui_cast_window() { return this; } + private: void TaskSetTargetMap(CGameTask* task); void TaskShowMapSpot(CGameTask* task, bool show); @@ -137,6 +139,8 @@ class CUITaskItem : public CUIWindow void InitTask(CGameTask* task); CGameTask* OwnerTask() { return m_owner; } + virtual CUIWindow* ui_cast_window() { return this; } + public: bool show_hint_can; bool show_hint; diff --git a/src/xrGame/ui/UITrackBar.h b/src/xrGame/ui/UITrackBar.h index 97782776e7..887befc65e 100644 --- a/src/xrGame/ui/UITrackBar.h +++ b/src/xrGame/ui/UITrackBar.h @@ -37,6 +37,9 @@ class CUITrackBar : public CUI_IB_FrameLineWnd, public CUIOptionsItem void SetFValue(float f); void SetOptIBounds(int imin, int imax); void SetOptFBounds(float fmin, float fmax); + + virtual CUIWindow* ui_cast_window() { return this; } + protected: void UpdatePos(); void UpdatePosRelativeToMouse(); diff --git a/src/xrGame/ui/UIVote.h b/src/xrGame/ui/UIVote.h index 079c9befff..eaaa7ec0db 100644 --- a/src/xrGame/ui/UIVote.h +++ b/src/xrGame/ui/UIVote.h @@ -21,6 +21,9 @@ class CUIVote : public CUIDialogWnd void OnBtnNo(); void OnBtnCancel(); void SetVoting(LPCSTR txt); + + virtual CUIWindow* ui_cast_window() { return this; } + protected: CUITextWnd* msg; CUITextWnd* cap[3]; diff --git a/src/xrGame/ui/UIVoteStatusWnd.h b/src/xrGame/ui/UIVoteStatusWnd.h index 4c969d0d39..bd9888edf8 100644 --- a/src/xrGame/ui/UIVoteStatusWnd.h +++ b/src/xrGame/ui/UIVoteStatusWnd.h @@ -14,4 +14,6 @@ class UIVoteStatusWnd : public CUIFrameWindow void InitFromXML(CUIXml& xml_doc); void SetVoteTimeResultMsg(LPCSTR s); void SetVoteMsg(LPCSTR s); + + virtual CUIWindow* ui_cast_window() { return this; } }; diff --git a/src/xrGame/ui/UIVotingCategory.h b/src/xrGame/ui/UIVotingCategory.h index ebc0d931a4..4de318fdf5 100644 --- a/src/xrGame/ui/UIVotingCategory.h +++ b/src/xrGame/ui/UIVotingCategory.h @@ -27,6 +27,8 @@ class CUIVotingCategory : public CUIDialogWnd virtual void Update(); + virtual CUIWindow* ui_cast_window() { return this; } + protected: void InitVotingCategory(); diff --git a/src/xrGame/ui/UIWindow.cpp b/src/xrGame/ui/UIWindow.cpp index 5840c89f68..5017b2bf1d 100644 --- a/src/xrGame/ui/UIWindow.cpp +++ b/src/xrGame/ui/UIWindow.cpp @@ -138,16 +138,25 @@ CUIWindow::~CUIWindow() //if (m_pHint) // xr_delete(m_pHint); + if (CurrentGameUI()) + { + CurrentGameUI()->RemoveDialogToRender(this); + } + CUIWindow* parent = GetParent(); bool ad = IsAutoDelete(); if (parent && !ad) parent->CUIWindow::DetachChild(this); - DetachAll(); + if (!m_ChildWndList.empty()) { + DetachAll(); + } if (GetPPMode()) MainMenu()->UnregisterPPDraw(this); + CollectGarbage(); + #ifdef LOG_ALL_WNDS xr_vector::iterator _it = dbg_list_wnds.begin(); bool bOK = false; @@ -171,15 +180,17 @@ CUIWindow::~CUIWindow() void CUIWindow::Draw() { - for (WINDOW_LIST_it it = m_ChildWndList.begin(); m_ChildWndList.end() != it; ++it) + PROF_EVENT("CUIWindow::Draw"); + xrCriticalSectionGuard guard(csUi); + for (CUIWindow* W : m_ChildWndList) { - if (!(*it)) continue; - if (!(*it)->IsShown()) continue; - if ((*it)->GetCustomDraw()) continue; - (*it)->Draw(); + if (!W) continue; + if (!W->IsShown()) continue; + if (W->GetCustomDraw()) continue; + W->Draw(); } #ifdef DEBUG - if(g_show_wnd_rect2){ + if (g_show_wnd_rect2) { Frect r; GetAbsoluteRect(r); add_rect_to_draw(r); @@ -189,12 +200,14 @@ void CUIWindow::Draw() void CUIWindow::Draw(float x, float y) { + PROF_EVENT("CUIWindow::Draw"); SetWndPos(Fvector2().set(x, y)); Draw(); } void CUIWindow::Update() { + PROF_EVENT("CUIWindow::Update"); CUIDialogWnd* TIR = CurrentGameUI() ? CurrentGameUI()->TopInputReceiver() : nullptr; if (GetUICursor().IsVisible() || (TIR && !TIR->NeedCursor())) @@ -215,20 +228,30 @@ void CUIWindow::Update() } } - for (WINDOW_LIST_it it = m_ChildWndList.begin(); m_ChildWndList.end() != it; ++it) - { - if (!(*it)->IsShown()) continue; - (*it)->Update(); - } + { + xrCriticalSectionGuard guard(csUi); + for (WINDOW_LIST_it it = m_ChildWndList.begin(); m_ChildWndList.end() != it; ++it) + { + if (!(*it)->IsShown()) continue; + (*it)->Update(); + } + } - /* - if (m_pHint && bShowHint) - { - if (Device.dwTimeGlobal < (m_dwFocusReceiveTime + dwHintDelay)) - return; - m_pHint->set_text(m_sHint); - } - */ + CollectGarbage(); +} + +void CUIWindow::CollectGarbage() +{ + if (m_ChildWndToDelete.empty()) + return; + + WINDOW_LIST temp; + temp.swap(m_ChildWndToDelete); + for (CUIWindow* pChild : temp) + { + if (pChild) + xr_delete(pChild); + } } void CUIWindow::AttachChild(CUIWindow* pChild) @@ -243,6 +266,8 @@ void CUIWindow::AttachChild(CUIWindow* pChild) } pChild->SetParent(this); + + xrCriticalSectionGuard guard(csUi); m_ChildWndList.push_back(pChild); } @@ -255,19 +280,26 @@ void CUIWindow::DetachChild(CUIWindow* pChild) if (m_pMouseCapturer == pChild) SetCapture(pChild, false); - //. SafeRemoveChild (pChild); - WINDOW_LIST_it it = std::find(m_ChildWndList.begin(), m_ChildWndList.end(), pChild); - R_ASSERT(it!=m_ChildWndList.end()); - m_ChildWndList.erase(it); + { + xrCriticalSectionGuard guard(csUi); + + //. SafeRemoveChild (pChild); + WINDOW_LIST_it it = std::find(m_ChildWndList.begin(), m_ChildWndList.end(), pChild); + R_ASSERT(it != m_ChildWndList.end()); + m_ChildWndList.erase(it); + } pChild->SetParent(NULL); - if (pChild->IsAutoDelete()) - xr_delete(pChild); + if (pChild->IsAutoDelete()) + if (std::find(m_ChildWndToDelete.begin(), m_ChildWndToDelete.end(), pChild) == m_ChildWndToDelete.end()) + m_ChildWndToDelete.push_back(pChild); } void CUIWindow::DetachAll() { + xrCriticalSectionGuard guard(csUi); + while (!m_ChildWndList.empty()) { DetachChild(m_ChildWndList.back()); @@ -334,8 +366,8 @@ bool CUIWindow::OnMouseAction(float x, float y, EUIMessages mouse_action) if (m_pMouseCapturer) { m_pMouseCapturer->OnMouseAction(cursor_pos.x - m_pMouseCapturer->GetWndRect().left, - cursor_pos.y - m_pMouseCapturer->GetWndRect().top, - mouse_action); + cursor_pos.y - m_pMouseCapturer->GetWndRect().top, + mouse_action); return true; } @@ -370,6 +402,7 @@ bool CUIWindow::OnMouseAction(float x, float y, EUIMessages mouse_action) //Проверка на попадание мыши в окно, //происходит в обратном порядке, чем рисование окон //(последние в списке имеют высший приоритет) + xrCriticalSectionGuard guard(csUi); WINDOW_LIST::reverse_iterator it = m_ChildWndList.rbegin(); for (; it != m_ChildWndList.rend(); ++it) @@ -381,14 +414,14 @@ bool CUIWindow::OnMouseAction(float x, float y, EUIMessages mouse_action) if (w->IsEnabled()) { if (w->OnMouseAction(cursor_pos.x - w->GetWndRect().left, - cursor_pos.y - w->GetWndRect().top, mouse_action)) + cursor_pos.y - w->GetWndRect().top, mouse_action)) return true; } } else if (w->IsEnabled() && w->CursorOverWindow()) { if (w->OnMouseAction(cursor_pos.x - w->GetWndRect().left, - cursor_pos.y - w->GetWndRect().top, mouse_action)) + cursor_pos.y - w->GetWndRect().top, mouse_action)) return true; } } @@ -486,6 +519,7 @@ bool CUIWindow::OnKeyboardAction(int dik, EUIMessages keyboard_action) if (result) return true; } + xrCriticalSectionGuard guard(csUi); WINDOW_LIST::reverse_iterator it = m_ChildWndList.rbegin(); for (; it != m_ChildWndList.rend(); ++it) @@ -511,6 +545,7 @@ bool CUIWindow::OnKeyboardHold(int dik) if (result) return true; } + xrCriticalSectionGuard guard(csUi); WINDOW_LIST::reverse_iterator it = m_ChildWndList.rbegin(); for (; it != m_ChildWndList.rend(); ++it) @@ -547,6 +582,7 @@ void CUIWindow::SetKeyboardCapture(CUIWindow* pChildWindow, bool capture_status) //обработка сообщений void CUIWindow::SendMessage(CUIWindow* pWnd, s16 msg, void* pData) { + xrCriticalSectionGuard guard(csUi); //оповестить дочерние окна for (WINDOW_LIST_it it = m_ChildWndList.begin(); m_ChildWndList.end() != it; ++it) { @@ -562,6 +598,7 @@ CUIWindow* CUIWindow::GetCurrentMouseHandler() CUIWindow* CUIWindow::GetChildMouseHandler() { + xrCriticalSectionGuard guard(csUi); CUIWindow* pWndResult; WINDOW_LIST::reverse_iterator it = m_ChildWndList.rbegin(); @@ -594,6 +631,7 @@ void CUIWindow::Reset() void CUIWindow::ResetAll() { + xrCriticalSectionGuard guard(csUi); for (WINDOW_LIST_it it = m_ChildWndList.begin(); m_ChildWndList.end() != it; ++it) { (*it)->Reset(); @@ -607,6 +645,7 @@ CUIWindow* CUIWindow::GetMessageTarget() bool CUIWindow::IsChild(CUIWindow* pPossibleChild) const { + xrCriticalSectionGuard guard(const_cast(csUi)); WINDOW_LIST::const_iterator it = std::find(m_ChildWndList.begin(), m_ChildWndList.end(), pPossibleChild); return it != m_ChildWndList.end(); } @@ -617,6 +656,7 @@ CUIWindow* CUIWindow::FindChild(const shared_str name) if (WindowName() == name) return this; + xrCriticalSectionGuard guard(csUi); WINDOW_LIST::const_iterator it = m_ChildWndList.begin(); WINDOW_LIST::const_iterator it_e = m_ChildWndList.end(); for (; it != it_e; ++it) @@ -641,6 +681,7 @@ void CUIWindow::SetParent(CUIWindow* pNewParent) void CUIWindow::ShowChildren(bool show) { + xrCriticalSectionGuard guard(csUi); for (WINDOW_LIST_it it = m_ChildWndList.begin(); m_ChildWndList.end() != it; ++it) (*it)->Show(show); } diff --git a/src/xrGame/ui/UIWindow.h b/src/xrGame/ui/UIWindow.h index 881f3763b1..e3c0cf980c 100644 --- a/src/xrGame/ui/UIWindow.h +++ b/src/xrGame/ui/UIWindow.h @@ -5,6 +5,19 @@ class UIHint; class CScriptXmlInit; class CUIWindow; +class CUIStatic; +class CUICellItem; +class CUIListBoxItem; +class CUIListItem; +class CUIListWnd; +class ITextureOwner; +class CUILightAnimColorConroller; +class CUITreeViewItem; +class CUIScrollView; +class CUIFixedScrollBar; +class CUISelectable; +class CUIListItemServer; + struct _12b { DWORD _[3]; @@ -115,6 +128,20 @@ class CUIWindow : public CUISimpleWindow CUIWindow(); virtual ~CUIWindow(); + virtual CUIWindow* ui_cast_window() { return this; } + virtual CUIStatic* ui_cast_static() { return nullptr; } + virtual CUICellItem* ui_cast_cell_item() { return nullptr; } + virtual CUIListBoxItem* ui_cast_list_box_item() { return nullptr; } + virtual CUIListItem* ui_cast_list_item() { return nullptr; } + virtual CUIListWnd* ui_cast_list() { return nullptr; } + virtual ITextureOwner* ui_cast_texture_owner() { return nullptr; } + virtual CUILightAnimColorConroller* ui_cast_light_anim_color_controller() { return nullptr; } + virtual CUITreeViewItem* ui_cast_tree_view_item() { return nullptr; } + virtual CUIScrollView* ui_cast_scroll_view() { return nullptr; } + virtual CUIFixedScrollBar* ui_cast_fixed_scroll_bar() { return nullptr; } + virtual CUISelectable* ui_cast_selectable() { return nullptr; } + virtual CUIListItemServer* ui_cast_list_item_server() { return nullptr; } + //////////////////////////////////// //работа с дочерними и родительскими окнами @@ -122,7 +149,11 @@ class CUIWindow : public CUISimpleWindow virtual void DetachChild(CUIWindow* pChild); virtual bool IsChild(CUIWindow* pChild) const; virtual void DetachAll(); - int GetChildNum() { return m_ChildWndList.size(); } + int GetChildNum() + { + xrCriticalSectionGuard guard(csUi); + return m_ChildWndList.size(); + } void SetParent(CUIWindow* pNewParent); CUIWindow* GetParent() const { return m_pParentWnd; } @@ -293,17 +324,23 @@ class CUIWindow : public CUISimpleWindow IC bool GetCustomDraw() const { return m_bCustomDraw; } IC void SetCustomDraw(bool b) { m_bCustomDraw = b; } + xrCriticalSection csUi; + protected: IC void SafeRemoveChild(CUIWindow* child) { + xrCriticalSectionGuard guard(csUi); WINDOW_LIST_it it = std::find(m_ChildWndList.begin(), m_ChildWndList.end(), child); - if (it != m_ChildWndList.end())m_ChildWndList.erase(it); + if (it != m_ChildWndList.end()) m_ChildWndList.erase(it); }; shared_str m_windowName; //список дочерних окон WINDOW_LIST m_ChildWndList; + WINDOW_LIST m_ChildWndToDelete; + void CollectGarbage(); + //указатель на родительское окно CUIWindow* m_pParentWnd; diff --git a/src/xrGame/ui/UIWndCallback.h b/src/xrGame/ui/UIWndCallback.h index 0cc32ef9b8..13e9520fda 100644 --- a/src/xrGame/ui/UIWndCallback.h +++ b/src/xrGame/ui/UIWndCallback.h @@ -6,7 +6,7 @@ class CUIWindow; class CUIWndCallback { public: - typedef fastdelegate::FastDelegate2 void_function; + typedef xr_delegate void_function; private: typedef xr_vector CALLBACKS; typedef CALLBACKS::iterator CALLBACK_IT; @@ -21,4 +21,6 @@ class CUIWndCallback void Register(CUIWindow* pChild); void AddCallback(CUIWindow* pWnd, s16 evt, const void_function& f); void AddCallbackStr(const shared_str& control_id, s16 evt, const void_function& f); + + virtual CUIWindow* ui_cast_window() { return nullptr; } }; diff --git a/src/xrGame/ui/UIWpnParams.h b/src/xrGame/ui/UIWpnParams.h index d8c4ebcb92..ff1b2c58b9 100644 --- a/src/xrGame/ui/UIWpnParams.h +++ b/src/xrGame/ui/UIWpnParams.h @@ -20,6 +20,8 @@ class CUIWpnParams : public CUIWindow void SetInfo(CInventoryItem* slot_wpn, CInventoryItem& cur_wpn); bool Check(const shared_str& wpn_section); + virtual CUIWindow* ui_cast_window() { return this; } + protected: CUIDoubleProgressBar m_progressAccuracy; // red or green CUIDoubleProgressBar m_progressHandling; @@ -60,6 +62,8 @@ class CUIConditionParams : public CUIWindow void InitFromXml(CUIXml& xml_doc); void SetInfo(CInventoryItem const* slot_wpn, CInventoryItem const& cur_wpn); + virtual CUIWindow* ui_cast_window() { return this; } + protected: CUIDoubleProgressBar m_progress; // red or green CUIStatic m_text; diff --git a/src/xrGame/ui/UIXmlInit.cpp b/src/xrGame/ui/UIXmlInit.cpp index 4261799b6b..70d13e9a4b 100644 --- a/src/xrGame/ui/UIXmlInit.cpp +++ b/src/xrGame/ui/UIXmlInit.cpp @@ -96,7 +96,6 @@ bool CUIXmlInit::InitWindow(CUIXml& xml_doc, LPCSTR path, pWnd->SetWindowName(xml_doc.Read(buf, index, NULL)); InitAutoStaticGroup(xml_doc, path, index, pWnd); - //. InitAutoFrameLineGroup (xml_doc, path, index, pWnd); return true; } @@ -230,7 +229,7 @@ bool CUIXmlInit::InitTextWnd(CUIXml& xml_doc, LPCSTR path, int index, CUITextWnd strconcat(sizeof(buf), buf, path, ":texture"); R_ASSERT3(NULL==xml_doc.NavigateToNode(buf,index), xml_doc.m_xml_file_name, buf); - R_ASSERT(pWnd->GetChildWndList().size()==0); + R_ASSERT(pWnd->GetChildNum() == 0); return true; } @@ -363,7 +362,7 @@ bool CUIXmlInit::Init3tButton(CUIXml& xml_doc, LPCSTR path, int index, CUI3tButt { R_ASSERT4(xml_doc.NavigateToNode(path,index), "XML node not found", path, xml_doc.m_xml_file_name); - pWnd->m_frameline_mode = (xml_doc.ReadAttribInt(path, index, "frame_mode", 0) == 1) ? true : false; + pWnd->m_frameline_mode = (CUI3tButton::EFrameMode)xml_doc.ReadAttribInt(path, index, "frame_mode", 0); pWnd->vertical = (xml_doc.ReadAttribInt(path, index, "vertical", 0) == 1) ? true : false; @@ -667,6 +666,7 @@ void CUIXmlInit::InitAutoStaticGroup(CUIXml& xml_doc, LPCSTR path, int index, CU XML_NODE* node = curr_root->IterateChildren(NULL); int cnt_static = 0; int cnt_frameline = 0; + int cnt_framewindow = 0; int cnt_text = 0; string512 buff; @@ -695,6 +695,17 @@ void CUIXmlInit::InitAutoStaticGroup(CUIXml& xml_doc, LPCSTR path, int index, CU ++cnt_frameline; } + else if (0 == _stricmp(node_name, "auto_framewindow")) + { + CUIFrameWindow* pUIFramewindow = xr_new(); + InitFrameWindow(xml_doc, "auto_framewindow", cnt_framewindow, pUIFramewindow); + xr_sprintf(buff, "auto_framewindow_%d", cnt_framewindow); + pUIFramewindow->SetWindowName(buff); + pUIFramewindow->SetAutoDelete(true); + pParentWnd->AttachChild(pUIFramewindow); + + ++cnt_framewindow; + } else if (0 == stricmp(node_name, "auto_text")) { ++cnt_text; @@ -1089,6 +1100,10 @@ bool CUIXmlInit::InitMultiTexture(CUIXml& xml_doc, LPCSTR path, int index, CUI3t { pWnd->m_back_frameline->InitState(S_Enabled, texture.c_str(), pWnd->vertical); } + else if (pWnd->m_back_framewindow) + { + pWnd->m_back_framewindow->InitState(S_Enabled, texture.c_str()); + } success = true; } @@ -1104,6 +1119,10 @@ bool CUIXmlInit::InitMultiTexture(CUIXml& xml_doc, LPCSTR path, int index, CUI3t { pWnd->m_back_frameline->InitState(S_Touched, texture.c_str(), pWnd->vertical); } + else if (pWnd->m_back_framewindow) + { + pWnd->m_back_framewindow->InitState(S_Touched, texture.c_str()); + } success = true; } @@ -1119,6 +1138,10 @@ bool CUIXmlInit::InitMultiTexture(CUIXml& xml_doc, LPCSTR path, int index, CUI3t { pWnd->m_back_frameline->InitState(S_Disabled, texture.c_str(), pWnd->vertical); } + else if (pWnd->m_back_framewindow) + { + pWnd->m_back_framewindow->InitState(S_Disabled, texture.c_str()); + } success = true; } @@ -1134,6 +1157,10 @@ bool CUIXmlInit::InitMultiTexture(CUIXml& xml_doc, LPCSTR path, int index, CUI3t { pWnd->m_back_frameline->InitState(S_Highlighted, texture.c_str(), pWnd->vertical); } + else if (pWnd->m_back_framewindow) + { + pWnd->m_back_framewindow->InitState(S_Highlighted, texture.c_str()); + } success = true; } diff --git a/src/xrGame/ui/UI_IB_Static.h b/src/xrGame/ui/UI_IB_Static.h index 13a9d75575..794c3e6499 100644 --- a/src/xrGame/ui/UI_IB_Static.h +++ b/src/xrGame/ui/UI_IB_Static.h @@ -17,4 +17,5 @@ class CUI_IB_Static : public CUIInteractiveBackground public: virtual void SetTextureOffset(float x, float y); void SetStretchTexture(bool stretch_texture); + virtual CUIWindow* ui_cast_window() { return this; } }; diff --git a/src/xrGame/ui/ui_af_params.h b/src/xrGame/ui/ui_af_params.h index 42342b28ee..a9af1ef99e 100644 --- a/src/xrGame/ui/ui_af_params.h +++ b/src/xrGame/ui/ui_af_params.h @@ -17,6 +17,8 @@ class CUIArtefactParams : public CUIWindow bool Check(const shared_str& af_section); void SetInfo(CInventoryItem& pInvItem); + virtual CUIWindow* ui_cast_window() { return this; } + protected: UIArtefactParamItem* m_immunity_item[9]; UIArtefactParamItem* m_restore_item[ALife::eRestoreTypeMax]; @@ -38,6 +40,8 @@ class UIArtefactParamItem : public CUIWindow void SetCaption(LPCSTR name); void SetValue(float value); + virtual CUIWindow* ui_cast_window() { return this; } + private: CUIStatic* m_caption; CUITextWnd* m_value; diff --git a/src/xrGame/ui/uiabstract.h b/src/xrGame/ui/uiabstract.h index f6d9689ac1..b7815f94ce 100644 --- a/src/xrGame/ui/uiabstract.h +++ b/src/xrGame/ui/uiabstract.h @@ -130,4 +130,6 @@ class CUISelectable bool GetSelected() const { return m_bSelected; } virtual void SetSelected(bool b) { m_bSelected = b; }; + + virtual CUISelectable* ui_cast_selectable() { return this; } }; diff --git a/src/xrGame/ui_defs.h b/src/xrGame/ui_defs.h index 21b31cbe17..230820cf02 100644 --- a/src/xrGame/ui_defs.h +++ b/src/xrGame/ui_defs.h @@ -3,6 +3,9 @@ #include "../Include/xrRender/FactoryPtr.h" #include "../Include/xrRender/UIRender.h" #include "../Include/xrRender/UIShader.h" + +#include "../xrCore/_thread_types.h" + typedef FactoryPtr ui_shader; #define UI_BASE_WIDTH 1024.0f @@ -85,4 +88,4 @@ class C2DFrustum u32 ClipBudget(u32 src_verts) const { return 3 * (src_verts + (u32)planes.size() - 2); } }; -extern ENGINE_API BOOL g_bRendering; +extern ENGINE_API xr_atomic_bool g_bRendering; diff --git a/src/xrGame/ui_export_script.cpp b/src/xrGame/ui_export_script.cpp index 2c3bb25382..c79ea8ea23 100644 --- a/src/xrGame/ui_export_script.cpp +++ b/src/xrGame/ui_export_script.cpp @@ -14,6 +14,7 @@ #include "UI/UIComboBox.h" #include "ui/UIOptionsManagerScript.h" #include "ui/UIMapInfo.h" +#include "map_manager.h" #include "ScriptXmlInit.h" #include "ui/UIActorMenu.h" diff --git a/src/xrGame/vision_client.cpp b/src/xrGame/vision_client.cpp index a8ab93eae9..428c2a0be3 100644 --- a/src/xrGame/vision_client.cpp +++ b/src/xrGame/vision_client.cpp @@ -52,7 +52,7 @@ void vision_client::eye_pp_s01() mProject.build_projection(field_of_view, aspect_ratio, near_plane, far_plane); mFull.mul(mProject, mView); - feel_vision_query(mFull, c); + feel_vision_query(mFull); Device.Statistic->AI_Vis_Query.End(); } @@ -64,7 +64,13 @@ void vision_client::eye_pp_s2() u32 dwTime = Device.dwTimeGlobal; u32 dwDT = dwTime - m_time_stamp; m_time_stamp = dwTime; - feel_vision_update(m_object, m_position, float(dwDT) / 1000.f, visual().transparency_threshold()); + static DWORD this_thread_id = 0; + this_thread_id = GetCurrentThreadId(); + Device.secondary_tasks.run([=]() + { + if (this_thread_id != GetCurrentThreadId()) { PROF_THREAD("X-Ray PPL Thread") } + feel_vision_update(m_position, float(dwDT) / 1000.f, visual().transparency_threshold()); + }); Device.Statistic->AI_Vis_RayTests.End(); } @@ -76,6 +82,7 @@ float vision_client::shedule_Scale() void vision_client::shedule_Update(u32 dt) { + PROF_EVENT("vision_client::shedule_Update"); inherited::shedule_Update(dt); if (!object().g_Alive()) diff --git a/src/xrGame/visual_memory_manager.cpp b/src/xrGame/visual_memory_manager.cpp index 5a58d311ef..c548a0d09e 100644 --- a/src/xrGame/visual_memory_manager.cpp +++ b/src/xrGame/visual_memory_manager.cpp @@ -331,7 +331,7 @@ float CVisualMemoryManager::get_object_velocity(const CGameObject* game_object, const CNotYetVisibleObject& not_yet_visible_object) const { //Alundaio: no need to check velocity on anything but stalkers, mutants and actor - if (!smart_cast(game_object)) + if (!const_cast(game_object)->cast_entity_alive()) return (0.f); //-Alundaio @@ -394,7 +394,13 @@ CNotYetVisibleObject* CVisualMemoryManager::not_yet_visible_object(const CGameOb void CVisualMemoryManager::add_not_yet_visible_object(const CNotYetVisibleObject& not_yet_visible_object) { - m_not_yet_visible_objects.push_back(not_yet_visible_object); + xr_vector::iterator I = std::find_if( + m_not_yet_visible_objects.begin(), + m_not_yet_visible_objects.end(), + CNotYetVisibleObjectPredicate(not_yet_visible_object.m_object) + ); + if (I == m_not_yet_visible_objects.end()) + m_not_yet_visible_objects.push_back(not_yet_visible_object); } u32 CVisualMemoryManager::get_prev_time(const CGameObject* game_object) const @@ -658,8 +664,8 @@ struct CVisibleObjectPredicateEx void CVisualMemoryManager::remove_links(CObject* object) { + if (m_objects) { - VERIFY(m_objects); VISIBLES::iterator I = std::find_if(m_objects->begin(), m_objects->end(), CVisibleObjectPredicateEx(object)); if (I != m_objects->end()) m_objects->erase(I); @@ -674,6 +680,9 @@ void CVisualMemoryManager::remove_links(CObject* object) CVisibleObject* CVisualMemoryManager::visible_object(const CGameObject* game_object) { + if (!m_objects) + return nullptr; + VISIBLES::iterator I = std::find_if(m_objects->begin(), m_objects->end(), CVisibleObjectPredicateEx(game_object)); if (I == m_objects->end()) return (0); @@ -698,8 +707,10 @@ void CVisualMemoryManager::update(float time_delta) m_last_update_time = Device.dwTimeGlobal; + if (!m_objects) + return; + squad_mask_type mask = this->mask(); - VERIFY(m_objects); m_visible_objects.clear(); START_PROFILE("Memory Manager/visuals/update/feel_vision_get") diff --git a/src/xrGame/visual_memory_manager.h b/src/xrGame/visual_memory_manager.h index f62a963a60..aa321e18fb 100644 --- a/src/xrGame/visual_memory_manager.h +++ b/src/xrGame/visual_memory_manager.h @@ -80,7 +80,6 @@ class CVisualMemoryManager public: u32 visible_object_time_last_seen(const CObject* object) const; -protected: void add_not_yet_visible_object(const CNotYetVisibleObject& not_yet_visible_object); CNotYetVisibleObject* not_yet_visible_object(const CGameObject* game_object); @@ -136,6 +135,7 @@ class CVisualMemoryManager public: IC const VISIBLES& objects() const; + IC const VISIBLES* objectsPtr() const; IC const RAW_VISIBLES& raw_objects() const; IC const NOT_YET_VISIBLES& not_yet_visible_objects() const; IC const CVisionParameters& current_state() const; diff --git a/src/xrGame/visual_memory_manager_inline.h b/src/xrGame/visual_memory_manager_inline.h index 15b6b5457a..fa252e331a 100644 --- a/src/xrGame/visual_memory_manager_inline.h +++ b/src/xrGame/visual_memory_manager_inline.h @@ -13,6 +13,11 @@ IC const CVisualMemoryManager::VISIBLES& CVisualMemoryManager::objects() const return (*m_objects); } +IC const CVisualMemoryManager::VISIBLES* CVisualMemoryManager::objectsPtr() const +{ + return m_objects; +} + IC const CVisualMemoryManager::RAW_VISIBLES& CVisualMemoryManager::raw_objects() const { return (m_visible_objects); diff --git a/src/xrGame/wallmark_manager.cpp b/src/xrGame/wallmark_manager.cpp index b9d0424868..801961683f 100644 --- a/src/xrGame/wallmark_manager.cpp +++ b/src/xrGame/wallmark_manager.cpp @@ -89,7 +89,7 @@ void CWalmarkManager::PlaceWallmarks(const Fvector& start_pos) //. LPCSTR sect = pSettings->r_string(m_owner->cNameSect(), "wallmark_section"); Load("explosion_marks"); - //. Device.seqParallel.push_back (fastdelegate::FastDelegate0<>(this,&CWalmarkManager::StartWorkflow)); + //. Device.seqParallel.push_back (xr_make_delegate(this,&CWalmarkManager::StartWorkflow)); StartWorkflow(); } diff --git a/src/xrGame/weaponBM16.h b/src/xrGame/weaponBM16.h index 0b3e6ad1f2..3f9fda94c1 100644 --- a/src/xrGame/weaponBM16.h +++ b/src/xrGame/weaponBM16.h @@ -21,5 +21,8 @@ class CWeaponBM16 : public CWeaponShotgun virtual void PlayAnimShow(); virtual void PlayAnimHide(); virtual bool TryPlayAnimBore(); + + virtual CWeaponBM16* cast_weapon_bm16() { return this; } + DECLARE_SCRIPT_REGISTER_FUNCTION }; diff --git a/src/xrGame/xrGame.vcxproj b/src/xrGame/xrGame.vcxproj index ccbcc14b2c..d4e7586e4f 100644 --- a/src/xrGame/xrGame.vcxproj +++ b/src/xrGame/xrGame.vcxproj @@ -13,6 +13,10 @@ Release x64 + + VerifiedDX11ASAN + x64 + VerifiedDX11 x64 @@ -58,6 +62,15 @@ false x64 + + StaticLibrary + v143 + false + MultiByte + false + x64 + true + StaticLibrary v143 @@ -88,6 +101,11 @@ + + + + + @@ -117,6 +135,11 @@ $(xrGameDir)bin_dbg\$(Platform)\$(Configuration)\ $(xrIntDir)$(ProjectName)\ + + false + $(xrGameDir)bin_dbg\$(Platform)\$(Configuration)\ + $(xrIntDir)$(ProjectName)\ + false $(xrGameDir)bin_dbg\$(Platform)\$(Configuration)\ @@ -233,7 +256,7 @@ false false .\;$(SolutionDir);$(SolutionDir)xrCore;$(SolutionDir)xrServerEntities;$(SolutionDir)3rd party\luajit-2\src\;$(SolutionDir)3rd party\luabind\;$(xrSdkDir)include;$(XRAY_16X_LIBS)OpenAutomate\inc;$(SolutionDir)3rd party\CxImage;%(AdditionalIncludeDirectories) - USE_VERIFY_IN_RELEASE;WIN32;NDEBUG;_WINDOWS;_USRDLL;XRGAME_EXPORTS;dSINGLE;MSVC;_SECURE_SCL=0;%(PreprocessorDefinitions) + XRCORE_PROFILER;USE_VERIFY_IN_RELEASE;WIN32;NDEBUG;_WINDOWS;_USRDLL;XRGAME_EXPORTS;dSINGLE;MSVC;_SECURE_SCL=0;%(PreprocessorDefinitions) NotSet Use stdafx.h @@ -282,7 +305,7 @@ false false .\;$(SolutionDir);$(SolutionDir)xrCore;$(SolutionDir)xrServerEntities;$(SolutionDir)3rd party\luajit-2\src\;$(SolutionDir)3rd party\luabind\;$(xrSdkDir)include;$(XRAY_16X_LIBS)OpenAutomate\inc;$(SolutionDir)3rd party\CxImage;%(AdditionalIncludeDirectories) - USE_VERIFY_IN_RELEASE;WIN32;NDEBUG;_WINDOWS;_USRDLL;XRGAME_EXPORTS;dSINGLE;MSVC;_SECURE_SCL=0;%(PreprocessorDefinitions) + XRCORE_PROFILER;USE_VERIFY_IN_RELEASE;WIN32;NDEBUG;_WINDOWS;_USRDLL;XRGAME_EXPORTS;dSINGLE;MSVC;_SECURE_SCL=0;%(PreprocessorDefinitions) NotSet Use stdafx.h @@ -315,6 +338,55 @@ true + + + NDEBUG;%(PreprocessorDefinitions) + true + true + $(OutDir)$(TargetName).tlb + + + Disabled + Disabled + false + Neither + false + false + false + .\;$(SolutionDir);$(SolutionDir)xrCore;$(SolutionDir)xrServerEntities;$(SolutionDir)3rd party\luajit-2\src\;$(SolutionDir)3rd party\luabind\;$(xrSdkDir)include;$(XRAY_16X_LIBS)OpenAutomate\inc;$(SolutionDir)3rd party\CxImage;%(AdditionalIncludeDirectories) + XRCORE_PROFILER;USE_VERIFY_IN_RELEASE;_DISABLE_VECTOR_ANNOTATION;_DISABLE_STRING_ANNOTATION;WIN32;NDEBUG;_WINDOWS;_USRDLL;XRGAME_EXPORTS;dSINGLE;MSVC;_SECURE_SCL=0;%(PreprocessorDefinitions) + NotSet + Use + stdafx.h + ProgramDatabase + 4995;4005;4237;%(DisableSpecificWarnings) + USE_LUAJIT_ONE + true + Level4 + false + MultiThreadedDLL + false + stdcpp17 + true + + + NDEBUG;%(PreprocessorDefinitions) + 0x0419 + + + /ignore:4099 + true + $(SolutionDir)3rd party\luajit-2\src\;$(xrSdkDir)libraries;$(xrLibDir);$(XRAY_16X_LIBS)OpenAutomate\libraries;$(XRAY_16X_LIBS)jpeg\libraries\Release;$(xrGameDir)bin_dbg;%(AdditionalLibraryDirectories) + NotSet + true + true + true + Default + false + $(xrLibDir)$(TargetName).lib + true + + NDEBUG;%(PreprocessorDefinitions) @@ -1107,6 +1179,7 @@ true true true + true true @@ -2983,6 +3056,10 @@ + + pch_script.h + $(IntDir)$(ProjectName)_script.pch + pch_script.h @@ -3315,6 +3392,7 @@ true true true + true true @@ -3943,6 +4021,7 @@ true true true + true true @@ -4252,11 +4331,13 @@ pch_script.h + pch_script.h pch_script.h pch_script.h pch_script.h pch_script.h $(IntDir)$(ProjectName)_script.pch + $(IntDir)$(ProjectName)_script.pch $(IntDir)$(ProjectName)_script.pch $(IntDir)$(ProjectName)_script.pch $(IntDir)$(ProjectName)_script.pch @@ -4387,4 +4468,4 @@ - + \ No newline at end of file diff --git a/src/xrGame/xrGame.vcxproj.filters b/src/xrGame/xrGame.vcxproj.filters index 4334b441a2..8898af6a0b 100644 --- a/src/xrGame/xrGame.vcxproj.filters +++ b/src/xrGame/xrGame.vcxproj.filters @@ -5163,18 +5163,6 @@ AI\AScript\ScriptClasses\ScriptCallbackEx - - AI\AScript\ScriptClasses\ScriptCallbackEx - - - AI\AScript\ScriptClasses\ScriptCallbackEx - - - AI\AScript\ScriptClasses\ScriptCallbackEx - - - AI\AScript\ScriptClasses\ScriptCallbackEx - AI\AScript\ScriptClasses\ScriptLAnim @@ -9602,12 +9590,6 @@ Core\Client\Objects\searchlight - - Core\Client\Objects\searchlight_script - - - Core\Client\Objects\searchlight_struct - Core\Client\Objects\searchlight\Trade @@ -11111,6 +11093,11 @@ UI\Common\ImGui + + Core\Client\Objects\tasks_info_dialogs\map + + + Core\Client\Objects\items & weapons\HudItem diff --git a/src/xrGame/xrServer.cpp b/src/xrGame/xrServer.cpp index 0d059ccf00..813c201805 100644 --- a/src/xrGame/xrServer.cpp +++ b/src/xrGame/xrServer.cpp @@ -353,7 +353,7 @@ void xrServer::SendUpdatesToAll() //sending game_update - fastdelegate::FastDelegate1 sendtofd; + xr_delegate sendtofd; sendtofd.bind(this, &xrServer::SendGameUpdateTo); ForEachClientDoSender(sendtofd); @@ -415,14 +415,14 @@ u32 xrServer::OnDelayedMessage(NET_Packet& P, ClientID sender) // Non-Zero means string1024 buff; P.r_stringZ(buff); Msg("* Radmin [%s] is running command: %s", CL->ps->getName(), buff); - SetLogCB(console_log_cb); + xrLogger::AddLogCallback(console_log_cb); _tmp_log.clear(); LPSTR result_command; string64 tmp_number_str; xr_sprintf(tmp_number_str, " raid:%u", CL->ID.value()); STRCONCAT(result_command, buff, tmp_number_str); Console->Execute(result_command); - SetLogCB(NULL); + xrLogger::RemoveLogCallback(console_log_cb); NET_Packet P_answ; for (u32 i = 0; i < _tmp_log.size(); ++i) @@ -983,9 +983,8 @@ static BOOL _ve_use = TRUE; bool xrServer::verify_entities () const { - if (!_ve_initialized) { - _ve_initialized = TRUE; - if (strstr(Core.Params,"-~ve")) _ve_use=FALSE; + if (!_ve_initialized) { + _ve_initialized = TRUE; } if (!_ve_use) return true; diff --git a/src/xrGame/xrServer_Connect.cpp b/src/xrGame/xrServer_Connect.cpp index fddf215d9d..d7d4edf5f2 100644 --- a/src/xrGame/xrServer_Connect.cpp +++ b/src/xrGame/xrServer_Connect.cpp @@ -42,7 +42,7 @@ xrServer::EConnect xrServer::Connect(shared_str& session_name, GameDescriptionDa #ifdef DEBUG Msg ("* sv_Connect: %s", *session_name); #endif - + PROF_EVENT("xrServer::Connect"); // Parse options and create game if (0 == strchr(*session_name, '/')) return ErrConnect; diff --git a/src/xrGame/xrServer_info.h b/src/xrGame/xrServer_info.h index ed9b65fda6..8c6a5fcd25 100644 --- a/src/xrGame/xrServer_info.h +++ b/src/xrGame/xrServer_info.h @@ -2,10 +2,10 @@ #define SERVER_INFO_UPLOADER -#include +#include "../xrCore/xr_delegate.h" #include "file_transfer.h" -typedef fastdelegate::FastDelegate svinfo_upload_complete_cb; +typedef xr_delegate svinfo_upload_complete_cb; class server_info_uploader : xray::noncopyable { diff --git a/src/xrGame/xrServer_perform_sls_default.cpp b/src/xrGame/xrServer_perform_sls_default.cpp index 96ae48d1b8..428056beee 100644 --- a/src/xrGame/xrServer_perform_sls_default.cpp +++ b/src/xrGame/xrServer_perform_sls_default.cpp @@ -19,7 +19,7 @@ void xrServer::SLS_Default() } #ifdef USE_DESIGNER_KEY - bool _designer = !!strstr(Core.Params, "-designer"); + bool _designer = Core.ParamsData.test(ECoreParams::designer); CSE_ALifeCreatureActor* _actor = 0; #endif diff --git a/src/xrGame/xr_dsa_signer.h b/src/xrGame/xr_dsa_signer.h index 665420439d..76f8037471 100644 --- a/src/xrGame/xr_dsa_signer.h +++ b/src/xrGame/xr_dsa_signer.h @@ -3,7 +3,7 @@ #include "../3rd party/crypto/crypto.h" -typedef fastdelegate::FastDelegate1 sha_process_yielder; +typedef xr_delegate sha_process_yielder; class xr_dsa_signer { diff --git a/src/xrGame/xr_level_controller.cpp b/src/xrGame/xr_level_controller.cpp index 48690514aa..a70534543c 100644 --- a/src/xrGame/xr_level_controller.cpp +++ b/src/xrGame/xr_level_controller.cpp @@ -370,7 +370,7 @@ _action* action_name_to_ptr(LPCSTR _name) return &actions[idx]; ++idx; } - Msg("! cant find corresponding [id] for action_name", _name); + Msg ("! cant find corresponding [id] for action_name %s", _name); return NULL; } diff --git a/src/xrNetServer/NET_Client.cpp b/src/xrNetServer/NET_Client.cpp index 79bc030516..538c474510 100644 --- a/src/xrNetServer/NET_Client.cpp +++ b/src/xrNetServer/NET_Client.cpp @@ -473,7 +473,7 @@ BOOL IPureClient::Connect(LPCSTR options) R_CHK(NET->Initialize (this, Handler, DPNINITIALIZE_DISABLEPARAMVAL )); #endif BOOL bSimulator = FALSE; - if (strstr(Core.Params, "-netsim")) bSimulator = TRUE; + if (Core.ParamsData.test(ECoreParams::netsim)) bSimulator = TRUE; // Create our IDirectPlay8Address Device Address, --- Set the SP for our Device Address net_Address_device = NULL; diff --git a/src/xrNetServer/NET_Common.cpp b/src/xrNetServer/NET_Common.cpp index 72fe30cc8e..c6617e03c7 100644 --- a/src/xrNetServer/NET_Common.cpp +++ b/src/xrNetServer/NET_Common.cpp @@ -164,7 +164,7 @@ MultipacketSender::_FlushSendBuffer(u32 timeout, Buffer* buf) ); #endif // NET_LOG_PACKETS - if (strstr(Core.Params, "-dump_traffic")) + if (Core.ParamsData.test(ECoreParams::dump_traffic)) { static bool first_time = true; FILE* dump = fopen("raw-out-traffic.bins", (first_time) ? "wb" : "ab"); @@ -210,7 +210,7 @@ MultipacketReciever::RecievePacket(const void* packet_data, u32 packet_sz, u32 p Msg( "#receive multi-packet %u", packet_sz ); #endif - if (strstr(Core.Params, "-dump_traffic")) + if (Core.ParamsData.test(ECoreParams::dump_traffic)) { static bool first_time = true; FILE* dump = fopen("raw-in-traffic.bins", (first_time) ? "wb" : "ab"); diff --git a/src/xrNetServer/NET_Compressor.cpp b/src/xrNetServer/NET_Compressor.cpp index 6768735e93..f14eef6893 100644 --- a/src/xrNetServer/NET_Compressor.cpp +++ b/src/xrNetServer/NET_Compressor.cpp @@ -267,12 +267,6 @@ NET_Compressor::NET_Compressor() NET_Compressor::~NET_Compressor() { -#if 1//def DEBUG - // if( strstr(Core.Params,"-dump_traffic") ) - // { - // fclose( OriginalTrafficDump ); - // fclose( CompressedTrafficDump ); - // } if (CompressionDump) { fclose(CompressionDump); @@ -283,25 +277,8 @@ NET_Compressor::~NET_Compressor() fclose(RawTrafficDump); RawTrafficDump = NULL; } -#endif // DEBUG } -/* -void NET_Compressor::Initialize () -{ - CS.Enter (); - -#if 1//def DEBUG - if( strstr(Core.Params,"-dump_traffic") ) - { - OriginalTrafficDump = fopen( "x:/network_out_original.dat", "wb" ); - CompressedTrafficDump = fopen( "x:/network_out_compressed.dat", "wb" ); - } -#endif // DEBUG - - CS.Leave (); -}*/ - u16 NET_Compressor::compressed_size(const u32& count) { #if NET_USE_COMPRESSION @@ -341,14 +318,6 @@ u16 NET_Compressor::Compress(BYTE* dest, const u32& dest_size, BYTE* src, const VERIFY(src); VERIFY(count); -#if 1//def DEBUG - if (strstr(Core.Params, "-dump_traffic")) - { - // fwrite( src,count,1,OriginalTrafficDump ); - // fflush( OriginalTrafficDump ); - } -#endif // DEBUG - #if !NET_USE_COMPRESSION CopyMemory(dest,src,count); @@ -422,28 +391,6 @@ u16 NET_Compressor::Compress(BYTE* dest, const u32& dest_size, BYTE* src, const if (g_net_compressor_gather_stats && b_compress_packet) _p->compressed_size += compressed_size; -#if 1//def DEBUG - // if( strstr(Core.Params,"-dump_traffic")) - // { - // fwrite(dest,compressed_size,1,CompressedTrafficDump); - // fflush(CompressedTrafficDump); - // } -#endif // DEBUG - -#ifdef DEBUG - /* - BYTE *src_back = (BYTE*)_alloca(count); - Decompress (src_back,count,dest,compressed_size); - BYTE *I = src_back; - BYTE *E = src_back + count; - BYTE *J = src; - for ( ; I != E; ++I, ++J) - VERIFY (*I == *J); - - */ - // CS.Leave (); -#endif // DEBUG - return (u16(compressed_size)); #endif // if !NET_USE_COMPRESSION diff --git a/src/xrNetServer/NET_PlayersMonitor.h b/src/xrNetServer/NET_PlayersMonitor.h index b4eb205ad2..941860beae 100644 --- a/src/xrNetServer/NET_PlayersMonitor.h +++ b/src/xrNetServer/NET_PlayersMonitor.h @@ -3,7 +3,7 @@ #include "net_shared.h" #include "NET_Common.h" -#include +#include "../xrCore/xr_delegate.h" class IClient; @@ -63,7 +63,7 @@ class PlayersMonitor csPlayers.Leave(); } - void ForEachClientDo(fastdelegate::FastDelegate1& fast_delegate) + void ForEachClientDo(xr_delegate& fast_delegate) { //Msg("-S- Entering to csPlayers [%d]", GetCurrentThreadId()); csPlayers.Enter(); diff --git a/src/xrNetServer/NET_Server.cpp b/src/xrNetServer/NET_Server.cpp index 74472dbf3b..dde8d6469b 100644 --- a/src/xrNetServer/NET_Server.cpp +++ b/src/xrNetServer/NET_Server.cpp @@ -333,7 +333,7 @@ IPureServer::EConnect IPureServer::Connect(LPCSTR options, GameDescriptionData& #endif BOOL bSimulator = FALSE; - if (strstr(Core.Params, "-netsim")) bSimulator = TRUE; + if (Core.ParamsData.test(ECoreParams::netsim)) bSimulator = TRUE; // dump_URL ("! sv ", net_Address_device); diff --git a/src/xrNetServer/xrNetServer.vcxproj b/src/xrNetServer/xrNetServer.vcxproj index 20c0e9cbf9..8c56e7d220 100644 --- a/src/xrNetServer/xrNetServer.vcxproj +++ b/src/xrNetServer/xrNetServer.vcxproj @@ -13,6 +13,10 @@ Release x64 + + VerifiedDX11ASAN + x64 + VerifiedDX11 x64 @@ -57,6 +61,15 @@ false x64 + + StaticLibrary + v143 + false + MultiByte + false + x64 + true + StaticLibrary v143 @@ -87,6 +100,11 @@ + + + + + @@ -116,6 +134,11 @@ $(xrGameDir)bin_dbg\$(Platform)\$(Configuration)\ $(xrIntDir)$(ProjectName)\ + + false + $(xrGameDir)bin_dbg\$(Platform)\$(Configuration)\ + $(xrIntDir)$(ProjectName)\ + false $(xrGameDir)bin_dbg\$(Platform)\$(Configuration)\ @@ -225,7 +248,7 @@ false false .;$(SolutionDir)xrCore;$(xrSdkDir)include;%(AdditionalIncludeDirectories) - USE_VERIFY_IN_RELEASE;NDEBUG;WIN32;_WINDOWS;XR_NETSERVER_EXPORTS;_SECURE_SCL=0;%(PreprocessorDefinitions) + XRCORE_PROFILER;USE_VERIFY_IN_RELEASE;NDEBUG;WIN32;_WINDOWS;XR_NETSERVER_EXPORTS;_SECURE_SCL=0;%(PreprocessorDefinitions) NotSet Use EditAndContinue @@ -273,7 +296,7 @@ false false .;$(SolutionDir)xrCore;$(xrSdkDir)include;%(AdditionalIncludeDirectories) - USE_VERIFY_IN_RELEASE;NDEBUG;WIN32;_WINDOWS;XR_NETSERVER_EXPORTS;_SECURE_SCL=0;%(PreprocessorDefinitions) + XRCORE_PROFILER;USE_VERIFY_IN_RELEASE;NDEBUG;WIN32;_WINDOWS;XR_NETSERVER_EXPORTS;_SECURE_SCL=0;%(PreprocessorDefinitions) NotSet Use EditAndContinue @@ -305,6 +328,54 @@ true + + + NDEBUG;%(PreprocessorDefinitions) + true + true + $(OutDir)$(TargetName).tlb + + + Disabled + Disabled + false + Neither + false + false + false + .;$(SolutionDir)xrCore;$(xrSdkDir)include;%(AdditionalIncludeDirectories) + XRCORE_PROFILER;USE_VERIFY_IN_RELEASE;_DISABLE_VECTOR_ANNOTATION;_DISABLE_STRING_ANNOTATION;NDEBUG;WIN32;_WINDOWS;XR_NETSERVER_EXPORTS;_SECURE_SCL=0;%(PreprocessorDefinitions) + NotSet + Use + ProgramDatabase + USE_LUAJIT_ONE + true + Level4 + false + MultiThreadedDLL + false + stdcpp17 + true + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + + + Ws2_32.lib;dxerr.lib;%(AdditionalDependencies) + /MACHINE:X64 %(AdditionalOptions) + true + $(xrSdkDir)libraries;$(xrLibDir);$(xrGameDir)bin_dbg;%(AdditionalLibraryDirectories) + NotSet + true + true + true + Default + false + $(xrLibDir)$(TargetName).lib + true + + NDEBUG;%(PreprocessorDefinitions) @@ -363,6 +434,7 @@ Create Create Create + Create Create diff --git a/src/xrParticles/ParticlesAsyncManager.cpp b/src/xrParticles/ParticlesAsyncManager.cpp new file mode 100644 index 0000000000..17d5578d56 --- /dev/null +++ b/src/xrParticles/ParticlesAsyncManager.cpp @@ -0,0 +1,94 @@ +#include "stdafx.h" +#include "ParticlesAsyncManager.h" + +#include "../Include/xrRender/ParticleCustom.h" +#include "../Include/xrRender/RenderVisual.h" +#include "../xrEngine/IGame_Persistent.h" + +static CParticlesAsync Instance; + +void CParticlesAsync::Play() +{ + if (DevicePtr && !Device.ParticleWorkerCallback) + Device.ParticleWorkerCallback.bind(&CParticlesAsync::Start); + + if (!psDeviceFlags.test(mtParticles)) + { + Instance.Start(); + } +} + +void CParticlesAsync::Start() +{ + Instance.IsStarted = true; + + { + PROF_EVENT("Particle Update"); + for (intrusive_ptr& particle: g_pGamePersistent->ps_active) + { + if (particle->m_bDead) + continue; + + Instance.UpdateParticle(particle); + } + } + + PROF_EVENT("Particle Shedule"); + for (intrusive_ptr& particle : g_pGamePersistent->ps_active) + { + particle->Update(Device.dwTimeDelta); + } + + Instance.IsStarted = false; +} + +void CParticlesAsync::Wait() +{ + if (psDeviceFlags.test(mtParticles)) + { + PROF_EVENT("Particles Wait"); + xrSpinWait w; + while (Instance.IsStarted) + { + w(); + } + } +} + +void CParticlesAsync::ForceUpdate(intrusive_ptr Obj) +{ + if (!Instance.IsStarted) + return; + + Instance.UpdateParticle(Obj); +} + +bool CParticlesAsync::NeedForceUpdate() +{ + return Instance.IsStarted; +} + +CParticlesAsync::CParticlesAsync() +{ + if (!DevicePtr) + return; + + if (g_dedicated_server) + return; + + Device.ParticleWorkerCallback.bind(&CParticlesAsync::Start); +} + +void CParticlesAsync::UpdateParticle(intrusive_ptr particle) const +{ + u32 dt = Device.dwTimeGlobal - particle->dwLastTime; + IParticleCustom* V = smart_cast(particle->renderable.visual); + + if (V == nullptr) + return; + + PROF_EVENT("Particle OnFrame"); + V->OnFrame(dt); + + particle->dwLastTime = Device.dwTimeGlobal; +} diff --git a/src/xrParticles/ParticlesAsyncManager.h b/src/xrParticles/ParticlesAsyncManager.h new file mode 100644 index 0000000000..ab2c43d5f3 --- /dev/null +++ b/src/xrParticles/ParticlesAsyncManager.h @@ -0,0 +1,24 @@ +#pragma once +#include "../xrGame/ParticlesObject.h" + +class CPS_Instance; + +class CParticlesAsync +{ +public: + static void Play(); + static void Wait(); + + static void ForceUpdate(intrusive_ptr Obj); + static bool NeedForceUpdate(); + +private: + void UpdateParticle(intrusive_ptr particle) const; + static void Start(); + +public: + CParticlesAsync(); + +private: + volatile bool IsStarted = false; +}; diff --git a/src/xrParticles/particle_actions.h b/src/xrParticles/particle_actions.h index 4d29f5e918..9ed41c8fed 100644 --- a/src/xrParticles/particle_actions.h +++ b/src/xrParticles/particle_actions.h @@ -28,57 +28,47 @@ namespace PAPI DEFINE_VECTOR(ParticleAction*, PAVec, PAVecIt); - class ParticleActions + class ParticleActions : public intrusive_base { PAVec actions; - bool m_bLocked; public: - ParticleActions() - { - actions.reserve(4); - m_bLocked = false; - } + IC ParticleActions(); + IC ~ParticleActions(); - ~ParticleActions() { clear(); } - IC void clear() - { - R_ASSERT(!m_bLocked); - for (PAVecIt it = actions.begin(); it != actions.end(); it++) - xr_delete(*it); - actions.clear(); - } + IC void clear(); + IC void reserve(u32 capacity); - IC void append(ParticleAction* pa) - { - R_ASSERT(!m_bLocked); - actions.push_back(pa); - } - - IC bool empty() { return actions.empty(); } - IC PAVecIt begin() { return actions.begin(); } - IC PAVecIt end() { return actions.end(); } - IC int size() { return actions.size(); } - IC void resize(int cnt) - { - R_ASSERT(!m_bLocked); - actions.resize(cnt); - } + IC void append(ParticleAction* pa) { actions.push_back(pa); } + IC bool empty() { return actions.empty(); } + IC PAVecIt begin() { return actions.begin(); } + IC PAVecIt end() { return actions.end(); } + IC int size() { return (int)actions.size(); } + IC void resize(int cnt) { actions.resize(cnt); } + }; +}; - void copy(ParticleActions* src); +IC PAPI::ParticleActions::ParticleActions() +{ + actions.reserve(8); +} - void lock() - { - R_ASSERT(!m_bLocked); - m_bLocked = true; - } +IC PAPI::ParticleActions::~ParticleActions() +{ + clear(); +} - void unlock() - { - R_ASSERT(m_bLocked); - m_bLocked = false; - } - }; -}; +IC void PAPI::ParticleActions::clear() +{ + for (ParticleAction* pPAction : actions) + xr_delete(pPAction); + + actions.clear(); +} + +IC void PAPI::ParticleActions::reserve(u32 capacity) +{ + actions.reserve(capacity); +} //--------------------------------------------------------------------------- #endif diff --git a/src/xrParticles/particle_actions_collection.cpp b/src/xrParticles/particle_actions_collection.cpp index d7b01c161b..29fac26e8a 100644 --- a/src/xrParticles/particle_actions_collection.cpp +++ b/src/xrParticles/particle_actions_collection.cpp @@ -4,9 +4,6 @@ #include "particle_actions_collection.h" #include "particle_effect.h" -#include -#include - using namespace PAPI; void PAPI::PAAvoid::Execute(ParticleEffect* effect, const float dt, float& tm_max) diff --git a/src/xrParticles/particle_core.h b/src/xrParticles/particle_core.h index 660cbe9525..158ca9e6ab 100644 --- a/src/xrParticles/particle_core.h +++ b/src/xrParticles/particle_core.h @@ -1,13 +1,9 @@ -//--------------------------------------------------------------------------- -#ifndef particle_coreH -#define particle_coreH - +#pragma once #define SQRT2PI 2.506628274631000502415765284811045253006f #define ONEOVERSQRT2PI (1.f/SQRT2PI) namespace PAPI { -#pragma pack (push,4) struct PARTICLES_API pDomain { PDomainEnum type; // PABoxDomain, PASphereDomain, PAConeDomain... @@ -35,10 +31,8 @@ namespace PAPI float a3 = 0.0f, float a4 = 0.0f, float a5 = 0.0f, float a6 = 0.0f, float a7 = 0.0f, float a8 = 0.0f); }; -#pragma pack (pop) // misc float NRand(float sigma = 1.0f); }; //--------------------------------------------------------------------------- -#endif diff --git a/src/xrParticles/particle_effect.cpp b/src/xrParticles/particle_effect.cpp index a12d7ce179..cac05c39f9 100644 --- a/src/xrParticles/particle_effect.cpp +++ b/src/xrParticles/particle_effect.cpp @@ -1,4 +1,99 @@ -#include "stdafx.h" -#pragma hdrstop - +#include "stdafx.h" #include "particle_effect.h" + +using namespace PAPI; + +xrCriticalSection ParticleEffect::mParticleRemoveCS; + +ParticleEffect::ParticleEffect(int mp) +{ + owner = 0; + param = 0; + b_cb = 0; + d_cb = 0; + p_count = 0; + max_particles = mp; + particles_allocated = max_particles; + particles = xr_alloc(max_particles); +} + +ParticleEffect::~ParticleEffect() +{ + xr_free(particles); +} + +int ParticleEffect::Resize(u32 max_count) +{ + // Reducing max + if (particles_allocated >= max_count) + { + max_particles = max_count; + + // May have to kill particles. + if (p_count > max_particles) + p_count = max_particles; + + return max_count; + } + + // Allocate particles. + Particle* new_particles = xr_alloc(max_count); + + std::memcpy(new_particles, particles, p_count * sizeof(Particle)); + xr_free(particles); + + particles = new_particles; + + max_particles = max_count; + particles_allocated = max_count; + return max_count; +} + +void ParticleEffect::Remove(int i) +{ + xrCriticalSectionGuard RemoveGuard(mParticleRemoveCS); + + if (0 == p_count) + return; + + Particle& m = particles[i]; + if (d_cb) + d_cb(owner, param, m, i); + + // �� ������ ������� �������� !!! (dependence ParticleGroup) + m = particles[--p_count]; +} + +BOOL ParticleEffect::Add(const pVector& pos, const pVector& posB, + const pVector& size, const pVector& rot, const pVector& vel, u32 color, + const float age, u16 frame, u16 flags) +{ + if (p_count >= max_particles) + return FALSE; + + Particle& P = particles[p_count]; + P.pos = pos; + P.posI = pos; + P.posB = posB; + P.size = size; + P.sizeI = size; + P.rot.x = rot.x; + P.rotI.x = rot.x; + P.vel = vel; + P.velI = vel; + float f = float(1.0) / float(255.0); + P.colorA = f * ((color >> 24) & 0xff); + P.colorR = f * ((color >> 16) & 0xff); + P.colorG = f * ((color >> 8) & 0xff); + P.colorB = f * ((color >> 0) & 0xff); + P.age = age; + P.frame = frame; + P.flags.assign(flags); + + if (b_cb) + b_cb(owner, param, P, p_count); + + p_count++; + + return TRUE; +} \ No newline at end of file diff --git a/src/xrParticles/particle_effect.h b/src/xrParticles/particle_effect.h index 2b1ec33676..393585fd62 100644 --- a/src/xrParticles/particle_effect.h +++ b/src/xrParticles/particle_effect.h @@ -1,119 +1,31 @@ -//--------------------------------------------------------------------------- -#ifndef particle_effectH -#define particle_effectH +#pragma once namespace PAPI { // A effect of particles - Info and an array of Particles - struct ParticleEffect + struct ParticleEffect : public intrusive_base { - u32 p_count; // Number of particles currently existing. - u32 max_particles; // Max particles allowed in effect. - u32 particles_allocated; // Actual allocated size. - Particle* particles; // Actually, num_particles in size - void* real_ptr; // Base, possible not aligned pointer - OnBirthParticleCB b_cb; - OnDeadParticleCB d_cb; - void* owner; - u32 param; - - public: - ParticleEffect(int mp) - { - owner = 0; - param = 0; - b_cb = 0; - d_cb = 0; - p_count = 0; - max_particles = mp; - particles_allocated = max_particles; - - real_ptr = xr_malloc(sizeof(Particle) * (max_particles + 1)); - particles = (Particle*)((uintptr_t)real_ptr + (64 - ((uintptr_t)real_ptr & 63))); - //Msg( "Allocated %u bytes (%u particles) with base address 0x%p" , max_particles * sizeof( Particle ) , max_particles , particles ); - } - - ~ParticleEffect() - { - xr_free(real_ptr); - } - - IC int Resize(u32 max_count) - { - // Reducing max. - if (particles_allocated >= max_count) - { - max_particles = max_count; - - // May have to kill particles. - if (p_count > max_particles) - p_count = max_particles; - - return max_count; - } + u32 p_count; // Number of particles currently existing. + u32 max_particles; // Max particles allowed in effect. + u32 particles_allocated; // Actual allocated size. - // Allocate particles. - void* new_real_ptr = xr_malloc(sizeof(Particle) * (max_count + 1)); + Particle* particles; // Actually, num_particles in size - if (new_real_ptr == NULL) - { - // ERROR - Not enough memory. Just give all we've got. - max_particles = particles_allocated; - return max_particles; - } + OnBirthParticleCB b_cb; + OnDeadParticleCB d_cb; - Particle* new_particles = (Particle*)((uintptr_t)new_real_ptr + (64 - ((uintptr_t)new_real_ptr & 63))); - //Msg( "Re-allocated %u bytes (%u particles) with base address 0x%p" , max_count * sizeof( Particle ) , max_count , new_particles ); - - CopyMemory(new_particles, particles, p_count * sizeof(Particle)); - xr_free(real_ptr); - - particles = new_particles; - real_ptr = new_real_ptr; - - max_particles = max_count; - particles_allocated = max_count; - return max_count; - } - - IC void Remove(int i) - { - if (0 == p_count) return; - Particle& m = particles[i]; - if (d_cb) d_cb(owner, param, m, i); - m = particles[--p_count]; // не менять правило удаления !!! (dependence ParticleGroup) - // Msg( "pDel() : %u" , p_count ); - } + void* owner; + u32 param; - IC BOOL Add(const pVector& pos, const pVector& posB, - const pVector& size, const pVector& rot, const pVector& vel, u32 color, - const float age = 0.0f, u16 frame = 0, u16 flags = 0) - { - if (p_count >= max_particles) return FALSE; - else - { - Particle& P = particles[p_count]; - P.pos = pos; - P.posB = posB; - P.size = size; - P.rot.x = rot.x; - P.vel = vel; - float f = float(1.0) / float(255.0); - P.colorA = f * ((color >> 24) & 0xff); - P.colorR = f * ((color >> 16) & 0xff); - P.colorG = f * ((color >> 8) & 0xff); - P.colorB = f * ((color >> 0) & 0xff); - P.age = age; - P.frame = frame; - P.flags.assign(flags); - if (b_cb) b_cb(owner, param, P, p_count); - p_count++; - // Msg( "pAdd() : %u" , p_count ); - return TRUE; - } - } + static xrCriticalSection mParticleRemoveCS; + public: + ParticleEffect(int mp); + ~ParticleEffect(); + + int Resize(u32 max_count); + void Remove(int i); + BOOL Add(const pVector& pos, const pVector& posB, + const pVector& size, const pVector& rot, const pVector& vel, u32 color, + const float age = 0.0f, u16 frame = 0, u16 flags = 0); }; -}; - -//--------------------------------------------------------------------------- -#endif +} \ No newline at end of file diff --git a/src/xrParticles/particle_manager.cpp b/src/xrParticles/particle_manager.cpp index 291ae85ded..ee1a7c50f4 100644 --- a/src/xrParticles/particle_manager.cpp +++ b/src/xrParticles/particle_manager.cpp @@ -1,221 +1,251 @@ //--------------------------------------------------------------------------- #include "stdafx.h" -#pragma hdrstop #include "particle_manager.h" #include "particle_effect.h" #include "particle_actions_collection.h" +#include "../xrGame/ParticlesObject.h" +#include "ParticlesAsyncManager.h" using namespace PAPI; // system -CParticleManager PM; -PARTICLES_API IParticleManager* PAPI::ParticleManager() { return &PM; } +CParticleManager* PM = nullptr; +PARTICLES_API IParticleManager* PAPI::ParticleManager() +{ + if (!PM) + { + PM = new CParticleManager(); + } + + return PM; +} // CParticleManager::CParticleManager() { + Device.seqFrame.Add(this, REG_PRIORITY_HIGH + 10500); } CParticleManager::~CParticleManager() { + Device.seqFrame.Remove(this); } -ParticleEffect* CParticleManager::GetEffectPtr(int effect_id) +CParticleManager::SharedParticleEffect CParticleManager::GetEffectPtr(int effect_id) { - R_ASSERT(effect_id>=0&&effect_id<(int)effect_vec.size()); - return effect_vec[effect_id]; + xrSRWLockGuard guard(m_effect_guard, true); + auto effectIter = m_effect_map.find(effect_id); + if (effectIter != m_effect_map.end()) + { + return effectIter->second; + } + + return CParticleManager::SharedParticleEffect(); } -ParticleActions* CParticleManager::GetActionListPtr(int a_list_num) +CParticleManager::SharedParticleActions CParticleManager::GetActionListPtr(int a_list_num) { - R_ASSERT(a_list_num>=0&&a_list_num<(int)m_alist_vec.size()); - return m_alist_vec[a_list_num]; + xrSRWLockGuard guard(m_action_guard, true); + auto actionIter = m_alist_map.find(a_list_num); + if (actionIter != m_alist_map.end()) + { + return actionIter->second; + } + + return CParticleManager::SharedParticleActions(); } // create int CParticleManager::CreateEffect(u32 max_particles) { - int eff_id = -1; - for (int i = 0; i < (int)effect_vec.size(); i++) - if (!effect_vec[i]) - { - eff_id = i; - break; - } + xrSRWLockGuard guard(m_effect_guard); + int effectId = m_effect_counter++; - if (eff_id < 0) - { - // Couldn't find a big enough gap. Reallocate. - eff_id = effect_vec.size(); - effect_vec.push_back(0); - } - - effect_vec[eff_id] = xr_new(max_particles); + auto EffectResultPair = m_effect_map.emplace(effectId, xr_new(max_particles)); + R_ASSERT2(EffectResultPair.second, "Can't create particle effect with global counter"); - return eff_id; + return effectId; } void CParticleManager::DestroyEffect(int effect_id) { - R_ASSERT(effect_id>=0&&effect_id<(int)effect_vec.size()); - xr_delete(effect_vec[effect_id]); + xrSRWLockGuard guard(m_effect_guard); + m_effect_map.erase(effect_id); } -int CParticleManager::CreateActionList() +int CParticleManager::CreateActionList() { - int list_id = -1; - for (u32 i = 0; i < m_alist_vec.size(); ++i) - if (!m_alist_vec[i]) - { - list_id = i; - break; - } + int actionId = m_action_counter++; - if (list_id < 0) + xrSpinWait w; + while (ActionIter.load(std::memory_order_acquire) != 0) { - // Couldn't find a big enough gap. Reallocate. - list_id = m_alist_vec.size(); - m_alist_vec.push_back(0); + w(); } - m_alist_vec[list_id] = xr_new(); + xrSRWLockGuard guard(m_action_guard); + auto ActionResultPair = m_alist_map.emplace(actionId, xr_new()); + R_ASSERT2(ActionResultPair.second, "Can't create particle action with global counter"); - return list_id; + return actionId; } void CParticleManager::DestroyActionList(int alist_id) { - R_ASSERT(alist_id>=0&&alist_id<(int)m_alist_vec.size()); - xr_delete(m_alist_vec[alist_id]); + SharedParticleActions to_delete; + { + xrSRWLockGuard guard(m_action_guard); + auto it = m_alist_map.find(alist_id); + if (it != m_alist_map.end()) + { + to_delete = it->second; // Keep a ref so it doesn't die yet + m_alist_map.erase(it); + } + } + + xrSpinWait w; + while (ActionIter.load(std::memory_order_acquire) != 0) + { + w(); + } } // control void CParticleManager::PlayEffect(int effect_id, int alist_id) { - // effect - // ParticleEffect* pe = GetEffectPtr(effect_id); // Execute the specified action list. - ParticleActions* pa = GetActionListPtr(alist_id); - VERIFY(pa); - if (pa == NULL) return; // ERROR - pa->lock(); + SharedParticleActions particleAction = GetActionListPtr(alist_id); + + if (!particleAction) + return; // ERROR + + ActionIter.fetch_add(1, std::memory_order_relaxed); + // Step through all the actions in the action list. - for (PAVecIt it = pa->begin(); it != pa->end(); ++it) + for (PAVecIt it = particleAction->begin(); it != particleAction->end(); ++it) { VERIFY((*it)); - if ((*it)) - switch ((*it)->type) - { - case PASourceID: static_cast(*it)->m_Flags.set(PASource::flSilent, FALSE); break; - case PAExplosionID: static_cast(*it)->age = 0.f; break; - case PATurbulenceID: static_cast(*it)->age = 0.f; break; - } + switch ((*it)->type) + { + case PASourceID: + static_cast(*it)->m_Flags.set(PASource::flSilent, FALSE); + break; + case PAExplosionID: + static_cast(*it)->age = 0.f; + break; + case PATurbulenceID: + static_cast(*it)->age = 0.f; + break; + } } - pa->unlock(); + + ActionIter.fetch_sub(1, std::memory_order_release); } void CParticleManager::StopEffect(int effect_id, int alist_id, BOOL deffered) { // Execute the specified action list. - ParticleActions* pa = GetActionListPtr(alist_id); - VERIFY(pa); - if (pa == NULL) return; // ERROR - pa->lock(); + SharedParticleActions particleAction = GetActionListPtr(alist_id); + + if (!particleAction) + return; // ERROR // Step through all the actions in the action list. - for (PAVecIt it = pa->begin(); it != pa->end(); it++) + ActionIter.fetch_add(1, std::memory_order_relaxed); + for (PAVecIt it = particleAction->begin(); it != particleAction->end(); ++it) { - if ((*it)) - switch ((*it)->type) - { - case PASourceID: static_cast(*it)->m_Flags.set(PASource::flSilent, TRUE); break; - } + switch ((*it)->type) + { + case PASourceID: + static_cast(*it)->m_Flags.set(PASource::flSilent, TRUE); + break; + } } + ActionIter.fetch_sub(1, std::memory_order_release); + if (!deffered) { // effect - ParticleEffect* pe = GetEffectPtr(effect_id); - pe->p_count = 0; + SharedParticleEffect particleEffect = GetEffectPtr(effect_id); + if (particleEffect != nullptr) + { + xrCriticalSectionGuard cs(ParticleEffect::mParticleRemoveCS); + particleEffect->p_count = 0; + } } - pa->unlock(); } // update&render void CParticleManager::Update(int effect_id, int alist_id, float dt) { - ParticleEffect* pe = GetEffectPtr(effect_id); - ParticleActions* pa = GetActionListPtr(alist_id); - - VERIFY(pa); - VERIFY(pe); + SharedParticleEffect pe = GetEffectPtr(effect_id); + SharedParticleActions pa = GetActionListPtr(alist_id); - pa->lock(); + if (!pe || !pa) + { + return; + } // Step through all the actions in the action list. - float kill_old_time = 1.0f; - for (PAVecIt it = pa->begin(); it != pa->end(); it++) + float kill_old_time = 3.0f; + for (PAPI::ParticleAction* pAction : *pa) { - VERIFY((*it)); - if ((*it)) - (*it)->Execute(pe, dt, kill_old_time); + pAction->Execute(&(*pe), dt, kill_old_time); } - pa->unlock(); -} - -void CParticleManager::Render(int effect_id) -{ - // ParticleEffect* pe = GetEffectPtr(effect_id); } void CParticleManager::Transform(int alist_id, const Fmatrix& full, const Fvector& vel) { // Execute the specified action list. - ParticleActions* pa = GetActionListPtr(alist_id); - VERIFY(pa); + SharedParticleActions pa = GetActionListPtr(alist_id); - if (pa == NULL) return; // ERROR - pa->lock(); + if (!pa) + return; Fmatrix mT; mT.translate(full.c); // Step through all the actions in the action list. - for (PAVecIt it = pa->begin(); it != pa->end(); it++) + for (PAVecIt it = pa->begin(); it != pa->end(); ++it) { - if (!(*it)) - continue; - BOOL r = (*it)->m_Flags.is(ParticleAction::ALLOW_ROTATE); const Fmatrix& m = r ? full : mT; (*it)->Transform(m); switch ((*it)->type) { case PASourceID: - static_cast(*it)->parent_vel = pVector(vel.x, vel.y, vel.z) * static_cast(*it)-> - parent_motion; + static_cast(*it)->parent_vel = pVector(vel.x, vel.y, vel.z) * static_cast(*it)->parent_motion; break; } } - pa->unlock(); } // effect void CParticleManager::RemoveParticle(int effect_id, u32 p_id) { - ParticleEffect* pe = GetEffectPtr(effect_id); + SharedParticleEffect pe = GetEffectPtr(effect_id); + if (!pe) + return; + pe->Remove(p_id); } void CParticleManager::SetMaxParticles(int effect_id, u32 max_particles) { - ParticleEffect* pe = GetEffectPtr(effect_id); + SharedParticleEffect pe = GetEffectPtr(effect_id); + if (!pe) + return; + pe->Resize(max_particles); } void CParticleManager::SetCallback(int effect_id, OnBirthParticleCB b, OnDeadParticleCB d, void* owner, u32 param) { - ParticleEffect* pe = GetEffectPtr(effect_id); + SharedParticleEffect pe = GetEffectPtr(effect_id); + if (!pe) + return; + pe->b_cb = b; pe->d_cb = d; pe->owner = owner; @@ -224,14 +254,24 @@ void CParticleManager::SetCallback(int effect_id, OnBirthParticleCB b, OnDeadPar void CParticleManager::GetParticles(int effect_id, Particle*& particles, u32& cnt) { - ParticleEffect* pe = GetEffectPtr(effect_id); + SharedParticleEffect pe = GetEffectPtr(effect_id); + if (!pe) + { + particles = nullptr; + cnt = 0; + return; + } + particles = pe->particles; cnt = pe->p_count; } -u32 CParticleManager::GetParticlesCount(int effect_id) +u32 CParticleManager::GetParticlesCount(int effect_id) { - ParticleEffect* pe = GetEffectPtr(effect_id); + SharedParticleEffect pe = GetEffectPtr(effect_id); + if (!pe) + return 0; + return pe->p_count; } @@ -239,70 +279,38 @@ u32 CParticleManager::GetParticlesCount(int effect_id) ParticleAction* CParticleManager::CreateAction(PActionEnum type) { ParticleAction* pa = 0; - switch (type) - { - case PAAvoidID: pa = xr_new(); - break; - case PABounceID: pa = xr_new(); - break; - case PACopyVertexBID: pa = xr_new(); - break; - case PADampingID: pa = xr_new(); - break; - case PAExplosionID: pa = xr_new(); - break; - case PAFollowID: pa = xr_new(); - break; - case PAGravitateID: pa = xr_new(); - break; - case PAGravityID: pa = xr_new(); - break; - case PAJetID: pa = xr_new(); - break; - case PAKillOldID: pa = xr_new(); - break; - case PAMatchVelocityID: pa = xr_new(); - break; - case PAMoveID: pa = xr_new(); - break; - case PAOrbitLineID: pa = xr_new(); - break; - case PAOrbitPointID: pa = xr_new(); - break; - case PARandomAccelID: pa = xr_new(); - break; - case PARandomDisplaceID: pa = xr_new(); - break; - case PARandomVelocityID: pa = xr_new(); - break; - case PARestoreID: pa = xr_new(); - break; - case PASinkID: pa = xr_new(); - break; - case PASinkVelocityID: pa = xr_new(); - break; - case PASourceID: pa = xr_new(); - break; - case PASpeedLimitID: pa = xr_new(); - break; - case PATargetColorID: pa = xr_new(); - break; - case PATargetSizeID: pa = xr_new(); - break; - case PATargetRotateID: pa = xr_new(); - break; - case PATargetRotateDID: pa = xr_new(); - break; - case PATargetVelocityID: pa = xr_new(); - break; - case PATargetVelocityDID: pa = xr_new(); - break; - case PAVortexID: pa = xr_new(); - break; - case PATurbulenceID: pa = xr_new(); - break; - case PAScatterID: pa = xr_new(); - break; + switch (type) { + case PAAvoidID: pa = xr_new(); break; + case PABounceID: pa = xr_new(); break; + case PACopyVertexBID: pa = xr_new(); break; + case PADampingID: pa = xr_new(); break; + case PAExplosionID: pa = xr_new(); break; + case PAFollowID: pa = xr_new(); break; + case PAGravitateID: pa = xr_new(); break; + case PAGravityID: pa = xr_new(); break; + case PAJetID: pa = xr_new(); break; + case PAKillOldID: pa = xr_new(); break; + case PAMatchVelocityID: pa = xr_new(); break; + case PAMoveID: pa = xr_new(); break; + case PAOrbitLineID: pa = xr_new(); break; + case PAOrbitPointID: pa = xr_new(); break; + case PARandomAccelID: pa = xr_new(); break; + case PARandomDisplaceID: pa = xr_new(); break; + case PARandomVelocityID: pa = xr_new(); break; + case PARestoreID: pa = xr_new(); break; + case PASinkID: pa = xr_new(); break; + case PASinkVelocityID: pa = xr_new(); break; + case PASourceID: pa = xr_new(); break; + case PASpeedLimitID: pa = xr_new(); break; + case PATargetColorID: pa = xr_new(); break; + case PATargetSizeID: pa = xr_new(); break; + case PATargetRotateID: pa = xr_new(); break; + case PATargetRotateDID: pa = xr_new(); break; + case PATargetVelocityID: pa = xr_new(); break; + case PATargetVelocityDID: pa = xr_new(); break; + case PAVortexID: pa = xr_new(); break; + case PATurbulenceID: pa = xr_new(); break; + case PAScatterID: pa = xr_new(); break; default: NODEFAULT; } pa->type = type; @@ -312,18 +320,18 @@ ParticleAction* CParticleManager::CreateAction(PActionEnum type) u32 CParticleManager::LoadActions(int alist_id, IReader& R) { // Execute the specified action list. - ParticleActions* pa = GetActionListPtr(alist_id); - VERIFY(pa); + SharedParticleActions pa = GetActionListPtr(alist_id); + if (!pa) + return 0; + pa->clear(); if (R.length()) { u32 cnt = R.r_u32(); - for (u32 k = 0; k < cnt; k++) + pa->reserve(cnt); + for (u32 k = 0; k < cnt; ++k) { - u32 type = R.r_u32(); - if (type == (u32)-1) - continue; - ParticleAction* act = CreateAction((PActionEnum)type); + ParticleAction* act = CreateAction((PActionEnum)R.r_u32()); act->Load(R); pa->append(act); } @@ -334,19 +342,17 @@ u32 CParticleManager::LoadActions(int alist_id, IReader& R) void CParticleManager::SaveActions(int alist_id, IWriter& W) { // Execute the specified action list. - ParticleActions* pa = GetActionListPtr(alist_id); - VERIFY(pa); - pa->lock(); + SharedParticleActions pa = GetActionListPtr(alist_id); + if (!pa) + return; + W.w_u32(pa->size()); - for (PAVecIt it = pa->begin(); it != pa->end(); it++) - { - if (!(*it)) { - W.w_u32((u32)-1); - continue; - } - W.w_u32((*it)->type); + for (PAVecIt it = pa->begin(); it != pa->end(); ++it) (*it)->Save(W); - } - pa->unlock(); +} + +void PAPI::CParticleManager::OnFrame() +{ + CParticlesAsync::Play(); } diff --git a/src/xrParticles/particle_manager.h b/src/xrParticles/particle_manager.h index 0ea1fc3e46..aab57ec8ea 100644 --- a/src/xrParticles/particle_manager.h +++ b/src/xrParticles/particle_manager.h @@ -1,54 +1,61 @@ -//--------------------------------------------------------------------------- -#ifndef particle_managerH -#define particle_managerH -//--------------------------------------------------------------------------- +#pragma once #include "particle_actions.h" +#include namespace PAPI { - class CParticleManager : public IParticleManager - { - // These are static because all threads access the same effects. - // All accesses to these should be locked. - DEFINE_VECTOR(ParticleEffect*, ParticleEffectVec, ParticleEffectVecIt); - DEFINE_VECTOR(ParticleActions*, ParticleActionsVec, ParticleActionsVecIt); - ParticleEffectVec effect_vec; - ParticleActionsVec m_alist_vec; - public: - CParticleManager(); - virtual ~CParticleManager(); - // Return an index into the list of particle effects where - ParticleEffect* GetEffectPtr(int effect_id); - ParticleActions* GetActionListPtr(int alist_id); - - // create&destroy - virtual int CreateEffect(u32 max_particles); - virtual void DestroyEffect(int effect_id); - virtual int CreateActionList(); - virtual void DestroyActionList(int alist_id); - - // control - virtual void PlayEffect(int effect_id, int alist_id); - virtual void StopEffect(int effect_id, int alist_id, BOOL deffered = TRUE); - - // update&render - virtual void Update(int effect_id, int alist_id, float dt); - virtual void Render(int effect_id); - virtual void Transform(int alist_id, const Fmatrix& m, const Fvector& velocity); - - // effect - virtual void RemoveParticle(int effect_id, u32 p_id); - virtual void SetMaxParticles(int effect_id, u32 max_particles); - virtual void SetCallback(int effect_id, OnBirthParticleCB b, OnDeadParticleCB d, void* owner, u32 param); - virtual void GetParticles(int effect_id, Particle*& particles, u32& cnt); - virtual u32 GetParticlesCount(int effect_id); - - // action - virtual ParticleAction* CreateAction(PActionEnum action_id); - virtual u32 LoadActions(int alist_id, IReader& R); - virtual void SaveActions(int alist_id, IWriter& W); - }; -}; + class CParticleManager : + public IParticleManager, + public pureFrame + { + // These are static because all threads access the same effects. + // All accesses to these should be locked. + + using SharedParticleEffect = intrusive_ptr; + using SharedParticleActions = intrusive_ptr; + + using ParticleEffectVec = xr_hash_map; + using ParticleActionsVec = xr_hash_map; + ParticleEffectVec m_effect_map; + ParticleActionsVec m_alist_map; + xr_atomic_s32 m_effect_counter; + xr_atomic_s32 m_action_counter; + + xrSRWLock m_effect_guard; + xrSRWLock m_action_guard; + xr_atomic_s32 ActionIter = 0; + + public: + CParticleManager(); + virtual ~CParticleManager(); + // Return an index into the list of particle effects where + SharedParticleEffect GetEffectPtr(int effect_id); + SharedParticleActions GetActionListPtr(int alist_id); -//--------------------------------------------------------------------------- -#endif + // create&destroy + virtual int CreateEffect(u32 max_particles); + virtual void DestroyEffect(int effect_id); + virtual int CreateActionList(); + virtual void DestroyActionList(int alist_id); + + // control + virtual void PlayEffect(int effect_id, int alist_id); + virtual void StopEffect(int effect_id, int alist_id, BOOL deffered = TRUE); + + // update&render + virtual void Update(int effect_id, int alist_id, float dt); + virtual void Transform(int alist_id, const Fmatrix& m, const Fvector& velocity); + // effect + virtual void RemoveParticle(int effect_id, u32 p_id); + virtual void SetMaxParticles(int effect_id, u32 max_particles); + virtual void SetCallback(int effect_id, OnBirthParticleCB b, OnDeadParticleCB d, void* owner, u32 param); + virtual void GetParticles(int effect_id, Particle*& particles, u32& cnt); + virtual u32 GetParticlesCount(int effect_id); + + // action + virtual ParticleAction* CreateAction(PActionEnum action_id); + virtual u32 LoadActions(int alist_id, IReader& R); + virtual void SaveActions(int alist_id, IWriter& W); + virtual void OnFrame() override; + }; +}; diff --git a/src/xrParticles/psystem.h b/src/xrParticles/psystem.h index 1fd92f8947..4794a496d4 100644 --- a/src/xrParticles/psystem.h +++ b/src/xrParticles/psystem.h @@ -109,6 +109,13 @@ namespace PAPI struct Rotation { float x; + ICF void set(float _x) { x = _x; } + ICF void set(const Rotation& rot_) { x = rot_.x; } + ICF void inertion(const Rotation& p, float v) + { + float inv = 1.f - v; + x = v * x + inv * p.x; + } }; struct Particle @@ -119,10 +126,14 @@ namespace PAPI }; Rotation rot; // 4 + Rotation rotI; // 4 pVector pos; // 12 + pVector posI; // 12 pVector posB; // 12 pVector vel; // 12 + pVector velI; // 12 pVector size; // 12 + pVector sizeI; // 12 float colorR; // 4 float colorG; // 4 float colorB; // 4 @@ -130,7 +141,7 @@ namespace PAPI float age; // 4 u16 frame; // 2 Flags16 flags; // 2 - }; // = 76 + }; // = 116 typedef void (* OnBirthParticleCB)(void* owner, u32 param, PAPI::Particle& P, u32 idx); typedef void (* OnDeadParticleCB)(void* owner, u32 param, PAPI::Particle& P, u32 idx); @@ -260,7 +271,6 @@ namespace PAPI // update&render virtual void Update(int effect_id, int alist_id, float dt) =0; - virtual void Render(int effect_id) =0; virtual void Transform(int alist_id, const Fmatrix& m, const Fvector& velocity) =0; // effect diff --git a/src/xrParticles/stdafx.h b/src/xrParticles/stdafx.h index 2112ae2a02..8d7f70e2e8 100644 --- a/src/xrParticles/stdafx.h +++ b/src/xrParticles/stdafx.h @@ -4,19 +4,8 @@ // // Third generation by Oles. -#ifndef stdafxH -#define stdafxH - #pragma once -#include "../xrCore/xrCore.h" - +#include "../xrEngine/stdafx.h" #include "psystem.h" - -#ifdef __BORLANDC__ -#pragma comment( lib, "x:\\xrCoreB.lib" ) -#else -#pragma comment( lib, "xrCore.lib" ) -#endif - -#endif //stdafxH +#include "../xrServerEntities/smart_cast.h" diff --git a/src/xrParticles/xrParticles.vcxproj b/src/xrParticles/xrParticles.vcxproj index 3e70fa1b80..ca5c951b00 100644 --- a/src/xrParticles/xrParticles.vcxproj +++ b/src/xrParticles/xrParticles.vcxproj @@ -13,6 +13,10 @@ Release x64 + + VerifiedDX11ASAN + x64 + VerifiedDX11 x64 @@ -52,6 +56,12 @@ v143 x64 + + StaticLibrary + v143 + x64 + true + StaticLibrary v143 @@ -82,6 +92,11 @@ + + + + + @@ -111,6 +126,11 @@ $(xrGameDir)bin_dbg\$(Platform)\$(Configuration)\ $(xrIntDir)$(ProjectName)\ + + false + $(xrGameDir)bin_dbg\$(Platform)\$(Configuration)\ + $(xrIntDir)$(ProjectName)\ + false $(xrGameDir)bin_dbg\$(Platform)\$(Configuration)\ @@ -124,7 +144,7 @@ $(OutDir)$(TargetName).tlb - $(xrSdkDir)include;%(AdditionalIncludeDirectories) + $(SolutionDir)3rd party\luabind\;$(xrSdkDir)include;%(AdditionalIncludeDirectories) NDEBUG;WIN32;_WINDOWS;XR_PARTICLES_EXPORTS;_SECURE_SCL=0;%(PreprocessorDefinitions) NotSet Use @@ -168,7 +188,7 @@ $(OutDir)$(TargetName).tlb - $(xrSdkDir)include;%(AdditionalIncludeDirectories) + $(SolutionDir)3rd party\luabind\;$(xrSdkDir)include;%(AdditionalIncludeDirectories) XRCORE_PROFILER;NDEBUG;WIN32;_WINDOWS;XR_PARTICLES_EXPORTS;_SECURE_SCL=0;%(PreprocessorDefinitions) NotSet Use @@ -217,8 +237,8 @@ false false false - $(xrSdkDir)include;%(AdditionalIncludeDirectories) - USE_VERIFY_IN_RELEASE;NDEBUG;WIN32;_WINDOWS;XR_PARTICLES_EXPORTS;_SECURE_SCL=0;%(PreprocessorDefinitions) + $(SolutionDir)3rd party\luabind\;$(xrSdkDir)include;%(AdditionalIncludeDirectories) + XRCORE_PROFILER;USE_VERIFY_IN_RELEASE;NDEBUG;WIN32;_WINDOWS;XR_PARTICLES_EXPORTS;_SECURE_SCL=0;%(PreprocessorDefinitions) NotSet Use EditAndContinue @@ -264,8 +284,8 @@ false false false - $(xrSdkDir)include;%(AdditionalIncludeDirectories) - USE_VERIFY_IN_RELEASE;NDEBUG;WIN32;_WINDOWS;XR_PARTICLES_EXPORTS;_SECURE_SCL=0;%(PreprocessorDefinitions) + $(SolutionDir)3rd party\luabind\;$(xrSdkDir)include;%(AdditionalIncludeDirectories) + XRCORE_PROFILER;USE_VERIFY_IN_RELEASE;NDEBUG;WIN32;_WINDOWS;XR_PARTICLES_EXPORTS;_SECURE_SCL=0;%(PreprocessorDefinitions) NotSet Use EditAndContinue @@ -296,6 +316,53 @@ true + + + NDEBUG;%(PreprocessorDefinitions) + true + true + $(OutDir)$(TargetName).tlb + + + Disabled + Disabled + false + Neither + false + false + false + $(SolutionDir)3rd party\luabind\;$(xrSdkDir)include;%(AdditionalIncludeDirectories) + XRCORE_PROFILER;USE_VERIFY_IN_RELEASE;_DISABLE_VECTOR_ANNOTATION;_DISABLE_STRING_ANNOTATION;NDEBUG;WIN32;_WINDOWS;XR_PARTICLES_EXPORTS;_SECURE_SCL=0;%(PreprocessorDefinitions) + NotSet + Use + ProgramDatabase + USE_LUAJIT_ONE + true + Level4 + false + MultiThreadedDLL + false + stdcpp17 + true + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + + + /MACHINE:X64 %(AdditionalOptions) + true + $(xrSdkDir)libraries;$(xrLibDir);%(AdditionalLibraryDirectories) + NotSet + true + true + true + Default + false + $(xrLibDir)$(TargetName).lib + true + + NDEBUG;%(PreprocessorDefinitions) @@ -304,7 +371,7 @@ $(OutDir)$(TargetName).tlb - $(xrSdkDir)include;%(AdditionalIncludeDirectories) + $(SolutionDir)3rd party\luabind\;$(xrSdkDir)include;%(AdditionalIncludeDirectories) NDEBUG;WIN32;_WINDOWS;XR_PARTICLES_EXPORTS;_SECURE_SCL=0;%(PreprocessorDefinitions) AdvancedVectorExtensions Use @@ -342,6 +409,7 @@ + @@ -352,6 +420,7 @@ + @@ -363,6 +432,7 @@ Create Create Create + Create Create diff --git a/src/xrParticles/xrParticles.vcxproj.filters b/src/xrParticles/xrParticles.vcxproj.filters index e02384046e..21ae10946d 100644 --- a/src/xrParticles/xrParticles.vcxproj.filters +++ b/src/xrParticles/xrParticles.vcxproj.filters @@ -33,6 +33,9 @@ PAPI + + PAPI + @@ -59,5 +62,8 @@ PAPI + + PAPI + \ No newline at end of file diff --git a/src/xrPhysics/IActivationShape.cpp b/src/xrPhysics/IActivationShape.cpp index 5d8c0323e4..8b4d285721 100644 --- a/src/xrPhysics/IActivationShape.cpp +++ b/src/xrPhysics/IActivationShape.cpp @@ -7,6 +7,7 @@ void ActivateShapeExplosive(IPhysicsShellHolder* self_obj, const Fvector& size, Fvector& out_size, Fvector& in_out_pos) { + PROF_EVENT("ActivateShapeExplosive"); ////////////// CPHActivationShape activation_shape; //Fvector start_box;m_PhysicMovementControl.Box().getsize(start_box); activation_shape.Create(in_out_pos, size, self_obj); @@ -24,6 +25,7 @@ void ActivateShapeExplosive(IPhysicsShellHolder* self_obj, const Fvector& size, void ActivateShapePhysShellHolder(IPhysicsShellHolder* obj, const Fmatrix& in_xform, const Fvector& in_size, Fvector& in_pos, Fvector& out_pos) { + PROF_EVENT("ActivateShapePhysShellHolder"); CPHActivationShape activation_shape; activation_shape.Create(in_pos, in_size, obj); activation_shape.set_rotation(in_xform); @@ -55,6 +57,7 @@ bool ActivateShapeCharacterPhysicsSupport(Fvector& out_pos, const Fvector& vbox, const Fmatrix& mXFORM, bool not_collide_characters, bool set_rotation, IPhysicsShellHolder* m_EntityAlife) { + PROF_EVENT("ActivateShapeCharacterPhysicsSupport"); CPHActivationShape activation_shape; activation_shape.Create(activation_pos, vbox, m_EntityAlife); if (not_collide_characters) diff --git a/src/xrPhysics/IPHWorld.h b/src/xrPhysics/IPHWorld.h index 0a0e7e2bf2..7e614dd158 100644 --- a/src/xrPhysics/IPHWorld.h +++ b/src/xrPhysics/IPHWorld.h @@ -36,7 +36,7 @@ class IPHWorld : virtual void StepNumIterations(int num_it) = 0; virtual void set_default_contact_shotmark(ContactCallbackFun* f) = 0; virtual void set_default_character_contact_shotmark(ContactCallbackFun* f) = 0; - virtual void set_step_time_callback(PhysicsStepTimeCallback* cb) = 0; + virtual void set_update_callback(IPHWorldUpdateCallbck* cb) = 0; #ifdef DEBUG virtual u16 ObjectsNumber () = 0; diff --git a/src/xrPhysics/MovementBoxDynamicActivate.cpp b/src/xrPhysics/MovementBoxDynamicActivate.cpp index 24961874cd..3eefc958bd 100644 --- a/src/xrPhysics/MovementBoxDynamicActivate.cpp +++ b/src/xrPhysics/MovementBoxDynamicActivate.cpp @@ -79,13 +79,13 @@ void TTestDepthCallback(bool& do_colide, bool bo1, dContact& c, SGameMtl* materi dxGeomUserData* ud1 = retrieveGeomUserData(c.geom.g1); dxGeomUserData* ud2 = retrieveGeomUserData(c.geom.g2); - if (ud1) + if (ud1 && ud1->ph_ref_object) { CPhysicsShell* phsl = ud1->ph_ref_object->ObjectPPhysicsShell(); if (phsl) phsl->Enable(); } - if (ud2) + if (ud2 && ud2->ph_ref_object) { CPhysicsShell* phsl = ud2->ph_ref_object->ObjectPPhysicsShell(); if (phsl) phsl->Enable(); diff --git a/src/xrPhysics/PHActivationShape.cpp b/src/xrPhysics/PHActivationShape.cpp index 261fe7de91..0effa006ca 100644 --- a/src/xrPhysics/PHActivationShape.cpp +++ b/src/xrPhysics/PHActivationShape.cpp @@ -353,7 +353,7 @@ dGeomID CPHActivationShape::dSpacedGeom() void CPHActivationShape::get_spatial_params() { - spatialParsFromDGeom(m_geom, spatial.sphere.P, AABB, spatial.sphere.R); + spatialParsFromDGeom(m_geom, SpatialComponent->spatial.sphere.P, AABB, SpatialComponent->spatial.sphere.R); } void CPHActivationShape::InitContact(dContact* c, bool& do_collide, u16, u16) diff --git a/src/xrPhysics/PHInterpolation.cpp b/src/xrPhysics/PHInterpolation.cpp index 6d0cfaa61f..cfbeafe840 100644 --- a/src/xrPhysics/PHInterpolation.cpp +++ b/src/xrPhysics/PHInterpolation.cpp @@ -7,17 +7,16 @@ extern CPHWorld* ph_world; - -CPHInterpolation::CPHInterpolation() +CPHInterpolation::CPHInterpolation(): + m_body(nullptr) { - m_body = NULL; - - // fTimeDelta=0.f; } void CPHInterpolation::SetBody(dBodyID body) { - if (!body) return; + if (!body) + return; + m_body = body; qPositions.fill_in(*((Fvector*)dBodyGetPosition(m_body))); const dReal* dQ = dBodyGetQuaternion(m_body); @@ -29,14 +28,12 @@ void CPHInterpolation::SetBody(dBodyID body) void CPHInterpolation::UpdatePositions() { VERIFY(m_body); - ///VERIFY2(dV_valid(dBodyGetPosition(m_body)),"invalid body position in update interpolation"); qPositions.push_back(*((Fvector*)dBodyGetPosition(m_body))); } void CPHInterpolation::UpdateRotations() { VERIFY(m_body); - //VERIFY2(dM_valid(dBodyGetRotation(m_body)),"invalid body rotation in update interpolation"); const dReal* dQ = dBodyGetQuaternion(m_body); Fquaternion fQ; fQ.set(-dQ[0], dQ[1], dQ[2], dQ[3]); @@ -45,34 +42,27 @@ void CPHInterpolation::UpdateRotations() void CPHInterpolation::InterpolatePosition(Fvector& pos) { - //if(!b_udating_positions) pos.lerp(qPositions[0], qPositions[1], ph_world->m_frame_time / fixed_step); - //else - //pos.lerp(*bkp_pos,bk_pos,ph_world->FrameTime(b_frame_mark)/fixed_step); } - void CPHInterpolation::InterpolateRotation(Fmatrix& rot) { Fquaternion q; float t = ph_world->m_frame_time / fixed_step; - VERIFY(t>=0.f && t<=1.f); - //if(!b_udating_rotations) + VERIFY(t >= 0.f && t <= 1.f); q.slerp(qRotations[0], qRotations[1], t); - // else - //q.slerp(*bkp_quat,bk_quat,t); rot.rotation(q); } void CPHInterpolation::ResetPositions() { - VERIFY2(dBodyStateValide(m_body), "Invalid body state"); + VERIFY2(dV_valid(dBodyGetPosition(m_body)), "Invalid body state: Position"); qPositions.fill_in(*((Fvector*)dBodyGetPosition(m_body))); } void CPHInterpolation::ResetRotations() { - VERIFY2(dBodyStateValide(m_body), "Invalid body state"); + VERIFY2(dV_valid(dBodyGetQuaternion(m_body)), "Invalid body state: Quaternion"); const dReal* dQ = dBodyGetQuaternion(m_body); Fquaternion fQ; fQ.set(-dQ[0], dQ[1], dQ[2], dQ[3]); @@ -81,24 +71,31 @@ void CPHInterpolation::ResetRotations() void CPHInterpolation::GetRotation(Fquaternion& q, u16 num) { - if (!m_body) return; + if (!m_body) + return; + q.set(qRotations[num]); } void CPHInterpolation::GetPosition(Fvector& p, u16 num) { - if (!m_body) return; + if (!m_body) + return; + p.set(qPositions[num]); } void CPHInterpolation::SetPosition(const Fvector& p, u16 num) { - if (!m_body) return; + if (!m_body) + return; + qPositions[num].set(p); } void CPHInterpolation::SetRotation(const Fquaternion& q, u16 num) { - if (!m_body) return; + if (!m_body) + return; qRotations[num] = q; } diff --git a/src/xrPhysics/PHObject.cpp b/src/xrPhysics/PHObject.cpp index 7fca03fa07..10e4cecf37 100644 --- a/src/xrPhysics/PHObject.cpp +++ b/src/xrPhysics/PHObject.cpp @@ -11,12 +11,14 @@ #endif extern CPHWorld* ph_world; -CPHObject::CPHObject() : ISpatial(g_SpatialSpacePhysic) +CPHObject::CPHObject() { + ISpatialOwner::spatial_create(g_SpatialSpacePhysic, this, STYPE_PHYSIC); + m_flags.flags = 0; - spatial.type |= STYPE_PHYSIC; m_island.Init(); m_check_count = 0; + m_flags.set(fl_collision_disable, FALSE); CPHCollideValidator::InitObject(*this); } @@ -79,7 +81,7 @@ void CPHObject::check_recently_deactivated() void CPHObject::spatial_move() { get_spatial_params(); - ISpatial::spatial_move(); + ISpatialOwner::spatial_move(); m_flags.set(st_dirty,TRUE); } @@ -114,8 +116,8 @@ void CPHObject::Collide() qResultIt i = result.begin(), e = result.end(); for (; i != e; ++i) { - CPHObject* obj2 = static_cast(*i); - if (!obj2 || obj2 == this || !obj2->m_flags.test(st_dirty)) continue; + CPHObject* obj2 = (*i)->dcast_CPHObject(); + if (obj2 == this || !obj2->m_flags.test(st_dirty)) continue; dGeomID motion_ray = ph_world->GetMotionRayGeom(); dGeomRayMotionSetGeom(motion_ray, I.dGeom()); dGeomRayMotionsSet(motion_ray, (const dReal*)from, (const dReal*)&dir, magnitude); @@ -125,7 +127,7 @@ void CPHObject::Collide() } CollideDynamics(); /////////////////////////////// - if (CPHCollideValidator::DoCollideStatic(*this)) CollideStatic(dSpacedGeom(), this); + if (CPHCollideValidator::DoCollideStatic(*this) && !m_flags.test(fl_collision_disable)) CollideStatic(dSpacedGeom(), this); m_flags.set(st_dirty,FALSE); } @@ -134,14 +136,14 @@ extern u32 g_dead_body_collision; void CPHObject::CollideDynamics() { - g_SpatialSpacePhysic->q_box(ph_world->r_spatial, 0, STYPE_PHYSIC, spatial.sphere.P, AABB); + g_SpatialSpacePhysic->q_box(ph_world->r_spatial, 0, STYPE_PHYSIC, SpatialComponent->spatial.sphere.P, AABB); qResultVec& result = ph_world->r_spatial; qResultIt i = result.begin(), e = result.end(); for (; i != e; ++i) { - CPHObject* obj2 = static_cast(*i); + CPHObject* obj2 = (*i)->dcast_CPHObject(); - if (!obj2 || obj2 == this || !obj2->m_flags.test(st_dirty)) continue; + if (obj2 == this || !obj2->m_flags.test(st_dirty) || m_flags.test(fl_collision_disable) || obj2->m_flags.test(fl_collision_disable)) continue; // Dead Body Collision if (obj2->m_flags.test(is_deadbody)) @@ -171,7 +173,7 @@ void CPHObject::reinit_single() qResultIt i = result.begin(), e = result.end(); for (; i != e; ++i) { - CPHObject* obj = static_cast(*i); + CPHObject* obj = (*i)->dcast_CPHObject(); obj->IslandReinit(); } result.clear_not_free(); @@ -242,18 +244,20 @@ void CPHObject::UnFreezeContent() void CPHObject::spatial_register() { get_spatial_params(); - ISpatial::spatial_register(); + ISpatialOwner::spatial_register(); m_flags.set(st_dirty,TRUE); } void CPHObject::collision_disable() { - ISpatial::spatial_unregister(); + spatial_unregister(); + m_flags.set(fl_collision_disable, TRUE); } void CPHObject::collision_enable() { - ISpatial::spatial_register(); + spatial_register(); + m_flags.set(fl_collision_disable, FALSE); } void CPHObject::Freeze() diff --git a/src/xrPhysics/PHObject.h b/src/xrPhysics/PHObject.h index 3a386ed1c9..b969566096 100644 --- a/src/xrPhysics/PHObject.h +++ b/src/xrPhysics/PHObject.h @@ -1,13 +1,14 @@ #pragma once -#ifndef CPHOBJECT -#define CPHOBJECT + #include "../xrcdb/ispatial.h" #include "PHItemList.h" #include "PHIsland.h" typedef u32 CLClassBits; typedef u32 CLBits; class ISpatial; -DEFINE_VECTOR(ISpatial*, qResultVec, qResultIt) + +using qResultVec = xr_vector; +using qResultIt = qResultVec::iterator; class CPHObject; class CPHUpdateObject; class CPHMoveStorage; @@ -17,8 +18,8 @@ typedef void CollideCallback(CPHObject* obj1, CPHObject* obj2, dGeomID o1, dGeom #ifdef DEBUG class IPhysicsShellHolder; #endif -class CPHObject : - public ISpatial +class CPHObject: + public ISpatialOwner { #ifdef DEBUG friend struct SPHObjDBGDraw; @@ -35,7 +36,8 @@ class CPHObject : st_net_interpolation =(1 << 3), fl_ray_motions =(1 << 4), st_recently_deactivated =(1 << 5), - is_deadbody =(1 << 6) + is_deadbody =(1 << 6), + fl_collision_disable =(1 << 7) }; CPHIsland m_island; @@ -140,9 +142,8 @@ virtual IPhysicsShellHolder *ref_object () =0; IC const CLBits& collide_bits() const { return m_collide_bits; } IC const _flags& collide_class_bits() const { return m_collide_class_bits; } void CollideDynamics(); + virtual CPHObject* dcast_CPHObject() override { return this; } }; DEFINE_PHITEM_LIST(CPHObject, PH_OBJECT_STORAGE, PH_OBJECT_I) - -#endif//CPHOBJECT diff --git a/src/xrPhysics/PHShell.cpp b/src/xrPhysics/PHShell.cpp index 233bdd4ed7..6cf31b1407 100644 --- a/src/xrPhysics/PHShell.cpp +++ b/src/xrPhysics/PHShell.cpp @@ -208,7 +208,7 @@ float CPHShell::getMass() void CPHShell::get_spatial_params() { - spatialParsFromDGeom((dGeomID)m_space, spatial.sphere.P, AABB, spatial.sphere.R); + spatialParsFromDGeom((dGeomID)m_space, SpatialComponent->spatial.sphere.P, AABB, SpatialComponent->spatial.sphere.R); } float CPHShell::getVolume() @@ -1819,10 +1819,10 @@ void CPHShell::SetAnimated(bool v) } -void CPHShell::AnimatorOnFrame() +void CPHShell::AnimatorOnFrame(bool calculate_bones) { VERIFY(PPhysicsShellAnimator()); - PPhysicsShellAnimator()->OnFrame(); + PPhysicsShellAnimator()->OnFrame(calculate_bones); } void CPHShell::SetScale(float scale) diff --git a/src/xrPhysics/PHShell.h b/src/xrPhysics/PHShell.h index 8ac36fc5de..f3e2aefb5d 100644 --- a/src/xrPhysics/PHShell.h +++ b/src/xrPhysics/PHShell.h @@ -273,7 +273,7 @@ class CPHShell : virtual void SmoothElementsInertia(float k); virtual void _BCL InterpolateGlobalTransform(Fmatrix* m); virtual void InterpolateGlobalPosition(Fvector* v); - virtual void AnimatorOnFrame(); + virtual void AnimatorOnFrame(bool calculate_bones = true); virtual void GetGlobalTransformDynamic(Fmatrix* m); virtual void GetGlobalPositionDynamic(Fvector* v); virtual Fmatrix& ObjectInRoot() { return m_object_in_root; } diff --git a/src/xrPhysics/PHSimpleCharacter.cpp b/src/xrPhysics/PHSimpleCharacter.cpp index 960f1ab2c6..e45b413cb2 100644 --- a/src/xrPhysics/PHSimpleCharacter.cpp +++ b/src/xrPhysics/PHSimpleCharacter.cpp @@ -593,7 +593,7 @@ void CPHSimpleCharacter::PhDataUpdate(dReal /**step/**/) } m_last_move.sub(cast_fv(dBodyGetPosition(m_body)), m_last_move); m_last_move.mul(1.f / fixed_step); - VERIFY2(dBodyStateValide(m_body), "WRONG BODYSTATE IN PhDataUpdate"); + VERIFY2(dV_valid(dBodyGetPosition(m_body)), "WRONG BODYSTATE IN PhDataUpdate"); if (PhOutOfBoundaries(cast_fv(dBodyGetPosition(m_body))))Disable(); VERIFY_BOUNDARIES(cast_fv(dBodyGetPosition(m_body)), phBoundaries, PhysicsRefObject()); m_body_interpolation.UpdatePositions(); @@ -624,7 +624,7 @@ void CPHSimpleCharacter::PhTune(dReal step) } #endif - bool b_good_graund = b_valide_ground_contact && m_ground_contact_normal[1] > M_SQRT1_2; + const bool b_good_graund = b_valide_ground_contact && m_ground_contact_normal[1] > M_SQRT1_2; dxGeomUserData* ud = dGeomGetUserData(m_wheel); if ((ud->pushing_neg || ud->pushing_b_neg) && !b_death_pos) @@ -1389,6 +1389,20 @@ void CPHSimpleCharacter::SafeAndLimitVelocity() dVectorSet(m_safe_position, dBodyGetPosition(m_body)); dVectorSet(m_safe_velocity, linear_velocity); + + // FX: Нахер всякие e-37 + if (fis_zero(m_safe_velocity[0])) + { + m_safe_velocity[0] = 0; + } + if (fis_zero(m_safe_velocity[1])) + { + m_safe_velocity[1] = 0; + } + if (fis_zero(m_safe_velocity[2])) + { + m_safe_velocity[2] = 0; + } } void CPHSimpleCharacter::SetObjectContactCallback(ObjectContactCallbackFun* callback) @@ -1786,7 +1800,7 @@ void CPHSimpleCharacter::set_State(const SPHNetState& state) void CPHSimpleCharacter::get_spatial_params() { - spatialParsFromDGeom((dGeomID)m_space, spatial.sphere.P, AABB, spatial.sphere.R); + spatialParsFromDGeom((dGeomID)m_space, SpatialComponent->spatial.sphere.P, AABB, SpatialComponent->spatial.sphere.R); } float CPHSimpleCharacter::FootRadius() @@ -1906,7 +1920,6 @@ void CPHSimpleCharacter::SCollisionDamageInfo::Reinit() //m_damege_contact; m_obj_id = u16(-1); - m_hit_callback = NULL; m_contact_velocity = 0; is_initiated = false; @@ -1948,7 +1961,16 @@ CElevatorState* CPHSimpleCharacter::ElevatorState() ICollisionHitCallback* CPHSimpleCharacter::HitCallback() const { - return m_collision_damage_info.m_hit_callback; + if (m_collision_damage_info.m_dmc_type != SCollisionDamageInfo::ctObject || + m_collision_damage_info.m_obj_id == u16(-1)) + return nullptr; + + CObject* obj = inl_ph_world().LevelObjects().net_Find(m_collision_damage_info.m_obj_id); + IPhysicsShellHolder* object = smart_cast(obj); + if (!object || object->ObjectGetDestroy()) + return nullptr; + + return object->ObjectGetCollisionHitCallback(); } const float resolve_depth = 0.05f; diff --git a/src/xrPhysics/PHSimpleCharacter.h b/src/xrPhysics/PHSimpleCharacter.h index cc5d3e6c88..49e8a33f21 100644 --- a/src/xrPhysics/PHSimpleCharacter.h +++ b/src/xrPhysics/PHSimpleCharacter.h @@ -39,7 +39,6 @@ class CPHSimpleCharacter : IC const Fvector& HitPos() const { return cast_fv(m_damege_contact.geom.pos); } void Reinit(); dContact m_damege_contact; - ICollisionHitCallback* m_hit_callback; u16 m_obj_id; float m_dmc_signum; diff --git a/src/xrPhysics/PHSimpleCharacterInline.h b/src/xrPhysics/PHSimpleCharacterInline.h index 369b3ebbbe..500628786d 100644 --- a/src/xrPhysics/PHSimpleCharacterInline.h +++ b/src/xrPhysics/PHSimpleCharacterInline.h @@ -123,17 +123,34 @@ void CPHSimpleCharacter::UpdateDynamicDamage(dContact* c, u16 obj_material_idx, #endif if (c_vel > m_collision_damage_info.m_contact_velocity) { - IPhysicsShellHolder* obj = bo1 ? retrieveRefObject(c->geom.g2) : retrieveRefObject(c->geom.g1); - VERIFY(obj); - if (obj && !obj->ObjectGetDestroy()) - { - m_collision_damage_info.m_contact_velocity = c_vel; - m_collision_damage_info.m_dmc_signum = bo1 ? 1.f : -1.f; - m_collision_damage_info.m_dmc_type = SCollisionDamageInfo::ctObject; - m_collision_damage_info.m_damege_contact = *c; - m_collision_damage_info.m_hit_callback = obj->ObjectGetCollisionHitCallback(); - m_collision_damage_info.m_obj_id = obj->ObjectID(); - } + IPhysicsShellHolder* obj = nullptr; + if (bo1) + { + if (c->geom.g2) + obj = retrieveRefObject(c->geom.g2); + } + else if (c->geom.g1) + obj = retrieveRefObject(c->geom.g1); + +#ifdef _MSC_VER + __try + { +#endif + if (obj && !obj->ObjectGetDestroy()) + { + m_collision_damage_info.m_contact_velocity = c_vel; + m_collision_damage_info.m_dmc_signum = bo1 ? 1.f : -1.f; + m_collision_damage_info.m_dmc_type = SCollisionDamageInfo::ctObject; + m_collision_damage_info.m_damege_contact = *c; + m_collision_damage_info.m_obj_id = obj->ObjectID(); + } +#ifdef _MSC_VER + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + // Stale geometry owner pointer. Ignore this collision source safely. + } +#endif } } diff --git a/src/xrPhysics/PHSplitedShell.cpp b/src/xrPhysics/PHSplitedShell.cpp index 2d18a849b0..28eb332ce8 100644 --- a/src/xrPhysics/PHSplitedShell.cpp +++ b/src/xrPhysics/PHSplitedShell.cpp @@ -19,8 +19,9 @@ void CPHSplitedShell::Collide() void CPHSplitedShell::get_spatial_params() { - spatialParsFromDGeom((dGeomID)m_space, spatial.sphere.P, AABB, spatial.sphere.R); - if (spatial.sphere.R > m_max_AABBradius) spatial.sphere.R = m_max_AABBradius; + spatialParsFromDGeom((dGeomID)m_space, SpatialComponent->spatial.sphere.P, AABB, SpatialComponent->spatial.sphere.R); + if (SpatialComponent->spatial.sphere.R > m_max_AABBradius) + SpatialComponent->spatial.sphere.R = m_max_AABBradius; } void CPHSplitedShell::DisableObject() diff --git a/src/xrPhysics/PHStaticGeomShell.cpp b/src/xrPhysics/PHStaticGeomShell.cpp index f9ef47856a..06a166151b 100644 --- a/src/xrPhysics/PHStaticGeomShell.cpp +++ b/src/xrPhysics/PHStaticGeomShell.cpp @@ -16,7 +16,7 @@ void CPHStaticGeomShell::get_spatial_params() { Fvector AABB; - spatialParsFromDGeom(dSpacedGeometry(), spatial.sphere.P, AABB, spatial.sphere.R); + spatialParsFromDGeom(dSpacedGeometry(), SpatialComponent->spatial.sphere.P, AABB, SpatialComponent->spatial.sphere.R); } void CPHStaticGeomShell::PhDataUpdate(dReal step) @@ -44,7 +44,7 @@ void CPHStaticGeomShell::Deactivate() CPHStaticGeomShell::CPHStaticGeomShell() { - spatial.type |= STYPE_PHYSIC; + SpatialComponent->spatial.type |= STYPE_PHYSIC; } void _BCL cb(CBoneInstance* B) diff --git a/src/xrPhysics/PHWorld.cpp b/src/xrPhysics/PHWorld.cpp index 5b5e890ba5..dfba1a1434 100644 --- a/src/xrPhysics/PHWorld.cpp +++ b/src/xrPhysics/PHWorld.cpp @@ -143,7 +143,6 @@ CPHWorld::CPHWorld(): // IPHWorldUpdateCallbck *_update_callback m_update_callback(&empty_update_callback), m_default_contact_shotmark(0), m_default_character_contact_shotmark(0), - physics_step_time_callback(0), m_object_space(0), m_level_objects(0), m_device(0) @@ -279,6 +278,7 @@ void CPHWorld::SetGravity(float g) void CPHWorld::OnFrame() { + PROF_EVENT("CPHWorld::OnFrame"); // Msg ("------------- physics: %d / %d",u32(Device.dwFrame),u32(m_steps_num)); //просчитать полет пуль /* @@ -301,10 +301,10 @@ void CPHWorld::OnFrame() ////////////////////////////////////////////////////////////////////////////// //static dReal frame_time=0.f; -static u32 start_time = 0; void CPHWorld::Step() { + PROF_EVENT("CPHWorld::Step"); #ifdef DEBUG debug_output().dbg_reused_queries_per_step() =0 ; debug_output().dbg_new_queries_per_step() =0 ; @@ -457,16 +457,11 @@ void CPHWorld::Step() ContactFeedBacks.empty(); ContactEffectors.empty(); - - if (physics_step_time_callback) - { - physics_step_time_callback(start_time, start_time + u32(fixed_step * 1000)); - start_time += u32(fixed_step * 1000); - }; } void CPHWorld::StepTouch() { + PROF_EVENT("CPHWorld::StepTouch"); PH_OBJECT_I i_object; for (i_object = m_objects.begin(); m_objects.end() != i_object;) { @@ -549,7 +544,6 @@ void CPHWorld::FrameStep(dReal step) #endif b_processing = true; - start_time = Device().dwTimeGlobal; // - u32(m_frame_time*1000); if (ph_console::g_bDebugDumpPhysicsStep && it_number > 20) Msg("!!!TOO MANY PHYSICS STEPS PER FRAME = %d !!!", it_number); for (UINT i = 0; i < it_number; ++i) diff --git a/src/xrPhysics/PHWorld.h b/src/xrPhysics/PHWorld.h index 254985c485..869f9a5c00 100644 --- a/src/xrPhysics/PHWorld.h +++ b/src/xrPhysics/PHWorld.h @@ -61,9 +61,9 @@ class CPHWorld : public pureFrame, IPHWorldUpdateCallbck* m_update_callback; CObjectSpace* m_object_space; CObjectList* m_level_objects; - CRenderDeviceBase* m_device; ; + CRenderDeviceBase* m_device; public: - xr_vector r_spatial; + xr_vector r_spatial; public: u64 m_steps_num; private: @@ -79,7 +79,6 @@ class CPHWorld : public pureFrame, private: ContactCallbackFun* m_default_contact_shotmark; ContactCallbackFun* m_default_character_contact_shotmark; - PhysicsStepTimeCallback* physics_step_time_callback; public: CPHWorld(); @@ -155,7 +154,6 @@ class CPHWorld : public pureFrame, private: void StepNumIterations(int num_it); iphysics_scripted& get_scripted() { return *this; } - void set_step_time_callback(PhysicsStepTimeCallback* cb) { physics_step_time_callback = cb; } void set_update_callback(IPHWorldUpdateCallbck* cb) { diff --git a/src/xrPhysics/Physics.cpp b/src/xrPhysics/Physics.cpp index f5a4bf832f..8479b1370c 100644 --- a/src/xrPhysics/Physics.cpp +++ b/src/xrPhysics/Physics.cpp @@ -284,6 +284,7 @@ IC static int CollideIntoGroup(dGeomID o1, dGeomID o2, dJointGroupID jointGroup, void NearCallback(CPHObject* obj1, CPHObject* obj2, dGeomID o1, dGeomID o2) { + PROF_EVENT("CollideDynamic"); CPHIsland* island1 = obj1->DActiveIsland(); CPHIsland* island2 = obj2->DActiveIsland(); obj2->near_callback(obj1); @@ -298,6 +299,7 @@ void NearCallback(CPHObject* obj1, CPHObject* obj2, dGeomID o1, dGeomID o2) void CollideStatic(dGeomID o2, CPHObject* obj2) { + PROF_EVENT("CollideStatic"); CPHIsland* island2 = obj2->DActiveIsland(); CollideIntoGroup(ph_world->GetMeshGeom(), o2, ContactGroup, island2, island2->MaxJoints()); } diff --git a/src/xrPhysics/PhysicsShell.cpp b/src/xrPhysics/PhysicsShell.cpp index b00d3c5340..4aa35f8ac7 100644 --- a/src/xrPhysics/PhysicsShell.cpp +++ b/src/xrPhysics/PhysicsShell.cpp @@ -88,7 +88,7 @@ void fix_bones(LPCSTR fixed_bones, CPhysicsShell* shell) string64 fixed_bone; _GetItem(fixed_bones, i, fixed_bone); u16 fixed_bone_id = pKinematics->LL_BoneID(fixed_bone); - R_ASSERT2(BI_NONE!=fixed_bone_id, "wrong fixed bone") ; + R_ASSERT2(BI_NONE != fixed_bone_id, make_string("wrong fixed bone [%s] for object with visual [%s]", fixed_bone, pKinematics->getDebugName().c_str()).c_str()); CPhysicsElement* E = shell->get_Element(fixed_bone_id); if (E) E->Fix(); @@ -109,7 +109,7 @@ CPhysicsShell* P_build_Shell(IPhysicsShellHolder* obj, bool not_active_state, BO string64 fixed_bone; _GetItem(fixed_bones, i, fixed_bone); u16 fixed_bone_id = pKinematics->LL_BoneID(fixed_bone); - R_ASSERT2(BI_NONE!=fixed_bone_id, "wrong fixed bone") ; + R_ASSERT2(BI_NONE != fixed_bone_id, make_string("wrong fixed bone [%s] for object with visual [%s]", fixed_bone, pKinematics->getDebugName().c_str()).c_str()); p_bone_map->insert(mk_pair(fixed_bone_id, physicsBone())); } diff --git a/src/xrPhysics/PhysicsShell.h b/src/xrPhysics/PhysicsShell.h index 5e99405d87..96879d72fa 100644 --- a/src/xrPhysics/PhysicsShell.h +++ b/src/xrPhysics/PhysicsShell.h @@ -353,7 +353,7 @@ class XRPHYSICS_API CPhysicsShell : virtual void CreateShellAnimator(CInifile const* ini, LPCSTR section) = 0; virtual void SetIgnoreAnimated() = 0; // virtual bool Animated () = 0; - virtual void AnimatorOnFrame() = 0; + virtual void AnimatorOnFrame(bool calculate_bones = true) = 0; virtual void SetSmall() = 0; virtual void SetIgnoreSmall() = 0; virtual bool isFractured() = 0; diff --git a/src/xrPhysics/PhysicsShellAnimator.cpp b/src/xrPhysics/PhysicsShellAnimator.cpp index 83dae6c764..983d320039 100644 --- a/src/xrPhysics/PhysicsShellAnimator.cpp +++ b/src/xrPhysics/PhysicsShellAnimator.cpp @@ -81,7 +81,7 @@ void CPhysicsShellAnimator::CreateJoint(CPHElement* e) m_bones_data.push_back(PhysicsShellAnimatorBoneDataC); } -void CPhysicsShellAnimator::OnFrame() +void CPhysicsShellAnimator::OnFrame(bool calculate_bones) { m_pPhysicsShell->Enable(); @@ -94,8 +94,11 @@ void CPhysicsShellAnimator::OnFrame() #pragma todo("reset callback?") B.set_callback(B.callback_type(), 0, B.callback_param(),FALSE); - m_pPhysicsShell->PKinematics()->CalculateBones_Invalidate(); - m_pPhysicsShell->PKinematics()->CalculateBones(TRUE); + if (calculate_bones) + { + m_pPhysicsShell->PKinematics()->CalculateBones_Invalidate(); + m_pPhysicsShell->PKinematics()->CalculateBones(TRUE); + } target_obj_posFmatrixS.mul_43(m_StartXFORM, B.mTransform); dQuaternion target_obj_quat_dQuaternionS; @@ -104,7 +107,11 @@ void CPhysicsShellAnimator::OnFrame() dQfromR(target_obj_quat_dQuaternionS, ph_mat); Fvector mc; i->m_element->CPHGeometryOwner::get_mc_vs_transform(mc, target_obj_posFmatrixS); - dJointSetFixedQuaternionPos(i->m_anim_fixed_dJointID, target_obj_quat_dQuaternionS, &mc.x); + + Fvector4 ODEVect; + ODEVect.set(mc.x, mc.y, mc.z); + + dJointSetFixedQuaternionPos(i->m_anim_fixed_dJointID, target_obj_quat_dQuaternionS, &ODEVect.x); } //(*(m_pPhysicsShell->Elements().begin()))->PhysicsRefObject()->XFORM().set(m_pPhysicsShell->mXFORM); } diff --git a/src/xrPhysics/PhysicsShellAnimator.h b/src/xrPhysics/PhysicsShellAnimator.h index 6bbf9a61b4..b8329cb544 100644 --- a/src/xrPhysics/PhysicsShellAnimator.h +++ b/src/xrPhysics/PhysicsShellAnimator.h @@ -16,5 +16,5 @@ class CPhysicsShellAnimator public: CPhysicsShellAnimator(CPhysicsShell* _pPhysicsShell, CInifile const* ini, LPCSTR section); ~CPhysicsShellAnimator(); - void OnFrame(); + void OnFrame(bool calculate_bones = true); }; diff --git a/src/xrPhysics/collisiondamagereceiver.cpp b/src/xrPhysics/collisiondamagereceiver.cpp index 1034adbafc..df3d0c6529 100644 --- a/src/xrPhysics/collisiondamagereceiver.cpp +++ b/src/xrPhysics/collisiondamagereceiver.cpp @@ -26,12 +26,12 @@ void DamageReceiverCollisionCallback(bool& do_colide, bool bo1, dContact& c, SGa u16 source_id = o_damager ? o_damager->ObjectID() : u16(-1); //CPHCollisionDamageReceiver *dr = static_cast( o_self )->PHCollisionDamageReceiver(); - ICollisionDamageReceiver* dr = (o_self)->ObjectPhCollisionDamageReceiver(); + ICollisionDamageReceiver* dr = o_self ? (o_self)->ObjectPhCollisionDamageReceiver() : nullptr; VERIFY2(dr, "wrong callback"); float damager_material_factor = material_damager->fBounceDamageFactor; - if (ud_damager && ud_damager->ph_object && + if (o_damager && ud_damager && ud_damager->ph_object && ud_damager->ph_object->CastType() == CPHObject::tpCharacter) o_damager->BonceDamagerCallback(damager_material_factor); @@ -47,8 +47,8 @@ void DamageReceiverCollisionCallback(bool& do_colide, bool bo1, dContact& c, SGa pos.sub(*(Fvector*)c.geom.pos, *(Fvector*)dGeomGetPosition(bo1 ? c.geom.g1 : c.geom.g2)); //it is not true pos in bone space - dr->CollisionHit(source_id, ud_self->bone_id, E_NL(b1, b2, c.geom.normal) * damager_material_factor / dfs, dir, - pos); + if (dr) + dr->CollisionHit(source_id, ud_self->bone_id, E_NL(b1, b2, c.geom.normal) * damager_material_factor / dfs, dir, pos); } @@ -57,8 +57,8 @@ void BreakableObjectCollisionCallback(bool&/**do_colide/**/, bool bo1, dContact& { dxGeomUserData* usr_data_1 = retrieveGeomUserData(c.geom.g1); dxGeomUserData* usr_data_2 = retrieveGeomUserData(c.geom.g2); - VERIFY(usr_data_1); - VERIFY(usr_data_2); + if (!usr_data_1) return; + if (!usr_data_2) return; //CBreakableObject* this_object = 0; ICollisionDamageReceiver* damag_receiver = 0; @@ -68,19 +68,19 @@ void BreakableObjectCollisionCallback(bool&/**do_colide/**/, bool bo1, dContact& if (bo1) { - VERIFY(usr_data_1->ph_ref_object); + if (!usr_data_1->ph_ref_object) return; damag_receiver = usr_data_1->ph_ref_object->ObjectPhCollisionDamageReceiver(); body = dGeomGetBody(c.geom.g2); norm_sign = -1.f; } else { - VERIFY(usr_data_2->ph_ref_object); + if (!usr_data_2->ph_ref_object) return; damag_receiver = usr_data_2->ph_ref_object->ObjectPhCollisionDamageReceiver(); body = dGeomGetBody(c.geom.g1); norm_sign = 1.f; } - VERIFY(damag_receiver); + if (!damag_receiver) return; /* diff --git a/src/xrPhysics/params.cpp b/src/xrPhysics/params.cpp index 6742c3e2fe..6998647234 100644 --- a/src/xrPhysics/params.cpp +++ b/src/xrPhysics/params.cpp @@ -2,6 +2,7 @@ #include "params.h" float object_damage_factor = 1.f; //times increace damage from object collision + void LoadParams() { if (!pSettings) diff --git a/src/xrPhysics/stdafx.h b/src/xrPhysics/stdafx.h index 5d72aabd3a..aa92ab0ed5 100644 --- a/src/xrPhysics/stdafx.h +++ b/src/xrPhysics/stdafx.h @@ -22,6 +22,8 @@ #include "xrPhysics.h" +#include "../xrCore/profiler.h" + #include "../include/xrapi/xrapi.h" #ifdef DEBUG #include "d3d9types.h" diff --git a/src/xrPhysics/xrPhysics.vcxproj b/src/xrPhysics/xrPhysics.vcxproj index 4acca23998..2686c0123b 100644 --- a/src/xrPhysics/xrPhysics.vcxproj +++ b/src/xrPhysics/xrPhysics.vcxproj @@ -13,6 +13,10 @@ Release x64 + + VerifiedDX11ASAN + x64 + VerifiedDX11 x64 @@ -49,6 +53,14 @@ false x64 + + StaticLibrary + v143 + MultiByte + false + x64 + true + StaticLibrary v143 @@ -81,6 +93,11 @@ + + + + + @@ -110,6 +127,11 @@ $(xrGameDir)bin_dbg\$(Platform)\$(Configuration)\ $(xrIntDir)$(ProjectName)\ + + false + $(xrGameDir)bin_dbg\$(Platform)\$(Configuration)\ + $(xrIntDir)$(ProjectName)\ + false $(xrGameDir)bin_dbg\$(Platform)\$(Configuration)\ @@ -164,7 +186,7 @@ false false $(xrSdkDir)include;%(AdditionalIncludeDirectories) - USE_VERIFY_IN_RELEASE;WIN32;NDEBUG;_WINDOWS;dSINGLE;_USRDLL;XRPHYSICS_EXPORTS;MSVC;_SECURE_SCL=0;%(PreprocessorDefinitions) + XRCORE_PROFILER;USE_VERIFY_IN_RELEASE;WIN32;NDEBUG;_WINDOWS;dSINGLE;_USRDLL;XRPHYSICS_EXPORTS;MSVC;_SECURE_SCL=0;%(PreprocessorDefinitions) NotSet Use EditAndContinue @@ -199,7 +221,7 @@ false false $(xrSdkDir)include;%(AdditionalIncludeDirectories) - USE_VERIFY_IN_RELEASE;WIN32;NDEBUG;_WINDOWS;dSINGLE;_USRDLL;XRPHYSICS_EXPORTS;MSVC;_SECURE_SCL=0;%(PreprocessorDefinitions) + XRCORE_PROFILER;USE_VERIFY_IN_RELEASE;WIN32;NDEBUG;_WINDOWS;dSINGLE;_USRDLL;XRPHYSICS_EXPORTS;MSVC;_SECURE_SCL=0;%(PreprocessorDefinitions) NotSet Use EditAndContinue @@ -224,6 +246,41 @@ true + + + Disabled + Disabled + false + Neither + false + false + false + $(xrSdkDir)include;%(AdditionalIncludeDirectories) + XRCORE_PROFILER;USE_VERIFY_IN_RELEASE;_DISABLE_VECTOR_ANNOTATION;_DISABLE_STRING_ANNOTATION;WIN32;NDEBUG;_WINDOWS;dSINGLE;_USRDLL;XRPHYSICS_EXPORTS;MSVC;_SECURE_SCL=0;%(PreprocessorDefinitions) + NotSet + Use + ProgramDatabase + USE_LUAJIT_ONE + true + Level4 + false + MultiThreadedDLL + false + stdcpp17 + true + + + $(xrSdkDir)libraries;$(xrLibDir);%(AdditionalLibraryDirectories) + NotSet + true + true + true + Default + false + $(xrLibDir)$(TargetName).lib + true + + MaxSpeed @@ -350,6 +407,7 @@ Create Create Create + Create Create Create @@ -357,6 +415,7 @@ true true true + true true true diff --git a/src/xrServerEntities/InfoPortionDefs.h b/src/xrServerEntities/InfoPortionDefs.h index 92d30a650b..62f80a12d2 100644 --- a/src/xrServerEntities/InfoPortionDefs.h +++ b/src/xrServerEntities/InfoPortionDefs.h @@ -4,11 +4,14 @@ typedef shared_str INFO_DATA; DEFINE_VECTOR(INFO_DATA, KNOWN_INFO_VECTOR, KNOWN_INFO_VECTOR_IT); +namespace IDPredstatic +{ + static shared_str element; +}; + class CFindByIDPred { public: - CFindByIDPred(shared_str element_to_find) { element = element_to_find; } - IC bool operator ()(const INFO_DATA& data) const { return data == element; } -private: - shared_str element; + CFindByIDPred(shared_str& element_to_find) { IDPredstatic::element = element_to_find; } + IC bool operator ()(const INFO_DATA& data) const { return data == IDPredstatic::element; } }; diff --git a/src/xrServerEntities/ItemListTypes.h b/src/xrServerEntities/ItemListTypes.h index 2297383b8e..3ec13cb3bc 100644 --- a/src/xrServerEntities/ItemListTypes.h +++ b/src/xrServerEntities/ItemListTypes.h @@ -12,8 +12,8 @@ class ListItem int type; void* item; public: - typedef fastdelegate::FastDelegate1 TOnListItemFocused; - typedef fastdelegate::FastDelegate1 TOnClick; + typedef xr_delegate TOnListItemFocused; + typedef xr_delegate TOnClick; TOnClick OnClickEvent; TOnListItemFocused OnItemFocused; TOnDrawThumbnail OnDrawThumbnail; diff --git a/src/xrServerEntities/PropertiesListTypes.h b/src/xrServerEntities/PropertiesListTypes.h index 6ea1663bf4..61687c9784 100644 --- a/src/xrServerEntities/PropertiesListTypes.h +++ b/src/xrServerEntities/PropertiesListTypes.h @@ -53,8 +53,8 @@ DEFINE_VECTOR(PropItem*, PropItemVec, PropItemIt); //------------------------------------------------------------------------------ #include "../xrcore/ChooseTypes.H" //------------------------------------------------------------------------------ -typedef fastdelegate::FastDelegate2 TOnDrawTextEvent; -typedef fastdelegate::FastDelegate1 TOnClick; +typedef xr_delegate TOnDrawTextEvent; +typedef xr_delegate TOnClick; //------------------------------------------------------------------------------ @@ -68,7 +68,7 @@ class PropValue u32 tag; public: // base events - typedef fastdelegate::FastDelegate1 TOnChange; + typedef xr_delegate TOnChange; TOnChange OnChangeEvent; public: PropValue(): tag(0), m_Owner(0), OnChangeEvent(0) { ; } @@ -100,8 +100,8 @@ class CustomValue : public PropValue TYPE init_value; TYPE* value; public: - typedef fastdelegate::FastDelegate2 TOnBeforeEditEvent; - typedef fastdelegate::FastDelegate2 TOnAfterEditEvent; + typedef xr_delegate TOnBeforeEditEvent; + typedef xr_delegate TOnAfterEditEvent; TOnBeforeEditEvent OnBeforeEditEvent; TOnAfterEditEvent OnAfterEditEvent; public: @@ -148,7 +148,7 @@ class PropItem TProperties* m_Owner; // events public: - typedef fastdelegate::FastDelegate1 TOnPropItemFocused; + typedef xr_delegate TOnPropItemFocused; TOnDrawTextEvent OnDrawTextEvent; TOnPropItemFocused OnItemFocused; TOnClick OnClickEvent; @@ -315,8 +315,8 @@ class CanvasValue : public PropValue { shared_str value; public: - typedef fastdelegate::FastDelegate3 TOnTestEqual; - typedef fastdelegate::FastDelegate3 TOnDrawCanvasEvent; + typedef xr_delegate TOnTestEqual; + typedef xr_delegate TOnDrawCanvasEvent; public: int height; TOnTestEqual OnTestEqual; @@ -343,7 +343,7 @@ class ButtonValue : public PropValue public: RStringVec value; int btn_num; - typedef fastdelegate::FastDelegate3 TOnBtnClick; + typedef xr_delegate TOnBtnClick; TOnBtnClick OnBtnClickEvent; enum @@ -392,7 +392,7 @@ IC bool operator ==(const xr_shortcut& A, const xr_shortcut& B) { return !!A.sim class ShortcutValue : public CustomValue { public: - typedef fastdelegate::FastDelegate3 TOnValidateResult; + typedef xr_delegate TOnValidateResult; TOnValidateResult OnValidateResultEvent; public: ShortcutValue(TYPE* val): CustomValue(val) @@ -454,8 +454,8 @@ class CTextValue : public PropValue public: LPSTR value; public: - typedef fastdelegate::FastDelegate2 TOnBeforeEditEvent; - typedef fastdelegate::FastDelegate2 TOnAfterEditEvent; + typedef xr_delegate TOnBeforeEditEvent; + typedef xr_delegate TOnAfterEditEvent; TOnBeforeEditEvent OnBeforeEditEvent; TOnAfterEditEvent OnAfterEditEvent; public: @@ -503,7 +503,7 @@ class ChooseValue : public RTextValue u32 m_ChooseFlags; shared_str m_StartPath; ChooseItemVec* m_Items; - typedef fastdelegate::FastDelegate1 TOnChooseValueFill; + typedef xr_delegate TOnChooseValueFill; TOnChooseValueFill OnChooseFillEvent; TOnDrawThumbnail OnDrawThumbnailEvent; void* m_FillParam; diff --git a/src/xrServerEntities/alife_human_brain.cpp b/src/xrServerEntities/alife_human_brain.cpp index f1e608c005..cfc15bc9e2 100644 --- a/src/xrServerEntities/alife_human_brain.cpp +++ b/src/xrServerEntities/alife_human_brain.cpp @@ -74,11 +74,8 @@ CALifeHumanBrain::~CALifeHumanBrain() void CALifeHumanBrain::on_state_write(NET_Packet& packet) { - if (packet.inistream == NULL) - { - save_data(m_cpEquipmentPreferences, packet); - save_data(m_cpMainWeaponPreferences, packet); - } + save_data(m_cpEquipmentPreferences, packet); + save_data(m_cpMainWeaponPreferences, packet); } void CALifeHumanBrain::on_state_read(NET_Packet& packet) @@ -113,9 +110,6 @@ void CALifeHumanBrain::on_state_read(NET_Packet& packet) load_data(temp, packet); } - if (packet.inistream == NULL) - { - load_data(m_cpEquipmentPreferences, packet); - load_data(m_cpMainWeaponPreferences, packet); - } + load_data(m_cpEquipmentPreferences, packet); + load_data(m_cpMainWeaponPreferences, packet); } diff --git a/src/xrServerEntities/character_info.h b/src/xrServerEntities/character_info.h index 4fac1f9661..44975e15e3 100644 --- a/src/xrServerEntities/character_info.h +++ b/src/xrServerEntities/character_info.h @@ -122,6 +122,8 @@ class CCharacterInfo : public CSharedClass const CHARACTER_REPUTATION& Reputation() const { return m_CurrentReputation; } float Sympathy() const { return m_Sympathy; } void SetSympathy(float sympathy) { m_Sympathy = sympathy; } + shared_str GetCharacterId() const { return data()->m_CharacterId; } + shared_str GetSpecificCharacterId() const { return m_SpecificCharacterId; } //доступут только у InventoryOwner protected: diff --git a/src/xrServerEntities/object_destroyer.h b/src/xrServerEntities/object_destroyer.h index 8b75b3e15e..9b0bacca91 100644 --- a/src/xrServerEntities/object_destroyer.h +++ b/src/xrServerEntities/object_destroyer.h @@ -120,8 +120,8 @@ struct CDestroyer template IC static void delete_data(T& data) { - T::iterator I = data.begin(); - T::iterator E = data.end(); + auto I = data.begin(); + auto E = data.end(); for (; I != E; ++I) CDestroyer::delete_data(*I); data.clear(); diff --git a/src/xrServerEntities/script_engine.cpp b/src/xrServerEntities/script_engine.cpp index 30392b3710..2a1bc9c838 100644 --- a/src/xrServerEntities/script_engine.cpp +++ b/src/xrServerEntities/script_engine.cpp @@ -15,6 +15,7 @@ #include "script_storage.h" #include #include +#include #ifdef USE_DEBUGGER # ifndef USE_LUA_STUDIO @@ -141,6 +142,10 @@ CScriptEngine::CScriptEngine() m_last_no_file_length = 0; *m_last_no_file = 0; +#ifdef USE_LUA_FUNCTOR_CACHE + m_cache_valid = true; +#endif + #ifdef USE_DEBUGGER # ifndef USE_LUA_STUDIO m_scriptDebugger = NULL; @@ -153,6 +158,11 @@ CScriptEngine::CScriptEngine() CScriptEngine::~CScriptEngine() { + +#ifdef USE_LUA_FUNCTOR_CACHE + m_cache_valid = false; +#endif + while (!m_script_processes.empty()) remove_script_process(m_script_processes.begin()->first); @@ -365,7 +375,7 @@ void CScriptEngine::setup_auto_load() } extern void export_classes(lua_State* L); -extern xr_unordered_map> unlocalizers; +extern xr_unordered_map> unlocalizers; extern bool unlocalizerPassed; void CScriptEngine::init() @@ -376,10 +386,15 @@ void CScriptEngine::init() m_lua_studio_world->remove (lua()); #endif // #ifdef USE_LUA_STUDIO + // Invalidate functor cache as the Lua state is being recreated +#ifdef USE_LUA_FUNCTOR_CACHE + invalidate_functor_cache(); +#endif + CScriptStorage::reinit(); #ifdef USE_LUA_STUDIO - if (m_lua_studio_world || strstr(Core.Params, "-lua_studio")) { + if (m_lua_studio_world || Core.ParamsData.test(ECoreParams::lua_studio) { if (!lua_studio_connected) try_connect_to_debugger (); else { @@ -395,6 +410,7 @@ void CScriptEngine::init() #endif // #ifdef USE_LUA_STUDIO ::luabind::open(lua()); + ::luabind::bind_class_info(lua()); setup_callbacks(); export_classes(lua()); setup_auto_load(); @@ -427,8 +443,12 @@ void CScriptEngine::init() load_common_scripts(); #endif m_stack_level = lua_gettop(lua()); + +#ifdef USE_LUA_FUNCTOR_CACHE + m_cache_valid = true; +#endif - if (strstr(Core.Params, "-ldbg")) { + if (strstr(Core.Params, "-ldbg")) { CScriptStorage::DebuggerAttach(); } } @@ -506,7 +526,7 @@ void CScriptEngine::process_file_if_exists(LPCSTR file_name, bool warn_if_not_ex return; } //#ifndef MASTER_GOLD - if (strstr(Core.Params, "-dbg")) + if (Core.isDebug()) Msg("* loading script %s", S1); //#endif // MASTER_GOLD m_reload_modules = false; diff --git a/src/xrServerEntities/script_engine.h b/src/xrServerEntities/script_engine.h index e01aa610d9..9b9ce17434 100644 --- a/src/xrServerEntities/script_engine.h +++ b/src/xrServerEntities/script_engine.h @@ -14,6 +14,14 @@ #include "associative_vector.h" #include "script_storage.h" +#define USE_LUA_FUNCTOR_CACHE + +#ifdef USE_LUA_FUNCTOR_CACHE +#include +#include +#include <_global_functions.h> +#endif + //AVO: lua re-org #include "lua.hpp" /*extern "C" { @@ -73,6 +81,46 @@ class CScriptEngine : public CScriptStorage string128 m_last_no_file; u32 m_last_no_file_length; +#ifdef USE_LUA_FUNCTOR_CACHE + + // Functor cache + struct FunctorCacheKey + { + xr_string function_name; + size_t result_type_hash; + + bool operator<(const FunctorCacheKey& other) const + { + int name_cmp = xr_strcmp(function_name.c_str(), other.function_name.c_str()); + if (name_cmp != 0) + return name_cmp < 0; + return result_type_hash < other.result_type_hash; + } + + bool operator==(const FunctorCacheKey& other) const + { + return result_type_hash == other.result_type_hash && function_name == other.function_name; + } + }; + + struct FunctorCacheKeyHash + { + size_t operator()(const FunctorCacheKey& s) const noexcept + { + size_t h1 = xr_hash()(s.function_name.c_str()); + size_t h2 = s.result_type_hash; + return hash_combine(0, h1, h2); + } + }; + + typedef xr_unordered_map FunctorCache; + FunctorCache m_functor_cache; + +public: + bool m_cache_valid; + void invalidate_functor_cache(); +#endif + bool no_file_exists(LPCSTR file_name, u32 string_length); void add_no_file(LPCSTR file_name, u32 string_length); diff --git a/src/xrServerEntities/script_engine_export.cpp b/src/xrServerEntities/script_engine_export.cpp index 9af7c94bd3..8728df87a2 100644 --- a/src/xrServerEntities/script_engine_export.cpp +++ b/src/xrServerEntities/script_engine_export.cpp @@ -263,6 +263,7 @@ void export_classes (lua_State *L) CAntirad::script_register(L); CInventoryItem::script_register(L); gamespy_gp_profile::script_register(L); + CMapManager::script_register(L); CMedkit::script_register(L); player_hud::script_register(L); script_attachment::script_register(L); diff --git a/src/xrServerEntities/script_engine_inline.h b/src/xrServerEntities/script_engine_inline.h index 003344ed1a..b53822ef6a 100644 --- a/src/xrServerEntities/script_engine_inline.h +++ b/src/xrServerEntities/script_engine_inline.h @@ -44,15 +44,61 @@ IC void CScriptEngine::parse_script_namespace(LPCSTR function_to_call, LPSTR nam } } +#ifdef USE_LUA_FUNCTOR_CACHE +extern BOOL lua_use_functor_cache; +extern BOOL g_bootComplete; +IC void CScriptEngine::invalidate_functor_cache() +{ + m_functor_cache.clear(); + m_cache_valid = false; +} +#endif // USE_LUA_FUNCTOR_CACHE + template IC bool CScriptEngine::functor(LPCSTR function_to_call, ::luabind::functor<_result_type>& lua_function) { + +#ifdef USE_LUA_FUNCTOR_CACHE + // Check if cache is valid + if (!m_cache_valid) + { + invalidate_functor_cache(); + } + else if (lua_use_functor_cache && g_bootComplete) + { + // PROF_EVENT("CScriptEngine::functor cached"); + + // Create cache key + FunctorCacheKey key{ function_to_call, typeid(_result_type).hash_code() }; + + // Try to find in cache + auto it = m_functor_cache.find(key); + if (it != m_functor_cache.end()) + { + lua_function = ::luabind::object_cast<::luabind::functor<_result_type>>(it->second); + return true; + } + } +#endif + + // PROF_EVENT("CScriptEngine::functor"); + + // Not in cache or invalid, create new entry ::luabind::object object; if (!function_object(function_to_call, object)) return (false); lua_function = ::luabind::object_cast<::luabind::functor<_result_type>>(object); +#ifdef USE_LUA_FUNCTOR_CACHE + // Store in cache + if (lua_use_functor_cache && m_cache_valid && g_bootComplete) + { + FunctorCacheKey key{ function_to_call, typeid(_result_type).hash_code() }; + m_functor_cache.insert({ key, object }); + } +#endif + return (true); } diff --git a/src/xrServerEntities/script_engine_script.cpp b/src/xrServerEntities/script_engine_script.cpp index 2d23b21318..1c15f87016 100644 --- a/src/xrServerEntities/script_engine_script.cpp +++ b/src/xrServerEntities/script_engine_script.cpp @@ -67,7 +67,7 @@ void PrintStack() void FlushLogs() { //#ifdef DEBUG - FlushLog(); + xrLogger::FlushLog(); #ifdef LUA_DEBUG_PRINT //DEBUG ai().script_engine().flush_log(); #endif // DEBUG diff --git a/src/xrServerEntities/script_ini_file_script.cpp b/src/xrServerEntities/script_ini_file_script.cpp index a904a1233a..f53997ec32 100644 --- a/src/xrServerEntities/script_ini_file_script.cpp +++ b/src/xrServerEntities/script_ini_file_script.cpp @@ -125,7 +125,7 @@ int get_modded_exes_version() { } LPCSTR get_modded_exes_name() { - shared_str result = "Modded Exes"; + shared_str result = "Modded Exes MT-TEST"; return result.c_str(); } diff --git a/src/xrServerEntities/script_process.cpp b/src/xrServerEntities/script_process.cpp index 7daf32c5ca..add4886617 100644 --- a/src/xrServerEntities/script_process.cpp +++ b/src/xrServerEntities/script_process.cpp @@ -60,6 +60,7 @@ void CScriptProcess::run_scripts() // changed log-output to stack-based buffer (avoid persistent 4K storage) void CScriptProcess::update() { + PROF_EVENT("CScriptProcess::update"); #ifdef DBG_DISABLE_SCRIPTS m_scripts_to_run.clear(); return; diff --git a/src/xrServerEntities/script_reader_script.cpp b/src/xrServerEntities/script_reader_script.cpp index 12918c0b57..0fd79e8b74 100644 --- a/src/xrServerEntities/script_reader_script.cpp +++ b/src/xrServerEntities/script_reader_script.cpp @@ -8,6 +8,8 @@ #include "pch_script.h" #include "script_reader.h" +#include "script_engine.h" +#include "ai_space.h" using namespace luabind; @@ -33,6 +35,44 @@ void r_fvector3(IReader* self, Fvector* arg0) self->r_fvector3(*arg0); } +static luabind::internal_string r_file_as_string(const char* path) +{ + auto fileIter = FS.exist(path); + if (fileIter == nullptr) + { + lua_pushfstring(ai().script_engine().lua(), "Not found file: %s", path); + lua_error(ai().script_engine().lua()); + + return nullptr; + } + + IReader* reader = FS.r_open(path); + + luabind::internal_string result; + result.resize(reader->length()); + std::memcpy(result.data(), reader->pointer(), sizeof(char) * reader->length()); + FS.r_close(reader); + + return result; +} + +static void w_file_from_string(const char* path, const char* buffer) +{ + auto fileIter = FS.exist(path); + if (fileIter == nullptr) + { + lua_pushfstring(ai().script_engine().lua(), "Not found file: %s", path); + lua_error(ai().script_engine().lua()); + + return; + } + + shared_str newPath = fileIter->name; + IWriter* writer = FS.w_open(*newPath); + writer->w(buffer, xr_strlen(buffer)); + FS.w_close(writer); +} + #pragma optimize("s",on) void CScriptReader::script_register(lua_State* L) { @@ -70,6 +110,9 @@ void CScriptReader::script_register(lua_State* L) .def("r_stringZ", &r_stringZ) .def("r_elapsed", &IReader::elapsed) .def("r_advance", &IReader::advance) - .def("r_eof", &r_eof) + .def("r_eof", &r_eof), + + def("r_file_as_string", &r_file_as_string) + //def("w_file_from_string", &w_file_from_string) ]; } diff --git a/src/xrServerEntities/script_stack_tracker.cpp b/src/xrServerEntities/script_stack_tracker.cpp index b7b1eaf7c9..e2debae53f 100644 --- a/src/xrServerEntities/script_stack_tracker.cpp +++ b/src/xrServerEntities/script_stack_tracker.cpp @@ -57,12 +57,16 @@ void CScriptStackTracker::script_hook(lua_State* L, lua_Debug* dbg) } case LUA_HOOKLINE: { + if (m_current_stack_level >= max_stack_size) + return; lua_getinfo(L, "l", dbg); m_stack[m_current_stack_level]->currentline = dbg->currentline; break; } case LUA_HOOKCOUNT: { + if (m_current_stack_level >= max_stack_size) + return; lua_getinfo(L, "l", dbg); m_stack[m_current_stack_level]->currentline = dbg->currentline; break; diff --git a/src/xrServerEntities/script_stack_tracker.h b/src/xrServerEntities/script_stack_tracker.h index 53d9e64cbc..5377e55536 100644 --- a/src/xrServerEntities/script_stack_tracker.h +++ b/src/xrServerEntities/script_stack_tracker.h @@ -16,7 +16,7 @@ class CScriptStackTracker protected: enum consts { - max_stack_size = u32(256), + max_stack_size = u32(512), }; protected: diff --git a/src/xrServerEntities/script_storage.cpp b/src/xrServerEntities/script_storage.cpp index 48a738e965..b0d72d0dc3 100644 --- a/src/xrServerEntities/script_storage.cpp +++ b/src/xrServerEntities/script_storage.cpp @@ -161,38 +161,32 @@ u32 game_lua_memory_usage() } #endif //!USE_DL_ALLOCATOR -static void* __cdecl luabind_allocator( - const void* pointer, +static LPVOID __cdecl luabind_allocator( + luabind::memory_allocation_function_parameter const, + void const* const pointer, size_t const size ) { if (!size) { - void* non_const_pointer = const_cast(pointer); + LPVOID non_const_pointer = const_cast(pointer); xr_free(non_const_pointer); - return nullptr; + return (0); } if (!pointer) { -#ifdef DEBUG - return (Memory.mem_alloc(size, "luabind")); -#else //!DEBUG return (Memory.mem_alloc(size)); -#endif //-DEBUG } - void* non_const_pointer = const_cast(pointer); -#ifdef DEBUG - return (Memory.mem_realloc(non_const_pointer, size, "luabind")); -#else //!DEBUG + LPVOID non_const_pointer = const_cast(pointer); return (Memory.mem_realloc(non_const_pointer, size)); -#endif //-DEBUG } void setup_luabind_allocator() { - ::luabind::set_allocator(&luabind_allocator); + ::luabind::allocator = &luabind_allocator; + ::luabind::allocator_parameter = 0; } #ifdef USE_LUAJIT_ONE // [1/14/2015 Andrey] @@ -388,11 +382,16 @@ bool LoadKernelScriptToGlobal(lua_State* L, const char* name) }; BOOL lua_debug = FALSE; + +#ifdef USE_LUA_FUNCTOR_CACHE +BOOL lua_use_functor_cache = FALSE; +#endif + void CScriptStorage::reinit() { if (m_virtual_machine) lua_close(m_virtual_machine); - + #ifdef USE_GSC_MEM_ALLOC m_virtual_machine = lua_newstate(lua_alloc, NULL); #else @@ -408,7 +407,7 @@ void CScriptStorage::reinit() #ifndef USE_LUAJIT_ONE luaL_openlibs(lua()); - if (strstr(Core.Params, "-nojit")) + if (Core.ParamsData.test(ECoreParams::nojit)) luaJIT_setmode(lua(), 0, LUAJIT_MODE_ENGINE | LUAJIT_MODE_OFF); #else // USE_LUAJIT_ONE // initialize lua standard library functions @@ -428,11 +427,11 @@ void CScriptStorage::reinit() luajit::open_lib(lua(), LUA_DBLIBNAME, luaopen_debug); #else //!DEBUG - if (strstr(Core.Params, "-dbg")) + if (Core.isDebug()) luajit::open_lib(lua(), LUA_DBLIBNAME, luaopen_debug); #endif //-DEBUG - if (!strstr(Core.Params, "-nojit")) + if (!Core.ParamsData.test(ECoreParams::nojit)) { luajit::open_lib(lua(), LUA_JITLIBNAME, luaopen_jit); #ifndef DEBUG @@ -464,8 +463,8 @@ void CScriptStorage::reinit() LoadKernelScriptToGlobal(lua(), "LuaPanda.lua"); } } - - if (strstr(Core.Params, "-_g")) + + if (Core.ParamsData.test(ECoreParams::_g)) file_header = file_header_new; //AVO: I get fatal crash at the start if this is used else file_header = file_header_old; @@ -501,10 +500,10 @@ int CScriptStorage::vscript_log(ScriptStorage::ELuaMessageType tLuaMessageType, //return (0); //#else //PRINT_CALL_STACK # ifndef NO_XRGAME_SCRIPT_ENGINE - //AVO: allow LUA debug prints (i.e.: ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, "CWeapon : cannot access class member Weapon_IsScopeAttached!");) + //AVO: allow LUA debug prints (i.e.: ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, make_string("CWeapon [%s]: cannot access class member Weapon_IsScopeAttached!", object().cNameSect().c_str()).c_str());) # ifndef DEBUG - if (!strstr(Core.Params, "-dbg")) + if (!Core.isDebug()) return (0); # endif //!DEBUG # ifndef LUA_DEBUG_PRINT @@ -778,7 +777,7 @@ bool CScriptStorage::load_buffer(lua_State* L, LPCSTR caBuffer, size_t tSize, LP if (l_iErrorCode) { //#ifdef DEBUG - if (strstr(Core.Params, "-dbg")) print_output(L,caScriptName,l_iErrorCode); + if (Core.isDebug()) print_output(L,caScriptName,l_iErrorCode); //#endif //-DEBUG on_error(L); return (false); @@ -786,11 +785,11 @@ bool CScriptStorage::load_buffer(lua_State* L, LPCSTR caBuffer, size_t tSize, LP return (true); } -xr_unordered_map> unlocalizers; +xr_unordered_map> unlocalizers; bool unlocalizerPassed = false; -static std::string join_list(const std::vector& items_vec, std::string delim = "\n") { - std::string ret; +static xr_string join_list(const xr_vector& items_vec, xr_string delim = "\n") { + xr_string ret; for (const auto& i : items_vec) { if (!ret.empty()) { ret += delim; @@ -800,12 +799,12 @@ static std::string join_list(const std::vector& items_vec, std::str return ret; }; -static bool unlocalRegex(std::set& unlocals, std::string& s, const std::regex& pattern, const int group, const std::string& replacement) { +static bool unlocalRegex(xr_set& unlocals, xr_string& s, const std::regex& pattern, const int group, const xr_string& replacement) { if (std::regex_match(s, pattern)) { //Msg("matching local function pattern"); std::smatch match; std::regex_search(s, match, pattern); - std::string variable = match[group]; + xr_string variable = std::string(match[group]).c_str(); if (unlocals.find(variable) != unlocals.end()) { Msg("[unlocalRegex] found variable %s to unlocal", variable.c_str()); s = std::regex_replace(s, pattern, replacement); @@ -854,8 +853,7 @@ bool CScriptStorage::do_file(LPCSTR caScriptName, LPCSTR caNameSpaceName) sections_type::const_iterator e = sections.end(); for (; i != e; ++i) { - auto sectionName = std::string((*i).Name.c_str()); - toLowerCase(sectionName); + auto sectionName = xr_string((*i).Name.c_str()).ToLowerCase(); if (unlocalizers.find(sectionName) == unlocalizers.end()) { // construct set that contains top level variables to delocalize by section name @@ -864,7 +862,7 @@ bool CScriptStorage::do_file(LPCSTR caScriptName, LPCSTR caNameSpaceName) } auto& data = (*i).Data; for (auto& item : data) { - unlocalizers[sectionName].insert(std::string(item.first.c_str())); + unlocalizers[sectionName].insert(xr_string(item.first.c_str())); Msg("adding variable %s for unlocalizer for script %s", item.first.c_str(), sectionName.c_str()); } } @@ -888,23 +886,23 @@ bool CScriptStorage::do_file(LPCSTR caScriptName, LPCSTR caNameSpaceName) auto scriptContents = static_cast(l_tpFileReader->pointer()); auto scriptLength = (size_t)l_tpFileReader->length(); bool unlocalPerformed = false; - std::string unlocalizerResult; - std::string loweredNameSpaceName = caNameSpaceName; - toLowerCase(loweredNameSpaceName); + xr_string unlocalizerResult; + xr_string loweredNameSpaceName = caNameSpaceName; + loweredNameSpaceName = loweredNameSpaceName.ToLowerCase(); if (unlocalizers.find(loweredNameSpaceName) != unlocalizers.end()) { Msg("found script %s in unlocalizers data", caNameSpaceName); // Get contents of the script file and split by lines - std::vector tokens; - std::string temp; + xr_vector tokens; + xr_string temp; while (!l_tpFileReader->eof()) { char c = l_tpFileReader->r_u8(); temp += c; } - std::stringstream stringStream(temp); - std::string line; + std::stringstream stringStream(std::string(temp.c_str())); + xr_string line; tokens.clear(); while (std::getline(stringStream, line)) { tokens.push_back(line); @@ -943,7 +941,7 @@ bool CScriptStorage::do_file(LPCSTR caScriptName, LPCSTR caNameSpaceName) if (std::regex_match(s, pattern)) { std::smatch match; std::regex_search(s, match, pattern); - std::string m = match[3]; + xr_string m = std::string(match[3]).c_str(); // strip comments std::regex r = std::regex(R"((.*)--.*)"); @@ -951,12 +949,12 @@ bool CScriptStorage::do_file(LPCSTR caScriptName, LPCSTR caNameSpaceName) //Msg("found comments\n"); std::smatch noncomments; std::regex_search(m, noncomments, r); - m = noncomments[1]; + m = std::string(noncomments[1]).c_str(); } - auto variablesAndValues = splitStringLimit(m, "=", 1); + auto variablesAndValues = m.SplitStringLimit("=", 1); bool hasValue = variablesAndValues.size() > 1; - auto variables = splitStringMulti(variablesAndValues[0], ","); + auto variables = variablesAndValues[0].SplitStringMulti(","); for (auto v : variables) { trim(v); //Msg("%s\n", v.c_str()); @@ -972,7 +970,7 @@ bool CScriptStorage::do_file(LPCSTR caScriptName, LPCSTR caNameSpaceName) //Msg("found comments\n"); std::smatch noncomments; std::regex_search(s, noncomments, r); - s = std::string(noncomments[1]) + "= nil " + std::string(noncomments[2]); + s = xr_string((std::string(noncomments[1]) + "= nil " + std::string(noncomments[2])).c_str()); } else { s += " = nil"; } @@ -1041,7 +1039,7 @@ bool CScriptStorage::do_file(LPCSTR caScriptName, LPCSTR caNameSpaceName) if (l_iErrorCode) { //#ifdef DEBUG - if (strstr(Core.Params, "-dbg")) print_output(lua(),caScriptName,l_iErrorCode); + if (Core.isDebug()) print_output(lua(),caScriptName,l_iErrorCode); //#endif on_error(lua()); lua_settop(lua(), start); @@ -1195,7 +1193,7 @@ struct raii_guard : private xray::noncopyable #endif //-DEBUG { #ifdef DEBUG - static bool const break_on_assert = !!strstr(Core.Params,"-break_on_assert"); + static bool const break_on_assert = Core.ParamsData.test(ECoreParams::break_on_assert); #else //!DEBUG static bool const break_on_assert = false; //Alundaio: Can't get a proper stack trace with this enabled #endif //-DEBUG diff --git a/src/xrServerEntities/script_storage.h b/src/xrServerEntities/script_storage.h index cff86c36e1..6191fa9059 100644 --- a/src/xrServerEntities/script_storage.h +++ b/src/xrServerEntities/script_storage.h @@ -29,7 +29,7 @@ class CScriptThread; # endif // #ifndef NDEBUG #endif //-XRGAME_EXPORTS -//AVO: allow LUA debug prints (i.e.: ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, "CWeapon : cannot access class member Weapon_IsScopeAttached!");) +//AVO: allow LUA debug prints (i.e.: ai().script_engine().script_log(ScriptStorage::eLuaMessageTypeError, make_string("CWeapon [%s]: cannot access class member Weapon_IsScopeAttached!", object().cNameSect().c_str()).c_str());) #include "..\build_config_defines.h" #ifndef DEBUG # ifdef LUA_DEBUG_PRINT diff --git a/src/xrServerEntities/smart_cast.h b/src/xrServerEntities/smart_cast.h index 1cc5ccbc5b..b02293ec09 100644 --- a/src/xrServerEntities/smart_cast.h +++ b/src/xrServerEntities/smart_cast.h @@ -2,349 +2,313 @@ #include -#define smart_cast fast_dynamic_cast - -// Original code - -//////////////////////////////////////////////////////////////////////////// -// Module : smart_cast.h -// Created : 17.09.2004 -// Modified : 17.09.2004 -// Author : Dmitriy Iassenev -// Description : Smart dynamic cast -//////////////////////////////////////////////////////////////////////////// - -//#ifndef SMART_CAST_H -//#define SMART_CAST_H -// -//#ifdef DEBUG -//# define PURE_DYNAMIC_CAST -//#endif // DEBUG -// -//#ifdef PURE_DYNAMIC_CAST -//# define smart_cast dynamic_cast -//#else -//#define TL_FAST_COMPILATION -//#undef STATIC_CHECK -//#include -//# define PURE_DYNAMIC_CAST_COMPATIBILITY_CHECK -// -//# ifdef DEBUG -////# define SMART_CAST_STATS_ALL -//# endif -// -//# ifndef DECLARE_SPECIALIZATION -//# include "smart_cast_impl0.h" -//# else -//# include "smart_cast_impl2.h" -//# define DO_NOT_DECLARE_TYPE_LIST -//# endif -// -//# ifdef XRGAME_EXPORTS -// -//DECLARE_SPECIALIZATION(IKinematics, IRenderVisual, dcast_PKinematics); -//# undef cast_type_list -//# define cast_type_list save_cast_list (IKinematics, IRenderVisual) -// -//DECLARE_SPECIALIZATION(IKinematicsAnimated, IRenderVisual, dcast_PKinematicsAnimated); -//# undef cast_type_list -//# define cast_type_list save_cast_list (IKinematicsAnimated, IRenderVisual) -// -//DECLARE_SPECIALIZATION(IParticleCustom, IRenderVisual, dcast_ParticleCustom); -//# undef cast_type_list -//# define cast_type_list save_cast_list (IParticleCustom, IRenderVisual) -// -//DECLARE_SPECIALIZATION(IKinematics, IKinematicsAnimated, dcast_PKinematics); -//# undef cast_type_list -//# define cast_type_list save_cast_list (IKinematics, IKinematicsAnimated) -// -//DECLARE_SPECIALIZATION(IKinematicsAnimated, IKinematics, dcast_PKinematicsAnimated); -//# undef cast_type_list -//# define cast_type_list save_cast_list (IKinematicsAnimated, IKinematics) -// -//DECLARE_SPECIALIZATION(IRenderVisual, IKinematicsAnimated, dcast_RenderVisual); -//# undef cast_type_list -//# define cast_type_list save_cast_list (IRenderVisual, IKinematicsAnimated) -// -//DECLARE_SPECIALIZATION(IRenderVisual, IKinematics, dcast_RenderVisual); -//# undef cast_type_list -//# define cast_type_list save_cast_list (IRenderVisual, IKinematics) -// -//# ifndef DO_NOT_DECLARE_TYPE_LIST -//class ENGINE_API ISpatial; -// -//namespace Feel -//{ -// class ENGINE_API Sound; -//} -// -//typedef Feel::Sound Feel__Sound; -//template <> -//extern -//Feel::Sound* SmartDynamicCast::smart_cast(ISpatial* p); -//add_to_cast_list(Feel__Sound, ISpatial); -//# undef cast_type_list -//# define cast_type_list save_cast_list (Feel__Sound, ISpatial) -//# endif -// -//DECLARE_SPECIALIZATION(IRenderable, ISpatial, dcast_Renderable); -//# undef cast_type_list -//# define cast_type_list save_cast_list (IRenderable, ISpatial) -// -//DECLARE_SPECIALIZATION(IRender_Light, ISpatial, dcast_Light); -//# undef cast_type_list -//# define cast_type_list save_cast_list (IRender_Light, ISpatial) -// -//DECLARE_SPECIALIZATION(CObject, ISpatial, dcast_CObject); -//# undef cast_type_list -//# define cast_type_list save_cast_list (CObject, ISpatial) -// -//# ifndef DO_NOT_DECLARE_TYPE_LIST -//class CObject; -//class CGameObject; -//add_to_cast_list(CGameObject, CObject); -//# undef cast_type_list -//# define cast_type_list save_cast_list (CGameObject, CObject) -//# endif -// -//DECLARE_SPECIALIZATION(CEntity, CGameObject, cast_entity); -//# undef cast_type_list -//# define cast_type_list save_cast_list (CEntity, CGameObject) -// -//DECLARE_SPECIALIZATION(CEntityAlive, CGameObject, cast_entity_alive); -//# undef cast_type_list -//# define cast_type_list save_cast_list (CEntityAlive, CGameObject) -// -//DECLARE_SPECIALIZATION(CInventoryItem, CGameObject, cast_inventory_item); -//# undef cast_type_list -//# define cast_type_list save_cast_list (CInventoryItem, CGameObject) -// -//DECLARE_SPECIALIZATION(CInventoryOwner, CGameObject, cast_inventory_owner); -//# undef cast_type_list -//# define cast_type_list save_cast_list (CInventoryOwner, CGameObject) -// -//DECLARE_SPECIALIZATION(CActor, CGameObject, cast_actor); -//# undef cast_type_list -//# define cast_type_list save_cast_list (CActor, CGameObject) -// -//DECLARE_SPECIALIZATION(CGameObject, CInventoryOwner, cast_game_object); -//# undef cast_type_list -//# define cast_type_list save_cast_list (CGameObject, CInventoryOwner) -// -//DECLARE_SPECIALIZATION(CWeapon, CInventoryItem, cast_weapon); -//# undef cast_type_list -//# define cast_type_list save_cast_list (CWeapon, CInventoryItem) -// -//DECLARE_SPECIALIZATION(CWeapon, CGameObject, cast_weapon); -//# undef cast_type_list -//# define cast_type_list save_cast_list (CWeapon, CGameObject) -// -//DECLARE_SPECIALIZATION(CFoodItem, CInventoryItem, cast_food_item); -//# undef cast_type_list -//# define cast_type_list save_cast_list (CFoodItem, CInventoryItem) -// -//DECLARE_SPECIALIZATION(CMissile, CInventoryItem, cast_missile); -//# undef cast_type_list -//# define cast_type_list save_cast_list (CMissile, CInventoryItem) -// -//DECLARE_SPECIALIZATION(CFlashlight, CInventoryItem, cast_flashlight); -//# undef cast_type_list -//# define cast_type_list save_cast_list (CFlashlight, CInventoryItem) -// -//DECLARE_SPECIALIZATION(CCustomZone, CGameObject, cast_custom_zone); -//# undef cast_type_list -//# define cast_type_list save_cast_list (CCustomZone, CGameObject) -// -//DECLARE_SPECIALIZATION(CWeaponMagazined, CWeapon, cast_weapon_magazined); -//# undef cast_type_list -//# define cast_type_list save_cast_list (CWeaponMagazined, CWeapon) -// -//DECLARE_SPECIALIZATION(CHudItem, CInventoryItem, cast_hud_item); -//# undef cast_type_list -//# define cast_type_list save_cast_list (CHudItem, CInventoryItem) -// -//DECLARE_SPECIALIZATION(CPhysicsShellHolder, CGameObject, cast_physics_shell_holder); -//# undef cast_type_list -//# define cast_type_list save_cast_list (CPhysicsShellHolder,CGameObject) -// -//DECLARE_SPECIALIZATION(IInputReceiver, CGameObject, cast_input_receiver); -//# undef cast_type_list -//# define cast_type_list save_cast_list (IInputReceiver, CGameObject) -// -//DECLARE_SPECIALIZATION(CWeaponAmmo, CInventoryItem, cast_weapon_ammo); -//# undef cast_type_list -//# define cast_type_list save_cast_list (CWeaponAmmo, CInventoryItem) -///* -// DECLARE_SPECIALIZATION (CCameraShotEffector, CCameraEffector, cast_effector_shot); -//# undef cast_type_list -//# define cast_type_list save_cast_list (CCameraShotEffector, CCameraEffector) -// -// DECLARE_SPECIALIZATION (CEffectorZoomInertion, CCameraEffector, cast_effector_zoom_inertion); -//# undef cast_type_list -//# define cast_type_list save_cast_list (CEffectorZoomInertion, CCameraEffector) -//*/ -//DECLARE_SPECIALIZATION(CParticlesPlayer, CGameObject, cast_particles_player); -//# undef cast_type_list -//# define cast_type_list save_cast_list (CParticlesPlayer, CGameObject) -// -//DECLARE_SPECIALIZATION(CArtefact, CGameObject, cast_artefact); -//# undef cast_type_list -//# define cast_type_list save_cast_list (CArtefact, CGameObject) -// -//DECLARE_SPECIALIZATION(CCustomMonster, CGameObject, cast_custom_monster); -//# undef cast_type_list -//# define cast_type_list save_cast_list (CCustomMonster, CGameObject) -// -//DECLARE_SPECIALIZATION(CAI_Stalker, CGameObject, cast_stalker); -//# undef cast_type_list -//# define cast_type_list save_cast_list (CAI_Stalker, CGameObject) -// -//DECLARE_SPECIALIZATION(CScriptEntity, CGameObject, cast_script_entity); -//# undef cast_type_list -//# define cast_type_list save_cast_list (CScriptEntity, CGameObject) -// -//DECLARE_SPECIALIZATION(CSpaceRestrictor, CGameObject, cast_restrictor); -//# undef cast_type_list -//# define cast_type_list save_cast_list (CSpaceRestrictor, CGameObject) -// -//DECLARE_SPECIALIZATION(CExplosive, CGameObject, cast_explosive); -//# undef cast_type_list -//# define cast_type_list save_cast_list (CExplosive, CGameObject) -// -//DECLARE_SPECIALIZATION(CGameObject, CAttachmentOwner, cast_game_object); -//# undef cast_type_list -//# define cast_type_list save_cast_list (CGameObject, CAttachmentOwner) -// -//DECLARE_SPECIALIZATION(CGameObject, CInventoryItem, cast_game_object); -//# undef cast_type_list -//# define cast_type_list save_cast_list (CGameObject, CInventoryItem) -// -//DECLARE_SPECIALIZATION(CAttachableItem, CGameObject, cast_attachable_item); -//# undef cast_type_list -//# define cast_type_list save_cast_list (CAttachableItem, CGameObject) -// -//DECLARE_SPECIALIZATION(CHolderCustom, CGameObject, cast_holder_custom); -//# undef cast_type_list -//# define cast_type_list save_cast_list (CHolderCustom, CGameObject) -// -//DECLARE_SPECIALIZATION(CAttachmentOwner, CGameObject, cast_attachment_owner); -//# undef cast_type_list -//# define cast_type_list save_cast_list (CAttachmentOwner, CGameObject) -// -//DECLARE_SPECIALIZATION(CEatableItem, CInventoryItem, cast_eatable_item); -//# undef cast_type_list -//# define cast_type_list save_cast_list (CEatableItem, CInventoryItem) -// -//DECLARE_SPECIALIZATION(CBaseMonster, CGameObject, cast_base_monster); -//# undef cast_type_list -//# define cast_type_list save_cast_list (CBaseMonster, CGameObject) -// -//# endif -// -//DECLARE_SPECIALIZATION(CSE_Abstract, CSE_ALifeInventoryItem, cast_abstract); -//# undef cast_type_list -//# define cast_type_list save_cast_list (CSE_Abstract, CSE_ALifeInventoryItem) -// -//DECLARE_SPECIALIZATION(CSE_Abstract, CSE_ALifeTraderAbstract, cast_abstract); -//# undef cast_type_list -//# define cast_type_list save_cast_list (CSE_Abstract, CSE_ALifeTraderAbstract) -// -//DECLARE_SPECIALIZATION(CSE_Abstract, CSE_ALifeGroupAbstract, cast_abstract); -//# undef cast_type_list -//# define cast_type_list save_cast_list (CSE_Abstract, CSE_ALifeGroupAbstract) -// -//DECLARE_SPECIALIZATION(CSE_Abstract, CSE_ALifeSchedulable, cast_abstract); -//# undef cast_type_list -//# define cast_type_list save_cast_list (CSE_Abstract, CSE_ALifeSchedulable) -// -//DECLARE_SPECIALIZATION(CSE_ALifeGroupAbstract, CSE_Abstract, cast_group_abstract); -//# undef cast_type_list -//# define cast_type_list save_cast_list (CSE_ALifeGroupAbstract, CSE_Abstract) -// -//DECLARE_SPECIALIZATION(CSE_ALifeSchedulable, CSE_Abstract, cast_schedulable); -//# undef cast_type_list -//# define cast_type_list save_cast_list (CSE_ALifeSchedulable, CSE_Abstract) -// -//DECLARE_SPECIALIZATION(CSE_ALifeInventoryItem, CSE_Abstract, cast_inventory_item); -//# undef cast_type_list -//# define cast_type_list save_cast_list (CSE_ALifeInventoryItem, CSE_Abstract) -// -//DECLARE_SPECIALIZATION(CSE_ALifeTraderAbstract, CSE_Abstract, cast_trader_abstract); -//# undef cast_type_list -//# define cast_type_list save_cast_list (CSE_ALifeTraderAbstract, CSE_Abstract) -// -//DECLARE_SPECIALIZATION(CSE_Visual, CSE_Abstract, visual); -//# undef cast_type_list -//# define cast_type_list save_cast_list (CSE_Visual, CSE_Abstract) -// -//DECLARE_SPECIALIZATION(CSE_Motion, CSE_Abstract, motion); -//# undef cast_type_list -//# define cast_type_list save_cast_list (CSE_Motion, CSE_Abstract) -// -//DECLARE_SPECIALIZATION(ISE_Shape, CSE_Abstract, shape); -//# undef cast_type_list -//# define cast_type_list save_cast_list (ISE_Shape, CSE_Abstract) -// -//DECLARE_SPECIALIZATION(CSE_Abstract, CSE_PHSkeleton, cast_abstract); -//# undef cast_type_list -//# define cast_type_list save_cast_list (CSE_Abstract, CSE_PHSkeleton) -// -//DECLARE_SPECIALIZATION(CSE_ALifeObject, CSE_Abstract, cast_alife_object); -//# undef cast_type_list -//# define cast_type_list save_cast_list (CSE_ALifeObject, CSE_Abstract) -// -//DECLARE_SPECIALIZATION(CSE_ALifeDynamicObject, CSE_Abstract, cast_alife_dynamic_object); -//# undef cast_type_list -//# define cast_type_list save_cast_list (CSE_ALifeDynamicObject, CSE_Abstract) -// -//DECLARE_SPECIALIZATION(CSE_ALifeItemAmmo, CSE_Abstract, cast_item_ammo); -//# undef cast_type_list -//# define cast_type_list save_cast_list (CSE_ALifeItemAmmo, CSE_Abstract) -// -//DECLARE_SPECIALIZATION(CSE_ALifeItemWeapon, CSE_Abstract, cast_item_weapon); -//# undef cast_type_list -//# define cast_type_list save_cast_list (CSE_ALifeItemWeapon, CSE_Abstract) -// -//DECLARE_SPECIALIZATION(CSE_ALifeItemDetector, CSE_Abstract, cast_item_detector); -//# undef cast_type_list -//# define cast_type_list save_cast_list (CSE_ALifeItemDetector, CSE_Abstract) -// -//DECLARE_SPECIALIZATION(CSE_ALifeMonsterAbstract, CSE_Abstract, cast_monster_abstract); -//# undef cast_type_list -//# define cast_type_list save_cast_list (CSE_ALifeMonsterAbstract, CSE_Abstract) -// -//DECLARE_SPECIALIZATION(CSE_ALifeHumanAbstract, CSE_Abstract, cast_human_abstract); -//# undef cast_type_list -//# define cast_type_list save_cast_list (CSE_ALifeHumanAbstract, CSE_Abstract) -// -//DECLARE_SPECIALIZATION(CSE_ALifeAnomalousZone, CSE_Abstract, cast_anomalous_zone); -//# undef cast_type_list -//# define cast_type_list save_cast_list (CSE_ALifeAnomalousZone, CSE_Abstract) -// -//DECLARE_SPECIALIZATION(CSE_ALifeTrader, CSE_Abstract, cast_trader); -//# undef cast_type_list -//# define cast_type_list save_cast_list (CSE_ALifeTrader, CSE_Abstract) -// -//DECLARE_SPECIALIZATION(CSE_ALifeCreatureAbstract, CSE_Abstract, cast_creature_abstract); -//# undef cast_type_list -//# define cast_type_list save_cast_list (CSE_ALifeCreatureAbstract, CSE_Abstract) -// -//DECLARE_SPECIALIZATION(CSE_ALifeSmartZone, CSE_Abstract, cast_smart_zone); -//# undef cast_type_list -//# define cast_type_list save_cast_list (CSE_ALifeSmartZone, CSE_Abstract) -// -//DECLARE_SPECIALIZATION(CSE_ALifeOnlineOfflineGroup, CSE_Abstract, cast_online_offline_group); -//# undef cast_type_list -//# define cast_type_list save_cast_list (CSE_ALifeOnlineOfflineGroup, CSE_Abstract) -// -//DECLARE_SPECIALIZATION(CSE_ALifeItemPDA, CSE_Abstract, cast_item_pda); -//# undef cast_type_list -//# define cast_type_list save_cast_list (CSE_ALifeItemPDA, CSE_Abstract) -// -//# ifndef DO_NOT_DECLARE_TYPE_LIST -//# include "smart_cast_impl1.h" -//# endif -//#endif -// -//#endif //SMART_CAST_H +// demonized: smart_cast with specializations modern c++ way +// Fallback uses fast_dynamic_cast library +// Helper to detect if a type has a dedicated cast method +// Specializations will be provided for known dcast methods +template +struct has_dcast : std::false_type {}; + +#define DECLARE_SPECIALIZATION(TO, FROM, METHOD) \ +template<> struct has_dcast : std::true_type { \ + static_assert(std::is_convertible_v()->METHOD()), TO*>, \ + "Specialization Error: " #METHOD " does not return " #TO "*"); \ + static TO* cast(FROM* ptr) { return ptr ? ptr->METHOD() : nullptr; } \ +}; + +#include "../include/xrRender/RenderVisual.h" +#include "../include/xrRender/Kinematics.h" +#include "../include/xrRender/KinematicsAnimated.h" +#include "../include/xrRender/ParticleCustom.h" + +DECLARE_SPECIALIZATION(IKinematics, IRenderVisual, dcast_PKinematics) +DECLARE_SPECIALIZATION(IKinematicsAnimated, IRenderVisual, dcast_PKinematicsAnimated) +DECLARE_SPECIALIZATION(IKinematics, IKinematicsAnimated, dcast_PKinematics) +DECLARE_SPECIALIZATION(IKinematicsAnimated, IKinematics, dcast_PKinematicsAnimated) +DECLARE_SPECIALIZATION(IRenderVisual, IKinematics, dcast_RenderVisual) +DECLARE_SPECIALIZATION(IRenderVisual, IKinematicsAnimated, dcast_RenderVisual) +DECLARE_SPECIALIZATION(IParticleCustom, IRenderVisual, dcast_ParticleCustom) + +// Project-specific specializations +#ifdef XRGAME_EXPORTS +#include "../xrGame/GameObject.h" +#include "../xrGame/InventoryOwner.h" +#include "../xrGame/inventory_item.h" +#include "../xrGame/Weapon.h" +#include "../xrGame/WeaponStatMgun.h" +#include "../xrGame/CustomRocket.h" +#include "xrServer_Objects_ALife.h" +#include "xrServer_Objects_ALife_Monsters.h" + +class CObject; +class CGameObject; +class CEntity; +class CEntityAlive; +class CInventoryItem; +class CInventoryOwner; +class CHudItem; +class CFoodItem; +class CWeapon; +class CWeaponMagazined; +class CWeaponAmmo; +class CSE_ALifeTraderAbstract; +class CWeaponStatMgun; +class CHangingLamp; +class CCustomRocket; + +// Original specializations +DECLARE_SPECIALIZATION(IRenderable, ISpatial, dcast_Renderable) +DECLARE_SPECIALIZATION(IRender_Light, ISpatial, dcast_Light) +DECLARE_SPECIALIZATION(CObject, ISpatial, dcast_CObject) +DECLARE_SPECIALIZATION(Feel::Sound, ISpatial, dcast_FeelSound) +DECLARE_SPECIALIZATION(CEntity, CGameObject, cast_entity) +DECLARE_SPECIALIZATION(CEntityAlive, CGameObject, cast_entity_alive) +DECLARE_SPECIALIZATION(CInventoryItem, CGameObject, cast_inventory_item) +DECLARE_SPECIALIZATION(CInventoryOwner, CGameObject, cast_inventory_owner) +DECLARE_SPECIALIZATION(CActor, CGameObject, cast_actor) +DECLARE_SPECIALIZATION(CGameObject, CInventoryOwner, cast_game_object) +DECLARE_SPECIALIZATION(CWeapon, CInventoryItem, cast_weapon) +DECLARE_SPECIALIZATION(CWeapon, CGameObject, cast_weapon) +DECLARE_SPECIALIZATION(CFoodItem, CInventoryItem, cast_food_item) +DECLARE_SPECIALIZATION(CMissile, CInventoryItem, cast_missile) +DECLARE_SPECIALIZATION(CFlashlight, CInventoryItem, cast_flashlight) +DECLARE_SPECIALIZATION(CCustomZone, CGameObject, cast_custom_zone) +DECLARE_SPECIALIZATION(CWeaponMagazined, CWeapon, cast_weapon_magazined) +DECLARE_SPECIALIZATION(CHudItem, CInventoryItem, cast_hud_item) +DECLARE_SPECIALIZATION(CPhysicsShellHolder, CGameObject, cast_physics_shell_holder) +DECLARE_SPECIALIZATION(IInputReceiver, CGameObject, cast_input_receiver) +DECLARE_SPECIALIZATION(CWeaponAmmo, CInventoryItem, cast_weapon_ammo) +DECLARE_SPECIALIZATION(CParticlesPlayer, CGameObject, cast_particles_player) +DECLARE_SPECIALIZATION(CArtefact, CGameObject, cast_artefact) +DECLARE_SPECIALIZATION(CCustomMonster, CGameObject, cast_custom_monster) +DECLARE_SPECIALIZATION(CAI_Stalker, CGameObject, cast_stalker) +DECLARE_SPECIALIZATION(CScriptEntity, CGameObject, cast_script_entity) +DECLARE_SPECIALIZATION(CSpaceRestrictor, CGameObject, cast_restrictor) +DECLARE_SPECIALIZATION(CExplosive, CGameObject, cast_explosive) +DECLARE_SPECIALIZATION(CGameObject, CAttachmentOwner, cast_game_object) +DECLARE_SPECIALIZATION(CGameObject, CInventoryItem, cast_game_object) +DECLARE_SPECIALIZATION(CAttachableItem, CGameObject, cast_attachable_item) +DECLARE_SPECIALIZATION(CHolderCustom, CGameObject, cast_holder_custom) +DECLARE_SPECIALIZATION(CAttachmentOwner, CGameObject, cast_attachment_owner) +DECLARE_SPECIALIZATION(CEatableItem, CInventoryItem, cast_eatable_item) +DECLARE_SPECIALIZATION(CBaseMonster, CGameObject, cast_base_monster) +DECLARE_SPECIALIZATION(CSE_Abstract, CSE_ALifeInventoryItem, cast_abstract) +DECLARE_SPECIALIZATION(CSE_Abstract, CSE_ALifeTraderAbstract, cast_abstract) +DECLARE_SPECIALIZATION(CSE_Abstract, CSE_ALifeGroupAbstract, cast_abstract) +DECLARE_SPECIALIZATION(CSE_Abstract, CSE_ALifeSchedulable, cast_abstract) +DECLARE_SPECIALIZATION(CSE_ALifeGroupAbstract, CSE_Abstract, cast_group_abstract) +DECLARE_SPECIALIZATION(CSE_ALifeSchedulable, CSE_Abstract, cast_schedulable) +DECLARE_SPECIALIZATION(CSE_ALifeInventoryItem, CSE_Abstract, cast_inventory_item) +DECLARE_SPECIALIZATION(CSE_ALifeTraderAbstract, CSE_Abstract, cast_trader_abstract) +DECLARE_SPECIALIZATION(CSE_Visual, CSE_Abstract, visual) +DECLARE_SPECIALIZATION(CSE_Motion, CSE_Abstract, motion) +DECLARE_SPECIALIZATION(ISE_Shape, CSE_Abstract, shape) +DECLARE_SPECIALIZATION(CSE_Abstract, CSE_PHSkeleton, cast_abstract) +DECLARE_SPECIALIZATION(CSE_ALifeObject, CSE_Abstract, cast_alife_object) +DECLARE_SPECIALIZATION(CSE_ALifeDynamicObject, CSE_Abstract, cast_alife_dynamic_object) +DECLARE_SPECIALIZATION(CSE_ALifeItemAmmo, CSE_Abstract, cast_item_ammo) +DECLARE_SPECIALIZATION(CSE_ALifeItemWeapon, CSE_Abstract, cast_item_weapon) +DECLARE_SPECIALIZATION(CSE_ALifeItemDetector, CSE_Abstract, cast_item_detector) +DECLARE_SPECIALIZATION(CSE_ALifeMonsterAbstract, CSE_Abstract, cast_monster_abstract) +DECLARE_SPECIALIZATION(CSE_ALifeHumanAbstract, CSE_Abstract, cast_human_abstract) +DECLARE_SPECIALIZATION(CSE_ALifeAnomalousZone, CSE_Abstract, cast_anomalous_zone) +DECLARE_SPECIALIZATION(CSE_ALifeTrader, CSE_Abstract, cast_trader) +DECLARE_SPECIALIZATION(CSE_ALifeCreatureAbstract, CSE_Abstract, cast_creature_abstract) +DECLARE_SPECIALIZATION(CSE_ALifeSmartZone, CSE_Abstract, cast_smart_zone) +DECLARE_SPECIALIZATION(CSE_ALifeOnlineOfflineGroup, CSE_Abstract, cast_online_offline_group) +DECLARE_SPECIALIZATION(CSE_ALifeItemPDA, CSE_Abstract, cast_item_pda) + +template<> +struct has_dcast : std::true_type { + static CGameObject* cast(CObject* ptr) { + return static_cast(ptr); + } +}; + +// Additional specializations +DECLARE_SPECIALIZATION(CGrenade, CInventoryItem, cast_grenade) +DECLARE_SPECIALIZATION(CCustomOutfit, CInventoryItem, cast_outfit) +DECLARE_SPECIALIZATION(CArtefact, CInventoryItem, cast_artefact) +DECLARE_SPECIALIZATION(CHelmet, CInventoryItem, cast_helmet) +DECLARE_SPECIALIZATION(CTorch, CInventoryItem, cast_torch) +DECLARE_SPECIALIZATION(CAttachableItem, CInventoryItem, cast_attachable_item) +DECLARE_SPECIALIZATION(CPda, CInventoryItem, cast_pda) +DECLARE_SPECIALIZATION(CCustomDevice, CInventoryItem, cast_custom_device) +DECLARE_SPECIALIZATION(CCustomDetector, CInventoryItem, cast_custom_detector) +DECLARE_SPECIALIZATION(CFlare, CInventoryItem, cast_flare) +DECLARE_SPECIALIZATION(CWeaponMagazined, CInventoryItem, cast_weapon_magazined) +DECLARE_SPECIALIZATION(CWeaponKnife, CInventoryItem, cast_weapon_knife) +DECLARE_SPECIALIZATION(CWeaponBinoculars, CInventoryItem, cast_weapon_binoculars) +DECLARE_SPECIALIZATION(CWeaponMagazinedWGrenade, CInventoryItem, cast_weapon_magazined_w_grenade) +DECLARE_SPECIALIZATION(CWeaponBM16, CInventoryItem, cast_weapon_bm16) +DECLARE_SPECIALIZATION(CWeaponRG6, CInventoryItem, cast_weapon_rg6) +DECLARE_SPECIALIZATION(CWeaponRPG7, CInventoryItem, cast_weapon_rpg7) +DECLARE_SPECIALIZATION(CBolt, CInventoryItem, cast_bolt) +DECLARE_SPECIALIZATION(CSilencer, CInventoryItem, cast_addon_silencer) +DECLARE_SPECIALIZATION(CScope, CInventoryItem, cast_addon_scope) +DECLARE_SPECIALIZATION(CGrenadeLauncher, CInventoryItem, cast_addon_grenade_launcher) + +DECLARE_SPECIALIZATION(CEntityAlive, CInventoryOwner, cast_entity_alive) +DECLARE_SPECIALIZATION(CActor, CInventoryOwner, cast_actor) + +DECLARE_SPECIALIZATION(CInventoryOwner, CEntityAlive, cast_inventory_owner) + +DECLARE_SPECIALIZATION(CWeaponKnife, CWeapon, cast_weapon_knife) +DECLARE_SPECIALIZATION(CWeaponBinoculars, CWeapon, cast_weapon_binoculars) +DECLARE_SPECIALIZATION(CWeaponMagazinedWGrenade, CWeapon, cast_weapon_magazined_w_grenade) +DECLARE_SPECIALIZATION(CWeaponBM16, CWeapon, cast_weapon_bm16) +DECLARE_SPECIALIZATION(CWeaponRG6, CWeapon, cast_weapon_rg6) +DECLARE_SPECIALIZATION(CWeaponRPG7, CWeapon, cast_weapon_rpg7) + +DECLARE_SPECIALIZATION(CGameObject, CActor, cast_game_object) + +DECLARE_SPECIALIZATION(CWeaponStatMgun, CHolderCustom, cast_weapon_stat_mgun) +DECLARE_SPECIALIZATION(CCar, CHolderCustom, cast_car) +DECLARE_SPECIALIZATION(CGameObject, CHolderCustom, cast_game_object) + +DECLARE_SPECIALIZATION(CHolderCustom, CObject, cast_holder_custom) +DECLARE_SPECIALIZATION(CPhysicsShellHolder, CObject, cast_physics_shell_holder) +DECLARE_SPECIALIZATION(CActor, CObject, cast_actor) +DECLARE_SPECIALIZATION(CInventoryOwner, CObject, cast_inventory_owner) +DECLARE_SPECIALIZATION(CCar, CObject, cast_car) +DECLARE_SPECIALIZATION(CSpectator, CObject, cast_spectator) + +DECLARE_SPECIALIZATION(CHolderCustom, CPhysicsShellHolder, cast_holder_custom) +DECLARE_SPECIALIZATION(CExplosiveRocket, CPhysicsShellHolder, cast_explosive_rocket) +DECLARE_SPECIALIZATION(CGrenade, CPhysicsShellHolder, cast_grenade) + +DECLARE_SPECIALIZATION(CInventoryBox, CGameObject, cast_inventory_box) +DECLARE_SPECIALIZATION(CHangingLamp, CGameObject, cast_hanging_lamp) +DECLARE_SPECIALIZATION(CHelicopter, CGameObject, cast_helicopter) +DECLARE_SPECIALIZATION(CPhantom, CGameObject, cast_phantom) +DECLARE_SPECIALIZATION(CScriptZone, CGameObject, cast_script_zone) +DECLARE_SPECIALIZATION(CHudItem, CGameObject, cast_hud_item) +DECLARE_SPECIALIZATION(CLevelChanger, CGameObject, cast_level_changer) +DECLARE_SPECIALIZATION(CPhysicObject, CGameObject, cast_physics_object) +DECLARE_SPECIALIZATION(CPda, CGameObject, cast_pda) +DECLARE_SPECIALIZATION(CCustomDevice, CGameObject, cast_custom_device) +DECLARE_SPECIALIZATION(CWeaponAmmo, CGameObject, cast_weapon_ammo) +DECLARE_SPECIALIZATION(CUsableScriptObject, CGameObject, cast_usable_script_object) +DECLARE_SPECIALIZATION(CProjector, CGameObject, cast_projector) +DECLARE_SPECIALIZATION(CAI_Trader, CGameObject, cast_trader) + +DECLARE_SPECIALIZATION(CBolt, CMissile, cast_bolt) +DECLARE_SPECIALIZATION(CGrenade, CMissile, cast_grenade) + +DECLARE_SPECIALIZATION(CExplosiveRocket, CCustomRocket, cast_explosive_rocket) + +#endif + +#ifdef XRPHYSICS_EXPORTS +#include "../xrCDB/ISpatial.h" + +DECLARE_SPECIALIZATION(IRenderable, ISpatial, dcast_Renderable) +DECLARE_SPECIALIZATION(IRender_Light, ISpatial, dcast_Light) +DECLARE_SPECIALIZATION(CObject, ISpatial, dcast_CObject) +#endif + +#if defined(XRRENDER_R1_EXPORTS) || defined(XRRENDER_R2_EXPORTS) || defined(XRRENDER_R3_EXPORTS) || defined(XRRENDER_R4_EXPORTS) +#include "../xrCDB/ISpatial.h" + +DECLARE_SPECIALIZATION(IRenderable, ISpatial, dcast_Renderable) +DECLARE_SPECIALIZATION(IRender_Light, ISpatial, dcast_Light) +DECLARE_SPECIALIZATION(CObject, ISpatial, dcast_CObject) +#endif + +#undef DECLARE_SPECIALIZATION + +template < typename _Ty > +using clean_type_t = typename std::remove_cv_t>>; + +template +struct is_smart_ptr : std::false_type {}; + +template +struct is_smart_ptr> : std::true_type {}; + +template +struct is_smart_ptr> : std::true_type {}; + +template +struct is_smart_ptr> : std::true_type {}; + +// Helper variable template +template +inline constexpr bool is_smart_ptr_v = is_smart_ptr>>::value; + +#pragma warning(push) +#pragma warning(disable : 4702) +template < typename _To, typename _From > +__forceinline _To smart_cast(_From* ptr) +{ + // Try dedicated cast function if available + if constexpr (has_dcast<_To, _From*>::value) + return has_dcast<_To, _From*>::cast(ptr); + else + return fast_dynamic_cast<_To>(ptr); +}; +#pragma warning(pop) + +// const T* +template < typename _To, typename _From > +__forceinline const _To smart_cast(const _From* ptr) +{ + _From* nonconst_ptr = const_cast<_From*>(ptr); + _To casted_ptr = smart_cast<_To>(nonconst_ptr); + return const_cast(casted_ptr); +}; + +// T& +template < typename _To, typename _From, typename = std::enable_if_t, clean_type_t<_From&>>::value>> +__forceinline _To smart_cast(_From& ref) +{ + using _ToPtr = std::add_pointer_t>; + if constexpr (is_smart_ptr_v<_From>) + { + auto casted_ptr = smart_cast<_ToPtr>(ref.get()); + if (!casted_ptr) throw std::bad_cast{}; + return *casted_ptr; + } + else // It's just a regular object/engine-class + { + auto casted_ptr = smart_cast<_ToPtr>(&ref); + if (!casted_ptr) throw std::bad_cast{}; + return *casted_ptr; + } +}; + +// const T& +template < typename _To, typename _From, typename = std::enable_if_t, clean_type_t<_From&>>::value>> +__forceinline _To smart_cast(const _From& ref) +{ + using _ToPtr = std::add_pointer_t>; + if constexpr (is_smart_ptr_v<_From>) + { + auto casted_ptr = smart_cast<_ToPtr>(const_cast<_From*>(ref.get())); + if (!casted_ptr) throw std::bad_cast{}; + return *casted_ptr; + } + else // It's just a regular object/engine-class + { + auto casted_ptr = smart_cast<_ToPtr>(const_cast<_From*>(&ref)); + if (!casted_ptr) throw std::bad_cast{}; + return *casted_ptr; + } +}; + +// intrusive_ptr -> intrusive_ptr +template +__forceinline intrusive_ptr<_To> smart_cast(intrusive_ptr<_From>& ptr) +{ + return intrusive_ptr<_To>(smart_cast<_To*>(ptr.get())); +} +template +__forceinline intrusive_ptr<_To> smart_cast(const intrusive_ptr<_From>& ptr) +{ + return intrusive_ptr<_To>(smart_cast<_To*>(ptr.get())); +} + +// T -> T +template < typename _To > +__forceinline _To smart_cast(_To ptr) { return ptr; } diff --git a/src/xrServerEntities/smart_cast_impl0.h b/src/xrServerEntities/smart_cast_impl0.h deleted file mode 100644 index e36ef67b94..0000000000 --- a/src/xrServerEntities/smart_cast_impl0.h +++ /dev/null @@ -1,73 +0,0 @@ -//////////////////////////////////////////////////////////////////////////// -// Module : smart_cast_impl1.h -// Created : 17.09.2004 -// Modified : 17.09.2004 -// Author : Dmitriy Iassenev -// Description : Smart dynamic cast implementation -//////////////////////////////////////////////////////////////////////////// - -//#pragma once -// -//#include "../xrcore/_type_traits.h" -//#include "object_type_traits.h" -// -//namespace SmartDynamicCast -//{ -// template -// IC T1* smart_cast(T2* p); -// -// template -// struct CTypeHelper -// { -// template -// struct add -// { -// typedef typename T1::Head Head; -// -// template -// struct selector -// { -// typedef Loki::Typelist< -// Loki::Typelist< -// typename Head::Head, -// Loki::Typelist< -// P, -// typename Head::Tail -// > -// >, -// typename Loki::TL::Erase< -// List, -// Head -// >::Result -// > result; -// }; -// -// template <> -// struct selector -// { -// typedef typename add::result result; -// }; -// -// typedef typename selector::value>::result result; -// }; -// -// template <> -// struct add -// { -// typedef Loki::Typelist>, List> result; -// }; -// -// typedef typename add::result result; -// }; -//}; -// -//#define cast_type_list Loki::NullType -//#define add_to_cast_list(B,A) typedef SmartDynamicCast::CTypeHelper::result TypeList_##A##B -//#define save_cast_list(B,A) TypeList_##A##B -// -//#define DECLARE_SPECIALIZATION(B,A,C) \ -// class A;\ -// class B;\ -// template <> extern\ -// B* SmartDynamicCast::smart_cast(A *p);\ -// add_to_cast_list(B,A); diff --git a/src/xrServerEntities/smart_cast_impl1.h b/src/xrServerEntities/smart_cast_impl1.h deleted file mode 100644 index f764fbc170..0000000000 --- a/src/xrServerEntities/smart_cast_impl1.h +++ /dev/null @@ -1,586 +0,0 @@ -//////////////////////////////////////////////////////////////////////////// -// Module : smart_cast_impl1.h -// Created : 17.09.2004 -// Modified : 17.09.2004 -// Author : Dmitriy Iassenev -// Description : Smart dynamic cast implementation -//////////////////////////////////////////////////////////////////////////// - -//#pragma once -// -//#include "../xrcore/_type_traits.h" -//#include "object_type_traits.h" -// -//#ifdef DEBUG -// void add_smart_cast_stats (LPCSTR,LPCSTR); -//# ifdef SMART_CAST_STATS_ALL -// void add_smart_cast_stats_all (LPCSTR,LPCSTR); -//# endif -//#endif -// -//#ifdef MASTER_GOLD -//# define MAX_SEQUENCE_LENGTH 1 -//#else // #ifdef MASTER_GOLD -//# define MAX_SEQUENCE_LENGTH 1 -//#endif // #ifdef MASTER_GOLD -// -////#define SHOW_SMART_CAST_UNOPTIMIZED_CASES -// -//namespace SmartDynamicCast -//{ -// template -// struct exists -// { -// template -// struct iterator -// { -// typedef typename P::Head Head; -// typedef typename P::Tail Tail; -// -// template -// struct selector -// { -// enum { value = iterator::value }; -// }; -// -// template <> -// struct selector -// { -// enum { value = true }; -// }; -// -// enum { value = selector::value }; -// }; -// -// template <> -// struct iterator -// { -// enum { value = false }; -// }; -// -// enum { value = iterator::value }; -// }; -// -// template -// struct merge -// { -// template -// struct iterator -// { -// typedef Loki::Typelist::result> result; -// }; -// -// template <> -// struct iterator -// { -// typedef List2 result; -// }; -// -// typedef typename iterator::result result; -// }; -// -// template -// struct has_conversion -// { -// template -// struct search_base -// { -// typedef typename T::Head Head; -// typedef typename T::Tail Tail; -// -// template -// struct selector -// { -// typedef typename Head result; -// }; -// -// template <> -// struct selector -// { -// typedef typename search_base::result result; -// }; -// -// typedef typename -// selector< -// is_type::value -// >::result result; -// }; -// -// template <> -// struct search_base -// { -// typedef Loki::NullType result; -// }; -// -// template -// struct search_conversion -// { -// template -// struct selector -// { -// enum { value = true }; -// }; -// -// template <> -// struct selector -// { -// enum { value = search_conversion::value }; -// }; -// -// enum -// { -// value = -// selector< -// object_type_traits::is_same< -// typename T::Head, -// Source -// >::value -// >::value -// }; -// }; -// -// template <> -// struct search_conversion -// { -// enum { value = false }; -// }; -// -// enum { value = search_conversion::result>::value }; -// }; -// -// template -// struct has_any_conversion -// { -// template -// struct iterator -// { -// typedef typename P::Head Head; -// typedef typename P::Tail Tail; -// -// template -// struct _selector -// { -// enum { value = iterator::value }; -// }; -// -// template <> -// struct _selector -// { -// enum { value = true }; -// }; -// -// enum { value = _selector::value }; -// }; -// -// template <> -// struct iterator -// { -// enum { value = false }; -// }; -// -// enum { value = iterator::value }; -// }; -// -// template -// struct CMatcher -// { -// template -// struct CMatchHelper; -// -// template -// struct CMatchHelper2 -// { -// template -// struct CMatchHelper3 -// { -// typedef typename P::Head Head; -// typedef typename P::Tail Tail; -// typedef typename T::Head PrevHead; -// -// template -// struct selector -// { -// template -// struct _selector -// { -// typedef Loki::Typelist> result; -// }; -// -// template <> -// struct _selector -// { -// typedef Loki::Typelist>> result; -// }; -// -// typedef typename -// _selector< -// object_type_traits::is_same< -// Head, -// typename PrevHead::Head -// >::value -// >::result result; -// }; -// -// template <> -// struct selector -// { -// typedef typename CMatchHelper3::result result; -// }; -// -// typedef typename selector::value>::result result; -// }; -// -// template <> -// struct CMatchHelper3 -// { -// typedef typename CMatchHelper::result result; -// }; -// -// typedef typename CMatchHelper3::result result; -// }; -// -// template -// struct CMatchHelper -// { -// typedef typename T::Head Head; -// typedef typename T::Tail Tail; -// typedef typename Head::Tail HeadTail; -// -// template -// struct selector -// { -// typedef typename CMatchHelper2::result result; -// }; -// -// template <> -// struct selector -// { -// typedef typename CMatchHelper::result result; -// }; -// -// typedef typename selector< -// object_type_traits::is_base_and_derived::value || object_type_traits:: -// is_same::value -// >::result result; -// }; -// -// template <> -// struct CMatchHelper -// { -// typedef Loki::NullType result; -// }; -// -// typedef typename CMatchHelper::result result; -// }; -// -// template -// struct conversion_sequence -// { -// template -// struct list_iterator -// { -// typedef typename T::Head Head; -// typedef typename T::Tail Tail; -// typedef typename Head::Tail HeadTail; -// -// template -// struct helper -// { -// typedef typename conversion_sequence::result -// search_result; -// -// template -// struct selector -// { -// typedef typename list_iterator::result result; -// }; -// -// template <> -// struct selector -// { -// typedef search_result result; -// }; -// -// typedef typename -// selector< -// is_type::value -// >::result result; -// }; -// -// template -// struct selector -// { -// typedef typename helper::result helper_result; -// -// template -// struct _selector -// { -// typedef helper_result result; -// }; -// -// template <> -// struct _selector -// { -// typedef typename list_iterator::result result; -// }; -// -// typedef typename _selector::value>::result result; -// }; -// -// template <> -// struct selector -// { -// template -// struct _selector -// { -// typedef typename helper::result helper_result; -// -// template -// struct _selector2 -// { -// typedef Loki::Typelist result; -// }; -// -// template <> -// struct _selector2 -// { -// typedef typename list_iterator::result result; -// }; -// -// typedef typename _selector2::value>::result result; -// }; -// -// template <> -// struct _selector -// { -// typedef typename list_iterator::result result; -// }; -// -// typedef typename _selector::value>::result result; -// }; -// -// typedef typename -// selector< -// can_use_heritage && -// object_type_traits::is_base_and_derived< -// typename Head::Head, -// Source -// >::value -// >::result result; -// }; -// -// template <> -// struct list_iterator -// { -// typedef Loki::NullType result; -// }; -// -// -// template -// struct selector -// { -// STATIC_CHECK(length > 1, Internal_error_please_report); -// -// typedef typename selector<1>::result nearest; -// -// template -// struct _selector -// { -// typedef nearest result; -// }; -// -// template <> -// struct _selector -// { -// typedef typename list_iterator::result result; -// }; -// -// typedef typename -// _selector< -// !is_type::value -// >::result result; -// }; -// -// template <> -// struct selector<1> -// { -// typedef typename CMatcher::result result; -// }; -// -// template <> -// struct selector<0> -// { -// typedef Loki::NullType result; -// }; -// -// typedef typename selector::result result; -// }; -// -// template -// struct get_conversion_sequence -// { -// typedef typename conversion_sequence::result result; -// }; -// -// template -// struct CSmartCaster -// { -// typedef typename T::Head Head; -// typedef typename T::Tail Tail; -// typedef typename Tail::Head NextHead; -// -// template -// struct CHelper -// { -// IC static Target* smart_cast(Head* p) -// { -// return (CSmartCaster::smart_cast(SmartDynamicCast::smart_cast(p))); -// } -// }; -// -// template <> -// struct CHelper -// { -// IC static Target* smart_cast(Head* p) -// { -// return (SmartDynamicCast::smart_cast(p)); -// } -// }; -// -// IC static Target* smart_cast(Head* p) -// { -// if (!p) -// return (reinterpret_cast(p)); -// return (CHelper::smart_cast(p)); -// } -// }; -// -// template -// struct CSmartMatcher -// { -// template -// IC static T1* smart_cast(T2* p) -// { -// return (CSmartCaster::smart_cast(static_cast(p))); -// } -// -// template <> -// IC static T1* smart_cast(T2* p) -// { -//#ifdef SHOW_SMART_CAST_UNOPTIMIZED_CASES -//#pragma todo("Dima to all : this smart_cast is not optimized!") -//#endif -//#ifdef DEBUG -// add_smart_cast_stats(typeid(T2*).name(),typeid(T1*).name()); -//#endif -// return (dynamic_cast(p)); -// } -// }; -// -// template -// struct CHelper1 -// { -// template -// IC static T1* smart_cast(T2* p) -// { -// return (CSmartMatcher::smart_cast < get_conversion_sequence::result > (p)); -// } -// -// template <> -// IC static T1* smart_cast(T2* p) -// { -// return (static_cast(p)); -// } -// }; -// -// template -// IC T1* smart_cast(T2* p) -// { -// return (CHelper1::smart_cast < object_type_traits::is_base_and_derived::value || -// object_type_traits::is_same::value > (p)); -// } -// -// template -// struct CHelper2 -// { -// template -// IC static T1* smart_cast(T2* p) -// { -// STATIC_CHECK(!object_type_traits::is_const::value || object_type_traits::is_const::value, -// Cannot_use_smart_cast_to_convert_const_to_non_const); -// typedef object_type_traits::remove_const::type _T1; -// typedef object_type_traits::remove_const::type _T2; -//#ifdef DEBUG -// T1 *temp = SmartDynamicCast::smart_cast<_T1>(const_cast<_T2*>(p)); -// T1 *test = dynamic_cast(p); -// VERIFY2 ( -// temp == test, -// make_string( -// "SmartCast<%s*>(%s*) FAILED (result differs from the dynamic_cast) or object is CORRUPTED (0x%08x -> 0x%08x)!", -// typeid(T1).name(), -// typeid(T2).name(), -// *(u32*)&test, -// *(u32*)&temp -// ) -// ); -// return (temp); -//#else -// return (SmartDynamicCast::smart_cast<_T1>(const_cast<_T2*>(p))); -//#endif -// } -// -// template <> -// IC static void* smart_cast(T2* p) -// { -//#ifdef SHOW_SMART_CAST_UNOPTIMIZED_CASES -//#pragma todo("Dima to all : this smart_cast is not optimized!") -//#endif -//#ifdef DEBUG -// add_smart_cast_stats(typeid(T2*).name(),typeid(void*).name()); -//#endif -// if (!p) -// return ((void*)0); -// return (dynamic_cast(p)); -// } -// }; -//}; -// -//template -//IC T1 smart_cast(T2* p) -//{ -//#ifdef PURE_DYNAMIC_CAST_COMPATIBILITY_CHECK -// STATIC_CHECK(object_type_traits::is_pointer::value, Invalid_target_type_for_Dynamic_Cast); -// STATIC_CHECK( -// object_type_traits::is_void::type>::value || is_polymorphic< -// object_type_traits::remove_pointer::type>::result, Invalid_target_type_for_Dynamic_Cast); -// STATIC_CHECK(is_polymorphic::result, Invalid_source_type_for_Dynamic_Cast); -//#endif -//#ifdef SMART_CAST_STATS_ALL -// add_smart_cast_stats_all (typeid(T2*).name(),typeid(T1).name()); -//#endif -// if (!p) -// return (reinterpret_cast(p)); -// return (SmartDynamicCast::CHelper2::smart_cast < object_type_traits::remove_pointer::type > (p)); -//} -// -//template -//IC T1 smart_cast(T2& p) -//{ -//#ifdef PURE_DYNAMIC_CAST_COMPATIBILITY_CHECK -// STATIC_CHECK(object_type_traits::is_reference::value, Invalid_target_type_for_Dynamic_Cast); -// STATIC_CHECK(is_polymorphic::type>::result, -// Invalid_target_type_for_Dynamic_Cast); -// STATIC_CHECK(is_polymorphic::result, Invalid_source_type_for_Dynamic_Cast); -//#endif -//#ifdef SMART_CAST_STATS_ALL -// add_smart_cast_stats_all (typeid(T2*).name(),typeid(object_type_traits::remove_reference::type*).name()); -//#endif -// return (*SmartDynamicCast::CHelper2::smart_cast < object_type_traits::remove_reference::type > (&p)); -//} -// -//#ifdef XRGAME_EXPORTS -//template <> -//extern -//CGameObject* SmartDynamicCast::smart_cast(CObject* p); -//#endif diff --git a/src/xrServerEntities/smart_cast_impl2.h b/src/xrServerEntities/smart_cast_impl2.h deleted file mode 100644 index 057f705555..0000000000 --- a/src/xrServerEntities/smart_cast_impl2.h +++ /dev/null @@ -1,28 +0,0 @@ -//////////////////////////////////////////////////////////////////////////// -// Module : smart_cast_impl2.h -// Created : 17.09.2004 -// Modified : 17.09.2004 -// Author : Dmitriy Iassenev -// Description : Smart dynamic cast implementation -//////////////////////////////////////////////////////////////////////////// - -//#pragma once -// -//#undef DECLARE_SPECIALIZATION -// -//#define DECLARE_SPECIALIZATION(B,A,C) \ -// template <>\ -// B* SmartDynamicCast::smart_cast(A *p){return p->C();}; -//#ifdef XRGAME_EXPORTS -//template <> -//CGameObject* SmartDynamicCast::smart_cast(CObject* p) -//{ -// return static_cast(p); -//} -// -//template <> -//Feel::Sound* SmartDynamicCast::smart_cast(ISpatial* p) -//{ -// return (p->dcast_FeelSound()); -//} -//#endif diff --git a/src/xrServerEntities/xrEProps.h b/src/xrServerEntities/xrEProps.h index 568158424f..f99622133f 100644 --- a/src/xrServerEntities/xrEProps.h +++ b/src/xrServerEntities/xrEProps.h @@ -21,17 +21,17 @@ enum EItemType TYPE_OBJECT = 1 }; -typedef fastdelegate::FastDelegate1 TOnILItemsFocused; -typedef fastdelegate::FastDelegate0<> TOnILCloseEvent; -typedef fastdelegate::FastDelegate3 TOnItemRename; -typedef fastdelegate::FastDelegate3 TOnItemRemove; -typedef fastdelegate::FastDelegate0<> TOnItemAfterRemove; -typedef fastdelegate::FastDelegate0<> TOnCloseEvent; -typedef fastdelegate::FastDelegate0<> TOnModifiedEvent; +typedef xr_delegate TOnILItemsFocused; +typedef xr_delegate TOnILCloseEvent; +typedef xr_delegate TOnItemRename; +typedef xr_delegate TOnItemRemove; +typedef xr_delegate TOnItemAfterRemove; +typedef xr_delegate TOnCloseEvent; +typedef xr_delegate TOnModifiedEvent; #ifdef __BORLANDC__ # include "mxPlacemnt.hpp" - typedef fastdelegate::FastDelegate1 TOnILItemFocused; + typedef xr_delegate TOnILItemFocused; //--------------------------------------------------------------------------- void XR_EPROPS_API CheckWindowPos(TForm* form); //--------------------------------------------------------------------------- diff --git a/src/xrServerEntities/xrServer_Object_Base.cpp b/src/xrServerEntities/xrServer_Object_Base.cpp index 10f250f4c4..5898bd14d7 100644 --- a/src/xrServerEntities/xrServer_Object_Base.cpp +++ b/src/xrServerEntities/xrServer_Object_Base.cpp @@ -366,7 +366,7 @@ BOOL CSE_Abstract::Spawn_Read(NET_Packet& tNetPacket) u16 size; tNetPacket.r_u16(size); // size bool b1 = (m_tClassID == CLSID_SPECTATOR); - bool b2 = (size > sizeof(size)) || (tNetPacket.inistream != NULL); + bool b2 = size > sizeof(size); R_ASSERT3((b1 || b2), "cannot read object, which is not successfully saved :(", name_replace()); STATE_Read(tNetPacket, size); return TRUE; diff --git a/src/xrServerEntities/xrServer_Objects.cpp b/src/xrServerEntities/xrServer_Objects.cpp index c55bc99eed..98ad52974d 100644 --- a/src/xrServerEntities/xrServer_Objects.cpp +++ b/src/xrServerEntities/xrServer_Objects.cpp @@ -35,13 +35,7 @@ void CSE_Shape::cform_read(NET_Packet& tNetPacket) { case 0: { - if (tNetPacket.inistream) - { - tNetPacket.r_vec3(S.data.sphere.P); - tNetPacket.r_float(S.data.sphere.R); - } - else - tNetPacket.r(&S.data.sphere, sizeof(S.data.sphere)); + tNetPacket.r(&S.data.sphere, sizeof(S.data.sphere)); } break; case 1: @@ -64,13 +58,7 @@ void CSE_Shape::cform_write(NET_Packet& tNetPacket) { case 0: { - if (tNetPacket.inistream) - { - tNetPacket.w_vec3(S.data.sphere.P); - tNetPacket.w_float(S.data.sphere.R); - } - else - tNetPacket.w(&S.data.sphere, sizeof(S.data.sphere)); + tNetPacket.w(&S.data.sphere, sizeof(S.data.sphere)); } break; case 1: diff --git a/src/xrServerEntities/xrServer_Objects_ALife_Items.cpp b/src/xrServerEntities/xrServer_Objects_ALife_Items.cpp index d6c73db7b0..020565bd52 100644 --- a/src/xrServerEntities/xrServer_Objects_ALife_Items.cpp +++ b/src/xrServerEntities/xrServer_Objects_ALife_Items.cpp @@ -550,6 +550,11 @@ void CSE_ALifeItemWeapon::clone_addons(CSE_ALifeItemWeapon* parent) m_addon_flags = parent->m_addon_flags; } +void CSE_ALifeItemWeapon::clone_upgrades(CSE_ALifeItemWeapon* parent) +{ + m_upgrades = parent->m_upgrades; +} + void CSE_ALifeItemWeapon::UPDATE_Write(NET_Packet& tNetPacket) { inherited::UPDATE_Write(tNetPacket); diff --git a/src/xrServerEntities/xrServer_Objects_ALife_Items.h b/src/xrServerEntities/xrServer_Objects_ALife_Items.h index 539291362a..518d674426 100644 --- a/src/xrServerEntities/xrServer_Objects_ALife_Items.h +++ b/src/xrServerEntities/xrServer_Objects_ALife_Items.h @@ -199,6 +199,8 @@ SERVER_ENTITY_DECLARE_BEGIN(CSE_ALifeItemWeapon, CSE_ALifeItem) u16 get_ammo_magsize(); void clone_addons(CSE_ALifeItemWeapon* parent); + void clone_upgrades(CSE_ALifeItemWeapon* parent); + virtual BOOL Net_Relevant(); virtual CSE_ALifeItemWeapon* cast_item_weapon() { return this; } diff --git a/src/xrServerEntities/xrServer_Objects_ALife_Items_script.cpp b/src/xrServerEntities/xrServer_Objects_ALife_Items_script.cpp index c00abe8412..1d890ee9f9 100644 --- a/src/xrServerEntities/xrServer_Objects_ALife_Items_script.cpp +++ b/src/xrServerEntities/xrServer_Objects_ALife_Items_script.cpp @@ -78,6 +78,7 @@ void CSE_ALifeItemWeapon::script_register(lua_State* L) CSE_ALifeItem ) .def("clone_addons", &CSE_ALifeItemWeapon::clone_addons) + .def("clone_upgrades", &CSE_ALifeItemWeapon::clone_upgrades) .def("set_ammo_elapsed", &CSE_ALifeItemWeapon::set_ammo_elapsed) .def("get_ammo_elapsed", &CSE_ALifeItemWeapon::get_ammo_elapsed) .def("get_ammo_magsize", &CSE_ALifeItemWeapon::get_ammo_magsize) diff --git a/src/xrServerEntities/xrServer_Objects_ALife_Monsters.cpp b/src/xrServerEntities/xrServer_Objects_ALife_Monsters.cpp index 671e4a3f17..e7a8f290e5 100644 --- a/src/xrServerEntities/xrServer_Objects_ALife_Monsters.cpp +++ b/src/xrServerEntities/xrServer_Objects_ALife_Monsters.cpp @@ -610,7 +610,7 @@ CSE_ALifeTrader::~CSE_ALifeTrader() #ifdef DEBUG bool CSE_ALifeTrader::match_configuration () const { - return (!strstr(Core.Params,"-designer")); + return (!Core.ParamsData.test(ECoreParams::designer)); } #endif @@ -1041,7 +1041,7 @@ CSE_ALifeCreatureAbstract::~CSE_ALifeCreatureAbstract() #ifdef DEBUG bool CSE_ALifeCreatureAbstract::match_configuration () const { - return (!strstr(Core.Params,"-designer")); + return (!Core.ParamsData.test(ECoreParams::designer)); } #endif @@ -1329,11 +1329,7 @@ void CSE_ALifeMonsterAbstract::STATE_Write(NET_Packet& tNetPacket) tNetPacket.w_stringZ(m_out_space_restrictors); tNetPacket.w_stringZ(m_in_space_restrictors); tNetPacket.w_u16(m_smart_terrain_id); - - if (tNetPacket.inistream) - tNetPacket.w_u16((m_task_reached) ? 1 : 0); - else - tNetPacket.w(&m_task_reached, sizeof(m_task_reached)); + tNetPacket.w(&m_task_reached, sizeof(m_task_reached)); } void CSE_ALifeMonsterAbstract::STATE_Read(NET_Packet& tNetPacket, u16 size) @@ -1351,14 +1347,7 @@ void CSE_ALifeMonsterAbstract::STATE_Read(NET_Packet& tNetPacket, u16 size) if (m_wVersion > 113) { - if (tNetPacket.inistream) - { - u16 tmp; - tNetPacket.r_u16(tmp); - m_task_reached = (tmp != 0); - } - else - tNetPacket.r(&m_task_reached, sizeof(m_task_reached)); + tNetPacket.r(&m_task_reached, sizeof(m_task_reached)); } } diff --git a/src/xrSound/Sound.h b/src/xrSound/Sound.h index 98d57177bc..1c14f68c20 100644 --- a/src/xrSound/Sound.h +++ b/src/xrSound/Sound.h @@ -2,6 +2,7 @@ #define SoundH #pragma once + #ifdef XRSOUND_EXPORTS #define XRSOUND_API //__declspec(dllexport) diff --git a/src/xrSound/SoundRender_Core.cpp b/src/xrSound/SoundRender_Core.cpp index ea3f448cb1..79cfd90970 100644 --- a/src/xrSound/SoundRender_Core.cpp +++ b/src/xrSound/SoundRender_Core.cpp @@ -80,7 +80,7 @@ void CSoundRender_Core::_initialize(int stage) bReady = TRUE; - if (strstr(Core.Params, "-prefetch_sounds")) + if (Core.ParamsData.test(ECoreParams::prefetch_sounds)) { i_create_all_sources(); } diff --git a/src/xrSound/SoundRender_Core_Processor.cpp b/src/xrSound/SoundRender_Core_Processor.cpp index f7d0925384..f353887309 100644 --- a/src/xrSound/SoundRender_Core_Processor.cpp +++ b/src/xrSound/SoundRender_Core_Processor.cpp @@ -163,6 +163,7 @@ static u32 g_saved_event_count = 0; void CSoundRender_Core::update_events() { + PROF_EVENT("Sound: Update Events"); g_saved_event_count = s_events.size(); for (u32 it = 0; it < s_events.size(); it++) { diff --git a/src/xrSound/SoundRender_Core_SourceManager.cpp b/src/xrSound/SoundRender_Core_SourceManager.cpp index 3d78d8d2cb..51938d7c20 100644 --- a/src/xrSound/SoundRender_Core_SourceManager.cpp +++ b/src/xrSound/SoundRender_Core_SourceManager.cpp @@ -4,7 +4,6 @@ #include "SoundRender_Core.h" #include "SoundRender_Source.h" #include "../xrCore/ScopeLock.hpp" -#include CSoundRender_Source* CSoundRender_Core::i_create_source(LPCSTR name) { @@ -67,7 +66,7 @@ void CSoundRender_Core::i_create_all_sources() lock.Leave(); }; - tbb::parallel_for_each(flist, processFile); + xr_parallel_foreach(flist.begin(), flist.end(), processFile); Msg("Finished creating %d sound sources. Duration: %d ms", s_sources.size() - sizeBefore, T.GetElapsed_ms()); } diff --git a/src/xrSound/SoundRender_Environment.cpp b/src/xrSound/SoundRender_Environment.cpp index 31f29bbc80..273d39d752 100644 --- a/src/xrSound/SoundRender_Environment.cpp +++ b/src/xrSound/SoundRender_Environment.cpp @@ -108,7 +108,7 @@ bool CSoundRender_Environment::load(IReader* fs) fs->r_stringZ(name); - static auto mB_to_gain = [](float mb) + static auto mB_to_gain = [](float mb) noexcept { return powf(10.0f, mb / 2000.0f); }; diff --git a/src/xrSound/SoundRender_Source_loader.cpp b/src/xrSound/SoundRender_Source_loader.cpp index 7b56b235d4..67394c2058 100644 --- a/src/xrSound/SoundRender_Source_loader.cpp +++ b/src/xrSound/SoundRender_Source_loader.cpp @@ -63,6 +63,7 @@ void CSoundRender_Source::decompress(u32 line, OggVorbis_File* ovf) bool CSoundRender_Source::LoadWave(LPCSTR pName) { + PROF_EVENT("Sound: Load ogg"); pname = pName; // Load file into memory and parse WAV-format @@ -75,6 +76,7 @@ bool CSoundRender_Source::LoadWave(LPCSTR pName) vorbis_info* ovi = ov_info(&ovf, -1); // verify R_ASSERT3(ovi, "Invalid source info:", pname.c_str()); + //R_ASSERT3(ovi->rate == 44100, "Invalid source rate:", pname.c_str()); if (ovi->rate != 44100) { @@ -136,7 +138,7 @@ bool CSoundRender_Source::LoadWave(LPCSTR pName) } else { - if (strstr(Core.Params, "-dbg")) + if (Core.isDebug()) { Log("! Invalid ogg-comment version, file: ", pname.c_str()); } @@ -144,7 +146,7 @@ bool CSoundRender_Source::LoadWave(LPCSTR pName) } else { - if (strstr(Core.Params, "-dbg")) + if (Core.isDebug()) { Log("! Missing ogg-comment, file: ", pname.c_str()); } diff --git a/src/xrSound/sound.cpp b/src/xrSound/sound.cpp index af377819e0..273f73af44 100644 --- a/src/xrSound/sound.cpp +++ b/src/xrSound/sound.cpp @@ -14,7 +14,7 @@ void CSound_manager_interface::_create(int stage) SoundRender = SoundRenderA; Sound = SoundRender; - if (strstr(Core.Params, "-nosound")) + if (Core.ParamsData.test(ECoreParams::nosound)) { SoundRender->bPresent = FALSE; return; diff --git a/src/xrSound/stdafx.h b/src/xrSound/stdafx.h index e9c4e6b5a5..326bd39c4c 100644 --- a/src/xrSound/stdafx.h +++ b/src/xrSound/stdafx.h @@ -33,6 +33,7 @@ #define ENGINE_API #include "../xrCore/xr_resource.h" + #include "../xrCore/profiler.h" #ifdef _EDITOR diff --git a/src/xrSound/xrSound.vcxproj b/src/xrSound/xrSound.vcxproj index d0f9b1575e..005f91fcbf 100644 --- a/src/xrSound/xrSound.vcxproj +++ b/src/xrSound/xrSound.vcxproj @@ -13,6 +13,10 @@ Release x64 + + VerifiedDX11ASAN + x64 + VerifiedDX11 x64 @@ -56,6 +60,14 @@ false x64 + + StaticLibrary + v143 + MultiByte + false + x64 + true + StaticLibrary v143 @@ -86,6 +98,11 @@ + + + + + @@ -115,6 +132,11 @@ $(xrGameDir)bin_dbg\$(Platform)\$(Configuration)\ $(xrIntDir)$(ProjectName)\ + + false + $(xrGameDir)bin_dbg\$(Platform)\$(Configuration)\ + $(xrIntDir)$(ProjectName)\ + false $(xrGameDir)bin_dbg\$(Platform)\$(Configuration)\ @@ -200,7 +222,7 @@ false false $(xrSdkDir)include;$(XRAY_16X_LIBS)libvorbis-1.2.3\include;$(XRAY_16X_LIBS)libogg-1.1.4\include;$(SolutionDir)3rd party\OpenAL-new\include;%(AdditionalIncludeDirectories) - USE_VERIFY_IN_RELEASE;WIN32;NDEBUG;_WINDOWS;_USRDLL;XRSOUND_EXPORTS;_SECURE_SCL=0;AL_LIBTYPE_STATIC;%(PreprocessorDefinitions) + XRCORE_PROFILER;USE_VERIFY_IN_RELEASE;WIN32;NDEBUG;_WINDOWS;_USRDLL;XRSOUND_EXPORTS;_SECURE_SCL=0;AL_LIBTYPE_STATIC;%(PreprocessorDefinitions) NotSet Use EditAndContinue @@ -237,7 +259,7 @@ false false $(xrSdkDir)include;$(XRAY_16X_LIBS)libvorbis-1.2.3\include;$(XRAY_16X_LIBS)libogg-1.1.4\include;$(SolutionDir)3rd party\OpenAL-new\include;%(AdditionalIncludeDirectories) - USE_VERIFY_IN_RELEASE;WIN32;NDEBUG;_WINDOWS;_USRDLL;XRSOUND_EXPORTS;_SECURE_SCL=0;AL_LIBTYPE_STATIC;%(PreprocessorDefinitions) + XRCORE_PROFILER;USE_VERIFY_IN_RELEASE;WIN32;NDEBUG;_WINDOWS;_USRDLL;XRSOUND_EXPORTS;_SECURE_SCL=0;AL_LIBTYPE_STATIC;%(PreprocessorDefinitions) NotSet Use EditAndContinue @@ -264,6 +286,43 @@ true + + + Disabled + Disabled + false + Neither + false + false + false + $(xrSdkDir)include;$(XRAY_16X_LIBS)libvorbis-1.2.3\include;$(XRAY_16X_LIBS)libogg-1.1.4\include;$(SolutionDir)3rd party\OpenAL-new\include;%(AdditionalIncludeDirectories) + XRCORE_PROFILER;USE_VERIFY_IN_RELEASE;_DISABLE_VECTOR_ANNOTATION;_DISABLE_STRING_ANNOTATION;WIN32;NDEBUG;_WINDOWS;_USRDLL;XRSOUND_EXPORTS;_SECURE_SCL=0;AL_LIBTYPE_STATIC;%(PreprocessorDefinitions) + NotSet + Use + ProgramDatabase + USE_LUAJIT_ONE + true + Level4 + false + MultiThreadedDLL + false + stdcpp17 + true + + + libogg_static.lib;libvorbis_static.lib;libvorbisfile_static.lib;OpenAL32.lib;%(AdditionalDependencies) + $(xrSdkDir)libraries;$(xrLibDir);$(xrSdkDir)..\lib\$(Platform)\Release;$(xrGameDir)bin_dbg;%(AdditionalLibraryDirectories) + NotSet + true + true + true + Default + false + $(xrLibDir)$(TargetName).lib + /ignore:4099 + true + + $(xrSdkDir)include;$(XRAY_16X_LIBS)libvorbis-1.2.3\include;$(XRAY_16X_LIBS)libogg-1.1.4\include;$(SolutionDir)3rd party\OpenAL-new\include;%(AdditionalIncludeDirectories) @@ -326,6 +385,8 @@ + + @@ -352,6 +413,7 @@ Create Create Create + Create Create diff --git a/src/xrXMLParser/xrXMLParser.vcxproj b/src/xrXMLParser/xrXMLParser.vcxproj index 6ae1c69718..109825b7f2 100644 --- a/src/xrXMLParser/xrXMLParser.vcxproj +++ b/src/xrXMLParser/xrXMLParser.vcxproj @@ -13,6 +13,10 @@ Release x64 + + VerifiedDX11ASAN + x64 + VerifiedDX11 x64 @@ -57,6 +61,15 @@ false x64 + + StaticLibrary + v143 + false + MultiByte + false + x64 + true + StaticLibrary v143 @@ -87,6 +100,11 @@ + + + + + @@ -116,6 +134,11 @@ $(xrGameDir)bin_dbg\$(Platform)\$(Configuration)\ $(xrIntDir)$(ProjectName)\ + + false + $(xrGameDir)bin_dbg\$(Platform)\$(Configuration)\ + $(xrIntDir)$(ProjectName)\ + false $(xrGameDir)bin_dbg\$(Platform)\$(Configuration)\ @@ -223,7 +246,7 @@ false false $(xrSdkDir)include;$(xrSdkDir)include;%(AdditionalIncludeDirectories) - USE_VERIFY_IN_RELEASE;NDEBUG;WIN32;_WINDOWS;XRXMLPARSER_EXPORTS;_SECURE_SCL=0;%(PreprocessorDefinitions) + XRCORE_PROFILER;USE_VERIFY_IN_RELEASE;NDEBUG;WIN32;_WINDOWS;XRXMLPARSER_EXPORTS;_SECURE_SCL=0;%(PreprocessorDefinitions) NotSet Use EditAndContinue @@ -270,7 +293,7 @@ false false $(xrSdkDir)include;$(xrSdkDir)include;%(AdditionalIncludeDirectories) - USE_VERIFY_IN_RELEASE;NDEBUG;WIN32;_WINDOWS;XRXMLPARSER_EXPORTS;_SECURE_SCL=0;%(PreprocessorDefinitions) + XRCORE_PROFILER;USE_VERIFY_IN_RELEASE;NDEBUG;WIN32;_WINDOWS;XRXMLPARSER_EXPORTS;_SECURE_SCL=0;%(PreprocessorDefinitions) NotSet Use EditAndContinue @@ -301,6 +324,53 @@ true + + + NDEBUG;%(PreprocessorDefinitions) + true + true + $(OutDir)$(TargetName).tlb + + + Disabled + Disabled + false + Neither + false + false + false + $(xrSdkDir)include;$(xrSdkDir)include;%(AdditionalIncludeDirectories) + XRCORE_PROFILER;USE_VERIFY_IN_RELEASE;_DISABLE_VECTOR_ANNOTATION;_DISABLE_STRING_ANNOTATION;NDEBUG;WIN32;_WINDOWS;XRXMLPARSER_EXPORTS;_SECURE_SCL=0;%(PreprocessorDefinitions) + NotSet + Use + ProgramDatabase + USE_LUAJIT_ONE + true + Level4 + false + MultiThreadedDLL + false + stdcpp17 + true + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + + + /MACHINE:X64 %(AdditionalOptions) + true + $(xrSdkDir)libraries;$(xrLibDir);%(AdditionalLibraryDirectories) + NotSet + true + true + true + Default + false + $(xrLibDir)$(TargetName).lib + true + + NDEBUG;%(PreprocessorDefinitions) @@ -351,6 +421,7 @@ Create Create Create + Create Create