Merge pull request #46 from KiwanoEngine/docs

Add documents
This commit is contained in:
Haibo 2020-01-07 18:06:50 +08:00 committed by GitHub
commit 920256886e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
231 changed files with 16053 additions and 13739 deletions

4
.gitignore vendored
View File

@ -26,4 +26,6 @@ packages/
!*.lib
# Resources bin
*.aps
*.aps
docs/

90
Doxyfile Normal file
View File

@ -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

BIN
logo/logo_square_tiny.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

View File

@ -185,4 +185,4 @@
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
</Project>

View File

@ -1,97 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<ClInclude Include="..\..\..\src\3rd-party\StackWalker\StackWalker.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\..\..\src\3rd-party\StackWalker\StackWalker.cpp" />
</ItemGroup>
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{3A3948DC-9865-46B3-B7B9-7E5572704ED2}</ProjectGuid>
<RootNamespace>libStackWalker</RootNamespace>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<CharacterSet>Unicode</CharacterSet>
<PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>false</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
<PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<OutDir>$(SolutionDir)\output\$(PlatformToolset)\$(Platform)\$(Configuration)\</OutDir>
<IntDir>$(SolutionDir)\build\$(PlatformToolset)\$(Platform)\$(Configuration)\$(ProjectName)\</IntDir>
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<OutDir>$(SolutionDir)\output\$(PlatformToolset)\$(Platform)\$(Configuration)\</OutDir>
<IntDir>$(SolutionDir)\build\$(PlatformToolset)\$(Platform)\$(Configuration)\$(ProjectName)\</IntDir>
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<TreatWarningAsError>true</TreatWarningAsError>
<DebugInformationFormat>None</DebugInformationFormat>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<AdditionalIncludeDirectories>../../../src/3rd-party;</AdditionalIncludeDirectories>
<MinimalRebuild>false</MinimalRebuild>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<BufferSecurityCheck>false</BufferSecurityCheck>
<TreatWarningAsError>true</TreatWarningAsError>
<DebugInformationFormat>None</DebugInformationFormat>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<AdditionalIncludeDirectories>../../../src/3rd-party;</AdditionalIncludeDirectories>
<MinimalRebuild>false</MinimalRebuild>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>false</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
</Link>
</ItemDefinitionGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View File

@ -1,9 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<ClCompile Include="..\..\..\src\3rd-party\StackWalker\StackWalker.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\..\src\3rd-party\StackWalker\StackWalker.h" />
</ItemGroup>
</Project>

View File

@ -102,4 +102,4 @@
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
</Project>

View File

@ -102,4 +102,4 @@
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
</Project>

View File

@ -94,4 +94,4 @@
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
</Project>

View File

@ -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}

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<ClInclude Include="..\..\src\kiwano-audio\audio-modules.h" />
<ClInclude Include="..\..\src\kiwano-audio\libraries.h" />
<ClInclude Include="..\..\src\kiwano-audio\AudioEngine.h" />
<ClInclude Include="..\..\src\kiwano-audio\kiwano-audio.h" />
<ClInclude Include="..\..\src\kiwano-audio\Sound.h" />
@ -19,7 +19,7 @@
</ProjectConfiguration>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\..\src\kiwano-audio\audio-modules.cpp" />
<ClCompile Include="..\..\src\kiwano-audio\libraries.cpp" />
<ClCompile Include="..\..\src\kiwano-audio\AudioEngine.cpp" />
<ClCompile Include="..\..\src\kiwano-audio\Sound.cpp" />
<ClCompile Include="..\..\src\kiwano-audio\SoundPlayer.cpp" />
@ -39,7 +39,7 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>false</WholeProgramOptimization>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
<PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
</PropertyGroup>
@ -108,4 +108,4 @@
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
</Project>

View File

@ -3,16 +3,16 @@
<ItemGroup>
<ClInclude Include="..\..\src\kiwano-audio\kiwano-audio.h" />
<ClInclude Include="..\..\src\kiwano-audio\AudioEngine.h" />
<ClInclude Include="..\..\src\kiwano-audio\audio-modules.h" />
<ClInclude Include="..\..\src\kiwano-audio\Sound.h" />
<ClInclude Include="..\..\src\kiwano-audio\SoundPlayer.h" />
<ClInclude Include="..\..\src\kiwano-audio\Transcoder.h" />
<ClInclude Include="..\..\src\kiwano-audio\libraries.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\..\src\kiwano-audio\AudioEngine.cpp" />
<ClCompile Include="..\..\src\kiwano-audio\audio-modules.cpp" />
<ClCompile Include="..\..\src\kiwano-audio\Sound.cpp" />
<ClCompile Include="..\..\src\kiwano-audio\SoundPlayer.cpp" />
<ClCompile Include="..\..\src\kiwano-audio\Transcoder.cpp" />
<ClCompile Include="..\..\src\kiwano-audio\libraries.cpp" />
</ItemGroup>
</Project>

View File

@ -38,7 +38,7 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>false</WholeProgramOptimization>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
<PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
</PropertyGroup>
@ -110,4 +110,4 @@
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
</Project>

View File

@ -34,7 +34,7 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>false</WholeProgramOptimization>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
<PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
</PropertyGroup>
@ -106,4 +106,4 @@
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
</Project>

View File

@ -13,6 +13,7 @@
<ItemGroup>
<ClInclude Include="..\..\src\kiwano-physics\Body.h" />
<ClInclude Include="..\..\src\kiwano-physics\Contact.h" />
<ClInclude Include="..\..\src\kiwano-physics\ContactEdge.h" />
<ClInclude Include="..\..\src\kiwano-physics\ContactEvent.h" />
<ClInclude Include="..\..\src\kiwano-physics\Fixture.h" />
<ClInclude Include="..\..\src\kiwano-physics\helper.h" />
@ -24,6 +25,7 @@
<ItemGroup>
<ClCompile Include="..\..\src\kiwano-physics\Body.cpp" />
<ClCompile Include="..\..\src\kiwano-physics\Contact.cpp" />
<ClCompile Include="..\..\src\kiwano-physics\ContactEdge.cpp" />
<ClCompile Include="..\..\src\kiwano-physics\ContactEvent.cpp" />
<ClCompile Include="..\..\src\kiwano-physics\Fixture.cpp" />
<ClCompile Include="..\..\src\kiwano-physics\Joint.cpp" />
@ -44,7 +46,7 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>false</WholeProgramOptimization>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
<PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
</PropertyGroup>

View File

@ -10,6 +10,7 @@
<ClInclude Include="..\..\src\kiwano-physics\Fixture.h" />
<ClInclude Include="..\..\src\kiwano-physics\Contact.h" />
<ClInclude Include="..\..\src\kiwano-physics\ContactEvent.h" />
<ClInclude Include="..\..\src\kiwano-physics\ContactEdge.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\..\src\kiwano-physics\Body.cpp" />
@ -19,5 +20,6 @@
<ClCompile Include="..\..\src\kiwano-physics\Fixture.cpp" />
<ClCompile Include="..\..\src\kiwano-physics\Contact.cpp" />
<ClCompile Include="..\..\src\kiwano-physics\ContactEvent.cpp" />
<ClCompile Include="..\..\src\kiwano-physics\ContactEdge.cpp" />
</ItemGroup>
</Project>

View File

@ -11,24 +11,16 @@
<ClInclude Include="..\..\src\kiwano\2d\action\Animation.h" />
<ClInclude Include="..\..\src\kiwano\2d\Frame.h" />
<ClInclude Include="..\..\src\kiwano\2d\GifSprite.h" />
<ClInclude Include="..\..\src\kiwano\core\Event.h" />
<ClInclude Include="..\..\src\kiwano\core\common.h" />
<ClInclude Include="..\..\src\kiwano\core\event\Event.h" />
<ClInclude Include="..\..\src\kiwano\core\event\EventType.h" />
<ClInclude Include="..\..\src\kiwano\core\event\KeyEvent.h" />
<ClInclude Include="..\..\src\kiwano\core\event\MouseEvent.h" />
<ClInclude Include="..\..\src\kiwano\core\event\WindowEvent.h" />
<ClInclude Include="..\..\src\kiwano\core\Library.h" />
<ClInclude Include="..\..\src\kiwano\core\win32\ComPtr.hpp" />
<ClInclude Include="..\..\src\kiwano\core\win32\helper.h" />
<ClInclude Include="..\..\src\kiwano\common\any.hpp" />
<ClInclude Include="..\..\src\kiwano\common\basic_json.hpp" />
<ClInclude Include="..\..\src\kiwano\common\function.hpp" />
<ClInclude Include="..\..\src\kiwano\common\common.h" />
<ClInclude Include="..\..\src\kiwano\common\intrusive_list.hpp" />
<ClInclude Include="..\..\src\kiwano\common\intrusive_ptr.hpp" />
<ClInclude Include="..\..\src\kiwano\common\noncopyable.hpp" />
<ClInclude Include="..\..\src\kiwano\common\singleton.hpp" />
<ClInclude Include="..\..\src\kiwano\common\string.hpp" />
<ClInclude Include="..\..\src\kiwano\common\vector.hpp" />
<ClInclude Include="..\..\src\kiwano\kiwano.h" />
<ClInclude Include="..\..\src\kiwano\config.h" />
<ClInclude Include="..\..\src\kiwano\macros.h" />
<ClInclude Include="..\..\src\kiwano\2d\include-forwards.h" />
<ClInclude Include="..\..\src\kiwano\2d\Canvas.h" />
<ClInclude Include="..\..\src\kiwano\2d\DebugActor.h" />
<ClInclude Include="..\..\src\kiwano\2d\FrameSequence.h" />
@ -37,8 +29,7 @@
<ClInclude Include="..\..\src\kiwano\2d\Actor.h" />
<ClInclude Include="..\..\src\kiwano\2d\Stage.h" />
<ClInclude Include="..\..\src\kiwano\2d\Sprite.h" />
<ClInclude Include="..\..\src\kiwano\2d\Text.h" />
<ClInclude Include="..\..\src\kiwano\2d\TextStyle.hpp" />
<ClInclude Include="..\..\src\kiwano\2d\TextActor.h" />
<ClInclude Include="..\..\src\kiwano\2d\Transform.h" />
<ClInclude Include="..\..\src\kiwano\2d\Transition.h" />
<ClInclude Include="..\..\src\kiwano\core\AsyncTask.h" />
@ -48,7 +39,7 @@
<ClInclude Include="..\..\src\kiwano\core\keys.h" />
<ClInclude Include="..\..\src\kiwano\core\Logger.h" />
<ClInclude Include="..\..\src\kiwano\core\ObjectBase.h" />
<ClInclude Include="..\..\src\kiwano\core\RefCounter.hpp" />
<ClInclude Include="..\..\src\kiwano\core\RefCounter.h" />
<ClInclude Include="..\..\src\kiwano\core\Resource.h" />
<ClInclude Include="..\..\src\kiwano\core\SmartPtr.hpp" />
<ClInclude Include="..\..\src\kiwano\core\Timer.h" />
@ -66,15 +57,18 @@
<ClInclude Include="..\..\src\kiwano\platform\Director.h" />
<ClInclude Include="..\..\src\kiwano\platform\FileSystem.h" />
<ClInclude Include="..\..\src\kiwano\platform\Input.h" />
<ClInclude Include="..\..\src\kiwano\platform\modules.h" />
<ClInclude Include="..\..\src\kiwano\platform\win32\ComPtr.hpp" />
<ClInclude Include="..\..\src\kiwano\platform\win32\helper.h" />
<ClInclude Include="..\..\src\kiwano\platform\win32\libraries.h" />
<ClInclude Include="..\..\src\kiwano\platform\Window.h" />
<ClInclude Include="..\..\src\kiwano\renderer\Brush.h" />
<ClInclude Include="..\..\src\kiwano\renderer\Color.h" />
<ClInclude Include="..\..\src\kiwano\renderer\Font.h" />
<ClInclude Include="..\..\src\kiwano\renderer\FontCollection.h" />
<ClInclude Include="..\..\src\kiwano\renderer\Geometry.h" />
<ClInclude Include="..\..\src\kiwano\renderer\GeometrySink.h" />
<ClInclude Include="..\..\src\kiwano\renderer\GifImage.h" />
<ClInclude Include="..\..\src\kiwano\renderer\StrokeStyle.h" />
<ClInclude Include="..\..\src\kiwano\renderer\TextStyle.hpp" />
<ClInclude Include="..\..\src\kiwano\renderer\Texture.h" />
<ClInclude Include="..\..\src\kiwano\renderer\TextureCache.h" />
<ClInclude Include="..\..\src\kiwano\renderer\LayerArea.h" />
@ -86,6 +80,7 @@
<ClInclude Include="..\..\src\kiwano\renderer\win32\D3D11DeviceResources.h" />
<ClInclude Include="..\..\src\kiwano\renderer\win32\D3DDeviceResourcesBase.h" />
<ClInclude Include="..\..\src\kiwano\renderer\win32\FontCollectionLoader.h" />
<ClInclude Include="..\..\src\kiwano\renderer\win32\helper.h" />
<ClInclude Include="..\..\src\kiwano\renderer\win32\TextRenderer.h" />
<ClInclude Include="..\..\src\kiwano\ui\Button.h" />
<ClInclude Include="..\..\src\kiwano\ui\Menu.h" />
@ -111,17 +106,21 @@
<ClCompile Include="..\..\src\kiwano\2d\Actor.cpp" />
<ClCompile Include="..\..\src\kiwano\2d\Stage.cpp" />
<ClCompile Include="..\..\src\kiwano\2d\Sprite.cpp" />
<ClCompile Include="..\..\src\kiwano\2d\Text.cpp" />
<ClCompile Include="..\..\src\kiwano\2d\TextActor.cpp" />
<ClCompile Include="..\..\src\kiwano\2d\Transform.cpp" />
<ClCompile Include="..\..\src\kiwano\2d\Transition.cpp" />
<ClCompile Include="..\..\src\kiwano\core\AsyncTask.cpp" />
<ClCompile Include="..\..\src\kiwano\core\Component.cpp" />
<ClCompile Include="..\..\src\kiwano\core\Event.cpp" />
<ClCompile Include="..\..\src\kiwano\core\EventDispatcher.cpp" />
<ClCompile Include="..\..\src\kiwano\core\EventListener.cpp" />
<ClCompile Include="..\..\src\kiwano\core\event\Event.cpp" />
<ClCompile Include="..\..\src\kiwano\core\event\KeyEvent.cpp" />
<ClCompile Include="..\..\src\kiwano\core\event\MouseEvent.cpp" />
<ClCompile Include="..\..\src\kiwano\core\event\WindowEvent.cpp" />
<ClCompile Include="..\..\src\kiwano\core\Library.cpp" />
<ClCompile Include="..\..\src\kiwano\core\Logger.cpp" />
<ClCompile Include="..\..\src\kiwano\core\ObjectBase.cpp" />
<ClCompile Include="..\..\src\kiwano\core\RefCounter.cpp" />
<ClCompile Include="..\..\src\kiwano\core\Resource.cpp" />
<ClCompile Include="..\..\src\kiwano\core\Timer.cpp" />
<ClCompile Include="..\..\src\kiwano\core\TimerManager.cpp" />
@ -130,13 +129,14 @@
<ClCompile Include="..\..\src\kiwano\platform\Director.cpp" />
<ClCompile Include="..\..\src\kiwano\platform\FileSystem.cpp" />
<ClCompile Include="..\..\src\kiwano\platform\Input.cpp" />
<ClCompile Include="..\..\src\kiwano\platform\modules.cpp" />
<ClCompile Include="..\..\src\kiwano\platform\win32\libraries.cpp" />
<ClCompile Include="..\..\src\kiwano\platform\win32\StackWalker.cpp" />
<ClCompile Include="..\..\src\kiwano\platform\Window.cpp" />
<ClCompile Include="..\..\src\kiwano\renderer\Brush.cpp" />
<ClCompile Include="..\..\src\kiwano\renderer\Color.cpp" />
<ClCompile Include="..\..\src\kiwano\renderer\Font.cpp" />
<ClCompile Include="..\..\src\kiwano\renderer\FontCollection.cpp" />
<ClCompile Include="..\..\src\kiwano\renderer\Geometry.cpp" />
<ClCompile Include="..\..\src\kiwano\renderer\GeometrySink.cpp" />
<ClCompile Include="..\..\src\kiwano\renderer\GifImage.cpp" />
<ClCompile Include="..\..\src\kiwano\renderer\Texture.cpp" />
<ClCompile Include="..\..\src\kiwano\renderer\TextureCache.cpp" />
@ -166,9 +166,6 @@
</ProjectConfiguration>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\3rd-party\StackWalker\libStackWalker.vcxproj">
<Project>{3a3948dc-9865-46b3-b7b9-7e5572704ed2}</Project>
</ProjectReference>
<ProjectReference Include="..\3rd-party\tinyxml2\libtinyxml2.vcxproj">
<Project>{ab47e875-85e5-4105-a71e-88930eaab910}</Project>
</ProjectReference>
@ -187,7 +184,7 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>false</WholeProgramOptimization>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
<PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
</PropertyGroup>

View File

@ -25,14 +25,14 @@
<Filter Include="2d\action">
<UniqueIdentifier>{9314f30d-5742-48b6-94e5-e3b4284106f6}</UniqueIdentifier>
</Filter>
<Filter Include="common">
<UniqueIdentifier>{86e2d0f2-a9d0-4456-b6a5-d480228bbf82}</UniqueIdentifier>
</Filter>
<Filter Include="renderer\win32">
<UniqueIdentifier>{30333461-e9bc-4709-84bd-ce6e0e1a3079}</UniqueIdentifier>
</Filter>
<Filter Include="core\win32">
<UniqueIdentifier>{192a47a9-9df6-4f40-a7d3-888eb00c53ac}</UniqueIdentifier>
<Filter Include="platform\win32">
<UniqueIdentifier>{e84dcf9a-e650-473e-8c9c-193804ab9e76}</UniqueIdentifier>
</Filter>
<Filter Include="core\event">
<UniqueIdentifier>{c629aedd-ffb9-4bc1-82c3-f50e77c82e77}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
@ -45,21 +45,12 @@
<ClInclude Include="..\..\src\kiwano\2d\Canvas.h">
<Filter>2d</Filter>
</ClInclude>
<ClInclude Include="..\..\src\kiwano\2d\include-forwards.h">
<Filter>2d</Filter>
</ClInclude>
<ClInclude Include="..\..\src\kiwano\2d\Layer.h">
<Filter>2d</Filter>
</ClInclude>
<ClInclude Include="..\..\src\kiwano\2d\Sprite.h">
<Filter>2d</Filter>
</ClInclude>
<ClInclude Include="..\..\src\kiwano\2d\Text.h">
<Filter>2d</Filter>
</ClInclude>
<ClInclude Include="..\..\src\kiwano\2d\TextStyle.hpp">
<Filter>2d</Filter>
</ClInclude>
<ClInclude Include="..\..\src\kiwano\2d\Transition.h">
<Filter>2d</Filter>
</ClInclude>
@ -72,9 +63,6 @@
<ClInclude Include="..\..\src\kiwano\core\EventListener.h">
<Filter>core</Filter>
</ClInclude>
<ClInclude Include="..\..\src\kiwano\core\RefCounter.hpp">
<Filter>core</Filter>
</ClInclude>
<ClInclude Include="..\..\src\kiwano\core\Resource.h">
<Filter>core</Filter>
</ClInclude>
@ -93,9 +81,6 @@
<ClInclude Include="..\..\src\kiwano\platform\Application.h">
<Filter>platform</Filter>
</ClInclude>
<ClInclude Include="..\..\src\kiwano\platform\modules.h">
<Filter>platform</Filter>
</ClInclude>
<ClInclude Include="..\..\src\kiwano\config.h" />
<ClInclude Include="..\..\src\kiwano\macros.h" />
<ClInclude Include="..\..\src\kiwano\math\Vec2.hpp">
@ -150,33 +135,6 @@
<ClInclude Include="..\..\src\kiwano\2d\FrameSequence.h">
<Filter>2d</Filter>
</ClInclude>
<ClInclude Include="..\..\src\kiwano\common\basic_json.hpp">
<Filter>common</Filter>
</ClInclude>
<ClInclude Include="..\..\src\kiwano\common\function.hpp">
<Filter>common</Filter>
</ClInclude>
<ClInclude Include="..\..\src\kiwano\common\intrusive_list.hpp">
<Filter>common</Filter>
</ClInclude>
<ClInclude Include="..\..\src\kiwano\common\intrusive_ptr.hpp">
<Filter>common</Filter>
</ClInclude>
<ClInclude Include="..\..\src\kiwano\common\noncopyable.hpp">
<Filter>common</Filter>
</ClInclude>
<ClInclude Include="..\..\src\kiwano\common\singleton.hpp">
<Filter>common</Filter>
</ClInclude>
<ClInclude Include="..\..\src\kiwano\common\string.hpp">
<Filter>common</Filter>
</ClInclude>
<ClInclude Include="..\..\src\kiwano\common\vector.hpp">
<Filter>common</Filter>
</ClInclude>
<ClInclude Include="..\..\src\kiwano\common\common.h">
<Filter>common</Filter>
</ClInclude>
<ClInclude Include="..\..\src\kiwano\2d\DebugActor.h">
<Filter>2d</Filter>
</ClInclude>
@ -240,9 +198,6 @@
<ClInclude Include="..\..\src\kiwano\renderer\RenderTarget.h">
<Filter>renderer</Filter>
</ClInclude>
<ClInclude Include="..\..\src\kiwano\renderer\FontCollection.h">
<Filter>renderer</Filter>
</ClInclude>
<ClInclude Include="..\..\src\kiwano\2d\Transform.h">
<Filter>2d</Filter>
</ClInclude>
@ -267,27 +222,15 @@
<ClInclude Include="..\..\src\kiwano\math\scalar.h">
<Filter>math</Filter>
</ClInclude>
<ClInclude Include="..\..\src\kiwano\core\win32\ComPtr.hpp">
<Filter>core\win32</Filter>
</ClInclude>
<ClInclude Include="..\..\src\kiwano\core\win32\helper.h">
<Filter>core\win32</Filter>
</ClInclude>
<ClInclude Include="..\..\src\kiwano\utils\LocalStorage.h">
<Filter>utils</Filter>
</ClInclude>
<ClInclude Include="..\..\src\kiwano\common\any.hpp">
<Filter>common</Filter>
</ClInclude>
<ClInclude Include="..\..\src\kiwano\utils\UserData.h">
<Filter>utils</Filter>
</ClInclude>
<ClInclude Include="..\..\src\kiwano\core\Library.h">
<Filter>core</Filter>
</ClInclude>
<ClInclude Include="..\..\src\kiwano\core\Event.h">
<Filter>core</Filter>
</ClInclude>
<ClInclude Include="..\..\src\kiwano\platform\FileSystem.h">
<Filter>platform</Filter>
</ClInclude>
@ -303,6 +246,48 @@
<ClInclude Include="..\..\src\kiwano\platform\Director.h">
<Filter>platform</Filter>
</ClInclude>
<ClInclude Include="..\..\src\kiwano\2d\TextActor.h">
<Filter>2d</Filter>
</ClInclude>
<ClInclude Include="..\..\src\kiwano\core\common.h">
<Filter>core</Filter>
</ClInclude>
<ClInclude Include="..\..\src\kiwano\core\RefCounter.h">
<Filter>core</Filter>
</ClInclude>
<ClInclude Include="..\..\src\kiwano\renderer\TextStyle.hpp">
<Filter>renderer</Filter>
</ClInclude>
<ClInclude Include="..\..\src\kiwano\renderer\win32\helper.h">
<Filter>renderer\win32</Filter>
</ClInclude>
<ClInclude Include="..\..\src\kiwano\renderer\GeometrySink.h">
<Filter>renderer</Filter>
</ClInclude>
<ClInclude Include="..\..\src\kiwano\platform\win32\ComPtr.hpp">
<Filter>platform\win32</Filter>
</ClInclude>
<ClInclude Include="..\..\src\kiwano\platform\win32\libraries.h">
<Filter>platform\win32</Filter>
</ClInclude>
<ClInclude Include="..\..\src\kiwano\platform\win32\helper.h">
<Filter>platform\win32</Filter>
</ClInclude>
<ClInclude Include="..\..\src\kiwano\core\event\Event.h">
<Filter>core\event</Filter>
</ClInclude>
<ClInclude Include="..\..\src\kiwano\core\event\EventType.h">
<Filter>core\event</Filter>
</ClInclude>
<ClInclude Include="..\..\src\kiwano\core\event\KeyEvent.h">
<Filter>core\event</Filter>
</ClInclude>
<ClInclude Include="..\..\src\kiwano\core\event\MouseEvent.h">
<Filter>core\event</Filter>
</ClInclude>
<ClInclude Include="..\..\src\kiwano\core\event\WindowEvent.h">
<Filter>core\event</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\..\src\kiwano\ui\Button.cpp">
@ -320,9 +305,6 @@
<ClCompile Include="..\..\src\kiwano\2d\Sprite.cpp">
<Filter>2d</Filter>
</ClCompile>
<ClCompile Include="..\..\src\kiwano\2d\Text.cpp">
<Filter>2d</Filter>
</ClCompile>
<ClCompile Include="..\..\src\kiwano\2d\Transition.cpp">
<Filter>2d</Filter>
</ClCompile>
@ -341,9 +323,6 @@
<ClCompile Include="..\..\src\kiwano\platform\Application.cpp">
<Filter>platform</Filter>
</ClCompile>
<ClCompile Include="..\..\src\kiwano\platform\modules.cpp">
<Filter>platform</Filter>
</ClCompile>
<ClCompile Include="..\..\src\kiwano\core\Timer.cpp">
<Filter>core</Filter>
</ClCompile>
@ -443,9 +422,6 @@
<ClCompile Include="..\..\src\kiwano\renderer\RenderTarget.cpp">
<Filter>renderer</Filter>
</ClCompile>
<ClCompile Include="..\..\src\kiwano\renderer\FontCollection.cpp">
<Filter>renderer</Filter>
</ClCompile>
<ClCompile Include="..\..\src\kiwano\2d\Transform.cpp">
<Filter>2d</Filter>
</ClCompile>
@ -470,9 +446,6 @@
<ClCompile Include="..\..\src\kiwano\core\Library.cpp">
<Filter>core</Filter>
</ClCompile>
<ClCompile Include="..\..\src\kiwano\core\Event.cpp">
<Filter>core</Filter>
</ClCompile>
<ClCompile Include="..\..\src\kiwano\platform\FileSystem.cpp">
<Filter>platform</Filter>
</ClCompile>
@ -485,5 +458,32 @@
<ClCompile Include="..\..\src\kiwano\platform\Director.cpp">
<Filter>platform</Filter>
</ClCompile>
<ClCompile Include="..\..\src\kiwano\2d\TextActor.cpp">
<Filter>2d</Filter>
</ClCompile>
<ClCompile Include="..\..\src\kiwano\core\RefCounter.cpp">
<Filter>core</Filter>
</ClCompile>
<ClCompile Include="..\..\src\kiwano\renderer\GeometrySink.cpp">
<Filter>renderer</Filter>
</ClCompile>
<ClCompile Include="..\..\src\kiwano\platform\win32\libraries.cpp">
<Filter>platform\win32</Filter>
</ClCompile>
<ClCompile Include="..\..\src\kiwano\platform\win32\StackWalker.cpp">
<Filter>platform\win32</Filter>
</ClCompile>
<ClCompile Include="..\..\src\kiwano\core\event\Event.cpp">
<Filter>core\event</Filter>
</ClCompile>
<ClCompile Include="..\..\src\kiwano\core\event\KeyEvent.cpp">
<Filter>core\event</Filter>
</ClCompile>
<ClCompile Include="..\..\src\kiwano\core\event\MouseEvent.cpp">
<Filter>core\event</Filter>
</ClCompile>
<ClCompile Include="..\..\src\kiwano\core\event\WindowEvent.cpp">
<Filter>core\event</Filter>
</ClCompile>
</ItemGroup>
</Project>

View File

@ -3,14 +3,19 @@ function Set-FileConfiguration {
[string]$filePath
)
$replace = "<DebugInformationFormat>(EditAndContinue|ProgramDatabase)</DebugInformationFormat>"
$replaceTo = "<DebugInformationFormat>None</DebugInformationFormat>"
$debugInfoReplace = "<DebugInformationFormat>(EditAndContinue|ProgramDatabase)</DebugInformationFormat>"
$debugInfoReplaceTo = "<DebugInformationFormat>None</DebugInformationFormat>"
$optimizationReplace = "<WholeProgramOptimization>true</WholeProgramOptimization>"
$optimizationReplaceTo = "<WholeProgramOptimization>false</WholeProgramOptimization>"
# 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 + '\' + $_)
}
}

21
src/3rd-party/OuterC/LICENSE vendored Normal file
View File

@ -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.

View File

@ -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 <typeinfo>
#include <type_traits>
#include <exception>
namespace kiwano
{
namespace common
namespace oc
{
class bad_any_cast : public std::exception
@ -133,7 +112,7 @@ public:
template <typename _Ty>
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);
}
}

169
src/3rd-party/OuterC/oc/function.h vendored Normal file
View File

@ -0,0 +1,169 @@
// Copyright (c) 2019-2020 OuterC - Nomango
#pragma once
#include "function/details.h"
#include <stdexcept>
namespace oc
{
class bad_function_call : public ::std::exception
{
public:
bad_function_call() {}
virtual const char* what() const override
{
return "bad function call";
}
};
template<typename _Ty>
class function;
template<typename _Ret, typename... _Args>
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<typename _Ty,
typename _Uty,
typename = typename ::std::enable_if<::std::is_same<_Ty, _Uty>::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<typename _Ty,
typename _Uty,
typename = typename ::std::enable_if<::std::is_same<_Ty, _Uty>::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<typename _Ty,
typename _Uty,
typename = typename std::enable_if<
std::is_same<_Ty, _Uty>::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<typename _Ty,
typename _Uty,
typename = typename std::enable_if<
std::is_same<_Ty, _Uty>::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<typename _Ret, typename... _Args>
inline void swap(oc::function<_Ret(_Args...)>& lhs, oc::function<_Ret(_Args...)>& rhs) noexcept
{
lhs.swap(rhs);
}
} // namespace oc

View File

@ -0,0 +1,168 @@
// Copyright (c) 2019-2020 OuterC - Nomango
#pragma once
#include <type_traits>
namespace oc
{
namespace __function_detail
{
template <typename _Ty, typename _Ret, typename... _Args>
struct is_callable_helper
{
template <typename _Uty, _Ret(_Uty::*)(_Args...)>
struct class_mem;
template <typename _Uty, _Ret(_Uty::*)(_Args...) const>
struct class_const_mem;
template <typename _Uty>
static int test(...);
template <typename _Uty>
static char test(class_mem<_Uty, &_Uty::operator()>*);
template <typename _Uty>
static char test(class_const_mem<_Uty, &_Uty::operator()>*);
template<
typename _Uty,
typename _Uret = typename std::decay<decltype(std::declval<_Uty>().operator()(std::declval<_Args>()...))>::type,
typename = typename std::enable_if<std::is_convertible<_Ret, _Uret>::value>::type
>
static char test(int);
static constexpr bool value = sizeof(test<_Ty>(0)) == sizeof(char);
};
template<typename _Ty, typename _Ret, typename... _Args>
struct is_callable
: public ::std::bool_constant<is_callable_helper<_Ty, _Ret, _Args...>::value>
{
};
//
// callable
//
template<typename _Ret, typename... _Args>
class callable
{
public:
virtual ~callable() {}
virtual void retain() = 0;
virtual void release() = 0;
virtual _Ret invoke(_Args... args) const = 0;
};
template<typename _Ret, typename... _Args>
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<typename _Ty, typename _Ret, typename... _Args>
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<typename _Ty, typename _Ret, typename... _Args>
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<typename _Ty, typename _Ret, typename... _Args>
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

254
src/3rd-party/OuterC/oc/intrusive_list.h vendored Normal file
View File

@ -0,0 +1,254 @@
// Copyright (c) 2019-2020 OuterC - Nomango
#pragma once
#include <type_traits>
#include <iterator>
#include <stdexcept>
#include "macros.h"
namespace oc
{
template <typename _Ty, typename _PTy = typename std::pointer_traits<_Ty>::pointer>
class intrusive_list;
template <typename _Ty, typename _PTy = typename std::pointer_traits<_Ty>::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 <typename _Ty, typename _PTy>
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 <typename _PTy>
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<pointer_type>;
using const_iterator = iterator_impl<const pointer_type>;
using reverse_iterator = std::reverse_iterator<iterator>;
using const_reverse_iterator = std::reverse_iterator<const_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

201
src/3rd-party/OuterC/oc/intrusive_ptr.h vendored Normal file
View File

@ -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 <utility>
#include <type_traits>
#include <atomic>
#include "macros.h"
namespace oc
{
template <typename _Ty, typename _ProxyTy>
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 <typename _UTy>
intrusive_ptr(const intrusive_ptr<_UTy, ref_proxy_type>& other) { ptr_ = const_cast<pointer_type>(dynamic_cast<const_pointer_type>(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 <class _Ty, class _UTy, class _ProxyTy>
inline bool operator==(intrusive_ptr<_Ty, _ProxyTy> const& lhs, intrusive_ptr<_UTy, _ProxyTy> const& rhs) noexcept
{
return lhs.get() == rhs.get();
}
template <class _Ty, class _ProxyTy>
inline bool operator==(intrusive_ptr<_Ty, _ProxyTy> const& lhs, _Ty* rhs) noexcept
{
return lhs.get() == rhs;
}
template <class _Ty, class _ProxyTy>
inline bool operator==(_Ty* lhs, intrusive_ptr<_Ty, _ProxyTy> const& rhs) noexcept
{
return lhs == rhs.get();
}
template <class _Ty, class _ProxyTy>
inline bool operator==(intrusive_ptr<_Ty, _ProxyTy> const& lhs, std::nullptr_t) noexcept
{
return !static_cast<bool>(lhs);
}
template <class _Ty, class _ProxyTy>
inline bool operator==(std::nullptr_t, intrusive_ptr<_Ty, _ProxyTy> const& rhs) noexcept
{
return !static_cast<bool>(rhs);
}
template <class _Ty, class _UTy, class _ProxyTy>
inline bool operator!=(intrusive_ptr<_Ty, _ProxyTy> const& lhs, intrusive_ptr<_UTy, _ProxyTy> const& rhs) noexcept
{
return !(lhs == rhs);
}
template <class _Ty, class _ProxyTy>
inline bool operator!=(intrusive_ptr<_Ty, _ProxyTy> const& lhs, _Ty* rhs) noexcept
{
return lhs.get() != rhs;
}
template <class _Ty, class _ProxyTy>
inline bool operator!=(_Ty* lhs, intrusive_ptr<_Ty, _ProxyTy> const& rhs) noexcept
{
return lhs != rhs.get();
}
template <class _Ty, class _ProxyTy>
inline bool operator!=(intrusive_ptr<_Ty, _ProxyTy> const& lhs, std::nullptr_t) noexcept
{
return static_cast<bool>(lhs);
}
template <class _Ty, class _ProxyTy>
inline bool operator!=(std::nullptr_t, intrusive_ptr<_Ty, _ProxyTy> const& rhs) noexcept
{
return static_cast<bool>(rhs);
}
template <class _Ty, class _UTy, class _ProxyTy>
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 <class _Ty, class _ProxyTy>
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<int16_t> 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<std::is_base_of<intrusive_ref, _Ty>::value, int>::type>
using intrusive_ref_ptr = intrusive_ptr<_Ty, intrusive_ref_proxy>;
} // namespace oc

50
src/3rd-party/OuterC/oc/json.h vendored Normal file
View File

@ -0,0 +1,50 @@
// Copyright (c) 2019-2020 OuterC - Nomango
#pragma once
#include <map>
#include "vector.h"
#include "string.h"
#include "json/basic_json.h"
namespace oc
{
using json = oc::basic_json<std::map, oc::vector, oc::string, int, double, bool, std::allocator>;
using wjson = oc::basic_json<std::map, oc::vector, oc::wstring, int, double, bool, std::allocator>;
} // 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);
}
}

View File

@ -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 <class _Kty, class _Ty, class ..._Args> typename _ObjectTy, \
template <class _Kty, class ..._Args> typename _ArrayTy, \
typename _StringTy, \
typename _IntegerTy, \
typename _FloatTy, \
typename _BooleanTy, \
template <class _Ty> 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 <typename>
struct is_basic_json
: std::false_type
{
};
OC_DECLARE_BASIC_JSON_TEMPLATE
struct is_basic_json< basic_json<OC_DECLARE_BASIC_JSON_TPL_ARGS> >
: std::true_type
{
};
OC_DECLARE_BASIC_JSON_TEMPLATE
class basic_json
{
friend struct __json_detail::iterator_impl<basic_json>;
friend struct __json_detail::iterator_impl<const basic_json>;
friend struct __json_detail::json_serializer<basic_json>;
friend struct __json_detail::json_parser<basic_json>;
friend struct __json_detail::json_value_getter<basic_json>;
public:
template <typename _Ty>
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<basic_json, allocator_type<basic_json>>;
using object_type = typename _ObjectTy<string_type, basic_json, std::less<string_type>, allocator_type<std::pair<const string_type, basic_json>>>;
using initializer_list = std::initializer_list<basic_json>;
using iterator = __json_detail::iterator_impl<basic_json>;
using const_iterator = __json_detail::iterator_impl<const basic_json>;
using reverse_iterator = std::reverse_iterator<iterator>;
using const_reverse_iterator = std::reverse_iterator<const_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<std::is_constructible<string_type, _CompatibleTy>::value, int>::type = 0>
basic_json(const _CompatibleTy& value)
{
value_.type = json_type::STRING;
value_.data.string = value_.template create<string_type>(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<std::is_integral<_IntegerTy>::value, int>::type = 0>
basic_json(_IntegerTy value)
: value_(static_cast<integer_type>(value))
{
}
basic_json(float_type value)
: value_(value)
{
}
template <
typename _FloatingTy,
typename std::enable_if<std::is_floating_point<_FloatingTy>::value, int>::type = 0>
basic_json(_FloatingTy value)
: value_(static_cast<float_type>(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 <typename _Kty>
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 <typename _Kty>
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<difference_type>(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<float_type>(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<std::is_integral<_IntegerTy>::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<std::is_floating_point<_FloatingTy>::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 <typename _Ty>
_Ty get() const
{
_Ty value;
__json_detail::json_value_getter<basic_json>::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 <typename _CharT>
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 <typename _CharT>
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<string_type> adapter(result);
dump(&adapter, indent, indent_char, char_escape);
return result;
}
void dump(
__json_detail::output_adapter<char_type>* adapter,
const int indent = -1,
const char_type indent_char = ' ',
const bool char_escape = true) const
{
__json_detail::json_serializer<basic_json>(adapter, indent_char).dump(*this, (indent >= 0), char_escape, static_cast<uint32_t>(indent));
}
friend std::basic_ostream<char_type>& operator<<(std::basic_ostream<char_type>& out, const basic_json& json)
{
using char_type = typename std::basic_ostream<char_type>::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<char_type> adapter(out);
__json_detail::json_serializer<basic_json>(&adapter, out.fill()).dump(json, pretty_print, true, static_cast<uint32_t>(indentation));
return out;
}
public:
// parse functions
static inline basic_json parse(const string_type& str)
{
__json_detail::string_input_adapter<string_type> adapter(str);
return parse(&adapter);
}
static inline basic_json parse(const char_type* str)
{
__json_detail::buffer_input_adapter<char_type> adapter(str);
return parse(&adapter);
}
static inline basic_json parse(std::FILE* file)
{
__json_detail::file_input_adapter<char_type> adapter(file);
return parse(&adapter);
}
static inline basic_json parse(__json_detail::input_adapter<char_type>* adapter)
{
basic_json result;
__json_detail::json_parser<basic_json>(adapter).parse(result);
return result;
}
friend std::basic_istream<char_type>&
operator>>(std::basic_istream<char_type>& in, basic_json& json)
{
__json_detail::stream_input_adapter<char_type> adapter(in);
__json_detail::json_parser<basic_json>(&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<float_type>(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<float_type>(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<float_type>(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<float_type>(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<basic_json> value_;
};
} // namespace oc
#undef OC_DECLARE_BASIC_JSON_TEMPLATE
#undef OC_DECLARE_BASIC_JSON_TPL_ARGS

View File

@ -0,0 +1,47 @@
// Copyright (c) 2019-2020 OuterC - Nomango
#pragma once
#include <stdexcept>
#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

View File

@ -0,0 +1,112 @@
// Copyright (c) 2019-2020 OuterC - Nomango
#pragma once
#include <iosfwd>
namespace oc
{
namespace __json_detail
{
template <typename _CharTy>
struct input_adapter
{
using char_type = _CharTy;
using char_traits = std::char_traits<char_type>;
virtual typename char_traits::int_type get_char() = 0;
virtual ~input_adapter() = default;
};
template <typename _CharTy>
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 <typename _CharTy>
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<char_type>& 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<char_type>& stream;
std::basic_streambuf<char_type>& streambuf;
};
template <typename _StringTy>
struct string_input_adapter
: public input_adapter<typename _StringTy::value_type>
{
using char_type = typename input_adapter<typename _StringTy::value_type>::char_type;
using char_traits = typename input_adapter<typename _StringTy::value_type>::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 <typename _CharTy>
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

View File

@ -0,0 +1,377 @@
// Copyright (c) 2019-2020 OuterC - Nomango
#pragma once
#include <cctype>
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 <typename _BasicJsonTy>
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

View File

@ -0,0 +1,76 @@
// Copyright (c) 2019-2020 OuterC - Nomango
#pragma once
#include <iosfwd>
namespace oc
{
namespace __json_detail
{
template <typename _CharTy>
struct output_adapter
{
using char_type = _CharTy;
using char_traits = std::char_traits<char_type>;
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<uint32_t>(size));
}
};
template <typename _StringTy>
struct string_output_adapter
: public output_adapter<typename _StringTy::value_type>
{
using char_type = typename _StringTy::value_type;
using size_type = typename _StringTy::size_type;
using char_traits = std::char_traits<char_type>;
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_type>(size));
}
private:
_StringTy& str_;
};
template <typename _CharTy>
struct stream_output_adapter
: public output_adapter<_CharTy>
{
using char_type = _CharTy;
using size_type = typename std::streamsize;
using char_traits = std::char_traits<char_type>;
stream_output_adapter(std::basic_ostream<char_type>& 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_type>(size));
}
private:
std::basic_ostream<char_type>& stream_;
};
} // namespace __json_detail
} // namespace oc

View File

@ -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 <typename _BasicJsonTy>
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<char_type>;
json_lexer(input_adapter<char_type>* 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<float_type>(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<float_type>(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<float_type>(0.1);
number_value += static_cast<float_type>(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<float_type>(0.1);
number_value += static_cast<float_type>(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<float_type>(0.1);
read_next();
}
uint32_t exponent = static_cast<uint32_t>(current - '0');
while (std::isdigit(read_next()))
{
exponent = (exponent * 10) + static_cast<uint32_t>(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<integer_type>(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<char_type>* adapter;
typename char_traits::int_type current;
bool is_negative;
float_type number_value;
string_type string_buffer;
};
template <typename _BasicJsonTy>
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<char_type>;
json_parser(input_adapter<char_type>* 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

View File

@ -0,0 +1,421 @@
// Copyright (c) 2019-2020 OuterC - Nomango
#pragma once
#include "json_output_adapter.h"
#include <array>
#include <memory>
namespace oc
{
namespace __json_detail
{
template <typename _CharTy>
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 <typename _FloatTy>
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<wchar_t>
{
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 <typename _FloatTy>
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 <typename _BasicJsonTy>
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<char_type>;
json_serializer(output_adapter<char_type>* 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<std::make_unsigned_t<integer_type>>(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<char_type>('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<uint32_t>(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<char_type>* out;
char_type indent_char;
string_type indent_string;
using number_buffer_type = std::array<char_type, 21>;
std::unique_ptr<number_buffer_type> number_buffer;
};
} // namespace __json_detail
} // namespace oc

View File

@ -0,0 +1,240 @@
// Copyright (c) 2019-2020 OuterC - Nomango
#pragma once
#include <type_traits>
#include <memory>
namespace oc
{
enum class json_type
{
INTEGER,
FLOAT,
STRING,
VECTOR,
OBJECT,
BOOL,
NIL,
};
namespace __json_detail
{
template <typename _BasicJsonTy>
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<object_type>(value);
}
json_value(const array_type& value)
{
type = json_type::VECTOR;
data.vector = create<array_type>(value);
}
json_value(const string_type& value)
{
type = json_type::STRING;
data.string = create<string_type>(value);
}
template <typename _CharT>
json_value(const _CharT* str)
{
type = json_type::STRING;
data.string = create<string_type>(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<object_type>();
break;
case json_type::VECTOR:
data.vector = create<array_type>();
break;
case json_type::STRING:
data.string = create<string_type>();
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<object_type>(*other.data.object);
break;
case json_type::VECTOR:
data.vector = create<array_type>(*other.data.vector);
break;
case json_type::STRING:
data.string = create<string_type>(*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<object_type>(data.object);
break;
case json_type::VECTOR:
destroy<array_type>(data.vector);
break;
case json_type::STRING:
destroy<string_type>(data.string);
break;
default:
break;
}
}
template <typename _Ty, typename ..._Args>
inline _Ty* create(_Args&&... args)
{
using allocator_type = typename _BasicJsonTy::template allocator_type<_Ty>;
using allocator_traits = std::allocator_traits<allocator_type>;
allocator_type allocator;
_Ty* ptr = allocator_traits::allocate(allocator, 1);
allocator_traits::construct(allocator, ptr, std::forward<_Args>(args)...);
return ptr;
}
template <typename _Ty>
inline void destroy(_Ty* ptr)
{
using allocator_type = typename _BasicJsonTy::template allocator_type<_Ty>;
using allocator_traits = std::allocator_traits<allocator_type>;
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

View File

@ -0,0 +1,79 @@
// Copyright (c) 2019-2020 OuterC - Nomango
#pragma once
#include "json_value.h"
namespace oc
{
namespace __json_detail
{
template <typename _BasicJsonTy>
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<std::is_integral<_IntegerTy>::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<std::is_floating_point<_FloatingTy>::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

8
src/3rd-party/OuterC/oc/macros.h vendored Normal file
View File

@ -0,0 +1,8 @@
// Copyright (c) 2019-2020 OuterC - Nomango
#pragma once
#include <cassert>
#include <cstdio>
#include <cwchar>
#define OC_ASSERT(EXPR) assert(EXPR)

19
src/3rd-party/OuterC/oc/noncopyable.h vendored Normal file
View File

@ -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

13
src/3rd-party/OuterC/oc/oc.h vendored Normal file
View File

@ -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"

50
src/3rd-party/OuterC/oc/singleton.h vendored Normal file
View File

@ -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 <typename _Ty>
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 _Ty>
typename singleton<_Ty>::object_creator singleton<_Ty>::creator_;
} // namespace oc

File diff suppressed because it is too large Load Diff

View File

@ -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 <memory>
#include <type_traits>
#include <exception>
#include <stdexcept>
#include "vector/details.h"
namespace kiwano
namespace oc
{
namespace common
{
//
// vector_memory_manager<> with memory operations
//
namespace __vector_details
{
template<typename _Ty, typename _Alloc, bool _IsClassType = std::is_class<_Ty>::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 <typename _Ty, typename _Alloc = std::allocator<_Ty>>
class vector
{
public:
@ -59,7 +25,7 @@ public:
using reverse_iterator = std::reverse_iterator<iterator>;
using const_reverse_iterator = std::reverse_iterator<const_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<value_type>;
public:
@ -74,11 +40,11 @@ public:
template <typename _Iter>
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<typename _Ty, typename _Alloc, typename _Manager>
void vector<_Ty, _Alloc, _Manager>::resize(size_type new_size, const _Ty& val)
template<typename _Ty, typename _Alloc>
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<typename _Ty, typename _Alloc, typename _Manager>
void vector<_Ty, _Alloc, _Manager>::reserve(size_type new_capacity)
template<typename _Ty, typename _Alloc>
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 _Ty, typename _Alloc, typename _Manager>
typename vector<_Ty, _Alloc, _Manager>::iterator
vector<_Ty, _Alloc, _Manager>::erase(const_iterator first, const_iterator last)
template<typename _Ty, typename _Alloc>
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 _Ty, typename _Alloc, typename _Manager>
typename vector<_Ty, _Alloc, _Manager>::iterator
vector<_Ty, _Alloc, _Manager>::insert(const_iterator where, const _Ty& v)
template<typename _Ty, typename _Alloc>
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<typename _Ty, typename _Alloc>
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<typename _Ty, typename _Alloc>
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

172
src/3rd-party/OuterC/oc/vector/details.h vendored Normal file
View File

@ -0,0 +1,172 @@
// Copyright (c) 2019-2020 OuterC - Nomango
#pragma once
#include <type_traits>
#include <iterator>
#include <algorithm>
#include <cstring>
namespace oc
{
namespace __vector_details
{
// vector_memory_manager<> with memory operations
template<typename _Ty, typename _Alloc, bool _IsTrivial = std::is_trivial<_Ty>::value>
struct vector_memory_manager;
//
// vector_memory_manager for common type
//
template<typename _Ty, typename _Alloc>
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<typename _Ty, typename _Alloc>
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

File diff suppressed because it is too large Load Diff

View File

@ -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

View File

@ -18,8 +18,9 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#include <kiwano/core/win32/helper.h>
#include <kiwano-audio/audio-modules.h>
#include <kiwano/platform/win32/helper.h> // win32::ThrowIfFailed
#include <kiwano/core/Logger.h>
#include <kiwano-audio/libraries.h>
#include <kiwano-audio/AudioEngine.h>
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();
}
}
}

View File

@ -19,47 +19,64 @@
// THE SOFTWARE.
#pragma once
#include <kiwano/common/singleton.hpp>
#include <kiwano/core/common.h>
#include <kiwano/core/Component.h>
#include <kiwano/core/win32/ComPtr.hpp>
#include <kiwano-audio/Transcoder.h>
#include <kiwano-audio/Sound.h>
#include <xaudio2.h>
namespace kiwano
{
namespace audio
{
/**
* \~chinese
* \defgroup Audio
*/
/**
* \addtogroup Audio
* @{
*/
/**
* \~chinese
* @brief
*/
class KGE_API AudioEngine
: public Singleton<AudioEngine>
, public ComponentBase
{
KGE_DECLARE_SINGLETON(AudioEngine);
friend Singleton<AudioEngine>;
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_;
};
/** @} */
}
}

View File

@ -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);

View File

@ -19,9 +19,9 @@
// THE SOFTWARE.
#pragma once
#include <kiwano/common/intrusive_ptr.hpp>
#include <kiwano/core/ObjectBase.h>
#include <kiwano/core/Resource.h>
#include <kiwano/platform/win32/ComPtr.hpp>
#include <kiwano-audio/Transcoder.h>
#include <xaudio2.h>
@ -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;
}
}
}

View File

@ -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();
}

View File

@ -19,7 +19,6 @@
// THE SOFTWARE.
#pragma once
#include <kiwano/common/intrusive_ptr.hpp>
#include <kiwano/core/ObjectBase.h>
#include <kiwano-audio/Sound.h>
@ -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<size_t, SoundPtr>;
SoundMap sound_cache_;
};
/** @} */
}
}

View File

@ -23,12 +23,12 @@
#endif
#include <kiwano/macros.h>
#include <kiwano/common/string.hpp>
#include <kiwano/core/common.h>
#include <kiwano/core/Resource.h>
#include <kiwano/core/Logger.h>
#include <kiwano/core/win32/ComPtr.hpp>
#include <kiwano/platform/modules.h>
#include <kiwano-audio/audio-modules.h>
#include <kiwano/platform/win32/ComPtr.hpp>
#include <kiwano/platform/win32/libraries.h>
#include <kiwano-audio/libraries.h>
#include <kiwano-audio/Transcoder.h>
namespace kiwano
@ -76,7 +76,7 @@ namespace kiwano
ComPtr<IMFSourceReader> 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<const BYTE*>(data.buffer),
static_cast<uint32_t>(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<IMFMediaType> partial_type;
ComPtr<IMFMediaType> 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

View File

@ -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_;
};
/** @} */
}
}

View File

@ -19,13 +19,13 @@
// THE SOFTWARE.
#include <kiwano/core/Logger.h>
#include <kiwano-audio/audio-modules.h>
#include <kiwano-audio/libraries.h>
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<PFN_XAudio2Create>(L"XAudio2Create");
XAudio2Create = xaudio2.GetProcess<PFN_XAudio2Create>("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<PFN_MFStartup>(L"MFStartup");
MFShutdown = mfplat.GetProcess<PFN_MFShutdown>(L"MFShutdown");
MFCreateMediaType = mfplat.GetProcess<PFN_MFCreateMediaType>(L"MFCreateMediaType");
MFCreateWaveFormatExFromMFMediaType = mfplat.GetProcess<PFN_MFCreateWaveFormatExFromMFMediaType>(L"MFCreateWaveFormatExFromMFMediaType");
MFCreateMFByteStreamOnStream = mfplat.GetProcess<PFN_MFCreateMFByteStreamOnStream>(L"MFCreateMFByteStreamOnStream");
MFStartup = mfplat.GetProcess<PFN_MFStartup>("MFStartup");
MFShutdown = mfplat.GetProcess<PFN_MFShutdown>("MFShutdown");
MFCreateMediaType = mfplat.GetProcess<PFN_MFCreateMediaType>("MFCreateMediaType");
MFCreateWaveFormatExFromMFMediaType = mfplat.GetProcess<PFN_MFCreateWaveFormatExFromMFMediaType>("MFCreateWaveFormatExFromMFMediaType");
MFCreateMFByteStreamOnStream = mfplat.GetProcess<PFN_MFCreateMFByteStreamOnStream>("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<PFN_MFCreateSourceReaderFromURL>(L"MFCreateSourceReaderFromURL");
MFCreateSourceReaderFromByteStream = mfreadwrite.GetProcess<PFN_MFCreateSourceReaderFromByteStream>(L"MFCreateSourceReaderFromByteStream");
MFCreateSourceReaderFromURL = mfreadwrite.GetProcess<PFN_MFCreateSourceReaderFromURL>("MFCreateSourceReaderFromURL");
MFCreateSourceReaderFromByteStream = mfreadwrite.GetProcess<PFN_MFCreateSourceReaderFromByteStream>("MFCreateSourceReaderFromByteStream");
}
else
{
KGE_LOG(L"Load Mfreadwrite.dll failed");
KGE_ERROR(L"Load Mfreadwrite.dll failed");
throw std::runtime_error("Load Mfreadwrite.dll failed");
}
}

View File

@ -25,11 +25,13 @@
#include <mfidl.h>
#include <mfreadwrite.h>
#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

View File

@ -35,7 +35,7 @@ namespace kiwano
void ImGuiLayer::OnRender(RenderTarget* rt)
{
PrepareRender(rt);
PrepareToRender(rt);
for (const auto& pipeline : pipelines_)
{
pipeline.second();

View File

@ -27,8 +27,14 @@ namespace kiwano
{
KGE_DECLARE_SMART_PTR(ImGuiLayer);
/// \~chinese
/// @brief ImGui管道
using ImGuiPipeline = Function<void()>;
/**
* \~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<String, ImGuiPipeline> pipelines_;
};
}

View File

@ -1,8 +1,6 @@
// Copyright (C) 2019 Nomango
#include <kiwano/common/common.h>
#include <kiwano/common/Function.hpp>
#include <kiwano/common/intrusive_ptr.hpp>
#include <kiwano/core/common.h>
#include <kiwano/platform/Window.h>
#include <kiwano/platform/Input.h>
#include <kiwano/renderer/Renderer.h>
@ -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()
{

View File

@ -19,27 +19,24 @@
// THE SOFTWARE.
#pragma once
#include <kiwano/core/common.h>
#include <kiwano/core/Component.h>
#include <kiwano/common/singleton.hpp>
namespace kiwano
{
namespace imgui
{
/**
* \~chinese
* @brief ImGuiÄ£¿é
*/
class ImGuiModule
: public Singleton<ImGuiModule>
, public RenderComponent
, public UpdateComponent
, public EventComponent
{
KGE_DECLARE_SINGLETON(ImGuiModule);
private:
void Init(HWND hwnd);
void NewFrame();
void Render();
friend Singleton<ImGuiModule>;
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();

View File

@ -2,6 +2,8 @@
#pragma once
#ifndef KGE_DOXYGEN_DO_NOT_INCLUDE
#if !defined(KGE_USE_DIRECTX10)
#include <kiwano-imgui/imgui_impl_dx11.h>
@ -27,3 +29,5 @@ inline void ImGui_Impl_InvalidateDeviceObjects() { ImGui_ImplDX10_Invalid
inline bool ImGui_Impl_CreateDeviceObjects() { return ImGui_ImplDX10_CreateDeviceObjects(); }
#endif
#endif

View File

@ -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

View File

@ -1,6 +1,5 @@
// dear imgui: Renderer for Kiwano (DirectX11)
#include <kiwano/core/win32/helper.h>
#include <kiwano-imgui/imgui_impl_dx11.h>
// 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();
}

View File

@ -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

View File

@ -24,4 +24,4 @@
#include <kiwano-imgui/ImGuiModule.h>
// ImGui
#include <3rd-party/imgui/imgui.h>
#include <imgui/imgui.h>

View File

@ -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<std::codecvt_utf8<wchar_t>> 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<std::codecvt_utf8<wchar_t>> utf8_conv;
common::wstring result;
oc::string_convert<std::codecvt_utf8<wchar_t>> 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<common::string> const& headers, common::string const& url, common::string* response_data, common::string* response_header, char* error_buffer)
bool Init(HttpClient* client, Vector<ByteString> 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<common::string> const& headers,
common::string const& url,
Vector<ByteString> 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<common::string> const& headers,
common::string const& url,
common::string const& request_data,
Vector<ByteString> 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<common::string> const& headers,
common::string const& url,
common::string const& request_data,
Vector<ByteString> 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<common::string> const& headers,
common::string const& url,
Vector<ByteString> 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<common::string> headers;
Vector<ByteString> 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
{

View File

@ -19,8 +19,7 @@
// THE SOFTWARE.
#pragma once
#include <kiwano/common/common.h>
#include <kiwano/common/singleton.hpp>
#include <kiwano/core/common.h>
#include <kiwano/core/Component.h>
#include <mutex>
#include <condition_variable>
@ -29,25 +28,55 @@ namespace kiwano
{
namespace network
{
/**
* \~chinese
* \defgroup Network
*/
/**
* \addtogroup Network
* @{
*/
/**
* \~chinese
* @brief HTTP客户端
*/
class KGE_API HttpClient
: public Singleton<HttpClient>
, public ComponentBase
{
KGE_DECLARE_SINGLETON(HttpClient);
friend Singleton<HttpClient>;
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)
{

View File

@ -19,8 +19,7 @@
// THE SOFTWARE.
#pragma once
#include <kiwano/common/function.hpp>
#include <kiwano/common/basic_json.hpp>
#include <kiwano/core/common.h>
#include <kiwano/core/ObjectBase.h>
#include <kiwano/core/SmartPtr.hpp>
@ -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<void(HttpRequest*, HttpResponse*)>;
/// \~chinese
/// @brief 响应回调函数
using ResponseCallback = Function<void(HttpRequest* /* request */, HttpResponse* /* response */)>;
/// \~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<String, String> 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<String, String> const& headers);
void SetHeader(String const& field, String const& content);
/// \~chinese
/// @brief 获取HTTP头
Map<String, String>& 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) {}

View File

@ -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_; }

View File

@ -104,8 +104,7 @@ namespace kiwano
{
if (fixture.GetB2Fixture())
{
b2Fixture* ptr = const_cast<b2Fixture*>(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);
}

View File

@ -22,7 +22,7 @@
#include <kiwano-physics/helper.h>
#include <kiwano-physics/Shape.h>
#include <kiwano-physics/Fixture.h>
#include <kiwano-physics/Contact.h>
#include <kiwano-physics/ContactEdge.h>
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<Point> 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<Point> 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<b2BodyType>(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<b2BodyType>(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_; }
}
}

View File

@ -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);
}
}
}

View File

@ -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<Contact>
{
template <typename _Ty>
class IteratorImpl
: public std::iterator<std::forward_iterator_tag, _Ty>
{
using herit = std::iterator<std::forward_iterator_tag, _Ty>;
public:
IteratorImpl(const _Ty& elem)
: elem_(elem)
{
}
inline typename herit::reference operator*() const
{
return const_cast<typename herit::reference>(elem_);
}
inline typename herit::pointer operator->() const
{
return std::pointer_traits<typename herit::pointer>::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<value_type>;
using const_iterator = IteratorImpl<const value_type>;
// 获取接触物体
Body* GetOtherBody() { KGE_ASSERT(edge_); return static_cast<Body*>(edge_->other->GetUserData()); }
const Body* GetOtherBody() const { KGE_ASSERT(edge_); return static_cast<Body*>(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_; }
}
}

View File

@ -18,23 +18,23 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#include <kiwano/core/Logger.h>
#include <3rd-party/StackWalker/StackWalker.h>
#include <kiwano-physics/ContactEdge.h>
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);
}
}
}

View File

@ -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 <kiwano-physics/Contact.h>
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 <typename _Ty>
class IteratorImpl
: public std::iterator<std::forward_iterator_tag, _Ty>
{
using herit = std::iterator<std::forward_iterator_tag, _Ty>;
public:
inline IteratorImpl(const _Ty& elem)
: elem_(elem)
{
}
inline typename herit::reference operator*() const
{
return const_cast<typename herit::reference>(elem_);
}
inline typename herit::pointer operator->() const
{
return std::pointer_traits<typename herit::pointer>::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<value_type>;
using const_iterator = IteratorImpl<const value_type>;
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<Body*>(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_; }
}
}

View File

@ -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();
}
}

View File

@ -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; // 接触结束
/** @} */
}
}

View File

@ -58,30 +58,18 @@ namespace kiwano
}
}
Body* Fixture::GetBody()
Body* Fixture::GetBody() const
{
KGE_ASSERT(fixture_);
return static_cast<Body*>(fixture_->GetBody()->GetUserData());
}
const Body* Fixture::GetBody() const
{
KGE_ASSERT(fixture_);
return static_cast<const Body*>(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_);

View File

@ -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<Fixture>
{
template <typename _Ty>
class IteratorImpl
: public std::iterator<std::forward_iterator_tag, _Ty>
{
using herit = std::iterator<std::forward_iterator_tag, _Ty>;
public:
IteratorImpl(const _Ty& elem)
: elem_(elem)
{
}
inline typename herit::reference operator*() const
{
return const_cast<typename herit::reference>(elem_);
}
inline typename herit::pointer operator->() const
{
return std::pointer_traits<typename herit::pointer>::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<value_type>;
using const_iterator = IteratorImpl<const value_type>;
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_; }
}
}

View File

@ -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<b2MotorJoint*>(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<b2WeldJoint*>(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());
}
//

View File

@ -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_;
};
// 鼠标关节
// 用于使身体的某个点追踪世界上的指定点,例如让物体追踪鼠标位置
/// \~chinese
/// @brief 鼠标关节
/// @details 用于使身体的某个点追踪世界上的指定点,例如让物体追踪鼠标位置
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(); }
}
}

View File

@ -35,12 +35,7 @@ namespace kiwano
{
}
b2Shape* Shape::GetB2Shape()
{
return shape_;
}
const b2Shape* Shape::GetB2Shape() const
b2Shape* Shape::GetB2Shape() const
{
return shape_;
}

View File

@ -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<Point> const& vertexs);
private:
void FitWorld(World* world) override;
protected:
private:
Vector<Point> 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<Point> const& vertexs, bool loop = false);
private:
void FitWorld(World* world) override;
protected:
private:
bool loop_;
Vector<Point> vertexs_;
b2ChainShape chain_;
};
/** @} */
}
}

View File

@ -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<Body*>(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<Body*>(b2body->GetUserData());
if (body && body->GetType() != Body::Type::Static)
{
Body* body = static_cast<Body*>(b2body->GetUserData());
if (body && body->GetType() != Body::Type::Static)
{
body->UpdateActor();
}
b2body = b2body->GetNext();
body->UpdateActor();
}
b2body = b2body->GetNext();
}
Stage::Update(dt);

View File

@ -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<Joint*> 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;
}
}
}

View File

@ -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); }
}
}

View File

@ -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<MouseMoveEvent>())
{
auto mouse_evt = evt.SafeCast<MouseMoveEvent>();
if (!mouse_evt->target && ContainsPoint(mouse_evt->pos))
auto& mouse_evt = evt.SafeCast<MouseMoveEvent>();
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<MouseDownEvent>() && hover_)
{
pressed_ = true;
evt.SafeCast<MouseDownEvent>()->target = this;
evt.SafeCast<MouseDownEvent>().target = this;
}
if (evt.type == event::MouseUp && pressed_)
if (evt.IsType<MouseUpEvent>() && pressed_)
{
pressed_ = false;
auto mouse_up_evt = evt.SafeCast<MouseUpEvent>();
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<ActorPtr> children;
size_t hash_code = std::hash<String>{}(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<Actor*>(child));
}
}
return children;
@ -541,11 +557,11 @@ namespace kiwano
{
size_t hash_code = std::hash<String>{}(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<Actor*>(child);
}
}
return nullptr;

View File

@ -19,7 +19,10 @@
// THE SOFTWARE.
#pragma once
#include <kiwano/2d/include-forwards.h>
#include <kiwano/core/common.h>
#include <kiwano/core/time.h>
#include <kiwano/core/ObjectBase.h>
#include <kiwano/math/math.h>
#include <kiwano/2d/Transform.h>
#include <kiwano/2d/action/ActionManager.h>
#include <kiwano/core/TimerManager.h>
@ -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<ActorPtr>;
public:
using Children = IntrusiveList<ActorPtr>;
using UpdateCallback = Function<void(Duration)>;
/// \~chinese
/// @brief 子成员列表
using Children = IntrusiveList<ActorPtr>;
/// \~chinese
/// @brief 角色更新回调函数
using UpdateCallback = Function<void(Duration)>;
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<ActorPtr> const& children
);
/// \~chinese
/// @brief 添加多个子角色
void AddChildren(Vector<ActorPtr> const& children);
// 获取名称相同的子角色
Actor* GetChild(
String const& name
) const;
/// \~chinese
/// @brief 获取名称相同的子角色
Actor* GetChild(String const& name) const;
// 获取所有名称相同的子角色
Vector<ActorPtr> GetChildren(
String const& name
) const;
/// \~chinese
/// @brief 获取所有名称相同的子角色
Vector<ActorPtr> 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);

View File

@ -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;
}
}
}

View File

@ -21,235 +21,314 @@
#pragma once
#include <kiwano/2d/Actor.h>
#include <kiwano/renderer/RenderTarget.h>
#ifdef DrawText
# undef DrawText
#endif
#include <kiwano/renderer/GeometrySink.h>
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<Point> 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<Point> 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_;
}
}

View File

@ -19,8 +19,8 @@
// THE SOFTWARE.
#include <kiwano/2d/DebugActor.h>
#include <kiwano/2d/Text.h>
#include <kiwano/renderer/Renderer.h>
#include <kiwano/core/Logger.h>
#include <psapi.h>
#pragma comment(lib, "psapi.lib")
@ -31,7 +31,7 @@ namespace kiwano
{
class comma_numpunct : public std::numpunct<wchar_t>
{
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<MouseHoverEvent>([=](Event&) { SetOpacity(0.4f); });
AddListener<MouseOutEvent>([=](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;
}
}

View File

@ -20,9 +20,21 @@
#pragma once
#include <kiwano/2d/Actor.h>
#include <kiwano/2d/TextActor.h>
#include <kiwano/renderer/Color.h>
#include <kiwano/renderer/Brush.h>
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<Time> frame_time_;
};
/** @} */
}

View File

@ -27,25 +27,10 @@ namespace kiwano
{
}
Frame::Frame(String const& file_path)
{
Load(file_path);
}
Frame::Frame(Resource const& res)
{
Load(res);
}
Frame::Frame(Texture const& texture)
{
SetTexture(texture);
}
bool Frame::Load(String const& file_path)
{
Texture texture = TextureCache::GetInstance()->AddOrGetTexture(file_path);
if (texture.IsValid())
TexturePtr texture = TextureCache::instance().AddOrGetTexture(file_path);
if (texture->IsValid())
{
SetTexture(texture);
return true;
@ -55,8 +40,8 @@ namespace kiwano
bool Frame::Load(Resource const& res)
{
Texture texture = TextureCache::GetInstance()->AddOrGetTexture(res);
if (texture.IsValid())
TexturePtr texture = TextureCache::instance().AddOrGetTexture(res);
if (texture->IsValid())
{
SetTexture(texture);
return true;
@ -66,9 +51,9 @@ namespace kiwano
void Frame::SetCropRect(Rect const& crop_rect)
{
if (texture_.IsValid())
if (texture_->IsValid())
{
auto bitmap_size = texture_.GetSize();
auto bitmap_size = texture_->GetSize();
crop_rect_.left_top.x = std::min(std::max(crop_rect.left_top.x, 0.f), bitmap_size.x);
crop_rect_.left_top.y = std::min(std::max(crop_rect.left_top.y, 0.f), bitmap_size.y);
crop_rect_.right_bottom.x = std::min(std::max(crop_rect.right_bottom.x, 0.f), bitmap_size.x);
@ -76,14 +61,14 @@ namespace kiwano
}
}
void Frame::SetTexture(Texture const& texture)
void Frame::SetTexture(TexturePtr texture)
{
texture_ = texture;
if (texture_.IsValid())
if (texture_->IsValid())
{
crop_rect_.left_top.x = crop_rect_.left_top.y = 0;
crop_rect_.right_bottom.x = texture_.GetWidth();
crop_rect_.right_bottom.y = texture_.GetHeight();
crop_rect_.right_bottom.x = texture_->GetWidth();
crop_rect_.right_bottom.y = texture_->GetHeight();
}
}
}

View File

@ -24,63 +24,78 @@
namespace kiwano
{
// 帧图像
KGE_DECLARE_SMART_PTR(Frame);
/**
* \~chinese
* @brief
*/
class KGE_API Frame
: public ObjectBase
{
public:
/// \~chinese
/// @brief 构建空图像帧
Frame();
explicit Frame(
String const& file_path
);
/// \~chinese
/// @brief 加载图像
/// @param file_path 图像路径
bool Load(String const& file_path);
explicit Frame(
Resource const& res
);
/// \~chinese
/// @brief 加载图像
/// @param res 图像资源
bool Load(Resource const& res);
explicit Frame(
Texture const& texture
);
/// \~chinese
/// @brief 裁剪图像帧为矩形
/// @param crop_rect 裁剪矩形定义
void SetCropRect(Rect const& crop_rect);
bool Load(
String const& file_path
);
/// \~chinese
/// @brief 设置纹理
/// @param texture 纹理
void SetTexture(TexturePtr texture);
bool Load(
Resource const& res
);
/// \~chinese
/// @brief 是否有效
bool IsValid() const;
// 裁剪矩形
void SetCropRect(
Rect const& crop_rect /* 裁剪矩形 */
);
/// \~chinese
/// @brief 获取宽度
float GetWidth() const;
// 设置纹理
void SetTexture(
Texture const& texture
);
/// \~chinese
/// @brief 获取高度
float GetHeight() const;
// 获取宽度
float GetWidth() const { return crop_rect_.GetWidth(); }
/// \~chinese
/// @brief 获取大小
Size GetSize() const;
// 获取高度
float GetHeight() const { return crop_rect_.GetHeight(); }
/// \~chinese
/// @brief 获取裁剪位置
Point GetCropPoint() const;
// 获取大小
Size GetSize() const { return crop_rect_.GetSize(); }
/// \~chinese
/// @brief 获取裁剪矩形
Rect const& GetCropRect() const;
// 获取裁剪位置
Point GetCropPoint() const { return crop_rect_.GetLeftTop(); }
/// \~chinese
/// @brief 获取纹理
TexturePtr GetTexture() const;
// 获取裁剪矩形
inline Rect const& GetCropRect() const { return crop_rect_; }
// 获取纹理
inline Texture const& GetTexture() const { return texture_; }
protected:
Texture texture_;
private:
TexturePtr texture_;
Rect crop_rect_;
};
inline bool Frame::IsValid() const { return texture_ && texture_->IsValid(); }
inline float Frame::GetWidth() const { return crop_rect_.GetWidth(); }
inline float Frame::GetHeight() const { return crop_rect_.GetHeight(); }
inline Size Frame::GetSize() const { return crop_rect_.GetSize(); }
inline Point Frame::GetCropPoint() const { return crop_rect_.GetLeftTop(); }
inline Rect const& Frame::GetCropRect() const { return crop_rect_; }
inline TexturePtr Frame::GetTexture() const { return texture_; }
}

View File

@ -19,7 +19,6 @@
// THE SOFTWARE.
#include <kiwano/2d/FrameSequence.h>
#include <kiwano/2d/Frame.h>
#include <kiwano/core/Logger.h>
namespace kiwano
@ -70,6 +69,11 @@ namespace kiwano
return frames_;
}
size_t FrameSequence::GetFramesCount() const
{
return frames_.size();
}
FrameSequencePtr FrameSequence::Clone() const
{
auto frame_seq = new (std::nothrow) FrameSequence;

View File

@ -19,46 +19,65 @@
// THE SOFTWARE.
#pragma once
#include <kiwano/2d/include-forwards.h>
#include <kiwano/core/common.h>
#include <kiwano/core/time.h>
#include <kiwano/2d/Frame.h>
namespace kiwano
{
// 序列帧
KGE_DECLARE_SMART_PTR(FrameSequence);
/**
* \~chinese
* @brief
*/
class KGE_API FrameSequence
: public ObjectBase
{
public:
/// \~chinese
/// @brief 构建空序列帧
FrameSequence();
explicit FrameSequence(
Vector<FramePtr> const& frames /* 帧序列 */
);
/// \~chinese
/// @brief 构建序列帧
/// @param frames 图像帧集合
explicit FrameSequence(Vector<FramePtr> const& frames);
virtual ~FrameSequence();
// 添加关键帧
void AddFrame(
FramePtr frame
);
/// \~chinese
/// @brief 添加关键帧
/// @param frame 图像帧
void AddFrame(FramePtr frame);
// 添加多个关键帧
void AddFrames(
Vector<FramePtr> const& frames
);
/// \~chinese
/// @brief 添加多个关键帧
/// @param frames 图像帧集合
void AddFrames(Vector<FramePtr> const& frames);
// 获取关键帧
/// \~chinese
/// @brief 获取关键帧
/// @param index 图像帧下标
FramePtr GetFrame(size_t index) const;
// 获取关键帧
/// \~chinese
/// @brief 获取所有关键帧
Vector<FramePtr> const& GetFrames() const;
// 获取帧动画的拷贝对象
/// \~chinese
/// @brief 获取关键帧数量
size_t GetFramesCount() const;
/// \~chinese
/// @brief 获取序列帧的拷贝对象
FrameSequencePtr Clone() const;
// 获取帧动画的倒转
/// \~chinese
/// @brief 获取序列帧的倒转
FrameSequencePtr Reverse() const;
protected:
private:
Vector<FramePtr> frames_;
};
}

View File

@ -19,7 +19,6 @@
// THE SOFTWARE.
#include <kiwano/2d/GifSprite.h>
#include <kiwano/core/win32/helper.h>
#include <kiwano/renderer/TextureCache.h>
#include <kiwano/renderer/Renderer.h>
@ -33,37 +32,21 @@ namespace kiwano
{
}
GifSprite::GifSprite(String const& file_path)
{
Load(file_path);
}
GifSprite::GifSprite(Resource const& res)
: GifSprite()
{
Load(res);
}
GifSprite::GifSprite(GifImage gif)
{
Load(gif);
}
bool GifSprite::Load(String const& file_path)
{
GifImage texture = TextureCache::GetInstance()->AddOrGetGifImage(file_path);
return Load(texture);
GifImagePtr image = TextureCache::instance().AddOrGetGifImage(file_path);
return Load(image);
}
bool GifSprite::Load(Resource const& res)
{
GifImage texture = TextureCache::GetInstance()->AddOrGetGifImage(res);
return Load(texture);
GifImagePtr image = TextureCache::instance().AddOrGetGifImage(res);
return Load(image);
}
bool GifSprite::Load(GifImage gif)
bool GifSprite::Load(GifImagePtr gif)
{
if (gif.IsValid())
if (gif && gif->IsValid())
{
gif_ = gif;
@ -71,14 +54,14 @@ namespace kiwano
loop_count_ = 0;
frame_.disposal_type = GifImage::DisposalType::None;
SetSize(Size{ static_cast<float>(gif_.GetWidthInPixels()), static_cast<float>(gif_.GetHeightInPixels()) });
SetSize(Size{ static_cast<float>(gif_->GetWidthInPixels()), static_cast<float>(gif_->GetHeightInPixels()) });
if (!frame_rt_.IsValid())
if (!frame_rt_)
{
Renderer::GetInstance()->CreateTextureRenderTarget(frame_rt_);
Renderer::instance().CreateTextureRenderTarget(frame_rt_);
}
if (gif_.GetFramesCount() > 0)
if (gif_->GetFramesCount() > 0)
{
ComposeNextFrame();
}
@ -89,11 +72,11 @@ namespace kiwano
void GifSprite::OnRender(RenderTarget* rt)
{
if (frame_.raw.IsValid() && CheckVisibilty(rt))
if (frame_to_render_ && CheckVisibilty(rt))
{
PrepareRender(rt);
PrepareToRender(rt);
rt->DrawTexture(frame_.raw, &frame_.rect, nullptr);
rt->DrawTexture(*frame_to_render_, &frame_.rect, nullptr);
}
}
@ -101,7 +84,7 @@ namespace kiwano
{
Actor::Update(dt);
if (gif_.IsValid() && animating_)
if (gif_ && gif_->IsValid() && animating_)
{
frame_elapsed_ += dt;
if (frame_.delay <= frame_elapsed_)
@ -113,7 +96,7 @@ namespace kiwano
}
}
void GifSprite::SetGifImage(GifImage const& gif)
void GifSprite::SetGifImage(GifImagePtr gif)
{
gif_ = gif;
RestartAnimation();
@ -129,7 +112,10 @@ namespace kiwano
void GifSprite::ComposeNextFrame()
{
if (frame_rt_.IsValid())
KGE_ASSERT(frame_rt_);
KGE_ASSERT(gif_);
if (frame_rt_->IsValid())
{
do
{
@ -137,7 +123,7 @@ namespace kiwano
OverlayNextFrame();
} while (frame_.delay.IsZero() && !IsLastFrame());
animating_ = (!EndOfAnimation() && gif_.GetFramesCount() > 1);
animating_ = (!EndOfAnimation() && gif_->GetFramesCount() > 1);
}
}
@ -150,48 +136,51 @@ namespace kiwano
break;
case GifImage::DisposalType::Background:
{
ClearCurrentFrameArea();
break;
}
case GifImage::DisposalType::Previous:
{
RestoreSavedFrame();
break;
}
default:
ThrowIfFailed(E_FAIL);
}
}
void GifSprite::OverlayNextFrame()
{
Renderer::GetInstance()->CreateGifImageFrame(frame_, gif_, next_index_);
KGE_ASSERT(frame_rt_);
KGE_ASSERT(gif_ && gif_->IsValid());
frame_ = gif_->GetFrame(next_index_);
if (frame_.disposal_type == GifImage::DisposalType::Previous)
{
SaveComposedFrame();
}
if (frame_rt_.IsValid())
if (frame_rt_->IsValid())
{
frame_rt_.BeginDraw();
frame_rt_->BeginDraw();
if (next_index_ == 0)
{
loop_count_++;
}
frame_rt_.DrawTexture(frame_.raw, nullptr, &frame_.rect);
frame_rt_.EndDraw();
Texture frame_to_render = frame_rt_.GetOutput();
if (frame_to_render.IsValid())
if (frame_.texture)
{
frame_.raw = frame_to_render;
next_index_ = (++next_index_) % gif_.GetFramesCount();
frame_rt_->DrawTexture(*frame_.texture, nullptr, &frame_.rect);
}
frame_rt_->EndDraw();
if (!frame_to_render_)
{
frame_to_render_ = new Texture;
}
if (frame_rt_->GetOutput(*frame_to_render_))
{
next_index_ = (++next_index_) % gif_->GetFramesCount();
}
}
@ -208,63 +197,47 @@ namespace kiwano
void GifSprite::SaveComposedFrame()
{
Texture frame_to_be_saved = frame_rt_.GetOutput();
KGE_ASSERT(frame_rt_);
HRESULT hr = frame_to_be_saved.IsValid() ? S_OK : E_FAIL;
TexturePtr frame_to_be_saved = new Texture;
if (SUCCEEDED(hr))
if (frame_rt_->GetOutput(*frame_to_be_saved))
{
if (!saved_frame_.IsValid())
if (!saved_frame_)
{
auto size = frame_to_be_saved.GetSizeInPixels();
auto prop = D2D1::BitmapProperties(frame_to_be_saved.GetPixelFormat());
ComPtr<ID2D1Bitmap> saved_bitmap;
hr = frame_rt_.GetRenderTarget()->CreateBitmap(D2D1::SizeU(size.x, size.y), prop, &saved_bitmap);
if (SUCCEEDED(hr))
{
saved_frame_.SetBitmap(saved_bitmap);
}
saved_frame_ = new Texture;
frame_rt_->CreateTexture(*saved_frame_, frame_to_be_saved->GetSizeInPixels(), frame_to_be_saved->GetPixelFormat());
}
}
if (SUCCEEDED(hr))
{
saved_frame_.CopyFrom(frame_to_be_saved);
saved_frame_->CopyFrom(frame_to_be_saved);
}
ThrowIfFailed(hr);
}
void GifSprite::RestoreSavedFrame()
{
HRESULT hr = saved_frame_.IsValid() ? S_OK : E_FAIL;
KGE_ASSERT(frame_rt_);
if (SUCCEEDED(hr))
if (saved_frame_)
{
Texture frame_to_copy_to = frame_rt_.GetOutput();
TexturePtr frame_to_copy_to = new Texture;
hr = frame_to_copy_to.IsValid() ? S_OK : E_FAIL;
if (SUCCEEDED(hr))
if (frame_rt_->GetOutput(*frame_to_copy_to))
{
frame_to_copy_to.CopyFrom(saved_frame_);
frame_to_copy_to->CopyFrom(saved_frame_);
}
}
ThrowIfFailed(hr);
}
void GifSprite::ClearCurrentFrameArea()
{
frame_rt_.BeginDraw();
KGE_ASSERT(frame_rt_);
frame_rt_->BeginDraw();
frame_rt_.PushClipRect(frame_.rect);
frame_rt_.Clear();
frame_rt_.PopClipRect();
frame_rt_->PushClipRect(frame_.rect);
frame_rt_->Clear();
frame_rt_->PopClipRect();
return frame_rt_.EndDraw();
return frame_rt_->EndDraw();
}
}

View File

@ -26,93 +26,145 @@
namespace kiwano
{
// GIF 精灵
KGE_DECLARE_SMART_PTR(GifSprite);
/**
* \addtogroup Actors
* @{
*/
/**
* \~chinese
* @brief GIF
*/
class KGE_API GifSprite
: public Actor
{
public:
using LoopDoneCallback = Function<void(int)>;
/// \~chinese
/// @brief GIF播放循环结束回调
using LoopDoneCallback = Function<void(int /* times */)>;
/// \~chinese
/// @brief GIF播放结束回调
using DoneCallback = Function<void()>;
GifSprite();
GifSprite(
String const& file_path
);
/// \~chinese
/// @brief 加载GIF图片
/// @param file_path GIF图片路径
bool Load(String const& file_path);
GifSprite(
Resource const& res
);
/// \~chinese
/// @brief 加载GIF图片
/// @param res GIF图片资源
bool Load(Resource const& res);
GifSprite(
GifImage gif
);
/// \~chinese
/// @brief 加载GIF图片
/// @param gif GIF图片
bool Load(GifImagePtr gif);
bool Load(
String const& file_path
);
/// \~chinese
/// @brief 设置 GIF 动画循环次数
void SetLoopCount(int loops);
bool Load(
Resource const& res
);
/// \~chinese
/// @brief 设置 GIF 动画每次循环结束回调函数
void SetLoopDoneCallback(LoopDoneCallback const& cb);
bool Load(
GifImage gif
);
/// \~chinese
/// @brief 设置 GIF 动画结束回调函数
void SetDoneCallback(DoneCallback const& cb);
// 设置 GIF 动画循环次数
inline void SetLoopCount(int loops) { total_loop_count_ = loops; }
/// \~chinese
/// @brief 设置 GIF 图像
void SetGifImage(GifImagePtr gif);
// 设置 GIF 动画每次循环结束回调函数
inline void SetLoopDoneCallback(LoopDoneCallback const& cb) { loop_cb_ = cb; }
// 设置 GIF 动画结束回调函数
inline void SetDoneCallback(DoneCallback const& cb) { done_cb_ = cb; }
// 设置 GIF 图像
void SetGifImage(GifImage const& gif);
// 重新播放动画
/// \~chinese
/// @brief 重新播放 GIF 动画
void RestartAnimation();
inline LoopDoneCallback GetLoopDoneCallback() const { return loop_cb_; }
/// \~chinese
/// @brief 获取 GIF 动画循环结束回调
LoopDoneCallback GetLoopDoneCallback() const;
inline DoneCallback GetDoneCallback() const { return done_cb_; }
/// \~chinese
/// @brief 获取 GIF 动画播放结束回调
DoneCallback GetDoneCallback() const;
inline GifImage const& GetGifImage() const { return gif_; }
/// \~chinese
/// @brief 获取 GIF 图片
GifImagePtr GetGifImage() const;
void OnRender(RenderTarget* rt) override;
protected:
private:
void Update(Duration dt) override;
inline bool IsLastFrame() const { return (next_index_ == 0); }
/// \~chinese
/// @brief 是否是最后一帧
bool IsLastFrame() const;
inline bool EndOfAnimation() const { return IsLastFrame() && loop_count_ == total_loop_count_ + 1; }
/// \~chinese
/// @brief 动画是否已结束
bool EndOfAnimation() const;
/// \~chinese
/// @brief 合成下一帧
void ComposeNextFrame();
/// \~chinese
/// @brief 解析当前图像帧
void DisposeCurrentFrame();
/// \~chinese
/// @brief 覆盖下一帧
void OverlayNextFrame();
/// \~chinese
/// @brief 保存合成后的图像帧
void SaveComposedFrame();
/// \~chinese
/// @brief 恢复已保存的图像帧
void RestoreSavedFrame();
/// \~chinese
/// @brief 清空当前图像区域
void ClearCurrentFrameArea();
protected:
bool animating_;
int total_loop_count_;
int loop_count_;
size_t next_index_;
Duration frame_elapsed_;
LoopDoneCallback loop_cb_;
DoneCallback done_cb_;
GifImage gif_;
GifImage::Frame frame_;
Texture saved_frame_;
TextureRenderTarget frame_rt_;
private:
bool animating_;
int total_loop_count_;
int loop_count_;
size_t next_index_;
Duration frame_elapsed_;
LoopDoneCallback loop_cb_;
DoneCallback done_cb_;
GifImagePtr gif_;
GifImage::Frame frame_;
TexturePtr saved_frame_;
TexturePtr frame_to_render_;
TextureRenderTargetPtr frame_rt_;
};
/** @} */
inline void GifSprite::SetLoopCount(int loops) { total_loop_count_ = loops; }
inline void GifSprite::SetLoopDoneCallback(LoopDoneCallback const& cb) { loop_cb_ = cb; }
inline void GifSprite::SetDoneCallback(DoneCallback const& cb) { done_cb_ = cb; }
inline GifSprite::LoopDoneCallback GifSprite::GetLoopDoneCallback() const { return loop_cb_; }
inline GifSprite::DoneCallback GifSprite::GetDoneCallback() const { return done_cb_; }
inline GifImagePtr GifSprite::GetGifImage() const { return gif_; }
inline bool GifSprite::IsLastFrame() const { return (next_index_ == 0); }
inline bool GifSprite::EndOfAnimation() const { return IsLastFrame() && loop_count_ == total_loop_count_ + 1; }
}

View File

@ -27,16 +27,6 @@ namespace kiwano
Layer::Layer()
: swallow_(false)
{
auto handler = Closure(this, &Layer::HandleMessages);
AddListener(event::MouseDown, handler);
AddListener(event::MouseUp, handler);
AddListener(event::MouseMove, handler);
AddListener(event::MouseWheel, handler);
AddListener(event::KeyDown, handler);
AddListener(event::KeyUp, handler);
AddListener(event::KeyChar, handler);
}
Layer::~Layer()
@ -84,50 +74,17 @@ namespace kiwano
void Layer::Render(RenderTarget* rt)
{
PrepareRender(rt);
rt->PushLayer(area_);
Actor::Render(rt);
rt->PopLayer();
}
void Layer::HandleMessages(Event& evt)
bool Layer::CheckVisibilty(RenderTarget* rt) const
{
if (evt.type == event::MouseDown)
{
auto real_evt = evt.SafeCast<MouseDownEvent>();
OnMouseButtonDown(real_evt->button, real_evt->pos);
}
else if (evt.type == event::MouseUp)
{
auto real_evt = evt.SafeCast<MouseUpEvent>();
OnMouseButtonUp(real_evt->button, real_evt->pos);
}
else if (evt.type == event::MouseMove)
{
auto real_evt = evt.SafeCast<MouseMoveEvent>();
OnMouseMoved(real_evt->pos);
}
else if (evt.type == event::MouseWheel)
{
auto real_evt = evt.SafeCast<MouseWheelEvent>();
OnMouseWheel(real_evt->wheel);
}
else if (evt.type == event::KeyDown)
{
auto real_evt = evt.SafeCast<KeyDownEvent>();
OnKeyDown(real_evt->code);
}
else if (evt.type == event::KeyUp)
{
auto real_evt = evt.SafeCast<KeyUpEvent>();
OnKeyUp(real_evt->code);
}
else if (evt.type == event::KeyChar)
{
auto real_evt = evt.SafeCast<KeyCharEvent>();
OnChar(real_evt->value);
}
// Do not need to render Layer
return false;
}
}

View File

@ -20,11 +20,22 @@
#pragma once
#include <kiwano/2d/Actor.h>
#include <kiwano/2d/..\renderer\LayerArea.h>
#include <kiwano/2d/..\renderer\RenderTarget.h>
#include <kiwano/renderer/LayerArea.h>
#include <kiwano/renderer/RenderTarget.h>
namespace kiwano
{
KGE_DECLARE_SMART_PTR(Layer);
/**
* \addtogroup Actors
* @{
*/
/**
* \~chinese
* @brief
*/
class KGE_API Layer
: public Actor
{
@ -33,49 +44,64 @@ namespace kiwano
virtual ~Layer();
// 重载下列函数以获取图层事件
virtual void OnMouseButtonDown(MouseButton::Value btn, Point const& p) {}
virtual void OnMouseButtonUp(MouseButton::Value btn, Point const& p) {}
virtual void OnMouseMoved(Point const& p) {}
virtual void OnMouseWheel(float wheel) {}
virtual void OnKeyDown(int key) {}
virtual void OnKeyUp(int key) {}
virtual void OnChar(char c) {}
/// \~chinese
/// @brief 是否开启消息吞没
bool IsSwallowEventsEnabled() const;
// 是否开启消息吞没
inline bool IsSwallowEventsEnabled() const { return swallow_; }
/// \~chinese
/// @brief 设置消息吞没功能
/// @param enabled 是否启用
void SetSwallowEvents(bool enabled);
// 吞没消息
inline void SetSwallowEvents(bool enabled) { swallow_ = enabled; }
// 设置裁剪区域
/// \~chinese
/// @brief 设置裁剪区域
/// @param clip_rect 裁剪矩形
void SetClipRect(Rect const& clip_rect);
// 设置图层透明度
/// \~chinese
/// @brief 设置图层透明度
/// @param opacity 透明度
void SetOpacity(float opacity) override;
// 设置几何蒙层
/// \~chinese
/// @brief 设置几何蒙层
/// @param mask 蒙层的几何形状
void SetMaskGeometry(Geometry const& mask);
// 设置几何蒙层的二维变换
/// \~chinese
/// @brief 设置几何蒙层的二维变换
/// @param transform 应用于蒙层的二维变换
void SetMaskTransform(Matrix3x2 const& transform);
// 设置图层区域
inline void SetArea(LayerArea const& area) { area_ = area; }
/// \~chinese
/// @brief 设置图层区域
/// @param area 图层区域属性
void SetArea(LayerArea const& area);
// 获取图层区域
inline LayerArea const& GetArea() const { return area_; }
/// \~chinese
/// @brief 获取图层区域
LayerArea const& GetArea() const;
public:
void Dispatch(Event& evt) override;
protected:
void Render(RenderTarget* rt) override;
void HandleMessages(Event& evt);
bool CheckVisibilty(RenderTarget* rt) const override;
protected:
private:
bool swallow_;
LayerArea area_;
};
/** @} */
inline bool Layer::IsSwallowEventsEnabled() const { return swallow_; }
inline void Layer::SetSwallowEvents(bool enabled) { swallow_ = enabled; }
inline void Layer::SetArea(LayerArea const& area) { area_ = area; }
inline LayerArea const& Layer::GetArea() const { return area_; }
}

View File

@ -25,19 +25,11 @@
namespace kiwano
{
ShapeActor::ShapeActor()
: fill_color_(Color::White)
, stroke_color_(Color(Color::Black, 0))
, stroke_width_(1.f)
: stroke_width_(1.f)
, stroke_style_(StrokeStyle::Miter)
{
}
ShapeActor::ShapeActor(Geometry const& geometry)
: ShapeActor()
{
SetGeometry(geometry);
}
ShapeActor::~ShapeActor()
{
}
@ -49,7 +41,7 @@ namespace kiwano
Rect ShapeActor::GetBoundingBox() const
{
if (!geo_)
if (!geo_.IsValid())
return Rect{};
return geo_.GetBoundingBox(GetTransformMatrix());
@ -57,17 +49,7 @@ namespace kiwano
bool ShapeActor::ContainsPoint(const Point& point) const
{
return geo_.ContainsPoint(point, GetTransformMatrix());
}
void ShapeActor::SetFillColor(const Color & color)
{
fill_color_ = color;
}
void ShapeActor::SetStrokeColor(const Color & color)
{
stroke_color_ = color;
return geo_.ContainsPoint(point, &GetTransformMatrix());
}
void ShapeActor::SetStrokeWidth(float width)
@ -83,7 +65,7 @@ namespace kiwano
void ShapeActor::SetGeometry(Geometry const& geometry)
{
geo_ = geometry;
if (geo_)
if (geo_.IsValid())
{
bounds_ = geo_.GetBoundingBox();
SetSize(bounds_.GetSize());
@ -97,22 +79,29 @@ namespace kiwano
void ShapeActor::OnRender(RenderTarget* rt)
{
if (geo_ && CheckVisibilty(rt))
// Create default brush
if (!fill_brush_)
{
PrepareRender(rt);
rt->SetDefaultBrushColor(stroke_color_);
rt->DrawGeometry(
geo_,
stroke_width_ * 2, // twice width for widening
stroke_style_
);
rt->SetDefaultBrushColor(fill_color_);
rt->FillGeometry(
geo_
);
fill_brush_ = new Brush;
fill_brush_->SetColor(Color::White);
}
if (!stroke_brush_)
{
stroke_brush_ = new Brush;
stroke_brush_->SetColor(Color::Transparent);
}
rt->SetCurrentBrush(stroke_brush_);
rt->DrawGeometry(geo_, stroke_width_ * 2 /* twice width for widening */, stroke_style_);
rt->SetCurrentBrush(fill_brush_);
rt->FillGeometry(geo_);
}
bool ShapeActor::CheckVisibilty(RenderTarget* rt) const
{
return geo_.IsValid() && Actor::CheckVisibilty(rt);
}
//-------------------------------------------------------
@ -123,11 +112,6 @@ namespace kiwano
{
}
LineActor::LineActor(Point const& begin, Point const& end)
{
SetLine(begin, end);
}
LineActor::~LineActor()
{
}
@ -151,11 +135,6 @@ namespace kiwano
{
}
RectActor::RectActor(Size const& size)
{
SetRectSize(size);
}
RectActor::~RectActor()
{
}
@ -178,11 +157,6 @@ namespace kiwano
{
}
RoundRectActor::RoundRectActor(Size const& size, Vec2 const& radius)
{
SetRoundedRect(size, radius);
}
RoundRectActor::~RoundRectActor()
{
}
@ -217,11 +191,6 @@ namespace kiwano
{
}
CircleActor::CircleActor(float radius)
{
SetRadius(radius);
}
CircleActor::~CircleActor()
{
}
@ -244,11 +213,6 @@ namespace kiwano
{
}
EllipseActor::EllipseActor(Vec2 const& radius)
{
SetRadius(radius);
}
EllipseActor::~EllipseActor()
{
}
@ -271,11 +235,6 @@ namespace kiwano
{
}
PolygonActor::PolygonActor(Vector<Point> const& points)
{
SetVertices(points);
}
PolygonActor::~PolygonActor()
{
}
@ -296,56 +255,56 @@ namespace kiwano
//-------------------------------------------------------
// PathActor
// PathShapeActor
//-------------------------------------------------------
PathActor::PathActor()
PathShapeActor::PathShapeActor()
{
}
PathActor::~PathActor()
PathShapeActor::~PathShapeActor()
{
}
void PathActor::BeginPath(Point const& begin_pos)
void PathShapeActor::BeginPath(Point const& begin_pos)
{
sink_.BeginPath(begin_pos);
}
void PathActor::EndPath(bool closed)
void PathShapeActor::EndPath(bool closed)
{
sink_.EndPath(closed);
Geometry geo = sink_.GetGeometry();
if (geo)
if (geo.IsValid())
{
SetGeometry(geo);
}
}
void PathActor::AddLine(Point const& point)
void PathShapeActor::AddLine(Point const& point)
{
sink_.AddLine(point);
}
void PathActor::AddLines(Vector<Point> const& points)
void PathShapeActor::AddLines(Vector<Point> const& points)
{
sink_.AddLines(points);
}
void PathActor::AddBezier(Point const& point1, Point const& point2, Point const& point3)
void PathShapeActor::AddBezier(Point const& point1, Point const& point2, Point const& point3)
{
sink_.AddBezier(point1, point2, point3);
}
void PathActor::AddArc(Point const& point, Size const& radius, float rotation, bool clockwise, bool is_small)
void PathShapeActor::AddArc(Point const& point, Size const& radius, float rotation, bool clockwise, bool is_small)
{
sink_.AddArc(point, radius, rotation, clockwise, is_small);
}
void PathActor::ClearPath()
void PathShapeActor::ClearPath()
{
geo_.SetGeometry(nullptr);
SetGeometry(Geometry());
}
}

View File

@ -20,68 +20,113 @@
#pragma once
#include <kiwano/2d/Actor.h>
#include <kiwano/renderer/Brush.h>
#include <kiwano/renderer/Geometry.h>
#include <kiwano/renderer/GeometrySink.h>
#include <kiwano/renderer/StrokeStyle.h>
namespace kiwano
{
// 二维图形角色
KGE_DECLARE_SMART_PTR(ShapeActor);
KGE_DECLARE_SMART_PTR(LineActor);
KGE_DECLARE_SMART_PTR(RectActor);
KGE_DECLARE_SMART_PTR(RoundRectActor);
KGE_DECLARE_SMART_PTR(CircleActor);
KGE_DECLARE_SMART_PTR(EllipseActor);
KGE_DECLARE_SMART_PTR(PolygonActor);
KGE_DECLARE_SMART_PTR(PathShapeActor);
/**
* \addtogroup Actors
* @{
*/
/**
* \~chinese
* @brief
*/
class KGE_API ShapeActor
: public Actor
{
public:
/// \~chinese
/// @brief 构造二维形状角色
ShapeActor();
ShapeActor(
Geometry const& geometry
);
virtual ~ShapeActor();
// 获取填充颜色
inline Color GetFillColor() const { return fill_color_; }
/// \~chinese
/// @brief 获取填充画刷
BrushPtr GetFillBrush() const;
// 获取线条颜色
inline Color GetStrokeColor() const { return stroke_color_; }
/// \~chinese
/// @brief 获取轮廓画刷
BrushPtr GetStrokeBrush() const;
// 获取线条宽度
inline float GetStrokeWidth() const { return stroke_width_; }
/// \~chinese
/// @brief 获取线条宽度
float GetStrokeWidth() const;
// 获取线条样式
inline StrokeStyle SetStrokeStyle() const { return stroke_style_; }
/// \~chinese
/// @brief 获取线条样式
StrokeStyle SetStrokeStyle() const;
// 获取形状
inline Geometry GetGeometry() const { return geo_; }
/// \~chinese
/// @brief 获取形状
Geometry GetGeometry() const;
// 获取边界
/// \~chinese
/// @brief 获取边界
Rect GetBounds() const override;
// 获取外切包围盒
/// \~chinese
/// @brief 获取外切包围盒
Rect GetBoundingBox() const override;
// 判断点是否在形状内
/// \~chinese
/// @brief 判断点是否在形状内
bool ContainsPoint(const Point& point) const override;
// 设置填充颜色
void SetFillColor(const Color& color);
/// \~chinese
/// @brief 设置填充颜色
/// @param color 填充颜色
void SetFillColor(Color const& color);
// 设置线条颜色
void SetStrokeColor(const Color& color);
/// \~chinese
/// @brief 设置填充画刷
/// @param[in] brush 填充画刷
void SetFillBrush(BrushPtr brush);
// 设置线条宽度
/// \~chinese
/// @brief 设置轮廓颜色
/// @param color 轮廓颜色
void SetStrokeColor(Color const& color);
/// \~chinese
/// @brief 设置轮廓画刷
/// @param[in] brush 轮廓画刷
void SetStrokeBrush(BrushPtr brush);
/// \~chinese
/// @brief 设置线条宽度,默认为 1.0
void SetStrokeWidth(float width);
// 设置线条样式
/// \~chinese
/// @brief 设置线条样式
void SetStrokeStyle(StrokeStyle stroke_style);
// 设置形状
/// \~chinese
/// @brief 设置几何形状
void SetGeometry(Geometry const& geometry);
void OnRender(RenderTarget* rt) override;
protected:
Color fill_color_;
Color stroke_color_;
bool CheckVisibilty(RenderTarget* rt) const override;
private:
BrushPtr fill_brush_;
BrushPtr stroke_brush_;
float stroke_width_;
StrokeStyle stroke_style_;
Rect bounds_;
@ -89,219 +134,269 @@ namespace kiwano
};
// 直线角色
/// \~chinese
/// @brief 线段图形角色
class KGE_API LineActor
: public ShapeActor
{
public:
LineActor();
LineActor(
Point const& begin,
Point const& end
);
virtual ~LineActor();
inline Point const& GetBeginPoint() const { return begin_; }
inline Point const& GetEndPoint() const { return end_; }
/// \~chinese
/// @brief 获取线段起点
Point const& GetBeginPoint() const;
inline void SetBeginPoint(Point const& begin)
{
SetLine(begin, end_);
}
/// \~chinese
/// @brief 获取线段终点
Point const& GetEndPoint() const;
inline void SetEndPoint(Point const& end)
{
SetLine(begin_, end);
}
/// \~chinese
/// @brief 设置线段起点
/// @param begin 线段起点
void SetBeginPoint(Point const& begin);
void SetLine(
Point const& begin,
Point const& end
);
/// \~chinese
/// @brief 设置线段终点
/// @param end 线段终点
void SetEndPoint(Point const& end);
protected:
/// \~chinese
/// @brief 设置矩形大小
/// @param begin 线段起点
/// @param end 线段终点
void SetLine(Point const& begin, Point const& end);
private:
Point begin_;
Point end_;
};
// 矩形角色
/// \~chinese
/// @brief 矩形角色
class KGE_API RectActor
: public ShapeActor
{
public:
RectActor();
RectActor(
Size const& size
);
virtual ~RectActor();
inline Size const& GetRectSize() const { return rect_size_; }
/// \~chinese
/// @brief 获取矩形大小
Size const& GetRectSize() const;
/// \~chinese
/// @brief 设置矩形大小
/// @param size 矩形大小
void SetRectSize(Size const& size);
protected:
private:
Size rect_size_;
};
// 圆角矩形角色
/// \~chinese
/// @brief 圆角矩形角色
class KGE_API RoundRectActor
: public ShapeActor
{
public:
RoundRectActor();
RoundRectActor(
Size const& size,
Vec2 const& radius
);
virtual ~RoundRectActor();
inline Vec2 GetRadius() const { return radius_; }
/// \~chinese
/// @brief 获取圆角半径
Vec2 GetRadius() const;
inline Size GetRectSize() const { return GetSize(); }
/// \~chinese
/// @brief 获取圆角矩形大小
Size GetRectSize() const;
void SetRadius(
Vec2 const& radius
);
/// \~chinese
/// @brief 设置圆角半径
/// @param radius 圆角半径
void SetRadius(Vec2 const& radius);
void SetRectSize(
Size const& size
);
/// \~chinese
/// @brief 设置圆角矩形大小
/// @param size 圆角矩形大小
void SetRectSize(Size const& size);
void SetRoundedRect(
Size const& size,
Vec2 const& radius
);
/// \~chinese
/// @brief 设置圆角矩形
/// @param size 圆角矩形大小
/// @param radius 圆角半径
void SetRoundedRect(Size const& size, Vec2 const& radius);
protected:
private:
Size rect_size_;
Vec2 radius_;
};
// 圆形角色
/// \~chinese
/// @brief 圆形角色
class KGE_API CircleActor
: public ShapeActor
{
public:
CircleActor();
CircleActor(
float radius
);
virtual ~CircleActor();
inline float GetRadius() const { return radius_; }
/// \~chinese
/// @brief 获取圆形半径
float GetRadius() const;
/// \~chinese
/// @brief 设置圆形半径
/// @param radius 圆形半径
void SetRadius(float radius);
protected:
private:
float radius_;
};
// 椭圆角色
/// \~chinese
/// @brief 椭圆角色
class KGE_API EllipseActor
: public ShapeActor
{
public:
EllipseActor();
EllipseActor(
Vec2 const& radius
);
virtual ~EllipseActor();
Vec2 GetRadius() const { return radius_; }
/// \~chinese
/// @brief 获取椭圆半径
Vec2 GetRadius() const;
void SetRadius(
Vec2 const& radius
);
/// \~chinese
/// @brief 设置椭圆半径
/// @param radius 椭圆半径
void SetRadius(Vec2 const& radius);
protected:
private:
Vec2 radius_;
};
// 多边形角色
/// \~chinese
/// @brief 多边形角色
class KGE_API PolygonActor
: public ShapeActor
{
public:
PolygonActor();
PolygonActor(
Vector<Point> const& points
);
virtual ~PolygonActor();
void SetVertices(
Vector<Point> const& points
);
/// \~chinese
/// @brief 设置多边形端点
/// @param points 多边形端点集合
void SetVertices(Vector<Point> const& points);
};
// 路径角色
class KGE_API PathActor
/// \~chinese
/// @brief 路径图形角色
class KGE_API PathShapeActor
: public ShapeActor
{
public:
PathActor();
PathShapeActor();
virtual ~PathActor();
virtual ~PathShapeActor();
// 开始添加路径
void BeginPath(
Point const& begin_pos = Point{} /* 起始点 */
);
/// \~chinese
/// @brief 开始添加路径
/// @param begin_pos 起始点
void BeginPath(Point const& begin_pos = Point());
// 结束路径
void EndPath(
bool closed = true /* 路径是否闭合 */
);
/// \~chinese
/// @brief 结束添加路径
/// @param closed 路径是否闭合
void EndPath(bool closed = true);
// 添加一条线段
void AddLine(
Point const& point /* 端点 */
);
/// \~chinese
/// @brief 添加一条线段
/// @param point 线段端点
void AddLine(Point const& point);
// 添加多条线段
void AddLines(
Vector<Point> const& points
);
/// \~chinese
/// @brief 添加多条线段
/// @param points 线段端点集合
void AddLines(Vector<Point> const& points);
// 添加一条三次方贝塞尔曲线
void AddBezier(
Point const& point1, /* 贝塞尔曲线的第一个控制点 */
Point const& point2, /* 贝塞尔曲线的第二个控制点 */
Point const& point3 /* 贝塞尔曲线的终点 */
);
/// \~chinese
/// @brief 添加一条三次方贝塞尔曲线
/// @param point1 贝塞尔曲线的第一个控制点
/// @param point2 贝塞尔曲线的第二个控制点
/// @param point3 贝塞尔曲线的终点
void AddBezier(Point const& point1, Point const& point2, Point const& point3);
// 添加弧线
void AddArc(
Point const& point, /* 终点 */
Size const& radius, /* 椭圆半径 */
float rotation, /* 椭圆旋转角度 */
bool clockwise = true, /* 顺时针 or 逆时针 */
bool is_small = true /* 是否取小于 180° 的弧 */
);
/// \~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 ClearPath();
protected:
private:
GeometrySink sink_;
};
/** @} */
inline void ShapeActor::SetStrokeColor(Color const& color)
{
if (!stroke_brush_)
{
stroke_brush_ = new Brush;
}
stroke_brush_->SetColor(color);
}
inline void ShapeActor::SetFillColor(Color const& color)
{
if (!fill_brush_)
{
fill_brush_ = new Brush;
}
fill_brush_->SetColor(color);
}
inline void ShapeActor::SetFillBrush(BrushPtr brush) { fill_brush_ = brush; }
inline void ShapeActor::SetStrokeBrush(BrushPtr brush) { stroke_brush_ = brush; }
inline BrushPtr ShapeActor::GetFillBrush() const { return fill_brush_; }
inline BrushPtr ShapeActor::GetStrokeBrush() const { return stroke_brush_; }
inline float ShapeActor::GetStrokeWidth() const { return stroke_width_; }
inline StrokeStyle ShapeActor::SetStrokeStyle() const { return stroke_style_; }
inline Geometry ShapeActor::GetGeometry() const { return geo_; }
inline Point const& LineActor::GetBeginPoint() const { return begin_; }
inline Point const& LineActor::GetEndPoint() const { return end_; }
inline void LineActor::SetBeginPoint(Point const& begin) { SetLine(begin, end_); }
inline void LineActor::SetEndPoint(Point const& end) { SetLine(begin_, end); }
inline Size const& RectActor::GetRectSize() const { return rect_size_; }
inline Vec2 RoundRectActor::GetRadius() const { return radius_; }
inline Size RoundRectActor::GetRectSize() const { return GetSize(); }
inline float CircleActor::GetRadius() const { return radius_; }
inline Vec2 EllipseActor::GetRadius() const { return radius_; }
}

Some files were not shown because too many files have changed in this diff Show More