diff --git a/.gitignore b/.gitignore index 17c3d9fa..e430d78f 100644 --- a/.gitignore +++ b/.gitignore @@ -26,4 +26,6 @@ packages/ !*.lib # Resources bin -*.aps \ No newline at end of file +*.aps + +docs/ \ No newline at end of file diff --git a/Doxyfile b/Doxyfile new file mode 100644 index 00000000..146898d9 --- /dev/null +++ b/Doxyfile @@ -0,0 +1,90 @@ +# Doxyfile 1.8.16 + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- + +PROJECT_NAME = "Kiwano Engine" +PROJECT_NUMBER = v1.0.0 +PROJECT_BRIEF = +PROJECT_LOGO = logo/logo_square_tiny.png + +DOXYFILE_ENCODING = UTF-8 +CREATE_SUBDIRS = YES + +OUTPUT_LANGUAGE = Chinese +OUTPUT_DIRECTORY = docs/ + +EXTRACT_PRIVATE = NO +EXTRACT_STATIC = YES +EXTRACT_LOCAL_CLASSES = NO + +HIDE_UNDOC_MEMBERS = NO +HIDE_UNDOC_CLASSES = NO + +SHOW_INCLUDE_FILES = YES +SHOW_USED_FILES = NO +SHOW_FILES = NO +SHOW_NAMESPACES = YES + +#--------------------------------------------------------------------------- +# Configuration options related to the input files +#--------------------------------------------------------------------------- + +INPUT = src/ +INPUT_ENCODING = gb2312 +FILE_PATTERNS = *.c \ + *.cc \ + *.cxx \ + *.cpp \ + *.c++ \ + *.h \ + *.hh \ + *.hxx \ + *.hpp \ + *.h++ + +RECURSIVE = YES +EXCLUDE = src/3rd-party \ + src/kiwano/platform/win32 \ + src/kiwano/renderer/win32 + +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- + +ENABLE_PREPROCESSING = YES +MACRO_EXPANSION = YES +PREDEFINED = KGE_API= \ + KGE_DOXYGEN_DO_NOT_INCLUDE= + +# The INCLUDE_PATH tag can be used to specify one or more directories that +# contain include files that are not input files but should be processed by the +# preprocessor. +# This tag requires that the tag SEARCH_INCLUDES is set to YES. + +SEARCH_INCLUDES = YES +INCLUDE_PATH = +INCLUDE_FILE_PATTERNS = + +#--------------------------------------------------------------------------- +# Configuration options related to the HTML output +#--------------------------------------------------------------------------- + +GENERATE_HTML = YES +HTML_OUTPUT = html + +HTML_HEADER = +HTML_FOOTER = +HTML_STYLESHEET = +HTML_EXTRA_STYLESHEET = + +GENERATE_TREEVIEW = YES +ENUM_VALUES_PER_LINE = 4 +TREEVIEW_WIDTH = 250 + +#--------------------------------------------------------------------------- +# Configuration options related to the LATEX output +#--------------------------------------------------------------------------- + +GENERATE_LATEX = NO diff --git a/logo/logo_square_tiny.png b/logo/logo_square_tiny.png new file mode 100644 index 00000000..63829ef3 Binary files /dev/null and b/logo/logo_square_tiny.png differ diff --git a/projects/3rd-party/Box2D/libBox2D.vcxproj b/projects/3rd-party/Box2D/libBox2D.vcxproj index d4adf92f..7e2bab7c 100644 --- a/projects/3rd-party/Box2D/libBox2D.vcxproj +++ b/projects/3rd-party/Box2D/libBox2D.vcxproj @@ -185,4 +185,4 @@ - \ No newline at end of file + diff --git a/projects/3rd-party/StackWalker/libStackWalker.vcxproj b/projects/3rd-party/StackWalker/libStackWalker.vcxproj deleted file mode 100644 index 8907d076..00000000 --- a/projects/3rd-party/StackWalker/libStackWalker.vcxproj +++ /dev/null @@ -1,97 +0,0 @@ - - - - - - - - - - - Debug - Win32 - - - Release - Win32 - - - - {3A3948DC-9865-46B3-B7B9-7E5572704ED2} - libStackWalker - - - - StaticLibrary - true - Unicode - $(DefaultPlatformToolset) - - - StaticLibrary - false - false - Unicode - $(DefaultPlatformToolset) - - - - - - - - - - - - - - - $(SolutionDir)\output\$(PlatformToolset)\$(Platform)\$(Configuration)\ - $(SolutionDir)\build\$(PlatformToolset)\$(Platform)\$(Configuration)\$(ProjectName)\ - true - - - $(SolutionDir)\output\$(PlatformToolset)\$(Platform)\$(Configuration)\ - $(SolutionDir)\build\$(PlatformToolset)\$(Platform)\$(Configuration)\$(ProjectName)\ - true - - - - Level3 - Disabled - true - None - true - ../../../src/3rd-party; - false - - - Windows - true - - - - - Level3 - MaxSpeed - true - true - false - true - None - true - ../../../src/3rd-party; - false - - - Windows - false - true - true - - - - - - \ No newline at end of file diff --git a/projects/3rd-party/StackWalker/libStackWalker.vcxproj.filters b/projects/3rd-party/StackWalker/libStackWalker.vcxproj.filters deleted file mode 100644 index 08a3c777..00000000 --- a/projects/3rd-party/StackWalker/libStackWalker.vcxproj.filters +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - \ No newline at end of file diff --git a/projects/3rd-party/curl/libcurl.vcxproj b/projects/3rd-party/curl/libcurl.vcxproj index 9a4c7664..4fa3e9d3 100644 --- a/projects/3rd-party/curl/libcurl.vcxproj +++ b/projects/3rd-party/curl/libcurl.vcxproj @@ -102,4 +102,4 @@ - \ No newline at end of file + diff --git a/projects/3rd-party/imgui/libimgui.vcxproj b/projects/3rd-party/imgui/libimgui.vcxproj index 0912e006..10ff944f 100644 --- a/projects/3rd-party/imgui/libimgui.vcxproj +++ b/projects/3rd-party/imgui/libimgui.vcxproj @@ -102,4 +102,4 @@ - \ No newline at end of file + diff --git a/projects/3rd-party/tinyxml2/libtinyxml2.vcxproj b/projects/3rd-party/tinyxml2/libtinyxml2.vcxproj index d6ba3b24..8d2e1039 100644 --- a/projects/3rd-party/tinyxml2/libtinyxml2.vcxproj +++ b/projects/3rd-party/tinyxml2/libtinyxml2.vcxproj @@ -94,4 +94,4 @@ - \ No newline at end of file + diff --git a/projects/Kiwano.sln b/projects/Kiwano.sln index 3cf1ce1f..2899bd53 100644 --- a/projects/Kiwano.sln +++ b/projects/Kiwano.sln @@ -14,8 +14,6 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "kiwano-physics", "kiwano-ph EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "3rd-party", "3rd-party", "{2D8919F2-8922-4B3F-8F68-D4127C6BCBB7}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libStackWalker", "3rd-party\StackWalker\libStackWalker.vcxproj", "{3A3948DC-9865-46B3-B7B9-7E5572704ED2}" -EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libtinyxml2", "3rd-party\tinyxml2\libtinyxml2.vcxproj", "{AB47E875-85E5-4105-A71E-88930EAAB910}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libimgui", "3rd-party\imgui\libimgui.vcxproj", "{7FA1E56D-62AC-47D1-97D1-40B302724198}" @@ -47,10 +45,10 @@ Global {A7062ED8-8910-48A5-A3BC-C1612672571F}.Debug|Win32.Build.0 = Debug|Win32 {A7062ED8-8910-48A5-A3BC-C1612672571F}.Release|Win32.ActiveCfg = Release|Win32 {A7062ED8-8910-48A5-A3BC-C1612672571F}.Release|Win32.Build.0 = Release|Win32 - {3A3948DC-9865-46B3-B7B9-7E5572704ED2}.Debug|Win32.ActiveCfg = Debug|Win32 - {3A3948DC-9865-46B3-B7B9-7E5572704ED2}.Debug|Win32.Build.0 = Debug|Win32 - {3A3948DC-9865-46B3-B7B9-7E5572704ED2}.Release|Win32.ActiveCfg = Release|Win32 - {3A3948DC-9865-46B3-B7B9-7E5572704ED2}.Release|Win32.Build.0 = Release|Win32 + {DF599AFB-744F-41E5-AF0C-2146F90575C8}.Debug|Win32.ActiveCfg = Debug|Win32 + {DF599AFB-744F-41E5-AF0C-2146F90575C8}.Debug|Win32.Build.0 = Debug|Win32 + {DF599AFB-744F-41E5-AF0C-2146F90575C8}.Release|Win32.ActiveCfg = Release|Win32 + {DF599AFB-744F-41E5-AF0C-2146F90575C8}.Release|Win32.Build.0 = Release|Win32 {AB47E875-85E5-4105-A71E-88930EAAB910}.Debug|Win32.ActiveCfg = Debug|Win32 {AB47E875-85E5-4105-A71E-88930EAAB910}.Debug|Win32.Build.0 = Debug|Win32 {AB47E875-85E5-4105-A71E-88930EAAB910}.Release|Win32.ActiveCfg = Release|Win32 @@ -67,16 +65,11 @@ Global {0CBA9295-F14D-4966-A7C4-1DD68158176C}.Debug|Win32.Build.0 = Debug|Win32 {0CBA9295-F14D-4966-A7C4-1DD68158176C}.Release|Win32.ActiveCfg = Release|Win32 {0CBA9295-F14D-4966-A7C4-1DD68158176C}.Release|Win32.Build.0 = Release|Win32 - {DF599AFB-744F-41E5-AF0C-2146F90575C8}.Debug|Win32.ActiveCfg = Debug|Win32 - {DF599AFB-744F-41E5-AF0C-2146F90575C8}.Debug|Win32.Build.0 = Debug|Win32 - {DF599AFB-744F-41E5-AF0C-2146F90575C8}.Release|Win32.ActiveCfg = Release|Win32 - {DF599AFB-744F-41E5-AF0C-2146F90575C8}.Release|Win32.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection GlobalSection(NestedProjects) = preSolution - {3A3948DC-9865-46B3-B7B9-7E5572704ED2} = {2D8919F2-8922-4B3F-8F68-D4127C6BCBB7} {AB47E875-85E5-4105-A71E-88930EAAB910} = {2D8919F2-8922-4B3F-8F68-D4127C6BCBB7} {7FA1E56D-62AC-47D1-97D1-40B302724198} = {2D8919F2-8922-4B3F-8F68-D4127C6BCBB7} {A9ABACC7-75A1-46BA-8E48-4105346D9719} = {2D8919F2-8922-4B3F-8F68-D4127C6BCBB7} diff --git a/projects/kiwano-audio/kiwano-audio.vcxproj b/projects/kiwano-audio/kiwano-audio.vcxproj index 4bb63a42..7836bc77 100644 --- a/projects/kiwano-audio/kiwano-audio.vcxproj +++ b/projects/kiwano-audio/kiwano-audio.vcxproj @@ -1,7 +1,7 @@ - + @@ -19,7 +19,7 @@ - + @@ -39,7 +39,7 @@ StaticLibrary false - false + true Unicode $(DefaultPlatformToolset) @@ -108,4 +108,4 @@ - \ No newline at end of file + diff --git a/projects/kiwano-audio/kiwano-audio.vcxproj.filters b/projects/kiwano-audio/kiwano-audio.vcxproj.filters index 2e5726c2..a842f4fe 100644 --- a/projects/kiwano-audio/kiwano-audio.vcxproj.filters +++ b/projects/kiwano-audio/kiwano-audio.vcxproj.filters @@ -3,16 +3,16 @@ - + - + \ No newline at end of file diff --git a/projects/kiwano-imgui/kiwano-imgui.vcxproj b/projects/kiwano-imgui/kiwano-imgui.vcxproj index faecc0d6..55833de5 100644 --- a/projects/kiwano-imgui/kiwano-imgui.vcxproj +++ b/projects/kiwano-imgui/kiwano-imgui.vcxproj @@ -38,7 +38,7 @@ StaticLibrary false - false + true Unicode $(DefaultPlatformToolset) @@ -110,4 +110,4 @@ - \ No newline at end of file + diff --git a/projects/kiwano-network/kiwano-network.vcxproj b/projects/kiwano-network/kiwano-network.vcxproj index 4192e881..6883d0be 100644 --- a/projects/kiwano-network/kiwano-network.vcxproj +++ b/projects/kiwano-network/kiwano-network.vcxproj @@ -34,7 +34,7 @@ StaticLibrary false - false + true Unicode $(DefaultPlatformToolset) @@ -106,4 +106,4 @@ - \ No newline at end of file + diff --git a/projects/kiwano-physics/kiwano-physics.vcxproj b/projects/kiwano-physics/kiwano-physics.vcxproj index cc69700c..33cce9e7 100644 --- a/projects/kiwano-physics/kiwano-physics.vcxproj +++ b/projects/kiwano-physics/kiwano-physics.vcxproj @@ -13,6 +13,7 @@ + @@ -24,6 +25,7 @@ + @@ -44,7 +46,7 @@ StaticLibrary false - false + true Unicode $(DefaultPlatformToolset) diff --git a/projects/kiwano-physics/kiwano-physics.vcxproj.filters b/projects/kiwano-physics/kiwano-physics.vcxproj.filters index a927a9b3..e4f5fe7f 100644 --- a/projects/kiwano-physics/kiwano-physics.vcxproj.filters +++ b/projects/kiwano-physics/kiwano-physics.vcxproj.filters @@ -10,6 +10,7 @@ + @@ -19,5 +20,6 @@ + \ No newline at end of file diff --git a/projects/kiwano/kiwano.vcxproj b/projects/kiwano/kiwano.vcxproj index ffe0546b..eab6029a 100644 --- a/projects/kiwano/kiwano.vcxproj +++ b/projects/kiwano/kiwano.vcxproj @@ -11,24 +11,16 @@ - + + + + + + - - - - - - - - - - - - - @@ -37,8 +29,7 @@ - - + @@ -48,7 +39,7 @@ - + @@ -66,15 +57,18 @@ - + + + - + + @@ -86,6 +80,7 @@ + @@ -111,17 +106,21 @@ - + - + + + + + @@ -130,13 +129,14 @@ - + + - + @@ -166,9 +166,6 @@ - - {3a3948dc-9865-46b3-b7b9-7e5572704ed2} - {ab47e875-85e5-4105-a71e-88930eaab910} @@ -187,7 +184,7 @@ StaticLibrary false - false + true Unicode $(DefaultPlatformToolset) diff --git a/projects/kiwano/kiwano.vcxproj.filters b/projects/kiwano/kiwano.vcxproj.filters index 87053e5a..dce7c87c 100644 --- a/projects/kiwano/kiwano.vcxproj.filters +++ b/projects/kiwano/kiwano.vcxproj.filters @@ -25,14 +25,14 @@ {9314f30d-5742-48b6-94e5-e3b4284106f6} - - {86e2d0f2-a9d0-4456-b6a5-d480228bbf82} - {30333461-e9bc-4709-84bd-ce6e0e1a3079} - - {192a47a9-9df6-4f40-a7d3-888eb00c53ac} + + {e84dcf9a-e650-473e-8c9c-193804ab9e76} + + + {c629aedd-ffb9-4bc1-82c3-f50e77c82e77} @@ -45,21 +45,12 @@ 2d - - 2d - 2d 2d - - 2d - - - 2d - 2d @@ -72,9 +63,6 @@ core - - core - core @@ -93,9 +81,6 @@ platform - - platform - @@ -150,33 +135,6 @@ 2d - - common - - - common - - - common - - - common - - - common - - - common - - - common - - - common - - - common - 2d @@ -240,9 +198,6 @@ renderer - - renderer - 2d @@ -267,27 +222,15 @@ math - - core\win32 - - - core\win32 - utils - - common - utils core - - core - platform @@ -303,6 +246,48 @@ platform + + 2d + + + core + + + core + + + renderer + + + renderer\win32 + + + renderer + + + platform\win32 + + + platform\win32 + + + platform\win32 + + + core\event + + + core\event + + + core\event + + + core\event + + + core\event + @@ -320,9 +305,6 @@ 2d - - 2d - 2d @@ -341,9 +323,6 @@ platform - - platform - core @@ -443,9 +422,6 @@ renderer - - renderer - 2d @@ -470,9 +446,6 @@ core - - core - platform @@ -485,5 +458,32 @@ platform + + 2d + + + core + + + renderer + + + platform\win32 + + + platform\win32 + + + core\event + + + core\event + + + core\event + + + core\event + \ No newline at end of file diff --git a/scripts/appveyor/clear_project_configuration.ps1 b/scripts/appveyor/clear_project_configuration.ps1 index 05b9fba9..185ad6bf 100644 --- a/scripts/appveyor/clear_project_configuration.ps1 +++ b/scripts/appveyor/clear_project_configuration.ps1 @@ -3,14 +3,19 @@ function Set-FileConfiguration { [string]$filePath ) - $replace = "(EditAndContinue|ProgramDatabase)" - $replaceTo = "None" + $debugInfoReplace = "(EditAndContinue|ProgramDatabase)" + $debugInfoReplaceTo = "None" + + $optimizationReplace = "true" + $optimizationReplaceTo = "false" # Create a copy of .vcxproj file Copy-Item -Path $filePath -Destination ($filePath + '.template') # Overlay some configurations - Get-Content ($filePath + '.template') -Encoding UTF8 | ForEach-Object { $_ -replace $replace, $replaceTo } | Out-File $filePath -Encoding UTF8 + Get-Content ($filePath + '.template') -Encoding UTF8 | ForEach-Object { + ( $_ -replace $debugInfoReplace, $debugInfoReplaceTo ) -replace $optimizationReplace, $optimizationReplaceTo + } | Out-File $filePath -Encoding UTF8 # Delete the copy file Remove-Item -Path ($filePath + '.template') @@ -24,3 +29,12 @@ Get-ChildItem -Path 'projects\' -Directory | ForEach-Object { Set-FileConfiguration ($dirPath + '\' + $_) } } + +Get-ChildItem -Path 'projects\3rd-party' -Directory | ForEach-Object { + $dirPath = "projects\3rd-party\$($_)" + + # Search all vcxproj files + Get-ChildItem -Path $dirPath *.vcxproj -File | ForEach-Object { + Set-FileConfiguration ($dirPath + '\' + $_) + } +} diff --git a/src/3rd-party/OuterC/LICENSE b/src/3rd-party/OuterC/LICENSE new file mode 100644 index 00000000..9e74ea5c --- /dev/null +++ b/src/3rd-party/OuterC/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2019 Nomango + +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. diff --git a/src/kiwano/common/any.hpp b/src/3rd-party/OuterC/oc/any.h similarity index 86% rename from src/kiwano/common/any.hpp rename to src/3rd-party/OuterC/oc/any.h index 0b3dfd6d..fa4594b5 100644 --- a/src/kiwano/common/any.hpp +++ b/src/3rd-party/OuterC/oc/any.h @@ -1,32 +1,11 @@ -// Copyright (c) 2018-2019 Kiwano - Nomango -// -// 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. +// Copyright (c) 2019-2020 OuterC - Nomango #pragma once #include #include #include -namespace kiwano -{ - -namespace common +namespace oc { class bad_any_cast : public std::exception @@ -133,7 +112,7 @@ public: template const _Ty* cast_pointer() const noexcept { - static_assert(!std::is_void<_Ty>::value, "kiwano::any cannot contain void"); + static_assert(!std::is_void<_Ty>::value, "oc::any cannot contain void"); const type_info* const info = typeinfo(); if (info && (*info == typeid(std::decay<_Ty>::type))) @@ -519,14 +498,14 @@ _Ty any_cast(any&& a) return static_cast<_Ty>(std::move(*ptr)); } -} // namespace common - -} // namespace kiwano +} // namespace oc namespace std { - inline void swap(kiwano::common::any& lhs, kiwano::common::any& rhs) noexcept - { - lhs.swap(rhs); - } + +inline void swap(oc::any& lhs, oc::any& rhs) noexcept +{ + lhs.swap(rhs); +} + } diff --git a/src/3rd-party/OuterC/oc/function.h b/src/3rd-party/OuterC/oc/function.h new file mode 100644 index 00000000..af9cce32 --- /dev/null +++ b/src/3rd-party/OuterC/oc/function.h @@ -0,0 +1,169 @@ +// Copyright (c) 2019-2020 OuterC - Nomango + +#pragma once +#include "function/details.h" +#include + +namespace oc +{ + +class bad_function_call : public ::std::exception +{ +public: + bad_function_call() {} + + virtual const char* what() const override + { + return "bad function call"; + } +}; + + +template +class function; + +template +class function<_Ret(_Args...)> +{ +public: + function() + : callable_(nullptr) + { + } + + function(std::nullptr_t) + : callable_(nullptr) + { + } + + function(const function& rhs) + : callable_(rhs.callable_) + { + if (callable_) callable_->retain(); + } + + function(function&& rhs) noexcept + : callable_(rhs.callable_) + { + rhs.callable_ = nullptr; + } + + function(_Ret(*func)(_Args...)) + { + callable_ = __function_detail::proxy_callable<_Ret(*)(_Args...), _Ret, _Args...>::make(::std::move(func)); + if (callable_) callable_->retain(); + } + + template< + typename _Ty, + typename = typename ::std::enable_if<__function_detail::is_callable<_Ty, _Ret, _Args...>::value, int>::type> + function(_Ty val) + { + callable_ = __function_detail::proxy_callable<_Ty, _Ret, _Args...>::make(::std::move(val)); + if (callable_) callable_->retain(); + } + + template::value || ::std::is_base_of<_Ty, _Uty>::value, int>::type> + function(_Uty* ptr, _Ret(_Ty::* func)(_Args...)) + { + callable_ = __function_detail::proxy_mem_callable<_Ty, _Ret, _Args...>::make(ptr, func); + if (callable_) callable_->retain(); + } + + template::value || ::std::is_base_of<_Ty, _Uty>::value, int>::type> + function(_Uty* ptr, _Ret(_Ty::* func)(_Args...) const) + { + callable_ = __function_detail::proxy_const_mem_callable<_Ty, _Ret, _Args...>::make(ptr, func); + if (callable_) callable_->retain(); + } + + ~function() + { + tidy(); + } + + inline void swap(const function& rhs) + { + std::swap(callable_, rhs.callable_); + } + + inline _Ret operator()(_Args... args) const + { + if (!callable_) + throw bad_function_call(); + return callable_->invoke(::std::forward<_Args>(args)...); + } + + inline operator bool() const + { + return !!callable_; + } + + inline function& operator=(const function& rhs) + { + tidy(); + callable_ = rhs.callable_; + if (callable_) callable_->retain(); + return (*this); + } + + inline function& operator=(function&& rhs) + { + tidy(); + callable_ = rhs.callable_; + rhs.callable_ = nullptr; + return (*this); + } + +private: + inline void tidy() + { + if (callable_) + { + callable_->release(); + callable_ = nullptr; + } + } + +private: + __function_detail::callable<_Ret, _Args...>* callable_; +}; + +template::value || std::is_base_of<_Ty, _Uty>::value, int + >::type, + typename _Ret, + typename... _Args +> +inline function<_Ret(_Args...)> closure(_Uty* ptr, _Ret(_Ty::* func)(_Args...)) +{ + return function<_Ret(_Args...)>(ptr, func); +} + +template::value || std::is_base_of<_Ty, _Uty>::value, int + >::type, + typename _Ret, + typename... _Args +> +inline function<_Ret(_Args...)> closure(_Uty* ptr, _Ret(_Ty::* func)(_Args...) const) +{ + return function<_Ret(_Args...)>(ptr, func); +} + + +template +inline void swap(oc::function<_Ret(_Args...)>& lhs, oc::function<_Ret(_Args...)>& rhs) noexcept +{ + lhs.swap(rhs); +} + +} // namespace oc diff --git a/src/3rd-party/OuterC/oc/function/details.h b/src/3rd-party/OuterC/oc/function/details.h new file mode 100644 index 00000000..9abefaa1 --- /dev/null +++ b/src/3rd-party/OuterC/oc/function/details.h @@ -0,0 +1,168 @@ +// Copyright (c) 2019-2020 OuterC - Nomango + +#pragma once +#include + +namespace oc +{ +namespace __function_detail +{ + +template +struct is_callable_helper +{ + template + struct class_mem; + + template + struct class_const_mem; + + template + static int test(...); + + template + static char test(class_mem<_Uty, &_Uty::operator()>*); + + template + static char test(class_const_mem<_Uty, &_Uty::operator()>*); + + template< + typename _Uty, + typename _Uret = typename std::decay().operator()(std::declval<_Args>()...))>::type, + typename = typename std::enable_if::value>::type + > + static char test(int); + + static constexpr bool value = sizeof(test<_Ty>(0)) == sizeof(char); +}; + +template +struct is_callable + : public ::std::bool_constant::value> +{ +}; + +// +// callable +// + +template +class callable +{ +public: + virtual ~callable() {} + + virtual void retain() = 0; + virtual void release() = 0; + virtual _Ret invoke(_Args... args) const = 0; +}; + +template +class ref_count_callable + : public callable<_Ret, _Args...> +{ +public: + ref_count_callable() : ref_count_(0) {} + + virtual void retain() override + { + ++ref_count_; + } + + virtual void release() override + { + --ref_count_; + if (ref_count_ <= 0) + { + delete this; + } + } + +private: + int ref_count_; +}; + +template +class proxy_callable + : public ref_count_callable<_Ret, _Args...> +{ +public: + proxy_callable(_Ty&& val) + : callee_(::std::move(val)) + { + } + + virtual _Ret invoke(_Args... args) const override + { + return callee_(::std::forward<_Args&&>(args)...); + } + + static inline callable<_Ret, _Args...>* make(_Ty&& val) + { + return new (::std::nothrow) proxy_callable<_Ty, _Ret, _Args...>(::std::move(val)); + } + +private: + _Ty callee_; +}; + +template +class proxy_mem_callable + : public ref_count_callable<_Ret, _Args...> +{ +public: + typedef _Ret(_Ty::* _FuncType)(_Args...); + + virtual _Ret invoke(_Args... args) const override + { + return (static_cast<_Ty*>(ptr_)->*func_)(::std::forward<_Args>(args)...); + } + + static inline callable<_Ret, _Args...>* make(void* ptr, _FuncType func) + { + return new (::std::nothrow) proxy_mem_callable<_Ty, _Ret, _Args...>(ptr, func); + } + +protected: + proxy_mem_callable(void* ptr, _FuncType func) + : ptr_(ptr) + , func_(func) + { + } + +protected: + void* ptr_; + _FuncType func_; +}; + +template +class proxy_const_mem_callable + : public ref_count_callable<_Ret, _Args...> +{ +public: + typedef _Ret(_Ty::* _FuncType)(_Args...) const; + + virtual _Ret invoke(_Args... args) const override + { + return (static_cast<_Ty*>(ptr_)->*func_)(::std::forward<_Args>(args)...); + } + + static inline callable<_Ret, _Args...>* make(void* ptr, _FuncType func) + { + return new (::std::nothrow) proxy_const_mem_callable<_Ty, _Ret, _Args...>(ptr, func); + } + +protected: + proxy_const_mem_callable(void* ptr, _FuncType func) + : ptr_(ptr) + , func_(func) + { + } + +protected: + void* ptr_; + _FuncType func_; +}; + +} // namespace __function_detail +} // namespace oc diff --git a/src/3rd-party/OuterC/oc/intrusive_list.h b/src/3rd-party/OuterC/oc/intrusive_list.h new file mode 100644 index 00000000..7138a22c --- /dev/null +++ b/src/3rd-party/OuterC/oc/intrusive_list.h @@ -0,0 +1,254 @@ +// Copyright (c) 2019-2020 OuterC - Nomango + +#pragma once +#include +#include +#include +#include "macros.h" + +namespace oc +{ + +template ::pointer> +class intrusive_list; + +template ::pointer> +class intrusive_list_item +{ +public: + using pointer_type = _PTy; + using const_pointer_type = const _PTy; + + intrusive_list_item() : prev_(nullptr), next_(nullptr) {} + intrusive_list_item(pointer_type rhs) : prev_(nullptr), next_(nullptr) { if (rhs) { prev_ = rhs->prev_; next_ = rhs->next_; } } + + const_pointer_type prev_item() const { return prev_; } + pointer_type prev_item() { return prev_; } + const_pointer_type next_item() const { return next_; } + pointer_type next_item() { return next_; } + +private: + pointer_type prev_; + pointer_type next_; + + friend class intrusive_list<_Ty, _PTy>; +}; + + +template +class intrusive_list +{ +public: + using pointer_type = _PTy; + using const_pointer_type = const _PTy; + + intrusive_list() : first_(), last_() {} + ~intrusive_list() { clear(); } + + const_pointer_type first_item() const { return first_; } + pointer_type first_item() { return first_; } + const_pointer_type last_item() const { return last_; } + pointer_type last_item() { return last_; } + + inline bool empty() const + { + return first_ == nullptr; + } + + void push_back(pointer_type child) + { + if (child->prev_) + child->prev_->next_ = child->next_; + if (child->next_) + child->next_->prev_ = child->prev_; + + child->prev_ = last_; + child->next_ = nullptr; + + if (first_) + { + last_->next_ = child; + } + else + { + first_ = child; + } + + last_ = child; + } + + void push_front(pointer_type child) + { + if (child->prev_) + child->prev_->next_ = child->next_; + if (child->next_) + child->next_->prev_ = child->prev_; + + child->prev_ = nullptr; + child->next_ = first_; + + if (first_) + { + first_->prev_ = child; + } + else + { + last_ = child; + } + + first_ = child; + } + + void insert_before(pointer_type child, pointer_type before) + { + if (child->prev_) + child->prev_->next_ = child->next_; + if (child->next_) + child->next_->prev_ = child->prev_; + + if (before->prev_) + before->prev_->next_ = child; + else + first_ = child; + + child->prev_ = before->prev_; + child->next_ = before; + before->prev_ = child; + } + + void insert_after(pointer_type child, pointer_type after) + { + if (child->prev_) + child->prev_->next_ = child->next_; + if (child->next_) + child->next_->prev_ = child->prev_; + + if (after->next_) + after->next_->prev_ = child; + else + last_ = child; + + child->next_ = after->next_; + child->prev_ = after; + after->next_ = child; + } + + void remove(pointer_type child) + { + if (child->next_) + { + child->next_->prev_ = child->prev_; + } + else + { + last_ = child->prev_; + } + + if (child->prev_) + { + child->prev_->next_ = child->next_; + } + else + { + first_ = child->next_; + } + + child->prev_ = nullptr; + child->next_ = nullptr; + } + + void clear() + { + pointer_type p = first_; + while (p) + { + pointer_type tmp = p; + p = p->next_; + if (tmp) + { + tmp->next_ = nullptr; + tmp->prev_ = nullptr; + } + } + first_ = nullptr; + last_ = nullptr; + } + + void check_list() + { + if (!first_) + return; + + int pos = 0; + pointer_type p = first_; + pointer_type tmp = p; + do + { + tmp = p; + p = p->next_; + ++pos; + + if (p) + { + OC_ASSERT(p->prev_ == tmp && "Check list failed"); + } + else + { + OC_ASSERT(tmp == last_ && "Check list failed"); + } + } while (p); + } + +public: + // Iterator + template + struct iterator_impl + { + using iterator_category = std::bidirectional_iterator_tag; + using pointer_type = _PTy; + using const_pointer_type = const _PTy; + + inline iterator_impl(pointer_type ptr = nullptr, bool is_end = false) : base_(ptr), is_end_(is_end) {} + + inline pointer_type operator*() const { OC_ASSERT(base_ && !is_end_); return base_; } + inline iterator_impl& operator++() { OC_ASSERT(base_ && !is_end_); pointer_type next = base_->next_item(); if (next) base_ = next; else is_end_ = true; return (*this); } + inline iterator_impl operator++(int) { iterator_impl old = (*this); ++(*this); return old; } + inline iterator_impl& operator--() { OC_ASSERT(base_); if (is_end_) is_end_ = false; else base_ = pointer_type(base_->prev_item()); return (*this); } + inline iterator_impl operator--(int) { iterator_impl old = (*this); --(*this); return old; } + inline bool operator==(iterator_impl const& other) const { return base_ == other.base_ && is_end_ == other.is_end_; } + inline bool operator!=(iterator_impl const& other) const { return !(*this == other); } + inline operator bool() const { return base_ != nullptr && !is_end_; } + + private: + bool is_end_; + pointer_type base_; + }; + + using iterator = iterator_impl; + using const_iterator = iterator_impl; + using reverse_iterator = std::reverse_iterator; + using const_reverse_iterator = std::reverse_iterator; + + inline iterator begin() { return iterator(first_item(), first_item() == nullptr); } + inline const_iterator begin() const { return const_iterator(first_item(), first_item() == nullptr); } + inline const_iterator cbegin() const { return begin(); } + inline iterator end() { return iterator(last_item(), true); } + inline const_iterator end() const { return const_iterator(last_item(), true); } + inline const_iterator cend() const { return end(); } + inline reverse_iterator rbegin() { return reverse_iterator(end()); } + inline const_reverse_iterator rbegin() const { return const_reverse_iterator(end()); } + inline const_reverse_iterator crbegin() const { return rbegin(); } + inline reverse_iterator rend() { return reverse_iterator(begin()); } + inline const_reverse_iterator rend() const { return const_reverse_iterator(begin()); } + inline const_reverse_iterator crend() const { return rend(); } + inline pointer_type front() { if (empty()) throw std::out_of_range("front() called on empty intrusive_list"); return first_item(); } + inline const_pointer_type front() const { if (empty()) throw std::out_of_range("front() called on empty intrusive_list"); return first_item(); } + inline pointer_type back() { if (empty()) throw std::out_of_range("back() called on empty intrusive_list"); return last_item(); } + inline const_pointer_type back() const { if (empty()) throw std::out_of_range("back() called on empty intrusive_list"); return last_item(); } + +private: + pointer_type first_; + pointer_type last_; +}; + +} // namespace oc diff --git a/src/3rd-party/OuterC/oc/intrusive_ptr.h b/src/3rd-party/OuterC/oc/intrusive_ptr.h new file mode 100644 index 00000000..e13aef0c --- /dev/null +++ b/src/3rd-party/OuterC/oc/intrusive_ptr.h @@ -0,0 +1,201 @@ +// Copyright (c) 2019-2020 OuterC - Nomango +// +// Permission is hereby granted, free of charge, to any person obtaining lhs 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. + +#pragma once +#include +#include +#include +#include "macros.h" + +namespace oc +{ + +template +class intrusive_ptr +{ +public: + using value_type = _Ty; + using pointer_type = _Ty*; + using const_pointer_type = const _Ty*; + using reference_type = _Ty&; + using const_reference_type = const _Ty&; + using ref_proxy_type = _ProxyTy; + + intrusive_ptr() noexcept : ptr_(nullptr) {} + intrusive_ptr(std::nullptr_t) noexcept : ptr_(nullptr) {} + intrusive_ptr(pointer_type p) : ptr_(p) { typename ref_proxy_type::add_ref(ptr_); } + intrusive_ptr(const intrusive_ptr& other) : ptr_(other.ptr_) { typename ref_proxy_type::add_ref(ptr_); } + intrusive_ptr(intrusive_ptr&& other) noexcept : ptr_(nullptr) { swap(other); } + ~intrusive_ptr() { tidy(); } + + template + intrusive_ptr(const intrusive_ptr<_UTy, ref_proxy_type>& other) { ptr_ = const_cast(dynamic_cast(other.get())); typename ref_proxy_type::add_ref(ptr_); } + + inline pointer_type get() noexcept { return ptr_; } + inline const_pointer_type get() const noexcept { return ptr_; } + inline void reset(pointer_type ptr = nullptr) { if (ptr) intrusive_ptr(ptr).swap(*this); else tidy(); } + inline void swap(intrusive_ptr& other) noexcept { std::swap(ptr_, other.ptr_); } + + inline pointer_type operator ->() { OC_ASSERT(ptr_ != nullptr && "Invalid pointer"); return ptr_; } + inline const_pointer_type operator ->() const { OC_ASSERT(ptr_ != nullptr && "Invalid pointer"); return ptr_; } + inline reference_type operator *() { OC_ASSERT(ptr_ != nullptr && "Invalid pointer"); return *ptr_; } + inline const_reference_type operator *() const { OC_ASSERT(ptr_ != nullptr && "Invalid pointer"); return *ptr_; } + inline pointer_type* operator &() { OC_ASSERT(ptr_ == nullptr && "Memory leak"); return &ptr_; } + inline operator bool() const noexcept { return ptr_ != nullptr; } + inline bool operator !() const noexcept { return ptr_ == 0; } + + inline intrusive_ptr& operator=(const intrusive_ptr& other) { if (other.ptr_ != ptr_) intrusive_ptr(other).swap(*this); return (*this); } + inline intrusive_ptr& operator=(intrusive_ptr&& other) noexcept { if (other.ptr_ != ptr_) other.swap(*this); return (*this); } + inline intrusive_ptr& operator=(pointer_type p) { if (p != ptr_) intrusive_ptr(p).swap(*this); return (*this); } + inline intrusive_ptr& operator=(std::nullptr_t) { tidy(); return *this; } + +private: + void tidy() + { + typename ref_proxy_type::release(ptr_); + ptr_ = nullptr; + } + +private: + pointer_type ptr_; +}; + +template +inline bool operator==(intrusive_ptr<_Ty, _ProxyTy> const& lhs, intrusive_ptr<_UTy, _ProxyTy> const& rhs) noexcept +{ + return lhs.get() == rhs.get(); +} + +template +inline bool operator==(intrusive_ptr<_Ty, _ProxyTy> const& lhs, _Ty* rhs) noexcept +{ + return lhs.get() == rhs; +} + +template +inline bool operator==(_Ty* lhs, intrusive_ptr<_Ty, _ProxyTy> const& rhs) noexcept +{ + return lhs == rhs.get(); +} + +template +inline bool operator==(intrusive_ptr<_Ty, _ProxyTy> const& lhs, std::nullptr_t) noexcept +{ + return !static_cast(lhs); +} + +template +inline bool operator==(std::nullptr_t, intrusive_ptr<_Ty, _ProxyTy> const& rhs) noexcept +{ + return !static_cast(rhs); +} + +template +inline bool operator!=(intrusive_ptr<_Ty, _ProxyTy> const& lhs, intrusive_ptr<_UTy, _ProxyTy> const& rhs) noexcept +{ + return !(lhs == rhs); +} + +template +inline bool operator!=(intrusive_ptr<_Ty, _ProxyTy> const& lhs, _Ty* rhs) noexcept +{ + return lhs.get() != rhs; +} + +template +inline bool operator!=(_Ty* lhs, intrusive_ptr<_Ty, _ProxyTy> const& rhs) noexcept +{ + return lhs != rhs.get(); +} + +template +inline bool operator!=(intrusive_ptr<_Ty, _ProxyTy> const& lhs, std::nullptr_t) noexcept +{ + return static_cast(lhs); +} + +template +inline bool operator!=(std::nullptr_t, intrusive_ptr<_Ty, _ProxyTy> const& rhs) noexcept +{ + return static_cast(rhs); +} + +template +inline bool operator<(intrusive_ptr<_Ty, _ProxyTy> const& lhs, intrusive_ptr<_UTy, _ProxyTy> const& rhs) noexcept +{ + return lhs.get() < rhs.get(); +} + +// template class cannot specialize std::swap, +// so implement a swap Function in oc namespace +template +inline void swap(intrusive_ptr<_Ty, _ProxyTy>& lhs, intrusive_ptr<_Ty, _ProxyTy>& rhs) noexcept +{ + lhs.swap(rhs); +} + + +class intrusive_ref +{ +public: + void add_ref() + { + ++ref_count_; + } + + void release() + { + --ref_count_; + if (ref_count_ == 0) + { + delete this; + } + } + + int16_t get_ref() const + { + return ref_count_; + } + +protected: + intrusive_ref() + : ref_count_(0) + { + } + +private: + std::atomic ref_count_; +}; + + +class intrusive_ref_proxy +{ +public: + static inline void add_ref(intrusive_ref* ptr) { if (ptr) ptr->add_ref(); } + + static inline void release(intrusive_ref* ptr) { if (ptr) ptr->release(); } +}; + +template< + typename _Ty, + typename = typename std::enable_if::value, int>::type> +using intrusive_ref_ptr = intrusive_ptr<_Ty, intrusive_ref_proxy>; + +} // namespace oc diff --git a/src/3rd-party/OuterC/oc/json.h b/src/3rd-party/OuterC/oc/json.h new file mode 100644 index 00000000..e61c0d95 --- /dev/null +++ b/src/3rd-party/OuterC/oc/json.h @@ -0,0 +1,50 @@ +// Copyright (c) 2019-2020 OuterC - Nomango + +#pragma once +#include +#include "vector.h" +#include "string.h" +#include "json/basic_json.h" + +namespace oc +{ + +using json = oc::basic_json; +using wjson = oc::basic_json; + +} // namespace oc + +namespace std +{ + +template<> +struct hash<::oc::json> +{ + size_t operator()(const ::oc::json& json) const + { + return hash<::oc::json::string_type>{}(json.dump()); + } +}; + +template<> +struct hash<::oc::wjson> +{ + size_t operator()(const ::oc::wjson& json) const + { + return hash<::oc::wjson::string_type>{}(json.dump()); + } +}; + +template<> +inline void swap<::oc::json>(::oc::json& lhs, ::oc::json& rhs) noexcept +{ + lhs.swap(rhs); +} + +template<> +inline void swap<::oc::wjson>(::oc::wjson& lhs, ::oc::wjson& rhs) noexcept +{ + lhs.swap(rhs); +} + +} diff --git a/src/3rd-party/OuterC/oc/json/basic_json.h b/src/3rd-party/OuterC/oc/json/basic_json.h new file mode 100644 index 00000000..f5a3c5cb --- /dev/null +++ b/src/3rd-party/OuterC/oc/json/basic_json.h @@ -0,0 +1,929 @@ +// Copyright (c) 2019-2020 OuterC - Nomango + +#pragma once +#include "json_exception.h" +#include "json_value.h" +#include "json_iterator.h" +#include "json_serializer.h" +#include "json_parser.h" +#include "json_value_getter.h" + +namespace oc +{ + +#define OC_DECLARE_BASIC_JSON_TEMPLATE\ + template <\ + template typename _ObjectTy, \ + template typename _ArrayTy, \ + typename _StringTy, \ + typename _IntegerTy, \ + typename _FloatTy, \ + typename _BooleanTy, \ + template typename _Allocator> + +#define OC_DECLARE_BASIC_JSON_TPL_ARGS \ + _ObjectTy, _ArrayTy, _StringTy, _IntegerTy, _FloatTy, _BooleanTy, _Allocator + + +OC_DECLARE_BASIC_JSON_TEMPLATE +class basic_json; + + +// +// is_basic_json +// + +template +struct is_basic_json + : std::false_type +{ +}; + +OC_DECLARE_BASIC_JSON_TEMPLATE +struct is_basic_json< basic_json > + : std::true_type +{ +}; + + +OC_DECLARE_BASIC_JSON_TEMPLATE +class basic_json +{ + friend struct __json_detail::iterator_impl; + friend struct __json_detail::iterator_impl; + friend struct __json_detail::json_serializer; + friend struct __json_detail::json_parser; + friend struct __json_detail::json_value_getter; + +public: + template + using allocator_type = _Allocator<_Ty>; + using size_type = size_t; + using difference_type = ptrdiff_t; + using string_type = _StringTy; + using char_type = typename _StringTy::value_type; + using integer_type = _IntegerTy; + using float_type = _FloatTy; + using boolean_type = _BooleanTy; + using array_type = typename _ArrayTy>; + using object_type = typename _ObjectTy, allocator_type>>; + using initializer_list = std::initializer_list; + + using iterator = __json_detail::iterator_impl; + using const_iterator = __json_detail::iterator_impl; + using reverse_iterator = std::reverse_iterator; + using const_reverse_iterator = std::reverse_iterator; + +public: + basic_json() {} + + basic_json(std::nullptr_t) {} + + basic_json(const json_type type) : value_(type) {} + + basic_json(basic_json const& other) : value_(other.value_) {} + + basic_json(basic_json&& other) noexcept : value_(std::move(other.value_)) + { + // invalidate payload + other.value_.type = json_type::NIL; + other.value_.data.object = nullptr; + } + + basic_json(string_type const& value) : value_(value) {} + + template < + typename _CompatibleTy, + typename std::enable_if::value, int>::type = 0> + basic_json(const _CompatibleTy& value) + { + value_.type = json_type::STRING; + value_.data.string = value_.template create(value); + } + + basic_json(array_type const& arr) + : value_(arr) + { + } + + basic_json(object_type const& object) + : value_(object) + { + } + + basic_json(integer_type value) + : value_(value) + { + } + + template < + typename _IntegerTy, + typename std::enable_if::value, int>::type = 0> + basic_json(_IntegerTy value) + : value_(static_cast(value)) + { + } + + basic_json(float_type value) + : value_(value) + { + } + + template < + typename _FloatingTy, + typename std::enable_if::value, int>::type = 0> + basic_json(_FloatingTy value) + : value_(static_cast(value)) + { + } + + basic_json(boolean_type value) + : value_(value) + { + } + + basic_json(initializer_list const& init_list) + { + bool is_an_object = std::all_of(init_list.begin(), init_list.end(), [](const basic_json& json) + { + return (json.is_array() && json.size() == 2 && json[0].is_string()); + }); + + if (is_an_object) + { + value_ = json_type::OBJECT; + + std::for_each(init_list.begin(), init_list.end(), [this](const basic_json& json) + { + value_.data.object->emplace( + *((*json.value_.data.vector)[0].value_.data.string), + (*json.value_.data.vector)[1] + ); + }); + } + else + { + value_ = json_type::VECTOR; + value_.data.vector->reserve(init_list.size()); + value_.data.vector->assign(init_list.begin(), init_list.end()); + } + } + + static inline basic_json object(initializer_list const& init_list) + { + if (init_list.size() != 2 || !(*init_list.begin()).is_string()) + { + throw json_type_error("cannot create object from initializer_list"); + } + + basic_json json; + json.value_ = json_type::OBJECT; + json.value_.data.object->emplace(*((*init_list.begin()).value_.data.string), *(init_list.begin() + 1)); + return json; + } + + static inline basic_json array(initializer_list const& init_list) + { + basic_json json; + json.value_ = json_type::VECTOR; + + if (init_list.size()) + { + json.value_.data.vector->reserve(init_list.size()); + json.value_.data.vector->assign(init_list.begin(), init_list.end()); + } + return json; + } + + inline bool is_object() const { return value_.type == json_type::OBJECT; } + + inline bool is_array() const { return value_.type == json_type::VECTOR; } + + inline bool is_string() const { return value_.type == json_type::STRING; } + + inline bool is_boolean() const { return value_.type == json_type::BOOL; } + + inline bool is_integer() const { return value_.type == json_type::INTEGER; } + + inline bool is_float() const { return value_.type == json_type::FLOAT; } + + inline bool is_number() const { return is_integer() || is_float(); } + + inline bool is_null() const { return value_.type == json_type::NIL; } + + inline json_type type() const { return value_.type; } + + inline string_type type_name() const + { + switch (type()) + { + case json_type::OBJECT: + return string_type(L"object"); + case json_type::VECTOR: + return string_type(L"array"); + case json_type::STRING: + return string_type(L"string"); + case json_type::INTEGER: + return string_type(L"integer"); + case json_type::FLOAT: + return string_type(L"float"); + case json_type::BOOL: + return string_type(L"boolean"); + case json_type::NIL: + return string_type(L"null"); + } + return string_type(); + } + + inline void swap(basic_json& rhs) { value_.swap(rhs.value_); } + +public: + + inline iterator begin() { iterator iter(this); iter.set_begin(); return iter; } + inline const_iterator begin() const { return cbegin(); } + inline const_iterator cbegin() const { const_iterator iter(this); iter.set_begin(); return iter; } + inline iterator end() { iterator iter(this); iter.set_end(); return iter; } + inline const_iterator end() const { return cend(); } + inline const_iterator cend() const { const_iterator iter(this); iter.set_end(); return iter; } + inline reverse_iterator rbegin() { return reverse_iterator(end()); } + inline const_reverse_iterator rbegin() const { return const_reverse_iterator(end()); } + inline const_reverse_iterator crbegin() const { return rbegin(); } + inline reverse_iterator rend() { return reverse_iterator(begin()); } + inline const_reverse_iterator rend() const { return const_reverse_iterator(begin()); } + inline const_reverse_iterator crend() const { return rend(); } + +public: + inline size_type size() const + { + switch (type()) + { + case json_type::NIL: + return 0; + case json_type::VECTOR: + return value_.data.vector->size(); + case json_type::OBJECT: + return value_.data.object->size(); + default: + return 1; + } + } + + inline bool empty() const + { + if (is_null()) + return true; + + if (is_object()) + return value_.data.object->empty(); + + if (is_array()) + return value_.data.vector->empty(); + + return false; + } + + template + inline const_iterator find(_Kty && key) const + { + if (is_object()) + { + const_iterator iter; + iter.object_iter = value_.data.object->find(std::forward<_Kty>(key)); + return iter; + } + return cend(); + } + + template + inline size_type count(_Kty && key) const + { + return is_object() ? value_.data.object->count(std::forward<_Kty>(key)) : 0; + } + + inline size_type erase(const typename object_type::key_type& key) + { + if (!is_object()) + { + throw json_invalid_key("cannot use erase() with non-object value"); + } + return value_.data.object->erase(key); + } + + inline void erase(const size_type index) + { + if (!is_array()) + { + throw json_invalid_key("cannot use erase() with non-array value"); + } + value_.data.vector->erase(value_.data.vector->begin() + static_cast(index)); + } + + template< + class _IteratorTy, + typename std::enable_if< + std::is_same<_IteratorTy, iterator>::value || + std::is_same<_IteratorTy, const_iterator>::value, int + >::type = 0> + inline _IteratorTy erase(_IteratorTy pos) + { + _IteratorTy result = end(); + + switch (type()) + { + case json_type::OBJECT: + { + result.object_iter = value_.data.object->erase(pos.object_iter); + break; + } + + case json_type::VECTOR: + { + result.array_iter = value_.data.vector->erase(pos.array_iter); + break; + } + + default: + throw json_invalid_iterator("cannot use erase() with non-object & non-array value"); + } + + return result; + } + + template< + class _IteratorTy, + typename std::enable_if< + std::is_same<_IteratorTy, iterator>::value || + std::is_same<_IteratorTy, const_iterator>::value, int + >::type = 0> + inline _IteratorTy erase(_IteratorTy first, _IteratorTy last) + { + _IteratorTy result = end(); + + switch (type()) + { + case json_type::OBJECT: + { + result.object_iter = value_.data.object->erase(first.object_iter, last.object_iter); + break; + } + + case json_type::VECTOR: + { + result.array_iter = value_.data.vector->erase(first.array_iter, last.array_iter); + break; + } + + default: + throw json_invalid_iterator("cannot use erase() with non-object & non-array value"); + } + + return result; + } + + inline void push_back(basic_json&& json) + { + if (!is_null() && !is_array()) + { + throw json_type_error("cannot use push_back() with non-array value"); + } + + if (is_null()) + { + value_ = json_type::VECTOR; + } + + value_.data.vector->push_back(std::move(json)); + } + + inline basic_json& operator+=(basic_json&& json) + { + push_back(std::move(json)); + return (*this); + } + + inline void clear() + { + switch (type()) + { + case json_type::INTEGER: + { + value_.data.number_integer = 0; + break; + } + + case json_type::FLOAT: + { + value_.data.number_float = static_cast(0.0); + break; + } + + case json_type::BOOL: + { + value_.data.boolean = false; + break; + } + + case json_type::STRING: + { + value_.data.string->clear(); + break; + } + + case json_type::VECTOR: + { + value_.data.vector->clear(); + break; + } + + case json_type::OBJECT: + { + value_.data.object->clear(); + break; + } + + default: + break; + } + } + +public: + // GET value functions + + inline bool get_value(boolean_type& val) const + { + if (is_boolean()) + { + val = value_.data.boolean; + return true; + } + return false; + } + + inline bool get_value(integer_type& val) const + { + if (is_integer()) + { + val = value_.data.number_integer; + return true; + } + return false; + } + + inline bool get_value(float_type& val) const + { + if (is_float()) + { + val = value_.data.number_float; + return true; + } + return false; + } + + template < + typename _IntegerTy, + typename std::enable_if::value, int>::type = 0> + inline bool get_value(_IntegerTy& val) const + { + if (is_integer()) + { + val = static_cast<_IntegerTy>(value_.data.number_integer); + return true; + } + return false; + } + + template < + typename _FloatingTy, + typename std::enable_if::value, int>::type = 0> + inline bool get_value(_FloatingTy& val) const + { + if (is_float()) + { + val = static_cast<_FloatingTy>(value_.data.number_float); + return true; + } + return false; + } + + inline bool get_value(array_type& val) const + { + if (is_array()) + { + val.assign((*value_.data.vector).begin(), (*value_.data.vector).end()); + return true; + } + return false; + } + + inline bool get_value(string_type& val) const + { + if (is_string()) + { + val.assign(*value_.data.string); + return true; + } + return false; + } + + inline bool get_value(object_type& val) const + { + if (is_object()) + { + val.assign(*value_.data.object); + return true; + } + return false; + } + + boolean_type as_bool() const + { + if (!is_boolean()) throw json_type_error("json value must be boolean"); + return value_.data.boolean; + } + + integer_type as_int() const + { + if (!is_integer()) throw json_type_error("json value must be integer"); + return value_.data.number_integer; + } + + float_type as_float() const + { + if (!is_float()) throw json_type_error("json value must be float"); + return value_.data.number_float; + } + + const array_type& as_array() const + { + if (!is_array()) throw json_type_error("json value must be array"); + return *value_.data.vector; + } + + const string_type& as_string() const + { + if (!is_string()) throw json_type_error("json value must be string"); + return *value_.data.string; + } + + const object_type& as_object() const + { + if (!is_object()) throw json_type_error("json value must be object"); + return *value_.data.object; + } + + template + _Ty get() const + { + _Ty value; + __json_detail::json_value_getter::assign(*this, value); + return value; + } + +public: + // operator= functions + + inline basic_json& operator=(basic_json const& other) + { + value_ = other.value_; + return (*this); + } + + inline basic_json& operator=(basic_json&& other) noexcept + { + value_ = std::move(other.value_); + return (*this); + } + + inline basic_json& operator=(std::nullptr_t) + { + value_ = nullptr; + return (*this); + } + +public: + // operator[] functions + + inline basic_json& operator[](size_type index) + { + if (is_null()) + { + value_ = json_type::VECTOR; + } + + if (!is_array()) + { + throw json_invalid_key("operator[] called on a non-array object"); + } + + if (index >= value_.data.vector->size()) + { + value_.data.vector->insert(value_.data.vector->end(), + index - value_.data.vector->size() + 1, + basic_json() + ); + } + return (*value_.data.vector)[index]; + } + + inline basic_json& operator[](size_type index) const + { + if (!is_array()) + { + throw json_invalid_key("operator[] called on a non-array type"); + } + + if (index >= value_.data.vector->size()) + { + throw std::out_of_range("operator[] index out of range"); + } + return (*value_.data.vector)[index]; + } + + inline basic_json& operator[](const typename object_type::key_type& key) + { + if (is_null()) + { + value_ = json_type::OBJECT; + } + + if (!is_object()) + { + throw json_invalid_key("operator[] called on a non-object type"); + } + return (*value_.data.object)[key]; + } + + inline basic_json& operator[](const typename object_type::key_type& key) const + { + if (!is_object()) + { + throw json_invalid_key("operator[] called on a non-object object"); + } + + auto iter = value_.data.object->find(key); + if (iter == value_.data.object->end()) + { + throw std::out_of_range("operator[] key out of range"); + } + return iter->second; + } + + template + inline basic_json& operator[](_CharT* key) + { + if (is_null()) + { + value_ = json_type::OBJECT; + } + + if (!is_object()) + { + throw json_invalid_key("operator[] called on a non-object object"); + } + return (*value_.data.object)[key]; + } + + template + inline basic_json& operator[](_CharT* key) const + { + if (!is_object()) + { + throw json_invalid_key("operator[] called on a non-object object"); + } + + auto iter = value_.data.object->find(key); + if (iter == value_.data.object->end()) + { + throw std::out_of_range("operator[] key out of range"); + } + return iter->second; + } + +public: + // implicitly convert functions + + inline operator boolean_type () const + { + return as_bool(); + } + + inline operator integer_type () const + { + return as_int(); + } + + inline operator float_type () const + { + return as_float(); + } + + inline operator const array_type& () const + { + return as_array(); + } + + inline operator const string_type& () const + { + return as_string(); + } + + inline operator const object_type& () const + { + return as_object(); + } + +public: + // dumps functions + + string_type dump( + const int indent = -1, + const char_type indent_char = ' ', + const bool char_escape = true) const + { + string_type result; + __json_detail::string_output_adapter adapter(result); + dump(&adapter, indent, indent_char, char_escape); + return result; + } + + void dump( + __json_detail::output_adapter* adapter, + const int indent = -1, + const char_type indent_char = ' ', + const bool char_escape = true) const + { + __json_detail::json_serializer(adapter, indent_char).dump(*this, (indent >= 0), char_escape, static_cast(indent)); + } + + friend std::basic_ostream& operator<<(std::basic_ostream& out, const basic_json& json) + { + using char_type = typename std::basic_ostream::char_type; + + const bool pretty_print = (out.width() > 0); + const auto indentation = (pretty_print ? out.width() : 0); + out.width(0); + + __json_detail::stream_output_adapter adapter(out); + __json_detail::json_serializer(&adapter, out.fill()).dump(json, pretty_print, true, static_cast(indentation)); + return out; + } + +public: + // parse functions + + static inline basic_json parse(const string_type& str) + { + __json_detail::string_input_adapter adapter(str); + return parse(&adapter); + } + + static inline basic_json parse(const char_type* str) + { + __json_detail::buffer_input_adapter adapter(str); + return parse(&adapter); + } + + static inline basic_json parse(std::FILE* file) + { + __json_detail::file_input_adapter adapter(file); + return parse(&adapter); + } + + static inline basic_json parse(__json_detail::input_adapter* adapter) + { + basic_json result; + __json_detail::json_parser(adapter).parse(result); + return result; + } + + friend std::basic_istream& + operator>>(std::basic_istream& in, basic_json& json) + { + __json_detail::stream_input_adapter adapter(in); + __json_detail::json_parser(&adapter).parse(json); + return in; + } + +public: + // compare functions + + friend bool operator==(const basic_json& lhs, const basic_json& rhs) + { + const auto lhs_type = lhs.type(); + const auto rhs_type = rhs.type(); + + if (lhs_type == rhs_type) + { + switch (lhs_type) + { + case json_type::VECTOR: + return (*lhs.value_.data.vector == *rhs.value_.data.vector); + + case json_type::OBJECT: + return (*lhs.value_.data.object == *rhs.value_.data.object); + + case json_type::NIL: + return true; + + case json_type::STRING: + return (*lhs.value_.data.string == *rhs.value_.data.string); + + case json_type::BOOL: + return (lhs.value_.data.boolean == rhs.value_.data.boolean); + + case json_type::INTEGER: + return (lhs.value_.data.number_integer == rhs.value_.data.number_integer); + + case json_type::FLOAT: + return (lhs.value_.data.number_float == rhs.value_.data.number_float); + + default: + return false; + } + } + else if (lhs_type == json_type::INTEGER && rhs_type == json_type::FLOAT) + { + return (static_cast(lhs.value_.data.number_integer) == rhs.value_.data.number_float); + } + else if (lhs_type == json_type::FLOAT && rhs_type == json_type::INTEGER) + { + return (lhs.value_.data.number_float == static_cast(rhs.value_.data.number_integer)); + } + + return false; + } + + friend bool operator!=(const basic_json& lhs, const basic_json& rhs) + { + return !(lhs == rhs); + } + + friend bool operator<(const basic_json& lhs, const basic_json& rhs) + { + const auto lhs_type = lhs.type(); + const auto rhs_type = rhs.type(); + + if (lhs_type == rhs_type) + { + switch (lhs_type) + { + case json_type::VECTOR: + return (*lhs.value_.data.vector) < (*rhs.value_.data.vector); + + case json_type::OBJECT: + return (*lhs.value_.data.object) < (*rhs.value_.data.object); + + case json_type::NIL: + return false; + + case json_type::STRING: + return (*lhs.value_.data.string) < (*rhs.value_.data.string); + + case json_type::BOOL: + return (lhs.value_.data.boolean < rhs.value_.data.boolean); + + case json_type::INTEGER: + return (lhs.value_.data.number_integer < rhs.value_.data.number_integer); + + case json_type::FLOAT: + return (lhs.value_.data.number_float < rhs.value_.data.number_float); + + default: + return false; + } + } + else if (lhs_type == json_type::INTEGER && rhs_type == json_type::FLOAT) + { + return (static_cast(lhs.value_.data.number_integer) < rhs.value_.data.number_float); + } + else if (lhs_type == json_type::FLOAT && rhs_type == json_type::INTEGER) + { + return (lhs.value_.data.number_float < static_cast(rhs.value_.data.number_integer)); + } + + return false; + } + + friend bool operator<=(const basic_json& lhs, const basic_json& rhs) + { + return !(rhs < lhs); + } + + friend bool operator>(const basic_json& lhs, const basic_json& rhs) + { + return rhs < lhs; + } + + friend bool operator>=(const basic_json& lhs, const basic_json& rhs) + { + return !(lhs < rhs); + } + +private: + __json_detail::json_value value_; +}; + +} // namespace oc + +#undef OC_DECLARE_BASIC_JSON_TEMPLATE +#undef OC_DECLARE_BASIC_JSON_TPL_ARGS diff --git a/src/3rd-party/OuterC/oc/json/json_exception.h b/src/3rd-party/OuterC/oc/json/json_exception.h new file mode 100644 index 00000000..0bf579e9 --- /dev/null +++ b/src/3rd-party/OuterC/oc/json/json_exception.h @@ -0,0 +1,47 @@ +// Copyright (c) 2019-2020 OuterC - Nomango + +#pragma once +#include +#include "json_value.h" + +namespace oc +{ + +class json_exception + : public std::runtime_error +{ +public: + json_exception(const char* message) + : std::runtime_error(message) + {} +}; + +class json_type_error + : public json_exception +{ +public: + json_type_error(const char* message) : json_exception(message) {} +}; + +class json_invalid_key + : public json_exception +{ +public: + json_invalid_key(const char* message) : json_exception(message) {} +}; + +class json_invalid_iterator + : public json_exception +{ +public: + json_invalid_iterator(const char* message) : json_exception(message) {} +}; + +class json_parse_error + : public json_exception +{ +public: + json_parse_error(const char* message) : json_exception(message) {} +}; + +} // namespace oc diff --git a/src/3rd-party/OuterC/oc/json/json_intput_adapter.h b/src/3rd-party/OuterC/oc/json/json_intput_adapter.h new file mode 100644 index 00000000..5fdba4af --- /dev/null +++ b/src/3rd-party/OuterC/oc/json/json_intput_adapter.h @@ -0,0 +1,112 @@ +// Copyright (c) 2019-2020 OuterC - Nomango + +#pragma once +#include + +namespace oc +{ +namespace __json_detail +{ + +template +struct input_adapter +{ + using char_type = _CharTy; + using char_traits = std::char_traits; + + virtual typename char_traits::int_type get_char() = 0; + virtual ~input_adapter() = default; +}; + +template +struct file_input_adapter + : public input_adapter<_CharTy> +{ + using char_type = typename input_adapter<_CharTy>::char_type; + using char_traits = typename input_adapter<_CharTy>::char_traits; + + file_input_adapter(std::FILE* file) : file(file) {} + + virtual typename char_traits::int_type get_char() override + { + return std::fgetc(file); + } + +private: + std::FILE* file; +}; + +template +struct stream_input_adapter + : public input_adapter<_CharTy> +{ + using char_type = typename input_adapter<_CharTy>::char_type; + using char_traits = typename input_adapter<_CharTy>::char_traits; + + stream_input_adapter(std::basic_istream& stream) : stream(stream), streambuf(*stream.rdbuf()) {} + + virtual typename char_traits::int_type get_char() override + { + auto ch = streambuf.sbumpc(); + if (ch == EOF) + { + stream.clear(stream.rdstate() | std::ios::eofbit); + } + return ch; + } + + virtual ~stream_input_adapter() + { + stream.clear(stream.rdstate() & std::ios::eofbit); + } + +private: + std::basic_istream& stream; + std::basic_streambuf& streambuf; +}; + +template +struct string_input_adapter + : public input_adapter +{ + using char_type = typename input_adapter::char_type; + using char_traits = typename input_adapter::char_traits; + + string_input_adapter(const _StringTy& str) : str(str), index(0) {} + + virtual typename char_traits::int_type get_char() override + { + if (index == str.size()) + return char_traits::eof(); + return str[index++]; + } + +private: + const _StringTy& str; + typename _StringTy::size_type index; +}; + +template +struct buffer_input_adapter + : public input_adapter<_CharTy> +{ + using char_type = typename input_adapter<_CharTy>::char_type; + using char_traits = typename input_adapter<_CharTy>::char_traits; + + buffer_input_adapter(const _CharTy* str) : str(str), index(0) {} + + virtual typename char_traits::int_type get_char() override + { + if (str[index] == '\0') + return char_traits::eof(); + return str[index++]; + } + +private: + const char_type* str; + uint32_t index; +}; + +} // namespace __json_detail + +} // namespace oc diff --git a/src/3rd-party/OuterC/oc/json/json_iterator.h b/src/3rd-party/OuterC/oc/json/json_iterator.h new file mode 100644 index 00000000..2520860b --- /dev/null +++ b/src/3rd-party/OuterC/oc/json/json_iterator.h @@ -0,0 +1,377 @@ +// Copyright (c) 2019-2020 OuterC - Nomango + +#pragma once +#include + +namespace oc +{ +namespace __json_detail +{ + +struct primitive_iterator +{ + using difference_type = ptrdiff_t; + + inline primitive_iterator(difference_type it = 0) : it_(it) {} + + inline void set_begin() { it_ = 0; } + inline void set_end() { it_ = 1; } + + inline primitive_iterator& operator++() { ++it_; return *this; } + + inline primitive_iterator operator++(int) { primitive_iterator old(it_); ++(*this); return old; } + + inline primitive_iterator& operator--() { --it_; return (*this); } + inline primitive_iterator operator--(int) { primitive_iterator old = (*this); --(*this); return old; } + + inline bool operator==(primitive_iterator const& other) const { return it_ == other.it_; } + inline bool operator!=(primitive_iterator const& other) const { return !(*this == other); } + + inline const primitive_iterator operator+(difference_type off) const { return primitive_iterator(it_ + off); } + inline const primitive_iterator operator-(difference_type off) const { return primitive_iterator(it_ - off); } + + inline primitive_iterator& operator+=(difference_type off) { it_ += off; return (*this); } + inline primitive_iterator& operator-=(difference_type off) { it_ -= off; return (*this); } + + inline difference_type operator-(primitive_iterator const& other) const { return it_ - other.it_; } + + inline bool operator<(primitive_iterator const& other) const { return it_ < other.it_; } + inline bool operator<=(primitive_iterator const& other) const { return it_ <= other.it_; } + inline bool operator>(primitive_iterator const& other) const { return it_ > other.it_; } + inline bool operator>=(primitive_iterator const& other) const { return it_ >= other.it_; } + +private: + difference_type it_; +}; + +template +struct iterator_impl +{ + friend _BasicJsonTy; + + using string_type = typename _BasicJsonTy::string_type; + using char_type = typename _BasicJsonTy::char_type; + using integer_type = typename _BasicJsonTy::integer_type; + using float_type = typename _BasicJsonTy::float_type; + using boolean_type = typename _BasicJsonTy::boolean_type; + using array_type = typename _BasicJsonTy::array_type; + using object_type = typename _BasicJsonTy::object_type; + + using value_type = _BasicJsonTy; + using difference_type = ptrdiff_t; + using iterator_category = std::bidirectional_iterator_tag; + using pointer = value_type*; + using reference = value_type&; + + using array_iterator = typename _BasicJsonTy::array_type::iterator; + using object_iterator = typename _BasicJsonTy::object_type::iterator; + + inline iterator_impl(pointer json = nullptr) : data_(json), primitive_iter(0), array_iter(), object_iter() {} + + inline iterator_impl(const iterator_impl& rhs) : iterator_impl() + { + operator=(rhs); + } + + ~iterator_impl() {} + + inline iterator_impl& operator=(const iterator_impl& rhs) + { + data_ = rhs.data_; + if (data_) + { + switch (data_->type()) + { + case json_type::OBJECT: + object_iter = rhs.object_iter; + break; + case json_type::VECTOR: + array_iter = rhs.array_iter; + break; + default: + primitive_iter = rhs.primitive_iter; + break; + } + } + return (*this); + } + + inline reference operator*() const + { + check_data(); + check_iterator(); + switch (data_->type()) + { + case json_type::OBJECT: + return (object_iter->second); + case json_type::VECTOR: + return (*array_iter); + default: + return *data_; + } + } + + inline pointer operator->() const + { + check_data(); + check_iterator(); + switch (data_->type()) + { + case json_type::OBJECT: + return &(object_iter->second); + case json_type::VECTOR: + return &(*array_iter); + default: + return data_; + } + } + + inline const typename object_type::key_type& key() const + { + check_data(); + check_iterator(); + if (!data_->is_object()) + throw json_invalid_iterator("cannot use key() with non-object type"); + return object_iter->first; + } + + inline reference value() const + { + return operator*(); + } + + inline void set_begin() + { + check_data(); + + switch (data_->type()) + { + case json_type::OBJECT: + { + object_iter = data_->value_.data.object->begin(); + break; + } + case json_type::VECTOR: + { + array_iter = data_->value_.data.vector->begin(); + break; + } + default: + { + primitive_iter.set_begin(); + break; + } + } + } + + inline void set_end() + { + check_data(); + + switch (data_->type()) + { + case json_type::OBJECT: + { + object_iter = data_->value_.data.object->end(); + break; + } + case json_type::VECTOR: + { + array_iter = data_->value_.data.vector->end(); + break; + } + default: + { + primitive_iter.set_end(); + break; + } + } + } + + inline iterator_impl operator++(int) { iterator_impl old = (*this); ++(*this); return old; } + inline iterator_impl& operator++() + { + check_data(); + + switch (data_->type()) + { + case json_type::OBJECT: + { + std::advance(object_iter, 1); + break; + } + case json_type::VECTOR: + { + std::advance(array_iter, 1); + break; + } + default: + { + ++primitive_iter; + break; + } + } + return *this; + } + + inline iterator_impl operator--(int) { iterator_impl old = (*this); --(*this); return old; } + inline iterator_impl& operator--() + { + check_data(); + + switch (data_->type()) + { + case json_type::OBJECT: + { + std::advance(object_iter, -1); + break; + } + case json_type::VECTOR: + { + std::advance(array_iter, -1); + break; + } + default: + { + --primitive_iter; + break; + } + } + } + + inline const iterator_impl operator-(difference_type off) const { return operator+(-off); } + inline const iterator_impl operator+(difference_type off) const { iterator_impl ret(*this); ret += off; return ret; } + + inline iterator_impl& operator-=(difference_type off) { return operator+=(-off); } + inline iterator_impl& operator+=(difference_type off) + { + check_data(); + + switch (data_->type()) + { + case json_type::OBJECT: + { + throw json_invalid_iterator("cannot use offsets with object type"); + break; + } + case json_type::VECTOR: + { + std::advance(array_iter, off); + break; + } + default: + { + primitive_iter += off; + break; + } + } + return *this; + } + + inline bool operator!=(iterator_impl const& other) const { return !(*this == other); } + inline bool operator==(iterator_impl const& other) const + { + check_data(); + other.check_data(); + + if (data_ != other.data_) + throw json_invalid_iterator("cannot compare iterators of different objects"); + + switch (data_->type()) + { + case json_type::OBJECT: + { + return object_iter == other.object_iter; + } + case json_type::VECTOR: + { + return array_iter == other.array_iter; + } + default: + { + return primitive_iter == other.primitive_iter; + } + } + } + + inline bool operator>(iterator_impl const& other) const { return other.operator<(*this); } + inline bool operator>=(iterator_impl const& other) const { return !operator<(other); } + inline bool operator<=(iterator_impl const& other) const { return !other.operator<(*this); } + inline bool operator<(iterator_impl const& other) const + { + check_data(); + other.check_data(); + + if (data_ != other.data_) + throw json_invalid_iterator("cannot compare iterators of different objects"); + + switch (data_->type()) + { + case json_type::OBJECT: + throw json_invalid_iterator("cannot compare iterators with object type"); + case json_type::VECTOR: + return array_iter < other.array_iter; + default: + return primitive_iter < other.primitive_iter; + } + } + +private: + inline void check_data() const + { + if (data_ == nullptr) + { + throw json_invalid_iterator("iterator contains an empty object"); + } + } + + inline void check_iterator() const + { + switch (data_->type()) + { + case json_type::OBJECT: + if (object_iter == data_->value_.data.object->end()) + { + throw std::out_of_range("iterator out of range"); + } + break; + case json_type::VECTOR: + if (array_iter == data_->value_.data.vector->end()) + { + throw std::out_of_range("iterator out of range"); + } + break; + default: + if (primitive_iter == 1) + { + throw std::out_of_range("iterator out of range"); + } + break; + } + } + +private: + pointer data_; + + union + { + struct + { + array_iterator array_iter; + }; + + struct + { + object_iterator object_iter; + }; + + struct + { + primitive_iterator primitive_iter; // for other types + }; + }; +}; + +} // namespace __json_detail + +} // namespace oc diff --git a/src/3rd-party/OuterC/oc/json/json_output_adapter.h b/src/3rd-party/OuterC/oc/json/json_output_adapter.h new file mode 100644 index 00000000..8c0d2adb --- /dev/null +++ b/src/3rd-party/OuterC/oc/json/json_output_adapter.h @@ -0,0 +1,76 @@ +// Copyright (c) 2019-2020 OuterC - Nomango + +#pragma once +#include + +namespace oc +{ +namespace __json_detail +{ + +template +struct output_adapter +{ + using char_type = _CharTy; + using char_traits = std::char_traits; + + virtual void write(const _CharTy ch) = 0; + virtual void write(const _CharTy* str, uint32_t size) = 0; + virtual void write(const _CharTy* str) + { + const auto size = char_traits::length(str); + write(str, static_cast(size)); + } +}; + +template +struct string_output_adapter + : public output_adapter +{ + using char_type = typename _StringTy::value_type; + using size_type = typename _StringTy::size_type; + using char_traits = std::char_traits; + + string_output_adapter(_StringTy& str) : str_(str) {} + + virtual void write(const char_type ch) override + { + str_.push_back(ch); + } + + virtual void write(const char_type* str, uint32_t size) override + { + str_.append(str, static_cast(size)); + } + +private: + _StringTy& str_; +}; + +template +struct stream_output_adapter + : public output_adapter<_CharTy> +{ + using char_type = _CharTy; + using size_type = typename std::streamsize; + using char_traits = std::char_traits; + + stream_output_adapter(std::basic_ostream& stream) : stream_(stream) {} + + virtual void write(const char_type ch) override + { + stream_.put(ch); + } + + virtual void write(const char_type* str, uint32_t size) override + { + stream_.write(str, static_cast(size)); + } + +private: + std::basic_ostream& stream_; +}; + +} // namespace __json_detail + +} // namespace oc diff --git a/src/3rd-party/OuterC/oc/json/json_parser.h b/src/3rd-party/OuterC/oc/json/json_parser.h new file mode 100644 index 00000000..706233e9 --- /dev/null +++ b/src/3rd-party/OuterC/oc/json/json_parser.h @@ -0,0 +1,567 @@ +// Copyright (c) 2019-2020 OuterC - Nomango + +#pragma once +#include "json_intput_adapter.h" + +namespace oc +{ +namespace __json_detail +{ + +enum class token_type +{ + UNINITIALIZED, + + LITERAL_TRUE, + LITERAL_FALSE, + LITERAL_NULL, + + VALUE_STRING, + VALUE_INTEGER, + VALUE_FLOAT, + + BEGIN_ARRAY, + END_ARRAY, + + BEGIN_OBJECT, + END_OBJECT, + + NAME_SEPARATOR, + VALUE_SEPARATOR, + + PARSE_ERROR, + + END_OF_INPUT +}; + +template +struct json_lexer +{ + using string_type = typename _BasicJsonTy::string_type; + using char_type = typename _BasicJsonTy::char_type; + using integer_type = typename _BasicJsonTy::integer_type; + using float_type = typename _BasicJsonTy::float_type; + using boolean_type = typename _BasicJsonTy::boolean_type; + using array_type = typename _BasicJsonTy::array_type; + using object_type = typename _BasicJsonTy::object_type; + using char_traits = std::char_traits; + + json_lexer(input_adapter* adapter) : adapter(adapter) + { + // read first char + read_next(); + } + + typename char_traits::int_type read_next() + { + current = adapter->get_char(); + return current; + } + + void skip_spaces() + { + while (current == ' ' || current == '\t' || current == '\n' || current == '\r') + { + read_next(); + } + } + + token_type scan() + { + skip_spaces(); + + token_type result = token_type::UNINITIALIZED; + switch (current) + { + case '[': + result = token_type::BEGIN_ARRAY; + break; + case ']': + result = token_type::END_ARRAY; + break; + case '{': + result = token_type::BEGIN_OBJECT; + break; + case '}': + result = token_type::END_OBJECT; + break; + case ':': + result = token_type::NAME_SEPARATOR; + break; + case ',': + result = token_type::VALUE_SEPARATOR; + break; + + case 't': + return scan_literal(L"true", token_type::LITERAL_TRUE); + case 'f': + return scan_literal(L"false", token_type::LITERAL_FALSE); + case 'n': + return scan_literal(L"null", token_type::LITERAL_NULL); + + case '\"': + return scan_string(); + + case '-': + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + return scan_number(); + + case '\0': + case char_traits::eof(): + return token_type::END_OF_INPUT; + + // unexpected char + default: + return token_type::PARSE_ERROR; + } + + // skip current char + read_next(); + + return result; + } + + token_type scan_literal(const char_type* text, token_type result) + { + for (uint32_t i = 0; text[i] != '\0'; ++i) + { + if (text[i] != char_traits::to_char_type(current)) + { + return token_type::PARSE_ERROR; + } + read_next(); + } + return result; + } + + token_type scan_string() + { + if (current != '\"') + return token_type::PARSE_ERROR; + + string_buffer.clear(); + + while (true) + { + const auto ch = read_next(); + switch (ch) + { + case char_traits::eof(): + { + // unexpected end + return token_type::PARSE_ERROR; + } + + case '\"': + { + // skip last `\"` + read_next(); + return token_type::VALUE_STRING; + } + + case 0x00: + case 0x01: + case 0x02: + case 0x03: + case 0x04: + case 0x05: + case 0x06: + case 0x07: + case 0x08: + case 0x09: + case 0x0A: + case 0x0B: + case 0x0C: + case 0x0D: + case 0x0E: + case 0x0F: + case 0x10: + case 0x11: + case 0x12: + case 0x13: + case 0x14: + case 0x15: + case 0x16: + case 0x17: + case 0x18: + case 0x19: + case 0x1A: + case 0x1B: + case 0x1C: + case 0x1D: + case 0x1E: + case 0x1F: + { + // invalid control character + return token_type::PARSE_ERROR; + } + + case '\\': + { + switch (read_next()) + { + case '\"': + string_buffer.push_back('\"'); + break; + case '\\': + string_buffer.push_back('\\'); + break; + case '/': + string_buffer.push_back('/'); + break; + case 'b': + string_buffer.push_back('\b'); + break; + case 'f': + string_buffer.push_back('\f'); + break; + case 'n': + string_buffer.push_back('\n'); + break; + case 'r': + string_buffer.push_back('\r'); + break; + case 't': + string_buffer.push_back('\t'); + break; + + case 'u': + { + // unicode escapes + uint16_t byte = 0; + + for (const auto factor : { 12, 8, 4, 0 }) + { + const auto n = read_next(); + if (n >= L'0' && n <= L'9') + { + byte += ((n - L'0') << factor); + } + else if (n >= L'A' && n <= L'F') + { + byte += ((n - L'A' + 10) << factor); + } + else if (n >= L'a' && n <= L'f') + { + byte += ((n - L'a' + 10) << factor); + } + else + { + // '\u' must be followed by 4 hex digits + return token_type::PARSE_ERROR; + } + } + + string_buffer.push_back(char_traits::to_char_type(byte)); + break; + } + + default: + { + return token_type::PARSE_ERROR; + } + } + break; + } + + default: + { + if (ch > 0x1F && ch < 0x7F) + { + string_buffer.push_back(char_traits::to_char_type(ch)); + break; + } + else + { + return token_type::PARSE_ERROR; + } + } + + } + } + } + + token_type scan_number() + { + is_negative = false; + number_value = static_cast(0.0); + + if (current == '-') + { + return scan_negative(); + } + + if (current == '0') + { + return scan_zero(); + } + + return scan_integer(); + } + + token_type scan_negative() + { + if (current == '-') + { + is_negative = true; + read_next(); + + return scan_integer(); + } + return token_type::PARSE_ERROR; + } + + token_type scan_zero() + { + if (current == '0') + { + if (read_next() == '.') + return scan_float(); + else + return token_type::VALUE_INTEGER; + } + return token_type::PARSE_ERROR; + } + + token_type scan_integer() + { + if (std::isdigit(current)) + { + number_value = static_cast(current - '0'); + + while (true) + { + const auto ch = read_next(); + if (ch == '.') + return scan_float(); + + if (ch == 'e' || ch == 'E') + return scan_exponent(); + + if (std::isdigit(ch)) + number_value = number_value * 10 + (ch - '0'); + else + break; + } + return token_type::VALUE_INTEGER; + } + return token_type::PARSE_ERROR; + } + + token_type scan_float() + { + if (current != '.') + return token_type::PARSE_ERROR; + + if (std::isdigit(read_next())) + { + float_type fraction = static_cast(0.1); + number_value += static_cast(current - '0') * fraction; + + while (true) + { + const auto ch = read_next(); + if (ch == 'e' || ch == 'E') + return scan_exponent(); + + if (std::isdigit(ch)) + { + fraction *= static_cast(0.1); + number_value += static_cast(ch - '0') * fraction; + } + else + break; + } + return token_type::VALUE_FLOAT; + } + return token_type::PARSE_ERROR; + } + + token_type scan_exponent() + { + if (current != 'e' && current != 'E') + return token_type::PARSE_ERROR; + + // skip current char + read_next(); + + if ((std::isdigit(current) && current != '0') || (current == '-') || (current == '+')) + { + float_type core = 10; + if (current == '+') + { + read_next(); + } + else if (current == '-') + { + core = static_cast(0.1); + read_next(); + } + + uint32_t exponent = static_cast(current - '0'); + while (std::isdigit(read_next())) + { + exponent = (exponent * 10) + static_cast(current - '0'); + } + + float_type power = 1; + for (; exponent; exponent >>= 1, core *= core) + if (exponent & 1) + power *= core; + + number_value *= power; + return token_type::VALUE_FLOAT; + } + return token_type::PARSE_ERROR; + } + + integer_type token_to_integer() const + { + integer_type integer = static_cast(number_value); + return is_negative ? -integer : integer; + } + + float_type token_to_float() const + { + return is_negative ? -number_value : number_value; + } + + string_type token_to_string() const + { + return string_buffer; + } + +private: + input_adapter* adapter; + typename char_traits::int_type current; + + bool is_negative; + float_type number_value; + string_type string_buffer; +}; + + +template +struct json_parser +{ + using string_type = typename _BasicJsonTy::string_type; + using char_type = typename _BasicJsonTy::char_type; + using integer_type = typename _BasicJsonTy::integer_type; + using float_type = typename _BasicJsonTy::float_type; + using boolean_type = typename _BasicJsonTy::boolean_type; + using array_type = typename _BasicJsonTy::array_type; + using object_type = typename _BasicJsonTy::object_type; + using char_traits = std::char_traits; + + json_parser(input_adapter* adapter) + : lexer(adapter) + , last_token(token_type::UNINITIALIZED) + {} + + void parse(_BasicJsonTy& json) + { + parse_value(json); + + if (get_token() != token_type::END_OF_INPUT) + throw json_parse_error("unexpected token, expect end"); + } + +private: + token_type get_token() + { + last_token = lexer.scan(); + return last_token; + } + + void parse_value(_BasicJsonTy& json) + { + switch (get_token()) + { + case token_type::LITERAL_TRUE: + json = json_type::BOOL; + json.value_.data.boolean = true; + break; + + case token_type::LITERAL_FALSE: + json = json_type::BOOL; + json.value_.data.boolean = false; + break; + + case token_type::LITERAL_NULL: + json = json_type::NIL; + break; + + case token_type::VALUE_STRING: + json = lexer.token_to_string(); + break; + + case token_type::VALUE_INTEGER: + json = lexer.token_to_integer(); + break; + + case token_type::VALUE_FLOAT: + json = lexer.token_to_float(); + break; + + case token_type::BEGIN_ARRAY: + json = json_type::VECTOR; + while (true) + { + json.value_.data.vector->push_back(_BasicJsonTy()); + parse_value(json.value_.data.vector->back()); + + // read ',' + if (get_token() != token_type::VALUE_SEPARATOR) + break; + } + if (last_token != token_type::END_ARRAY) + throw json_parse_error("unexpected token in array"); + break; + + case token_type::BEGIN_OBJECT: + json = json_type::OBJECT; + while (true) + { + if (get_token() != token_type::VALUE_STRING) + break; + string_type key = lexer.token_to_string(); + + if (get_token() != token_type::NAME_SEPARATOR) + break; + + _BasicJsonTy object; + parse_value(object); + json.value_.data.object->insert(std::make_pair(key, object)); + + // read ',' + if (get_token() != token_type::VALUE_SEPARATOR) + break; + } + if (last_token != token_type::END_OBJECT) + throw json_parse_error("unexpected token in object"); + break; + + default: + // unexpected token + throw json_parse_error("unexpected token"); + break; + } + } + +private: + json_lexer<_BasicJsonTy> lexer; + token_type last_token; +}; + +} // namespace __json_detail + +} // namespace oc diff --git a/src/3rd-party/OuterC/oc/json/json_serializer.h b/src/3rd-party/OuterC/oc/json/json_serializer.h new file mode 100644 index 00000000..68e120d1 --- /dev/null +++ b/src/3rd-party/OuterC/oc/json/json_serializer.h @@ -0,0 +1,421 @@ +// Copyright (c) 2019-2020 OuterC - Nomango + +#pragma once +#include "json_output_adapter.h" +#include +#include + +namespace oc +{ + +namespace __json_detail +{ + +template +struct json_literaler +{ + using char_type = _CharTy; + using string_type = const char_type*; + + static inline string_type value_separator() { return ",\n"; } + + static inline string_type empty_object() { return "{}"; } + static inline string_type object_begin() { return "{\n"; } + static inline string_type object_key_begin() { return "\": "; } + + static inline string_type empty_array() { return "[]"; } + static inline string_type array_begin() { return "[\n"; } + + static inline string_type literal_true() { return "true"; } + static inline string_type literal_false() { return "false"; } + static inline string_type literal_null() { return "null"; } + + static inline string_type escape_t() { return "\\t"; } + static inline string_type escape_r() { return "\\r"; } + static inline string_type escape_n() { return "\\n"; } + static inline string_type escape_b() { return "\\b"; } + static inline string_type escape_f() { return "\\f"; } + static inline string_type escape_quote() { return "\\\""; } + static inline string_type escape_slash() { return "\\\\"; } + + template + static inline void sprint_float(char_type* buff, const _FloatTy value) + { + const auto digits = std::numeric_limits<_FloatTy>::max_digits10; + const auto len = ::_scprintf("%.*g", digits, value); + if (len) + { + buff[0] = '\0'; + ::sprintf_s(buff, size_t(len) + 1, "%.*g", digits, value); + } + else + { + buff[0] = '0'; + buff[1] = '.'; + buff[2] = '0'; + buff[3] = '\0'; + } + } +}; + +template <> +struct json_literaler +{ + using char_type = wchar_t; + using string_type = const char_type*; + + static inline string_type value_separator() { return L",\n"; } + + static inline string_type empty_object() { return L"{}"; } + static inline string_type object_begin() { return L"{\n"; } + static inline string_type object_key_begin() { return L"\":"; } + + static inline string_type empty_array() { return L"[]"; } + static inline string_type array_begin() { return L"[\n"; } + + static inline string_type literal_true() { return L"true"; } + static inline string_type literal_false() { return L"false"; } + static inline string_type literal_null() { return L"null"; } + + static inline string_type escape_t() { return L"\\t"; } + static inline string_type escape_r() { return L"\\r"; } + static inline string_type escape_n() { return L"\\n"; } + static inline string_type escape_b() { return L"\\b"; } + static inline string_type escape_f() { return L"\\f"; } + static inline string_type escape_quote() { return L"\\\""; } + static inline string_type escape_slash() { return L"\\\\"; } + + template + static inline void sprint_float(char_type* buff, const _FloatTy value) + { + const auto digits = std::numeric_limits<_FloatTy>::max_digits10; + const auto len = ::_scwprintf(L"%.*g", digits, value); + if (len) + { + buff[0] = '\0'; + ::swprintf_s(buff, size_t(len) + 1, L"%.*g", digits, value); + } + else + { + buff[0] = '0'; + buff[1] = '.'; + buff[2] = '0'; + buff[3] = '\0'; + } + } +}; + +template +struct json_serializer +{ + using string_type = typename _BasicJsonTy::string_type; + using char_type = typename _BasicJsonTy::char_type; + using integer_type = typename _BasicJsonTy::integer_type; + using float_type = typename _BasicJsonTy::float_type; + using boolean_type = typename _BasicJsonTy::boolean_type; + using array_type = typename _BasicJsonTy::array_type; + using object_type = typename _BasicJsonTy::object_type; + using literaler = json_literaler; + + json_serializer(output_adapter* out, const char_type indent_char) + : out(out) + , indent_char(indent_char) + , indent_string(32, indent_char) + {} + + void dump( + const _BasicJsonTy& json, + const bool pretty_print, + const bool char_escape, + const uint32_t indent_step, + const uint32_t current_indent = 0) + { + switch (json.type()) + { + case json_type::OBJECT: + { + auto& object = *json.value_.data.object; + + if (object.empty()) + { + out->write(literaler::empty_object()); + return; + } + + if (pretty_print) + { + out->write(literaler::object_begin()); + + const auto new_indent = current_indent + indent_step; + if (indent_string.size() < new_indent) + { + indent_string.resize(indent_string.size() * 2, indent_char); + } + + auto iter = object.cbegin(); + const auto size = object.size(); + for (uint32_t i = 0; i < size; ++i, ++iter) + { + out->write(indent_string.c_str(), new_indent); + out->write('\"'); + out->write(iter->first.c_str()); + out->write(literaler::object_key_begin()); + out->write(' '); + dump(iter->second, pretty_print, char_escape, indent_step, new_indent); + + // not last element + if (i != size - 1) + out->write(literaler::value_separator()); + } + + out->write('\n'); + out->write(indent_string.c_str(), current_indent); + out->write('}'); + } + else + { + out->write('{'); + + auto iter = object.cbegin(); + const auto size = object.size(); + for (uint32_t i = 0; i < size; ++i, ++iter) + { + out->write('\"'); + out->write(iter->first.c_str()); + out->write(literaler::object_key_begin()); + dump(iter->second, pretty_print, char_escape, indent_step, current_indent); + + // not last element + if (i != size - 1) + out->write(','); + } + + out->write('}'); + } + + return; + } + + case json_type::VECTOR: + { + auto& vector = *json.value_.data.vector; + + if (vector.empty()) + { + out->write(literaler::empty_array()); + return; + } + + if (pretty_print) + { + out->write(literaler::array_begin()); + + const auto new_indent = current_indent + indent_step; + if (indent_string.size() < new_indent) + { + indent_string.resize(indent_string.size() * 2, indent_char); + } + + auto iter = vector.cbegin(); + const auto size = vector.size(); + for (uint32_t i = 0; i < size; ++i, ++iter) + { + out->write(indent_string.c_str(), new_indent); + dump(*iter, pretty_print, char_escape, indent_step, new_indent); + + // not last element + if (i != size - 1) + out->write(literaler::value_separator()); + } + + out->write('\n'); + out->write(indent_string.c_str(), current_indent); + out->write(']'); + } + else + { + out->write('['); + + auto iter = vector.cbegin(); + const auto size = vector.size(); + for (uint32_t i = 0; i < size; ++i, ++iter) + { + dump(*iter, pretty_print, char_escape, indent_step, current_indent); + // not last element + if (i != size - 1) + out->write(','); + } + + out->write(']'); + } + + return; + } + + case json_type::STRING: + { + out->write('\"'); + dump_string(*json.value_.data.string, char_escape); + out->write('\"'); + return; + } + + case json_type::BOOL: + { + if (json.value_.data.boolean) + { + out->write(literaler::literal_true()); + } + else + { + out->write(literaler::literal_false()); + } + return; + } + + case json_type::INTEGER: + { + dump_integer(json.value_.data.number_integer); + return; + } + + case json_type::FLOAT: + { + dump_float(json.value_.data.number_float); + return; + } + + case json_type::NIL: + { + out->write(literaler::literal_null()); + return; + } + } + } + + void dump_integer(integer_type val) + { + if (val == 0) + { + out->write('0'); + return; + } + + auto uval = static_cast>(val); + + if (val < 0) + uval = 0 - uval; + + if (number_buffer == nullptr) + number_buffer.reset(new number_buffer_type); + + auto next = (*number_buffer).rbegin(); + *next = '\0'; + + do + { + *(++next) = static_cast('0' + uval % 10); + uval /= 10; + } while (uval != 0); + + if (val < 0) + *(++next) = '-'; + + out->write(&(*next)); + } + + void dump_float(float_type val) + { + if (number_buffer == nullptr) + number_buffer.reset(new number_buffer_type); + + literaler::sprint_float((*number_buffer).data(), val); + out->write((*number_buffer).data()); + } + + void dump_string(const string_type & val, const bool char_escape) + { + for (const auto& ch : val) + { + switch (ch) + { + case '\t': + { + out->write(literaler::escape_t()); + break; + } + + case '\r': + { + out->write(literaler::escape_r()); + break; + } + + case '\n': + { + out->write(literaler::escape_n()); + break; + } + + case '\b': + { + out->write(literaler::escape_b()); + break; + } + + case '\f': + { + out->write(literaler::escape_f()); + break; + } + + case '\"': + { + out->write(literaler::escape_quote()); + break; + } + + case '\\': + { + out->write(literaler::escape_slash()); + break; + } + + default: + { + uint32_t char_byte = static_cast(ch); + if (char_byte > 0x1F && (!char_escape || char_byte < 0x7F)) + { + out->write(ch); + } + else + { + char_type escaped[7] = { '\\', 'u', 0 }; + + uint8_t index = 2; + for (const auto factor : { 12, 8, 4, 0 }) + { + char_type code = ((char_byte >> factor) & 0x0F); + code += (code < 0x0A) ? '0' : 'a' - 0x0A; + escaped[index++] = code; + } + out->write(escaped); + } + break; + } + } + } + } + +private: + output_adapter* out; + char_type indent_char; + string_type indent_string; + + using number_buffer_type = std::array; + std::unique_ptr number_buffer; +}; + +} // namespace __json_detail + +} // namespace oc diff --git a/src/3rd-party/OuterC/oc/json/json_value.h b/src/3rd-party/OuterC/oc/json/json_value.h new file mode 100644 index 00000000..94f5ba0f --- /dev/null +++ b/src/3rd-party/OuterC/oc/json/json_value.h @@ -0,0 +1,240 @@ +// Copyright (c) 2019-2020 OuterC - Nomango + +#pragma once +#include +#include + +namespace oc +{ + +enum class json_type +{ + INTEGER, + FLOAT, + STRING, + VECTOR, + OBJECT, + BOOL, + NIL, +}; + +namespace __json_detail +{ + +template +struct json_value +{ + using string_type = typename _BasicJsonTy::string_type; + using char_type = typename _BasicJsonTy::char_type; + using integer_type = typename _BasicJsonTy::integer_type; + using float_type = typename _BasicJsonTy::float_type; + using boolean_type = typename _BasicJsonTy::boolean_type; + using array_type = typename _BasicJsonTy::array_type; + using object_type = typename _BasicJsonTy::object_type; + + json_type type; + union + { + object_type* object; + array_type* vector; + string_type* string; + integer_type number_integer; + float_type number_float; + boolean_type boolean; + } data; + + json_value() + { + type = json_type::NIL; + data.object = nullptr; + } + + json_value(std::nullptr_t) + { + type = json_type::NIL; + data.object = nullptr; + } + + json_value(const object_type& value) + { + type = json_type::OBJECT; + data.object = create(value); + } + + json_value(const array_type& value) + { + type = json_type::VECTOR; + data.vector = create(value); + } + + json_value(const string_type& value) + { + type = json_type::STRING; + data.string = create(value); + } + + template + json_value(const _CharT* str) + { + type = json_type::STRING; + data.string = create(str); + } + + json_value(const integer_type value) + { + type = json_type::INTEGER; + data.number_integer = value; + } + + json_value(const float_type value) + { + type = json_type::FLOAT; + data.number_float = value; + } + + json_value(const boolean_type value) + { + type = json_type::BOOL; + data.boolean = value; + } + + json_value(const json_type value_type) + { + type = value_type; + switch (type) + { + case json_type::OBJECT: + data.object = create(); + break; + case json_type::VECTOR: + data.vector = create(); + break; + case json_type::STRING: + data.string = create(); + break; + case json_type::INTEGER: + data.number_integer = integer_type(0); + break; + case json_type::FLOAT: + data.number_float = float_type(0.0); + break; + case json_type::BOOL: + data.boolean = boolean_type(false); + break; + default: + data.object = nullptr; + break; + } + } + + json_value(json_value const& other) + { + type = other.type; + + switch (other.type) + { + case json_type::OBJECT: + data.object = create(*other.data.object); + break; + case json_type::VECTOR: + data.vector = create(*other.data.vector); + break; + case json_type::STRING: + data.string = create(*other.data.string); + break; + case json_type::INTEGER: + data.number_integer = other.data.number_integer; + break; + case json_type::FLOAT: + data.number_float = other.data.number_float; + break; + case json_type::BOOL: + data.boolean = other.data.boolean; + break; + default: + data.object = nullptr; + break; + } + } + + json_value(json_value&& other) noexcept + { + type = other.type; + data = other.data; + other.type = json_type::NIL; + other.data.object = nullptr; + } + + ~json_value() + { + clear(); + } + + void swap(json_value& other) + { + std::swap(type, other.type); + std::swap(data, other.data); + } + + void clear() + { + switch (type) + { + case json_type::OBJECT: + destroy(data.object); + break; + case json_type::VECTOR: + destroy(data.vector); + break; + case json_type::STRING: + destroy(data.string); + break; + default: + break; + } + } + + template + inline _Ty* create(_Args&&... args) + { + using allocator_type = typename _BasicJsonTy::template allocator_type<_Ty>; + using allocator_traits = std::allocator_traits; + + allocator_type allocator; + _Ty* ptr = allocator_traits::allocate(allocator, 1); + allocator_traits::construct(allocator, ptr, std::forward<_Args>(args)...); + return ptr; + } + + template + inline void destroy(_Ty* ptr) + { + using allocator_type = typename _BasicJsonTy::template allocator_type<_Ty>; + using allocator_traits = std::allocator_traits; + + allocator_type allocator; + allocator_traits::destroy(allocator, ptr); + allocator_traits::deallocate(allocator, ptr, 1); + } + + inline json_value& operator=(json_value const& other) + { + json_value{ other }.swap(*this); + return (*this); + } + + inline json_value& operator=(json_value&& other) noexcept + { + clear(); + type = other.type; + data = std::move(other.data); + // invalidate payload + other.type = json_type::NIL; + other.data.object = nullptr; + return (*this); + } +}; + +} // namespace __json_detail + +} // namespace oc diff --git a/src/3rd-party/OuterC/oc/json/json_value_getter.h b/src/3rd-party/OuterC/oc/json/json_value_getter.h new file mode 100644 index 00000000..220deb27 --- /dev/null +++ b/src/3rd-party/OuterC/oc/json/json_value_getter.h @@ -0,0 +1,79 @@ +// Copyright (c) 2019-2020 OuterC - Nomango + +#pragma once +#include "json_value.h" + +namespace oc +{ +namespace __json_detail +{ + +template +struct json_value_getter +{ + using string_type = typename _BasicJsonTy::string_type; + using char_type = typename _BasicJsonTy::char_type; + using integer_type = typename _BasicJsonTy::integer_type; + using float_type = typename _BasicJsonTy::float_type; + using boolean_type = typename _BasicJsonTy::boolean_type; + using array_type = typename _BasicJsonTy::array_type; + using object_type = typename _BasicJsonTy::object_type; + + static inline void assign(const _BasicJsonTy& json, object_type& value) + { + if (!json.is_object()) throw json_type_error("json value type must be object"); + value = *json.value_.data.object; + } + + static inline void assign(const _BasicJsonTy& json, array_type& value) + { + if (!json.is_array()) throw json_type_error("json value type must be array"); + value = *json.value_.data.vector; + } + + static inline void assign(const _BasicJsonTy& json, string_type& value) + { + if (!json.is_string()) throw json_type_error("json value type must be string"); + value = *json.value_.data.string; + } + + static inline void assign(const _BasicJsonTy& json, boolean_type& value) + { + if (!json.is_boolean()) throw json_type_error("json value type must be boolean"); + value = json.value_.data.boolean; + } + + static inline void assign(const _BasicJsonTy& json, integer_type& value) + { + if (!json.is_integer()) throw json_type_error("json value type must be integer"); + value = json.value_.data.number_integer; + } + + template < + typename _IntegerTy, + typename std::enable_if::value, int>::type = 0> + static inline void assign(const _BasicJsonTy& json, _IntegerTy& value) + { + if (!json.is_integer()) throw json_type_error("json value type must be integer"); + value = static_cast<_IntegerTy>(json.value_.data.number_integer); + } + + static inline void assign(const _BasicJsonTy& json, float_type& value) + { + if (!json.is_float()) throw json_type_error("json value type must be float"); + value = json.value_.data.number_float; + } + + template < + typename _FloatingTy, + typename std::enable_if::value, int>::type = 0> + static inline void assign(const _BasicJsonTy& json, _FloatingTy& value) + { + if (!json.is_float()) throw json_type_error("json value type must be float"); + value = static_cast<_FloatingTy>(json.value_.data.number_float); + } +}; + +} // namespace __json_detail + +} // namespace oc diff --git a/src/3rd-party/OuterC/oc/macros.h b/src/3rd-party/OuterC/oc/macros.h new file mode 100644 index 00000000..c85a8d7b --- /dev/null +++ b/src/3rd-party/OuterC/oc/macros.h @@ -0,0 +1,8 @@ +// Copyright (c) 2019-2020 OuterC - Nomango + +#pragma once +#include +#include +#include + +#define OC_ASSERT(EXPR) assert(EXPR) diff --git a/src/3rd-party/OuterC/oc/noncopyable.h b/src/3rd-party/OuterC/oc/noncopyable.h new file mode 100644 index 00000000..76725522 --- /dev/null +++ b/src/3rd-party/OuterC/oc/noncopyable.h @@ -0,0 +1,19 @@ +// Copyright (c) 2019-2020 OuterC - Nomango + +#pragma once + +namespace oc +{ + +class noncopyable +{ +protected: + noncopyable() = default; + +private: + noncopyable(const noncopyable&) = delete; + + noncopyable& operator=(const noncopyable&) = delete; +}; + +} // namespace oc diff --git a/src/3rd-party/OuterC/oc/oc.h b/src/3rd-party/OuterC/oc/oc.h new file mode 100644 index 00000000..5171e999 --- /dev/null +++ b/src/3rd-party/OuterC/oc/oc.h @@ -0,0 +1,13 @@ +// Copyright (c) 2019-2020 OuterC - Nomango + +#pragma once +#include "macros.h" +#include "vector.h" +#include "string.h" +#include "any.h" +#include "function.h" +#include "noncopyable.h" +#include "singleton.h" +#include "intrusive_ptr.h" +#include "intrusive_list.h" +#include "json.h" diff --git a/src/3rd-party/OuterC/oc/singleton.h b/src/3rd-party/OuterC/oc/singleton.h new file mode 100644 index 00000000..44726bb6 --- /dev/null +++ b/src/3rd-party/OuterC/oc/singleton.h @@ -0,0 +1,50 @@ +// Copyright (c) 2019-2020 OuterC - Nomango + +#pragma once + +// Class that will implement the singleton mode must use the macro in its delare file + +#ifndef OC_DECLARE_SINGLETON +#define OC_DECLARE_SINGLETON( CLASS ) \ + friend ::oc::singleton< CLASS >; +#endif + +namespace oc +{ + +template +struct singleton +{ +protected: + singleton() = default; + singleton(const singleton&) = delete; + singleton& operator=(const singleton&) = delete; + +private: + struct object_creator + { + object_creator() + { + (void)singleton<_Ty>::instance(); + } + + inline void dummy() const {} + }; + static object_creator creator_; + +public: + using object_type = _Ty; + + static inline object_type& instance() + { + static object_type instance; + creator_.dummy(); + return instance; + } +}; + +template +typename singleton<_Ty>::object_creator singleton<_Ty>::creator_; + + +} // namespace oc diff --git a/src/kiwano/common/string.hpp b/src/3rd-party/OuterC/oc/string.h similarity index 50% rename from src/kiwano/common/string.hpp rename to src/3rd-party/OuterC/oc/string.h index a34789e8..0fc944d4 100644 --- a/src/kiwano/common/string.hpp +++ b/src/3rd-party/OuterC/oc/string.h @@ -1,22 +1,4 @@ -// Copyright (c) 2016-2018 Kiwano - Nomango -// -// 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. +// Copyright (c) 2019-2020 OuterC - Nomango #pragma once #include @@ -27,9 +9,7 @@ #include #include -namespace kiwano -{ -namespace common +namespace oc { // @@ -425,8 +405,8 @@ basic_string format_string(const wchar_t* const fmt, _Args&& ... args); // // string && wstring // -using string = ::kiwano::common::basic_string; -using wstring = ::kiwano::common::basic_string; +using string = ::oc::basic_string; +using wstring = ::oc::basic_string; inline string to_string(int val) { return to_basic_string(val); } @@ -450,10 +430,9 @@ inline wstring to_wstring(double val) { return to_basic_string(val); inline wstring to_wstring(long double val) { return to_basic_string(val); } -} // namespace common -} // namespace kiwano +} // namespace oc -namespace kiwano +namespace oc { // @@ -515,153 +494,95 @@ namespace __string_details } } -namespace common + +template +inline basic_string<_CharTy>::basic_string() + : str_(nullptr) + , size_(0) + , capacity_(0) + , operable_(true) { +} - template - inline basic_string<_CharTy>::basic_string() - : str_(nullptr) - , size_(0) - , capacity_(0) - , operable_(true) +template +inline basic_string<_CharTy>::basic_string(const char_type* cstr, bool const_str) + : operable_(!const_str) + , size_(0) + , capacity_(0) + , str_(nullptr) +{ + if (cstr == nullptr) + return; + + if (operable_) { + assign(cstr, traits_type::length(cstr)); } - - template - inline basic_string<_CharTy>::basic_string(const char_type* cstr, bool const_str) - : operable_(!const_str) - , size_(0) - , capacity_(0) - , str_(nullptr) + else { - if (cstr == nullptr) - return; - - if (operable_) - { - assign(cstr, traits_type::length(cstr)); - } - else - { - const_str_ = cstr; - size_ = traits_type::length(cstr); - capacity_ = size_; - } + const_str_ = cstr; + size_ = traits_type::length(cstr); + capacity_ = size_; } +} - template - inline basic_string<_CharTy>::basic_string(const char_type* cstr, size_type count) - : basic_string() +template +inline basic_string<_CharTy>::basic_string(const char_type* cstr, size_type count) + : basic_string() +{ + assign(cstr, count); +} + +template +inline basic_string<_CharTy>::basic_string(size_type count, char_type ch) + : basic_string() +{ + assign(count, ch); +} + +template +inline basic_string<_CharTy>::basic_string(basic_string const& rhs) + : basic_string(rhs.const_str_, !rhs.operable_) +{ +} + +template +inline basic_string<_CharTy>::basic_string(basic_string const& rhs, size_type pos, size_type count) + : basic_string() +{ + assign(rhs, pos, count); +} + +template +inline basic_string<_CharTy>::basic_string(std::basic_string const& str) + : basic_string(str.c_str(), false) +{ +} + +template +inline basic_string<_CharTy>::basic_string(basic_string&& rhs) noexcept + : str_(rhs.str_) + , size_(rhs.size_) + , capacity_(rhs.capacity_) + , operable_(rhs.operable_) +{ + rhs.str_ = nullptr; + rhs.size_ = rhs.capacity_ = 0; +} + +template +inline basic_string<_CharTy>::~basic_string() +{ + destroy(); +} + +template +inline basic_string<_CharTy>& basic_string<_CharTy>::assign(size_type count, const char_type ch) +{ + discard_const_data(); + + if (count != 0) { - assign(cstr, count); - } - - template - inline basic_string<_CharTy>::basic_string(size_type count, char_type ch) - : basic_string() - { - assign(count, ch); - } - - template - inline basic_string<_CharTy>::basic_string(basic_string const& rhs) - : basic_string(rhs.const_str_, !rhs.operable_) - { - } - - template - inline basic_string<_CharTy>::basic_string(basic_string const& rhs, size_type pos, size_type count) - : basic_string() - { - assign(rhs, pos, count); - } - - template - inline basic_string<_CharTy>::basic_string(std::basic_string const& str) - : basic_string(str.c_str(), false) - { - } - - template - inline basic_string<_CharTy>::basic_string(basic_string&& rhs) noexcept - : str_(rhs.str_) - , size_(rhs.size_) - , capacity_(rhs.capacity_) - , operable_(rhs.operable_) - { - rhs.str_ = nullptr; - rhs.size_ = rhs.capacity_ = 0; - } - - template - inline basic_string<_CharTy>::~basic_string() - { - destroy(); - } - - template - inline basic_string<_CharTy>& basic_string<_CharTy>::assign(size_type count, const char_type ch) - { - discard_const_data(); - - if (count != 0) - { - if (count > capacity_) - { - destroy(); - str_ = allocate(count + 1); - capacity_ = count; - } - size_ = count; - - traits_type::assign(str_, size_, ch); - traits_type::assign(*(str_ + size_), value_type()); - } - else - { - clear(); - } - return (*this); - } - - template - inline basic_string<_CharTy>& basic_string<_CharTy>::assign(const char_type* cstr, size_type count) - { - discard_const_data(); - - if (cstr && count) - { - if (count > capacity_) - { - destroy(); - str_ = allocate(count + 1); - capacity_ = count; - } - size_ = count; - - traits_type::move(str_, cstr, size_); - traits_type::assign(str_[size_], value_type()); - } - else - { - clear(); - } - return (*this); - } - - template - inline basic_string<_CharTy>& basic_string<_CharTy>::assign(basic_string const& rhs, size_type pos, size_type count) - { - if (count == 0 || pos > rhs.size()) - { - clear(); - return (*this); - } - - discard_const_data(); - - count = rhs.clamp_suffix_size(pos, count); - if (count > capacity_) { destroy(); @@ -670,855 +591,911 @@ namespace common } size_ = count; - traits_type::move(str_, rhs.begin().core() + pos, size_); + traits_type::assign(str_, size_, ch); + traits_type::assign(*(str_ + size_), value_type()); + } + else + { + clear(); + } + return (*this); +} + +template +inline basic_string<_CharTy>& basic_string<_CharTy>::assign(const char_type* cstr, size_type count) +{ + discard_const_data(); + + if (cstr && count) + { + if (count > capacity_) + { + destroy(); + str_ = allocate(count + 1); + capacity_ = count; + } + size_ = count; + + traits_type::move(str_, cstr, size_); traits_type::assign(str_[size_], value_type()); + } + else + { + clear(); + } + return (*this); +} + +template +inline basic_string<_CharTy>& basic_string<_CharTy>::assign(basic_string const& rhs, size_type pos, size_type count) +{ + if (count == 0 || pos > rhs.size()) + { + clear(); return (*this); } - template - inline basic_string<_CharTy>& basic_string<_CharTy>::erase(size_type offset, size_type count) + discard_const_data(); + + count = rhs.clamp_suffix_size(pos, count); + + if (count > capacity_) { - if (count == 0) - return (*this); - - check_offset(offset); - check_operability(); - - count = clamp_suffix_size(offset, count); - - if (count == 0) - { - clear(); - return (*this); - } - - size_type new_size = size_ - count; - iterator erase_at = begin().core() + offset; - traits_type::move(erase_at.core(), erase_at.core() + count, new_size - offset + 1); - return (*this); - } - - template - inline basic_string<_CharTy>& basic_string<_CharTy>::insert(size_type index, size_type count, char_type ch) - { - if (count == 0) - return (*this); - - if (index >= size()) - return append(count, ch); - - check_operability(); - - char_type* const old_ptr = str_; - const size_type old_size = size_; - const size_type old_capacity = capacity_; - const size_type suffix_size = old_size - index + 1; - - size_ = old_size + count; - - if (size_ > old_capacity) - { - capacity_ = size_; - char_type* new_ptr = allocate(capacity_ + 1); - - char_type* const insert_at = new_ptr + index; - traits_type::move(new_ptr, old_ptr, index); // (0) - (index) - traits_type::assign(insert_at, count, ch); // (index) - (index + count) - traits_type::move(insert_at + count, old_ptr + index, suffix_size); // (index + count) - (old_size - index) - - deallocate(str_, old_capacity + 1); - str_ = new_ptr; - } - else - { - char_type* const insert_at = old_ptr + index; - traits_type::move(insert_at + count, old_ptr + index, suffix_size); - traits_type::assign(insert_at, count, ch); - } - - return (*this); - } - - template - inline basic_string<_CharTy>& basic_string<_CharTy>::insert(size_type index, const char_type* cstr, size_type count) - { - if (count == 0) - return (*this); - - if (index >= size()) - return append(cstr, count); - - check_operability(); - - char_type* const old_ptr = str_; - const size_type old_size = size_; - const size_type old_capacity = capacity_; - const size_type suffix_size = old_size - index + 1; - - size_ = old_size + count; - - if (size_ > old_capacity) - { - capacity_ = size_; - char_type* new_ptr = allocate(capacity_ + 1); - - char_type* const insert_at = new_ptr + index; - traits_type::move(new_ptr, old_ptr, index); // (0) - (index) - traits_type::move(insert_at, cstr, count); // (index) - (index + count) - traits_type::move(insert_at + count, old_ptr + index, suffix_size); // (index + count) - (old_size - index) - - deallocate(str_, old_capacity + 1); - str_ = new_ptr; - } - else - { - char_type* const insert_at = old_ptr + index; - traits_type::move(insert_at + count, old_ptr + index, suffix_size); - traits_type::move(insert_at, cstr, count); - } - - return (*this); - } - - template - inline basic_string<_CharTy>& basic_string<_CharTy>::insert(size_type index, const basic_string& str, size_type off, size_type count) - { - if (count == 0 || off > str.size()) - return (*this); - - if (index >= size()) - return append(str, off, count); - - check_operability(); - - count = clamp_suffix_size(off, count); - - char_type* const old_ptr = str_; - const size_type old_size = size_; - const size_type old_capacity = capacity_; - const size_type suffix_size = old_size - index + 1; - - size_ = old_size + count; - - if (size_ > old_capacity) - { - capacity_ = size_; - char_type* new_ptr = allocate(capacity_ + 1); - - char_type* const insert_at = new_ptr + index; - traits_type::move(new_ptr, old_ptr, index); // (0) - (index) - traits_type::move(insert_at, str.begin().core() + off, count); // (index) - (index + count) - traits_type::move(insert_at + count, old_ptr + index, suffix_size); // (index + count) - (old_size - index) - - deallocate(str_, old_capacity + 1); - str_ = new_ptr; - } - else - { - char_type* const insert_at = old_ptr + index; - traits_type::move(insert_at + count, old_ptr + index, suffix_size); - traits_type::move(insert_at, str.begin().core() + off, count); - } - - return (*this); - } - - template - inline basic_string<_CharTy>& basic_string<_CharTy>::append(size_type count, char_type ch) - { - check_operability(); - - size_type new_size = size_ + count; - size_type new_cap = new_size + 1; - char_type* new_str = allocate(new_cap); - - traits_type::move(new_str, str_, size_); - traits_type::assign(new_str + size_, count, ch); - traits_type::assign(new_str[new_size], value_type()); - destroy(); + str_ = allocate(count + 1); + capacity_ = count; + } + size_ = count; - str_ = new_str; - size_ = new_size; - capacity_ = new_cap; + traits_type::move(str_, rhs.begin().core() + pos, size_); + traits_type::assign(str_[size_], value_type()); + return (*this); +} + +template +inline basic_string<_CharTy>& basic_string<_CharTy>::erase(size_type offset, size_type count) +{ + if (count == 0) + return (*this); + + check_offset(offset); + check_operability(); + + count = clamp_suffix_size(offset, count); + + if (count == 0) + { + clear(); return (*this); } - template - inline basic_string<_CharTy>& basic_string<_CharTy>::append(const char_type* cstr, size_type count) + size_type new_size = size_ - count; + iterator erase_at = begin().core() + offset; + traits_type::move(erase_at.core(), erase_at.core() + count, new_size - offset + 1); + return (*this); +} + +template +inline basic_string<_CharTy>& basic_string<_CharTy>::insert(size_type index, size_type count, char_type ch) +{ + if (count == 0) + return (*this); + + if (index >= size()) + return append(count, ch); + + check_operability(); + + char_type* const old_ptr = str_; + const size_type old_size = size_; + const size_type old_capacity = capacity_; + const size_type suffix_size = old_size - index + 1; + + size_ = old_size + count; + + if (size_ > old_capacity) { - check_operability(); + capacity_ = size_; + char_type* new_ptr = allocate(capacity_ + 1); - size_type new_size = size_ + count; - size_type new_cap = new_size + 1; - char_type* new_str = allocate(new_cap); + char_type* const insert_at = new_ptr + index; + traits_type::move(new_ptr, old_ptr, index); // (0) - (index) + traits_type::assign(insert_at, count, ch); // (index) - (index + count) + traits_type::move(insert_at + count, old_ptr + index, suffix_size); // (index + count) - (old_size - index) - traits_type::move(new_str, str_, size_); - traits_type::move(new_str + size_, cstr, count); - traits_type::assign(new_str[new_size], value_type()); + deallocate(str_, old_capacity + 1); + str_ = new_ptr; + } + else + { + char_type* const insert_at = old_ptr + index; + traits_type::move(insert_at + count, old_ptr + index, suffix_size); + traits_type::assign(insert_at, count, ch); + } - destroy(); + return (*this); +} - str_ = new_str; - size_ = new_size; - capacity_ = new_cap; +template +inline basic_string<_CharTy>& basic_string<_CharTy>::insert(size_type index, const char_type* cstr, size_type count) +{ + if (count == 0) + return (*this); + + if (index >= size()) + return append(cstr, count); + + check_operability(); + + char_type* const old_ptr = str_; + const size_type old_size = size_; + const size_type old_capacity = capacity_; + const size_type suffix_size = old_size - index + 1; + + size_ = old_size + count; + + if (size_ > old_capacity) + { + capacity_ = size_; + char_type* new_ptr = allocate(capacity_ + 1); + + char_type* const insert_at = new_ptr + index; + traits_type::move(new_ptr, old_ptr, index); // (0) - (index) + traits_type::move(insert_at, cstr, count); // (index) - (index + count) + traits_type::move(insert_at + count, old_ptr + index, suffix_size); // (index + count) - (old_size - index) + + deallocate(str_, old_capacity + 1); + str_ = new_ptr; + } + else + { + char_type* const insert_at = old_ptr + index; + traits_type::move(insert_at + count, old_ptr + index, suffix_size); + traits_type::move(insert_at, cstr, count); + } + + return (*this); +} + +template +inline basic_string<_CharTy>& basic_string<_CharTy>::insert(size_type index, const basic_string& str, size_type off, size_type count) +{ + if (count == 0 || off > str.size()) + return (*this); + + if (index >= size()) + return append(str, off, count); + + check_operability(); + + count = clamp_suffix_size(off, count); + + char_type* const old_ptr = str_; + const size_type old_size = size_; + const size_type old_capacity = capacity_; + const size_type suffix_size = old_size - index + 1; + + size_ = old_size + count; + + if (size_ > old_capacity) + { + capacity_ = size_; + char_type* new_ptr = allocate(capacity_ + 1); + + char_type* const insert_at = new_ptr + index; + traits_type::move(new_ptr, old_ptr, index); // (0) - (index) + traits_type::move(insert_at, str.begin().core() + off, count); // (index) - (index + count) + traits_type::move(insert_at + count, old_ptr + index, suffix_size); // (index + count) - (old_size - index) + + deallocate(str_, old_capacity + 1); + str_ = new_ptr; + } + else + { + char_type* const insert_at = old_ptr + index; + traits_type::move(insert_at + count, old_ptr + index, suffix_size); + traits_type::move(insert_at, str.begin().core() + off, count); + } + + return (*this); +} + +template +inline basic_string<_CharTy>& basic_string<_CharTy>::append(size_type count, char_type ch) +{ + check_operability(); + + size_type new_size = size_ + count; + size_type new_cap = new_size + 1; + char_type* new_str = allocate(new_cap); + + traits_type::move(new_str, str_, size_); + traits_type::assign(new_str + size_, count, ch); + traits_type::assign(new_str[new_size], value_type()); + + destroy(); + + str_ = new_str; + size_ = new_size; + capacity_ = new_cap; + return (*this); +} + +template +inline basic_string<_CharTy>& basic_string<_CharTy>::append(const char_type* cstr, size_type count) +{ + check_operability(); + + size_type new_size = size_ + count; + size_type new_cap = new_size + 1; + char_type* new_str = allocate(new_cap); + + traits_type::move(new_str, str_, size_); + traits_type::move(new_str + size_, cstr, count); + traits_type::assign(new_str[new_size], value_type()); + + destroy(); + + str_ = new_str; + size_ = new_size; + capacity_ = new_cap; + return (*this); +} + +template +inline basic_string<_CharTy>& basic_string<_CharTy>::append(basic_string const& other, size_type pos, size_type count) +{ + check_operability(); + + if (pos >= other.size()) + return (*this); + + count = other.clamp_suffix_size(pos, count); + + size_type new_size = size_ + count; + size_type new_cap = new_size + 1; + char_type* new_str = allocate(new_cap); + + traits_type::move(new_str, str_, size_); + traits_type::move(new_str + size_, other.begin().core() + pos, count); + traits_type::assign(new_str[new_size], value_type()); + + destroy(); + + str_ = new_str; + size_ = new_size; + capacity_ = new_cap; + return (*this); +} + +template +inline void basic_string<_CharTy>::reserve(const size_type new_cap) +{ + if (new_cap <= capacity_) + return; + + check_operability(); + + char_type* new_str = allocate(new_cap); + traits_type::move(new_str, str_, capacity_); + + destroy(); + + str_ = new_str; + capacity_ = new_cap; +} + +template +inline typename basic_string<_CharTy>::size_type basic_string<_CharTy>::hash() const +{ + static size_type fnv_prime = 16777619U; + size_type fnv_offset_basis = 2166136261U; + + for (size_type index = 0; index < size_; ++index) + { + fnv_offset_basis ^= static_cast(const_str_[index]); + fnv_offset_basis *= fnv_prime; + } + return fnv_offset_basis; +} + +template +inline int basic_string<_CharTy>::compare(const char_type* const str) const +{ + size_type count1 = size(); + size_type count2 = traits_type::length(str); + size_type rlen = std::min(count1, count2); + + int ret = traits_type::compare(const_str_, str, rlen); + if (ret != 0) + return ret; + + if (count1 < count2) + return -1; + + if (count1 > count2) + return 1; + + return 0; +} + +template +inline typename basic_string<_CharTy>::size_type basic_string<_CharTy>::find(const char_type ch, size_type offset) const +{ + if (offset >= size_) + return basic_string<_CharTy>::npos; + + const_iterator citer = traits_type::find(cbegin().core() + offset, size_, ch); + return citer ? (citer - cbegin()) : basic_string<_CharTy>::npos; +} + +template +inline typename basic_string<_CharTy>::size_type basic_string<_CharTy>::find(const char_type* const str, size_type offset, size_type count) const +{ + if (offset >= size_) + return basic_string<_CharTy>::npos; + return __string_details::TraitsFind(const_str_, size_, offset, str, count); +} + +template +inline typename basic_string<_CharTy>::size_type basic_string<_CharTy>::find_first_of(const char_type* const str, size_type offset, size_type count) const +{ + if (offset >= size_) + return basic_string<_CharTy>::npos; + + const_iterator citer = std::find_first_of(cbegin().core() + offset, cend().core(), str, str + count); + return (citer != cend()) ? (citer - cbegin()) : basic_string<_CharTy>::npos; +} + +template +inline typename basic_string<_CharTy>::size_type basic_string<_CharTy>::find_last_of(const char_type ch, size_type pos) const +{ + if (pos == 0 || pos > size_ || pos == npos) + return npos; + + const_reverse_iterator criter = std::find(crbegin(), crend(), ch); + return (criter != crend()) ? (criter.core() - cbegin()) : basic_string<_CharTy>::npos; +} + +template +inline typename basic_string<_CharTy>::size_type basic_string<_CharTy>::find_last_of(const char_type* const str, size_type pos, size_type count) const +{ + if (pos == 0 || pos > size_ || pos == npos) + return npos; + + return __string_details::TraitsFindLastOf(const_str_, size_, pos, str, count); +} + +template +inline basic_string<_CharTy>& basic_string<_CharTy>::replace(size_type pos, size_type count, const char_type* cstr, size_type count2) +{ + check_offset(pos); + check_operability(); + + count = clamp_suffix_size(pos, count); + if (count == count2) + { + traits_type::move(str_ + pos, cstr, count2); return (*this); } - template - inline basic_string<_CharTy>& basic_string<_CharTy>::append(basic_string const& other, size_type pos, size_type count) + char_type* new_ptr = nullptr; + char_type* const old_ptr = str_; + const size_type old_size = size_; + const size_type old_capacity = capacity_; + const size_type suffix_size = old_size - count - pos + 1; + + if (count < count2 && (old_size + count2 - count) > capacity_) { - check_operability(); + const size_type growth = count2 - count; + size_ = old_size + growth; + capacity_ = size_; + new_ptr = allocate(capacity_ + 1); - if (pos >= other.size()) - return (*this); + traits_type::move(new_ptr, old_ptr, pos); + } + else + { + size_ = old_size - (count - count2); + } - count = other.clamp_suffix_size(pos, count); + char_type* const insert_at = (new_ptr ? new_ptr : old_ptr) + pos; + traits_type::move(insert_at, cstr, count2); + traits_type::move(insert_at + count2, old_ptr + count, suffix_size); - size_type new_size = size_ + count; - size_type new_cap = new_size + 1; - char_type* new_str = allocate(new_cap); + if (new_ptr) + { + deallocate(str_, old_capacity + 1); + str_ = new_ptr; + } - traits_type::move(new_str, str_, size_); - traits_type::move(new_str + size_, other.begin().core() + pos, count); - traits_type::assign(new_str[new_size], value_type()); + return (*this); +} - destroy(); +template +inline basic_string<_CharTy>& basic_string<_CharTy>::replace(size_type pos, size_type count, size_type count2, const char_type ch) +{ + check_offset(pos); + check_operability(); - str_ = new_str; - size_ = new_size; - capacity_ = new_cap; + count = clamp_suffix_size(pos, count); + if (count == count2) + { + traits_type::assign(str_ + pos, count2, ch); return (*this); } - template - inline void basic_string<_CharTy>::reserve(const size_type new_cap) + char_type* new_ptr = nullptr; + char_type* const old_ptr = str_; + const size_type old_size = size_; + const size_type old_capacity = capacity_; + const size_type suffix_size = old_size - count - pos + 1; + + if (count < count2 && (old_size + count2 - count) > capacity_) { - if (new_cap <= capacity_) - return; + const size_type growth = count2 - count; + size_ = old_size + growth; + capacity_ = size_; + new_ptr = allocate(capacity_ + 1); - check_operability(); - - char_type* new_str = allocate(new_cap); - traits_type::move(new_str, str_, capacity_); - - destroy(); - - str_ = new_str; - capacity_ = new_cap; + traits_type::move(new_ptr, old_ptr, pos); + } + else + { + size_ = old_size - (count - count2); } - template - inline typename basic_string<_CharTy>::size_type basic_string<_CharTy>::hash() const - { - static size_type fnv_prime = 16777619U; - size_type fnv_offset_basis = 2166136261U; + char_type* const insert_at = (new_ptr ? new_ptr : old_ptr) + pos; + traits_type::assign(insert_at, count2, ch); + traits_type::move(insert_at + count2, old_ptr + count, suffix_size); - for (size_type index = 0; index < size_; ++index) - { - fnv_offset_basis ^= static_cast(const_str_[index]); - fnv_offset_basis *= fnv_prime; - } - return fnv_offset_basis; + if (new_ptr) + { + deallocate(str_, old_capacity + 1); + str_ = new_ptr; } - template - inline int basic_string<_CharTy>::compare(const char_type* const str) const - { - size_type count1 = size(); - size_type count2 = traits_type::length(str); - size_type rlen = std::min(count1, count2); - - int ret = traits_type::compare(const_str_, str, rlen); - if (ret != 0) - return ret; - - if (count1 < count2) - return -1; - - if (count1 > count2) - return 1; + return (*this); +} +template +inline typename basic_string<_CharTy>::size_type basic_string<_CharTy>::copy(char_type* cstr, size_type count, size_type pos) const +{ + if (count == 0 || cstr == const_str_) return 0; - } - template - inline typename basic_string<_CharTy>::size_type basic_string<_CharTy>::find(const char_type ch, size_type offset) const + check_offset(pos); + + count = clamp_suffix_size(pos, count); + traits_type::move(cstr, cbegin().core() + pos, count); + return count; +} + +template +inline typename basic_string<_CharTy>::char_type* basic_string<_CharTy>::allocate(size_type count) +{ + return get_allocator().allocate(count); +} + +template +inline void basic_string<_CharTy>::deallocate(char_type*& ptr, size_type count) +{ + get_allocator().deallocate(ptr, count); + ptr = nullptr; +} + +template +inline void basic_string<_CharTy>::destroy() +{ + if (operable_ && str_) { - if (offset >= size_) - return basic_string<_CharTy>::npos; - - const_iterator citer = traits_type::find(cbegin().core() + offset, size_, ch); - return citer ? (citer - cbegin()) : basic_string<_CharTy>::npos; + deallocate(str_, capacity_ + 1); } - - template - inline typename basic_string<_CharTy>::size_type basic_string<_CharTy>::find(const char_type* const str, size_type offset, size_type count) const + else { - if (offset >= size_) - return basic_string<_CharTy>::npos; - return __string_details::TraitsFind(const_str_, size_, offset, str, count); + const_str_ = nullptr; } + size_ = capacity_ = 0; +} - template - inline typename basic_string<_CharTy>::size_type basic_string<_CharTy>::find_first_of(const char_type* const str, size_type offset, size_type count) const +template +inline void basic_string<_CharTy>::swap(basic_string& rhs) noexcept +{ + std::swap(const_str_, rhs.const_str_); + std::swap(size_, rhs.size_); + std::swap(capacity_, rhs.capacity_); + + // swap const datas + std::swap(*const_cast(&operable_), *const_cast(&rhs.operable_)); +} + +template +inline void basic_string<_CharTy>::discard_const_data() +{ + if (!operable_) { - if (offset >= size_) - return basic_string<_CharTy>::npos; - - const_iterator citer = std::find_first_of(cbegin().core() + offset, cend().core(), str, str + count); - return (citer != cend()) ? (citer - cbegin()) : basic_string<_CharTy>::npos; + // force to enable operability + *const_cast(&operable_) = true; + const_str_ = nullptr; + capacity_ = size_ = 0; } +} - template - inline typename basic_string<_CharTy>::size_type basic_string<_CharTy>::find_last_of(const char_type ch, size_type pos) const +template +inline void basic_string<_CharTy>::check_operability() +{ + if (!operable_) { - if (pos == 0 || pos > size_ || pos == npos) - return npos; - - const_reverse_iterator criter = std::find(crbegin(), crend(), ch); - return (criter != crend()) ? (criter.core() - cbegin()) : basic_string<_CharTy>::npos; + // create a new string, then swap it with self + basic_string(const_str_, false).swap(*this); } +} - template - inline typename basic_string<_CharTy>::size_type basic_string<_CharTy>::find_last_of(const char_type* const str, size_type pos, size_type count) const +// +// details of basic_string<>::parese +// + +template +inline basic_string<_CharTy> basic_string<_CharTy>::parse(int val) { return ::oc::to_basic_string(val); } + +template +inline basic_string<_CharTy> basic_string<_CharTy>::parse(unsigned int val) { return ::oc::to_basic_string(val); } + +template +inline basic_string<_CharTy> basic_string<_CharTy>::parse(long val) { return ::oc::to_basic_string(val); } + +template +inline basic_string<_CharTy> basic_string<_CharTy>::parse(unsigned long val) { return ::oc::to_basic_string(val); } + +template +inline basic_string<_CharTy> basic_string<_CharTy>::parse(long long val) { return ::oc::to_basic_string(val); } + +template +inline basic_string<_CharTy> basic_string<_CharTy>::parse(unsigned long long val) { return ::oc::to_basic_string(val); } + +template +inline basic_string<_CharTy> basic_string<_CharTy>::parse(float val) { return ::oc::to_basic_string(val); } + +template +inline basic_string<_CharTy> basic_string<_CharTy>::parse(double val) { return ::oc::to_basic_string(val); } + +template +inline basic_string<_CharTy> basic_string<_CharTy>::parse(long double val) { return ::oc::to_basic_string(val); } + +// +// details of basic_string::format +// + +template +template +inline basic_string<_CharTy> basic_string<_CharTy>::format(const char_type* fmt, _Args&& ... args) +{ + return ::oc::format_string(fmt, std::forward<_Args>(args)...); +} + +// +// details of operator<<>> +// + +template +inline std::basic_ostream::char_type>& operator<<(std::basic_ostream::char_type>& os, const basic_string<_CharTy>& str) +{ + using ostream = std::basic_ostream::char_type, typename basic_string<_CharTy>::traits_type>; + using size_type = typename basic_string<_CharTy>::size_type; + using traits = typename basic_string<_CharTy>::traits_type; + + const ostream::sentry ok(os); + std::ios_base::iostate state = std::ios_base::goodbit; + + if (!ok) { - if (pos == 0 || pos > size_ || pos == npos) - return npos; - - return __string_details::TraitsFindLastOf(const_str_, size_, pos, str, count); + state |= std::ios_base::badbit; } - - template - inline basic_string<_CharTy>& basic_string<_CharTy>::replace(size_type pos, size_type count, const char_type* cstr, size_type count2) + else { - check_offset(pos); - check_operability(); + const auto str_size = str.size(); + size_type pad = (os.width() <= 0 || static_cast(os.width()) <= str_size) ? 0 : static_cast(os.width()) - str_size; - count = clamp_suffix_size(pos, count); - if (count == count2) + try { - traits_type::move(str_ + pos, cstr, count2); - return (*this); - } - - char_type* new_ptr = nullptr; - char_type* const old_ptr = str_; - const size_type old_size = size_; - const size_type old_capacity = capacity_; - const size_type suffix_size = old_size - count - pos + 1; - - if (count < count2 && (old_size + count2 - count) > capacity_) - { - const size_type growth = count2 - count; - size_ = old_size + growth; - capacity_ = size_; - new_ptr = allocate(capacity_ + 1); - - traits_type::move(new_ptr, old_ptr, pos); - } - else - { - size_ = old_size - (count - count2); - } - - char_type* const insert_at = (new_ptr ? new_ptr : old_ptr) + pos; - traits_type::move(insert_at, cstr, count2); - traits_type::move(insert_at + count2, old_ptr + count, suffix_size); - - if (new_ptr) - { - deallocate(str_, old_capacity + 1); - str_ = new_ptr; - } - - return (*this); - } - - template - inline basic_string<_CharTy>& basic_string<_CharTy>::replace(size_type pos, size_type count, size_type count2, const char_type ch) - { - check_offset(pos); - check_operability(); - - count = clamp_suffix_size(pos, count); - if (count == count2) - { - traits_type::assign(str_ + pos, count2, ch); - return (*this); - } - - char_type* new_ptr = nullptr; - char_type* const old_ptr = str_; - const size_type old_size = size_; - const size_type old_capacity = capacity_; - const size_type suffix_size = old_size - count - pos + 1; - - if (count < count2 && (old_size + count2 - count) > capacity_) - { - const size_type growth = count2 - count; - size_ = old_size + growth; - capacity_ = size_; - new_ptr = allocate(capacity_ + 1); - - traits_type::move(new_ptr, old_ptr, pos); - } - else - { - size_ = old_size - (count - count2); - } - - char_type* const insert_at = (new_ptr ? new_ptr : old_ptr) + pos; - traits_type::assign(insert_at, count2, ch); - traits_type::move(insert_at + count2, old_ptr + count, suffix_size); - - if (new_ptr) - { - deallocate(str_, old_capacity + 1); - str_ = new_ptr; - } - - return (*this); - } - - template - inline typename basic_string<_CharTy>::size_type basic_string<_CharTy>::copy(char_type* cstr, size_type count, size_type pos) const - { - if (count == 0 || cstr == const_str_) - return 0; - - check_offset(pos); - - count = clamp_suffix_size(pos, count); - traits_type::move(cstr, cbegin().core() + pos, count); - return count; - } - - template - inline typename basic_string<_CharTy>::char_type* basic_string<_CharTy>::allocate(size_type count) - { - return get_allocator().allocate(count); - } - - template - inline void basic_string<_CharTy>::deallocate(char_type*& ptr, size_type count) - { - get_allocator().deallocate(ptr, count); - ptr = nullptr; - } - - template - inline void basic_string<_CharTy>::destroy() - { - if (operable_ && str_) - { - deallocate(str_, capacity_ + 1); - } - else - { - const_str_ = nullptr; - } - size_ = capacity_ = 0; - } - - template - inline void basic_string<_CharTy>::swap(basic_string& rhs) noexcept - { - std::swap(const_str_, rhs.const_str_); - std::swap(size_, rhs.size_); - std::swap(capacity_, rhs.capacity_); - - // swap const datas - std::swap(*const_cast(&operable_), *const_cast(&rhs.operable_)); - } - - template - inline void basic_string<_CharTy>::discard_const_data() - { - if (!operable_) - { - // force to enable operability - *const_cast(&operable_) = true; - const_str_ = nullptr; - capacity_ = size_ = 0; - } - } - - template - inline void basic_string<_CharTy>::check_operability() - { - if (!operable_) - { - // create a new string, then swap it with self - basic_string(const_str_, false).swap(*this); - } - } - - // - // details of basic_string<>::parese - // - - template - inline basic_string<_CharTy> basic_string<_CharTy>::parse(int val) { return ::kiwano::common::to_basic_string(val); } - - template - inline basic_string<_CharTy> basic_string<_CharTy>::parse(unsigned int val) { return ::kiwano::common::to_basic_string(val); } - - template - inline basic_string<_CharTy> basic_string<_CharTy>::parse(long val) { return ::kiwano::common::to_basic_string(val); } - - template - inline basic_string<_CharTy> basic_string<_CharTy>::parse(unsigned long val) { return ::kiwano::common::to_basic_string(val); } - - template - inline basic_string<_CharTy> basic_string<_CharTy>::parse(long long val) { return ::kiwano::common::to_basic_string(val); } - - template - inline basic_string<_CharTy> basic_string<_CharTy>::parse(unsigned long long val) { return ::kiwano::common::to_basic_string(val); } - - template - inline basic_string<_CharTy> basic_string<_CharTy>::parse(float val) { return ::kiwano::common::to_basic_string(val); } - - template - inline basic_string<_CharTy> basic_string<_CharTy>::parse(double val) { return ::kiwano::common::to_basic_string(val); } - - template - inline basic_string<_CharTy> basic_string<_CharTy>::parse(long double val) { return ::kiwano::common::to_basic_string(val); } - - // - // details of basic_string::format - // - - template - template - inline basic_string<_CharTy> basic_string<_CharTy>::format(const char_type* fmt, _Args&& ... args) - { - return ::kiwano::common::format_string(fmt, std::forward<_Args>(args)...); - } - - // - // details of operator<<>> - // - - template - inline std::basic_ostream::char_type>& operator<<(std::basic_ostream::char_type>& os, const basic_string<_CharTy>& str) - { - using ostream = std::basic_ostream::char_type, typename basic_string<_CharTy>::traits_type>; - using size_type = typename basic_string<_CharTy>::size_type; - using traits = typename basic_string<_CharTy>::traits_type; - - const ostream::sentry ok(os); - std::ios_base::iostate state = std::ios_base::goodbit; - - if (!ok) - { - state |= std::ios_base::badbit; - } - else - { - const auto str_size = str.size(); - size_type pad = (os.width() <= 0 || static_cast(os.width()) <= str_size) ? 0 : static_cast(os.width()) - str_size; - - try + if ((os.flags() & std::ios_base::adjustfield) != std::ios_base::left) { - if ((os.flags() & std::ios_base::adjustfield) != std::ios_base::left) + for (; 0 < pad; --pad) { - for (; 0 < pad; --pad) + if (traits::eq_int_type(traits::eof(), os.rdbuf()->sputc(os.fill()))) { - if (traits::eq_int_type(traits::eof(), os.rdbuf()->sputc(os.fill()))) - { - state |= std::ios_base::badbit; - break; - } + state |= std::ios_base::badbit; + break; } } + } - if (state == std::ios_base::goodbit - && os.rdbuf()->sputn(str.data(), (std::streamsize)str_size) != (std::streamsize)str_size) + if (state == std::ios_base::goodbit + && os.rdbuf()->sputn(str.data(), (std::streamsize)str_size) != (std::streamsize)str_size) + { + state |= std::ios_base::badbit; + } + else + { + for (; 0 < pad; --pad) { - state |= std::ios_base::badbit; + if (traits::eq_int_type(traits::eof(), os.rdbuf()->sputc(os.fill()))) + { + state |= std::ios_base::badbit; + break; + } + } + } + os.width(0); + } + catch (...) + { + os.setstate(std::ios_base::badbit, true); + } + } + + os.setstate(state); + return (os); +} + +template +inline std::basic_istream::char_type>& operator>>(std::basic_istream::char_type>& is, basic_string<_CharTy>& str) +{ + using ctype = std::ctype::char_type>; + using istream = std::basic_istream::char_type, typename basic_string<_CharTy>::traits_type>; + using size_type = typename basic_string<_CharTy>::size_type; + using traits = typename basic_string<_CharTy>::traits_type; + + bool changed = false; + const istream::sentry ok(is); + std::ios_base::iostate state = std::ios_base::goodbit; + + if (ok) + { + const ctype& ctype_fac = std::use_facet(is.getloc()); + str.erase(); + try + { + size_type size = (0 < is.width() && static_cast(is.width()) < str.max_size()) ? static_cast(is.width()) : str.max_size(); + typename traits::int_type meta = is.rdbuf()->sgetc(); + + for (; 0 < size; --size, meta = is.rdbuf()->snextc()) + { + if (traits::eq_int_type(traits::eof(), meta)) + { + state |= std::ios_base::eofbit; + break; + } + else if (ctype_fac.is(ctype::space, traits::to_char_type(meta))) + { + break; } else { - for (; 0 < pad; --pad) - { - if (traits::eq_int_type(traits::eof(), os.rdbuf()->sputc(os.fill()))) - { - state |= std::ios_base::badbit; - break; - } - } - } - os.width(0); - } - catch (...) - { - os.setstate(std::ios_base::badbit, true); - } - } - - os.setstate(state); - return (os); - } - - template - inline std::basic_istream::char_type>& operator>>(std::basic_istream::char_type>& is, basic_string<_CharTy>& str) - { - using ctype = std::ctype::char_type>; - using istream = std::basic_istream::char_type, typename basic_string<_CharTy>::traits_type>; - using size_type = typename basic_string<_CharTy>::size_type; - using traits = typename basic_string<_CharTy>::traits_type; - - bool changed = false; - const istream::sentry ok(is); - std::ios_base::iostate state = std::ios_base::goodbit; - - if (ok) - { - const ctype& ctype_fac = std::use_facet(is.getloc()); - str.erase(); - try - { - size_type size = (0 < is.width() && static_cast(is.width()) < str.max_size()) ? static_cast(is.width()) : str.max_size(); - typename traits::int_type meta = is.rdbuf()->sgetc(); - - for (; 0 < size; --size, meta = is.rdbuf()->snextc()) - { - if (traits::eq_int_type(traits::eof(), meta)) - { - state |= std::ios_base::eofbit; - break; - } - else if (ctype_fac.is(ctype::space, traits::to_char_type(meta))) - { - break; - } - else - { - str.push_back(traits::to_char_type(meta)); - changed = true; - } + str.push_back(traits::to_char_type(meta)); + changed = true; } } - catch (...) - { - is.setstate(std::ios_base::badbit, true); - } } - - is.width(0); - if (!changed) - state |= std::ios_base::failbit; - is.setstate(state); - return is; - } - - // - // details of to_string functions - // - - namespace __to_string_detail - { - template - struct FloatingToString + catch (...) { - // template - // static basic_string<_CharTy> convert(const _Ty val); - }; - - template - struct IntegralToString - { - // template - // static basic_string<_CharTy> convert(const _Ty val); - }; - } - - template - inline basic_string<_CharTy> to_basic_string(int val) - { - return (__to_string_detail::IntegralToString<_CharTy>::convert(val)); - } - - template - inline basic_string<_CharTy> to_basic_string(unsigned int val) - { - return (__to_string_detail::IntegralToString<_CharTy>::convert(val)); - } - - template - inline basic_string<_CharTy> to_basic_string(long val) - { - return (__to_string_detail::IntegralToString<_CharTy>::convert(val)); - } - - template - inline basic_string<_CharTy> to_basic_string(unsigned long val) - { - return (__to_string_detail::IntegralToString<_CharTy>::convert(val)); - } - - template - inline basic_string<_CharTy> to_basic_string(long long val) - { - return (__to_string_detail::IntegralToString<_CharTy>::convert(val)); - } - - template - inline basic_string<_CharTy> to_basic_string(unsigned long long val) - { - return (__to_string_detail::IntegralToString<_CharTy>::convert(val)); - } - - template - inline basic_string<_CharTy> to_basic_string(float val) - { - return (__to_string_detail::FloatingToString<_CharTy>::convert(val)); - } - - template - inline basic_string<_CharTy> to_basic_string(double val) - { - return (__to_string_detail::FloatingToString<_CharTy>::convert(val)); - } - - template - inline basic_string<_CharTy> to_basic_string(long double val) - { - return (__to_string_detail::FloatingToString<_CharTy>::convert(val)); - } - - template - inline basic_string format_string(const char* const fmt, _Args&& ... args) - { - using string_type = basic_string; - const auto len = static_cast(::_scprintf(fmt, std::forward<_Args>(args)...)); - if (len) - { - string_type str(len, '\0'); - ::sprintf_s(&str[0], len + 1, fmt, std::forward<_Args>(args)...); - return str; + is.setstate(std::ios_base::badbit, true); } - return string_type{}; } - template - inline basic_string format_string(const wchar_t* const fmt, _Args&& ... args) - { - using string_type = basic_string; - const auto len = static_cast(::_scwprintf(fmt, std::forward<_Args>(args)...)); - if (len) - { - string_type str(len, L'\0'); - ::swprintf_s(&str[0], len + 1, fmt, std::forward<_Args>(args)...); - return str; - } - return string_type{}; - } - - namespace __to_string_detail - { - template - _Elem* __IntegerToStringBufferEnd(const _Ty val, _Elem* const buffer_end) - { - using _UTy = std::make_unsigned_t<_Ty>; - - _Elem* next = buffer_end; - auto uval = static_cast<_UTy>(val); - - if (val < 0) - uval = 0 - uval; - - do - { - *--next = static_cast<_Elem>('0' + uval % 10); - uval /= 10; - } while (uval != 0); - - if (val < 0) - * --next = static_cast<_Elem>('-'); - - return next; - } - - template <> - struct IntegralToString - { - template - static basic_string convert(const _Ty val) - { - static_assert(std::is_integral<_Ty>::value, "_Ty must be integral"); - - using _Elem = typename basic_string::traits_type::char_type; - - _Elem buffer[21]; - _Elem* const buffer_end = std::end(buffer); - _Elem* buffer_begin = __IntegerToStringBufferEnd(val, buffer_end); - - return basic_string(buffer_begin, buffer_end); - } - }; - - template <> - struct IntegralToString - { - template - static basic_string convert(const _Ty val) - { - static_assert(std::is_integral<_Ty>::value, "_Ty must be integral"); - - using _Elem = typename basic_string::traits_type::char_type; - - _Elem buffer[21]; - _Elem* const buffer_end = std::end(buffer); - _Elem* buffer_begin = __IntegerToStringBufferEnd(val, buffer_end); - - return basic_string(buffer_begin, buffer_end); - } - }; - - template<> - struct FloatingToString - { - static inline basic_string convert(const float val) - { - return format_string(L"%g", val); - } - - static inline basic_string convert(const double val) - { - return format_string(L"%g", val); - } - - static inline basic_string convert(const long double val) - { - return format_string(L"%Lg", val); - } - }; - - template<> - struct FloatingToString - { - static inline basic_string convert(const float val) - { - return format_string("%g", val); - } - - static inline basic_string convert(const double val) - { - return format_string("%g", val); - } - - static inline basic_string convert(const long double val) - { - return format_string("%Lg", val); - } - }; - } -} + is.width(0); + if (!changed) + state |= std::ios_base::failbit; + is.setstate(state); + return is; } -namespace kiwano +// +// details of to_string functions +// + +namespace __to_string_detail +{ + template + struct FloatingToString + { + // template + // static basic_string<_CharTy> convert(const _Ty val); + }; + + template + struct IntegralToString + { + // template + // static basic_string<_CharTy> convert(const _Ty val); + }; +} + +template +inline basic_string<_CharTy> to_basic_string(int val) +{ + return (__to_string_detail::IntegralToString<_CharTy>::convert(val)); +} + +template +inline basic_string<_CharTy> to_basic_string(unsigned int val) +{ + return (__to_string_detail::IntegralToString<_CharTy>::convert(val)); +} + +template +inline basic_string<_CharTy> to_basic_string(long val) +{ + return (__to_string_detail::IntegralToString<_CharTy>::convert(val)); +} + +template +inline basic_string<_CharTy> to_basic_string(unsigned long val) +{ + return (__to_string_detail::IntegralToString<_CharTy>::convert(val)); +} + +template +inline basic_string<_CharTy> to_basic_string(long long val) +{ + return (__to_string_detail::IntegralToString<_CharTy>::convert(val)); +} + +template +inline basic_string<_CharTy> to_basic_string(unsigned long long val) +{ + return (__to_string_detail::IntegralToString<_CharTy>::convert(val)); +} + +template +inline basic_string<_CharTy> to_basic_string(float val) +{ + return (__to_string_detail::FloatingToString<_CharTy>::convert(val)); +} + +template +inline basic_string<_CharTy> to_basic_string(double val) +{ + return (__to_string_detail::FloatingToString<_CharTy>::convert(val)); +} + +template +inline basic_string<_CharTy> to_basic_string(long double val) +{ + return (__to_string_detail::FloatingToString<_CharTy>::convert(val)); +} + +template +inline basic_string format_string(const char* const fmt, _Args&& ... args) +{ + using string_type = basic_string; + const auto len = static_cast(::_scprintf(fmt, std::forward<_Args>(args)...)); + if (len) + { + string_type str(len, '\0'); + ::sprintf_s(&str[0], len + 1, fmt, std::forward<_Args>(args)...); + return str; + } + return string_type{}; +} + +template +inline basic_string format_string(const wchar_t* const fmt, _Args&& ... args) +{ + using string_type = basic_string; + const auto len = static_cast(::_scwprintf(fmt, std::forward<_Args>(args)...)); + if (len) + { + string_type str(len, L'\0'); + ::swprintf_s(&str[0], len + 1, fmt, std::forward<_Args>(args)...); + return str; + } + return string_type{}; +} + +namespace __to_string_detail +{ + template + _Elem* __IntegerToStringBufferEnd(const _Ty val, _Elem* const buffer_end) + { + using _UTy = std::make_unsigned_t<_Ty>; + + _Elem* next = buffer_end; + auto uval = static_cast<_UTy>(val); + + if (val < 0) + uval = 0 - uval; + + do + { + *--next = static_cast<_Elem>('0' + uval % 10); + uval /= 10; + } while (uval != 0); + + if (val < 0) + * --next = static_cast<_Elem>('-'); + + return next; + } + + template <> + struct IntegralToString + { + template + static basic_string convert(const _Ty val) + { + static_assert(std::is_integral<_Ty>::value, "_Ty must be integral"); + + using _Elem = typename basic_string::traits_type::char_type; + + _Elem buffer[21]; + _Elem* const buffer_end = std::end(buffer); + _Elem* buffer_begin = __IntegerToStringBufferEnd(val, buffer_end); + + return basic_string(buffer_begin, buffer_end); + } + }; + + template <> + struct IntegralToString + { + template + static basic_string convert(const _Ty val) + { + static_assert(std::is_integral<_Ty>::value, "_Ty must be integral"); + + using _Elem = typename basic_string::traits_type::char_type; + + _Elem buffer[21]; + _Elem* const buffer_end = std::end(buffer); + _Elem* buffer_begin = __IntegerToStringBufferEnd(val, buffer_end); + + return basic_string(buffer_begin, buffer_end); + } + }; + + template<> + struct FloatingToString + { + static inline basic_string convert(const float val) + { + return format_string(L"%g", val); + } + + static inline basic_string convert(const double val) + { + return format_string(L"%g", val); + } + + static inline basic_string convert(const long double val) + { + return format_string(L"%Lg", val); + } + }; + + template<> + struct FloatingToString + { + static inline basic_string convert(const float val) + { + return format_string("%g", val); + } + + static inline basic_string convert(const double val) + { + return format_string("%g", val); + } + + static inline basic_string convert(const long double val) + { + return format_string("%Lg", val); + } + }; +} + +} + +namespace oc { template @@ -1527,8 +1504,8 @@ class string_convert enum : size_t { BUFFER_INCREASE = 8, BUFFER_MAX = 16 }; public: - using byte_string = ::kiwano::common::basic_string; - using wide_string = ::kiwano::common::basic_string<_Elem>; + using byte_string = ::oc::basic_string; + using wide_string = ::oc::basic_string<_Elem>; using codecvt_type = _Codecvt; using state_type = typename codecvt_type::state_type; using int_type = typename wide_string::traits_type::int_type; @@ -1605,7 +1582,8 @@ public: case codecvt_type::noconv: { // no conversion, just copy code values - for (; first != last; ++first) { + for (; first != last; ++first) + { wstr.push_back(static_cast<_Elem>(*first)); } break; @@ -1693,7 +1671,7 @@ private: const codecvt_type* cvt_; std::locale loc_; state_type state_; - size_t conv_num_; + size_t conv_num_; }; class chs_codecvt @@ -1702,63 +1680,62 @@ class chs_codecvt public: chs_codecvt() : codecvt_byname("chs") {} - static inline ::kiwano::common::wstring string_to_wide(::kiwano::common::string const& str) + static inline ::oc::wstring string_to_wide(::oc::string const& str) { string_convert conv; return conv.from_bytes(str); } - static inline ::kiwano::common::string wide_to_string(::kiwano::common::wstring const& str) + static inline ::oc::string wide_to_string(::oc::wstring const& str) { string_convert conv; return conv.to_bytes(str); } }; -inline ::kiwano::common::wstring string_to_wide(::kiwano::common::string const& str) +inline ::oc::wstring string_to_wide(::oc::string const& str) { - return kiwano::chs_codecvt::string_to_wide(str); + return oc::chs_codecvt::string_to_wide(str); } -inline ::kiwano::common::string wide_to_string(::kiwano::common::wstring const& str) +inline ::oc::string wide_to_string(::oc::wstring const& str) { - return kiwano::chs_codecvt::wide_to_string(str); + return oc::chs_codecvt::wide_to_string(str); } -} +} // namespace oc namespace std { - template<> - struct hash<::kiwano::common::string> - { - inline size_t operator()(const ::kiwano::common::string& key) const - { - return key.hash(); - } - }; - template<> - struct hash<::kiwano::common::wstring> - { - inline size_t operator()(const ::kiwano::common::wstring& key) const - { - return key.hash(); - } - }; -} - -namespace std +template<> +struct hash<::oc::string> { - template<> - inline void swap<::kiwano::common::string>(::kiwano::common::string& lhs, ::kiwano::common::string& rhs) noexcept + inline size_t operator()(const ::oc::string& key) const { - lhs.swap(rhs); + return key.hash(); } +}; - template<> - inline void swap<::kiwano::common::wstring>(::kiwano::common::wstring& lhs, ::kiwano::common::wstring& rhs) noexcept +template<> +struct hash<::oc::wstring> +{ + inline size_t operator()(const ::oc::wstring& key) const { - lhs.swap(rhs); + return key.hash(); } +}; + +template<> +inline void swap<::oc::string>(::oc::string& lhs, ::oc::string& rhs) noexcept +{ + lhs.swap(rhs); +} + +template<> +inline void swap<::oc::wstring>(::oc::wstring& lhs, ::oc::wstring& rhs) noexcept +{ + lhs.swap(rhs); +} + } diff --git a/src/kiwano/common/vector.hpp b/src/3rd-party/OuterC/oc/vector.h similarity index 53% rename from src/kiwano/common/vector.hpp rename to src/3rd-party/OuterC/oc/vector.h index dc8f9e0d..7f69080e 100644 --- a/src/kiwano/common/vector.hpp +++ b/src/3rd-party/OuterC/oc/vector.h @@ -1,52 +1,18 @@ -// Copyright (c) 2016-2018 Kiwano - Nomango -// -// 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. +// Copyright (c) 2019-2020 OuterC - Nomango #pragma once #include -#include -#include +#include +#include "vector/details.h" -namespace kiwano +namespace oc { -namespace common -{ - - -// -// vector_memory_manager<> with memory operations -// -namespace __vector_details -{ - template::value> - struct vector_memory_manager; -} - // // vector<> // Lightweight std::vector<>-like class // -template< - typename _Ty, - typename _Alloc = std::allocator<_Ty>, - typename _Manager = __vector_details::vector_memory_manager<_Ty, _Alloc>> +template > class vector { public: @@ -59,7 +25,7 @@ public: using reverse_iterator = std::reverse_iterator; using const_reverse_iterator = std::reverse_iterator; using allocator_type = typename _Alloc; - using manager = typename _Manager; + using manager = typename __vector_details::vector_memory_manager<_Ty, _Alloc>; using initializer_list = std::initializer_list; public: @@ -74,11 +40,11 @@ public: template inline vector(_Iter first, _Iter last) : vector() { assign(first, last); } - inline vector& operator=(const vector& src) { if (&src != this) { resize(src.size_); manager::copy_data(begin(), src.cbegin(), size_); } return (*this); } + inline vector& operator=(const vector& src) { if (&src != this) { resize(src.size_); manager::copy_n(begin(), src.cbegin(), size_); } return (*this); } inline vector& operator=(vector&& src) noexcept { swap(src); return *this; } inline vector& operator=(initializer_list list) { if (list.size()) { assign(list.begin(), list.end()); } else clear(); return (*this); } - inline vector& assign(size_type count, const _Ty& val) { if (count > 0) { resize(count); manager::copy_data(begin(), count, val); } else clear(); return (*this); } + inline vector& assign(size_type count, const _Ty& val) { if (count > 0) { resize(count); manager::fill_n(begin(), count, val); } else clear(); return (*this); } inline vector& assign(const vector& src) { return operator=(src); } inline vector& assign(initializer_list list) { return operator=(list); } @@ -140,8 +106,8 @@ protected: _Ty* data_; }; -template -void vector<_Ty, _Alloc, _Manager>::resize(size_type new_size, const _Ty& val) +template +void vector<_Ty, _Alloc>::resize(size_type new_size, const _Ty& val) { if (new_size > size_) { @@ -158,8 +124,8 @@ void vector<_Ty, _Alloc, _Manager>::resize(size_type new_size, const _Ty& val) size_ = new_size; } -template -void vector<_Ty, _Alloc, _Manager>::reserve(size_type new_capacity) +template +void vector<_Ty, _Alloc>::reserve(size_type new_capacity) { if (new_capacity <= capacity_) return; @@ -167,8 +133,7 @@ void vector<_Ty, _Alloc, _Manager>::reserve(size_type new_capacity) auto new_data = manager::allocate(new_capacity); if (data_) { - manager::construct(new_data, size_/* only construct needed size */); - manager::copy_data(new_data, data_, size_); + manager::construct_n(new_data, data_, size_/* only construct needed size */); /* destroy old memory, but not resize */ destroy(); } @@ -176,9 +141,9 @@ void vector<_Ty, _Alloc, _Manager>::reserve(size_type new_capacity) capacity_ = new_capacity; } -template -typename vector<_Ty, _Alloc, _Manager>::iterator - vector<_Ty, _Alloc, _Manager>::erase(const_iterator first, const_iterator last) +template +typename vector<_Ty, _Alloc>::iterator + vector<_Ty, _Alloc>::erase(const_iterator first, const_iterator last) { const auto off = first - begin(); const auto count = last - first; @@ -187,15 +152,15 @@ typename vector<_Ty, _Alloc, _Manager>::iterator { check_offset(off); - manager::move_data(begin() + off, begin() + off + count, size_ - off - count); + manager::move(begin() + off, begin() + off + count, size_ - off - count); resize(size_ - count); // do destruction } return begin() + off; } -template -typename vector<_Ty, _Alloc, _Manager>::iterator - vector<_Ty, _Alloc, _Manager>::insert(const_iterator where, const _Ty& v) +template +typename vector<_Ty, _Alloc>::iterator + vector<_Ty, _Alloc>::insert(const_iterator where, const _Ty& v) { const auto off = where - begin(); const auto insert_at = begin() + off; @@ -203,86 +168,9 @@ typename vector<_Ty, _Alloc, _Manager>::iterator check_offset(off); resize(size_ + 1); - manager::move_data(insert_at + 1, insert_at, size_ - off - 1); + manager::move(insert_at + 1, insert_at, size_ - off - 1); data_[off] = v; return begin() + off; } -namespace __vector_details -{ - // - // vector_memory_manager for common type - // - template - struct vector_memory_manager<_Ty, _Alloc, false> - { - using value_type = _Ty; - using size_type = size_t; - using allocator_type = typename _Alloc; - - static void copy_data(value_type* dest, const value_type* src, size_type count) { if (src == dest) return; ::memcpy(dest, src, size_type(count) * sizeof(value_type)); } - static void copy_data(value_type* dest, size_type count, const value_type& val) { ::memset(dest, int(val), size_type(count) * sizeof(value_type)); } - static void move_data(value_type* dest, const value_type* src, size_type count) { if (src == dest) return; ::memmove(dest, src, size_type(count) * sizeof(value_type)); } - - static value_type* allocate(size_type count) { return get_allocator().allocate(count); } - static void deallocate(value_type*& ptr, size_type count) { if (ptr) { get_allocator().deallocate(ptr, count); ptr = nullptr; } } - - static void construct(value_type* ptr, size_type count) { } - static void construct(value_type* ptr, size_type count, const value_type& val) { while (count) { --count; *(ptr + count) = val; } } - static void destroy(value_type* ptr, size_type count) { } - - private: - static allocator_type& get_allocator() - { - static allocator_type allocator_; - return allocator_; - } - }; - - // - // vector_memory_manager for classes - // - template - struct vector_memory_manager<_Ty, _Alloc, true> - { - using value_type = _Ty; - using size_type = size_t; - using allocator_type = typename _Alloc; - - static void copy_data(value_type* dest, const value_type* src, size_type count) { if (src == dest) return; while (count--) (*dest++) = (*src++); } - static void copy_data(value_type* dest, size_type count, const value_type& val) { while (count--) (*dest++) = val; } - static void move_data(value_type* dest, const value_type* src, size_type count) - { - if (src == dest) return; - if (dest > src && dest < src + count) - { - src = src + count - 1; - dest = dest + count - 1; - while (count--) - (*dest--) = (*src--); - } - else - { - while (count--) - (*dest++) = (*src++); - } - } - - static value_type* allocate(size_type count) { return get_allocator().allocate(count); } - static void deallocate(value_type*& ptr, size_type count) { if (ptr) { get_allocator().deallocate(ptr, count); ptr = nullptr; } } - - static void construct(value_type* ptr, size_type count) { construct(ptr, count, value_type()); } - static void construct(value_type* ptr, size_type count, const value_type& val) { while (count) get_allocator().construct(ptr + (--count), val); } - static void destroy(value_type* ptr, size_type count) { while (count) get_allocator().destroy(ptr + (--count)); } - - private: - static allocator_type& get_allocator() - { - static allocator_type allocator_; - return allocator_; - } - }; -} - -} // namespace common -} // namespace kiwano +} // namespace oc diff --git a/src/3rd-party/OuterC/oc/vector/details.h b/src/3rd-party/OuterC/oc/vector/details.h new file mode 100644 index 00000000..7acf836e --- /dev/null +++ b/src/3rd-party/OuterC/oc/vector/details.h @@ -0,0 +1,172 @@ +// Copyright (c) 2019-2020 OuterC - Nomango + +#pragma once +#include +#include +#include +#include + +namespace oc +{ + +namespace __vector_details +{ + +// vector_memory_manager<> with memory operations +template::value> +struct vector_memory_manager; + + +// +// vector_memory_manager for common type +// +template +struct vector_memory_manager<_Ty, _Alloc, true> +{ + using value_type = _Ty; + using size_type = size_t; + using allocator_type = typename _Alloc; + + static void fill_n(value_type* const dest, ptrdiff_t count, const value_type& val) + { + for (ptrdiff_t i = 0; i < count; ++i) + std::memcpy(std::addressof(dest[i]), std::addressof(val), sizeof(value_type)); + } + + static void copy_n(value_type* const dest, const value_type* src, ptrdiff_t count) + { + if (src == dest) + return; + std::memcpy(dest, src, count * sizeof(value_type)); + } + + static void move(value_type* const dest, const value_type* src, ptrdiff_t count) + { + if (src == dest) + return; + std::memmove(dest, src, count * sizeof(value_type)); + } + + static void construct(value_type* const ptr, ptrdiff_t count, const value_type& val) + { + fill_n(ptr, count, val); + } + + static void construct_n(value_type* const ptr, const value_type* src, ptrdiff_t count) + { + copy_n(ptr, src, count); + } + + static void destroy(value_type* const ptr, ptrdiff_t count) + { + } + + static value_type* allocate(ptrdiff_t count) + { + return get_allocator().allocate(count); + } + + static void deallocate(value_type*& ptr, ptrdiff_t count) + { + if (ptr) + { + get_allocator().deallocate(ptr, count); + ptr = nullptr; + } + } + +private: + static inline allocator_type& get_allocator() + { + static allocator_type allocator_; + return allocator_; + } +}; + +// +// vector_memory_manager for classes +// +template +struct vector_memory_manager<_Ty, _Alloc, false> +{ + using value_type = _Ty; + using size_type = size_t; + using allocator_type = typename _Alloc; + + static void fill_n(value_type* const dest, ptrdiff_t count, const value_type& val) + { + // Avoid warning C4996 + // std::fill_n(dest, count, val); + for (ptrdiff_t i = 0; i < count; ++i) + dest[i] = val; + } + + static void copy_n(value_type* const dest, const value_type* src, ptrdiff_t count) + { + if (src == dest) + return; + + // Avoid warning C4996 + // std::copy_n(src, count, dest); + for (ptrdiff_t i = 0; i < count; ++i) + dest[i] = src[i]; + } + + static void move(value_type* const dest, const value_type* src, ptrdiff_t count) + { + if (src == dest) + return; + + if (dest > src && dest < src + count) + { + // Avoid warning C4996 + // std::copy_backward(src, src + count, dest); + for (ptrdiff_t i = 0; i < count; ++i) + dest[count - i - 1] = src[count - i - 1]; + } + else + copy_n(dest, src, count); + } + + static void construct(value_type* const ptr, ptrdiff_t count, const value_type& val) + { + for (ptrdiff_t i = 0; i < count; ++i) + get_allocator().construct(std::addressof(ptr[i]), val); + } + + static void construct_n(value_type* const ptr, const value_type* src, ptrdiff_t count) + { + for (ptrdiff_t i = 0; i < count; ++i) + get_allocator().construct(std::addressof(ptr[i]), src[i]); + } + + static void destroy(value_type* const ptr, ptrdiff_t count) + { + for (ptrdiff_t i = 0; i < count; ++i) + get_allocator().destroy(std::addressof(ptr[i])); + } + + static value_type* allocate(ptrdiff_t count) + { + return get_allocator().allocate(count); + } + + static void deallocate(value_type*& ptr, ptrdiff_t count) + { + if (ptr) + { + get_allocator().deallocate(ptr, count); + ptr = nullptr; + } + } + +private: + static inline allocator_type& get_allocator() + { + static allocator_type allocator_; + return allocator_; + } +}; + +} // namespace __vector_details +} // namespace oc diff --git a/src/3rd-party/StackWalker/StackWalker.cpp b/src/3rd-party/StackWalker/StackWalker.cpp deleted file mode 100644 index decb9d4a..00000000 --- a/src/3rd-party/StackWalker/StackWalker.cpp +++ /dev/null @@ -1,1223 +0,0 @@ -/********************************************************************** - * - * StackWalker.cpp - * - * - * History: - * 2005-07-27 v1 - First public release on http://www.codeproject.com/ - * http://www.codeproject.com/threads/StackWalker.asp - * 2005-07-28 v2 - Changed the params of the constructor and ShowCallstack - * (to simplify the usage) - * 2005-08-01 v3 - Changed to use 'CONTEXT_FULL' instead of CONTEXT_ALL - * (should also be enough) - * - Changed to compile correctly with the PSDK of VC7.0 - * (GetFileVersionInfoSizeA and GetFileVersionInfoA is wrongly defined: - * it uses LPSTR instead of LPCSTR as first paremeter) - * - Added declarations to support VC5/6 without using 'dbghelp.h' - * - Added a 'pUserData' member to the ShowCallstack function and the - * PReadProcessMemoryRoutine declaration (to pass some user-defined data, - * which can be used in the readMemoryFunction-callback) - * 2005-08-02 v4 - OnSymInit now also outputs the OS-Version by default - * - Added example for doing an exception-callstack-walking in main.cpp - * (thanks to owillebo: http://www.codeproject.com/script/profile/whos_who.asp?id=536268) - * 2005-08-05 v5 - Removed most Lint (http://www.gimpel.com/) errors... thanks to Okko Willeboordse! - * - **********************************************************************/ -#include -#include -#include -#pragma comment(lib, "version.lib") // for "VerQueryValue" - -#include "StackWalker.h" - - -// If VC7 and later, then use the shipped 'dbghelp.h'-file -#if _MSC_VER >= 1300 -#pragma warning(push) -#pragma warning(disable : 4091) // ignore warning in -#include -#pragma warning(pop) -#else -// inline the important dbghelp.h-declarations... -typedef enum { - SymNone = 0, - SymCoff, - SymCv, - SymPdb, - SymExport, - SymDeferred, - SymSym, - SymDia, - SymVirtual, - NumSymTypes -} SYM_TYPE; -typedef struct _IMAGEHLP_LINE64 { - DWORD SizeOfStruct; // set to sizeof(IMAGEHLP_LINE64) - PVOID Key; // internal - DWORD LineNumber; // line number in file - PCHAR FileName; // full filename - DWORD64 Address; // first instruction of line -} IMAGEHLP_LINE64, *PIMAGEHLP_LINE64; -typedef struct _IMAGEHLP_MODULE64 { - DWORD SizeOfStruct; // set to sizeof(IMAGEHLP_MODULE64) - DWORD64 BaseOfImage; // base load address of module - DWORD ImageSize; // virtual size of the loaded module - DWORD TimeDateStamp; // date/time stamp from pe header - DWORD CheckSum; // checksum from the pe header - DWORD NumSyms; // number of symbols in the symbol table - SYM_TYPE SymType; // type of symbols loaded - CHAR ModuleName[32]; // module name - CHAR ImageName[256]; // image name - CHAR LoadedImageName[256]; // symbol file name -} IMAGEHLP_MODULE64, *PIMAGEHLP_MODULE64; -typedef struct _IMAGEHLP_SYMBOL64 { - DWORD SizeOfStruct; // set to sizeof(IMAGEHLP_SYMBOL64) - DWORD64 Address; // virtual address including dll base address - DWORD Size; // estimated size of symbol, can be zero - DWORD Flags; // info about the symbols, see the SYMF defines - DWORD MaxNameLength; // maximum size of symbol name in 'Name' - CHAR Name[1]; // symbol name (null terminated string) -} IMAGEHLP_SYMBOL64, *PIMAGEHLP_SYMBOL64; -typedef enum { - AddrMode1616, - AddrMode1632, - AddrModeReal, - AddrModeFlat -} ADDRESS_MODE; -typedef struct _tagADDRESS64 { - DWORD64 Offset; - WORD Segment; - ADDRESS_MODE Mode; -} ADDRESS64, *LPADDRESS64; -typedef struct _KDHELP64 { - DWORD64 Thread; - DWORD ThCallbackStack; - DWORD ThCallbackBStore; - DWORD NextCallback; - DWORD FramePointer; - DWORD64 KiCallUserMode; - DWORD64 KeUserCallbackDispatcher; - DWORD64 SystemRangeStart; - DWORD64 Reserved[8]; -} KDHELP64, *PKDHELP64; -typedef struct _tagSTACKFRAME64 { - ADDRESS64 AddrPC; // program counter - ADDRESS64 AddrReturn; // return address - ADDRESS64 AddrFrame; // frame pointer - ADDRESS64 AddrStack; // stack pointer - ADDRESS64 AddrBStore; // backing store pointer - PVOID FuncTableEntry; // pointer to pdata/fpo or NULL - DWORD64 Params[4]; // possible arguments to the function - BOOL Far; // WOW far call - BOOL Virtual; // is this a virtual frame? - DWORD64 Reserved[3]; - KDHELP64 KdHelp; -} STACKFRAME64, *LPSTACKFRAME64; -typedef -BOOL -(__stdcall *PREAD_PROCESS_MEMORY_ROUTINE64)( - HANDLE hProcess, - DWORD64 qwBaseAddress, - PVOID lpBuffer, - DWORD nSize, - LPDWORD lpNumberOfBytesRead - ); -typedef -PVOID -(__stdcall *PFUNCTION_TABLE_ACCESS_ROUTINE64)( - HANDLE hProcess, - DWORD64 AddrBase - ); -typedef -DWORD64 -(__stdcall *PGET_MODULE_BASE_ROUTINE64)( - HANDLE hProcess, - DWORD64 Address - ); -typedef -DWORD64 -(__stdcall *PTRANSLATE_ADDRESS_ROUTINE64)( - HANDLE hProcess, - HANDLE hThread, - LPADDRESS64 lpaddr - ); -#define SYMOPT_CASE_INSENSITIVE 0x00000001 -#define SYMOPT_UNDNAME 0x00000002 -#define SYMOPT_DEFERRED_LOADS 0x00000004 -#define SYMOPT_NO_CPP 0x00000008 -#define SYMOPT_LOAD_LINES 0x00000010 -#define SYMOPT_OMAP_FIND_NEAREST 0x00000020 -#define SYMOPT_LOAD_ANYTHING 0x00000040 -#define SYMOPT_IGNORE_CVREC 0x00000080 -#define SYMOPT_NO_UNQUALIFIED_LOADS 0x00000100 -#define SYMOPT_FAIL_CRITICAL_ERRORS 0x00000200 -#define SYMOPT_EXACT_SYMBOLS 0x00000400 -#define SYMOPT_ALLOW_ABSOLUTE_SYMBOLS 0x00000800 -#define SYMOPT_IGNORE_NT_SYMPATH 0x00001000 -#define SYMOPT_INCLUDE_32BIT_MODULES 0x00002000 -#define SYMOPT_PUBLICS_ONLY 0x00004000 -#define SYMOPT_NO_PUBLICS 0x00008000 -#define SYMOPT_AUTO_PUBLICS 0x00010000 -#define SYMOPT_NO_IMAGE_SEARCH 0x00020000 -#define SYMOPT_SECURE 0x00040000 -#define SYMOPT_DEBUG 0x80000000 -#define UNDNAME_COMPLETE (0x0000) // Enable full undecoration -#define UNDNAME_NAME_ONLY (0x1000) // Crack only the name for primary declaration; -#endif // _MSC_VER < 1300 - -// Some missing defines (for VC5/6): -#ifndef INVALID_FILE_ATTRIBUTES -#define INVALID_FILE_ATTRIBUTES ((DWORD)-1) -#endif - - -// secure-CRT_functions are only available starting with VC8 -#if _MSC_VER < 1400 -#define strcpy_s strcpy -#define strcat_s(dst, len, src) strcat(dst, src) -#define _snprintf_s _snprintf -#define _tcscat_s _tcscat -#endif - -// Normally it should be enough to use 'CONTEXT_FULL' (better would be 'CONTEXT_ALL') -#define USED_CONTEXT_FLAGS CONTEXT_FULL - - -class StackWalkerInternal -{ -public: - StackWalkerInternal(StackWalker *parent, HANDLE hProcess) - { - m_parent = parent; - m_hDbhHelp = NULL; - pSC = NULL; - m_hProcess = hProcess; - m_szSymPath = NULL; - pSFTA = NULL; - pSGLFA = NULL; - pSGMB = NULL; - pSGMI = NULL; - pSGO = NULL; - pSGSFA = NULL; - pSI = NULL; - pSLM = NULL; - pSSO = NULL; - pSW = NULL; - pUDSN = NULL; - pSGSP = NULL; - } - ~StackWalkerInternal() - { - if (pSC != NULL) - pSC(m_hProcess); // SymCleanup - if (m_hDbhHelp != NULL) - FreeLibrary(m_hDbhHelp); - m_hDbhHelp = NULL; - m_parent = NULL; - if(m_szSymPath != NULL) - free(m_szSymPath); - m_szSymPath = NULL; - } - BOOL Init(LPCSTR szSymPath) - { - if (m_parent == NULL) - return FALSE; - // Dynamically load the Entry-Points for dbghelp.dll: - // First try to load the newsest one from - TCHAR szTemp[4096]; - // But before wqe do this, we first check if the ".local" file exists - if (GetModuleFileName(NULL, szTemp, 4096) > 0) - { - _tcscat_s(szTemp, _T(".local")); - if (GetFileAttributes(szTemp) == INVALID_FILE_ATTRIBUTES) - { - // ".local" file does not exist, so we can try to load the dbghelp.dll from the "Debugging Tools for Windows" - if (GetEnvironmentVariable(_T("ProgramFiles"), szTemp, 4096) > 0) - { - _tcscat_s(szTemp, _T("\\Debugging Tools for Windows\\dbghelp.dll")); - // now check if the file exists: - if (GetFileAttributes(szTemp) != INVALID_FILE_ATTRIBUTES) - { - m_hDbhHelp = LoadLibrary(szTemp); - } - } - // Still not found? Then try to load the 64-Bit version: - if ( (m_hDbhHelp == NULL) && (GetEnvironmentVariable(_T("ProgramFiles"), szTemp, 4096) > 0) ) - { - _tcscat_s(szTemp, _T("\\Debugging Tools for Windows 64-Bit\\dbghelp.dll")); - if (GetFileAttributes(szTemp) != INVALID_FILE_ATTRIBUTES) - { - m_hDbhHelp = LoadLibrary(szTemp); - } - } - } - } - if (m_hDbhHelp == NULL) // if not already loaded, try to load a default-one - m_hDbhHelp = LoadLibrary( _T("dbghelp.dll") ); - if (m_hDbhHelp == NULL) - return FALSE; - pSI = (tSI) GetProcAddress(m_hDbhHelp, "SymInitialize" ); - pSC = (tSC) GetProcAddress(m_hDbhHelp, "SymCleanup" ); - - pSW = (tSW) GetProcAddress(m_hDbhHelp, "StackWalk64" ); - pSGO = (tSGO) GetProcAddress(m_hDbhHelp, "SymGetOptions" ); - pSSO = (tSSO) GetProcAddress(m_hDbhHelp, "SymSetOptions" ); - - pSFTA = (tSFTA) GetProcAddress(m_hDbhHelp, "SymFunctionTableAccess64" ); - pSGLFA = (tSGLFA) GetProcAddress(m_hDbhHelp, "SymGetLineFromAddr64" ); - pSGMB = (tSGMB) GetProcAddress(m_hDbhHelp, "SymGetModuleBase64" ); - pSGMI = (tSGMI) GetProcAddress(m_hDbhHelp, "SymGetModuleInfo64" ); - //pSGMI_V3 = (tSGMI_V3) GetProcAddress(m_hDbhHelp, "SymGetModuleInfo64" ); - pSGSFA = (tSGSFA) GetProcAddress(m_hDbhHelp, "SymGetSymFromAddr64" ); - pUDSN = (tUDSN) GetProcAddress(m_hDbhHelp, "UnDecorateSymbolName" ); - pSLM = (tSLM) GetProcAddress(m_hDbhHelp, "SymLoadModule64" ); - pSGSP =(tSGSP) GetProcAddress(m_hDbhHelp, "SymGetSearchPath" ); - - if ( pSC == NULL || pSFTA == NULL || pSGMB == NULL || pSGMI == NULL || - pSGO == NULL || pSGSFA == NULL || pSI == NULL || pSSO == NULL || - pSW == NULL || pUDSN == NULL || pSLM == NULL ) - { - FreeLibrary(m_hDbhHelp); - m_hDbhHelp = NULL; - pSC = NULL; - return FALSE; - } - - // SymInitialize - if (szSymPath != NULL) - m_szSymPath = _strdup(szSymPath); - if (this->pSI(m_hProcess, m_szSymPath, FALSE) == FALSE) - this->m_parent->OnDbgHelpErr("SymInitialize", GetLastError(), 0); - - DWORD symOptions = this->pSGO(); // SymGetOptions - symOptions |= SYMOPT_LOAD_LINES; - symOptions |= SYMOPT_FAIL_CRITICAL_ERRORS; - //symOptions |= SYMOPT_NO_PROMPTS; - // SymSetOptions - symOptions = this->pSSO(symOptions); - - /*char buf[StackWalker::STACKWALK_MAX_NAMELEN] = {0}; - if (this->pSGSP != NULL) - { - if (this->pSGSP(m_hProcess, buf, StackWalker::STACKWALK_MAX_NAMELEN) == FALSE) - this->m_parent->OnDbgHelpErr("SymGetSearchPath", GetLastError(), 0); - } - char szUserName[1024] = {0}; - DWORD dwSize = 1024; - GetUserNameA(szUserName, &dwSize); - this->m_parent->OnSymInit(buf, symOptions, szUserName);*/ - - return TRUE; - } - - StackWalker *m_parent; - - HMODULE m_hDbhHelp; - HANDLE m_hProcess; - LPSTR m_szSymPath; - -/*typedef struct IMAGEHLP_MODULE64_V3 { - DWORD SizeOfStruct; // set to sizeof(IMAGEHLP_MODULE64) - DWORD64 BaseOfImage; // base load address of module - DWORD ImageSize; // virtual size of the loaded module - DWORD TimeDateStamp; // date/time stamp from pe header - DWORD CheckSum; // checksum from the pe header - DWORD NumSyms; // number of symbols in the symbol table - SYM_TYPE SymType; // type of symbols loaded - CHAR ModuleName[32]; // module name - CHAR ImageName[256]; // image name - // new elements: 07-Jun-2002 - CHAR LoadedImageName[256]; // symbol file name - CHAR LoadedPdbName[256]; // pdb file name - DWORD CVSig; // Signature of the CV record in the debug directories - CHAR CVData[MAX_PATH * 3]; // Contents of the CV record - DWORD PdbSig; // Signature of PDB - GUID PdbSig70; // Signature of PDB (VC 7 and up) - DWORD PdbAge; // DBI age of pdb - BOOL PdbUnmatched; // loaded an unmatched pdb - BOOL DbgUnmatched; // loaded an unmatched dbg - BOOL LineNumbers; // we have line number information - BOOL GlobalSymbols; // we have internal symbol information - BOOL TypeInfo; // we have type information - // new elements: 17-Dec-2003 - BOOL SourceIndexed; // pdb supports source server - BOOL Publics; // contains public symbols -}; -*/ -struct IMAGEHLP_MODULE64_V2 { - DWORD SizeOfStruct; // set to sizeof(IMAGEHLP_MODULE64) - DWORD64 BaseOfImage; // base load address of module - DWORD ImageSize; // virtual size of the loaded module - DWORD TimeDateStamp; // date/time stamp from pe header - DWORD CheckSum; // checksum from the pe header - DWORD NumSyms; // number of symbols in the symbol table - SYM_TYPE SymType; // type of symbols loaded - CHAR ModuleName[32]; // module name - CHAR ImageName[256]; // image name - CHAR LoadedImageName[256]; // symbol file name -}; - - - // SymCleanup() - typedef BOOL (__stdcall *tSC)( IN HANDLE hProcess ); - tSC pSC; - - // SymFunctionTableAccess64() - typedef PVOID (__stdcall *tSFTA)( HANDLE hProcess, DWORD64 AddrBase ); - tSFTA pSFTA; - - // SymGetLineFromAddr64() - typedef BOOL (__stdcall *tSGLFA)( IN HANDLE hProcess, IN DWORD64 dwAddr, - OUT PDWORD pdwDisplacement, OUT PIMAGEHLP_LINE64 Line ); - tSGLFA pSGLFA; - - // SymGetModuleBase64() - typedef DWORD64 (__stdcall *tSGMB)( IN HANDLE hProcess, IN DWORD64 dwAddr ); - tSGMB pSGMB; - - // SymGetModuleInfo64() - typedef BOOL (__stdcall *tSGMI)( IN HANDLE hProcess, IN DWORD64 dwAddr, OUT IMAGEHLP_MODULE64_V2 *ModuleInfo ); - tSGMI pSGMI; - -// // SymGetModuleInfo64() -// typedef BOOL (__stdcall *tSGMI_V3)( IN HANDLE hProcess, IN DWORD64 dwAddr, OUT IMAGEHLP_MODULE64_V3 *ModuleInfo ); -// tSGMI_V3 pSGMI_V3; - - // SymGetOptions() - typedef DWORD (__stdcall *tSGO)( VOID ); - tSGO pSGO; - - // SymGetSymFromAddr64() - typedef BOOL (__stdcall *tSGSFA)( IN HANDLE hProcess, IN DWORD64 dwAddr, - OUT PDWORD64 pdwDisplacement, OUT PIMAGEHLP_SYMBOL64 Symbol ); - tSGSFA pSGSFA; - - // SymInitialize() - typedef BOOL (__stdcall *tSI)( IN HANDLE hProcess, IN PSTR UserSearchPath, IN BOOL fInvadeProcess ); - tSI pSI; - - // SymLoadModule64() - typedef DWORD64 (__stdcall *tSLM)( IN HANDLE hProcess, IN HANDLE hFile, - IN PSTR ImageName, IN PSTR ModuleName, IN DWORD64 BaseOfDll, IN DWORD SizeOfDll ); - tSLM pSLM; - - // SymSetOptions() - typedef DWORD (__stdcall *tSSO)( IN DWORD SymOptions ); - tSSO pSSO; - - // StackWalk64() - typedef BOOL (__stdcall *tSW)( - DWORD MachineType, - HANDLE hProcess, - HANDLE hThread, - LPSTACKFRAME64 StackFrame, - PVOID ContextRecord, - PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemoryRoutine, - PFUNCTION_TABLE_ACCESS_ROUTINE64 FunctionTableAccessRoutine, - PGET_MODULE_BASE_ROUTINE64 GetModuleBaseRoutine, - PTRANSLATE_ADDRESS_ROUTINE64 TranslateAddress ); - tSW pSW; - - // UnDecorateSymbolName() - typedef DWORD (__stdcall WINAPI *tUDSN)( PCSTR DecoratedName, PSTR UnDecoratedName, - DWORD UndecoratedLength, DWORD Flags ); - tUDSN pUDSN; - - typedef BOOL (__stdcall WINAPI *tSGSP)(HANDLE hProcess, PSTR SearchPath, DWORD SearchPathLength); - tSGSP pSGSP; - - -private: - // **************************************** ToolHelp32 ************************ - #define MAX_MODULE_NAME32 255 - #define TH32CS_SNAPMODULE 0x00000008 - #pragma pack( push, 8 ) - typedef struct tagMODULEENTRY32 - { - DWORD dwSize; - DWORD th32ModuleID; // This module - DWORD th32ProcessID; // owning process - DWORD GlblcntUsage; // Global usage count on the module - DWORD ProccntUsage; // Module usage count in th32ProcessID's context - BYTE * modBaseAddr; // Base address of module in th32ProcessID's context - DWORD modBaseSize; // Size in bytes of module starting at modBaseAddr - HMODULE hModule; // The hModule of this module in th32ProcessID's context - char szModule[MAX_MODULE_NAME32 + 1]; - char szExePath[MAX_PATH]; - } MODULEENTRY32; - typedef MODULEENTRY32 * PMODULEENTRY32; - typedef MODULEENTRY32 * LPMODULEENTRY32; - #pragma pack( pop ) - - BOOL GetModuleListTH32(HANDLE hProcess, DWORD pid) - { - // CreateToolhelp32Snapshot() - typedef HANDLE (__stdcall *tCT32S)(DWORD dwFlags, DWORD th32ProcessID); - // Module32First() - typedef BOOL (__stdcall *tM32F)(HANDLE hSnapshot, LPMODULEENTRY32 lpme); - // Module32Next() - typedef BOOL (__stdcall *tM32N)(HANDLE hSnapshot, LPMODULEENTRY32 lpme); - - // try both dlls... - const TCHAR *dllname[] = { _T("kernel32.dll"), _T("tlhelp32.dll") }; - HINSTANCE hToolhelp = NULL; - tCT32S pCT32S = NULL; - tM32F pM32F = NULL; - tM32N pM32N = NULL; - - HANDLE hSnap; - MODULEENTRY32 me; - me.dwSize = sizeof(me); - BOOL keepGoing; - size_t i; - - for (i = 0; i<(sizeof(dllname) / sizeof(dllname[0])); i++ ) - { - hToolhelp = LoadLibrary( dllname[i] ); - if (hToolhelp == NULL) - continue; - pCT32S = (tCT32S) GetProcAddress(hToolhelp, "CreateToolhelp32Snapshot"); - pM32F = (tM32F) GetProcAddress(hToolhelp, "Module32First"); - pM32N = (tM32N) GetProcAddress(hToolhelp, "Module32Next"); - if ( (pCT32S != NULL) && (pM32F != NULL) && (pM32N != NULL) ) - break; // found the functions! - FreeLibrary(hToolhelp); - hToolhelp = NULL; - } - - if (hToolhelp == NULL) - return FALSE; - - hSnap = pCT32S( TH32CS_SNAPMODULE, pid ); - if (hSnap == (HANDLE) -1) - return FALSE; - - keepGoing = !!pM32F( hSnap, &me ); - int cnt = 0; - while (keepGoing) - { - this->LoadModule(hProcess, me.szExePath, me.szModule, (DWORD64) me.modBaseAddr, me.modBaseSize); - cnt++; - keepGoing = !!pM32N( hSnap, &me ); - } - CloseHandle(hSnap); - FreeLibrary(hToolhelp); - if (cnt <= 0) - return FALSE; - return TRUE; - } // GetModuleListTH32 - - // **************************************** PSAPI ************************ - typedef struct _MODULEINFO { - LPVOID lpBaseOfDll; - DWORD SizeOfImage; - LPVOID EntryPoint; - } MODULEINFO, *LPMODULEINFO; - - BOOL GetModuleListPSAPI(HANDLE hProcess) - { - // EnumProcessModules() - typedef BOOL (__stdcall *tEPM)(HANDLE hProcess, HMODULE *lphModule, DWORD cb, LPDWORD lpcbNeeded ); - // GetModuleFileNameEx() - typedef DWORD (__stdcall *tGMFNE)(HANDLE hProcess, HMODULE hModule, LPSTR lpFilename, DWORD nSize ); - // GetModuleBaseName() - typedef DWORD (__stdcall *tGMBN)(HANDLE hProcess, HMODULE hModule, LPSTR lpFilename, DWORD nSize ); - // GetModuleInformation() - typedef BOOL (__stdcall *tGMI)(HANDLE hProcess, HMODULE hModule, LPMODULEINFO pmi, DWORD nSize ); - - HINSTANCE hPsapi; - tEPM pEPM; - tGMFNE pGMFNE; - tGMBN pGMBN; - tGMI pGMI; - - DWORD i; - //ModuleEntry e; - DWORD cbNeeded; - MODULEINFO mi; - HMODULE *hMods = 0; - char *tt = NULL; - char *tt2 = NULL; - const SIZE_T TTBUFLEN = 8096; - int cnt = 0; - - hPsapi = LoadLibrary( _T("psapi.dll") ); - if (hPsapi == NULL) - return FALSE; - - pEPM = (tEPM) GetProcAddress( hPsapi, "EnumProcessModules" ); - pGMFNE = (tGMFNE) GetProcAddress( hPsapi, "GetModuleFileNameExA" ); - pGMBN = (tGMFNE) GetProcAddress( hPsapi, "GetModuleBaseNameA" ); - pGMI = (tGMI) GetProcAddress( hPsapi, "GetModuleInformation" ); - if ( (pEPM == NULL) || (pGMFNE == NULL) || (pGMBN == NULL) || (pGMI == NULL) ) - { - // we couldn´t find all functions - FreeLibrary(hPsapi); - return FALSE; - } - - hMods = (HMODULE*) malloc(sizeof(HMODULE) * (TTBUFLEN / sizeof HMODULE)); - tt = (char*) malloc(sizeof(char) * TTBUFLEN); - tt2 = (char*) malloc(sizeof(char) * TTBUFLEN); - if ( (hMods == NULL) || (tt == NULL) || (tt2 == NULL) ) - goto cleanup; - - if ( ! pEPM( hProcess, hMods, TTBUFLEN, &cbNeeded ) ) - { - //_ftprintf(fLogFile, _T("%lu: EPM failed, GetLastError = %lu\n"), g_dwShowCount, gle ); - goto cleanup; - } - - if ( cbNeeded > TTBUFLEN ) - { - //_ftprintf(fLogFile, _T("%lu: More than %lu module handles. Huh?\n"), g_dwShowCount, lenof( hMods ) ); - goto cleanup; - } - - for ( i = 0; i < cbNeeded / sizeof hMods[0]; i++ ) - { - // base address, size - pGMI(hProcess, hMods[i], &mi, sizeof mi ); - // image file name - tt[0] = 0; - pGMFNE(hProcess, hMods[i], tt, TTBUFLEN ); - // module name - tt2[0] = 0; - pGMBN(hProcess, hMods[i], tt2, TTBUFLEN ); - - DWORD dwRes = this->LoadModule(hProcess, tt, tt2, (DWORD64) mi.lpBaseOfDll, mi.SizeOfImage); - if (dwRes != ERROR_SUCCESS) - this->m_parent->OnDbgHelpErr("LoadModule", dwRes, 0); - cnt++; - } - - cleanup: - if (hPsapi != NULL) FreeLibrary(hPsapi); - if (tt2 != NULL) free(tt2); - if (tt != NULL) free(tt); - if (hMods != NULL) free(hMods); - - return cnt != 0; - } // GetModuleListPSAPI - - DWORD LoadModule(HANDLE hProcess, LPCSTR img, LPCSTR mod, DWORD64 baseAddr, DWORD size) - { - CHAR *szImg = _strdup(img); - CHAR *szMod = _strdup(mod); - DWORD result = ERROR_SUCCESS; - if ( (szImg == NULL) || (szMod == NULL) ) - result = ERROR_NOT_ENOUGH_MEMORY; - else - { - if (pSLM(hProcess, 0, szImg, szMod, baseAddr, size) == 0) - result = GetLastError(); - } - ULONGLONG fileVersion = 0; - if ( (m_parent != NULL) && (szImg != NULL) ) - { - // try to retrive the file-version: - if ( (this->m_parent->m_options & StackWalker::RetrieveFileVersion) != 0) - { - VS_FIXEDFILEINFO *fInfo = NULL; - DWORD dwHandle; - DWORD dwSize = GetFileVersionInfoSizeA(szImg, &dwHandle); - if (dwSize > 0) - { - LPVOID vData = malloc(dwSize); - if (vData != NULL) - { - if (GetFileVersionInfoA(szImg, NULL /* dwHandle reserved */, dwSize, vData) != 0) - { - UINT len; - TCHAR szSubBlock[] = _T("\\"); - if (VerQueryValue(vData, szSubBlock, (LPVOID*) &fInfo, &len) == 0) - fInfo = NULL; - else - { - fileVersion = ((ULONGLONG)fInfo->dwFileVersionLS) + ((ULONGLONG)fInfo->dwFileVersionMS << 32); - } - } - free(vData); - } - } - } - - // Retrive some additional-infos about the module - IMAGEHLP_MODULE64_V2 Module; - const char *szSymType = "-unknown-"; - if (this->GetModuleInfo(hProcess, baseAddr, &Module) != FALSE) - { - switch(Module.SymType) - { - case SymNone: - szSymType = "-nosymbols-"; - break; - case SymCoff: - szSymType = "COFF"; - break; - case SymCv: - szSymType = "CV"; - break; - case SymPdb: - szSymType = "PDB"; - break; - case SymExport: - szSymType = "-exported-"; - break; - case SymDeferred: - szSymType = "-deferred-"; - break; - case SymSym: - szSymType = "SYM"; - break; - case 8: //SymVirtual: - szSymType = "Virtual"; - break; - case 9: // SymDia: - szSymType = "DIA"; - break; - } - } - this->m_parent->OnLoadModule(img, mod, baseAddr, size, result, szSymType, Module.LoadedImageName, fileVersion); - } - if (szImg != NULL) free(szImg); - if (szMod != NULL) free(szMod); - return result; - } -public: - BOOL LoadModules(HANDLE hProcess, DWORD dwProcessId) - { - // first try toolhelp32 - if (GetModuleListTH32(hProcess, dwProcessId)) - return true; - // then try psapi - return GetModuleListPSAPI(hProcess); - } - - - BOOL GetModuleInfo(HANDLE hProcess, DWORD64 baseAddr, IMAGEHLP_MODULE64_V2 *pModuleInfo) - { - if(this->pSGMI == NULL) - { - SetLastError(ERROR_DLL_INIT_FAILED); - return FALSE; - } - // First try to use the larger ModuleInfo-Structure -// memset(pModuleInfo, 0, sizeof(IMAGEHLP_MODULE64_V3)); -// pModuleInfo->SizeOfStruct = sizeof(IMAGEHLP_MODULE64_V3); -// if (this->pSGMI_V3 != NULL) -// { -// if (this->pSGMI_V3(hProcess, baseAddr, pModuleInfo) != FALSE) -// return TRUE; -// // check if the parameter was wrong (size is bad...) -// if (GetLastError() != ERROR_INVALID_PARAMETER) -// return FALSE; -// } - // could not retrive the bigger structure, try with the smaller one (as defined in VC7.1)... - pModuleInfo->SizeOfStruct = sizeof(IMAGEHLP_MODULE64_V2); - void *pData = malloc(4096); // reserve enough memory, so the bug in v6.3.5.1 does not lead to memory-overwrites... - if (pData == NULL) - { - SetLastError(ERROR_NOT_ENOUGH_MEMORY); - return FALSE; - } - memcpy(pData, pModuleInfo, sizeof(IMAGEHLP_MODULE64_V2)); - if (this->pSGMI(hProcess, baseAddr, (IMAGEHLP_MODULE64_V2*) pData) != FALSE) - { - // only copy as much memory as is reserved... - memcpy(pModuleInfo, pData, sizeof(IMAGEHLP_MODULE64_V2)); - pModuleInfo->SizeOfStruct = sizeof(IMAGEHLP_MODULE64_V2); - free(pData); - return TRUE; - } - free(pData); - SetLastError(ERROR_DLL_INIT_FAILED); - return FALSE; - } -}; - -// ############################################################# -StackWalker::StackWalker(DWORD dwProcessId, HANDLE hProcess) -{ - this->m_options = OptionsAll; - this->m_modulesLoaded = FALSE; - this->m_hProcess = hProcess; - this->m_sw = new StackWalkerInternal(this, this->m_hProcess); - this->m_dwProcessId = dwProcessId; - this->m_szSymPath = NULL; -} -StackWalker::StackWalker(int options, LPCSTR szSymPath, DWORD dwProcessId, HANDLE hProcess) -{ - this->m_options = options; - this->m_modulesLoaded = FALSE; - this->m_hProcess = hProcess; - this->m_sw = new StackWalkerInternal(this, this->m_hProcess); - this->m_dwProcessId = dwProcessId; - if (szSymPath != NULL) - { - this->m_szSymPath = _strdup(szSymPath); - this->m_options |= SymBuildPath; - } - else - this->m_szSymPath = NULL; -} - -StackWalker::~StackWalker() -{ - if (m_szSymPath != NULL) - free(m_szSymPath); - m_szSymPath = NULL; - if (this->m_sw != NULL) - delete this->m_sw; - this->m_sw = NULL; -} - -BOOL StackWalker::LoadModules() -{ - if (this->m_sw == NULL) - { - SetLastError(ERROR_DLL_INIT_FAILED); - return FALSE; - } - if (m_modulesLoaded != FALSE) - return TRUE; - - // Build the sym-path: - char *szSymPath = NULL; - if ( (this->m_options & SymBuildPath) != 0) - { - const size_t nSymPathLen = 4096; - szSymPath = (char*) malloc(nSymPathLen); - if (szSymPath == NULL) - { - SetLastError(ERROR_NOT_ENOUGH_MEMORY); - return FALSE; - } - szSymPath[0] = 0; - // Now first add the (optional) provided sympath: - if (this->m_szSymPath != NULL) - { - strcat_s(szSymPath, nSymPathLen, this->m_szSymPath); - strcat_s(szSymPath, nSymPathLen, ";"); - } - - strcat_s(szSymPath, nSymPathLen, ".;"); - - const size_t nTempLen = 1024; - char szTemp[nTempLen]; - // Now add the current directory: - if (GetCurrentDirectoryA(nTempLen, szTemp) > 0) - { - szTemp[nTempLen-1] = 0; - strcat_s(szSymPath, nSymPathLen, szTemp); - strcat_s(szSymPath, nSymPathLen, ";"); - } - - // Now add the path for the main-module: - if (GetModuleFileNameA(NULL, szTemp, nTempLen) > 0) - { - szTemp[nTempLen-1] = 0; - for (char *p = (szTemp+strlen(szTemp)-1); p >= szTemp; --p) - { - // locate the rightmost path separator - if ( (*p == '\\') || (*p == '/') || (*p == ':') ) - { - *p = 0; - break; - } - } // for (search for path separator...) - if (strlen(szTemp) > 0) - { - strcat_s(szSymPath, nSymPathLen, szTemp); - strcat_s(szSymPath, nSymPathLen, ";"); - } - } - if (GetEnvironmentVariableA("_NT_SYMBOL_PATH", szTemp, nTempLen) > 0) - { - szTemp[nTempLen-1] = 0; - strcat_s(szSymPath, nSymPathLen, szTemp); - strcat_s(szSymPath, nSymPathLen, ";"); - } - if (GetEnvironmentVariableA("_NT_ALTERNATE_SYMBOL_PATH", szTemp, nTempLen) > 0) - { - szTemp[nTempLen-1] = 0; - strcat_s(szSymPath, nSymPathLen, szTemp); - strcat_s(szSymPath, nSymPathLen, ";"); - } - if (GetEnvironmentVariableA("SYSTEMROOT", szTemp, nTempLen) > 0) - { - szTemp[nTempLen-1] = 0; - strcat_s(szSymPath, nSymPathLen, szTemp); - strcat_s(szSymPath, nSymPathLen, ";"); - // also add the "system32"-directory: - strcat_s(szTemp, nTempLen, "\\system32"); - strcat_s(szSymPath, nSymPathLen, szTemp); - strcat_s(szSymPath, nSymPathLen, ";"); - } - - if ( (this->m_options & SymBuildPath) != 0) - { - if (GetEnvironmentVariableA("SYSTEMDRIVE", szTemp, nTempLen) > 0) - { - szTemp[nTempLen-1] = 0; - strcat_s(szSymPath, nSymPathLen, "SRV*"); - strcat_s(szSymPath, nSymPathLen, szTemp); - strcat_s(szSymPath, nSymPathLen, "\\websymbols"); - strcat_s(szSymPath, nSymPathLen, "*http://msdl.microsoft.com/download/symbols;"); - } - else - strcat_s(szSymPath, nSymPathLen, "SRV*c:\\websymbols*http://msdl.microsoft.com/download/symbols;"); - } - } - - // First Init the whole stuff... - BOOL bRet = this->m_sw->Init(szSymPath); - if (szSymPath != NULL) free(szSymPath); szSymPath = NULL; - if (bRet == FALSE) - { - this->OnDbgHelpErr("Error while initializing dbghelp.dll", 0, 0); - SetLastError(ERROR_DLL_INIT_FAILED); - return FALSE; - } - - bRet = this->m_sw->LoadModules(this->m_hProcess, this->m_dwProcessId); - if (bRet != FALSE) - m_modulesLoaded = TRUE; - return bRet; -} - - -// The following is used to pass the "userData"-Pointer to the user-provided readMemoryFunction -// This has to be done due to a problem with the "hProcess"-parameter in x64... -// Because this class is in no case multi-threading-enabled (because of the limitations -// of dbghelp.dll) it is "safe" to use a static-variable -static StackWalker::PReadProcessMemoryRoutine s_readMemoryFunction = NULL; -static LPVOID s_readMemoryFunction_UserData = NULL; - -BOOL StackWalker::ShowCallstack(HANDLE hThread, const CONTEXT *context, PReadProcessMemoryRoutine readMemoryFunction, LPVOID pUserData) -{ - CONTEXT c;; - CallstackEntry csEntry; - IMAGEHLP_SYMBOL64 *pSym = NULL; - StackWalkerInternal::IMAGEHLP_MODULE64_V2 Module; - IMAGEHLP_LINE64 Line; - int frameNum; - - if (m_modulesLoaded == FALSE) - this->LoadModules(); // ignore the result... - - if (this->m_sw->m_hDbhHelp == NULL) - { - SetLastError(ERROR_DLL_INIT_FAILED); - return FALSE; - } - - s_readMemoryFunction = readMemoryFunction; - s_readMemoryFunction_UserData = pUserData; - - if (context == NULL) - { - // If no context is provided, capture the context - if (hThread == GetCurrentThread()) - { - GET_CURRENT_CONTEXT(c, USED_CONTEXT_FLAGS); - } - else - { - SuspendThread(hThread); - memset(&c, 0, sizeof(CONTEXT)); - c.ContextFlags = USED_CONTEXT_FLAGS; - if (GetThreadContext(hThread, &c) == FALSE) - { - ResumeThread(hThread); - return FALSE; - } - } - } - else - c = *context; - - // init STACKFRAME for first call - STACKFRAME64 s; // in/out stackframe - memset(&s, 0, sizeof(s)); - DWORD imageType; -#ifdef _M_IX86 - // normally, call ImageNtHeader() and use machine info from PE header - imageType = IMAGE_FILE_MACHINE_I386; - s.AddrPC.Offset = c.Eip; - s.AddrPC.Mode = AddrModeFlat; - s.AddrFrame.Offset = c.Ebp; - s.AddrFrame.Mode = AddrModeFlat; - s.AddrStack.Offset = c.Esp; - s.AddrStack.Mode = AddrModeFlat; -#elif _M_X64 - imageType = IMAGE_FILE_MACHINE_AMD64; - s.AddrPC.Offset = c.Rip; - s.AddrPC.Mode = AddrModeFlat; - s.AddrFrame.Offset = c.Rsp; - s.AddrFrame.Mode = AddrModeFlat; - s.AddrStack.Offset = c.Rsp; - s.AddrStack.Mode = AddrModeFlat; -#elif _M_IA64 - imageType = IMAGE_FILE_MACHINE_IA64; - s.AddrPC.Offset = c.StIIP; - s.AddrPC.Mode = AddrModeFlat; - s.AddrFrame.Offset = c.IntSp; - s.AddrFrame.Mode = AddrModeFlat; - s.AddrBStore.Offset = c.RsBSP; - s.AddrBStore.Mode = AddrModeFlat; - s.AddrStack.Offset = c.IntSp; - s.AddrStack.Mode = AddrModeFlat; -#else -#error "Platform not supported!" -#endif - - pSym = (IMAGEHLP_SYMBOL64 *) malloc(sizeof(IMAGEHLP_SYMBOL64) + STACKWALK_MAX_NAMELEN); - if (!pSym) goto cleanup; // not enough memory... - memset(pSym, 0, sizeof(IMAGEHLP_SYMBOL64) + STACKWALK_MAX_NAMELEN); - pSym->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL64); - pSym->MaxNameLength = STACKWALK_MAX_NAMELEN; - - memset(&Line, 0, sizeof(Line)); - Line.SizeOfStruct = sizeof(Line); - - memset(&Module, 0, sizeof(Module)); - Module.SizeOfStruct = sizeof(Module); - - for (frameNum = 0; ; ++frameNum ) - { - // get next stack frame (StackWalk64(), SymFunctionTableAccess64(), SymGetModuleBase64()) - // if this returns ERROR_INVALID_ADDRESS (487) or ERROR_NOACCESS (998), you can - // assume that either you are done, or that the stack is so hosed that the next - // deeper frame could not be found. - // CONTEXT need not to be suplied if imageTyp is IMAGE_FILE_MACHINE_I386! - if ( ! this->m_sw->pSW(imageType, this->m_hProcess, hThread, &s, &c, myReadProcMem, this->m_sw->pSFTA, this->m_sw->pSGMB, NULL) ) - { - this->OnDbgHelpErr("StackWalk64", GetLastError(), s.AddrPC.Offset); - break; - } - - csEntry.offset = s.AddrPC.Offset; - csEntry.name[0] = 0; - csEntry.undName[0] = 0; - csEntry.undFullName[0] = 0; - csEntry.offsetFromSmybol = 0; - csEntry.offsetFromLine = 0; - csEntry.lineFileName[0] = 0; - csEntry.lineNumber = 0; - csEntry.loadedImageName[0] = 0; - csEntry.moduleName[0] = 0; - if (s.AddrPC.Offset == s.AddrReturn.Offset) - { - this->OnDbgHelpErr("StackWalk64-Endless-Callstack!", 0, s.AddrPC.Offset); - break; - } - if (s.AddrPC.Offset != 0) - { - // we seem to have a valid PC - // show procedure info (SymGetSymFromAddr64()) - if (this->m_sw->pSGSFA(this->m_hProcess, s.AddrPC.Offset, &(csEntry.offsetFromSmybol), pSym) != FALSE) - { - // TODO: Mache dies sicher...! - strcpy_s(csEntry.name, pSym->Name); - // UnDecorateSymbolName() - this->m_sw->pUDSN( pSym->Name, csEntry.undName, STACKWALK_MAX_NAMELEN, UNDNAME_NAME_ONLY ); - this->m_sw->pUDSN( pSym->Name, csEntry.undFullName, STACKWALK_MAX_NAMELEN, UNDNAME_COMPLETE ); - } - else - { - this->OnDbgHelpErr("SymGetSymFromAddr64", GetLastError(), s.AddrPC.Offset); - } - - // show line number info, NT5.0-method (SymGetLineFromAddr64()) - if (this->m_sw->pSGLFA != NULL ) - { // yes, we have SymGetLineFromAddr64() - if (this->m_sw->pSGLFA(this->m_hProcess, s.AddrPC.Offset, &(csEntry.offsetFromLine), &Line) != FALSE) - { - csEntry.lineNumber = Line.LineNumber; - // TODO: Mache dies sicher...! - strcpy_s(csEntry.lineFileName, Line.FileName); - } - else - { - this->OnDbgHelpErr("SymGetLineFromAddr64", GetLastError(), s.AddrPC.Offset); - } - } // yes, we have SymGetLineFromAddr64() - - // show module info (SymGetModuleInfo64()) - if (this->m_sw->GetModuleInfo(this->m_hProcess, s.AddrPC.Offset, &Module ) != FALSE) - { // got module info OK - switch ( Module.SymType ) - { - case SymNone: - csEntry.symTypeString = "-nosymbols-"; - break; - case SymCoff: - csEntry.symTypeString = "COFF"; - break; - case SymCv: - csEntry.symTypeString = "CV"; - break; - case SymPdb: - csEntry.symTypeString = "PDB"; - break; - case SymExport: - csEntry.symTypeString = "-exported-"; - break; - case SymDeferred: - csEntry.symTypeString = "-deferred-"; - break; - case SymSym: - csEntry.symTypeString = "SYM"; - break; -#if API_VERSION_NUMBER >= 9 - case SymDia: - csEntry.symTypeString = "DIA"; - break; -#endif - case 8: //SymVirtual: - csEntry.symTypeString = "Virtual"; - break; - default: - //_snprintf( ty, sizeof ty, "symtype=%ld", (long) Module.SymType ); - csEntry.symTypeString = NULL; - break; - } - - // TODO: Mache dies sicher...! - strcpy_s(csEntry.moduleName, Module.ModuleName); - csEntry.baseOfImage = Module.BaseOfImage; - strcpy_s(csEntry.loadedImageName, Module.LoadedImageName); - } // got module info OK - else - { - this->OnDbgHelpErr("SymGetModuleInfo64", GetLastError(), s.AddrPC.Offset); - } - } // we seem to have a valid PC - - CallstackEntryType et = nextEntry; - if (frameNum == 0) - et = firstEntry; - this->OnCallstackEntry(et, csEntry); - - if (s.AddrReturn.Offset == 0) - { - this->OnCallstackEntry(lastEntry, csEntry); - SetLastError(ERROR_SUCCESS); - break; - } - } // for ( frameNum ) - - cleanup: - if (pSym) free( pSym ); - - if (context == NULL) - ResumeThread(hThread); - - return TRUE; -} - -BOOL __stdcall StackWalker::myReadProcMem( - HANDLE hProcess, - DWORD64 qwBaseAddress, - PVOID lpBuffer, - DWORD nSize, - LPDWORD lpNumberOfBytesRead - ) -{ - if (s_readMemoryFunction == NULL) - { - SIZE_T st; - BOOL bRet = ReadProcessMemory(hProcess, (LPVOID) qwBaseAddress, lpBuffer, nSize, &st); - *lpNumberOfBytesRead = (DWORD) st; - //printf("ReadMemory: hProcess: %p, baseAddr: %p, buffer: %p, size: %d, read: %d, result: %d\n", hProcess, (LPVOID) qwBaseAddress, lpBuffer, nSize, (DWORD) st, (DWORD) bRet); - return bRet; - } - else - { - return s_readMemoryFunction(hProcess, qwBaseAddress, lpBuffer, nSize, lpNumberOfBytesRead, s_readMemoryFunction_UserData); - } -} - -void StackWalker::OnLoadModule(LPCSTR img, LPCSTR mod, DWORD64 baseAddr, DWORD size, DWORD result, LPCSTR symType, LPCSTR pdbName, ULONGLONG fileVersion) -{ - /*CHAR buffer[STACKWALK_MAX_NAMELEN]; - if (fileVersion == 0) - _snprintf_s(buffer, STACKWALK_MAX_NAMELEN, "%s:%s (%p), size: %d (result: %d), SymType: '%s', PDB: '%s'\n", img, mod, (LPVOID) baseAddr, size, result, symType, pdbName); - else - { - DWORD v4 = (DWORD) fileVersion & 0xFFFF; - DWORD v3 = (DWORD) (fileVersion>>16) & 0xFFFF; - DWORD v2 = (DWORD) (fileVersion>>32) & 0xFFFF; - DWORD v1 = (DWORD) (fileVersion>>48) & 0xFFFF; - _snprintf_s(buffer, STACKWALK_MAX_NAMELEN, "%s:%s (%p), size: %d (result: %d), SymType: '%s', PDB: '%s', fileVersion: %d.%d.%d.%d\n", img, mod, (LPVOID) baseAddr, size, result, symType, pdbName, v1, v2, v3, v4); - } - OnOutput(buffer);*/ -} - -void StackWalker::OnCallstackEntry(CallstackEntryType eType, CallstackEntry &entry) -{ - CHAR buffer[STACKWALK_MAX_NAMELEN]; - if ( (eType != lastEntry) && (entry.offset != 0) ) - { - if (entry.name[0] == 0) - strcpy_s(entry.name, "(function-name not available)"); - if (entry.undName[0] != 0) - strcpy_s(entry.name, entry.undName); - if (entry.undFullName[0] != 0) - strcpy_s(entry.name, entry.undFullName); - if (entry.lineFileName[0] == 0) - { - strcpy_s(entry.lineFileName, "(filename not available)"); - if (entry.moduleName[0] == 0) - strcpy_s(entry.moduleName, "(module-name not available)"); - _snprintf_s(buffer, STACKWALK_MAX_NAMELEN, "%p (%s): %s: %s\n", (LPVOID) entry.offset, entry.moduleName, entry.lineFileName, entry.name); - } - else - _snprintf_s(buffer, STACKWALK_MAX_NAMELEN, "%s (%d): %s\n", entry.lineFileName, entry.lineNumber, entry.name); - OnOutput(buffer); - } -} - -void StackWalker::OnDbgHelpErr(LPCSTR szFuncName, DWORD gle, DWORD64 addr) -{ - CHAR buffer[STACKWALK_MAX_NAMELEN]; - _snprintf_s(buffer, STACKWALK_MAX_NAMELEN, "ERROR: %s, GetLastError: %d (Address: %p)\n", szFuncName, gle, (LPVOID) addr); - OnOutput(buffer); -} - -void StackWalker::OnSymInit(LPCSTR szSearchPath, DWORD symOptions, LPCSTR szUserName) -{ - /*CHAR buffer[STACKWALK_MAX_NAMELEN]; - _snprintf_s(buffer, STACKWALK_MAX_NAMELEN, "SymInit: Symbol-SearchPath: '%s', symOptions: %d, UserName: '%s'\n", szSearchPath, symOptions, szUserName); - OnOutput(buffer);*/ -// // Also display the OS-version -//#if _MSC_VER <= 1200 -// OSVERSIONINFOA ver; -// ZeroMemory(&ver, sizeof(OSVERSIONINFOA)); -// ver.dwOSVersionInfoSize = sizeof(ver); -// if (GetVersionExA(&ver) != FALSE) -// { -// _snprintf_s(buffer, STACKWALK_MAX_NAMELEN, "OS-Version: %d.%d.%d (%s)\n", -// ver.dwMajorVersion, ver.dwMinorVersion, ver.dwBuildNumber, -// ver.szCSDVersion); -// OnOutput(buffer); -// } -//#else -// OSVERSIONINFOEXA ver; -// ZeroMemory(&ver, sizeof(OSVERSIONINFOEXA)); -// ver.dwOSVersionInfoSize = sizeof(ver); -// if (GetVersionExA( (OSVERSIONINFOA*) &ver) != FALSE) -// { -// _snprintf_s(buffer, STACKWALK_MAX_NAMELEN, "OS-Version: %d.%d.%d (%s) 0x%x-0x%x\n", -// ver.dwMajorVersion, ver.dwMinorVersion, ver.dwBuildNumber, -// ver.szCSDVersion, ver.wSuiteMask, ver.wProductType); -// OnOutput(buffer); -// } -//#endif -} - -void StackWalker::OnOutput(LPCSTR buffer) -{ - OutputDebugStringA(buffer); -} diff --git a/src/3rd-party/StackWalker/StackWalker.h b/src/3rd-party/StackWalker/StackWalker.h deleted file mode 100644 index 67498217..00000000 --- a/src/3rd-party/StackWalker/StackWalker.h +++ /dev/null @@ -1,187 +0,0 @@ -/********************************************************************** - * - * StackWalker.h - * - * - * History: - * 2005-07-27 v1 - First public release on http://www.codeproject.com/ - * (for additional changes see History in 'StackWalker.cpp'! - * - **********************************************************************/ -// #pragma once is supported starting with _MCS_VER 1000, -// so we need not to check the version (because we only support _MSC_VER >= 1100)! -#pragma once - -// special defines for VC5/6 (if no actual PSDK is installed): -#if _MSC_VER < 1300 -typedef unsigned __int64 DWORD64, *PDWORD64; -#if defined(_WIN64) -typedef unsigned __int64 SIZE_T, *PSIZE_T; -#else -typedef unsigned long SIZE_T, *PSIZE_T; -#endif -#endif // _MSC_VER < 1300 - -class StackWalkerInternal; // forward -class StackWalker -{ -public: - typedef enum StackWalkOptions - { - // No addition info will be retrived - // (only the address is available) - RetrieveNone = 0, - - // Try to get the symbol-name - RetrieveSymbol = 1, - - // Try to get the line for this symbol - RetrieveLine = 2, - - // Try to retrieve the module-infos - RetrieveModuleInfo = 4, - - // Also retrieve the version for the DLL/EXE - RetrieveFileVersion = 8, - - // Contains all the abouve - RetrieveVerbose = 0xF, - - // Generate a "good" symbol-search-path - SymBuildPath = 0x10, - - // Also use the public Microsoft-Symbol-Server - SymUseSymSrv = 0x20, - - // Contains all the abouve "Sym"-options - SymAll = 0x30, - - // Contains all options (default) - OptionsAll = 0x3F - } StackWalkOptions; - - StackWalker( - int options = OptionsAll, // 'int' is by design, to combine the enum-flags - LPCSTR szSymPath = NULL, - DWORD dwProcessId = GetCurrentProcessId(), - HANDLE hProcess = GetCurrentProcess() - ); - StackWalker(DWORD dwProcessId, HANDLE hProcess); - virtual ~StackWalker(); - - typedef BOOL (__stdcall *PReadProcessMemoryRoutine)( - HANDLE hProcess, - DWORD64 qwBaseAddress, - PVOID lpBuffer, - DWORD nSize, - LPDWORD lpNumberOfBytesRead, - LPVOID pUserData // optional data, which was passed in "ShowCallstack" - ); - - BOOL LoadModules(); - - BOOL ShowCallstack( - HANDLE hThread = GetCurrentThread(), - const CONTEXT *context = NULL, - PReadProcessMemoryRoutine readMemoryFunction = NULL, - LPVOID pUserData = NULL // optional to identify some data in the 'readMemoryFunction'-callback - ); - -#if _MSC_VER >= 1300 -// due to some reasons, the "STACKWALK_MAX_NAMELEN" must be declared as "public" -// in older compilers in order to use it... starting with VC7 we can declare it as "protected" -protected: -#endif - enum { STACKWALK_MAX_NAMELEN = 1024 }; // max name length for found symbols - -protected: - // Entry for each Callstack-Entry - typedef struct CallstackEntry - { - DWORD64 offset; // if 0, we have no valid entry - CHAR name[STACKWALK_MAX_NAMELEN]; - CHAR undName[STACKWALK_MAX_NAMELEN]; - CHAR undFullName[STACKWALK_MAX_NAMELEN]; - DWORD64 offsetFromSmybol; - DWORD offsetFromLine; - DWORD lineNumber; - CHAR lineFileName[STACKWALK_MAX_NAMELEN]; - DWORD symType; - LPCSTR symTypeString; - CHAR moduleName[STACKWALK_MAX_NAMELEN]; - DWORD64 baseOfImage; - CHAR loadedImageName[STACKWALK_MAX_NAMELEN]; - } CallstackEntry; - - enum CallstackEntryType {firstEntry, nextEntry, lastEntry}; - - virtual void OnSymInit(LPCSTR szSearchPath, DWORD symOptions, LPCSTR szUserName); - virtual void OnLoadModule(LPCSTR img, LPCSTR mod, DWORD64 baseAddr, DWORD size, DWORD result, LPCSTR symType, LPCSTR pdbName, ULONGLONG fileVersion); - virtual void OnCallstackEntry(CallstackEntryType eType, CallstackEntry &entry); - virtual void OnDbgHelpErr(LPCSTR szFuncName, DWORD gle, DWORD64 addr); - virtual void OnOutput(LPCSTR szText); - - StackWalkerInternal *m_sw; - HANDLE m_hProcess; - DWORD m_dwProcessId; - BOOL m_modulesLoaded; - LPSTR m_szSymPath; - - int m_options; - - static BOOL __stdcall myReadProcMem(HANDLE hProcess, DWORD64 qwBaseAddress, PVOID lpBuffer, DWORD nSize, LPDWORD lpNumberOfBytesRead); - - friend StackWalkerInternal; -}; - - -// The "ugly" assembler-implementation is needed for systems before XP -// If you have a new PSDK and you only compile for XP and later, then you can use -// the "RtlCaptureContext" -// Currently there is no define which determines the PSDK-Version... -// So we just use the compiler-version (and assumes that the PSDK is -// the one which was installed by the VS-IDE) - -// INFO: If you want, you can use the RtlCaptureContext if you only target XP and later... -// But I currently use it in x64/IA64 environments... -//#if defined(_M_IX86) && (_WIN32_WINNT <= 0x0500) && (_MSC_VER < 1400) - -#if defined(_M_IX86) -#ifdef CURRENT_THREAD_VIA_EXCEPTION -// TODO: The following is not a "good" implementation, -// because the callstack is only valid in the "__except" block... -#define GET_CURRENT_CONTEXT(c, contextFlags) \ - do { \ - memset(&c, 0, sizeof(CONTEXT)); \ - EXCEPTION_POINTERS *pExp = NULL; \ - __try { \ - throw 0; \ - } __except( ( (pExp = GetExceptionInformation()) ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_EXECUTE_HANDLER)) {} \ - if (pExp != NULL) \ - memcpy(&c, pExp->ContextRecord, sizeof(CONTEXT)); \ - c.ContextFlags = contextFlags; \ - } while(0); -#else -// The following should be enough for walking the callstack... -#define GET_CURRENT_CONTEXT(c, contextFlags) \ - do { \ - memset(&c, 0, sizeof(CONTEXT)); \ - c.ContextFlags = contextFlags; \ - __asm call x \ - __asm x: pop eax \ - __asm mov c.Eip, eax \ - __asm mov c.Ebp, ebp \ - __asm mov c.Esp, esp \ - } while(0); -#endif - -#else - -// The following is defined for x86 (XP and higher), x64 and IA64: -#define GET_CURRENT_CONTEXT(c, contextFlags) \ - do { \ - memset(&c, 0, sizeof(CONTEXT)); \ - c.ContextFlags = contextFlags; \ - RtlCaptureContext(&c); \ -} while(0); -#endif diff --git a/src/kiwano-audio/AudioEngine.cpp b/src/kiwano-audio/AudioEngine.cpp index 194b180d..d060e31f 100644 --- a/src/kiwano-audio/AudioEngine.cpp +++ b/src/kiwano-audio/AudioEngine.cpp @@ -18,8 +18,9 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. -#include -#include +#include // win32::ThrowIfFailed +#include +#include #include namespace kiwano @@ -38,13 +39,13 @@ namespace kiwano void AudioEngine::SetupComponent() { - // KGE_LOG(L"Creating audio resources"); + KGE_SYS_LOG(L"Creating audio resources"); - HRESULT hr = modules::MediaFoundation::Get().MFStartup(MF_VERSION, MFSTARTUP_FULL); + HRESULT hr = dlls::MediaFoundation::Get().MFStartup(MF_VERSION, MFSTARTUP_FULL); if (SUCCEEDED(hr)) { - hr = modules::XAudio2::Get().XAudio2Create(&x_audio2_, 0, XAUDIO2_DEFAULT_PROCESSOR); + hr = dlls::XAudio2::Get().XAudio2Create(&x_audio2_, 0, XAUDIO2_DEFAULT_PROCESSOR); } if (SUCCEEDED(hr)) @@ -52,12 +53,12 @@ namespace kiwano hr = x_audio2_->CreateMasteringVoice(&mastering_voice_); } - ThrowIfFailed(hr); + win32::ThrowIfFailed(hr); } void AudioEngine::DestroyComponent() { - // KGE_LOG(L"Destroying audio resources"); + KGE_SYS_LOG(L"Destroying audio resources"); if (mastering_voice_) { @@ -71,39 +72,54 @@ namespace kiwano x_audio2_ = nullptr; } - modules::MediaFoundation::Get().MFShutdown(); + dlls::MediaFoundation::Get().MFShutdown(); } - HRESULT AudioEngine::CreateVoice(IXAudio2SourceVoice** voice, const Transcoder::Buffer& buffer) + bool AudioEngine::CreateSound(Sound& sound, const Transcoder::Buffer& buffer) { KGE_ASSERT(x_audio2_ && "AudioEngine hasn't been initialized!"); - if (voice == nullptr) + HRESULT hr = S_OK; + + if (buffer.format == nullptr) + hr = E_INVALIDARG; + + if (SUCCEEDED(hr)) { - return E_INVALIDARG; + IXAudio2SourceVoice* voice = nullptr; + hr = x_audio2_->CreateSourceVoice(&voice, buffer.format, 0, XAUDIO2_DEFAULT_FREQ_RATIO); + + if (SUCCEEDED(hr)) + { + IXAudio2SourceVoice* old = sound.GetXAudio2Voice(); + if (old) + { + old->DestroyVoice(); + old = nullptr; + } + + sound.SetXAudio2Voice(voice); + } } - if (*voice) - { - (*voice)->DestroyVoice(); - (*voice) = nullptr; - } - - return x_audio2_->CreateSourceVoice(voice, buffer.format, 0, XAUDIO2_DEFAULT_FREQ_RATIO); + win32::WarnIfFailed(hr); + return SUCCEEDED(hr); } void AudioEngine::Open() { KGE_ASSERT(x_audio2_ && "AudioEngine hasn't been initialized!"); - x_audio2_->StartEngine(); + if (x_audio2_) + x_audio2_->StartEngine(); } void AudioEngine::Close() { KGE_ASSERT(x_audio2_ && "AudioEngine hasn't been initialized!"); - x_audio2_->StopEngine(); + if (x_audio2_) + x_audio2_->StopEngine(); } } } diff --git a/src/kiwano-audio/AudioEngine.h b/src/kiwano-audio/AudioEngine.h index 11187a2a..4321ac3a 100644 --- a/src/kiwano-audio/AudioEngine.h +++ b/src/kiwano-audio/AudioEngine.h @@ -19,47 +19,64 @@ // THE SOFTWARE. #pragma once -#include +#include #include -#include #include +#include #include namespace kiwano { namespace audio { + /** + * \~chinese + * \defgroup Audio ÒôƵÒýÇæ + */ + + /** + * \addtogroup Audio + * @{ + */ + + /** + * \~chinese + * @brief ÒôƵÒýÇæ + */ class KGE_API AudioEngine : public Singleton , public ComponentBase { - KGE_DECLARE_SINGLETON(AudioEngine); + friend Singleton; public: - // ¿ªÆôÉ豸 + /// \~chinese + /// @brief ¿ªÆôÒôƵÉ豸 void Open(); - // ¹Ø±ÕÉ豸 + /// \~chinese + /// @brief ¹Ø±ÕÒôƵÉ豸 void Close(); - HRESULT CreateVoice( - IXAudio2SourceVoice** voice, - const Transcoder::Buffer& buffer - ); + /// \~chinese + /// @brief ´Ó½âÂëÆ÷Êý¾Ý»º³åÖд´½¨ÒôƵ¶ÔÏó + bool CreateSound(Sound& sound, const Transcoder::Buffer& buffer); public: void SetupComponent() override; void DestroyComponent() override; - protected: + private: AudioEngine(); ~AudioEngine(); - protected: + private: IXAudio2* x_audio2_; IXAudio2MasteringVoice* mastering_voice_; }; + + /** @} */ } } diff --git a/src/kiwano-audio/Sound.cpp b/src/kiwano-audio/Sound.cpp index 622391fb..be9bcdc2 100644 --- a/src/kiwano-audio/Sound.cpp +++ b/src/kiwano-audio/Sound.cpp @@ -35,18 +35,6 @@ namespace kiwano { } - Sound::Sound(String const& file_path) - : Sound() - { - Load(file_path); - } - - Sound::Sound(Resource const& res) - : Sound() - { - Load(res); - } - Sound::~Sound() { Close(); @@ -54,9 +42,9 @@ namespace kiwano bool Sound::Load(String const& file_path) { - if (!FileSystem::GetInstance()->IsFileExists(file_path)) + if (!FileSystem::instance().IsFileExists(file_path)) { - KGE_WARNING_LOG(L"Media file '%s' not found", file_path.c_str()); + KGE_WARN(L"Media file '%s' not found", file_path.c_str()); return false; } @@ -65,22 +53,18 @@ namespace kiwano Close(); } - String full_path = FileSystem::GetInstance()->GetFullPathForFile(file_path); + String full_path = FileSystem::instance().GetFullPathForFile(file_path); HRESULT hr = transcoder_.LoadMediaFile(full_path); - if (FAILED(hr)) { - KGE_ERROR_LOG(L"Load media file failed with HRESULT of %08X", hr); + KGE_ERROR(L"Load media file failed with HRESULT of %08X", hr); return false; } - hr = AudioEngine::GetInstance()->CreateVoice(&voice_, transcoder_.GetBuffer()); - if (FAILED(hr)) + if (!AudioEngine::instance().CreateSound(*this, transcoder_.GetBuffer())) { Close(); - - KGE_ERROR_LOG(L"Create source voice failed with HRESULT of %08X", hr); return false; } @@ -96,19 +80,15 @@ namespace kiwano } HRESULT hr = transcoder_.LoadMediaResource(res); - if (FAILED(hr)) { - KGE_ERROR_LOG(L"Load media resource failed with HRESULT of %08X", hr); + KGE_ERROR(L"Load media resource failed with HRESULT of %08X", hr); return false; } - hr = AudioEngine::GetInstance()->CreateVoice(&voice_, transcoder_.GetBuffer()); - if (FAILED(hr)) + if (!AudioEngine::instance().CreateSound(*this, transcoder_.GetBuffer())) { Close(); - - KGE_ERROR_LOG(L"Create source voice failed with HRESULT of %08X", hr); return false; } @@ -116,11 +96,16 @@ namespace kiwano return true; } + bool Sound::IsValid() const + { + return voice_ != nullptr; + } + void Sound::Play(int loop_count) { if (!opened_) { - KGE_ERROR_LOG(L"Sound must be opened first!"); + KGE_ERROR(L"Sound must be opened first!"); return; } @@ -151,7 +136,7 @@ namespace kiwano if (FAILED(hr)) { - KGE_ERROR_LOG(L"Submitting source buffer failed with HRESULT of %08X", hr); + KGE_ERROR(L"Submitting source buffer failed with HRESULT of %08X", hr); } playing_ = SUCCEEDED(hr); diff --git a/src/kiwano-audio/Sound.h b/src/kiwano-audio/Sound.h index e94171a4..c1a1a1ac 100644 --- a/src/kiwano-audio/Sound.h +++ b/src/kiwano-audio/Sound.h @@ -19,9 +19,9 @@ // THE SOFTWARE. #pragma once -#include #include #include +#include #include #include @@ -29,68 +29,100 @@ namespace kiwano { namespace audio { + class AudioEngine; + KGE_DECLARE_SMART_PTR(Sound); + /** + * \addtogroup Audio + * @{ + */ + + /** + * \~chinese + * @brief ÒôƵ + */ class KGE_API Sound : public ObjectBase { + friend class AudioEngine; + public: Sound(); - Sound( - String const& file_path /* ±¾µØÒôƵÎļþ */ - ); - - Sound( - Resource const& res /* ÒôÀÖ×ÊÔ´ */ - ); - virtual ~Sound(); - // ´ò¿ª±¾µØÒôƵÎļþ - bool Load( - String const& file_path - ); + /// \~chinese + /// @brief ´ò¿ª±¾µØÒôƵÎļþ + /// @param res ±¾µØÒôƵÎļþ·¾¶ + bool Load(String const& file_path); - // ´ò¿ªÒôÀÖ×ÊÔ´ - bool Load( - Resource const& res /* ÒôÀÖ×ÊÔ´ */ - ); + /// \~chinese + /// @brief ´ò¿ªÒôƵ×ÊÔ´ + /// @param res ÒôƵ×ÊÔ´ + bool Load(Resource const& res); - // ²¥·Å - void Play( - int loop_count = 0 /* ²¥·ÅÑ­»·´ÎÊý (-1 Ϊѭ»·²¥·Å) */ - ); + /// \~chinese + /// @brief ÊÇ·ñÓÐЧ + bool IsValid() const; - // ÔÝÍ£ + /// \~chinese + /// @brief ²¥·Å + /// @param loop_count ²¥·ÅÑ­»·´ÎÊý£¬ÉèÖà -1 Ϊѭ»·²¥·Å + void Play(int loop_count = 0); + + /// \~chinese + /// @brief ÔÝÍ£ void Pause(); - // ¼ÌÐø + /// \~chinese + /// @brief ¼ÌÐø void Resume(); - // Í£Ö¹ + /// \~chinese + /// @brief Í£Ö¹ void Stop(); - // ¹Ø±Õ²¢»ØÊÕ×ÊÔ´ + /// \~chinese + /// @brief ¹Ø±Õ²¢Ïú»Ù×ÊÔ´ void Close(); - // ÊÇ·ñÕýÔÚ²¥·Å + /// \~chinese + /// @brief ÊÇ·ñÕýÔÚ²¥·Å bool IsPlaying() const; - // »ñÈ¡ÒôÁ¿ + /// \~chinese + /// @brief »ñÈ¡ÒôÁ¿ float GetVolume() const; - // ÉèÖÃÒôÁ¿ - void SetVolume( - float volume /* 1 ΪԭʼÒôÁ¿, ´óÓÚ 1 Ϊ·Å´óÒôÁ¿, 0 Ϊ×îСÒôÁ¿ */ - ); + /// \~chinese + /// @brief ÉèÖÃÒôÁ¿ + /// @param volume ÒôÁ¿´óС£¬1.0 ΪԭʼÒôÁ¿, ´óÓÚ 1 Ϊ·Å´óÒôÁ¿, 0 Ϊ×îСÒôÁ¿ + void SetVolume(float volume); - protected: - bool opened_; - bool playing_; - Transcoder transcoder_; + private: + IXAudio2SourceVoice* GetXAudio2Voice() const; + void SetXAudio2Voice(IXAudio2SourceVoice* voice); + + private: + bool opened_; + bool playing_; + Transcoder transcoder_; IXAudio2SourceVoice* voice_; }; + + /** @} */ + + + inline IXAudio2SourceVoice* Sound::GetXAudio2Voice() const + { + return voice_; + } + + inline void Sound::SetXAudio2Voice(IXAudio2SourceVoice* voice) + { + voice_ = voice; + } } } diff --git a/src/kiwano-audio/SoundPlayer.cpp b/src/kiwano-audio/SoundPlayer.cpp index 1d81484f..5146b885 100644 --- a/src/kiwano-audio/SoundPlayer.cpp +++ b/src/kiwano-audio/SoundPlayer.cpp @@ -118,7 +118,7 @@ namespace kiwano void SoundPlayer::SetVolume(float volume) { volume_ = std::min(std::max(volume, -224.f), 224.f); - for (const auto& pair : sound_cache_) + for (auto& pair : sound_cache_) { pair.second->SetVolume(volume_); } @@ -126,7 +126,7 @@ namespace kiwano void SoundPlayer::PauseAll() { - for (const auto& pair : sound_cache_) + for (auto& pair : sound_cache_) { pair.second->Pause(); } @@ -134,7 +134,7 @@ namespace kiwano void SoundPlayer::ResumeAll() { - for (const auto& pair : sound_cache_) + for (auto& pair : sound_cache_) { pair.second->Resume(); } @@ -142,7 +142,7 @@ namespace kiwano void SoundPlayer::StopAll() { - for (const auto& pair : sound_cache_) + for (auto& pair : sound_cache_) { pair.second->Stop(); } diff --git a/src/kiwano-audio/SoundPlayer.h b/src/kiwano-audio/SoundPlayer.h index 913fe04f..f3bd7809 100644 --- a/src/kiwano-audio/SoundPlayer.h +++ b/src/kiwano-audio/SoundPlayer.h @@ -19,7 +19,6 @@ // THE SOFTWARE. #pragma once -#include #include #include @@ -29,76 +28,93 @@ namespace kiwano { KGE_DECLARE_SMART_PTR(SoundPlayer); - // ÒôÀÖ²¥·ÅÆ÷ + /** + * \addtogroup Audio + * @{ + */ + + /** + * \~chinese + * @brief ÒôƵ²¥·ÅÆ÷ + */ class KGE_API SoundPlayer - : protected ObjectBase + : public ObjectBase { public: SoundPlayer(); ~SoundPlayer(); - // ¼ÓÔØ±¾µØÒôƵÎļþ, ·µ»Ø¸Ã×ÊÔ´µÄ±êʶ·û - size_t Load( - String const& file_path - ); + /// \~chinese + /// @brief ¼ÓÔØ±¾µØÒôƵÎļþ + /// @param file_path ±¾µØÒôƵÎļþ·¾¶ + /// @return ÒôƵ±êʶ·û + size_t Load(String const& file_path); - // ¼ÓÔØÒôÀÖ×ÊÔ´, ·µ»Ø¸Ã×ÊÔ´µÄ±êʶ·û - size_t Load( - Resource const& res /* ÒôÀÖ×ÊÔ´ */ - ); + /// \~chinese + /// @brief ¼ÓÔØÒôƵ×ÊÔ´ + /// @param res ÒôƵ×ÊÔ´ + /// @return ÒôƵ±êʶ·û + size_t Load(Resource const& res); - // ²¥·ÅÒôÀÖ - void Play( - size_t id, /* ±êʶ·û */ - int loop_count = 0 /* ²¥·ÅÑ­»·´ÎÊý (-1 Ϊѭ»·²¥·Å) */ - ); + /// \~chinese + /// @brief ²¥·ÅÒôƵ + /// @param id ÒôƵ±êʶ·û + /// @param loop_count ²¥·ÅÑ­»·´ÎÊý£¬ÉèÖà -1 Ϊѭ»·²¥·Å + void Play(size_t id, int loop_count = 0); - // ÔÝÍ£ÒôÀÖ - void Pause( - size_t id /* ±êʶ·û */ - ); + /// \~chinese + /// @brief ÔÝÍ£ÒôƵ + /// @param id ÒôƵ±êʶ·û + void Pause(size_t id); - // ¼ÌÐø²¥·ÅÒôÀÖ - void Resume( - size_t id /* ±êʶ·û */ - ); + /// \~chinese + /// @brief ¼ÌÐø²¥·ÅÒôƵ + /// @param id ÒôƵ±êʶ·û + void Resume(size_t id); - // Í£Ö¹ÒôÀÖ - void Stop( - size_t id /* ±êʶ·û */ - ); + /// \~chinese + /// @brief Í£Ö¹ÒôƵ + /// @param id ÒôƵ±êʶ·û + void Stop(size_t id); - // »ñÈ¡ÒôÀÖ²¥·Å״̬ - bool IsPlaying( - size_t id /* ±êʶ·û */ - ); + /// \~chinese + /// @brief »ñÈ¡ÒôƵ²¥·Å״̬ + /// @param id ÒôƵ±êʶ·û + bool IsPlaying(size_t id); - // »ñÈ¡ÒôÁ¿ + /// \~chinese + /// @brief »ñÈ¡ÒôÁ¿ float GetVolume() const; - // ÉèÖÃÒôÁ¿ - void SetVolume( - float volume /* 1.0 ΪԭʼÒôÁ¿ */ - ); + /// \~chinese + /// @brief ÉèÖÃÒôÁ¿ + /// @param volume ÒôÁ¿´óС£¬1.0 ΪԭʼÒôÁ¿, ´óÓÚ 1 Ϊ·Å´óÒôÁ¿, 0 Ϊ×îСÒôÁ¿ + void SetVolume(float volume); - // ÔÝÍ£ËùÓÐÒôÀÖ + /// \~chinese + /// @brief ÔÝÍ£ËùÓÐÒôƵ void PauseAll(); - // ¼ÌÐø²¥·ÅËùÓÐÒôÀÖ + /// \~chinese + /// @brief ¼ÌÐø²¥·ÅËùÓÐÒôƵ void ResumeAll(); - // Í£Ö¹ËùÓÐÒôÀÖ + /// \~chinese + /// @brief Í£Ö¹ËùÓÐÒôƵ void StopAll(); - // Çå³ý»º´æ + /// \~chinese + /// @brief Çå³ý»º´æ void ClearCache(); - protected: + private: float volume_; using SoundMap = Map; SoundMap sound_cache_; }; + + /** @} */ } } diff --git a/src/kiwano-audio/Transcoder.cpp b/src/kiwano-audio/Transcoder.cpp index 256ebe83..08ff08e6 100644 --- a/src/kiwano-audio/Transcoder.cpp +++ b/src/kiwano-audio/Transcoder.cpp @@ -23,12 +23,12 @@ #endif #include -#include +#include #include #include -#include -#include -#include +#include +#include +#include #include namespace kiwano @@ -76,7 +76,7 @@ namespace kiwano ComPtr reader; - hr = modules::MediaFoundation::Get().MFCreateSourceReaderFromURL( + hr = dlls::MediaFoundation::Get().MFCreateSourceReaderFromURL( file_path.c_str(), nullptr, &reader @@ -101,25 +101,25 @@ namespace kiwano Resource::Data data = res.GetData(); if (!data) { return E_FAIL; } - stream = kiwano::modules::Shlwapi::Get().SHCreateMemStream( + stream = win32::dlls::Shlwapi::Get().SHCreateMemStream( static_cast(data.buffer), static_cast(data.size) ); if (stream == nullptr) { - KGE_ERROR_LOG(L"SHCreateMemStream failed"); + KGE_ERROR(L"SHCreateMemStream failed"); return E_OUTOFMEMORY; } if (SUCCEEDED(hr)) { - hr = modules::MediaFoundation::Get().MFCreateMFByteStreamOnStream(stream.get(), &byte_stream); + hr = dlls::MediaFoundation::Get().MFCreateMFByteStreamOnStream(stream.get(), &byte_stream); } if (SUCCEEDED(hr)) { - hr = modules::MediaFoundation::Get().MFCreateSourceReaderFromByteStream( + hr = dlls::MediaFoundation::Get().MFCreateSourceReaderFromByteStream( byte_stream.get(), nullptr, &reader @@ -142,7 +142,7 @@ namespace kiwano ComPtr partial_type; ComPtr uncompressed_type; - hr = modules::MediaFoundation::Get().MFCreateMediaType(&partial_type); + hr = dlls::MediaFoundation::Get().MFCreateMediaType(&partial_type); if (SUCCEEDED(hr)) { @@ -186,7 +186,7 @@ namespace kiwano if (SUCCEEDED(hr)) { uint32_t size = 0; - hr = modules::MediaFoundation::Get().MFCreateWaveFormatExFromMFMediaType( + hr = dlls::MediaFoundation::Get().MFCreateWaveFormatExFromMFMediaType( uncompressed_type.get(), &wave_format_, &size, @@ -225,7 +225,7 @@ namespace kiwano if (data == nullptr) { - KGE_ERROR_LOG(L"Low memory"); + KGE_ERROR(L"Low memory"); hr = E_OUTOFMEMORY; } else diff --git a/src/kiwano-audio/Transcoder.h b/src/kiwano-audio/Transcoder.h index 1ee99cf3..50afd1c0 100644 --- a/src/kiwano-audio/Transcoder.h +++ b/src/kiwano-audio/Transcoder.h @@ -28,41 +28,64 @@ namespace kiwano { namespace audio { + class Sound; + /** + * \addtogroup Audio + * @{ + */ + + /** + * \~chinese + * @brief ÒôƵ½âÂëÆ÷ + */ class KGE_API Transcoder { + friend class Sound; + public: + /** + * \~chinese + * @brief ÒôƵÊý¾Ý»º³å + */ struct Buffer { - BYTE* data; - uint32_t size; - const WAVEFORMATEX* format; + BYTE* data; ///< ÒôƵÊý¾Ý + uint32_t size; ///< ÒôƵÊý¾Ý´óС + const WAVEFORMATEX* format; ///< ÒôƵÊý¾Ý¸ñʽ }; Transcoder(); ~Transcoder(); + /// \~chinese + /// @brief »ñÈ¡Êý¾Ý»º³å Buffer GetBuffer() const; + /// \~chinese + /// @brief Çå¿ÕÊý¾Ý»º³å void ClearBuffer(); - HRESULT LoadMediaFile( - String const& file_path - ); + private: + /// \~chinese + /// @brief ½âÂë±¾µØÒôƵÎļþ + HRESULT LoadMediaFile(String const& file_path); - HRESULT LoadMediaResource( - Resource const& res - ); + /// \~chinese + /// @brief ½âÂëÒôƵ×ÊÔ´ + HRESULT LoadMediaResource(Resource const& res); - HRESULT ReadSource( - IMFSourceReader* reader - ); + /// \~chinese + /// @brief ¶ÁÈ¡ÒôƵԴÊý¾Ý + HRESULT ReadSource(IMFSourceReader* reader); private: BYTE* wave_data_; uint32_t wave_size_; WAVEFORMATEX* wave_format_; }; + + /** @} */ } } diff --git a/src/kiwano-audio/audio-modules.cpp b/src/kiwano-audio/libraries.cpp similarity index 72% rename from src/kiwano-audio/audio-modules.cpp rename to src/kiwano-audio/libraries.cpp index f140f00d..5239d216 100644 --- a/src/kiwano-audio/audio-modules.cpp +++ b/src/kiwano-audio/libraries.cpp @@ -19,13 +19,13 @@ // THE SOFTWARE. #include -#include +#include namespace kiwano { namespace audio { - namespace modules + namespace dlls { XAudio2::XAudio2() : xaudio2() @@ -33,9 +33,9 @@ namespace kiwano { const auto xaudio2_dll_names = { - L"xaudio2_9.dll", // for Windows 10 - L"xaudio2_8.dll", // for Windows 8 - L"xaudio2_7.dll" // for DirectX SDK + "xaudio2_9.dll", // for Windows 10 + "xaudio2_8.dll", // for Windows 8 + "xaudio2_7.dll" // for DirectX SDK }; for (const auto& name : xaudio2_dll_names) @@ -48,11 +48,11 @@ namespace kiwano if (xaudio2.IsValid()) { - XAudio2Create = xaudio2.GetProcess(L"XAudio2Create"); + XAudio2Create = xaudio2.GetProcess("XAudio2Create"); } else { - KGE_ERROR_LOG(L"Load xaudio2.dll failed"); + KGE_ERROR(L"Load xaudio2.dll failed"); throw std::runtime_error("Load xaudio2.dll failed"); } } @@ -68,28 +68,28 @@ namespace kiwano , MFCreateSourceReaderFromByteStream(nullptr) , MFCreateMFByteStreamOnStream(nullptr) { - if (mfplat.Load(L"Mfplat.dll")) + if (mfplat.Load("Mfplat.dll")) { - MFStartup = mfplat.GetProcess(L"MFStartup"); - MFShutdown = mfplat.GetProcess(L"MFShutdown"); - MFCreateMediaType = mfplat.GetProcess(L"MFCreateMediaType"); - MFCreateWaveFormatExFromMFMediaType = mfplat.GetProcess(L"MFCreateWaveFormatExFromMFMediaType"); - MFCreateMFByteStreamOnStream = mfplat.GetProcess(L"MFCreateMFByteStreamOnStream"); + MFStartup = mfplat.GetProcess("MFStartup"); + MFShutdown = mfplat.GetProcess("MFShutdown"); + MFCreateMediaType = mfplat.GetProcess("MFCreateMediaType"); + MFCreateWaveFormatExFromMFMediaType = mfplat.GetProcess("MFCreateWaveFormatExFromMFMediaType"); + MFCreateMFByteStreamOnStream = mfplat.GetProcess("MFCreateMFByteStreamOnStream"); } else { - KGE_LOG(L"Load Mfplat.dll failed"); + KGE_ERROR(L"Load Mfplat.dll failed"); throw std::runtime_error("Load Mfplat.dll failed"); } - if (mfreadwrite.Load(L"Mfreadwrite.dll")) + if (mfreadwrite.Load("Mfreadwrite.dll")) { - MFCreateSourceReaderFromURL = mfreadwrite.GetProcess(L"MFCreateSourceReaderFromURL"); - MFCreateSourceReaderFromByteStream = mfreadwrite.GetProcess(L"MFCreateSourceReaderFromByteStream"); + MFCreateSourceReaderFromURL = mfreadwrite.GetProcess("MFCreateSourceReaderFromURL"); + MFCreateSourceReaderFromByteStream = mfreadwrite.GetProcess("MFCreateSourceReaderFromByteStream"); } else { - KGE_LOG(L"Load Mfreadwrite.dll failed"); + KGE_ERROR(L"Load Mfreadwrite.dll failed"); throw std::runtime_error("Load Mfreadwrite.dll failed"); } } diff --git a/src/kiwano-audio/audio-modules.h b/src/kiwano-audio/libraries.h similarity index 98% rename from src/kiwano-audio/audio-modules.h rename to src/kiwano-audio/libraries.h index 299beb34..44d26bf7 100644 --- a/src/kiwano-audio/audio-modules.h +++ b/src/kiwano-audio/libraries.h @@ -25,11 +25,13 @@ #include #include +#ifndef KGE_DOXYGEN_DO_NOT_INCLUDE + namespace kiwano { namespace audio { - namespace modules + namespace dlls { class KGE_API XAudio2 { @@ -93,3 +95,5 @@ namespace kiwano } } } + +#endif diff --git a/src/kiwano-imgui/ImGuiLayer.cpp b/src/kiwano-imgui/ImGuiLayer.cpp index ad29c3e1..94890048 100644 --- a/src/kiwano-imgui/ImGuiLayer.cpp +++ b/src/kiwano-imgui/ImGuiLayer.cpp @@ -35,7 +35,7 @@ namespace kiwano void ImGuiLayer::OnRender(RenderTarget* rt) { - PrepareRender(rt); + PrepareToRender(rt); for (const auto& pipeline : pipelines_) { pipeline.second(); diff --git a/src/kiwano-imgui/ImGuiLayer.h b/src/kiwano-imgui/ImGuiLayer.h index 59921cc7..8f4246b2 100644 --- a/src/kiwano-imgui/ImGuiLayer.h +++ b/src/kiwano-imgui/ImGuiLayer.h @@ -27,8 +27,14 @@ namespace kiwano { KGE_DECLARE_SMART_PTR(ImGuiLayer); + /// \~chinese + /// @brief ImGui¹ÜµÀ using ImGuiPipeline = Function; + /** + * \~chinese + * @brief ImGuiͼ²ã + */ class ImGuiLayer : public Layer { @@ -37,24 +43,26 @@ namespace kiwano virtual ~ImGuiLayer(); - // Ìí¼Ó ImGui ÔªËØ - void AddItem( - ImGuiPipeline const& item, - String const& name - ); + /// \~chinese + /// @brief Ìí¼Ó ImGui ÔªËØ + /// @param item ¹ÜµÀ + /// @param name ÔªËØÃû³Æ + void AddItem(ImGuiPipeline const& item, String const& name); - // ÒÆ³ý ImGui ÔªËØ - void RemoveItem( - String const& name - ); + /// \~chinese + /// @brief ÒÆ³ý ImGui ÔªËØ + /// @param name ÔªËØÃû³Æ + void RemoveItem(String const& name); // ÒÆ³ýËùÓÐÔªËØ + /// \~chinese + /// @brief ÒÆ³ýËùÓÐÔªËØ void RemoveAllItems(); public: void OnRender(RenderTarget* rt) override; - protected: + private: Map pipelines_; }; } diff --git a/src/kiwano-imgui/ImGuiModule.cpp b/src/kiwano-imgui/ImGuiModule.cpp index f164f2bd..d0fa9a0f 100644 --- a/src/kiwano-imgui/ImGuiModule.cpp +++ b/src/kiwano-imgui/ImGuiModule.cpp @@ -1,8 +1,6 @@ // Copyright (C) 2019 Nomango -#include -#include -#include +#include #include #include #include @@ -45,9 +43,9 @@ namespace kiwano //ImGui::StyleColorsClassic(); // Setup Platform/Renderer bindings - Init(Window::GetInstance()->GetHandle()); + Init(Window::instance().GetHandle()); - target_window_ = Renderer::GetInstance()->GetTargetWindow(); + target_window_ = Renderer::instance().GetTargetWindow(); } void ImGuiModule::DestroyComponent() @@ -64,9 +62,9 @@ namespace kiwano io.DeltaTime = dt.Seconds(); // Read keyboard modifiers inputs - io.KeyCtrl = Input::GetInstance()->IsDown(KeyCode::Ctrl); - io.KeyShift = Input::GetInstance()->IsDown(KeyCode::Shift); - io.KeyAlt = Input::GetInstance()->IsDown(KeyCode::Alt); + io.KeyCtrl = Input::instance().IsDown(KeyCode::Ctrl); + io.KeyShift = Input::instance().IsDown(KeyCode::Shift); + io.KeyAlt = Input::instance().IsDown(KeyCode::Alt); io.KeySuper = false; // io.KeysDown[], io.MousePos, io.MouseDown[], io.MouseWheel: filled by the WndProc handler below. @@ -106,7 +104,7 @@ namespace kiwano io.KeyMap[ImGuiKey_Y] = KeyCode::Y; io.KeyMap[ImGuiKey_Z] = KeyCode::Z; - ImGui_Impl_Init(Renderer::GetInstance()); + ImGui_Impl_Init(&Renderer::instance()); } void ImGuiModule::BeforeRender() @@ -213,7 +211,7 @@ namespace kiwano KGE_ASSERT(io.Fonts->IsBuilt() && "Font atlas not built!"); // Setup display size (every frame to accommodate for window resizing) - Size display_size = Renderer::GetInstance()->GetOutputSize(); + Size display_size = Renderer::instance().GetOutputSize(); io.DisplaySize = ImVec2(display_size.x, display_size.y); ImGui::NewFrame(); @@ -238,7 +236,7 @@ namespace kiwano ::SetCursorPos(pos.x, pos.y); } - Point pos = Input::GetInstance()->GetMousePos(); + Point pos = Input::instance().GetMousePos(); io.MousePos = ImVec2(pos.x, pos.y); } @@ -260,7 +258,7 @@ namespace kiwano case ImGuiMouseCursor_Hand: cursor = CursorType::Hand; break; } - Window::GetInstance()->SetCursor(cursor); + Window::instance().SetCursor(cursor); } void ImGuiModule::UpdateGamepads() { diff --git a/src/kiwano-imgui/ImGuiModule.h b/src/kiwano-imgui/ImGuiModule.h index c9069a40..50e50115 100644 --- a/src/kiwano-imgui/ImGuiModule.h +++ b/src/kiwano-imgui/ImGuiModule.h @@ -19,27 +19,24 @@ // THE SOFTWARE. #pragma once +#include #include -#include namespace kiwano { namespace imgui { + /** + * \~chinese + * @brief ImGuiÄ£¿é + */ class ImGuiModule : public Singleton , public RenderComponent , public UpdateComponent , public EventComponent { - KGE_DECLARE_SINGLETON(ImGuiModule); - - private: - void Init(HWND hwnd); - - void NewFrame(); - - void Render(); + friend Singleton; public: ImGuiModule(); @@ -48,14 +45,21 @@ namespace kiwano void DestroyComponent() override; - void OnUpdate(Duration dt) override; - void BeforeRender() override; void AfterRender() override; void HandleMessage(HWND hwnd, UINT32 msg, WPARAM wparam, LPARAM lparam) override; + void OnUpdate(Duration dt) override; + + private: + void Init(HWND hwnd); + + void NewFrame(); + + void Render(); + void UpdateMousePos(); void UpdateMouseCursor(); diff --git a/src/kiwano-imgui/imgui_impl.h b/src/kiwano-imgui/imgui_impl.h index d010cf30..372f26fe 100644 --- a/src/kiwano-imgui/imgui_impl.h +++ b/src/kiwano-imgui/imgui_impl.h @@ -2,6 +2,8 @@ #pragma once +#ifndef KGE_DOXYGEN_DO_NOT_INCLUDE + #if !defined(KGE_USE_DIRECTX10) #include @@ -27,3 +29,5 @@ inline void ImGui_Impl_InvalidateDeviceObjects() { ImGui_ImplDX10_Invalid inline bool ImGui_Impl_CreateDeviceObjects() { return ImGui_ImplDX10_CreateDeviceObjects(); } #endif + +#endif diff --git a/src/kiwano-imgui/imgui_impl_dx10.h b/src/kiwano-imgui/imgui_impl_dx10.h index 8e994ee9..26fdb0c1 100644 --- a/src/kiwano-imgui/imgui_impl_dx10.h +++ b/src/kiwano-imgui/imgui_impl_dx10.h @@ -3,6 +3,8 @@ #pragma once #include <3rd-party/imgui/imgui.h> +#ifndef KGE_DOXYGEN_DO_NOT_INCLUDE + struct ID3D10Device; IMGUI_IMPL_API bool ImGui_ImplDX10_Init(ID3D10Device* device); @@ -13,3 +15,5 @@ IMGUI_IMPL_API void ImGui_ImplDX10_RenderDrawData(ImDrawData* draw_data); // Use if you want to reset your rendering device without losing ImGui state. IMGUI_IMPL_API void ImGui_ImplDX10_InvalidateDeviceObjects(); IMGUI_IMPL_API bool ImGui_ImplDX10_CreateDeviceObjects(); + +#endif diff --git a/src/kiwano-imgui/imgui_impl_dx11.cpp b/src/kiwano-imgui/imgui_impl_dx11.cpp index a8dc29eb..470f914b 100644 --- a/src/kiwano-imgui/imgui_impl_dx11.cpp +++ b/src/kiwano-imgui/imgui_impl_dx11.cpp @@ -1,6 +1,5 @@ // dear imgui: Renderer for Kiwano (DirectX11) -#include #include // DirectX @@ -259,9 +258,7 @@ static void ImGui_ImplDX11_CreateFontsTexture() subResource.pSysMem = pixels; subResource.SysMemPitch = desc.Width * 4; subResource.SysMemSlicePitch = 0; - kiwano::ThrowIfFailed( - g_pd3dDevice->CreateTexture2D(&desc, &subResource, &pTexture) - ); + g_pd3dDevice->CreateTexture2D(&desc, &subResource, &pTexture); if (pTexture) { @@ -272,9 +269,7 @@ static void ImGui_ImplDX11_CreateFontsTexture() srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D; srvDesc.Texture2D.MipLevels = desc.MipLevels; srvDesc.Texture2D.MostDetailedMip = 0; - kiwano::ThrowIfFailed( - g_pd3dDevice->CreateShaderResourceView(pTexture, &srvDesc, &g_pFontTextureView) - ); + g_pd3dDevice->CreateShaderResourceView(pTexture, &srvDesc, &g_pFontTextureView); pTexture->Release(); } diff --git a/src/kiwano-imgui/imgui_impl_dx11.h b/src/kiwano-imgui/imgui_impl_dx11.h index 066c4ba2..4964c00c 100644 --- a/src/kiwano-imgui/imgui_impl_dx11.h +++ b/src/kiwano-imgui/imgui_impl_dx11.h @@ -3,6 +3,8 @@ #pragma once #include <3rd-party/imgui/imgui.h> +#ifndef KGE_DOXYGEN_DO_NOT_INCLUDE + struct ID3D11Device; struct ID3D11DeviceContext; @@ -14,3 +16,5 @@ IMGUI_IMPL_API void ImGui_ImplDX11_RenderDrawData(ImDrawData* draw_data); // Use if you want to reset your rendering device without losing ImGui state. IMGUI_IMPL_API void ImGui_ImplDX11_InvalidateDeviceObjects(); IMGUI_IMPL_API bool ImGui_ImplDX11_CreateDeviceObjects(); + +#endif diff --git a/src/kiwano-imgui/kiwano-imgui.h b/src/kiwano-imgui/kiwano-imgui.h index 68899fd5..453a1a0c 100644 --- a/src/kiwano-imgui/kiwano-imgui.h +++ b/src/kiwano-imgui/kiwano-imgui.h @@ -24,4 +24,4 @@ #include // ImGui -#include <3rd-party/imgui/imgui.h> +#include diff --git a/src/kiwano-network/HttpClient.cpp b/src/kiwano-network/HttpClient.cpp index 7e7d97cc..65b0305d 100644 --- a/src/kiwano-network/HttpClient.cpp +++ b/src/kiwano-network/HttpClient.cpp @@ -36,7 +36,7 @@ namespace uint32_t write_data(void* buffer, uint32_t size, uint32_t nmemb, void* userp) { - common::string* recv_buffer = (common::string*)userp; + ByteString* recv_buffer = (ByteString*)userp; uint32_t total = size * nmemb; // add data to the end of recv_buffer @@ -46,10 +46,10 @@ namespace return total; } - common::string convert_to_utf8(common::wstring const& str) + ByteString convert_to_utf8(String const& str) { std::wstring_convert> utf8_conv; - common::string result; + ByteString result; try { @@ -58,15 +58,15 @@ namespace catch (std::range_error&) { // bad conversion - result = wide_to_string(str); + result = WideToMultiByte(str); } return result; } - common::wstring convert_from_utf8(common::string const& str) + String convert_from_utf8(ByteString const& str) { - kiwano::string_convert> utf8_conv; - common::wstring result; + oc::string_convert> utf8_conv; + String result; try { @@ -75,7 +75,7 @@ namespace catch (std::range_error&) { // bad conversion - result = string_to_wide(str); + result = MultiByteToWide(str); } return result; } @@ -104,7 +104,7 @@ namespace } } - bool Init(HttpClient* client, Vector const& headers, common::string const& url, common::string* response_data, common::string* response_header, char* error_buffer) + bool Init(HttpClient* client, Vector const& headers, ByteString const& url, ByteString* response_data, ByteString* response_header, char* error_buffer) { if (!SetOption(CURLOPT_ERRORBUFFER, error_buffer)) return false; @@ -170,11 +170,11 @@ namespace public: static inline bool GetRequest( HttpClient* client, - Vector const& headers, - common::string const& url, + Vector const& headers, + ByteString const& url, long* response_code, - common::string* response_data, - common::string* response_header, + ByteString* response_data, + ByteString* response_header, char* error_buffer) { Curl curl; @@ -185,12 +185,12 @@ namespace static inline bool PostRequest( HttpClient* client, - Vector const& headers, - common::string const& url, - common::string const& request_data, + Vector const& headers, + ByteString const& url, + ByteString const& request_data, long* response_code, - common::string* response_data, - common::string* response_header, + ByteString* response_data, + ByteString* response_header, char* error_buffer) { Curl curl; @@ -203,12 +203,12 @@ namespace static inline bool PutRequest( HttpClient* client, - Vector const& headers, - common::string const& url, - common::string const& request_data, + Vector const& headers, + ByteString const& url, + ByteString const& request_data, long* response_code, - common::string* response_data, - common::string* response_header, + ByteString* response_data, + ByteString* response_header, char* error_buffer) { Curl curl; @@ -221,11 +221,11 @@ namespace static inline bool DeleteRequest( HttpClient* client, - Vector const& headers, - common::string const& url, + Vector const& headers, + ByteString const& url, long* response_code, - common::string* response_data, - common::string* response_header, + ByteString* response_data, + ByteString* response_header, char* error_buffer) { Curl curl; @@ -307,13 +307,13 @@ namespace kiwano bool ok = false; long response_code = 0; char error_message[256] = { 0 }; - common::string response_header; - common::string response_data; + ByteString response_header; + ByteString response_data; - common::string url = convert_to_utf8(request->GetUrl()); - common::string data = convert_to_utf8(request->GetData()); + ByteString url = convert_to_utf8(request->GetUrl()); + ByteString data = convert_to_utf8(request->GetData()); - Vector headers; + Vector headers; headers.reserve(request->GetHeaders().size()); for (const auto& pair : request->GetHeaders()) { @@ -335,17 +335,17 @@ namespace kiwano ok = Curl::DeleteRequest(this, headers, url, &response_code, &response_data, &response_header, error_message); break; default: - KGE_ERROR_LOG(L"HttpClient: unknown request type, only GET, POST, PUT or DELETE is supported"); + KGE_ERROR(L"HttpClient: unknown request type, only GET, POST, PUT or DELETE is supported"); return; } response->SetResponseCode(response_code); - response->SetHeader(string_to_wide(response_header)); + response->SetHeader(MultiByteToWide(response_header)); response->SetData(convert_from_utf8(response_data)); if (!ok) { response->SetSucceed(false); - response->SetError(string_to_wide(error_message)); + response->SetError(MultiByteToWide(error_message)); } else { diff --git a/src/kiwano-network/HttpClient.h b/src/kiwano-network/HttpClient.h index 31e7bf1f..600252ae 100644 --- a/src/kiwano-network/HttpClient.h +++ b/src/kiwano-network/HttpClient.h @@ -19,8 +19,7 @@ // THE SOFTWARE. #pragma once -#include -#include +#include #include #include #include @@ -29,25 +28,55 @@ namespace kiwano { namespace network { + /** + * \~chinese + * \defgroup Network ÍøÂçͨÐÅ + */ + + /** + * \addtogroup Network + * @{ + */ + + /** + * \~chinese + * @brief HTTP¿Í»§¶Ë + */ class KGE_API HttpClient : public Singleton , public ComponentBase { - KGE_DECLARE_SINGLETON(HttpClient); + friend Singleton; public: + /// \~chinese + /// @brief ·¢ËÍHTTPÇëÇó + /// @param[in] request HTTPÇëÇó + /// @details ·¢ËÍÇëÇóºó£¬ÎÞÂÛ½áÊø»òʧ°Ü¶¼½«µ÷ÓÃÇëÇóµÄÏìÓ¦»Øµ÷º¯Êý void Send(HttpRequestPtr request); + /// \~chinese + /// @brief ÉèÖÃÁ¬½Ó³¬Ê±Ê±³¤ void SetTimeoutForConnect(Duration timeout); + /// \~chinese + /// @brief »ñÈ¡Á¬½Ó³¬Ê±Ê±³¤ Duration GetTimeoutForConnect() const; + /// \~chinese + /// @brief ÉèÖöÁÈ¡³¬Ê±Ê±³¤ void SetTimeoutForRead(Duration timeout); + /// \~chinese + /// @brief »ñÈ¡¶ÁÈ¡³¬Ê±Ê±³¤ Duration GetTimeoutForRead() const; + /// \~chinese + /// @brief ÉèÖÃSSLÖ¤Ê鵨ַ void SetSSLVerification(String const& root_certificate_path); + /// \~chinese + /// @brief »ñÈ¡SSLÖ¤Ê鵨ַ String const& GetSSLVerification() const; public: @@ -60,10 +89,7 @@ namespace kiwano void NetworkThread(); - void Perform( - HttpRequestPtr request, - HttpResponsePtr response - ); + void Perform(HttpRequestPtr request, HttpResponsePtr response); void DispatchResponseCallback(); @@ -82,6 +108,8 @@ namespace kiwano std::condition_variable_any sleep_condition_; }; + /** @} */ + inline void HttpClient::SetTimeoutForConnect(Duration timeout) { diff --git a/src/kiwano-network/HttpRequest.h b/src/kiwano-network/HttpRequest.h index 716f8240..89dae6fa 100644 --- a/src/kiwano-network/HttpRequest.h +++ b/src/kiwano-network/HttpRequest.h @@ -19,8 +19,7 @@ // THE SOFTWARE. #pragma once -#include -#include +#include #include #include @@ -32,49 +31,91 @@ namespace kiwano KGE_DECLARE_SMART_PTR(HttpRequest); + /** + * \addtogroup Network + * @{ + */ + + /** + * \~chinese + * @brief HTTPÇëÇó + */ class KGE_API HttpRequest : public ObjectBase { public: - using ResponseCallback = Function; + /// \~chinese + /// @brief ÏìÓ¦»Øµ÷º¯Êý + using ResponseCallback = Function; + /// \~chinese + /// @brief ÇëÇóÀàÐÍ enum class Type { - Unknown, - Get, - Post, - Put, - Delete + Unknown, ///< δ֪ + Get, ///< HTTP GETÇëÇó + Post, ///< HTTP POSTÇëÇó + Put, ///< HTTP PUTÇëÇó + Delete ///< HTTP DELETEÇëÇó }; HttpRequest(); HttpRequest(Type type); - // ÇëÇóµØÖ· + /// \~chinese + /// @brief ÉèÖÃÇëÇóµØÖ· void SetUrl(String const& url); + + /// \~chinese + /// @brief ÉèÖÃÇëÇóÀàÐÍ + void SetType(Type type); + + /// \~chinese + /// @brief ÉèÖÃÇëÇóЯ´øµÄÊý¾Ý + void SetData(String const& data); + + /// \~chinese + /// @brief ÉèÖÃÇëÇóЯ´øµÄJSONÊý¾Ý + void SetJsonData(Json const& json); + + /// \~chinese + /// @brief ÉèÖÃHTTPÍ· + void SetHeaders(Map const& headers); + + /// \~chinese + /// @brief ÉèÖÃHTTPÍ· + void SetHeader(String const& field, String const& content); + + /// \~chinese + /// @brief ÉèÖÃÏìÓ¦»Øµ÷º¯Êý + void SetResponseCallback(ResponseCallback const& callback); + + /// \~chinese + /// @brief »ñÈ¡ÇëÇóµØÖ· String const& GetUrl() const; - // ÇëÇóÀàÐÍ - void SetType(Type type); + /// \~chinese + /// @brief »ñÈ¡ÇëÇóÀàÐÍ Type GetType() const; - // ÇëÇóÊý¾Ý - void SetData(String const& data); - void SetJsonData(Json const& json); + /// \~chinese + /// @brief »ñÈ¡ÇëÇóÊý¾Ý String const& GetData() const; - // ÇëÇóÍ· - void SetHeaders(Map const& headers); - void SetHeader(String const& field, String const& content); + /// \~chinese + /// @brief »ñÈ¡HTTPÍ· Map& GetHeaders(); + + /// \~chinese + /// @brief »ñÈ¡HTTPÍ· String const& GetHeader(String const& header) const; - // ÏìÓ¦»Øµ÷ - void SetResponseCallback(ResponseCallback const& callback); + /// \~chinese + /// @brief »ñÈ¡ÏìÓ¦»Øµ÷º¯Êý ResponseCallback const& GetResponseCallback() const; - protected: + private: Type type_; String url_; String data_; @@ -82,6 +123,8 @@ namespace kiwano ResponseCallback response_cb_; }; + /** @} */ + inline HttpRequest::HttpRequest() : type_(Type::Unknown) {} inline HttpRequest::HttpRequest(Type type) : type_(type) {} diff --git a/src/kiwano-network/HttpResponse.hpp b/src/kiwano-network/HttpResponse.hpp index a2d043b0..14f80831 100644 --- a/src/kiwano-network/HttpResponse.hpp +++ b/src/kiwano-network/HttpResponse.hpp @@ -27,36 +27,66 @@ namespace kiwano { KGE_DECLARE_SMART_PTR(HttpResponse); + /** + * \addtogroup Network + * @{ + */ + + /** + * \~chinese + * @brief HTTPÏìÓ¦ + */ class KGE_API HttpResponse : public ObjectBase { public: HttpResponse(HttpRequestPtr request); - // »ñÈ¡ÇëÇó + /// \~chinese + /// @brief »ñÈ¡¶ÔÓ¦µÄHTTPÇëÇó HttpRequestPtr GetRequest() const; - // ÏìӦ״̬ + /// \~chinese + /// @brief »ñÈ¡ÏìӦ״̬ bool IsSucceed() const; + + /// \~chinese + /// @brief »ñÈ¡HTTP״̬Âë + long GetResponseCode() const; + + /// \~chinese + /// @brief »ñÈ¡ÏìӦͷ + String GetHeader() const; + + /// \~chinese + /// @brief »ñÈ¡ÏìÓ¦Êý¾Ý + String const& GetData() const; + + /// \~chinese + /// @brief »ñÈ¡´íÎóÐÅÏ¢ + String const& GetError() const; + + /// \~chinese + /// @brief ÉèÖÃÏìӦ״̬ void SetSucceed(bool succeed); - // ÏìӦ״̬Âë - long GetResponseCode() const; + /// \~chinese + /// @brief ÉèÖÃHTTP״̬Âë void SetResponseCode(long response_code); - // ÏìӦͷ - String GetHeader() const; + /// \~chinese + /// @brief ÉèÖÃÏìӦͷ void SetHeader(String const& response_header); - // ÏìÓ¦Êý¾Ý - String const& GetData() const; + /// \~chinese + /// @brief ÉèÖÃÏìÓ¦Êý¾Ý void SetData(String const& response_data); - // ´íÎóÐÅÏ¢ - String const& GetError() const; + /// \~chinese + /// @brief ÉèÖôíÎóÐÅÏ¢ void SetError(String const& error_buffer); - protected: + private: bool succeed_; long response_code_; HttpRequestPtr request_; @@ -66,6 +96,8 @@ namespace kiwano String error_buffer_; }; + /** @} */ + inline HttpResponse::HttpResponse(HttpRequestPtr request) : request_(request), succeed_(false), response_code_(0) {} inline HttpRequestPtr HttpResponse::GetRequest() const { return request_; } diff --git a/src/kiwano-physics/Body.cpp b/src/kiwano-physics/Body.cpp index 379b40f1..37cf93e4 100644 --- a/src/kiwano-physics/Body.cpp +++ b/src/kiwano-physics/Body.cpp @@ -104,8 +104,7 @@ namespace kiwano { if (fixture.GetB2Fixture()) { - b2Fixture* ptr = const_cast(fixture.GetB2Fixture()); - body_->DestroyFixture(ptr); + body_->DestroyFixture(fixture.GetB2Fixture()); } } @@ -254,7 +253,7 @@ namespace kiwano void Body::Destroy() { - if (world_) + if (world_ && body_) { world_->RemoveBody(this); } diff --git a/src/kiwano-physics/Body.h b/src/kiwano-physics/Body.h index e9f25989..b8049afd 100644 --- a/src/kiwano-physics/Body.h +++ b/src/kiwano-physics/Body.h @@ -22,7 +22,7 @@ #include #include #include -#include +#include namespace kiwano { @@ -30,141 +30,284 @@ namespace kiwano { class World; - // ÎïÌå KGE_DECLARE_SMART_PTR(Body); + + /** + * \addtogroup Physics + * @{ + */ + + /// \~chinese + /// @brief ÎïÌå class KGE_API Body : public virtual RefCounter { public: + /// \~chinese + /// @brief ÎïÌåÀàÐÍ enum class Type { - Static = 0, - Kinematic, - Dynamic, + Static = 0, ///< ¾²Ì¬ÎïÌå + Kinematic, ///< ¶¯Á¦Ñ§ÎïÌå + Dynamic, ///< ¶¯Ì¬ÎïÌå }; Body(); Body(b2Body* body, Actor* actor); Body(World* world, Actor* actor); - Body(World* world, ActorPtr actor) : Body(world, actor.get()) {} + Body(World* world, ActorPtr actor); virtual ~Body(); - // ³õʼ»¯ + /// \~chinese + /// @brief ³õʼ»¯ + /// @param[in] world ÎïÀíÊÀ½ç + /// @param[in] actor °ó¶¨µÄ½ÇÉ« void Init(World* world, Actor* actor); - // Ìí¼Ó¼Ð¾ß + /// \~chinese + /// @brief Ìí¼Ó¼Ð¾ß + /// @param shape ÎïÌåÐÎ×´ + /// @param density ÎïÌåÃÜ¶È Fixture AddFixture(Shape* shape, const Fixture::Param& param); - // Ìí¼ÓÐÎ×´ + /// \~chinese + /// @brief Ìí¼ÓÔ²ÐÎ¼Ð¾ß + /// @param radius Ô²Ðΰ뾶 + /// @param density ÎïÌåÃÜ¶È Fixture AddCircleShape(float radius, float density = 0.f); + + /// \~chinese + /// @brief Ìí¼ÓºÐÐÎ¼Ð¾ß + /// @param size ºÐ´óС + /// @param density ÎïÌåÃÜ¶È Fixture AddBoxShape(Vec2 const& size, float density = 0.f); + + /// \~chinese + /// @brief Ìí¼Ó¶à±ßÐÎ¼Ð¾ß + /// @param vertexs ¶à±ßÐζ˵ã + /// @param density ÎïÌåÃÜ¶È Fixture AddPolygonShape(Vector const& vertexs, float density = 0.f); + + /// \~chinese + /// @brief Ìí¼ÓÏß¶ÎÐÎ¼Ð¾ß + /// @param p1 Ïß¶ÎÆðµã + /// @param p2 Ïß¶ÎÖÕµã + /// @param density ÎïÌåÃÜ¶È Fixture AddEdgeShape(Point const& p1, Point const& p2, float density = 0.f); + + /// \~chinese + /// @brief Ìí¼ÓÁ´ÌõÐÎ¼Ð¾ß + /// @param vertexs Á´Ìõ¶Ëµã + /// @param loop ÊÇ·ñ±ÕºÏ + /// @param density ÎïÌåÃÜ¶È Fixture AddChainShape(Vector const& vertexs, bool loop, float density = 0.f); - // »ñÈ¡¼Ð¾ß - Fixture GetFixtureList() const { KGE_ASSERT(body_); return Fixture(body_->GetFixtureList()); } + /// \~chinese + /// @brief »ñÈ¡¼Ð¾ßÁбí + FixtureList GetFixtureList() const; - // ÒÆ³ý¼Ð¾ß + /// \~chinese + /// @brief ÒÆ³ý¼Ð¾ß void RemoveFixture(Fixture const& fixture); - // »ñÈ¡½Ó´¥±ß - ContactEdge GetContactList() const { KGE_ASSERT(body_); ContactEdge(body_->GetContactList()); } + /// \~chinese + /// @brief »ñÈ¡½Ó´¥±ßÁбí + ContactEdgeList GetContactList() const; - // Àà±ðÂë - uint16_t GetCategoryBits() const { return category_bits_; } + /// \~chinese + /// @brief »ñÈ¡Àà±ðÂë + uint16_t GetCategoryBits() const; + + /// \~chinese + /// @brief ÉèÖÃÀà±ðÂë void SetCategoryBits(uint16_t category_bits); - // ÅöײÑÚÂë - uint16_t GetMaskBits() const { return mask_bits_; } + /// \~chinese + /// @brief »ñÈ¡ÅöײÑÚÂë + uint16_t GetMaskBits() const; + + /// \~chinese + /// @brief ÉèÖÃÅöײÑÚÂë void SetMaskBits(uint16_t mask_bits); - // ×éË÷Òý - int16_t GetGroupIndex() const { return group_index_; } + /// \~chinese + /// @brief »ñÈ¡×éË÷Òý + int16_t GetGroupIndex() const; + + /// \~chinese + /// @brief ÉèÖÃ×éË÷Òý void SetGroupIndex(int16_t index); - // Ðýת½Ç¶È - float GetBodyRotation() const { KGE_ASSERT(body_); return math::Radian2Degree(body_->GetAngle()); } - void SetBodyRotation(float angle) { SetBodyTransform(GetBodyPosition(), angle); } + /// \~chinese + /// @brief »ñÈ¡Ðýת½Ç¶È + float GetBodyRotation() const; - // λÖà + /// \~chinese + /// @brief ÉèÖÃÐýת½Ç¶È + void SetBodyRotation(float angle); + + /// \~chinese + /// @brief »ñÈ¡ÎïÌåλÖà Point GetBodyPosition() const; - void SetBodyPosition(Point const& pos) { SetBodyTransform(pos, GetBodyRotation()); } - // λÖúÍÐýת±ä»» + /// \~chinese + /// @brief ÉèÖÃÎïÌåλÖà + void SetBodyPosition(Point const& pos); + + /// \~chinese + /// @brief λÖúÍÐýת±ä»» void SetBodyTransform(Point const& pos, float angle); - // ÖÊÁ¿ - float GetMass() const { KGE_ASSERT(body_); return body_->GetMass(); } + /// \~chinese + /// @brief »ñÈ¡ÖÊÁ¿ [kg] + float GetMass() const; - // ¹ßÐÔ - float GetInertia() const { KGE_ASSERT(body_); return body_->GetInertia(); } + /// \~chinese + /// @brief »ñÈ¡¹ßÐÔ + float GetInertia() const; - // ÖÊÁ¿Êý¾Ý + /// \~chinese + /// @brief »ñÈ¡ÖÊÁ¿Êý¾Ý + /// @param[out] mass ÎïÌåÖÊÁ¿ [kg] + /// @param[out] center ÖÊÐÄλÖà + /// @param[out] inertia ¹ßÐÔ void GetMassData(float* mass, Point* center, float* inertia) const; + + /// \~chinese + /// @brief ÉèÖÃÖÊÁ¿Êý¾Ý + /// @param mass ÎïÌåÖÊÁ¿ [kg] + /// @param center ÖÊÐÄλÖà + /// @param inertia ¹ßÐÔ void SetMassData(float mass, Point const& center, float inertia); + + /// \~chinese + /// @brief ÖØÖÃÖÊÁ¿Êý¾Ý void ResetMassData(); - // ×ø±êת»» + /// \~chinese + /// @brief »ñÈ¡ÊÀ½ç×ø±êϵÉϵĵãÔÚÎïÌåÉϵÄλÖà Point GetLocalPoint(Point const& world) const; + + /// \~chinese + /// @brief »ñÈ¡ÎïÌåÉϵĵãÔÚÊÀ½ç×ø±êϵµÄλÖà Point GetWorldPoint(Point const& local) const; - // ÖÊÐÄ×ø±ê + /// \~chinese + /// @brief »ñÈ¡ÎïÌåÖÊÐÄÏà¶ÔÓÚÎïÌåµÄλÖà Point GetLocalCenter() const; + + /// \~chinese + /// @brief »ñÈ¡ÎïÌåÖÊÐÄλÖà Point GetWorldCenter() const; - // ÎïÌåÀàÐÍ - Type GetType() const { KGE_ASSERT(body_); return Type(body_->GetType()); } - void SetType(Type type) { KGE_ASSERT(body_); body_->SetType(static_cast(type)); } + /// \~chinese + /// @brief »ñÈ¡ÎïÌåÀàÐÍ + Type GetType() const; - // ÖØÁ¦Òò×Ó - float GetGravityScale() const { KGE_ASSERT(body_); return body_->GetGravityScale(); } - void SetGravityScale(float scale) { KGE_ASSERT(body_); body_->SetGravityScale(scale); } + /// \~chinese + /// @brief ÉèÖÃÎïÌåÀàÐÍ + void SetType(Type type); - // Ê©Á¦ + /// \~chinese + /// @brief »ñÈ¡ÎïÌåÊÜÖØÁ¦µÄ±ÈÀý + float GetGravityScale() const; + + /// \~chinese + /// @brief ÉèÖÃÎïÌåÊÜÖØÁ¦µÄ±ÈÀý + void SetGravityScale(float scale); + + /// \~chinese + /// @brief Ê©Á¦ + /// @param force Á¦µÄ´óСºÍ·½Ïò + /// @param point Ê©Á¦µã + /// @param wake ÊÇ·ñ»½ÐÑÎïÌå void ApplyForce(Vec2 const& force, Point const& point, bool wake = true); + + /// \~chinese + /// @brief ¸øÎïÌåÖÐÐÄÊ©Á¦ + /// @param force Á¦µÄ´óСºÍ·½Ïò + /// @param wake ÊÇ·ñ»½ÐÑÎïÌå void ApplyForceToCenter(Vec2 const& force, bool wake = true); - // Ê©¼ÓŤ¾Ø - void ApplyTorque(float torque, bool wake = true); + /// \~chinese + /// @brief Ê©¼ÓŤ¾Ø + /// @param torque Ť¾Ø + /// @param wake ÊÇ·ñ»½ÐÑÎïÌå + void ApplyTorque(float torque, bool wake = false); - // ¹Ì¶¨Ðýת - bool IsIgnoreRotation() const { KGE_ASSERT(body_); return body_->IsFixedRotation(); } - void SetIgnoreRotation(bool flag) { KGE_ASSERT(body_); body_->SetFixedRotation(flag); } + /// \~chinese + /// @brief Ðýת½Ç¶ÈÊÇ·ñ¹Ì¶¨ + bool IsIgnoreRotation() const; - // ×Óµ¯ - bool IsBullet() const { KGE_ASSERT(body_); return body_->IsBullet(); } - void SetBullet(bool flag) { KGE_ASSERT(body_); body_->SetBullet(flag); } + /// \~chinese + /// @brief ÉèÖÃÊÇ·ñ¹Ì¶¨Ðýת½Ç¶È + void SetIgnoreRotation(bool flag); - // ÐÝÃß - bool IsAwake() const { KGE_ASSERT(body_); return body_->IsAwake(); } - void SetAwake(bool flag) { KGE_ASSERT(body_); body_->SetAwake(flag); } - bool IsSleepingAllowed() const { KGE_ASSERT(body_); return body_->IsSleepingAllowed(); } - void SetSleepingAllowed(bool flag) { KGE_ASSERT(body_); body_->SetSleepingAllowed(flag); } + /// \~chinese + /// @brief ÊÇ·ñÊÇ×Óµ¯ÎïÌå + bool IsBullet() const; - // »î¶¯×´Ì¬ - bool IsActive() const { KGE_ASSERT(body_); return body_->IsActive(); } - void SetActive(bool flag) { KGE_ASSERT(body_); body_->SetActive(flag); } + /// \~chinese + /// @brief ÉèÖÃÎïÌåÊÇ·ñÊÇ×Óµ¯ÎïÌå + void SetBullet(bool flag); - Actor* GetActor() const { return actor_; } - void SetActor(Actor* actor) { actor_ = actor; } + /// \~chinese + /// @brief ÊÇ·ñ´¦ÓÚ»½ÐÑ״̬ + bool IsAwake() const; - b2Body* GetB2Body() { return body_; } - const b2Body* GetB2Body() const { return body_; } - void SetB2Body(b2Body* body); + /// \~chinese + /// @brief ÉèÖû½ÐÑ״̬ + void SetAwake(bool flag); - World* GetWorld() { return world_; } - const World* GetWorld() const { return world_; } + /// \~chinese + /// @brief ÊÇ·ñÆôÓÃÐÝÃß + bool IsSleepingAllowed() const; - void Destroy(); + /// \~chinese + /// @brief ÉèÖÃÊÇ·ñÔÊÐíÐÝÃß + void SetSleepingAllowed(bool flag); + /// \~chinese + /// @brief ÊÇ·ñÆôÓà + bool IsActive() const; + + /// \~chinese + /// @brief ÉèÖÃÆôÓÃ״̬ + void SetActive(bool flag); + + /// \~chinese + /// @brief »ñÈ¡ÎïÌåËùÔÚÎïÀíÊÀ½ç + World* GetWorld() const; + + /// \~chinese + /// @brief »ñÈ¡ÎïÌå°ó¶¨µÄ½ÇÉ« + Actor* GetActor() const; + + /// \~chinese + /// @brief ÉèÖÃÎïÌå°ó¶¨µÄ½ÇÉ« + void SetActor(Actor* actor); + + /// \~chinese + /// @brief ½«ÎïÌåÐÅÏ¢¸üе½½ÇÉ« void UpdateActor(); + + /// \~chinese + /// @brief ½«½ÇÉ«ÐÅÏ¢¸üе½ÎïÌå void UpdateFromActor(); - protected: + b2Body* GetB2Body() const; + void SetB2Body(b2Body* body); + + private: + /// \~chinese + /// @brief Ïú»ÙÎïÌå void UpdateFixtureFilter(b2Fixture* fixture); - protected: + /// \~chinese + /// @brief Ïú»ÙÎïÌå + void Destroy(); + + private: Actor* actor_; World* world_; b2Body* body_; @@ -173,5 +316,65 @@ namespace kiwano uint16_t mask_bits_; int16_t group_index_; }; + + /** @} */ + + inline Body::Body(World* world, ActorPtr actor) : Body(world, actor.get()) {} + + inline FixtureList Body::GetFixtureList() const { KGE_ASSERT(body_); return FixtureList(Fixture(body_->GetFixtureList())); } + + inline ContactEdgeList Body::GetContactList() const { KGE_ASSERT(body_); return ContactEdgeList(ContactEdge(body_->GetContactList())); } + + inline uint16_t Body::GetCategoryBits() const { return category_bits_; } + + inline uint16_t Body::GetMaskBits() const { return mask_bits_; } + + inline int16_t Body::GetGroupIndex() const { return group_index_; } + + inline float Body::GetBodyRotation() const { KGE_ASSERT(body_); return math::Radian2Degree(body_->GetAngle()); } + + inline void Body::SetBodyRotation(float angle) { SetBodyTransform(GetBodyPosition(), angle); } + + inline void Body::SetBodyPosition(Point const& pos) { SetBodyTransform(pos, GetBodyRotation()); } + + inline float Body::GetMass() const { KGE_ASSERT(body_); return body_->GetMass(); } + + inline float Body::GetInertia() const { KGE_ASSERT(body_); return body_->GetInertia(); } + + inline Body::Type Body::GetType() const { KGE_ASSERT(body_); return Type(body_->GetType()); } + + inline void Body::SetType(Type type) { KGE_ASSERT(body_); body_->SetType(static_cast(type)); } + + inline float Body::GetGravityScale() const { KGE_ASSERT(body_); return body_->GetGravityScale(); } + + inline void Body::SetGravityScale(float scale) { KGE_ASSERT(body_); body_->SetGravityScale(scale); } + + inline bool Body::IsIgnoreRotation() const { KGE_ASSERT(body_); return body_->IsFixedRotation(); } + + inline void Body::SetIgnoreRotation(bool flag) { KGE_ASSERT(body_); body_->SetFixedRotation(flag); } + + inline bool Body::IsBullet() const { KGE_ASSERT(body_); return body_->IsBullet(); } + + inline void Body::SetBullet(bool flag) { KGE_ASSERT(body_); body_->SetBullet(flag); } + + inline bool Body::IsAwake() const { KGE_ASSERT(body_); return body_->IsAwake(); } + + inline void Body::SetAwake(bool flag) { KGE_ASSERT(body_); body_->SetAwake(flag); } + + inline bool Body::IsSleepingAllowed() const { KGE_ASSERT(body_); return body_->IsSleepingAllowed(); } + + inline void Body::SetSleepingAllowed(bool flag) { KGE_ASSERT(body_); body_->SetSleepingAllowed(flag); } + + inline bool Body::IsActive() const { KGE_ASSERT(body_); return body_->IsActive(); } + + inline void Body::SetActive(bool flag) { KGE_ASSERT(body_); body_->SetActive(flag); } + + inline Actor* Body::GetActor() const { return actor_; } + + inline void Body::SetActor(Actor* actor) { actor_ = actor; } + + inline b2Body* Body::GetB2Body() const { return body_; } + + inline World* Body::GetWorld() const { return world_; } } } diff --git a/src/kiwano-physics/Contact.cpp b/src/kiwano-physics/Contact.cpp index b46698ce..db133c94 100644 --- a/src/kiwano-physics/Contact.cpp +++ b/src/kiwano-physics/Contact.cpp @@ -38,40 +38,26 @@ namespace kiwano SetB2Contact(contact); } - Contact Contact::GetNext() - { - KGE_ASSERT(contact_); - return Contact(contact_->GetNext()); - } - - const Contact Contact::GetNext() const - { - KGE_ASSERT(contact_); - return Contact(contact_->GetNext()); - } - - Fixture Contact::GetFixtureA() + Fixture Contact::GetFixtureA() const { KGE_ASSERT(contact_); return Fixture(contact_->GetFixtureA()); } - const Fixture Contact::GetFixtureA() const - { - KGE_ASSERT(contact_); - return Fixture(contact_->GetFixtureA()); - } - - Fixture Contact::GetFixtureB() + Fixture Contact::GetFixtureB() const { KGE_ASSERT(contact_); return Fixture(contact_->GetFixtureB()); } - const Fixture Contact::GetFixtureB() const + Body* Contact::GetBodyA() const { - KGE_ASSERT(contact_); - return Fixture(contact_->GetFixtureB()); + return GetFixtureA().GetBody(); + } + + Body* Contact::GetBodyB() const + { + return GetFixtureB().GetBody(); } void Contact::SetTangentSpeed(float speed) @@ -100,17 +86,5 @@ namespace kiwano return world->World2Stage(contact_->GetTangentSpeed()); } - - ContactEdge::ContactEdge() - : edge_(nullptr) - { - } - - ContactEdge::ContactEdge(b2ContactEdge* edge) - : ContactEdge() - { - SetB2ContactEdge(edge); - } - } } diff --git a/src/kiwano-physics/Contact.h b/src/kiwano-physics/Contact.h index 0f0ee915..68b43fd0 100644 --- a/src/kiwano-physics/Contact.h +++ b/src/kiwano-physics/Contact.h @@ -28,85 +28,223 @@ namespace kiwano { class Body; - // ½Ó´¥ + /** + * \addtogroup Physics + * @{ + */ + + /// \~chinese + /// @brief ÎïÀí½Ó´¥ class KGE_API Contact { public: Contact(); Contact(b2Contact* contact); - - // ÊÇ·ñÊǽӴ¥ - bool IsTouching() const { KGE_ASSERT(contact_); return contact_->IsTouching(); } - // ÆôÓûò½ûÓà (½ö×÷ÓÃÓÚÒ»¸öʱ¼ä²½) - void SetEnabled(bool flag) { KGE_ASSERT(contact_); contact_->SetEnabled(flag); } - bool IsEnabled() const { KGE_ASSERT(contact_); return contact_->IsEnabled(); } + /// \~chinese + /// @brief ÊÇ·ñÓÐЧ + bool IsValid() const; - // »ñÈ¡ÏÂÒ»½Ó´¥ - Contact GetNext(); - const Contact GetNext() const; + /// \~chinese + /// @brief ÊÇ·ñÊǽӴ¥ + bool IsTouching() const; - // ¼Ð¾ß A - Fixture GetFixtureA(); - const Fixture GetFixtureA() const; + /// \~chinese + /// @brief ÆôÓûò½ûÓà (½ö×÷ÓÃÓÚÒ»¸öʱ¼ä²½) + void SetEnabled(bool flag); - // ¼Ð¾ß B - Fixture GetFixtureB(); - const Fixture GetFixtureB() const; + /// \~chinese + /// @brief ÊÇ·ñÆôÓà + bool IsEnabled() const; - // Ħ²Á - void SetFriction(float friction) { KGE_ASSERT(contact_); contact_->SetFriction(friction); } - float GetFriction() const { KGE_ASSERT(contact_); return contact_->GetFriction(); } - void ResetFriction() { KGE_ASSERT(contact_); contact_->ResetFriction(); } + /// \~chinese + /// @brief »ñÈ¡ÎïÌåAµÄ¼Ð¾ß + Fixture GetFixtureA() const; - // µ¯ÐÔ»Ö¸´ - void SetRestitution(float restitution) { KGE_ASSERT(contact_); contact_->SetRestitution(restitution); } - float GetRestitution() const { KGE_ASSERT(contact_); return contact_->GetRestitution(); } - void ResetRestitution() { KGE_ASSERT(contact_); contact_->ResetRestitution(); } + /// \~chinese + /// @brief »ñÈ¡ÎïÌåBµÄ¼Ð¾ß + Fixture GetFixtureB() const; - // ÇÐÏßËÙ¶È + /// \~chinese + /// @brief »ñÈ¡ÎïÌåA + Body* GetBodyA() const; + + /// \~chinese + /// @brief »ñÈ¡ÎïÌåB + Body* GetBodyB() const; + + /// \~chinese + /// @brief ÉèÖÃĦ²ÁÁ¦ + void SetFriction(float friction); + + /// \~chinese + /// @brief »ñȡĦ²ÁÁ¦ + float GetFriction() const; + + /// \~chinese + /// @brief ÖØÖÃĦ²ÁÁ¦ + void ResetFriction(); + + /// \~chinese + /// @brief ÉèÖõ¯ÐÔ»Ö¸´ + void SetRestitution(float restitution); + + /// \~chinese + /// @brief »ñÈ¡µ¯ÐÔ»Ö¸´ + float GetRestitution() const; + + /// \~chinese + /// @brief ÖØÖõ¯ÐÔ»Ö¸´ + void ResetRestitution(); + + /// \~chinese + /// @brief ÉèÖÃÇÐÏßËÙ¶È void SetTangentSpeed(float speed); + + /// \~chinese + /// @brief »ñÈ¡ÇÐÏßËÙ¶È float GetTangentSpeed() const; - b2Contact* GetB2Contact() { return contact_; } - const b2Contact* GetB2Contact() const { return contact_; } - void SetB2Contact(b2Contact* contact) { contact_ = contact; } + b2Contact* GetB2Contact() const; + void SetB2Contact(b2Contact* contact); - protected: + bool operator== (const Contact& rhs) const; + bool operator!= (const Contact& rhs) const; + + private: b2Contact* contact_; }; - // ½Ó´¥±ß - class KGE_API ContactEdge + /// \~chinese + /// @brief ÎïÀí½Ó´¥Áбí + class ContactList + : public List { + template + class IteratorImpl + : public std::iterator + { + using herit = std::iterator; + + public: + IteratorImpl(const _Ty& elem) + : elem_(elem) + { + } + + inline typename herit::reference operator*() const + { + return const_cast(elem_); + } + + inline typename herit::pointer operator->() const + { + return std::pointer_traits::pointer_to(**this); + } + + inline IteratorImpl& operator++() + { + elem_ = elem_.GetB2Contact()->GetNext(); + return *this; + } + + inline IteratorImpl operator++(int) + { + IteratorImpl old = *this; + operator++(); + return old; + } + + inline bool operator== (const IteratorImpl& rhs) const + { + return elem_ == rhs.elem_; + } + + inline bool operator!= (const IteratorImpl& rhs) const + { + return !operator==(rhs); + } + + private: + _Ty elem_; + }; + public: - ContactEdge(); - ContactEdge(b2ContactEdge* edge); + using value_type = Contact; + using iterator = IteratorImpl; + using const_iterator = IteratorImpl; - // »ñÈ¡½Ó´¥ÎïÌå - Body* GetOtherBody() { KGE_ASSERT(edge_); return static_cast(edge_->other->GetUserData()); } - const Body* GetOtherBody() const { KGE_ASSERT(edge_); return static_cast(edge_->other->GetUserData()); } + inline ContactList() + { + } - // »ñÈ¡½Ó´¥ - Contact GetContact() { KGE_ASSERT(edge_); return Contact(edge_->contact); } - const Contact GetContact() const { KGE_ASSERT(edge_); return Contact(edge_->contact); } + inline ContactList(const value_type& first) + : first_(first) + { + } - // »ñÈ¡ÉÏÒ»½Ó´¥±ß - ContactEdge GetPrev() { KGE_ASSERT(edge_); return ContactEdge(edge_->prev); } - const ContactEdge GetPrev() const { KGE_ASSERT(edge_); return ContactEdge(edge_->prev); } + inline const value_type& front() const + { + return first_; + } - // »ñÈ¡ÏÂÒ»½Ó´¥±ß - ContactEdge GetNext() { KGE_ASSERT(edge_); return ContactEdge(edge_->next); } - const ContactEdge GetNext() const { KGE_ASSERT(edge_); return ContactEdge(edge_->next); } + inline value_type& front() + { + return first_; + } - b2ContactEdge* GetB2ContactEdge() { return edge_; } - const b2ContactEdge* GetB2ContactEdge() const { return edge_; } - void SetB2ContactEdge(b2ContactEdge* edge) { edge_ = edge; } + inline iterator begin() + { + return iterator(first_); + } - protected: - b2ContactEdge* edge_; + inline const_iterator begin() const + { + return cbegin(); + } + + inline const_iterator cbegin() const + { + return const_iterator(first_); + } + + inline iterator end() + { + return iterator(nullptr); + } + + inline const_iterator end() const + { + return cend(); + } + + inline const_iterator cend() const + { + return const_iterator(nullptr); + } + + private: + value_type first_; }; + /** @} */ + + + inline bool Contact::IsValid() const { return contact_ != nullptr;} + inline bool Contact::IsTouching() const { KGE_ASSERT(contact_); return contact_->IsTouching(); } + inline void Contact::SetEnabled(bool flag) { KGE_ASSERT(contact_); contact_->SetEnabled(flag); } + inline bool Contact::IsEnabled() const { KGE_ASSERT(contact_); return contact_->IsEnabled(); } + inline void Contact::SetFriction(float friction) { KGE_ASSERT(contact_); contact_->SetFriction(friction); } + inline float Contact::GetFriction() const { KGE_ASSERT(contact_); return contact_->GetFriction(); } + inline void Contact::ResetFriction() { KGE_ASSERT(contact_); contact_->ResetFriction(); } + inline void Contact::SetRestitution(float restitution) { KGE_ASSERT(contact_); contact_->SetRestitution(restitution); } + inline float Contact::GetRestitution() const { KGE_ASSERT(contact_); return contact_->GetRestitution(); } + inline void Contact::ResetRestitution() { KGE_ASSERT(contact_); contact_->ResetRestitution(); } + inline b2Contact* Contact::GetB2Contact() const { return contact_; } + inline void Contact::SetB2Contact(b2Contact* contact) { contact_ = contact; } + inline bool Contact::operator==(const Contact& rhs) const { return contact_ == rhs.contact_; } + inline bool Contact::operator!=(const Contact& rhs) const { return contact_ != rhs.contact_; } + } } diff --git a/src/kiwano/core/win32/helper.h b/src/kiwano-physics/ContactEdge.cpp similarity index 74% rename from src/kiwano/core/win32/helper.h rename to src/kiwano-physics/ContactEdge.cpp index a731dc96..f902edbc 100644 --- a/src/kiwano/core/win32/helper.h +++ b/src/kiwano-physics/ContactEdge.cpp @@ -18,23 +18,23 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. -#include -#include <3rd-party/StackWalker/StackWalker.h> +#include namespace kiwano { - // Display stack trace on exception - inline void ThrowIfFailed(HRESULT hr) + namespace physics { - if (FAILED(hr)) + + ContactEdge::ContactEdge() + : edge_(nullptr) { - KGE_ERROR_LOG(L"Fatal error with HRESULT of %08X", hr); - - StackWalker{}.ShowCallstack(); - - static char buffer[1024 + 1]; - sprintf_s(buffer, "Fatal error with HRESULT of %08X", hr); - throw std::runtime_error(buffer); } + + ContactEdge::ContactEdge(b2ContactEdge* edge) + : ContactEdge() + { + SetB2ContactEdge(edge); + } + } } diff --git a/src/kiwano-physics/ContactEdge.h b/src/kiwano-physics/ContactEdge.h new file mode 100644 index 00000000..09f6eccc --- /dev/null +++ b/src/kiwano-physics/ContactEdge.h @@ -0,0 +1,186 @@ +// Copyright (c) 2018-2019 Kiwano - Nomango +// +// 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. + +#pragma once +#include + +namespace kiwano +{ + namespace physics + { + /** + * \addtogroup Physics + * @{ + */ + + /// \~chinese + /// @brief ½Ó´¥±ß + class KGE_API ContactEdge + { + public: + ContactEdge(); + ContactEdge(b2ContactEdge* edge); + + /// \~chinese + /// @brief ÊÇ·ñÓÐЧ + bool IsValid() const; + + /// \~chinese + /// @brief »ñÈ¡½Ó´¥ÎïÌå + Body* GetOtherBody() const; + + /// \~chinese + /// @brief »ñÈ¡½Ó´¥ + Contact GetContact() const; + + b2ContactEdge* GetB2ContactEdge() const; + void SetB2ContactEdge(b2ContactEdge* edge); + + bool operator== (const ContactEdge& rhs) const; + bool operator!= (const ContactEdge& rhs) const; + + private: + b2ContactEdge* edge_; + }; + + + /// \~chinese + /// @brief ÎïÀí½Ó´¥±ßÁбí + class ContactEdgeList + { + template + class IteratorImpl + : public std::iterator + { + using herit = std::iterator; + + public: + inline IteratorImpl(const _Ty& elem) + : elem_(elem) + { + } + + inline typename herit::reference operator*() const + { + return const_cast(elem_); + } + + inline typename herit::pointer operator->() const + { + return std::pointer_traits::pointer_to(**this); + } + + inline IteratorImpl& operator++() + { + elem_ = elem_.GetB2ContactEdge()->next; + return *this; + } + + inline IteratorImpl operator++(int) + { + IteratorImpl old = *this; + operator++(); + return old; + } + + inline bool operator== (const IteratorImpl& rhs) const + { + return elem_ == rhs.elem_; + } + + inline bool operator!= (const IteratorImpl& rhs) const + { + return !operator==(rhs); + } + + private: + _Ty elem_; + }; + + public: + using value_type = ContactEdge; + using iterator = IteratorImpl; + using const_iterator = IteratorImpl; + + inline ContactEdgeList() + { + } + + inline ContactEdgeList(const value_type& first) + : first_(first) + { + } + + inline const value_type& front() const + { + return first_; + } + + inline value_type& front() + { + return first_; + } + + inline iterator begin() + { + return iterator(first_); + } + + inline const_iterator begin() const + { + return cbegin(); + } + + inline const_iterator cbegin() const + { + return const_iterator(first_); + } + + inline iterator end() + { + return iterator(nullptr); + } + + inline const_iterator end() const + { + return cend(); + } + + inline const_iterator cend() const + { + return const_iterator(nullptr); + } + + private: + value_type first_; + }; + + /** @} */ + + inline bool ContactEdge::IsValid() const { return edge_ != nullptr; } + inline Body* ContactEdge::GetOtherBody() const { KGE_ASSERT(edge_); return static_cast(edge_->other->GetUserData()); } + inline Contact ContactEdge::GetContact() const { KGE_ASSERT(edge_); return Contact(edge_->contact); } + inline b2ContactEdge* ContactEdge::GetB2ContactEdge() const { return edge_; } + inline void ContactEdge::SetB2ContactEdge(b2ContactEdge* edge) { edge_ = edge; } + inline bool ContactEdge::operator==(const ContactEdge& rhs) const { return edge_ == rhs.edge_; } + inline bool ContactEdge::operator!=(const ContactEdge& rhs) const { return edge_ != rhs.edge_; } + + } +} diff --git a/src/kiwano-physics/ContactEvent.cpp b/src/kiwano-physics/ContactEvent.cpp index ae7f13ac..8e0be3b1 100644 --- a/src/kiwano-physics/ContactEvent.cpp +++ b/src/kiwano-physics/ContactEvent.cpp @@ -22,19 +22,10 @@ namespace kiwano { - namespace event - { - EventType event::ContactBegin = EventType(L"ContactBegin"); - EventType event::ContactEnd = EventType(L"ContactEnd"); - } - namespace physics { - ContactBeginEvent::ContactBeginEvent() - : Event(event::ContactBegin) - , body_a(nullptr) - , body_b(nullptr) + : Event(KGE_EVENT(ContactBeginEvent)) { } @@ -42,14 +33,10 @@ namespace kiwano : ContactBeginEvent() { this->contact = contact; - body_a = this->contact.GetFixtureA().GetBody(); - body_b = this->contact.GetFixtureB().GetBody(); } ContactEndEvent::ContactEndEvent() - : Event(event::ContactEnd) - , body_a(nullptr) - , body_b(nullptr) + : Event(KGE_EVENT(ContactEndEvent)) { } @@ -57,8 +44,6 @@ namespace kiwano : ContactEndEvent() { this->contact = contact; - body_a = this->contact.GetFixtureA().GetBody(); - body_b = this->contact.GetFixtureB().GetBody(); } } diff --git a/src/kiwano-physics/ContactEvent.h b/src/kiwano-physics/ContactEvent.h index ba2488f4..79a11962 100644 --- a/src/kiwano-physics/ContactEvent.h +++ b/src/kiwano-physics/ContactEvent.h @@ -26,37 +26,37 @@ namespace kiwano { namespace physics { - // ½Ó´¥¿ªÊ¼Ê¼þ + /** + * \addtogroup Events + * @{ + */ + + /// \~chinese + /// @brief ÎïÀí½Ó´¥¿ªÊ¼Ê¼þ class KGE_API ContactBeginEvent : public Event { public: - Contact contact; - Body* body_a; - Body* body_b; + Contact contact; ///< ²úÉúµÄ½Ó´¥ ContactBeginEvent(); + ContactBeginEvent(Contact const& contact); }; - // ½Ó´¥½áÊøÊ¼þ + /// \~chinese + /// @brief ÎïÀí½Ó´¥½áÊøÊ¼þ class KGE_API ContactEndEvent : public Event { public: - Contact contact; - Body* body_a; - Body* body_b; + Contact contact; ///< ²úÉúµÄ½Ó´¥ ContactEndEvent(); + ContactEndEvent(Contact const& contact); }; - } - - namespace event - { - extern EventType ContactBegin; // ½Ó´¥¿ªÊ¼ - extern EventType ContactEnd; // ½Ó´¥½áÊø + /** @} */ } } diff --git a/src/kiwano-physics/Fixture.cpp b/src/kiwano-physics/Fixture.cpp index dc6a8c52..8eb2020b 100644 --- a/src/kiwano-physics/Fixture.cpp +++ b/src/kiwano-physics/Fixture.cpp @@ -58,30 +58,18 @@ namespace kiwano } } - Body* Fixture::GetBody() + Body* Fixture::GetBody() const { KGE_ASSERT(fixture_); return static_cast(fixture_->GetBody()->GetUserData()); } - const Body* Fixture::GetBody() const - { - KGE_ASSERT(fixture_); - return static_cast(fixture_->GetBody()->GetUserData()); - } - Shape Fixture::GetShape() const { KGE_ASSERT(fixture_); return Shape(fixture_->GetShape()); } - Fixture Fixture::GetNext() const - { - KGE_ASSERT(fixture_); - return Fixture(fixture_->GetNext()); - } - void Fixture::GetMassData(float* mass, Point* center, float* inertia) const { KGE_ASSERT(fixture_); diff --git a/src/kiwano-physics/Fixture.h b/src/kiwano-physics/Fixture.h index 2097d5a2..df8885ba 100644 --- a/src/kiwano-physics/Fixture.h +++ b/src/kiwano-physics/Fixture.h @@ -28,16 +28,24 @@ namespace kiwano { class Body; - // ¼Ð¾ß + /** + * \addtogroup Physics + * @{ + */ + + /// \~chinese + /// @brief ÎïÀí¼Ð¾ß class Fixture { public: + /// \~chinese + /// @brief ¼Ð¾ß²ÎÊý struct Param { - float density = 0.f; - float friction = 0.2f; - float restitution = 0.f; - bool is_sensor = false; + float density = 0.f; ///< ÃÜ¶È + float friction = 0.2f; ///< Ħ²ÁÁ¦ + float restitution = 0.f; ///< µ¯ÐÔ»Ö¸´ + bool is_sensor = false; ///< ÊÇ·ñÊǽӴ¥´«¸ÐÆ÷ Param() {} @@ -53,46 +61,195 @@ namespace kiwano Fixture(b2Fixture* fixture); Fixture(Body* body, Shape* shape, const Param& param); - // ÎïÌå - Body* GetBody(); - const Body* GetBody() const; + /// \~chinese + /// @brief ÊÇ·ñÓÐЧ + bool IsValid() const; - // ÐÎ×´ + /// \~chinese + /// @brief »ñÈ¡¼Ð¾ßËùÔÚµÄÎïÌå + Body* GetBody() const; + + /// \~chinese + /// @brief ÐÎ×´ Shape GetShape() const; - // ÏÂÒ»¼Ð¾ß (ͬһÎïÌåÉÏ) - Fixture GetNext() const; + /// \~chinese + /// @brief ÊÇ·ñÊǽӴ¥´«¸ÐÆ÷ + bool IsSensor() const; - // ½Ó´¥´«¸ÐÆ÷ - bool IsSensor() const { KGE_ASSERT(fixture_); return fixture_->IsSensor(); } - void SetSensor(bool sensor) { KGE_ASSERT(fixture_); fixture_->SetSensor(sensor); } + /// \~chinese + /// @brief ÉèÖüоßÊÇ·ñÊǽӴ¥´«¸ÐÆ÷ + /// @details ½Ó´¥´«¸ÐÆ÷Ö»»á²úÉúÎïÀí½Ó´¥£¬¶ø²»»áÓ°ÏìÎïÌåÔ˶¯ + void SetSensor(bool sensor); - // ÖÊÁ¿Êý¾Ý + /// \~chinese + /// @brief »ñÈ¡¼Ð¾ßµÄÖÊÁ¿Êý¾Ý void GetMassData(float* mass, Point* center, float* inertia) const; - // ÃÜ¶È - float GetDensity() const { KGE_ASSERT(fixture_); return fixture_->GetDensity(); } - void SetDensity(float density) { KGE_ASSERT(fixture_); fixture_->SetDensity(density); } + /// \~chinese + /// @brief »ñÈ¡ÃÜ¶È + float GetDensity() const; - // Ħ²ÁÁ¦ - float GetFriction() const { KGE_ASSERT(fixture_); return fixture_->GetFriction(); } - void SetFriction(float friction) { KGE_ASSERT(fixture_); fixture_->SetFriction(friction); } + /// \~chinese + /// @brief ÉèÖÃÃÜ¶È + void SetDensity(float density); - // µ¯ÐÔ»Ö¸´ - float GetRestitution() const { KGE_ASSERT(fixture_); return fixture_->GetRestitution(); } - void SetRestitution(float restitution) { KGE_ASSERT(fixture_); fixture_->SetRestitution(restitution); } + /// \~chinese + /// @brief »ñȡĦ²ÁÁ¦ [N] + float GetFriction() const; - // µã²âÊÔ + /// \~chinese + /// @brief ÉèÖÃĦ²ÁÁ¦ [N] + void SetFriction(float friction); + + /// \~chinese + /// @brief »ñÈ¡µ¯ÐÔ»Ö¸´ + float GetRestitution() const; + + /// \~chinese + /// @brief ÉèÖõ¯ÐÔ»Ö¸´ + void SetRestitution(float restitution); + + /// \~chinese + /// @brief µã²âÊÔ bool TestPoint(const Point& p) const; - bool IsValid() const { return !!fixture_; } + b2Fixture* GetB2Fixture() const; + void SetB2Fixture(b2Fixture* fixture); - b2Fixture* GetB2Fixture() { return fixture_; } - const b2Fixture* GetB2Fixture() const { return fixture_; } - void SetB2Fixture(b2Fixture* fixture) { fixture_ = fixture; } + bool operator== (const Fixture& rhs) const; + bool operator!= (const Fixture& rhs) const; - protected: + private: b2Fixture* fixture_; }; + + /// \~chinese + /// @brief ÎïÀí¼Ð¾ßÁбí + class FixtureList + : public List + { + template + class IteratorImpl + : public std::iterator + { + using herit = std::iterator; + + public: + IteratorImpl(const _Ty& elem) + : elem_(elem) + { + } + + inline typename herit::reference operator*() const + { + return const_cast(elem_); + } + + inline typename herit::pointer operator->() const + { + return std::pointer_traits::pointer_to(**this); + } + + inline IteratorImpl& operator++() + { + elem_ = elem_.GetB2Fixture()->GetNext(); + return *this; + } + + inline IteratorImpl operator++(int) + { + IteratorImpl old = *this; + operator++(); + return old; + } + + inline bool operator== (const IteratorImpl& rhs) const + { + return elem_ == rhs.elem_; + } + + inline bool operator!= (const IteratorImpl& rhs) const + { + return !operator==(rhs); + } + + private: + _Ty elem_; + }; + + public: + using value_type = Fixture; + using iterator = IteratorImpl; + using const_iterator = IteratorImpl; + + inline FixtureList() + { + } + + inline FixtureList(const value_type& first) + : first_(first) + { + } + + inline const value_type& front() const + { + return first_; + } + + inline value_type& front() + { + return first_; + } + + inline iterator begin() + { + return iterator(first_); + } + + inline const_iterator begin() const + { + return cbegin(); + } + + inline const_iterator cbegin() const + { + return const_iterator(first_); + } + + inline iterator end() + { + return iterator(nullptr); + } + + inline const_iterator end() const + { + return cend(); + } + + inline const_iterator cend() const + { + return const_iterator(nullptr); + } + + private: + value_type first_; + }; + + /** @} */ + + inline bool Fixture::IsSensor() const { KGE_ASSERT(fixture_); return fixture_->IsSensor(); } + inline void Fixture::SetSensor(bool sensor) { KGE_ASSERT(fixture_); fixture_->SetSensor(sensor); } + inline float Fixture::GetDensity() const { KGE_ASSERT(fixture_); return fixture_->GetDensity(); } + inline void Fixture::SetDensity(float density) { KGE_ASSERT(fixture_); fixture_->SetDensity(density); } + inline float Fixture::GetFriction() const { KGE_ASSERT(fixture_); return fixture_->GetFriction(); } + inline void Fixture::SetFriction(float friction) { KGE_ASSERT(fixture_); fixture_->SetFriction(friction); } + inline float Fixture::GetRestitution() const { KGE_ASSERT(fixture_); return fixture_->GetRestitution(); } + inline void Fixture::SetRestitution(float restitution) { KGE_ASSERT(fixture_); fixture_->SetRestitution(restitution); } + inline bool Fixture::IsValid() const { return fixture_ != nullptr; } + inline b2Fixture* Fixture::GetB2Fixture() const { return fixture_; } + inline void Fixture::SetB2Fixture(b2Fixture* fixture) { fixture_ = fixture; } + inline bool Fixture::operator==(const Fixture& rhs) const { return fixture_ == rhs.fixture_; } + inline bool Fixture::operator!=(const Fixture& rhs) const { return fixture_ != rhs.fixture_; } } } diff --git a/src/kiwano-physics/Joint.cpp b/src/kiwano-physics/Joint.cpp index 08be38b7..4005e078 100644 --- a/src/kiwano-physics/Joint.cpp +++ b/src/kiwano-physics/Joint.cpp @@ -126,14 +126,14 @@ namespace kiwano void DistanceJoint::SetLength(float length) { - KGE_ASSERT(raw_joint_ && world_); - raw_joint_->SetLength(world_->Stage2World(length)); + KGE_ASSERT(raw_joint_ && GetWorld()); + raw_joint_->SetLength(GetWorld()->Stage2World(length)); } float DistanceJoint::GetLength() const { - KGE_ASSERT(raw_joint_ && world_); - return world_->World2Stage(raw_joint_->GetLength()); + KGE_ASSERT(raw_joint_ && GetWorld()); + return GetWorld()->World2Stage(raw_joint_->GetLength()); } // @@ -181,14 +181,14 @@ namespace kiwano void FrictionJoint::SetMaxTorque(float length) { - KGE_ASSERT(raw_joint_ && world_); - raw_joint_->SetMaxTorque(world_->Stage2World(length)); + KGE_ASSERT(raw_joint_ && GetWorld()); + raw_joint_->SetMaxTorque(GetWorld()->Stage2World(length)); } float FrictionJoint::GetMaxTorque() const { - KGE_ASSERT(raw_joint_ && world_); - return world_->World2Stage(raw_joint_->GetMaxTorque()); + KGE_ASSERT(raw_joint_ && GetWorld()); + return GetWorld()->World2Stage(raw_joint_->GetMaxTorque()); } // @@ -207,7 +207,7 @@ namespace kiwano { } - GearJoint::GearJoint(World* world, GearJoint::Param const& param) + GearJoint::GearJoint(World* world, GearJoint::Param param) : Joint() , raw_joint_(nullptr) { @@ -260,6 +260,7 @@ namespace kiwano def.Initialize(param.body_a->GetB2Body(), param.body_b->GetB2Body()); def.maxForce = param.max_force; def.maxTorque = world->Stage2World(param.max_torque); + def.correctionFactor = param.correction_factor; Init(world, &def); raw_joint_ = static_cast(GetB2Joint()); @@ -279,14 +280,14 @@ namespace kiwano void MotorJoint::SetMaxTorque(float length) { - KGE_ASSERT(raw_joint_ && world_); - raw_joint_->SetMaxTorque(world_->Stage2World(length)); + KGE_ASSERT(raw_joint_ && GetWorld()); + raw_joint_->SetMaxTorque(GetWorld()->Stage2World(length)); } float MotorJoint::GetMaxTorque() const { - KGE_ASSERT(raw_joint_ && world_); - return world_->World2Stage(raw_joint_->GetMaxTorque()); + KGE_ASSERT(raw_joint_ && GetWorld()); + return GetWorld()->World2Stage(raw_joint_->GetMaxTorque()); } // @@ -326,32 +327,32 @@ namespace kiwano float PrismaticJoint::GetJointTranslation() const { - KGE_ASSERT(raw_joint_ && world_); - return world_->World2Stage(raw_joint_->GetJointTranslation()); + KGE_ASSERT(raw_joint_ && GetWorld()); + return GetWorld()->World2Stage(raw_joint_->GetJointTranslation()); } float PrismaticJoint::GetJointSpeed() const { - KGE_ASSERT(raw_joint_ && world_); - return world_->World2Stage(raw_joint_->GetJointSpeed()); + KGE_ASSERT(raw_joint_ && GetWorld()); + return GetWorld()->World2Stage(raw_joint_->GetJointSpeed()); } float PrismaticJoint::GetLowerLimit() const { - KGE_ASSERT(raw_joint_ && world_); - return world_->World2Stage(raw_joint_->GetLowerLimit()); + KGE_ASSERT(raw_joint_ && GetWorld()); + return GetWorld()->World2Stage(raw_joint_->GetLowerLimit()); } float PrismaticJoint::GetUpperLimit() const { - KGE_ASSERT(raw_joint_ && world_); - return world_->World2Stage(raw_joint_->GetUpperLimit()); + KGE_ASSERT(raw_joint_ && GetWorld()); + return GetWorld()->World2Stage(raw_joint_->GetUpperLimit()); } void PrismaticJoint::SetLimits(float lower, float upper) { - KGE_ASSERT(raw_joint_ && world_); - raw_joint_->SetLimits(world_->Stage2World(lower), world_->Stage2World(upper)); + KGE_ASSERT(raw_joint_ && GetWorld()); + raw_joint_->SetLimits(GetWorld()->Stage2World(lower), GetWorld()->Stage2World(upper)); } // @@ -386,14 +387,14 @@ namespace kiwano Point PulleyJoint::GetGroundAnchorA() const { - KGE_ASSERT(raw_joint_ && world_); - return world_->World2Stage(raw_joint_->GetGroundAnchorA()); + KGE_ASSERT(raw_joint_ && GetWorld()); + return GetWorld()->World2Stage(raw_joint_->GetGroundAnchorA()); } Point PulleyJoint::GetGroundAnchorB() const { - KGE_ASSERT(raw_joint_ && world_); - return world_->World2Stage(raw_joint_->GetGroundAnchorB()); + KGE_ASSERT(raw_joint_ && GetWorld()); + return GetWorld()->World2Stage(raw_joint_->GetGroundAnchorB()); } float PulleyJoint::GetRatio() const @@ -404,26 +405,26 @@ namespace kiwano float PulleyJoint::GetLengthA() const { - KGE_ASSERT(raw_joint_ && world_); - return world_->World2Stage(raw_joint_->GetLengthA()); + KGE_ASSERT(raw_joint_ && GetWorld()); + return GetWorld()->World2Stage(raw_joint_->GetLengthA()); } float PulleyJoint::GetLengthB() const { - KGE_ASSERT(raw_joint_ && world_); - return world_->World2Stage(raw_joint_->GetLengthB()); + KGE_ASSERT(raw_joint_ && GetWorld()); + return GetWorld()->World2Stage(raw_joint_->GetLengthB()); } float PulleyJoint::GetCurrentLengthA() const { - KGE_ASSERT(raw_joint_ && world_); - return world_->World2Stage(raw_joint_->GetCurrentLengthA()); + KGE_ASSERT(raw_joint_ && GetWorld()); + return GetWorld()->World2Stage(raw_joint_->GetCurrentLengthA()); } float PulleyJoint::GetCurrentLengthB() const { - KGE_ASSERT(raw_joint_ && world_); - return world_->World2Stage(raw_joint_->GetCurrentLengthB()); + KGE_ASSERT(raw_joint_ && GetWorld()); + return GetWorld()->World2Stage(raw_joint_->GetCurrentLengthB()); } // @@ -463,44 +464,44 @@ namespace kiwano float RevoluteJoint::GetJointAngle() const { - KGE_ASSERT(raw_joint_ && world_); + KGE_ASSERT(raw_joint_ && GetWorld()); return math::Radian2Degree(raw_joint_->GetJointAngle()); } float RevoluteJoint::GetJointSpeed() const { - KGE_ASSERT(raw_joint_ && world_); + KGE_ASSERT(raw_joint_ && GetWorld()); return math::Radian2Degree(raw_joint_->GetJointSpeed()); } float RevoluteJoint::GetLowerLimit() const { - KGE_ASSERT(raw_joint_ && world_); + KGE_ASSERT(raw_joint_ && GetWorld()); return math::Radian2Degree(raw_joint_->GetLowerLimit()); } float RevoluteJoint::GetUpperLimit() const { - KGE_ASSERT(raw_joint_ && world_); + KGE_ASSERT(raw_joint_ && GetWorld()); return math::Radian2Degree(raw_joint_->GetUpperLimit()); } void RevoluteJoint::SetLimits(float lower, float upper) { - KGE_ASSERT(raw_joint_ && world_); + KGE_ASSERT(raw_joint_ && GetWorld()); raw_joint_->SetLimits(math::Degree2Radian(lower), math::Degree2Radian(upper)); } void RevoluteJoint::SetMaxMotorTorque(float torque) { - KGE_ASSERT(raw_joint_ && world_); - raw_joint_->SetMaxMotorTorque(world_->Stage2World(torque)); + KGE_ASSERT(raw_joint_ && GetWorld()); + raw_joint_->SetMaxMotorTorque(GetWorld()->Stage2World(torque)); } float RevoluteJoint::GetMaxMotorTorque() const { - KGE_ASSERT(raw_joint_ && world_); - return world_->World2Stage(raw_joint_->GetMaxMotorTorque()); + KGE_ASSERT(raw_joint_ && GetWorld()); + return GetWorld()->World2Stage(raw_joint_->GetMaxMotorTorque()); } // @@ -538,14 +539,14 @@ namespace kiwano void RopeJoint::SetMaxLength(float length) { - KGE_ASSERT(raw_joint_ && world_); - raw_joint_->SetMaxLength(world_->Stage2World(length)); + KGE_ASSERT(raw_joint_ && GetWorld()); + raw_joint_->SetMaxLength(GetWorld()->Stage2World(length)); } float RopeJoint::GetMaxLength() const { - KGE_ASSERT(raw_joint_ && world_); - return world_->World2Stage(raw_joint_->GetMaxLength()); + KGE_ASSERT(raw_joint_ && GetWorld()); + return GetWorld()->World2Stage(raw_joint_->GetMaxLength()); } // @@ -579,6 +580,7 @@ namespace kiwano raw_joint_ = static_cast(GetB2Joint()); } + // // WheelJoint // @@ -615,26 +617,26 @@ namespace kiwano float WheelJoint::GetJointTranslation() const { - KGE_ASSERT(raw_joint_ && world_); - return world_->World2Stage(raw_joint_->GetJointTranslation()); + KGE_ASSERT(raw_joint_ && GetWorld()); + return GetWorld()->World2Stage(raw_joint_->GetJointTranslation()); } float WheelJoint::GetJointLinearSpeed() const { - KGE_ASSERT(raw_joint_ && world_); - return world_->World2Stage(raw_joint_->GetJointLinearSpeed()); + KGE_ASSERT(raw_joint_ && GetWorld()); + return GetWorld()->World2Stage(raw_joint_->GetJointLinearSpeed()); } void WheelJoint::SetMaxMotorTorque(float torque) { - KGE_ASSERT(raw_joint_ && world_); - raw_joint_->SetMaxMotorTorque(world_->Stage2World(torque)); + KGE_ASSERT(raw_joint_ && GetWorld()); + raw_joint_->SetMaxMotorTorque(GetWorld()->Stage2World(torque)); } float WheelJoint::GetMaxMotorTorque() const { - KGE_ASSERT(raw_joint_ && world_); - return world_->World2Stage(raw_joint_->GetMaxMotorTorque()); + KGE_ASSERT(raw_joint_ && GetWorld()); + return GetWorld()->World2Stage(raw_joint_->GetMaxMotorTorque()); } // diff --git a/src/kiwano-physics/Joint.h b/src/kiwano-physics/Joint.h index 46548a4f..85881ecc 100644 --- a/src/kiwano-physics/Joint.h +++ b/src/kiwano-physics/Joint.h @@ -39,34 +39,51 @@ namespace kiwano KGE_DECLARE_SMART_PTR(WeldJoint); KGE_DECLARE_SMART_PTR(WheelJoint); - // ¹Ø½Ú + /** + * \addtogroup Physics + * @{ + */ + + /// \~chinese + /// @brief ¹Ø½Ú class KGE_API Joint : public virtual RefCounter { public: + /// \~chinese + /// @brief ¹Ø½ÚÀàÐÍ enum class Type { - Unknown = 0, - Revolute, - Prismatic, - Distance, - Pulley, - Mouse, - Gear, - Wheel, - Weld, - Friction, - Rope, - Motor + Unknown = 0, ///< δ֪ + Revolute, ///< Ðýת¹Ø½Ú + Prismatic, ///< Æ½ÒÆ¹Ø½Ú + Distance, ///< ¹Ì¶¨¾àÀë¹Ø½Ú + Pulley, ///< »¬ÂÖ¹Ø½Ú + Mouse, ///< Êó±ê¹Ø½Ú + Gear, ///< ³ÝÂÖ¹Ø½Ú + Wheel, ///< ÂÖ¹Ø½Ú + Weld, ///< º¸½Ó¹Ø½Ú + Friction, ///< Ħ²Á¹Ø½Ú + Rope, ///< Éþ¹Ø½Ú + Motor ///< Âí´ï¹Ø½Ú }; + /// \~chinese + /// @brief ¹Ø½Ú»ù´¡²ÎÊý struct ParamBase { - Body* body_a; - Body* body_b; + Body* body_a; ///< ¹Ø½ÚÁ¬½ÓµÄÎïÌåA + Body* body_b; ///< ¹Ø½ÚÁ¬½ÓµÄÎïÌåB - ParamBase(Body* body_a, Body* body_b) : body_a(body_a), body_b(body_b) {} - ParamBase(BodyPtr body_a, BodyPtr body_b) : body_a(body_a.get()), body_b(body_b.get()) {} + ParamBase(Body* body_a, Body* body_b) + : body_a(body_a), body_b(body_b) + { + } + + ParamBase(BodyPtr body_a, BodyPtr body_b) + : body_a(body_a.get()), body_b(body_b.get()) + { + } }; Joint(); @@ -74,36 +91,46 @@ namespace kiwano Joint(World* world, b2JointDef* joint_def); virtual ~Joint(); + /// \~chinese + /// @brief ³õʼ»¯¹Ø½Ú void Init(World* world, b2JointDef* joint_def); + /// \~chinese + /// @brief »ñÈ¡¹Ø½ÚÁ¬½ÓµÄÎïÌåA BodyPtr GetBodyA() const; + + /// \~chinese + /// @brief »ñÈ¡¹Ø½ÚÁ¬½ÓµÄÎïÌåB BodyPtr GetBodyB() const; - b2Joint* GetB2Joint() { return joint_; } - const b2Joint* GetB2Joint() const { return joint_; } + /// \~chinese + /// @brief »ñÈ¡ÎïÀíÊÀ½ç + World* GetWorld() const; + + b2Joint* GetB2Joint() const; void SetB2Joint(b2Joint* joint); - World* GetWorld() { return world_; } - const World* GetWorld() const { return world_; } - - protected: + private: b2Joint* joint_; World* world_; Type type_; }; - // ¹Ì¶¨¾àÀë¹Ø½Ú + /// \~chinese + /// @brief ¹Ì¶¨¾àÀë¹Ø½Ú class KGE_API DistanceJoint : public Joint { public: + /// \~chinese + /// @brief ¹Ì¶¨¾àÀë¹Ø½Ú²ÎÊý struct Param : public Joint::ParamBase { - Point anchor_a; - Point anchor_b; - float frequency_hz; - float damping_ratio; + Point anchor_a; ///< ¹Ø½ÚÔÚÎïÌåAÉϵÄÁ¬½Óµã + Point anchor_b; ///< ¹Ø½ÚÔÚÎïÌåBÉϵÄÁ¬½Óµã + float frequency_hz; ///< ÏìÓ¦ËÙ¶È£¬ÊýÖµÔ½¸ß¹Ø½ÚÏìÓ¦µÄËÙ¶ÈÔ½¿ì£¬¿´ÉÏÈ¥Ô½¼á¹Ì + float damping_ratio; ///< ×èÄáÂÊ£¬ÖµÔ½´ó¹Ø½ÚÔ˶¯×èÄáÔ½´ó Param( Body* body_a, @@ -136,32 +163,46 @@ namespace kiwano DistanceJoint(World* world, b2DistanceJointDef* def); DistanceJoint(World* world, Param const& param); + /// \~chinese + /// @brief ÉèÖùؽڳ¤¶È void SetLength(float length); + + /// \~chinese + /// @brief »ñÈ¡¹Ø½Ú³¤¶È float GetLength() const; - // ÉèÖõ¯»É×èÄáÆ÷ƵÂÊ [ºÕ×È] - void SetFrequency(float hz) { KGE_ASSERT(raw_joint_); raw_joint_->SetFrequency(hz); } - float GetFrequency() const { KGE_ASSERT(raw_joint_); return raw_joint_->GetFrequency(); } + /// \~chinese + /// @brief ÉèÖõ¯»ÉÏìÓ¦ËÙ¶È [ºÕ×È] + void SetFrequency(float hz); - // ÉèÖÃ×èÄá±È - void SetDampingRatio(float ratio) { KGE_ASSERT(raw_joint_); raw_joint_->SetDampingRatio(ratio); } - float GetDampingRatio() const { KGE_ASSERT(raw_joint_); return raw_joint_->GetDampingRatio(); } + /// \~chinese + /// @brief »ñÈ¡µ¯»ÉÏìÓ¦ËÙ¶È [ºÕ×È] + float GetFrequency() const; - protected: + /// \~chinese + /// @brief ÉèÖÃ×èÄáÂÊ + void SetDampingRatio(float ratio); + + /// \~chinese + /// @brief »ñÈ¡×èÄáÂÊ + float GetDampingRatio() const; + + private: b2DistanceJoint* raw_joint_; }; - // Ħ²Á¹Ø½Ú + /// \~chinese + /// @brief Ħ²Á¹Ø½Ú class KGE_API FrictionJoint : public Joint { public: struct Param : public Joint::ParamBase { - Point anchor; - float max_force; - float max_torque; + Point anchor; ///< Ħ²Á×÷Óõã + float max_force; ///< ×î´óĦ²ÁÁ¦ + float max_torque; ///< ×î´óŤÁ¦ Param( Body* body_a, @@ -191,29 +232,40 @@ namespace kiwano FrictionJoint(World* world, b2FrictionJointDef* def); FrictionJoint(World* world, Param const& param); - // É趨×î´óĦ²ÁÁ¦ + /// \~chinese + /// @brief ÉèÖÃ×î´óĦ²ÁÁ¦ void SetMaxForce(float force); + + /// \~chinese + /// @brief »ñÈ¡×î´óĦ²ÁÁ¦ float GetMaxForce() const; - // É趨×î´óת¾Ø + /// \~chinese + /// @brief ÉèÖÃ×î´óת¾Ø void SetMaxTorque(float torque); + + /// \~chinese + /// @brief »ñÈ¡×î´óת¾Ø float GetMaxTorque() const; - protected: + private: b2FrictionJoint* raw_joint_; }; - // ³ÝÂÖ¹Ø½Ú + /// \~chinese + /// @brief ³ÝÂÖ¹Ø½Ú class KGE_API GearJoint : public Joint { public: + /// \~chinese + /// @brief ³ÝÂֹؽڲÎÊý struct Param : public Joint::ParamBase { - JointPtr joint_a; - JointPtr joint_b; - float ratio; + JointPtr joint_a; ///< ¹Ø½ÚA£¨Ðýת¹Ø½Ú/Æ½ÒÆ¹Ø½Ú£© + JointPtr joint_b; ///< ¹Ø½ÚB£¨Ðýת¹Ø½Ú/Æ½ÒÆ¹Ø½Ú£© + float ratio; ///< ³ÝÂÖ´«¶¯±È Param( Joint* joint_a, @@ -237,27 +289,34 @@ namespace kiwano GearJoint(); GearJoint(World* world, b2GearJointDef* def); - GearJoint(World* world, Param const& param); + GearJoint(World* world, Param param); - // É趨³ÝÂÖ´«¶¯±È + /// \~chinese + /// @brief É趨³ÝÂÖ´«¶¯±È void SetRatio(float ratio); + + /// \~chinese + /// @brief »ñÈ¡³ÝÂÖ´«¶¯±È float GetRatio() const; - protected: + private: b2GearJoint* raw_joint_; }; - // Âí´ï¹Ø½Ú + /// \~chinese + /// @brief Âí´ï¹Ø½Ú class KGE_API MotorJoint : public Joint { public: + /// \~chinese + /// @brief Âí´ï¹Ø½Ú²ÎÊý struct Param : public Joint::ParamBase { - float max_force; - float max_torque; - float correction_factor; + float max_force; ///< ×î´óĦ²ÁÁ¦ + float max_torque; ///< ×î´óת¾Ø + float correction_factor; ///< λÖýÃÕýÒò×Ó£¨·¶Î§ 0-1£© Param( Body* body_a, @@ -287,34 +346,45 @@ namespace kiwano MotorJoint(World* world, b2MotorJointDef* def); MotorJoint(World* world, Param const& param); - // É趨×î´óĦ²ÁÁ¦ + /// \~chinese + /// @brief ÉèÖÃ×î´óĦ²ÁÁ¦ void SetMaxForce(float force); + + /// \~chinese + /// @brief »ñÈ¡×î´óĦ²ÁÁ¦ float GetMaxForce() const; - // É趨×î´óת¾Ø + /// \~chinese + /// @brief ÉèÖÃ×î´óת¾Ø void SetMaxTorque(float torque); + + /// \~chinese + /// @brief »ñÈ¡×î´óת¾Ø float GetMaxTorque() const; - protected: + private: b2MotorJoint* raw_joint_; }; - // Æ½ÒÆ¹Ø½Ú + /// \~chinese + /// @brief Æ½ÒÆ¹Ø½Ú class KGE_API PrismaticJoint : public Joint { public: + /// \~chinese + /// @brief Æ½ÒÆ¹Ø½Ú²ÎÊý struct Param : public Joint::ParamBase { - Point anchor; - Vec2 axis; - bool enable_limit; - float lower_translation; - float upper_translation; - bool enable_motor; - float max_motor_force; - float motor_speed; + Point anchor; ///< ¹Ø½ÚλÖà + Vec2 axis; ///< ÎïÌåA»¬¶¯µÄ·½Ïò + bool enable_limit; ///< ÊÇ·ñÆôÓÃÏÞÖÆ + float lower_translation; ///< ÒÆ¶¯µÄ×îСÏÞÖÆ£¬Óë·½ÏòͬÏòΪÕý£¬·´ÏòΪ¸º£¬ÆôÓÃÏÞÖÆºó²ÅÓÐЧ¹û + float upper_translation; ///< ÒÆ¶¯µÄ×î´óÏÞÖÆ£¬Óë·½ÏòͬÏòΪÕý£¬·´ÏòΪ¸º£¬ÆôÓÃÏÞÖÆºó²ÅÓÐЧ¹û + bool enable_motor; ///< ÊÇ·ñÆôÓÃÂí´ï + float max_motor_force; ///< ×î´óÂí´ïÁ¦ [N] + float motor_speed; ///< Âí´ïתËÙ [degree/s] Param( Body* body_a, @@ -359,45 +429,82 @@ namespace kiwano PrismaticJoint(World* world, b2PrismaticJointDef* def); PrismaticJoint(World* world, Param const& param); - float GetReferenceAngle() const { KGE_ASSERT(raw_joint_); return math::Radian2Degree(raw_joint_->GetReferenceAngle()); } + /// \~chinese + /// @brief »ñÈ¡²Î¿¼½Ç + float GetReferenceAngle() const; + + /// \~chinese + /// @brief »ñÈ¡¹Ø½Úת»» float GetJointTranslation() const; + + /// \~chinese + /// @brief »ñÈ¡¹Ø½ÚËÙ¶È float GetJointSpeed() const; - bool IsLimitEnabled() const { KGE_ASSERT(raw_joint_); return raw_joint_->IsLimitEnabled(); } - void EnableLimit(bool flag) { KGE_ASSERT(raw_joint_); raw_joint_->EnableLimit(flag); } + /// \~chinese + /// @brief ÊÇ·ñÆôÓùؽÚÏÞÖÆ + bool IsLimitEnabled() const; + /// \~chinese + /// @brief ÉèÖÃÊÇ·ñÆôÓùؽÚÏÞÖÆ + void EnableLimit(bool flag); + + /// \~chinese + /// @brief »ñÈ¡Æ½ÒÆ×îСÏÞÖÆ float GetLowerLimit() const; + + /// \~chinese + /// @brief »ñÈ¡Æ½ÒÆ×î´óÏÞÖÆ float GetUpperLimit() const; + + /// \~chinese + /// @brief ÉèÖùؽÚÏÞÖÆ void SetLimits(float lower, float upper); - bool IsMotorEnabled() const { KGE_ASSERT(raw_joint_); return raw_joint_->IsMotorEnabled(); } - void EnableMotor(bool flag) { KGE_ASSERT(raw_joint_); raw_joint_->EnableMotor(flag); } + /// \~chinese + /// @brief ÊÇ·ñÆôÓÃÂí´ï + bool IsMotorEnabled() const; - // ÉèÖÃÂí´ïתËÙ [degree/s] - void SetMotorSpeed(float speed) { KGE_ASSERT(raw_joint_); raw_joint_->SetMotorSpeed(math::Degree2Radian(speed)); } - float GetMotorSpeed() const { KGE_ASSERT(raw_joint_); return math::Radian2Degree(raw_joint_->GetMotorSpeed()); } + /// \~chinese + /// @brief ÉèÖÃÊÇ·ñÆôÓÃÂí´ï + void EnableMotor(bool flag); - // É趨×î´óÂí´ïÁ¦ [N] - void SetMaxMotorForce(float force) { KGE_ASSERT(raw_joint_); raw_joint_->SetMaxMotorForce(force); } - float GetMaxMotorForce() const { KGE_ASSERT(raw_joint_); return raw_joint_->GetMaxMotorForce(); } + /// \~chinese + /// @brief ÉèÖÃÂí´ïתËÙ [degree/s] + void SetMotorSpeed(float speed); - protected: + /// \~chinese + /// @brief »ñÈ¡Âí´ïתËÙ [degree/s] + float GetMotorSpeed() const; + + /// \~chinese + /// @brief ÉèÖÃ×î´óÂí´ïÁ¦ [N] + void SetMaxMotorForce(float force); + + /// \~chinese + /// @brief »ñÈ¡×î´óÂí´ïÁ¦ [N] + float GetMaxMotorForce() const; + + private: b2PrismaticJoint* raw_joint_; }; - // »¬ÂÖ¹Ø½Ú + /// \~chinese + /// @brief »¬ÂÖ¹Ø½Ú class KGE_API PulleyJoint : public Joint { public: + /// \~chinese + /// @brief »¬ÂֹؽڲÎÊý struct Param : public Joint::ParamBase { - Point anchor_a; - Point anchor_b; - Point ground_anchor_a; - Point ground_anchor_b; - float ratio; + Point anchor_a; ///< ¹Ø½ÚÔÚÎïÌåAÉϵÄ×÷Óõã + Point anchor_b; ///< ¹Ø½ÚÔÚÎïÌåBÉϵÄ×÷Óõã + Point ground_anchor_a; ///< ÎïÌåA¶ÔÓ¦µÄ»¬ÂÖµÄλÖà + Point ground_anchor_b; ///< ÎïÌåB¶ÔÓ¦µÄ»¬ÂÖµÄλÖà + float ratio; ///< »¬Âֱȣ¬¹Ø½Ú´«¶¯Ê±£¬»¬ÂÖÉÏÉýºÍϽµµÄÁ½Í·µÄÎ»ÒÆ±ÈÀý Param( Body* body_a, @@ -433,36 +540,56 @@ namespace kiwano PulleyJoint(World* world, b2PulleyJointDef* def); PulleyJoint(World* world, Param const& param); + /// \~chinese + /// @brief ÎïÌåA¶ÔÓ¦µÄ»¬ÂÖµÄλÖà Point GetGroundAnchorA() const; + + /// \~chinese + /// @brief ÎïÌåB¶ÔÓ¦µÄ»¬ÂÖµÄλÖà Point GetGroundAnchorB() const; + /// \~chinese + /// @brief »ñÈ¡»¬ÂÖ´«¶¯±È float GetRatio() const; + /// \~chinese + /// @brief »ñÈ¡ÎïÌåAÓ뻬ÂֵľàÀë float GetLengthA() const; + + /// \~chinese + /// @brief »ñÈ¡ÎïÌåBÓ뻬ÂֵľàÀë float GetLengthB() const; + /// \~chinese + /// @brief »ñÈ¡ÎïÌåAÓ뻬Âֵĵ±Ç°¾àÀë float GetCurrentLengthA() const; + + /// \~chinese + /// @brief »ñÈ¡ÎïÌåBÓ뻬Âֵĵ±Ç°¾àÀë float GetCurrentLengthB() const; - protected: + private: b2PulleyJoint* raw_joint_; }; - // Ðýת¹Ø½Ú + /// \~chinese + /// @brief Ðýת¹Ø½Ú class KGE_API RevoluteJoint : public Joint { public: + /// \~chinese + /// @brief Ðýת¹Ø½Ú²ÎÊý struct Param : public Joint::ParamBase { - Point anchor; - bool enable_limit; - float lower_angle; - float upper_angle; - bool enable_motor; - float max_motor_torque; - float motor_speed; + Point anchor; ///< ¹Ø½ÚλÖà + bool enable_limit; ///< ÊÇ·ñÆôÓÃÏÞÖÆ + float lower_angle; ///< ÒÆ¶¯µÄ×îСÏÞÖÆ£¬Óë·½ÏòͬÏòΪÕý£¬·´ÏòΪ¸º£¬ÆôÓÃÏÞÖÆºó²ÅÓÐЧ¹û + float upper_angle; ///< ÒÆ¶¯µÄ×î´óÏÞÖÆ£¬Óë·½ÏòͬÏòΪÕý£¬·´ÏòΪ¸º£¬ÆôÓÃÏÞÖÆºó²ÅÓÐЧ¹û + bool enable_motor; ///< ÊÇ·ñÆôÓÃÂí´ï + float max_motor_torque; ///< ×î´óÂí´ïÁ¦ [N] + float motor_speed; ///< Âí´ïתËÙ [degree/s] Param( Body* body_a, @@ -504,43 +631,80 @@ namespace kiwano RevoluteJoint(World* world, b2RevoluteJointDef* def); RevoluteJoint(World* world, Param const& param); - float GetReferenceAngle() const { KGE_ASSERT(raw_joint_); return math::Radian2Degree(raw_joint_->GetReferenceAngle()); } + /// \~chinese + /// @brief »ñÈ¡²Î¿¼½Ç + float GetReferenceAngle() const; + + /// \~chinese + /// @brief »ñÈ¡¹Ø½Ú½Ç¶È float GetJointAngle() const; + + /// \~chinese + /// @brief »ñÈ¡¹Ø½ÚËÙ¶È float GetJointSpeed() const; - bool IsLimitEnabled() const { KGE_ASSERT(raw_joint_); return raw_joint_->IsLimitEnabled(); } - void EnableLimit(bool flag) { KGE_ASSERT(raw_joint_); raw_joint_->EnableLimit(flag); } + /// \~chinese + /// @brief ÊÇ·ñÆôÓùؽÚÏÞÖÆ + bool IsLimitEnabled() const; + /// \~chinese + /// @brief ÉèÖÃÊÇ·ñÆôÓùؽÚÏÞÖÆ + void EnableLimit(bool flag); + + /// \~chinese + /// @brief »ñÈ¡Æ½ÒÆ×îСÏÞÖÆ float GetLowerLimit() const; + + /// \~chinese + /// @brief »ñÈ¡Æ½ÒÆ×î´óÏÞÖÆ float GetUpperLimit() const; + + /// \~chinese + /// @brief ÉèÖùؽÚÏÞÖÆ void SetLimits(float lower, float upper); - bool IsMotorEnabled() const { KGE_ASSERT(raw_joint_); return raw_joint_->IsMotorEnabled(); } - void EnableMotor(bool flag) { KGE_ASSERT(raw_joint_); raw_joint_->EnableMotor(flag); } + /// \~chinese + /// @brief ÊÇ·ñÆôÓÃÂí´ï + bool IsMotorEnabled() const; - // ÉèÖÃÂí´ïתËÙ [degree/s] - void SetMotorSpeed(float speed) { KGE_ASSERT(raw_joint_); raw_joint_->SetMotorSpeed(math::Degree2Radian(speed)); } - float GetMotorSpeed() const { KGE_ASSERT(raw_joint_); return math::Radian2Degree(raw_joint_->GetMotorSpeed()); } + /// \~chinese + /// @brief ÉèÖÃÊÇ·ñÆôÓÃÂí´ï + void EnableMotor(bool flag); - // É趨×î´óÂí´ïת¾Ø [N/m] + /// \~chinese + /// @brief ÉèÖÃÂí´ïתËÙ [degree/s] + void SetMotorSpeed(float speed); + + /// \~chinese + /// @brief »ñÈ¡Âí´ïתËÙ [degree/s] + float GetMotorSpeed() const; + + /// \~chinese + /// @brief ÉèÖÃ×î´óÂí´ïת¾Ø [N/m] void SetMaxMotorTorque(float torque); + + /// \~chinese + /// @brief »ñÈ¡×î´óÂí´ïת¾Ø [N/m] float GetMaxMotorTorque() const; - protected: + private: b2RevoluteJoint* raw_joint_; }; - // Éþ¹Ø½Ú + /// \~chinese + /// @brief Éþ¹Ø½Ú class KGE_API RopeJoint : public Joint { public: + /// \~chinese + /// @brief Éþ¹Ø½Ú²ÎÊý struct Param : public Joint::ParamBase { - Point local_anchor_a; - Point local_anchor_b; - float max_length; + Point local_anchor_a; ///< ¹Ø½ÚÔÚÎïÌåAÉϵÄÁ¬½Óµã + Point local_anchor_b; ///< ¹Ø½ÚÔÚÎïÌåBÉϵÄÁ¬½Óµã + float max_length; ///< ÉþË÷×î´ó³¤¶È Param( Body* body_a, @@ -570,24 +734,32 @@ namespace kiwano RopeJoint(World* world, b2RopeJointDef* def); RopeJoint(World* world, Param const& param); + /// \~chinese + /// @brief ÉèÖùؽÚ×î´ó³¤¶È void SetMaxLength(float length); + + /// \~chinese + /// @brief »ñÈ¡¹Ø½Ú×î´ó³¤¶È float GetMaxLength() const; - protected: + private: b2RopeJoint* raw_joint_; }; - // º¸½Ó¹Ø½Ú + /// \~chinese + /// @brief º¸½Ó¹Ø½Ú class KGE_API WeldJoint : public Joint { public: + /// \~chinese + /// @brief º¸½Ó¹Ø½Ú²ÎÊý struct Param : public Joint::ParamBase { - Point anchor; - float frequency_hz; - float damping_ratio; + Point anchor; ///< º¸½ÓλÖà + float frequency_hz; ///< ÏìÓ¦ËÙ¶È£¬ÊýÖµÔ½¸ß¹Ø½ÚÏìÓ¦µÄËÙ¶ÈÔ½¿ì£¬¿´ÉÏÈ¥Ô½¼á¹Ì + float damping_ratio; ///< ×èÄáÂÊ£¬ÖµÔ½´ó¹Ø½ÚÔ˶¯×èÄáÔ½´ó Param( Body* body_a, @@ -617,33 +789,48 @@ namespace kiwano WeldJoint(World* world, b2WeldJointDef* def); WeldJoint(World* world, Param const& param); - // ÉèÖõ¯»É×èÄáÆ÷ƵÂÊ [ºÕ×È] - void SetFrequency(float hz) { KGE_ASSERT(raw_joint_); raw_joint_->SetFrequency(hz); } - float GetFrequency() const { KGE_ASSERT(raw_joint_); return raw_joint_->GetFrequency(); } + /// \~chinese + /// @brief »ñÈ¡ÎïÌåBÏà¶ÔÓÚÎïÌåAµÄ½Ç¶È + float GetReferenceAngle() const; - // ÉèÖÃ×èÄá±È - void SetDampingRatio(float ratio) { KGE_ASSERT(raw_joint_); raw_joint_->SetDampingRatio(ratio); } - float GetDampingRatio() const { KGE_ASSERT(raw_joint_); return raw_joint_->GetDampingRatio(); } + /// \~chinese + /// @brief ÉèÖõ¯»ÉÏìÓ¦ËÙ¶È [ºÕ×È] + void SetFrequency(float hz); - protected: + /// \~chinese + /// @brief »ñÈ¡µ¯»ÉÏìÓ¦ËÙ¶È [ºÕ×È] + float GetFrequency() const; + + /// \~chinese + /// @brief ÉèÖÃ×èÄáÂÊ + void SetDampingRatio(float ratio); + + /// \~chinese + /// @brief »ñÈ¡×èÄáÂÊ + float GetDampingRatio() const; + + private: b2WeldJoint* raw_joint_; }; - // ÂÖ¹Ø½Ú + /// \~chinese + /// @brief ÂÖ¹Ø½Ú class KGE_API WheelJoint : public Joint { public: + /// \~chinese + /// @brief ÂֹؽڲÎÊý struct Param : public Joint::ParamBase { - Point anchor; - Vec2 axis; - bool enable_motor; - float max_motor_torque; - float motor_speed; - float frequency_hz; - float damping_ratio; + Point anchor; ///< ÂֹؽÚλÖà + Vec2 axis; ///< ÎïÌåA»¬¶¯·½Ïò + bool enable_motor; ///< ÊÇ·ñÆôÓÃÂí´ï + float max_motor_torque; ///< ×î´óÂí´ïÁ¦ [N] + float motor_speed; ///< Âí´ïתËÙ [degree/s] + float frequency_hz; ///< ÏìÓ¦ËÙ¶È£¬ÊýÖµÔ½¸ß¹Ø½ÚÏìÓ¦µÄËÙ¶ÈÔ½¿ì£¬¿´ÉÏÈ¥Ô½¼á¹Ì + float damping_ratio; ///< µ¯»É×èÄáÂÊ£¬ÖµÔ½´ó¹Ø½ÚÔ˶¯×èÄáÔ½´ó Param( Body* body_a, @@ -685,45 +872,82 @@ namespace kiwano WheelJoint(World* world, b2WheelJointDef* def); WheelJoint(World* world, Param const& param); + /// \~chinese + /// @brief »ñÈ¡¹Ø½Úµ±Ç°µÄÆ½ÒÆ¾àÀë float GetJointTranslation() const; + + /// \~chinese + /// @brief »ñÈ¡¹Ø½Úµ±Ç°µÄÏßÐÔËÙ¶È float GetJointLinearSpeed() const; - float GetJointAngle() const { KGE_ASSERT(raw_joint_); return math::Radian2Degree(raw_joint_->GetJointAngle()); } - float GetJointAngularSpeed() const { KGE_ASSERT(raw_joint_); return math::Radian2Degree(raw_joint_->GetJointAngularSpeed()); } - bool IsMotorEnabled() const { KGE_ASSERT(raw_joint_); return raw_joint_->IsMotorEnabled(); } - void EnableMotor(bool flag) { KGE_ASSERT(raw_joint_); raw_joint_->EnableMotor(flag); } + /// \~chinese + /// @brief »ñÈ¡¹Ø½Úµ±Ç°µÄ½Ç¶È + float GetJointAngle() const; - // ÉèÖÃÂí´ïתËÙ [degree/s] - void SetMotorSpeed(float speed) { KGE_ASSERT(raw_joint_); raw_joint_->SetMotorSpeed(math::Degree2Radian(speed)); } - float GetMotorSpeed() const { KGE_ASSERT(raw_joint_); return math::Radian2Degree(raw_joint_->GetMotorSpeed()); } + /// \~chinese + /// @brief »ñÈ¡¹Ø½Úµ±Ç°µÄÐýתËÙ¶È + float GetJointAngularSpeed() const; - // É趨×î´óÂí´ïת¾Ø [N/m] + /// \~chinese + /// @brief ÊÇ·ñÆôÓÃÂí´ï + bool IsMotorEnabled() const; + + /// \~chinese + /// @brief ÉèÖÃÊÇ·ñÆôÓÃÂí´ï + void EnableMotor(bool flag); + + /// \~chinese + /// @brief ÉèÖÃÂí´ïתËÙ [degree/s] + void SetMotorSpeed(float speed); + + /// \~chinese + /// @brief »ñÈ¡Âí´ïתËÙ [degree/s] + float GetMotorSpeed() const; + + /// \~chinese + /// @brief ÉèÖÃ×î´óÂí´ïת¾Ø [N/m] void SetMaxMotorTorque(float torque); + + /// \~chinese + /// @brief »ñÈ¡×î´óÂí´ïת¾Ø [N/m] float GetMaxMotorTorque() const; - void SetSpringFrequencyHz(float hz) { KGE_ASSERT(raw_joint_); raw_joint_->SetSpringFrequencyHz(hz); } - float GetSpringFrequencyHz() const { KGE_ASSERT(raw_joint_); return raw_joint_->GetSpringFrequencyHz(); } + /// \~chinese + /// @brief ÉèÖõ¯»ÉÏìÓ¦ËÙ¶È + void SetSpringFrequencyHz(float hz); - void SetSpringDampingRatio(float ratio) { KGE_ASSERT(raw_joint_); raw_joint_->SetSpringDampingRatio(ratio); } - float GetSpringDampingRatio() const { KGE_ASSERT(raw_joint_); return raw_joint_->GetSpringDampingRatio(); } + /// \~chinese + /// @brief »ñÈ¡µ¯»ÉÏìÓ¦ËÙ¶È + float GetSpringFrequencyHz() const; - protected: + /// \~chinese + /// @brief ÉèÖõ¯»É×èÄáÂÊ + void SetSpringDampingRatio(float ratio); + + /// \~chinese + /// @brief »ñÈ¡µ¯»É×èÄáÂÊ + float GetSpringDampingRatio() const; + + private: b2WheelJoint* raw_joint_; }; - // Êó±ê¹Ø½Ú - // ÓÃÓÚʹÉíÌåµÄij¸öµã×·×ÙÊÀ½çÉϵÄÖ¸¶¨µã£¬ÀýÈçÈÃÎïÌå×·×ÙÊó±êλÖà + /// \~chinese + /// @brief Êó±ê¹Ø½Ú + /// @details ÓÃÓÚʹÉíÌåµÄij¸öµã×·×ÙÊÀ½çÉϵÄÖ¸¶¨µã£¬ÀýÈçÈÃÎïÌå×·×ÙÊó±êλÖà class KGE_API MouseJoint : public Joint { public: + /// \~chinese + /// @brief Êó±ê¹Ø½Ú²ÎÊý struct Param : public Joint::ParamBase { - Point target; - float max_force; - float frequency_hz; - float damping_ratio; + Point target; ///< ¹Ø½Ú×÷ÓÃÄ¿±êλÖà + float max_force; ///< ×÷ÓÃÔÚÎïÌåAÉϵÄ×î´óÁ¦ + float frequency_hz; ///< ÏìÓ¦ËÙ¶È£¬ÊýÖµÔ½¸ß¹Ø½ÚÏìÓ¦µÄËÙ¶ÈÔ½¿ì£¬¿´ÉÏÈ¥Ô½¼á¹Ì + float damping_ratio; ///< ×èÄáÂÊ£¬ÖµÔ½´ó¹Ø½ÚÔ˶¯×èÄáÔ½´ó Param( Body* body_a, @@ -740,14 +964,7 @@ namespace kiwano , damping_ratio(damping_ratio) {} - Param( - BodyPtr body_a, - BodyPtr body_b, - Point const& target, - float max_force, - float frequency_hz = 5.0f, - float damping_ratio = 0.7f - ) + Param(BodyPtr body_a, BodyPtr body_b, Point const& target, float max_force, float frequency_hz = 5.0f, float damping_ratio = 0.7f) : Param(body_a.get(), body_b.get(), target, max_force, frequency_hz, damping_ratio) {} }; @@ -756,20 +973,83 @@ namespace kiwano MouseJoint(World* world, b2MouseJointDef* def); MouseJoint(World* world, Param const& param); - // É趨×î´óĦ²ÁÁ¦ [N] + /// \~chinese + /// @brief É趨×î´óĦ²ÁÁ¦ [N] void SetMaxForce(float force); + + /// \~chinese + /// @brief »ñÈ¡×î´óĦ²ÁÁ¦ [N] float GetMaxForce() const; - // ÉèÖÃÏìÓ¦ËÙ¶È [hz] - void SetFrequency(float hz) { KGE_ASSERT(raw_joint_); raw_joint_->SetFrequency(hz); } - float GetFrequency() const { KGE_ASSERT(raw_joint_); return raw_joint_->GetFrequency(); } + /// \~chinese + /// @brief ÉèÖÃÏìÓ¦ËÙ¶È [hz] + void SetFrequency(float hz); - // ÉèÖÃ×èÄá±È - void SetDampingRatio(float ratio) { KGE_ASSERT(raw_joint_); raw_joint_->SetDampingRatio(ratio); } - float GetDampingRatio() const { KGE_ASSERT(raw_joint_); return raw_joint_->GetDampingRatio(); } + /// \~chinese + /// @brief »ñÈ¡ÏìÓ¦ËÙ¶È [hz] + float GetFrequency() const; - protected: + /// \~chinese + /// @brief ÉèÖÃ×èÄáÂÊ + void SetDampingRatio(float ratio); + + /// \~chinese + /// @brief »ñÈ¡×èÄáÂÊ + float GetDampingRatio() const; + + private: b2MouseJoint* raw_joint_; }; + + /** @} */ + + + inline b2Joint* Joint::GetB2Joint() const { return joint_; } + inline World* Joint::GetWorld() const { return world_; } + + inline void DistanceJoint::SetFrequency(float hz) { KGE_ASSERT(raw_joint_); raw_joint_->SetFrequency(hz); } + inline float DistanceJoint::GetFrequency() const { KGE_ASSERT(raw_joint_); return raw_joint_->GetFrequency(); } + inline void DistanceJoint::SetDampingRatio(float ratio) { KGE_ASSERT(raw_joint_); raw_joint_->SetDampingRatio(ratio); } + inline float DistanceJoint::GetDampingRatio() const { KGE_ASSERT(raw_joint_); return raw_joint_->GetDampingRatio(); } + + inline float PrismaticJoint::GetReferenceAngle() const { KGE_ASSERT(raw_joint_); return math::Radian2Degree(raw_joint_->GetReferenceAngle()); } + inline bool PrismaticJoint::IsLimitEnabled() const { KGE_ASSERT(raw_joint_); return raw_joint_->IsLimitEnabled(); } + inline void PrismaticJoint::EnableLimit(bool flag) { KGE_ASSERT(raw_joint_); raw_joint_->EnableLimit(flag); } + inline bool PrismaticJoint::IsMotorEnabled() const { KGE_ASSERT(raw_joint_); return raw_joint_->IsMotorEnabled(); } + inline void PrismaticJoint::EnableMotor(bool flag) { KGE_ASSERT(raw_joint_); raw_joint_->EnableMotor(flag); } + inline void PrismaticJoint::SetMotorSpeed(float speed) { KGE_ASSERT(raw_joint_); raw_joint_->SetMotorSpeed(math::Degree2Radian(speed)); } + inline float PrismaticJoint::GetMotorSpeed() const { KGE_ASSERT(raw_joint_); return math::Radian2Degree(raw_joint_->GetMotorSpeed()); } + inline void PrismaticJoint::SetMaxMotorForce(float force) { KGE_ASSERT(raw_joint_); raw_joint_->SetMaxMotorForce(force); } + inline float PrismaticJoint::GetMaxMotorForce() const { KGE_ASSERT(raw_joint_); return raw_joint_->GetMaxMotorForce(); } + + inline float RevoluteJoint::GetReferenceAngle() const { KGE_ASSERT(raw_joint_); return math::Radian2Degree(raw_joint_->GetReferenceAngle()); } + inline bool RevoluteJoint::IsLimitEnabled() const { KGE_ASSERT(raw_joint_); return raw_joint_->IsLimitEnabled(); } + inline void RevoluteJoint::EnableLimit(bool flag) { KGE_ASSERT(raw_joint_); raw_joint_->EnableLimit(flag); } + inline bool RevoluteJoint::IsMotorEnabled() const { KGE_ASSERT(raw_joint_); return raw_joint_->IsMotorEnabled(); } + inline void RevoluteJoint::EnableMotor(bool flag) { KGE_ASSERT(raw_joint_); raw_joint_->EnableMotor(flag); } + inline void RevoluteJoint::SetMotorSpeed(float speed) { KGE_ASSERT(raw_joint_); raw_joint_->SetMotorSpeed(math::Degree2Radian(speed)); } + inline float RevoluteJoint::GetMotorSpeed() const { KGE_ASSERT(raw_joint_); return math::Radian2Degree(raw_joint_->GetMotorSpeed()); } + + inline float WeldJoint::GetReferenceAngle() const { KGE_ASSERT(raw_joint_); return math::Radian2Degree(raw_joint_->GetReferenceAngle()); } + inline void WeldJoint::SetFrequency(float hz) { KGE_ASSERT(raw_joint_); raw_joint_->SetFrequency(hz); } + inline float WeldJoint::GetFrequency() const { KGE_ASSERT(raw_joint_); return raw_joint_->GetFrequency(); } + inline void WeldJoint::SetDampingRatio(float ratio) { KGE_ASSERT(raw_joint_); raw_joint_->SetDampingRatio(ratio); } + inline float WeldJoint::GetDampingRatio() const { KGE_ASSERT(raw_joint_); return raw_joint_->GetDampingRatio(); } + + inline float WheelJoint::GetJointAngle() const { KGE_ASSERT(raw_joint_); return math::Radian2Degree(raw_joint_->GetJointAngle()); } + inline float WheelJoint::GetJointAngularSpeed() const { KGE_ASSERT(raw_joint_); return math::Radian2Degree(raw_joint_->GetJointAngularSpeed()); } + inline bool WheelJoint::IsMotorEnabled() const { KGE_ASSERT(raw_joint_); return raw_joint_->IsMotorEnabled(); } + inline void WheelJoint::EnableMotor(bool flag) { KGE_ASSERT(raw_joint_); raw_joint_->EnableMotor(flag); } + inline void WheelJoint::SetMotorSpeed(float speed) { KGE_ASSERT(raw_joint_); raw_joint_->SetMotorSpeed(math::Degree2Radian(speed)); } + inline float WheelJoint::GetMotorSpeed() const { KGE_ASSERT(raw_joint_); return math::Radian2Degree(raw_joint_->GetMotorSpeed()); } + inline void WheelJoint::SetSpringFrequencyHz(float hz) { KGE_ASSERT(raw_joint_); raw_joint_->SetSpringFrequencyHz(hz); } + inline float WheelJoint::GetSpringFrequencyHz() const { KGE_ASSERT(raw_joint_); return raw_joint_->GetSpringFrequencyHz(); } + inline void WheelJoint::SetSpringDampingRatio(float ratio) { KGE_ASSERT(raw_joint_); raw_joint_->SetSpringDampingRatio(ratio); } + inline float WheelJoint::GetSpringDampingRatio() const { KGE_ASSERT(raw_joint_); return raw_joint_->GetSpringDampingRatio(); } + + inline void MouseJoint::SetFrequency(float hz) { KGE_ASSERT(raw_joint_); raw_joint_->SetFrequency(hz); } + inline float MouseJoint::GetFrequency() const { KGE_ASSERT(raw_joint_); return raw_joint_->GetFrequency(); } + inline void MouseJoint::SetDampingRatio(float ratio) { KGE_ASSERT(raw_joint_); raw_joint_->SetDampingRatio(ratio); } + inline float MouseJoint::GetDampingRatio() const { KGE_ASSERT(raw_joint_); return raw_joint_->GetDampingRatio(); } } } diff --git a/src/kiwano-physics/Shape.cpp b/src/kiwano-physics/Shape.cpp index 47d6dc0d..d39a49e1 100644 --- a/src/kiwano-physics/Shape.cpp +++ b/src/kiwano-physics/Shape.cpp @@ -35,12 +35,7 @@ namespace kiwano { } - b2Shape* Shape::GetB2Shape() - { - return shape_; - } - - const b2Shape* Shape::GetB2Shape() const + b2Shape* Shape::GetB2Shape() const { return shape_; } diff --git a/src/kiwano-physics/Shape.h b/src/kiwano-physics/Shape.h index 0d891f62..8ee206f1 100644 --- a/src/kiwano-physics/Shape.h +++ b/src/kiwano-physics/Shape.h @@ -26,25 +26,35 @@ namespace kiwano namespace physics { class World; + class Fixture; - // ÐÎ×´»ùÀà + /** + * \addtogroup Physics + * @{ + */ + + /// \~chinese + /// @brief ÐÎ×´»ùÀà class KGE_API Shape { + friend class Fixture; + public: Shape(); Shape(b2Shape* shape); - b2Shape* GetB2Shape(); - const b2Shape* GetB2Shape() const; + b2Shape* GetB2Shape() const; void SetB2Shape(b2Shape* shape); + private: virtual void FitWorld(World* world) {} - protected: + private: b2Shape* shape_; }; - // Ô²ÐÎÐÎ×´ + /// \~chinese + /// @brief Ô²ÐÎÐÎ×´ class KGE_API CircleShape : public Shape { @@ -55,15 +65,17 @@ namespace kiwano void Set(float radius, Point const& offset = Point()); + private: void FitWorld(World* world) override; - protected: + private: float radius_; Point offset_; b2CircleShape circle_; }; - // ºÐ×ÓÐÎ×´ + /// \~chinese + /// @brief ºÐ×ÓÐÎ×´ class KGE_API BoxShape : public Shape { @@ -74,16 +86,18 @@ namespace kiwano void Set(Vec2 const& size, Point const& offset = Point(), float rotation = 0.f); + private: void FitWorld(World* world) override; - protected: + private: float rotation_; Vec2 box_size_; Point offset_; b2PolygonShape polygon_; }; - // ¶à±ßÐÎÐÎ×´ + /// \~chinese + /// @brief ¶à±ßÐÎÐÎ×´ class KGE_API PolygonShape : public Shape { @@ -94,14 +108,16 @@ namespace kiwano void Set(Vector const& vertexs); + private: void FitWorld(World* world) override; - protected: + private: Vector vertexs_; b2PolygonShape polygon_; }; - // Ïß¶ÎÐÎ×´, ÓÃÓÚ±íʾһÌõ±ß + /// \~chinese + /// @brief Ïß¶ÎÐÎ×´, ÓÃÓÚ±íʾһÌõ±ß class KGE_API EdgeShape : public Shape { @@ -112,14 +128,16 @@ namespace kiwano void Set(Point const& p1, Point const& p2); + private: void FitWorld(World* world) override; - protected: + private: Point p_[2]; b2EdgeShape edge_; }; - // Á´Ê½ÐÎ×´ + /// \~chinese + /// @brief Á´Ê½ÐÎ×´ class KGE_API ChainShape : public Shape { @@ -130,12 +148,15 @@ namespace kiwano void Set(Vector const& vertexs, bool loop = false); + private: void FitWorld(World* world) override; - protected: + private: bool loop_; Vector vertexs_; b2ChainShape chain_; }; + + /** @} */ } } diff --git a/src/kiwano-physics/World.cpp b/src/kiwano-physics/World.cpp index 71f61377..8c47eee4 100644 --- a/src/kiwano-physics/World.cpp +++ b/src/kiwano-physics/World.cpp @@ -27,7 +27,7 @@ namespace kiwano { namespace { - const float DefaultGlobalScale = 100.f; // 100 pixels per meters + const float default_global_scale = 100.f; // 100 pixels per meters } class World::DestructionListener : public b2DestructionListener @@ -85,7 +85,7 @@ namespace kiwano : world_(b2Vec2(0, 10.0f)) , vel_iter_(6) , pos_iter_(2) - , global_scale_(DefaultGlobalScale) + , global_scale_(default_global_scale) , destruction_listener_(nullptr) , contact_listener_(nullptr) , removing_joint_(false) @@ -225,36 +225,25 @@ namespace kiwano world_.SetGravity(b2Vec2(gravity.x, gravity.y)); } + ContactList World::GetContactList() + { + return ContactList(Contact(world_.GetContactList())); + } + void World::Update(Duration dt) { - { - b2Body* b2body = world_.GetBodyList(); - while (b2body) - { - Body* body = static_cast(b2body->GetUserData()); - if (body && body->GetType() != Body::Type::Static) - { - body->UpdateFromActor(); - } - - b2body = b2body->GetNext(); - } - } - world_.Step(dt.Seconds(), vel_iter_, pos_iter_); + b2Body* b2body = world_.GetBodyList(); + while (b2body) { - b2Body* b2body = world_.GetBodyList(); - while (b2body) + Body* body = static_cast(b2body->GetUserData()); + if (body && body->GetType() != Body::Type::Static) { - Body* body = static_cast(b2body->GetUserData()); - if (body && body->GetType() != Body::Type::Static) - { - body->UpdateActor(); - } - - b2body = b2body->GetNext(); + body->UpdateActor(); } + + b2body = b2body->GetNext(); } Stage::Update(dt); diff --git a/src/kiwano-physics/World.h b/src/kiwano-physics/World.h index 51bab4fb..ef5914c2 100644 --- a/src/kiwano-physics/World.h +++ b/src/kiwano-physics/World.h @@ -26,7 +26,22 @@ namespace kiwano { namespace physics { - // ÎïÀíÊÀ½ç + KGE_DECLARE_SMART_PTR(World); + + /** + * \~chinese + * \defgroup Physics ÎïÀíÒýÇæ + */ + + /** + * \addtogroup Physics + * @{ + */ + + /** + * \~chinese + * @brief ÎïÀíÊÀ½ç + */ class KGE_API World : public Stage { @@ -38,54 +53,86 @@ namespace kiwano virtual ~World(); - // »ñÈ¡ÖØÁ¦ + /// \~chinese + /// @brief »ñÈ¡ÖØÁ¦ [N] Vec2 GetGravity() const; - // ÉèÖÃÖØÁ¦ + /// \~chinese + /// @brief ÉèÖÃÖØÁ¦ [N] void SetGravity(Vec2 gravity); - // »ñȡȫ¾ÖËõ·Å±ÈÀý - inline float GetGlobalScale() const { return global_scale_; } + /// \~chinese + /// @brief »ñÈ¡ÎïÀí½Ó´¥Áбí + ContactList GetContactList(); - // ÉèÖÃÈ«¾ÖËõ·Å±ÈÀý - inline void SetGlobalScale(float scale) { global_scale_ = scale; } + /// \~chinese + /// @brief »ñȡȫ¾ÖËõ·Å±ÈÀý + /// @details Ëõ·Å±ÈÀýÊÇÖ¸ÓÉÎïÀíÊÀ½çµÄµ¥Î»Ã×ת»»µ½ÆÁÄ»ÏñËØµÄ±ÈÀý£¬Ä¬ÈϱÈÀýΪ1:100 + float GetGlobalScale() const; - // ÓÎÏ·ÊÀ½çµ¥Î»×ª»»ÎªÎïÀíÊÀ½çµ¥Î» - inline float World2Stage(float value) const { return value * GetGlobalScale(); } - inline Point World2Stage(const b2Vec2& pos) const { return Point(World2Stage(pos.x), World2Stage(pos.y)); } + /// \~chinese + /// @brief ÉèÖÃÈ«¾ÖËõ·Å±ÈÀý + /// @details Ëõ·Å±ÈÀýÊÇÖ¸ÓÉÎïÀíÊÀ½çµÄµ¥Î»Ã×ת»»µ½ÆÁÄ»ÏñËØµÄ±ÈÀý£¬Ä¬ÈϱÈÀýΪ1:100 + void SetGlobalScale(float scale); - // ÎïÀíÊÀ½çµ¥Î»×ª»»ÎªÓÎÏ·ÊÀ½çµ¥Î» - inline float Stage2World(float value) const { return value / GetGlobalScale(); } - inline b2Vec2 Stage2World(const Point& pos) const { return b2Vec2(Stage2World(pos.x), Stage2World(pos.y)); } + /// \~chinese + /// @brief ÓÎÏ·ÊÀ½çµ¥Î»×ª»»ÎªÎïÀíÊÀ½çµ¥Î» + /// @details ¸ù¾ÝÈ«¾ÖËõ·Å±ÈÀý½«ÎïÀíÊÀ½çµÄµ¥Î»Ã×ת»»ÎªÏñËØµ¥Î» + float World2Stage(float value) const; - // ÉèÖÃËٶȵü´ú´ÎÊý, ĬÈÏΪ 6 - inline void SetVelocityIterations(int vel_iter) { vel_iter_ = vel_iter; } + /// \~chinese + /// @brief ÓÎÏ·ÊÀ½çµ¥Î»×ª»»ÎªÎïÀíÊÀ½çµ¥Î» + /// @details ¸ù¾ÝÈ«¾ÖËõ·Å±ÈÀý½«ÎïÀíÊÀ½çµÄµ¥Î»Ã×ת»»ÎªÏñËØµ¥Î» + Vec2 World2Stage(const b2Vec2& pos) const; - // ÉèÖÃλÖõü´ú´ÎÊý, ĬÈÏΪ 2 - inline void SetPositionIterations(int pos_iter) { pos_iter_ = pos_iter; } + /// \~chinese + /// @brief ÎïÀíÊÀ½çµ¥Î»×ª»»ÎªÓÎÏ·ÊÀ½çµ¥Î» + /// @details ¸ù¾ÝÈ«¾ÖËõ·Å±ÈÀý½«ÏñËØµ¥Î»×ª»»ÎªÎïÀíÊÀ½çµÄµ¥Î»Ã× + float Stage2World(float value) const; + + /// \~chinese + /// @brief ÎïÀíÊÀ½çµ¥Î»×ª»»ÎªÓÎÏ·ÊÀ½çµ¥Î» + /// @details ¸ù¾ÝÈ«¾ÖËõ·Å±ÈÀý½«ÏñËØµ¥Î»×ª»»ÎªÎïÀíÊÀ½çµÄµ¥Î»Ã× + b2Vec2 Stage2World(const Vec2& pos) const; + + /// \~chinese + /// @brief ÉèÖÃËٶȵü´ú´ÎÊý, ĬÈÏΪ 6 + void SetVelocityIterations(int vel_iter); + + /// \~chinese + /// @brief ÉèÖÃλÖõü´ú´ÎÊý, ĬÈÏΪ 2 + void SetPositionIterations(int pos_iter); b2World* GetB2World(); + const b2World* GetB2World() const; private: - // ÒÆ³ýÎïÌå + /// \~chinese + /// @brief ÒÆ³ýÎïÌå void RemoveBody(Body* body); - // ÒÆ³ýËùÓÐÎïÌå + /// \~chinese + /// @brief ÒÆ³ýËùÓÐÎïÌå void RemoveAllBodies(); - // Ìí¼Ó¹Ø½Ú + /// \~chinese + /// @brief Ìí¼Ó¹Ø½Ú void AddJoint(Joint* joint); - // ÒÆ³ý¹Ø½Ú + /// \~chinese + /// @brief ÒÆ³ý¹Ø½Ú void RemoveJoint(Joint* joint); - // ÒÆ³ýËùÓÐ¹Ø½Ú + /// \~chinese + /// @brief ÒÆ³ýËùÓÐ¹Ø½Ú void RemoveAllJoints(); - // ¹Ø½Ú±»ÒƳý + /// \~chinese + /// @brief ¹Ø½Ú±»ÒƳý void JointRemoved(b2Joint* joint); + protected: void Update(Duration dt) override; private: @@ -106,6 +153,47 @@ namespace kiwano Vector joints_; }; - KGE_DECLARE_SMART_PTR(World); + + /** @} */ + + inline float World::GetGlobalScale() const + { + return global_scale_; + } + + inline void World::SetGlobalScale(float scale) + { + global_scale_ = scale; + } + + inline float World::World2Stage(float value) const + { + return value * GetGlobalScale(); + } + + inline Vec2 World::World2Stage(const b2Vec2& pos) const + { + return Point(World2Stage(pos.x), World2Stage(pos.y)); + } + + inline float World::Stage2World(float value) const + { + return value / GetGlobalScale(); + } + + inline b2Vec2 World::Stage2World(const Vec2& pos) const + { + return b2Vec2(Stage2World(pos.x), Stage2World(pos.y)); + } + + inline void World::SetVelocityIterations(int vel_iter) + { + vel_iter_ = vel_iter; + } + + inline void World::SetPositionIterations(int pos_iter) + { + pos_iter_ = pos_iter; + } } } diff --git a/src/kiwano-physics/helper.h b/src/kiwano-physics/helper.h index c82aa765..3436b0a1 100644 --- a/src/kiwano-physics/helper.h +++ b/src/kiwano-physics/helper.h @@ -28,7 +28,7 @@ namespace kiwano { namespace physics { - inline b2Vec2 Stage2World(const Point& pos) { return b2Vec2(pos.x, pos.y); } - inline Point World2Stage(const b2Vec2& pos) { return Point(pos.x, pos.y); } + inline b2Vec2 Stage2World(const Vec2& pos) { return b2Vec2(pos.x, pos.y); } + inline Vec2 World2Stage(const b2Vec2& pos) { return Vec2(pos.x, pos.y); } } } diff --git a/src/kiwano/2d/Actor.cpp b/src/kiwano/2d/Actor.cpp index ec4f0eff..44411653 100644 --- a/src/kiwano/2d/Actor.cpp +++ b/src/kiwano/2d/Actor.cpp @@ -93,7 +93,11 @@ namespace kiwano if (children_.empty()) { - OnRender(rt); + if (CheckVisibilty(rt)) + { + PrepareToRender(rt); + OnRender(rt); + } } else { @@ -108,7 +112,11 @@ namespace kiwano child = child->next_item().get(); } - OnRender(rt); + if (CheckVisibilty(rt)) + { + PrepareToRender(rt); + OnRender(rt); + } while (child) { @@ -118,10 +126,10 @@ namespace kiwano } } - void Actor::PrepareRender(RenderTarget* rt) + void Actor::PrepareToRender(RenderTarget* rt) { rt->SetTransform(transform_matrix_); - rt->SetOpacity(displayed_opacity_); + rt->SetBrushOpacity(GetDisplayedOpacity()); } void Actor::RenderBorder(RenderTarget* rt) @@ -132,10 +140,10 @@ namespace kiwano rt->SetTransform(transform_matrix_); - rt->SetDefaultBrushColor(Color(Color::Red, .4f)); + rt->SetCurrentBrush(GetStage()->GetBorderFillBrush()); rt->FillRectangle(bounds); - rt->SetDefaultBrushColor(Color(Color::Red, .8f)); + rt->SetCurrentBrush(GetStage()->GetBorderStrokeBrush()); rt->DrawRectangle(bounds, 2.f); } @@ -150,7 +158,15 @@ namespace kiwano if (dirty_visibility_) { dirty_visibility_ = false; - visible_in_rt_ = rt->CheckVisibility(GetBounds(), GetTransformMatrix()); + + if (size_.IsOrigin()) + { + visible_in_rt_ = false; + } + else + { + visible_in_rt_ = rt->CheckVisibility(GetBounds(), GetTransformMatrix()); + } } return visible_in_rt_; } @@ -169,21 +185,21 @@ namespace kiwano if (responsible_) { - if (evt.type == event::MouseMove) + if (evt.IsType()) { - auto mouse_evt = evt.SafeCast(); - if (!mouse_evt->target && ContainsPoint(mouse_evt->pos)) + auto& mouse_evt = evt.SafeCast(); + if (!mouse_evt.target && ContainsPoint(mouse_evt.pos)) { - mouse_evt->target = this; + mouse_evt.target = this; if (!hover_) { hover_ = true; MouseHoverEvent hover; - hover.pos = mouse_evt->pos; - hover.left_btn_down = mouse_evt->left_btn_down; - hover.right_btn_down = mouse_evt->right_btn_down; + hover.pos = mouse_evt.pos; + hover.left_btn_down = mouse_evt.left_btn_down; + hover.right_btn_down = mouse_evt.right_btn_down; hover.target = this; EventDispatcher::Dispatch(hover); } @@ -194,33 +210,33 @@ namespace kiwano pressed_ = false; MouseOutEvent out; - out.pos = mouse_evt->pos; - out.left_btn_down = mouse_evt->left_btn_down; - out.right_btn_down = mouse_evt->right_btn_down; + out.pos = mouse_evt.pos; + out.left_btn_down = mouse_evt.left_btn_down; + out.right_btn_down = mouse_evt.right_btn_down; out.target = this; EventDispatcher::Dispatch(out); } } - if (evt.type == event::MouseDown && hover_) + if (evt.IsType() && hover_) { pressed_ = true; - evt.SafeCast()->target = this; + evt.SafeCast().target = this; } - if (evt.type == event::MouseUp && pressed_) + if (evt.IsType() && pressed_) { pressed_ = false; auto mouse_up_evt = evt.SafeCast(); - mouse_up_evt->target = this; + mouse_up_evt.target = this; MouseClickEvent click; - click.pos = mouse_up_evt->pos; - click.left_btn_down = mouse_up_evt->left_btn_down; - click.right_btn_down = mouse_up_evt->right_btn_down; + click.pos = mouse_up_evt.pos; + click.left_btn_down = mouse_up_evt.left_btn_down; + click.right_btn_down = mouse_up_evt.right_btn_down; click.target = this; - click.button = mouse_up_evt->button; + click.button = mouse_up_evt.button; EventDispatcher::Dispatch(click); } } @@ -272,7 +288,7 @@ namespace kiwano } // update children's transform - for (Actor* child = children_.first_item().get(); child; child = child->next_item().get()) + for (auto child = children_.first_item().get(); child; child = child->next_item().get()) child->dirty_transform_ = true; } @@ -481,7 +497,7 @@ namespace kiwano { if (parent == child) { - KGE_ERROR_LOG(L"A actor cannot be its own parent"); + KGE_ERROR(L"A actor cannot be its own parent"); return; } } @@ -527,11 +543,11 @@ namespace kiwano Vector children; size_t hash_code = std::hash{}(name); - for (Actor* child = children_.first_item().get(); child; child = child->next_item().get()) + for (auto child = children_.first_item().get(); child; child = child->next_item().get()) { if (child->hash_name_ == hash_code && child->IsName(name)) { - children.push_back(child); + children.push_back(const_cast(child)); } } return children; @@ -541,11 +557,11 @@ namespace kiwano { size_t hash_code = std::hash{}(name); - for (Actor* child = children_.first_item().get(); child; child = child->next_item().get()) + for (auto child = children_.first_item().get(); child; child = child->next_item().get()) { if (child->hash_name_ == hash_code && child->IsName(name)) { - return child; + return const_cast(child); } } return nullptr; diff --git a/src/kiwano/2d/Actor.h b/src/kiwano/2d/Actor.h index 975c5338..30564cf0 100644 --- a/src/kiwano/2d/Actor.h +++ b/src/kiwano/2d/Actor.h @@ -19,7 +19,10 @@ // THE SOFTWARE. #pragma once -#include +#include +#include +#include +#include #include #include #include @@ -27,10 +30,27 @@ namespace kiwano { + class Stage; class Director; class RenderTarget; - // ½ÇÉ« + KGE_DECLARE_SMART_PTR(Actor); + + /** + * \~chinese + * \defgroup Actors »ù´¡½ÇÉ« + */ + + /** + * \addtogroup Actors + * @{ + */ + + /** + * \~chinese + * @brief ½ÇÉ« + * @details ½ÇÉ«ÊÇÎę̀ÉÏ×î»ù±¾µÄÔªËØ£¬ÊÇÍê³ÉäÖȾ¡¢¸üС¢Ê¼þ·Ö·¢µÈ¹¦ÄܵÄ×îСµ¥Î»£¬Ò²ÊǶ¯»­¡¢¶¨Ê±Æ÷¡¢Ê¼þ¼àÌýµÈ¹¦ÄܵÄÔØÌå + */ class KGE_API Actor : public ObjectBase , public TimerManager @@ -43,353 +63,376 @@ namespace kiwano friend IntrusiveList; public: - using Children = IntrusiveList; - using UpdateCallback = Function; + /// \~chinese + /// @brief ×Ó³ÉÔ±Áбí + using Children = IntrusiveList; + + /// \~chinese + /// @brief ½ÇÉ«¸üлص÷º¯Êý + using UpdateCallback = Function; Actor(); - // ¸üнÇÉ« + /// \~chinese + /// @brief ¸üнÇÉ« + /// @details ÿ֡»­ÃæË¢ÐÂǰµ÷Óøú¯Êý£¬ÖØÔظú¯ÊýÒÔʵÏÖ½ÇÉ«µÄ¸üд¦Àí + /// @param dt ¾àÉÏÒ»´Î¸üеÄʱ¼ä¼ä¸ô virtual void OnUpdate(Duration dt); - // äÖȾ½ÇÉ« + /// \~chinese + /// @brief äÖȾ½ÇÉ« + /// @details ÿ֡»­ÃæË¢ÐÂʱµ÷Óøú¯Êý£¬Ä¬Èϲ»½øÐÐäÖȾ£¬ÖØÔظú¯ÊýÒÔʵÏÖ¾ßÌåäÖȾ¹ý³Ì + /// @param rt äÖȾĿ±ê virtual void OnRender(RenderTarget* rt); - // »ñÈ¡ÏÔʾ״̬ + /// \~chinese + /// @brief »ñÈ¡ÏÔʾ״̬ bool IsVisible() const; - // »ñÈ¡ÏìӦ״̬ + /// \~chinese + /// @brief »ñÈ¡ÏìӦ״̬ bool IsResponsible() const; - // ÊÇ·ñÆôÓü¶ÁªÍ¸Ã÷¶È + /// \~chinese + /// @brief ÊÇ·ñÆôÓü¶ÁªÍ¸Ã÷¶È bool IsCascadeOpacityEnabled() const; - // »ñÈ¡Ãû³ÆµÄ Hash Öµ + /// \~chinese + /// @brief »ñÈ¡Ãû³ÆµÄ Hash Öµ size_t GetHashName() const; - // »ñÈ¡ Z Öá˳Ðò + /// \~chinese + /// @brief »ñÈ¡ Z Öá˳Ðò int GetZOrder() const; - // »ñÈ¡×ø±ê + /// \~chinese + /// @brief »ñÈ¡×ø±ê Point const& GetPosition() const; - // »ñÈ¡ x ×ø±ê + /// \~chinese + /// @brief »ñÈ¡ x ×ø±ê float GetPositionX() const; - // »ñÈ¡ y ×ø±ê + /// \~chinese + /// @brief »ñÈ¡ y ×ø±ê float GetPositionY() const; - // »ñÈ¡Ëõ·Å±ÈÀý + /// \~chinese + /// @brief »ñÈ¡Ëõ·Å±ÈÀý Point const& GetScale() const; - // »ñÈ¡ºáÏòËõ·Å±ÈÀý + /// \~chinese + /// @brief »ñÈ¡ºáÏòËõ·Å±ÈÀý float GetScaleX() const; - // »ñÈ¡×ÝÏòËõ·Å±ÈÀý + /// \~chinese + /// @brief »ñÈ¡×ÝÏòËõ·Å±ÈÀý float GetScaleY() const; - // »ñÈ¡´íÇÐ½Ç¶È + /// \~chinese + /// @brief »ñÈ¡´íÇÐ½Ç¶È Point const& GetSkew() const; - // »ñÈ¡ºáÏò´íÇÐ½Ç¶È + /// \~chinese + /// @brief »ñÈ¡ºáÏò´íÇÐ½Ç¶È float GetSkewX() const; - // »ñÈ¡×ÝÏò´íÇÐ½Ç¶È + /// \~chinese + /// @brief »ñÈ¡×ÝÏò´íÇÐ½Ç¶È float GetSkewY() const; - // »ñÈ¡Ðýת½Ç¶È + /// \~chinese + /// @brief »ñÈ¡Ðýת½Ç¶È float GetRotation() const; - // »ñÈ¡¿í¶È + /// \~chinese + /// @brief »ñÈ¡¿í¶È float GetWidth() const; - // »ñÈ¡¸ß¶È + /// \~chinese + /// @brief »ñÈ¡¸ß¶È float GetHeight() const; - // »ñÈ¡´óС + /// \~chinese + /// @brief »ñÈ¡´óС Size const& GetSize() const; - // »ñÈ¡Ëõ·ÅºóµÄ¿í¶È + /// \~chinese + /// @brief »ñÈ¡Ëõ·ÅºóµÄ¿í¶È float GetScaledWidth() const; - // »ñÈ¡Ëõ·ÅºóµÄ¸ß¶È + /// \~chinese + /// @brief »ñÈ¡Ëõ·ÅºóµÄ¸ß¶È float GetScaledHeight() const; - // »ñÈ¡Ëõ·ÅºóµÄ´óС + /// \~chinese + /// @brief »ñÈ¡Ëõ·ÅºóµÄ´óС Size GetScaledSize() const; - // »ñȡêµã + /// \~chinese + /// @brief »ñȡêµã Point const& GetAnchor() const; - // »ñÈ¡ x ·½Ïòêµã + /// \~chinese + /// @brief »ñÈ¡ x ·½Ïòêµã float GetAnchorX() const; - // »ñÈ¡ y ·½Ïòêµã + /// \~chinese + /// @brief »ñÈ¡ y ·½Ïòêµã float GetAnchorY() const; - // »ñȡ͸Ã÷¶È + /// \~chinese + /// @brief »ñȡ͸Ã÷¶È float GetOpacity() const; - // »ñÈ¡ÏÔʾ͸Ã÷¶È + /// \~chinese + /// @brief »ñÈ¡ÏÔʾ͸Ã÷¶È float GetDisplayedOpacity() const; - // »ñÈ¡±ä»» + /// \~chinese + /// @brief »ñÈ¡±ä»» Transform GetTransform() const; - // »ñÈ¡¸¸½ÇÉ« + /// \~chinese + /// @brief »ñÈ¡¸¸½ÇÉ« Actor* GetParent() const; - // »ñÈ¡ËùÔÚÎę̀ + /// \~chinese + /// @brief »ñÈ¡ËùÔÚÎę̀ Stage* GetStage() const; - // »ñÈ¡±ß¿ò + /// \~chinese + /// @brief »ñÈ¡±ß¿ò virtual Rect GetBounds() const; - // »ñÈ¡ÍâÇаüΧºÐ + /// \~chinese + /// @brief »ñÈ¡ÍâÇаüΧºÐ virtual Rect GetBoundingBox() const; - // »ñÈ¡¶þά±ä»»¾ØÕó + /// \~chinese + /// @brief »ñÈ¡¶þά±ä»»¾ØÕó Matrix3x2 const& GetTransformMatrix() const; - // »ñÈ¡¶þά±ä»»µÄÄæ¾ØÕó + /// \~chinese + /// @brief »ñÈ¡¶þά±ä»»µÄÄæ¾ØÕó Matrix3x2 const& GetTransformInverseMatrix() const; - // ÉèÖÃÊÇ·ñÏÔʾ - void SetVisible( - bool val - ); + /// \~chinese + /// @brief ÉèÖýÇÉ«ÊÇ·ñ¿É¼û + void SetVisible(bool val); - // ÉèÖÃÃû³Æ - void SetName( - String const& name - ); + /// \~chinese + /// @brief ÉèÖÃÃû³Æ + void SetName(String const& name); - // ÉèÖÃ×ø±ê - virtual void SetPosition( - Point const& point - ); + /// \~chinese + /// @brief ÉèÖÃ×ø±ê + virtual void SetPosition(Point const& point); - // ÉèÖÃ×ø±ê - void SetPosition( - float x, - float y - ); + /// \~chinese + /// @brief ÉèÖÃ×ø±ê + void SetPosition(float x, float y); - // ÉèÖúá×ø±ê - void SetPositionX( - float x - ); + /// \~chinese + /// @brief ÉèÖúá×ø±ê + void SetPositionX(float x); - // ÉèÖÃ×Ý×ø±ê - void SetPositionY( - float y - ); + /// \~chinese + /// @brief ÉèÖÃ×Ý×ø±ê + void SetPositionY(float y); - // ÒÆ¶¯×ø±ê - void Move( - Vec2 const& v - ); + /// \~chinese + /// @brief ÒÆ¶¯×ø±ê + void Move(Vec2 const& v); - // ÒÆ¶¯×ø±ê - void Move( - float vx, - float vy - ); + /// \~chinese + /// @brief ÒÆ¶¯×ø±ê + void Move(float vx, float vy); - // ÉèÖÃËõ·Å±ÈÀý - // ĬÈÏΪ (1.0, 1.0) - virtual void SetScale( - Vec2 const& scale - ); + /// \~chinese + /// @brief ÉèÖÃËõ·Å±ÈÀý£¬Ä¬ÈÏΪ (1.0, 1.0) + virtual void SetScale(Vec2 const& scale); - // ÉèÖÃËõ·Å±ÈÀý - // ĬÈÏΪ (1.0, 1.0) - void SetScale( - float scalex, - float scaley - ); + /// \~chinese + /// @brief ÉèÖÃËõ·Å±ÈÀý£¬Ä¬ÈÏΪ (1.0, 1.0) + void SetScale(float scalex, float scaley); - // ÉèÖôíÇÐ½Ç¶È - // ĬÈÏΪ (0, 0) - virtual void SetSkew( - Vec2 const& skew - ); + /// \~chinese + /// @brief ÉèÖôíÇнǶȣ¬Ä¬ÈÏΪ (0, 0) + virtual void SetSkew(Vec2 const& skew); - // ÉèÖôíÇÐ½Ç¶È - // ĬÈÏΪ (0, 0) - void SetSkew( - float skewx, - float skewy - ); + /// \~chinese + /// @brief ÉèÖôíÇнǶȣ¬Ä¬ÈÏΪ (0, 0) + void SetSkew(float skewx, float skewy); - // ÉèÖÃÐýת½Ç¶È - // ĬÈÏΪ 0 - virtual void SetRotation( - float rotation - ); + /// \~chinese + /// @brief ÉèÖÃÐýת½Ç¶È£¬Ä¬ÈÏΪ 0 + virtual void SetRotation(float rotation); - // ÉèÖÃêµãλÖà - // ĬÈÏΪ (0, 0), ·¶Î§ [0, 1] - virtual void SetAnchor( - Vec2 const& anchor - ); + /// \~chinese + /// @brief ÉèÖÃêµãλÖã¬Ä¬ÈÏΪ (0, 0), ·¶Î§ [0, 1] + virtual void SetAnchor(Vec2 const& anchor); - // ÉèÖÃêµãλÖà - // ĬÈÏΪ (0, 0), ·¶Î§ [0, 1] - void SetAnchor( - float anchorx, - float anchory - ); + /// \~chinese + /// @brief ÉèÖÃêµãλÖã¬Ä¬ÈÏΪ (0, 0), ·¶Î§ [0, 1] + void SetAnchor(float anchorx, float anchory); - // Ð޸Ŀí¶È - virtual void SetWidth( - float width - ); + /// \~chinese + /// @brief Ð޸Ŀí¶È + virtual void SetWidth(float width); - // ÐÞ¸Ä¸ß¶È - virtual void SetHeight( - float height - ); + /// \~chinese + /// @brief ÐÞ¸Ä¸ß¶È + virtual void SetHeight(float height); - // Ð޸ĴóС - virtual void SetSize( - Size const& size - ); + /// \~chinese + /// @brief Ð޸ĴóС + virtual void SetSize(Size const& size); - // Ð޸ĴóС - void SetSize( - float width, - float height - ); + /// \~chinese + /// @brief Ð޸ĴóС + void SetSize(float width, float height); - // ÉèÖÃ͸Ã÷¶È - // ĬÈÏΪ 1.0, ·¶Î§ [0, 1] - virtual void SetOpacity( - float opacity - ); + /// \~chinese + /// @brief ÉèÖÃ͸Ã÷¶È£¬Ä¬ÈÏΪ 1.0, ·¶Î§ [0, 1] + virtual void SetOpacity(float opacity); - // ÆôÓûò½ûÓü¶ÁªÍ¸Ã÷¶È - void SetCascadeOpacityEnabled( - bool enabled - ); + /// \~chinese + /// @brief ÆôÓûò½ûÓü¶ÁªÍ¸Ã÷¶È + void SetCascadeOpacityEnabled(bool enabled); - // ÉèÖöþά·ÂÉä±ä»» - void SetTransform( - Transform const& transform - ); + /// \~chinese + /// @brief ÉèÖöþά·ÂÉä±ä»» + void SetTransform(Transform const& transform); - // ÉèÖà Z Öá˳Ðò - // ĬÈÏΪ 0 - void SetZOrder( - int zorder - ); + /// \~chinese + /// @brief ÉèÖà Z Öá˳Ðò£¬Ä¬ÈÏΪ 0 + void SetZOrder(int zorder); - // ÊÇ·ñ¿ÉÏìÓ¦ (Êó±ê Hover | Out | Click ÏûÏ¢) - // ĬÈÏΪ false - void SetResponsible( - bool enable - ); + /// \~chinese + /// @brief ÉèÖýÇÉ«ÊÇ·ñ¿ÉÏìÓ¦£¬Ä¬ÈÏΪ false + /// @details ¿ÉÏìÓ¦µÄ½ÇÉ«»áÊÕµ½Êó±êµÄ Hover | Out | Click ÏûÏ¢ + void SetResponsible(bool enable); - // Ìí¼Ó×Ó½ÇÉ« - void AddChild( - ActorPtr child, - int zorder = 0 - ); + /// \~chinese + /// @brief Ìí¼Ó×Ó½ÇÉ« + void AddChild(ActorPtr child, int zorder = 0); - // Ìí¼Ó×Ó½ÇÉ« - void AddChild( - Actor* child, - int zorder = 0 - ); + /// \~chinese + /// @brief Ìí¼Ó×Ó½ÇÉ« + void AddChild(Actor* child, int zorder = 0); - // Ìí¼Ó¶à¸ö×Ó½ÇÉ« - void AddChildren( - Vector const& children - ); + /// \~chinese + /// @brief Ìí¼Ó¶à¸ö×Ó½ÇÉ« + void AddChildren(Vector const& children); - // »ñÈ¡Ãû³ÆÏàͬµÄ×Ó½ÇÉ« - Actor* GetChild( - String const& name - ) const; + /// \~chinese + /// @brief »ñÈ¡Ãû³ÆÏàͬµÄ×Ó½ÇÉ« + Actor* GetChild(String const& name) const; - // »ñÈ¡ËùÓÐÃû³ÆÏàͬµÄ×Ó½ÇÉ« - Vector GetChildren( - String const& name - ) const; + /// \~chinese + /// @brief »ñÈ¡ËùÓÐÃû³ÆÏàͬµÄ×Ó½ÇÉ« + Vector GetChildren(String const& name) const; - // »ñȡȫ²¿×Ó½ÇÉ« + /// \~chinese + /// @brief »ñȡȫ²¿×Ó½ÇÉ« Children& GetAllChildren(); - // »ñȡȫ²¿×Ó½ÇÉ« + /// \~chinese + /// @brief »ñȡȫ²¿×Ó½ÇÉ« Children const& GetAllChildren() const; - // ÒÆ³ý×Ó½ÇÉ« - void RemoveChild( - ActorPtr child - ); + /// \~chinese + /// @brief ÒÆ³ý×Ó½ÇÉ« + void RemoveChild(ActorPtr child); - // ÒÆ³ý×Ó½ÇÉ« - void RemoveChild( - Actor* child - ); + /// \~chinese + /// @brief ÒÆ³ý×Ó½ÇÉ« + void RemoveChild(Actor* child); - // ÒÆ³ýËùÓÐÃû³ÆÏàͬµÄ×Ó½ÇÉ« - void RemoveChildren( - String const& child_name - ); + /// \~chinese + /// @brief ÒÆ³ýËùÓÐÃû³ÆÏàͬµÄ×Ó½ÇÉ« + void RemoveChildren(String const& child_name); - // ÒÆ³ýËùÓнÇÉ« + /// \~chinese + /// @brief ÒÆ³ýËùÓнÇÉ« void RemoveAllChildren(); - // ´Ó¸¸½ÇÉ«ÒÆ³ý + /// \~chinese + /// @brief ´Ó¸¸½ÇÉ«ÒÆ³ý void RemoveFromParent(); - // ÅжϵãÊÇ·ñÔÚ½ÇÉ«ÄÚ + /// \~chinese + /// @brief ÅжϵãÊÇ·ñÔÚ½ÇÉ«ÄÚ virtual bool ContainsPoint(const Point& point) const; - // ÔÝÍ£½ÇÉ«¸üР+ /// \~chinese + /// @brief ÔÝÍ£½ÇÉ«¸üРvoid PauseUpdating(); - // ¼ÌÐø½ÇÉ«¸üР+ /// \~chinese + /// @brief ¼ÌÐø½ÇÉ«¸üРvoid ResumeUpdating(); - // ½ÇÉ«¸üÐÂÊÇ·ñÔÝÍ£ + /// \~chinese + /// @brief ½ÇÉ«¸üÐÂÊÇ·ñÔÝÍ£ bool IsUpdatePausing() const; - // ÉèÖøüÐÂʱµÄ»Øµ÷º¯Êý + /// \~chinese + /// @brief ÉèÖøüÐÂʱµÄ»Øµ÷º¯Êý void SetCallbackOnUpdate(UpdateCallback const& cb); - // »ñÈ¡¸üÐÂʱµÄ»Øµ÷º¯Êý + /// \~chinese + /// @brief »ñÈ¡¸üÐÂʱµÄ»Øµ÷º¯Êý UpdateCallback GetCallbackOnUpdate() const; - // äÖȾ½ÇÉ«±ß½ç + /// \~chinese + /// @brief äÖȾ½ÇÉ«±ß½ç void ShowBorder(bool show); - // ʼþ·Ö·¢ + /// \~chinese + /// @brief ·Ö·¢Ê¼þ void Dispatch(Event& evt) override; - // ÉèÖÃĬÈÏêµã - static void SetDefaultAnchor( - float anchor_x, - float anchor_y - ); + /// \~chinese + /// @brief ÉèÖÃĬÈÏêµã + static void SetDefaultAnchor(float anchor_x, float anchor_y); protected: + /// \~chinese + /// @brief ¸üÐÂ×ÔÉíºÍËùÓÐ×Ó½ÇÉ« virtual void Update(Duration dt); + /// \~chinese + /// @brief äÖȾ×ÔÉíºÍËùÓÐ×Ó½ÇÉ« virtual void Render(RenderTarget* rt); - virtual void PrepareRender(RenderTarget* rt); - + /// \~chinese + /// @brief »æÖÆ×ÔÉíºÍËùÓÐ×Ó½ÇÉ«µÄ±ß½ç virtual void RenderBorder(RenderTarget* rt); + /// \~chinese + /// @brief ¼ì²éÊÇ·ñÔÚäÖȾĿ±êµÄÊÓÇøÄÚ virtual bool CheckVisibilty(RenderTarget* rt) const; + /// \~chinese + /// @brief äÖȾǰ³õʼ»¯äÖȾĿ±ê״̬£¬½öµ± CheckVisibilty ·µ»ØÕæÊ±µ÷Óøú¯Êý + virtual void PrepareToRender(RenderTarget* rt); + + /// \~chinese + /// @brief ¸üÐÂ×Ô¼ºµÄ¶þά±ä»»£¬²¢Í¨ÖªËùÓÐ×Ó½ÇÉ« void UpdateTransform() const; + /// \~chinese + /// @brief ¸üÐÂ×Ô¼ººÍËùÓÐ×Ó½ÇÉ«µÄ͸Ã÷¶È void UpdateOpacity(); + /// \~chinese + /// @brief ½«ËùÓÐ×Ó½ÇÉ«°´ZÖá˳ÐòÅÅÐò void Reorder(); + /// \~chinese + /// @brief ÉèÖýڵãËùÔÚÎę̀ void SetStage(Stage* stage); private: @@ -421,6 +464,9 @@ namespace kiwano mutable Matrix3x2 transform_matrix_inverse_; }; + /** @} */ + + inline void Actor::OnUpdate(Duration dt) { KGE_NOT_USED(dt); diff --git a/src/kiwano/2d/Canvas.cpp b/src/kiwano/2d/Canvas.cpp index cbb6b60e..0f009977 100644 --- a/src/kiwano/2d/Canvas.cpp +++ b/src/kiwano/2d/Canvas.cpp @@ -27,11 +27,8 @@ namespace kiwano Canvas::Canvas() : cache_expired_(false) , stroke_width_(1.0f) - , fill_color_(0, 0, 0) - , stroke_color_(Color::White) , stroke_style_(StrokeStyle::Miter) { - Renderer::GetInstance()->CreateTextureRenderTarget(rt_); } Canvas::~Canvas() @@ -40,12 +37,14 @@ namespace kiwano void Canvas::BeginDraw() { - rt_.BeginDraw(); + InitRenderTargetAndBrushs(); + rt_->BeginDraw(); } void Canvas::EndDraw() { - rt_.EndDraw(); + InitRenderTargetAndBrushs(); + rt_->EndDraw(); cache_expired_ = true; } @@ -53,58 +52,19 @@ namespace kiwano { UpdateCache(); - if (texture_cached_.IsValid()) + if (texture_cached_ && texture_cached_->IsValid()) { - PrepareRender(rt); + PrepareToRender(rt); - Rect bitmap_rect(0.f, 0.f, texture_cached_.GetWidth(), texture_cached_.GetHeight()); - rt->DrawTexture(texture_cached_, bitmap_rect, bitmap_rect); + Rect bitmap_rect(0.f, 0.f, texture_cached_->GetWidth(), texture_cached_->GetHeight()); + rt->DrawTexture(*texture_cached_, bitmap_rect, bitmap_rect); } } - void Canvas::SetStrokeColor(Color const& color) + void Canvas::SetBrush(BrushPtr brush) { - stroke_color_ = color; - } - - void Canvas::SetFillColor(Color const& color) - { - fill_color_ = color; - } - - void Canvas::SetStrokeWidth(float width) - { - stroke_width_ = std::max(width, 0.f); - } - - void Canvas::SetStrokeStyle(StrokeStyle stroke_style) - { - stroke_style_ = stroke_style; - } - - void Canvas::SetTextFont(Font const& font) - { - text_font_ = font; - } - - void Canvas::SetTextStyle(TextStyle const & text_style) - { - text_style_ = text_style; - } - - void Canvas::SetBrushOpacity(float opacity) - { - rt_.SetOpacity(opacity); - } - - Color Canvas::GetStrokeColor() const - { - return stroke_color_; - } - - Color Canvas::GetFillColor() const - { - return fill_color_; + InitRenderTargetAndBrushs(); + rt_->SetCurrentBrush(brush); } float Canvas::GetStrokeWidth() const @@ -112,45 +72,47 @@ namespace kiwano return stroke_width_; } - float Canvas::GetBrushOpacity() const - { - return rt_.GetOpacity(); - } - void Canvas::SetBrushTransform(Transform const& transform) { - rt_.SetTransform(transform.ToMatrix()); + InitRenderTargetAndBrushs(); + rt_->SetTransform(transform.ToMatrix()); } void Canvas::SetBrushTransform(Matrix3x2 const & transform) { - rt_.SetTransform(transform); + InitRenderTargetAndBrushs(); + rt_->SetTransform(transform); } void Canvas::PushLayerArea(LayerArea& area) { - rt_.PushLayer(area); + InitRenderTargetAndBrushs(); + rt_->PushLayer(area); } void Canvas::PopLayerArea() { - rt_.PopLayer(); + InitRenderTargetAndBrushs(); + rt_->PopLayer(); } void Canvas::PushClipRect(Rect const& clip_rect) { - rt_.PushClipRect(clip_rect); + InitRenderTargetAndBrushs(); + rt_->PushClipRect(clip_rect); } void Canvas::PopClipRect() { - rt_.PopClipRect(); + InitRenderTargetAndBrushs(); + rt_->PopClipRect(); } void Canvas::DrawLine(Point const& begin, Point const& end) { - rt_.SetDefaultBrushColor(stroke_color_); - rt_.DrawLine( + InitRenderTargetAndBrushs(); + rt_->SetCurrentBrush(stroke_brush_); + rt_->DrawLine( begin, end, stroke_width_, @@ -161,8 +123,9 @@ namespace kiwano void Canvas::DrawCircle(Point const& center, float radius) { - rt_.SetDefaultBrushColor(stroke_color_); - rt_.DrawEllipse( + InitRenderTargetAndBrushs(); + rt_->SetCurrentBrush(stroke_brush_); + rt_->DrawEllipse( center, Vec2(radius, radius), stroke_width_, @@ -173,8 +136,9 @@ namespace kiwano void Canvas::DrawEllipse(Point const& center, Vec2 const& radius) { - rt_.SetDefaultBrushColor(stroke_color_); - rt_.DrawEllipse( + InitRenderTargetAndBrushs(); + rt_->SetCurrentBrush(stroke_brush_); + rt_->DrawEllipse( center, radius, stroke_width_, @@ -185,8 +149,9 @@ namespace kiwano void Canvas::DrawRect(Rect const& rect) { - rt_.SetDefaultBrushColor(stroke_color_); - rt_.DrawRectangle( + InitRenderTargetAndBrushs(); + rt_->SetCurrentBrush(stroke_brush_); + rt_->DrawRectangle( rect, stroke_width_, stroke_style_ @@ -196,8 +161,9 @@ namespace kiwano void Canvas::DrawRoundedRect(Rect const& rect, Vec2 const& radius) { - rt_.SetDefaultBrushColor(stroke_color_); - rt_.DrawRoundedRectangle( + InitRenderTargetAndBrushs(); + rt_->SetCurrentBrush(stroke_brush_); + rt_->DrawRoundedRectangle( rect, radius, stroke_width_, @@ -208,8 +174,9 @@ namespace kiwano void Canvas::FillCircle(Point const& center, float radius) { - rt_.SetDefaultBrushColor(fill_color_); - rt_.FillEllipse( + InitRenderTargetAndBrushs(); + rt_->SetCurrentBrush(fill_brush_); + rt_->FillEllipse( center, Vec2(radius, radius) ); @@ -218,8 +185,9 @@ namespace kiwano void Canvas::FillEllipse(Point const& center, Vec2 const& radius) { - rt_.SetDefaultBrushColor(fill_color_); - rt_.FillEllipse( + InitRenderTargetAndBrushs(); + rt_->SetCurrentBrush(fill_brush_); + rt_->FillEllipse( center, radius ); @@ -228,8 +196,9 @@ namespace kiwano void Canvas::FillRect(Rect const& rect) { - rt_.SetDefaultBrushColor(fill_color_); - rt_.FillRectangle( + InitRenderTargetAndBrushs(); + rt_->SetCurrentBrush(fill_brush_); + rt_->FillRectangle( rect ); cache_expired_ = true; @@ -237,31 +206,40 @@ namespace kiwano void Canvas::FillRoundedRect(Rect const& rect, Vec2 const& radius) { - rt_.SetDefaultBrushColor(fill_color_); - rt_.FillRoundedRectangle( + InitRenderTargetAndBrushs(); + rt_->SetCurrentBrush(fill_brush_); + rt_->FillRoundedRectangle( rect, radius ); cache_expired_ = true; } - void Canvas::DrawTexture(Texture const& texture, const Rect* src_rect, const Rect* dest_rect) + void Canvas::DrawTexture(TexturePtr texture, const Rect* src_rect, const Rect* dest_rect) { - if (texture.IsValid()) + if (texture) { - rt_.DrawTexture(texture, src_rect, dest_rect); + InitRenderTargetAndBrushs(); + rt_->DrawTexture(*texture, src_rect, dest_rect); cache_expired_ = true; } } - void Canvas::DrawText(String const& text, Point const& point) + void Canvas::DrawTextLayout(String const& text, Point const& point) { if (text.empty()) return; - TextLayout layout(text, text_font_, text_style_); + TextLayout layout; + layout.SetStyle(text_style_); + layout.SetText(text); + DrawTextLayout(layout, point); + } - rt_.DrawTextLayout(layout, point); + void Canvas::DrawTextLayout(TextLayout const& layout, Point const& point) + { + InitRenderTargetAndBrushs(); + rt_->DrawTextLayout(layout, point); } void Canvas::BeginPath(Point const& begin_pos) @@ -289,15 +267,16 @@ namespace kiwano geo_sink_.AddBezier(point1, point2, point3); } - void Canvas::AddArc(Point const & point, Point const & radius, float rotation, bool clockwise, bool is_small) + void Canvas::AddArc(Point const & point, Size const & radius, float rotation, bool clockwise, bool is_small) { geo_sink_.AddArc(point, radius, rotation, clockwise, is_small); } void Canvas::StrokePath() { - rt_.SetDefaultBrushColor(stroke_color_); - rt_.DrawGeometry( + InitRenderTargetAndBrushs(); + rt_->SetCurrentBrush(stroke_brush_); + rt_->DrawGeometry( geo_sink_.GetGeometry(), stroke_width_, stroke_style_ @@ -307,8 +286,9 @@ namespace kiwano void Canvas::FillPath() { - rt_.SetDefaultBrushColor(fill_color_); - rt_.FillGeometry( + InitRenderTargetAndBrushs(); + rt_->SetCurrentBrush(fill_brush_); + rt_->FillGeometry( geo_sink_.GetGeometry() ); cache_expired_ = true; @@ -316,28 +296,57 @@ namespace kiwano void Canvas::Clear() { - rt_.Clear(); + InitRenderTargetAndBrushs(); + rt_->Clear(); cache_expired_ = true; } void Canvas::Clear(Color const& clear_color) { - rt_.Clear(clear_color); + InitRenderTargetAndBrushs(); + rt_->Clear(clear_color); cache_expired_ = true; } - Texture Canvas::ExportToTexture() const + TexturePtr Canvas::ExportToTexture() const { UpdateCache(); return texture_cached_; } + void Canvas::InitRenderTargetAndBrushs() + { + if (!rt_) + { + Renderer::instance().CreateTextureRenderTarget(rt_); + } + + if (!stroke_brush_) + { + stroke_brush_ = new Brush; + stroke_brush_->SetColor(Color::White); + } + + if (!fill_brush_) + { + fill_brush_ = new Brush; + fill_brush_->SetColor(Color::White); + } + } + void Canvas::UpdateCache() const { - if (cache_expired_) + if (cache_expired_ && rt_) { - texture_cached_ = rt_.GetOutput(); - cache_expired_ = false; + if (!texture_cached_) + { + texture_cached_ = new Texture; + } + + if (rt_->GetOutput(*texture_cached_)) + { + cache_expired_ = false; + } } } diff --git a/src/kiwano/2d/Canvas.h b/src/kiwano/2d/Canvas.h index eefaee8e..d1530ba2 100644 --- a/src/kiwano/2d/Canvas.h +++ b/src/kiwano/2d/Canvas.h @@ -21,235 +21,314 @@ #pragma once #include #include - -#ifdef DrawText -# undef DrawText -#endif +#include namespace kiwano { - // »­²¼ + KGE_DECLARE_SMART_PTR(Canvas); + + /** + * \addtogroup Actors + * @{ + */ + + /** + * \~chinese + * @brief »­²¼£¬ÓÃÓÚ»æÖÆÍ¼Ôª + */ class KGE_API Canvas : public Actor { public: + /// \~chinese + /// @brief ¹¹½¨¿Õ»­²¼ Canvas(); virtual ~Canvas(); - // ¿ªÊ¼»æÍ¼ + /// \~chinese + /// @brief ¿ªÊ¼»æÍ¼ void BeginDraw(); - // ½áÊø»æÍ¼ + /// \~chinese + /// @brief ½áÊø»æÍ¼ void EndDraw(); - // »­Ö±Ïß - void DrawLine( - Point const& begin, - Point const& end - ); + /// \~chinese + /// @brief »­Ïß¶Î + /// @param begin Ïß¶ÎÆðµã + /// @param end Ïß¶ÎÖÕµã + void DrawLine(Point const& begin, Point const& end); - // »­Ô²Ðα߿ò - void DrawCircle( - Point const& center, - float radius - ); + /// \~chinese + /// @brief »­Ô²Ðα߿ò + /// @param center Ô²ÐÎÔ­µã + /// @param radius Ô²Ðΰ뾶 + void DrawCircle(Point const& center, float radius); - // »­ÍÖÔ²Ðα߿ò - void DrawEllipse( - Point const& center, - Vec2 const& radius - ); + /// \~chinese + /// @brief »­ÍÖÔ²Ðα߿ò + /// @param center ÍÖÔ²Ô­µã + /// @param radius ÍÖÔ²°ë¾¶ + void DrawEllipse(Point const& center, Vec2 const& radius); - // »­¾ØÐα߿ò - void DrawRect( - Rect const& rect - ); + /// \~chinese + /// @brief »­¾ØÐα߿ò + /// @param rect ¾ØÐÎ + void DrawRect(Rect const& rect); - // »­Ô²½Ç¾ØÐα߿ò - void DrawRoundedRect( - Rect const& rect, - Vec2 const& radius - ); + /// \~chinese + /// @brief »­Ô²½Ç¾ØÐα߿ò + /// @param rect ¾ØÐÎ + /// @param radius ¾ØÐÎÔ²½Ç°ë¾¶ + void DrawRoundedRect(Rect const& rect, Vec2 const& radius); - // Ìî³äÔ²ÐÎ - void FillCircle( - Point const& center, - float radius - ); + /// \~chinese + /// @brief Ìî³äÔ²ÐÎ + /// @param center Ô²ÐÎÔ­µã + /// @param radius Ô²Ðΰ뾶 + void FillCircle(Point const& center, float radius); - // Ìî³äÍÖÔ²ÐÎ - void FillEllipse( - Point const& center, - Vec2 const& radius - ); + /// \~chinese + /// @brief Ìî³äÍÖÔ²ÐÎ + /// @param center ÍÖÔ²Ô­µã + /// @param radius ÍÖÔ²°ë¾¶ + void FillEllipse(Point const& center, Vec2 const& radius); - // Ìî³ä¾ØÐÎ - void FillRect( - Rect const& rect - ); + /// \~chinese + /// @brief Ìî³ä¾ØÐÎ + /// @param rect ¾ØÐÎ + void FillRect(Rect const& rect); - // Ìî³äÔ²½Ç¾ØÐÎ - void FillRoundedRect( - Rect const& rect, - Vec2 const& radius - ); + /// \~chinese + /// @brief Ìî³äÔ²½Ç¾ØÐÎ + /// @param rect ¾ØÐÎ + /// @param radius ¾ØÐÎÔ²½Ç°ë¾¶ + void FillRoundedRect(Rect const& rect, Vec2 const& radius); - // »­Í¼ - void DrawTexture( - Texture const& texture, - const Rect* src_rect = nullptr, - const Rect* dest_rect = nullptr - ); + /// \~chinese + /// @brief »æÖÆÎÆÀí + /// @param texture ÎÆÀí + /// @param src_rect ÎÆÀí²Ã¼ôÇøÓò + /// @param dest_rect »æÖÆÄ¿±êÇøÓò + void DrawTexture(TexturePtr texture, const Rect* src_rect = nullptr, const Rect* dest_rect = nullptr); - // »­ÎÄ×Ö - void DrawText( - String const& text, /* ÎÄ×Ö */ - Point const& point /* ÎÄ×ÖλÖà */ - ); + /// \~chinese + /// @brief »æÖÆÎÄ×Ö²¼¾Ö + /// @param text ÎÄ×Ö + /// @param point »æÖÆÎÄ×ÖµÄλÖà + void DrawTextLayout(String const& text, Point const& point); - // ¿ªÊ¼»æÖÆÂ·¾¶ - void BeginPath( - Point const& begin_pos /* ·¾¶Æðʼµã */ - ); + /// \~chinese + /// @brief »æÖÆÎÄ×Ö²¼¾Ö + /// @param layout ÎÄ×Ö²¼¾Ö + /// @param point »æÖƲ¼¾ÖµÄλÖà + void DrawTextLayout(TextLayout const& layout, Point const& point); - // ½áÊøÂ·¾¶ - void EndPath( - bool closed = true /* ·¾¶ÊÇ·ñ±ÕºÏ */ - ); + /// \~chinese + /// @brief ¿ªÊ¼»æÖÆÂ·¾¶ + /// @param begin_pos ·¾¶Æðʼµã + void BeginPath(Point const& begin_pos); - // Ìí¼ÓÒ»ÌõÏß¶Î - void AddLine( - Point const& point /* ¶Ëµã */ - ); + /// \~chinese + /// @brief ½áÊøÂ·¾¶ + /// @param closed ·¾¶ÊÇ·ñ±ÕºÏ + void EndPath(bool closed = false); - // Ìí¼Ó¶àÌõÏß¶Î - void AddLines( - Vector const& points - ); + /// \~chinese + /// @brief Ìí¼ÓÒ»ÌõÏß¶Î + /// @param point ¶Ëµã + void AddLine(Point const& point); - // Ìí¼ÓÒ»ÌõÈý´Î·½±´Èû¶ûÇúÏß - void AddBezier( - Point const& point1, /* ±´Èû¶ûÇúÏߵĵÚÒ»¸ö¿ØÖƵã */ - Point const& point2, /* ±´Èû¶ûÇúÏߵĵڶþ¸ö¿ØÖƵã */ - Point const& point3 /* ±´Èû¶ûÇúÏßµÄÖÕµã */ - ); + /// \~chinese + /// @brief Ìí¼Ó¶àÌõÏß¶Î + /// @param points ¶Ëµã¼¯ºÏ + void AddLines(Vector const& points); - // Ìí¼Ó»¡Ïß - void AddArc( - Point const& point, /* ÖÕµã */ - Point const& radius, /* ÍÖÔ²°ë¾¶ */ - float rotation, /* ÍÖÔ²Ðýת½Ç¶È */ - bool clockwise = true, /* ˳ʱÕë or ÄæÊ±Õë */ - bool is_small = true /* ÊÇ·ñȡСÓÚ 180¡ã µÄ»¡ */ - ); + /// \~chinese + /// @brief Ìí¼ÓÒ»ÌõÈý´Î·½±´Èû¶ûÇúÏß + /// @param point1 ±´Èû¶ûÇúÏߵĵÚÒ»¸ö¿ØÖƵã + /// @param point2 ±´Èû¶ûÇúÏߵĵڶþ¸ö¿ØÖƵã + /// @param point3 ±´Èû¶ûÇúÏßµÄÖÕµã + void AddBezier(Point const& point1, Point const& point2, Point const& point3); - // ·¾¶Ãè±ß + /// \~chinese + /// @brief Ìí¼Ó»¡Ïß + /// @param point ÖÕµã + /// @param radius ÍÖÔ²°ë¾¶ + /// @param rotation ÍÖÔ²Ðýת½Ç¶È + /// @param clockwise ˳ʱÕë or ÄæÊ±Õë + /// @param is_small ÊÇ·ñȡСÓÚ 180¡ã µÄ»¡ + void AddArc(Point const& point, Size const& radius, float rotation, bool clockwise = true, bool is_small = true); + + /// \~chinese + /// @brief ÒÔÃè±ßµÄ·½Ê½»æÖÆÂ·¾¶ void StrokePath(); - // ·¾¶Ìî³ä + /// \~chinese + /// @brief ÒÔÌî³äµÄ·½Ê½»æÖÆÂ·¾¶ void FillPath(); - // Çå¿Õ»­²¼ + /// \~chinese + /// @brief Çå¿Õ»­²¼ void Clear(); - // Çå¿Õ»­²¼ - void Clear( - Color const& clear_color - ); + /// \~chinese + /// @brief Çå¿Õ»­²¼ + /// @param clear_color Çå¿ÕÑÕÉ« + void Clear(Color const& clear_color); - // ÉèÖÃÌî³äÑÕÉ« - void SetFillColor( - Color const& color - ); + /// \~chinese + /// @brief ÉèÖÃÌî³äÑÕÉ« + /// @param color Ìî³äÑÕÉ« + void SetFillColor(Color const& color); - // ÉèÖÃÂÖÀªÑÕÉ« - void SetStrokeColor( - Color const& color - ); + /// \~chinese + /// @brief ÉèÖÃÌî³ä»­Ë¢ + /// @param[in] brush Ìî³ä»­Ë¢ + void SetFillBrush(BrushPtr brush); - // ÉèÖÃÂÖÀª¿í¶È - void SetStrokeWidth( - float width - ); + /// \~chinese + /// @brief ÉèÖÃÂÖÀªÑÕÉ« + /// @param color ÂÖÀªÑÕÉ« + void SetStrokeColor(Color const& color); - // ÉèÖÃÂÖÀªÑùʽ - void SetStrokeStyle( - StrokeStyle stroke_style - ); + /// \~chinese + /// @brief ÉèÖÃÂÖÀª»­Ë¢ + /// @param[in] brush ÂÖÀª»­Ë¢ + void SetStrokeBrush(BrushPtr brush); - // ÉèÖÃÎÄ×Ö×ÖÌå - void SetTextFont( - Font const& font - ); + /// \~chinese + /// @brief ÉèÖÃÂÖÀª¿í¶È + /// @param width ÂÖÀª¿í¶È + void SetStrokeWidth(float width); - // ÉèÖÃÎÄ×Ö»­Ë¢Ñùʽ - void SetTextStyle( - TextStyle const& text_style - ); + /// \~chinese + /// @brief ÉèÖÃÂÖÀªÑùʽ + /// @param stroke_style ÂÖÀªÑùʽ + void SetStrokeStyle(StrokeStyle stroke_style); - // ÉèÖû­±Ê͸Ã÷¶È - void SetBrushOpacity( - float opacity - ); + /// \~chinese + /// @brief ÉèÖÃÎÄ×Ö»­Ë¢Ñùʽ + /// @param text_style ÎÄ×Ö»­Ë¢Ñùʽ + void SetTextStyle(TextStyle const& text_style); - // »­±Ê¶þά±ä»» - void SetBrushTransform( - Transform const& transform - ); + /// \~chinese + /// @brief ÉèÖû­Ë¢ + /// @param[in] brush »­Ë¢ + void SetBrush(BrushPtr brush); - // »­±Ê¶þά±ä»» - void SetBrushTransform( - Matrix3x2 const& transform - ); + /// \~chinese + /// @brief ÉèÖû­Ë¢¶þά±ä»» + /// @param transform ¶þά±ä»» + void SetBrushTransform(Transform const& transform); - // ÉèÖÃͼ²ã - void PushLayerArea( - LayerArea& area - ); + /// \~chinese + /// @brief ÉèÖû­Ë¢¶þά±ä»»¾ØÕó + /// @param transform ¶þά±ä»»¾ØÕó + void SetBrushTransform(Matrix3x2 const& transform); - // µ¯³öͼ²ã + /// \~chinese + /// @brief Ìí¼ÓÒ»¸öͼ²ã + /// @param area ͼ²ãÇøÓò + void PushLayerArea(LayerArea& area); + + /// \~chinese + /// @brief ɾ³ý×î½üÌí¼ÓµÄͼ²ã void PopLayerArea(); - // ÉèÖòüôÇøÓò - void PushClipRect( - Rect const& clip_rect - ); + /// \~chinese + /// @brief Ìí¼ÓÒ»¸ö²Ã¼ôÇøÓò + /// @param clip_rect ²Ã¼ô¾ØÐÎ + void PushClipRect(Rect const& clip_rect); - // µ¯³ö²Ã¼ôÇøÓò + /// \~chinese + /// @brief ɾ³ý×î½üÌí¼ÓµÄ²Ã¼ôÇøÓò void PopClipRect(); - // »ñÈ¡Ìî³äÑÕÉ« - Color GetFillColor() const; - - // »ñÈ¡ÂÖÀªÑÕÉ« - Color GetStrokeColor() const; - - // »ñÈ¡ÂÖÀª¿í¶È + /// \~chinese + /// @brief »ñÈ¡ÂÖÀª¿í¶È float GetStrokeWidth() const; - // »ñÈ¡»­±Ê͸Ã÷¶È - float GetBrushOpacity() const; + /// \~chinese + /// @brief »ñÈ¡Ìî³ä»­Ë¢ + BrushPtr GetFillBrush() const; - // µ¼³öΪͼƬ - Texture ExportToTexture() const; + /// \~chinese + /// @brief »ñÈ¡ÂÖÀª»­Ë¢ + BrushPtr GetStrokeBrush() const; + + /// \~chinese + /// @brief µ¼³öÎÆÀí + TexturePtr ExportToTexture() const; void OnRender(RenderTarget* rt) override; - protected: + private: + void InitRenderTargetAndBrushs(); + void UpdateCache() const; - protected: - float stroke_width_; - Color fill_color_; - Color stroke_color_; - Font text_font_; - TextStyle text_style_; - StrokeStyle stroke_style_; - GeometrySink geo_sink_; - TextureRenderTarget rt_; + private: + float stroke_width_; + TextStyle text_style_; + StrokeStyle stroke_style_; + GeometrySink geo_sink_; + BrushPtr fill_brush_; + BrushPtr stroke_brush_; - mutable bool cache_expired_; - mutable Texture texture_cached_; + mutable bool cache_expired_; + mutable TexturePtr texture_cached_; + mutable TextureRenderTargetPtr rt_; }; + + /** @} */ + + inline void Canvas::SetStrokeWidth(float width) + { + stroke_width_ = std::max(width, 0.f); + } + + inline void Canvas::SetStrokeStyle(StrokeStyle stroke_style) + { + stroke_style_ = stroke_style; + } + + inline void Canvas::SetTextStyle(TextStyle const& text_style) + { + text_style_ = text_style; + } + + inline void Canvas::SetStrokeColor(Color const& color) + { + InitRenderTargetAndBrushs(); + stroke_brush_->SetColor(color); + } + + inline void Canvas::SetFillColor(Color const& color) + { + InitRenderTargetAndBrushs(); + fill_brush_->SetColor(color); + } + + inline void Canvas::SetFillBrush(BrushPtr brush) + { + fill_brush_ = brush; + } + + inline void Canvas::SetStrokeBrush(BrushPtr brush) + { + stroke_brush_ = brush; + } + + inline BrushPtr Canvas::GetFillBrush() const + { + return fill_brush_; + } + + inline BrushPtr Canvas::GetStrokeBrush() const + { + return stroke_brush_; + } + } diff --git a/src/kiwano/2d/DebugActor.cpp b/src/kiwano/2d/DebugActor.cpp index f220de25..ae47b7a5 100644 --- a/src/kiwano/2d/DebugActor.cpp +++ b/src/kiwano/2d/DebugActor.cpp @@ -19,8 +19,8 @@ // THE SOFTWARE. #include -#include #include +#include #include #pragma comment(lib, "psapi.lib") @@ -31,7 +31,7 @@ namespace kiwano { class comma_numpunct : public std::numpunct { - protected: + private: virtual wchar_t do_thousands_sep() const override { return L','; @@ -42,32 +42,34 @@ namespace kiwano return "\03"; } }; + + std::locale comma_locale(std::locale(), new comma_numpunct); } DebugActor::DebugActor() - : background_color_(0.0f, 0.0f, 0.0f, 0.7f) { SetName(L"kiwano-debug-actor"); SetPosition(Point{ 10, 10 }); SetResponsible(true); SetCascadeOpacityEnabled(true); - debug_text_ = new Text; + background_brush_ = new Brush; + background_brush_->SetColor(Color(0.0f, 0.0f, 0.0f, 0.7f)); + + debug_text_ = new TextActor; debug_text_->SetPosition(Point{ 10, 10 }); this->AddChild(debug_text_); - Font font; - font.family = L"Arial"; - font.size = 16.f; - font.weight = FontWeight::Normal; - debug_text_->SetFont(font); - TextStyle style; + style.font_family = L"Arial"; + style.font_size = 16.f; + style.font_weight = FontWeight::Normal; style.line_spacing = 20.f; debug_text_->SetStyle(style); + debug_text_->SetFillColor(Color::White); - AddListener(event::MouseHover, [=](Event&) { SetOpacity(0.4f); }); - AddListener(event::MouseOut, [=](Event&) { SetOpacity(1.f); }); + AddListener([=](Event&) { SetOpacity(0.4f); }); + AddListener([=](Event&) { SetOpacity(1.f); }); } DebugActor::~DebugActor() @@ -76,9 +78,7 @@ namespace kiwano void DebugActor::OnRender(RenderTarget* rt) { - PrepareRender(rt); - - rt->SetDefaultBrushColor(background_color_); + rt->SetCurrentBrush(background_brush_); rt->FillRoundedRectangle(GetBounds(), Vec2{ 5.f, 5.f }); } @@ -94,24 +94,21 @@ namespace kiwano StringStream ss; - { - // For formatting integers with commas - static std::locale comma_locale(std::locale(), new comma_numpunct); - (void)ss.imbue(comma_locale); - } + // For formatting integers with commas + (void)ss.imbue(comma_locale); ss << "Fps: " << frame_time_.size() << std::endl; #if defined(KGE_DEBUG) if (ObjectBase::IsTracingLeaks()) { - ss << "Objects: " << ObjectBase::__GetTracingObjects().size() << std::endl; + ss << "Objects: " << ObjectBase::GetTracingObjects().size() << std::endl; } #endif - ss << "Render: " << Renderer::GetInstance()->GetStatus().duration.Milliseconds() << "ms" << std::endl; + ss << "Render: " << Renderer::instance().GetStatus().duration.Milliseconds() << "ms" << std::endl; - ss << "Primitives / sec: " << std::fixed << Renderer::GetInstance()->GetStatus().primitives * frame_time_.size() << std::endl; + ss << "Primitives / sec: " << std::fixed << Renderer::instance().GetStatus().primitives * frame_time_.size() << std::endl; ss << "Memory: "; { @@ -140,4 +137,9 @@ namespace kiwano } } + bool DebugActor::CheckVisibilty(RenderTarget* rt) const + { + return true; + } + } diff --git a/src/kiwano/2d/DebugActor.h b/src/kiwano/2d/DebugActor.h index 7c4299e1..e35f2344 100644 --- a/src/kiwano/2d/DebugActor.h +++ b/src/kiwano/2d/DebugActor.h @@ -20,9 +20,21 @@ #pragma once #include +#include +#include +#include namespace kiwano { + /** + * \addtogroup Actors + * @{ + */ + + /** + * \~chinese + * @brief µ÷ÊÔ½Úµã + */ class KGE_API DebugActor : public Actor { @@ -36,8 +48,14 @@ namespace kiwano void OnUpdate(Duration dt) override; protected: - Color background_color_; - TextPtr debug_text_; + bool CheckVisibilty(RenderTarget* rt) const override; + + private: + BrushPtr background_brush_; + TextActorPtr debug_text_; Vector